Skip to content

feat(ci): scan published images for CVEs daily - #3

Merged
swibrow merged 1 commit into
mainfrom
feat/container-cve-scanning
Jul 26, 2026
Merged

feat(ci): scan published images for CVEs daily#3
swibrow merged 1 commit into
mainfrom
feat/container-cve-scanning

Conversation

@swibrow

@swibrow swibrow commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds .github/workflows/scan.yaml: a daily Trivy sweep of every published image, plus workflow_dispatch. One job per image per platform (13 jobs) on its native runner, so the manifest list resolves to the arch being scanned. HIGH/CRITICAL results upload to GitHub code scanning under a per-image/platform category. A CVE disclosed after an image ships only surfaces on a re-scan, so build.yaml structurally cannot catch it.

It reports, it does not gate. All 82 findings across the 7 published images are lang-pkgs; there are zero OS-package findings. They live in vendored upstream artefacts (the runner's .NET runtime, containerd/docker Go modules, the kubectl/rrda/gh binaries) where a patched upstream module exists but these images only consume a release build. Trivy calls those "fixable", so --ignore-unfixed does not filter them and a merge gate would block every PR on work this repo cannot do.

Also upgrades npm in the two Node-based images to clear what is actionable. The bundled npm ships tar, undici and brace-expansion CVEs under /usr/local/lib/node_modules/npm/, movable only by upgrading npm itself. Pinned to npm@12.0.1 with a Renovate annotation; verified against the 12.0.1 tarball (tar 7.5.19, undici 6.27.0, brace-expansion 5.0.7) and its engines (^24.15.0) against the 24.18.0 both images run.

image before after
infisical-mcp 5 (1 CRITICAL, 4 HIGH) 1 HIGH
sandbox-agent 7 (1 CRITICAL, 6 HIGH) 3 HIGH

Residual: brace-expansion CVE-2026-14257 needs 5.0.8, which no npm release bundles yet (Renovate will pick it up); the other two are gh's Go stdlib and grpc, pending a cli/cli rebuild.

Version bumps per the README rules: sandbox-agent 1.0.0 → 1.0.1 (PATCH rebuild). infisical-mcp 0.0.23 → 0.0.23-1, since upstream has not moved — and its version: field loses the Renovate annotation, because a -N suffix is a semver pre-release that would be "upgraded" straight back to the bare release. That is the trap actions-runner already documents; upstream tracking stays on INFISICAL_MCP_VERSION in the Dockerfile.

Not in this PR

claude-code is FROM ghcr.io/cloudsnacks/sandbox-agent:1.0.0@sha256:..., so its 7 findings clear only once that pin moves. It cannot ride along: build is a flat matrix over image × platform with no per-image ordering and merge waits on all of it, so claude-code would build against the currently published base. Needs a follow-up once sandbox-agent:1.0.1 publishes — Renovate's dockerfile manager should propose the digest, but the version: field needs the same -1 + de-annotation treatment applied to infisical-mcp here.

Test plan

  • hadolint -c .hadolint.yaml clean on both changed Dockerfiles
  • actionlint clean on scan.yaml (pre-existing warnings in build.yaml untouched)
  • Matrix generation dry-run emits 13 correct entries, incl. dev-desktop as amd64-only
  • All currently referenced tags resolve on GHCR (HTTP 200)
  • Both images built locally with container; metadata.yaml smoke tests pass; npm --version reports 12.0.1 and id -u is 1001
  • Rebuilt images exported to OCI and re-scanned to confirm the before/after counts above
  • CI green on both arches
  • First scheduled Scan run seeds code scanning (no analysis exists in this repo yet)

Add scan.yaml: a daily Trivy sweep of every published image, one job per
image per platform on its native runner so the manifest list resolves to
the right arch, reporting HIGH/CRITICAL findings to GitHub code scanning.
A CVE disclosed after an image ships only surfaces on a re-scan, so the
build workflow cannot catch it.

The scan reports rather than gates. Every current finding sits in a
vendored upstream artefact (Go binaries, the runner's .NET runtime, npm's
bundled dependencies) where a patched module exists but these images only
consume a release build, so a merge gate would block PRs on work this repo
cannot do.

Upgrade npm in the Node-based images to clear what is actionable: the
bundled npm carries tar, undici and brace-expansion CVEs that only move by
upgrading npm itself. infisical-mcp drops from 5 findings to 1 (including
the sole CRITICAL), sandbox-agent from 7 to 3; the rest need upstream
rebuilds.

infisical-mcp takes a -1 revision suffix since the upstream MCP version is
unchanged, and loses the annotation above its version field: a -N suffix
is a semver pre-release that Renovate would upgrade straight back to the
bare release. Upstream tracking stays on INFISICAL_MCP_VERSION.

claude-code inherits npm from sandbox-agent and needs a follow-up base
digest bump, which cannot ride along here: build runs a flat matrix with
no per-image ordering, so it would build against the currently published
base.

Signed-off-by: swibrow <15628653+swibrow@users.noreply.github.com>
@swibrow
swibrow merged commit 0a6fa29 into main Jul 26, 2026
7 checks passed
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