Skip to content

ci: scan and sign published container images#118

Merged
rubenhensen merged 3 commits into
mainfrom
ci/image-scan-sign
Jul 1, 2026
Merged

ci: scan and sign published container images#118
rubenhensen merged 3 commits into
mainfrom
ci/image-scan-sign

Conversation

@rubenhensen

Copy link
Copy Markdown
Contributor

Closes #109.

Adds vulnerability scanning and signing for the container images the pipeline publishes to GHCR.

Changes to ci.yml

  • image-scan job (new, isolated) — builds the amd64 runtime image locally (load: true, reusing the gha cache) and runs a Trivy scan (HIGH,CRITICAL, ignore-unfixed), uploading SARIF to the Security tab. Non-blocking for now (exit-code: 0) so it can't break publishing on pre-existing base-image noise; flip to 1 to gate once the baseline is clean. It doesn't touch the publish path.
  • finalize job — after the multi-arch manifest is pushed, installs cosign and signs the published image keyless (GitHub OIDC), so consumers can verify provenance with cosign verify. Added id-token: write for the OIDC flow.

Why this is safe to review with confidence

The signing step lives in finalize, which also runs on pull requests (it pushes the pr-<n> tag). So this PR's own finalize run exercises the cosign path end-to-end — if signing is green here, it will behave identically on main/release. I deliberately did not add buildx provenance:/sbom: attestations to the build job, because they interact awkwardly with the existing push-by-digest + imagetools create manifest merge; cosign signing achieves provenance without disturbing that flow.

Verify a signature

cosign verify ghcr.io/encryption4all/postguard-business:edge \
  --certificate-identity-regexp 'https://github.com/encryption4all/postguard-business/.*' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

@dobby-coder

dobby-coder Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

On it, @rubenhensen! I'm reviewing PR #118 now — checking the vulnerability scanning and image signing CI additions for correctness and rule compliance, and I'll post a consolidated review shortly.

@github-advanced-security

Copy link
Copy Markdown

You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool.

What Enabling Code Scanning Means:

  • The 'Security' tab will display more code scanning analysis results (e.g., for the default branch).
  • Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results.
  • You will be able to see the analysis results for the pull request's branch on this overview once the scans have completed and the checks have passed.

For more information about GitHub Code Scanning, check out the documentation.

@dobby-coder dobby-coder Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the Trivy scan + cosign signing addition to ci.yml. No blocking bugs and no rule violations (checked against Dobby's rule set and the postguard-business repo notes). The isolated, non-blocking image-scan job is a sensible first hardening pass. A few security-hygiene observations inline — none block merge, but the unpinned trivy:latest and the sign-on-every-PR behaviour are worth addressing.

Tests: skipped — CI-config-only change; a workflow-file diff does not affect the vitest/svelte-check/Playwright suites and GitHub Actions cannot be exercised locally.

Comment thread .github/workflows/ci.yml Outdated
docker run --rm \
-v /var/run/docker.sock:/var/run/docker.sock \
-v "$PWD:/work" \
aquasec/trivy:latest image \

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aquasec/trivy:latest is unpinned. The step comment (lines 237-238) justifies avoiding the Trivy GitHub Action due to a supply-chain compromise (GHSA-69fq-xp46-6x23), but pulling the mutable :latest tag reintroduces the same supply-chain exposure. Pin to a digest or an explicit version.

Comment thread .github/workflows/ci.yml
$(printf 'ghcr.io/${{ github.repository }}@sha256:%s ' *)
- name: Install cosign
uses: sigstore/cosign-installer@v3
- name: Sign the published image (keyless)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cosign sign runs on PR events too: finalize has no event filter (if: always() && needs.build.result == 'success'), so every PR signs its pr-N image. Keyless cosign records each signature (with commit/actor identity) permanently in the public Rekor transparency log and leaves orphan .sig tags in GHCR for throwaway images. Gate the sign step (or job) with if: github.event_name != 'pull_request'; the PR-run smoke test of the cosign path can be done once rather than on every future PR.

Comment thread .github/workflows/ci.yml
--output /work/trivy-results.sarif \
--exit-code 0 \
postguard-business:scan
- name: Upload Trivy results

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Upload Trivy results uses if: always(), but if the scan build or the Trivy step fails, trivy-results.sarif is never produced and the upload step errors, turning the image-scan check red even though the job is meant to be non-blocking. Guard with e.g. if: hashFiles('trivy-results.sarif') != ''.

Comment thread .github/workflows/ci.yml
# Build the runtime image and scan it for OS/dependency vulnerabilities.
# Non-blocking for now (exit-code 0): findings surface in the Security tab.
# Flip exit-code to 1 to gate once the baseline is clean.
image-scan:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: image-scan has no needs: build, so it races the build job that populates cache-to: type=gha. The PR description says it reuses the gha cache, but on a cold branch run the scan does a full cold build. Add needs: build (or accept the cold build and drop the reuse claim).

@dobby-coder

dobby-coder Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Reviewed! I left a consolidated comment on the CI config with 4 inline notes — all non-blocking:

  • Unpinned aquasec/trivy:latest — reintroduces the supply-chain risk the step comment itself warns about; pin to a digest or a fixed tag.
  • cosign signing on every PR — writes permanent Rekor transparency entries and orphan .sig tags for throwaway images; consider restricting signing to pushes to main/release branches only.
  • Upload Trivy step uses if: always() — but the SARIF file is only produced when the scan actually runs, so this errors on paths where the scan is skipped.
  • image-scan job missing needs: build — can race the GHA cache populator; add the dependency to guarantee the image is ready before scanning.

No rule violations, everything else looks clean. Let me know if you want me to dig into any of these!

@rubenhensen

Copy link
Copy Markdown
Contributor Author

Thanks @dobby-coder — addressed all four in 23c0979:

  • Unpinned trivy:latest → pinned to aquasec/trivy:0.72.0 (explicit version).
  • cosign signing on PRs → both cosign steps now gated with if: github.event_name != 'pull_request'. The path was smoke-tested on this PR's earlier run, so future PRs no longer sign throwaway pr-N images / write to Rekor.
  • Upload Trivy results with if: always() → changed to if: hashFiles('trivy-results.sarif') != '' so a failed build/scan can't turn the non-blocking job red.
  • image-scan racing the cache → added needs: build so it reuses the warm gha cache.

@rubenhensen rubenhensen merged commit d1d23b1 into main Jul 1, 2026
16 checks passed
@rubenhensen rubenhensen deleted the ci/image-scan-sign branch July 1, 2026 14:14
rubenhensen added a commit that referenced this pull request Jul 1, 2026
rubenhensen added a commit that referenced this pull request Jul 2, 2026
* test: add coverage reporting with a threshold gate

* test: exclude migrations from coverage and retune thresholds to new baseline

* ci: restore #118 signing+scan and keep lock minimal (revert stray prettier bump)

---------

Co-authored-by: dobby-yivi-agent[bot] <275734547+dobby-yivi-agent[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Supply chain: scan and sign published container images (Trivy + cosign/provenance)

2 participants