ci: scan and sign published container images#118
Conversation
|
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. |
|
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:
For more information about GitHub Code Scanning, check out the documentation. |
There was a problem hiding this comment.
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.
| docker run --rm \ | ||
| -v /var/run/docker.sock:/var/run/docker.sock \ | ||
| -v "$PWD:/work" \ | ||
| aquasec/trivy:latest image \ |
There was a problem hiding this comment.
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.
| $(printf 'ghcr.io/${{ github.repository }}@sha256:%s ' *) | ||
| - name: Install cosign | ||
| uses: sigstore/cosign-installer@v3 | ||
| - name: Sign the published image (keyless) |
There was a problem hiding this comment.
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.
| --output /work/trivy-results.sarif \ | ||
| --exit-code 0 \ | ||
| postguard-business:scan | ||
| - name: Upload Trivy results |
There was a problem hiding this comment.
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') != ''.
| # 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: |
There was a problem hiding this comment.
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).
|
Reviewed! I left a consolidated comment on the CI config with 4 inline notes — all non-blocking:
No rule violations, everything else looks clean. Let me know if you want me to dig into any of these! |
…pload, needs build
|
Thanks @dobby-coder — addressed all four in 23c0979:
|
* 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>
Closes #109.
Adds vulnerability scanning and signing for the container images the pipeline publishes to GHCR.
Changes to
ci.ymlimage-scanjob (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 to1to gate once the baseline is clean. It doesn't touch the publish path.finalizejob — after the multi-arch manifest is pushed, installs cosign and signs the published image keyless (GitHub OIDC), so consumers can verify provenance withcosign verify. Addedid-token: writefor 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 thepr-<n>tag). So this PR's ownfinalizerun exercises the cosign path end-to-end — if signing is green here, it will behave identically onmain/release. I deliberately did not add buildxprovenance:/sbom:attestations to thebuildjob, because they interact awkwardly with the existingpush-by-digest+imagetools createmanifest merge; cosign signing achieves provenance without disturbing that flow.Verify a signature