feat/cve-gate #71

Merged
ryangr0 merged 2 commits from feat/cve-gate into main 2026-07-31 14:23:07 +00:00
Owner
No description provided.
feat(cve-gate): hardened gate image, CVE budgets and OpenVEX
All checks were successful
[Workflow] On Source Change / Guard: per-image .releaserc.cjs present (push) Successful in 3s
[Workflow] On Source Change / Determine Changed Directories (push) Successful in 21s
[Workflow] On Source Change / Determine changed images (push) Successful in 0s
[Workflow] On Source Change / Release (cve-gate, ops/docker/cve-gate) (push) Has been skipped
c4ac8d81ee
Ships the CVE gate and its dependencies WITHOUT touching any existing image
directory, so this change releases exactly one image: cve-gate.

That constraint is the point. on_source_change triggers on ops/docker/** and
builds a matrix entry per changed dir, so a change that edits all 17 Dockerfiles
fans out a 17-image release wave onto fringe-workstation — the node already
co-locating Harbor, its Postgres, the Envoy data plane and the dind DaemonSet on
8 threads, and the documented cause of the "Harbor outages" in runs 136/137/158.
The OCI label repoint that does touch all 17 is split into its own PR, to be
staged deliberately.

Safe here because none of it lives under ops/docker/ except the new image:
ops/vex/, ops/security/, docs/ and .forgejo/actions/ are not release triggers.

Contents:

- ops/docker/cve-gate — the gate, and the worked example for ADR-0006. DHI
  alpine-base with the -dev variant as a BUILD STAGE ONLY (apk exists there and
  nowhere else); grype copied from dhi.io/grype rather than curl|sh'd from a
  mutable branch at release time; non-root 65532; /tmp the only writable path;
  build-time assertions that the toolchain runs as the nonroot user.
- ops/security/cve-budgets.yaml — per-image ceilings that ratchet. New images
  start in warn, the pipeline measures them, the budget is set at the observed
  number, then it only goes down. cve-gate itself is the sole entry starting at
  enforce 0/0.
- ops/vex/ — OpenVEX as the only sanctioned suppression mechanism: hand-authored,
  PR-reviewed, justified from the closed vocabulary. Harbor's project-wide
  cve_allowlist stays empty.
- .forgejo/actions/cve-gate — complete, but NOT yet called. Wiring the call site
  in the same change that first builds the image would make cve-gate's own
  release depend on an image that does not exist. Step 2 restores the call site;
  until then no image is gated, and ADR-0005 says so rather than reading as a
  live control.

Also carries two fixes that trigger no builds:

- syft pinned to cyclonedx-json@1.6. Unpinned it emits 1.7; Dependency-Track
  tops out at 1.6 and returned 400 on every upload since run 133 (~50 releases).
  The step is fail-soft, so it emitted :⚠️: and exited 0 each time.
- Dependency-Track failures now split by class: 5xx/000 (outage) stays a warning,
  4xx (we sent something bad) becomes ::error:: — loud, still non-fatal. Treating
  both the same is how a schema rejection hid for a month.

Deletes ops/kyverno/ — it targeted ghcr.io/webgrip/* with a Fulcio identity, a
registry we no longer publish to verified by a mechanism we no longer use. The
live policy in homelab-cluster is correct; this copy was fiction that read as a
guarantee.

ADR-0004 supersedes ADR-0002 (keyless/GitHub -> OpenBao Transit), stating the
regressions plainly: no SLSA provenance, no transparency log. ADR-0005 (VEX +
budgets), ADR-0006 (hardened bases, proposed).

VIK-631

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
docs(cve-gate): DHI access is via the Harbor proxy, not a builder login
All checks were successful
[Workflow] On Source Change / Guard: per-image .releaserc.cjs present (push) Successful in 3s
[Workflow] On Source Change / Determine Changed Directories (push) Successful in 18s
[Workflow] On Source Change / Determine changed images (push) Successful in 0s
[Workflow] On Source Change / Release (cve-gate, ops/docker/cve-gate) (push) Has been skipped
79e451072e
Corrects the integration shape I documented. The Dockerfile, ADR-0006, the
cve-gate page and the roadmap all offered "docker login dhi.io on the builder" as
a first-class option. It is the wrong shape for this platform: builders
authenticate to nothing, because bases already resolve through Harbor's
pull-through cache via REGISTRY_DOCKERHUB/GHCR/MCR.

And no new account is needed. dhi.io advertises service="registry.docker.io" —
the same Docker identity service as Docker Hub — so the `dhi` proxy endpoint
reuses the credential Harbor already holds (webgrip/homelab-cluster
feat/harbor-dhi-proxy). The Dockerfile default stays dhi.io so a developer with
`docker login dhi.io` can still build locally.

ADR-0006 also gains the consequence this exposes and I had missed: DHI cannot be
pulled anonymously at all, unlike every stock base in use today, so a Docker
account becomes a HARD dependency of building any migrated image — not a
rate-limit optimisation. If that account lapses or the free tier is withdrawn,
every Stage 1/2 image stops building until it falls back to a stock base.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign in to join this conversation.
No reviewers
No milestone
No project
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!71
No description provided.