Skip to content

fix(ci): gate image publishing on test, lint, and security checks (#99)#128

Merged
galt-tr merged 1 commit into
mainfrom
fix/issue-99-image-publish-gates
May 3, 2026
Merged

fix(ci): gate image publishing on test, lint, and security checks (#99)#128
galt-tr merged 1 commit into
mainfrom
fix/issue-99-image-publish-gates

Conversation

@galt-tr
Copy link
Copy Markdown
Contributor

@galt-tr galt-tr commented May 3, 2026

Summary

Closes #99 (F-041).

build.yml previously published a Docker image to GHCR on every push to main and every v* tag, with no dependency on the GoFortress test/lint/security jobs. A failing test, lint regression, vulnerable dependency (govulncheck), or leaked secret (gitleaks) could ship a release image.

This PR makes image publishing a downstream step gated on a successful GoFortress run:

  • build.yml now triggers via workflow_run after GoFortress completes (in addition to pull_request for verification builds and workflow_dispatch).
  • New gofortress-gate job runs first; the job only proceeds when github.event.workflow_run.conclusion == 'success'.
  • build-and-push declares needs: [get_tag, gofortress-gate], so the GHCR push cannot run unless GoFortress's required gates all passed.
  • The publish step now checks out the exact head_sha GoFortress validated, so we never push a different commit than was tested.

Gates required (all run inside GoFortress; verified by workflow_run conclusion)

  • code-quality (golangci-lint, yamllint, static analysis, go vet)
  • pre-commit
  • security (govulncheck, nancy, gitleaks)
  • test-magex
  • test-suite
  • setup, warm-cache

GoFortress's own status-check job already aggregates these and fails the workflow if any required gate fails, which is exactly what workflow_run.conclusion == 'success' reflects.

Approach

A (recommended): keep gating in-repo and visible. The needs: chain is now:

gofortress-gate -> get_tag -> build-and-push

with gofortress-gate only running when the upstream GoFortress workflow's conclusion is success.

Notes / post-merge build behavior

  • After merge, push-to-main will no longer directly trigger an image publish. Instead, GoFortress runs on the push, and only on its successful completion does build.yml (via workflow_run) build & publish. Time-to-publish increases by ~the GoFortress duration; this is intentional.
  • Tag pushes (v*): GoFortress's own release job already handles GoReleaser/tag releases. Image publishing now also flows through workflow_run; tag-named image tags via workflow_run are out of scope for this PR (workflow_run carries the head SHA, not the tag ref). If tag-named GHCR tags are needed, follow-up by reading the tag from the workflow_run payload or extending fortress-release to publish images.
  • PR builds: still run (no publish), unchanged for fast feedback.
  • workflow_dispatch: gate still attaches, but operators can dispatch manually; treat as intentional.

Test plan

  • Open this PR; confirm build.yml runs the build job (no push) and GoFortress runs in parallel as expected.
  • After merge to main, confirm GoFortress runs first and build.yml only fires after GoFortress concludes successfully.
  • Confirm a forced GoFortress failure on a follow-up PR/branch prevents build-and-push from running (job is skipped via gofortress-gate if:).
  • Confirm GHCR receives an image tagged with the head_sha GoFortress validated.

Publishing to GHCR previously ran on every push to `main` and every tag,
without any dependency on the GoFortress test, lint, govulncheck, or
gitleaks jobs. A failing test or vulnerable dependency could ship a
release image.

Restructure `build.yml`:

- Trigger via `workflow_run` after the `GoFortress` workflow completes.
- Add a `gofortress-gate` job that only succeeds when the upstream
  GoFortress run finished with `conclusion == 'success'`.
- Chain `needs: [get_tag, gofortress-gate]` on `build-and-push`, so the
  GHCR push step cannot run unless lint, pre-commit, govulncheck,
  gitleaks, govet, and the test suite all passed.
- Check out the exact `head_sha` GoFortress validated (instead of the
  current branch HEAD) to avoid publishing a different commit than was
  tested.
- Keep `pull_request` and `workflow_dispatch` triggers for build-only
  verification; PRs already use `push: false`, and manual dispatch is
  operator-initiated.

Closes #99 (F-041).
@galt-tr galt-tr requested a review from mrz1836 as a code owner May 3, 2026 13:51
@github-actions github-actions Bot added size/M Medium change (51–200 lines) bug-P3 Lowest rated bug, affects nearly none or low-impact security Security-related issue, vulnerability, or fix test Unit tests, mocking, integration testing labels May 3, 2026
@galt-tr galt-tr merged commit 33c6fb1 into main May 3, 2026
46 checks passed
@galt-tr galt-tr deleted the fix/issue-99-image-publish-gates branch May 3, 2026 21:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug-P3 Lowest rated bug, affects nearly none or low-impact security Security-related issue, vulnerability, or fix size/M Medium change (51–200 lines) test Unit tests, mocking, integration testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[F-041] image publishing workflow pushes without test or security gates

2 participants