Attach structured terraform plan/apply data to Atmos Pro exec-metadata upload (US3)
- Dominant language
- Go
- Stars
- 1.4k
- Forks
- 175
- Avg merge
- 2d 25m
- Merged PRs (30d)
- 143
Description
## Context
Follow-up to the Atmos Pro command-execution metadata upload feature (`specs/002-pro-exec-metadata/`). User Stories 1 (async default upload for every command) and 2 (synchronous, reliable base-envelope upload for `terraform plan`/`apply`/`describe affected`) are implemented, tested, and merged. User Story 3 — attaching itemized created/updated/deleted/replaced resources, output values, and warnings to `terraform plan`/`apply` execution records — is not yet implemented.
## What's blocking it
1. ~~`pkg/ci/internal/plugin.TerraformOutputData` is a Go `internal/` package~~ — **not actually blocking**: `pkg/ci/plugins/terraform` (which produces this data) is a **public** package exporting `ParsePlanOutput`/`ParseApplyOutput(output string) *plugin.OutputResult`. Since `OutputResult.Data` is typed `any`, callers outside `pkg/ci` can hold and pass the value through `any`-typed parameters (e.g. `proexec.CaptureSync(..., data any)`) without ever naming the internal type. This part is solved.
2. **The real blocker**: `internal/exec/terraform.go`'s `ExecuteTerraform` — where the exec-metadata `CaptureSync` hook lives — never captures the raw terraform plan/apply **stdout text** at all. The only place raw output is currently captured is a separate, per-component graph pipeline in `cmd/terraform/utils.go` (`runCIHooksForNode`/`rawOutput`), used exclusively for the Native-CI-gated job-summary feature (`atmosConfig.CI.Enabled`). That capture is per-component-node, not per-command-invocation, and is orthogonal to (and gated differently than) the exec-metadata upload's CI+Pro gate.
## What's needed
Add a `MultiWriter`-based stdout tee to `ExecuteTerraform`'s shared execution pipeline for `plan`/`apply` specifically (there's already a `WithStdoutOverride` shell-command option used by `terraform_plan_diff.go` for a different purpose, as prior art) — captured output must still stream to the real destination unchanged, so this needs the tee to preserve streaming/TTY-detection/secret-masking behavior across every terraform subcommand that shares this pipeline, not just plan/apply. Then call the now-confirmed-public `terraform.ParsePlanOutput`/`ParseApplyOutput` on the captured text and pass the result's `.Data` through as `CaptureSync`'s `data` argument.
## References
- `specs/002-pro-exec-metadata/spec.md` (User Story 3)
- `specs/002-pro-exec-metadata/research.md` (Decision 5)
- `specs/002-pro-exec-metadata/tasks.md` (T026, T028 — blocked)
- `internal/exec/terraform.go` (`captureExecMetadataSync`, `ExecuteTerraform`)
- `cmd/terraform/utils.go` (`runCIHooksForNode`, existing per-node raw-output capture for comparison)
- `pkg/ci/plugins/terraform/parser.go` (`ParsePlanOutput`, `ParseApplyOutput`)
Contributor guide
Assessment
This issue has not been assessed yet.