Skip to content

feat(ci): add Trivy HIGH/CRITICAL gate before image push (RFC #388 PR-2) - #35

Merged
HongmingWang-Rabbit merged 1 commit into
mainfrom
feat/trivy-image-scan
May 3, 2026
Merged

HongmingWang-Rabbit merged 1 commit into
mainfrom
feat/trivy-image-scan

Conversation

@HongmingWang-Rabbit

Copy link
Copy Markdown
Contributor

Summary

Belt-and-suspenders security gate inserted between boot-smoke and push-to-GHCR in the reusable `publish-template-image.yml`. Fails the publish on any HIGH or CRITICAL CVE in either the OS layer (apt deps) or the Python layer (pip deps). Image never reaches `:latest` if vulnerable, so no fresh workspace provision can pick up a known-bad layer.

Why pre-push

Same logic as boot-smoke — anything that fails here never poisons `:latest`. Catching post-push leaves a window where every fresh provision pulls the vulnerable image. Sequencing: build (load-only) → lint → static-import smoke → boot smoke → Trivy → push.

Why HIGH+CRITICAL only, with `ignore-unfixed: true`

Medium/low findings are too noisy in practice (~hundreds per Ubuntu base, mostly operationally non-actionable until the next Canonical respin). Promoting those to gate would drown signal in noise.

This becomes the matched pair with RFC #388 PR-2's second half (digest-pin `python:3.11-slim` base in each template's Dockerfile, deferred to per-template PRs):

  • Digest-pin avoids surprise base-bumps.
  • Trivy catches if the pinned digest itself accumulates fixable vulns over time.

Scope

Applies to all 4 supported template repos automatically since they all consume this reusable workflow (claude-code, hermes, openclaw, codex per PR #2536 prune set).

Test plan

  • YAML validates
  • Diff is additive (one new step + comment update on the next step's name)
  • CI green on this branch
  • After merge: next template image rebuild exercises the gate. Expected outcome: existing template images pass (Ubuntu 22.04 base + python:3.11-slim layer have no current HIGH/CRITICAL fixed CVEs; if they do, the failure is a real find we should action separately).
  • Spot-check: one operator-triggered `workflow_dispatch` against a clean template (codex is lightest) to confirm Trivy step runs and emits a clean result.

Refs

  • RFC: #388 (v3 §2 finding: most of bake-smoke shipped via #2275; Trivy + digest-pin remain unique)
  • Bench baseline (companion): #390
  • Thin AMI skeleton (companion): #391

🤖 Generated with Claude Code

Belt-and-suspenders security gate inserted between boot-smoke and
push-to-GHCR. Fails the publish on any HIGH or CRITICAL CVE in either
the OS layer (apt deps) or the Python layer (pip deps). Image never
reaches :latest if vulnerable, so no fresh workspace provision can
pick up a known-bad layer.

Why pre-push: same logic as boot-smoke — anything that fails here
never poisons :latest. Catching post-push leaves a window where
every fresh provision pulls the vulnerable image.

Why HIGH+CRITICAL only with ignore-unfixed=true: medium/low findings
are too noisy in practice (~hundreds per Ubuntu base, mostly
operationally non-actionable until the next Canonical respin).
Promoting those to gate would drown signal in noise. Once
Dockerfiles digest-pin their base image (RFC #388 PR-2 second
half), this becomes the matched pair: pin avoids surprise base-bumps;
Trivy catches if the pinned digest itself accumulates fixable vulns.

Applies to all 4 supported template repos automatically since they
all consume this reusable workflow (claude-code, hermes, openclaw,
codex per PR #2536 prune set).

Refs: Molecule-AI/molecule-controlplane#388

Co-Authored-By: Claude Opus 4.7 (1M context) <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.

1 participant