feat(security): restore SBOM ingestion, add OpenVEX + CVE budget gate #70
Closed
ryangr0
wants to merge 2 commits from
feat/harden-supply-chain into main
pull from: feat/harden-supply-chain
merge into: webgrip:main
webgrip:main
webgrip:feat/agent-runner-dhi-alpine
webgrip:feat/techdocs-builder-dhi
webgrip:feat/semrel-family-dhi-alpine
webgrip:feat/semantic-release-monorepo-dhi-base
webgrip:feat/semantic-release-dhi-base
webgrip:feat/node-ci-runner-dhi-base
webgrip:feat/helm-deploy-dhi-base
webgrip:feat/act-runner-dhi-base
webgrip:fix/promote-dash-candidate
webgrip:perf/consolidate-release-plumbing
webgrip:fix/helm-deploy-tool-bumps
webgrip:fix/candidate-keyed-by-version
webgrip:feat/promote-by-digest
webgrip:feat/cve-budgets-measured
webgrip:diag/measure-cve-budgets
webgrip:fix/techdocs-builder-zensical-conflict
webgrip:fix/semantic-release-rust-signed-reentry
webgrip:fix/node-ci-runner-signed-reentry
webgrip:docs/hardening-wave3-plan
webgrip:fix/techdocs-runner-pin-parent
webgrip:fix/mkdocs-runner-pin-parent
webgrip:fix/tauri-ci-runner-pin-parent
webgrip:fix/ci-runner-signed-cve-gate
webgrip:fix/helm-deploy-verify-downloads
webgrip:fix/techdocs-builder-annotate-stages
webgrip:fix/rust-ci-runner-pin-build-stage
webgrip:fix/rust-releaser-pin-toolchain
webgrip:fix/semantic-release-rust-pin-base
webgrip:fix/semantic-release-monorepo-pin-base
webgrip:fix/semantic-release-pin-base
webgrip:fix/playwright-runner-pin-base
webgrip:fix/act-runner-pin-act
webgrip:fix/node-ci-runner-pin-base
webgrip:fix/bump-workflows-pin-codeberg-bash
webgrip:fix/renovate-digest-aware-args
webgrip:docs/upstream-vex-in-harbor
webgrip:fix/harbor-sbom-honest-report
webgrip:fix/vex-aliases-and-unmatched-guard
webgrip:fix/gate-stderr-not-a-tty
webgrip:perf/drop-installer-actions
webgrip:fix/release-matrix-multiline-output
webgrip:fix/cve-gate-header-accuracy
webgrip:feat/release-manual-trigger
webgrip:fix/ci-runner-claude-code-and-renovate-annotation
webgrip:docs/adr-buildkitd-and-gate-as-step
webgrip:perf/release-verify-uses-buildkitd
webgrip:perf/cve-gate-as-a-step
webgrip:perf/ci-runner-bake-gate
webgrip:fix/cve-gate-volume-ownership
webgrip:fix/ci-runner-verify-helm-yq
webgrip:fix/cve-gate-scan-space
webgrip:chore/oci-labels-batch1
webgrip:perf/build-check-cli
webgrip:chore/forgejo-git-throughput-probe
webgrip:perf/ci-runner-bake-cosign-syft
webgrip:fix/cve-gate-seccomp-clone
webgrip:fix/cve-gate-pin-existing-version
webgrip:fix/cve-gate-readonly-inputs
webgrip:fix/cve-gate-moby-floor
webgrip:feat/cve-gate-static
webgrip:fix/cve-gate-vex-and-budget
webgrip:fix/cve-gate-staging-root
webgrip:ci/build-check-on-branches
webgrip:fix/cve-gate-dhi-registry
webgrip:feat/cve-gate
webgrip:fix/semrel-toolchain-one-source
webgrip:fix/semrel-fork-direct-binary
webgrip:renovate/actions-attest-build-provenance-3.x
webgrip:renovate/sigstore-cosign-installer-4.x
webgrip:renovate/github-codeql-action-4.x
webgrip:renovate/docker-login-action-4.x
webgrip:renovate/actions-create-github-app-token-3.x
webgrip:renovate/actions-attest-build-provenance-4.x
webgrip:copilot/fix-docker-build-and-push
webgrip:copilot/fix-1
No reviewers
No labels
pull-request
released
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set.
Reference
webgrip/infrastructure!70
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/harden-supply-chain"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The gate's own toolchain was the weakest link in it. The first version ran curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh at release time, in the job that decides whether an image is fit to sign: an unpinned script from a mutable branch, fetched over the internet, executed with the workspace and registry credentials in scope. A supply-chain hole inside a supply-chain control. Replaces it with ops/docker/cve-gate — which is both the gate and the worked example for ADR-0006, so every other image migration has something concrete to copy: - DHI alpine-base; the -dev variant is a BUILD STAGE ONLY. apk exists there and nowhere else, so nothing can be installed into a running gate container. - grype copied from dhi.io/grype (signed, has its own SBOM) rather than curl|sh. Located by find rather than an assumed path, so a layout change fails with a sentence instead of a cryptic COPY error. - jq + yq via apk in the build stage, installed into a single /out tree. - Runtime: no package manager, no curl, uid 65532, /tmp the only writable path (grype's DB cache) so it runs --read-only --cap-drop ALL --security-opt no-new-privileges. - Build-time assertions that grype/jq/yq execute, a shell exists, and the entrypoint reaches its own validation — all AS THE NONROOT USER. A gate that ships broken is worse than no gate: it reports "budget met" for an image nobody scanned. The gate logic moves out of the composite action into a POSIX sh entrypoint (the runtime has ash, not bash) with a three-way exit contract: 0 pass, 1 over budget in enforce mode, 2 could-not-run. 2 is deliberately not collapsed into either — a gate that failed to execute is not a gate that passed. cve-gate is the only image starting at mode: enforce, 0/0. If the image that decides whether everything else is fit to sign cannot meet the standard it enforces, the standard is not real. Two things this surfaced that gate all of ADR-0006's Wave 3: - dhi.io is free (Apache 2.0, Community tier) but NOT anonymous — /v2/ returns 401. Needs docker login, or preferably a `dhi` pull-through proxy in Harbor to match how REGISTRY_DOCKERHUB/GHCR/MCR are already routed. - Because of that, DHI digests cannot be resolved yet, so these bases are tag-pinned where every other base here is digest-pinned. Pin on first build. Also fixes two bugs found while wiring it up: - `docker start -a | tee` masked the exit code, so the gate would have always passed. Now reads PIPESTATUS[0]. - No bind mount: DOCKER_HOST targets the shared per-node dind DaemonSet over TCP, so -v ${GITHUB_WORKSPACE} would resolve on the DAEMON's filesystem. Workspace is copied in with docker cp instead. Includes a loud, self-limiting bootstrap escape (ALLOW_MISSING_GATE) for the window before cve-gate has ever been released — skipping a gate must never look like passing one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>Closing in favour of #74.
Everything here except the OCI-label repoint is superseded by #74, which carries newer versions of the same files — that is exactly what the conflict list shows (
cosign-sign-attest/action.yml, ADR-0005/0006,cve-gate.md,hardening-roadmap.md,cve-gate/Dockerfile). Merging this would revert three build fixes found in runs 188/192/194.The only unique content is the
org.opencontainers.image.{source,url,documentation}repoint across 17 Dockerfiles — verified as a pure three-line label change per file, nothing else. That is being re-cut as small batches, because a single PR touching all 17 produces 17 concurrent matrix builds (Forgejo ignoresstrategy.max-parallel) on fringe-workstation.No content is lost.
Pull request closed