ci(construct): add PR-time publish-manifest-rehearsal to catch buildx env-var leaks#273
Merged
Merged
Conversation
… env-var leaks Tier 3 follow-up to #266. The previous hardening rounds (#267 docs rules + #14/#15 terraform branch protection) are process- and gate-side. This one is the workflow-side companion: a PR-time rehearsal job that runs the same docker buildx CLI plumbing `publish-manifest` depends on, without the side-effect steps (Docker Hub login, `imagetools create`, `imagetools inspect`). The #266 break (`ERROR: no builder "jackin-construct" found`) was caused by hoisting BUILDX_BUILDER into workflow-level env, which docker buildx reads as the default-builder selection. The error surfaces at `docker buildx` startup — before any network write — so a network-free `docker buildx ls` invocation reproduces the exact failure shape. The rehearsal runs on the events publish-manifest itself skips: PR and feature-branch dispatch that touch construct paths. Two checks: - `docker buildx ls` exercises BUILDX_BUILDER (and any future buildx-controlling env var) without writing to a registry. A workflow-level env leak fails this step loudly. - `docker buildx imagetools --help` smoke-tests that the buildx CLI plugin is bundled and loadable on the runner. Cheap. The `construct-required` aggregator now includes publish-manifest-rehearsal in its `needs:` list so the rehearsal's result is rolled up into the same single check name branch protection requires. Skipping similar rehearsals for `build-validator`, `deploy`, and `publish-preview` for now: those side-effect surfaces (release artifacts, GitHub Pages, public Homebrew tap) don't have the same network-free reproducibility shape `buildx ls` provides for the docker case. Revisit if a #266-class break surfaces in any of them. Signed-off-by: Alexey Zhokhov <alexey@zhokhov.com> Co-authored-by: Claude <noreply@anthropic.com>
donbeave
added a commit
that referenced
this pull request
May 18, 2026
… env-var leaks (#273) Tier 3 follow-up to the post-#266 hardening. Add a PR-time `publish-manifest-rehearsal` job to `construct.yml` that runs the same docker buildx CLI plumbing `publish-manifest` depends on, without the side-effect steps (Docker Hub login, `imagetools create`, `imagetools inspect`). The previous hardening rounds were process- (#267 docs rules) and gate-side (#14 / #15 terraform branch protection). This is the workflow-side companion. The #266 break (`ERROR: no builder "jackin-construct" found`) was caused by hoisting `BUILDX_BUILDER` into workflow-level env, which docker buildx reads as the default-builder selection — surfacing only post-merge on main because `publish-manifest` is push-only and never runs on a `pull_request` event. `docker buildx ls` evaluates `BUILDX_BUILDER` at startup and exits non-zero on a missing-builder reference, regardless of whether the rest of the command would have hit the network. Running it on PR + feature-branch dispatch reproduces the failure shape without registry credentials. Two checks: `docker buildx ls` (catches workflow-level env-var leaks for any current or future buildx-controlling env var) and `docker buildx imagetools --help >/dev/null` (smoke-test that the buildx CLI plugin is bundled and loadable on the runner). The `construct-required` aggregator now lists `publish-manifest-rehearsal` in `needs:` so the rehearsal's result is rolled up into the same single check name branch protection requires. Equivalent rehearsals for `build-validator`, `deploy`, and `publish-preview` are deferred — those side-effect surfaces don't have the same network-free reproducibility shape `buildx ls` provides for docker, so the fidelity-vs-cost trade is worse. Reopen if a #266-class break surfaces in any of them. Signed-off-by: Alexey Zhokhov <alexey@zhokhov.com> Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Tier 3 follow-up to the post-#266 hardening. Adds a PR-time
publish-manifest-rehearsaljob toconstruct.ymlthat runs the samedocker buildxCLI plumbingpublish-manifestdepends on, without the side-effect steps (Docker Hub login,imagetools create,imagetools inspect). The rehearsal closes the gap that let #266 reachmain: workflow-level env vars consumed by third-party CLIs (in #266's caseBUILDX_BUILDER) were never exercised on PR because every job that callsdocker buildxis gated to push-to-main.How the rehearsal catches the #266 class of break
docker buildx lsevaluatesBUILDX_BUILDER(and any other buildx-controlling env var) at startup and exits non-zero on a missing-builder reference. That's the exact failure shapepublish-manifestemitted post-#256-merge:Running the same call without registry credentials surfaces the same error before any network write. A second cheap step —
docker buildx imagetools --help >/dev/null— confirms the buildx CLI plugin is bundled and loadable on the runner.The rehearsal runs on the events
publish-manifestitself skips: PR and feature-branchworkflow_dispatchthat touch construct paths. Theconstruct-requiredaggregator now listspublish-manifest-rehearsalinneeds:so its result is rolled up into the same single required-check name branch protection enforces.What's deferred
Similar rehearsals for
build-validator(CI),deploy(Docs), andpublish-preview(Homebrew preview) are not included. None of those side-effect surfaces — release artifacts in GitHub-side storage, GitHub Pages publish, Homebrew tap PR-create — has the same network-free reproducibility shapebuildx lsprovides for docker. Adding rehearsals for them would either require synthesizing fake side effects (high false-confidence risk) or re-architecting the workflow trigger (preview.yml fires onworkflow_runfrom CI completion on main, not PR). Reopen if a #266-class break surfaces in any of them.Verify locally
Checkout
export TIRITH=0Static checks
Smoke (CI runner only — local docker may not bundle buildx)
The CI run on this PR is the actual fidelity test —
publish-manifest-rehearsalshould run, report green, and be visible in theconstruct-requiredrollup. Push to main on merge will skip the rehearsal (becauseis_publish == 'true') and run the realpublish-manifest, exactly as before this PR.