Propagate OpenTofu outputs to downstream jobs as dotenv variables

What

Lets you propagate OpenTofu outputs to downstream CI jobs as environment variables, via a artifacts:reports:dotenv report.

Opt-in, defaults off. Implemented as gitlab-tofu-ctl outputs-to-dotenv behind a new gitlab-tofu output-dotenv command.

Why

Chaining apply outputs into a downstream job currently means hand-rolling jq against a JSON artifact. A dotenv report makes the outputs directly available as variables in later jobs.

Design decisions

Sensitive outputs are excluded by default. tofu output -json includes values marked sensitive, and dotenv values are readable in the UI/API and inherited downstream. There is an explicit opt-out only. Values are also piped rather than held in a shell variable, because GITLAB_TOFU_DEBUG enables xtrace and would otherwise print every value into the job log — there is a test asserting a sensitive value reaches neither the report nor stdout/stderr.

Name transformation: [^A-Za-z0-9_] → _, case preserved. Verified against GitLab's actual constraint (Ci::HasVariable, /\A[a-zA-Z0-9_]+\z/, max 255) and OpenTofu's identifier rules. Case is deliberately not upper-cased so that lower snake_case outputs cannot shadow PATH or CI_* downstream.

Collisions are a hard error naming both outputs, rather than silently picking one. This happens after a successful apply, so no infrastructure change is lost and re-running after a rename is safe.

Values: strings raw; numbers/bools as JSON literals (no float64 precision loss); lists/maps as compact JSON. Multi-line strings and null are skipped with a warning, not fatally — GitLab rejects the entire report on one multi-line value, so failing hard would drop every other output.

Documented GitLab limits (verified in the GitLab source, not from memory): dotenv_size default 5120 bytes, dotenv_variables default 20 self-managed / 50-150 on GitLab.com by tier.

Testing

  • 16 Go subtests, including the sensitive-value leak test.
  • tests/integration-tests/DotenvOutputs.gitlab-ci.yml + tests/iac-dotenv-outputs/ fixture, asserting an output actually arrives in a downstream job.
  • 1 new bats case; shellcheck clean; make docs idempotent.

Depends on !556 (merged)

The Go tests here will not run in CI until !556 (merged) (which adds the missing go:test:gitlab-tofu-ctl job) is merged. Please merge !556 (merged) first.

Pre-existing gap, deliberately not fixed here

validate-plan-apply.yml's child-pipeline trigger never forwarded apply_artifacts_access, apply_save_outputs_as_artifact or apply_output_artifact_name. The inputs added by this MR are forwarded; fixing the existing three is handled separately.

Merge request reports

Loading