fix(deps): SCA pass — close all fixable vulns across source, images and CI pins - #377
Merged
Conversation
…nd CI pins Consolidates the 7 open Dependabot PRs and adds what they could not see. Source (Go): go-git/v5 5.19.1 -> 5.19.2, closing CVE-2026-71556 (HIGH, worktree ops follow symlinks) and CVE-2026-71557 (MEDIUM, malicious ref names write outside ref storage). Only source-side finding across trivy fs, govulncheck -mode=source, osv-scanner and pip-audit. Container images: alpine 3.23 -> 3.24, and refreshed digests for caddy:2.11.4(-builder), alpine/kubectl:latest and lambda/provided:al2023. gcloud 567.0.0 -> 579.0.0 with a recomputed SHA-256. caddy.Dockerfile built its binary with `xcaddy build "v2.11.3"` while both FROM lines were already on 2.11.4 — the third "2.11.x" site the file header warns about was missed. The shipped binary therefore carried CVE-2026-52844 and CVE-2026-52845, both fixed in 2.11.4. Release pipeline: Every docker/build-push-action step shared one unscoped `type=gha` cache namespace, including a 5-way image matrix all writing `mode=max` concurrently. simplecontainer/caddy:latest (== :2026.8.3, pushed today) ships alpine 3.20.4 with caddy v2.8.4 from an Apr 27 binary and no http.handlers.rate_limit module, so it cannot be the output of the current Dockerfile whose build-time module assertion would have failed. Cache scope is now per image, so base-image bumps actually reach published artifacts. Docs build: welder build-docs ran on python:3.9.18, EOL since Oct 2025 and inconsistent with the requirements.txt lockfile compiled for 3.12. Now python:3.12-slim (10110 -> 213 image vulns); docs build verified against the real lockfile. CI pins: actions/checkout v6.0.3 -> v7.0.1, actions/cache(+/save) v5.0.5 -> v6.1.0, actions/setup-go v6 -> v7.0.0, attest-build-provenance v4.1.0 -> v4.2.2, setup-buildx-action v4.1.0 -> v4.2.0, build-push-action v7.2.0 -> v7.3.0, scorecard-action v2.4.3 -> v2.4.4, codeql-action v4 SHA refresh. All are already node24, so the ESM majors change no runner requirement. One actions/cache pin carried a `# v4.3.0` comment on a v5.0.5 SHA; corrected. VEX re-triage: GO-2022-0635 / GO-2022-0646 were marked `status: fixed`, but both carry `introduced: 0` with no fix event in OSV, so `fixed` was never reachable and was acting as an indefinite suppression. Corrected to `not_affected` / `component_not_present` with the real evidence: aws-sdk-go v1.55.8 is in the module requirement graph but zero of its packages link into any binary. GO-2026-5932 re-confirmed against the current tree. Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
Cre-eD
requested review from
Laboratory,
smecsia and
universe-ops
as code owners
August 10, 2026 15:30
This was referenced Aug 10, 2026
Semgrep Scan ResultsRepository:
Scanned at 2026-08-10 18:08 UTC |
Security Scan ResultsRepository:
Scanned at 2026-08-10 18:08 UTC |
📊 Statement coverageMeasured on the documented included set (see
Baseline: |
…tes, docs images
Round 2 of the SCA pass, from a six-reviewer panel (4 Claude lenses, Codex,
Gemini). Two findings were defects in round 1's own diff.
Cache scoping was wrong, not just inconsistent:
Round 1 scoped the buildx GHA cache per image, but `github-actions` is a
matrix value in BOTH push.yaml (`matrix.image`) and branch-preview.yaml
(`matrix.target`) — so the two collided on one scope. branch-preview is
dispatchable from any branch, and `mode=max` exports builder stages, so a
preview build could seed the layer a release build restores, skipping the
SHA-256-verified gcloud and Pulumi downloads entirely. Scopes are now keyed
by trust tier: releases read/write `prod-*` only; staging and preview write
their own tier and read `prod-*` as a warm fallback, which is the safe
direction. branch-preview gets an explicit `cache_scope` so its fallback
matches push.yaml's image names (`cloud-helpers-aws`, not `cloud-helpers`).
The Pulumi integrity gate could not fail:
`... && sha256sum -c - && ... && strip … || true && upx … || true` parses as
`((chain || true) && upx) || true`. `&&`/`||` are equal precedence and
left-associative, and errexit does not apply to non-final commands in an
AND-OR list, so a checksum mismatch exited 0. Verified before and after:
a wrong expected hash now fails the build. The gcloud chain ends on a real
command and was already fail-closed. Brace-grouped in both Dockerfiles.
Caddy version is now single-sourced from the base image:
`$CADDY_VERSION` is set by the caddy base images themselves, so
`xcaddy build "${CADDY_VERSION}"` cannot skew from the image it builds in —
there is no second literal to forget, which is what shipped a 2.11.3 binary
on a 2.11.4 base. Both stages assert the built binary against their own
base's version, and certmagic-gcs joins rate_limit in the module assertions
(a silently dropped storage plugin means per-pod ACME state and Let's
Encrypt lockout). Negative-tested: a genuine builder/runtime digest skew
now fails the build.
cloud-helpers shipped a non-executable entrypoint:
actions/upload-artifact does not preserve the exec bit and push.yaml has no
chmod for this binary (branch-preview.yaml does). The published
simplecontainer/cloud-helpers:aws-latest has /cloud-helpers at 0644 with
`ENTRYPOINT ["/cloud-helpers"]`, so it cannot start. Asserted in the
Dockerfile so it holds whichever workflow builds it.
Docs example images were carrying the CVEs this pass claims to close:
docs/DEPENDENCIES.md lists example dirs in the tracked Docker surface, but
dependabot.yml only scanned the root level and rationalised the gap in a
comment. blog-platform pinned caddy 2.11.3 (CVE-2026-52844/52845 HIGH) and
six files pinned node 22.22.3 (CVE-2026-48618, CVE-2026-48933 HIGH). Both
bumped, the docker ecosystem now globs docs/docs/examples/**, and the
advanced-configs example moves off EOL python:3.9.
welder.yaml docs build no longer weakens the pin:
round 1 replaced python:3.9.18 with a floating python:3.12-slim and a bare
pip install, against the repo's own digest-pin and --require-hashes policy.
Now digest-pinned and hash-enforced, identical to push.yaml's docs build —
and both refreshed to the current digest, which round 1 missed.
VEX accuracy:
the GO-2026-5932 statement claimed x/crypto was "a direct dependency for
chacha20poly1305 only" while stamped re-confirmed. It is not: 24 x/crypto
packages link, including ssh, ssh/agent, pkcs12 and ocsp. The conclusion is
unchanged (openpgp linkage is 0) but the evidence now matches the tree, and
cites -buildvcs=false because a plain `go list` can exit non-zero and print
nothing, which greps identically to a clean result. The aws-sdk-go
statements now say which scope `component_not_present` refers to.
Docs contracts that this pass contradicted:
DEPENDENCIES.md said every not_affected is mirrored into osv-scanner.toml
and that a superseded one gets flipped to `fixed`. Both now qualified: the
mirror covers only advisories osv-scanner actually reports, and an advisory
with `introduced: 0` and no fix event can never reach `fixed`.
Also: codeql/scorecard pins carried `# v4` where every neighbour has full
semver; the SHA is v4.37.6.
Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
smecsia
approved these changes
Aug 10, 2026
universe-ops
approved these changes
Aug 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Full SCA pass over source, all 5 published container images, and the CI pin surface. Consolidates the 7 open Dependabot PRs into one review and adds 5 findings none of them could see.
Locally-built images,
origin/mainvs this branch, identical build inputs:--only-fixed(main → branch)kubectlcaddycloud-helpersgithub-actionsEvery one of the 12 remaining findings sits inside a third-party prebuilt binary already at its newest available version. Nothing fixable is left unfixed, and no suppression was added.
Fixed
github.com/go-git/go-git/v5GHSA-hc8v-wwc9-vgxm) worktree ops follow symlinksgithub.com/go-git/go-git/v5GHSA-qgq7-7hm3-q39j) malicious ref names write outside ref storagexcaddy build)alpinebase (×4 stages)py3-cryptography46.0.7 → 47.0.0caddy:2.11.4+-builderalpine/kubectl:latestlambda/provided:al2023python:3.9.18→python@sha256:229a2c5b(3.12-slim) (welderbuild-docs)CI pin bumps
actions/checkoutv6.0.3 → v7.0.1 (Dependabot proposed v7.0.0; v7.0.1 adds the--unsetescaping and default-input fixes) ·actions/cache+actions/cache/savev5.0.5 → v6.1.0 ·actions/setup-gov6 → v7.0.0 ·actions/attest-build-provenancev4.1.0 → v4.2.2 ·docker/setup-buildx-actionv4.1.0 → v4.2.0 ·docker/build-push-actionv7.2.0 → v7.3.0 ·ossf/scorecard-actionv2.4.3 → v2.4.4 ·github/codeql-actionv4 SHA refresh (comment corrected to# v4.37.6in round 2).All SHAs resolved through the GitHub git-ref API, annotated tags dereferenced to commits. Compatibility checked before applying:
checkoutv7,cachev6 andsetup-gov7 are all "migrate to ESM" releases. Both the old and new versions declareusing: node24, so no runner requirement changes onblacksmith-8vcpu-ubuntu-2204,ubuntu-24.04orubuntu-latest.checkoutv7's fork-PR block does not bite. v7 refuses to check out fork PR code underpull_request_target/workflow_rununlessallow-unsafe-pr-checkoutis set. This repo has nopull_request_targetat all; the threeworkflow_runworkflows either do not check out (security-scan-comment.yml,semgrep-comment.yml) or check out the base repo with noref:(verify-attestations.yml). The one PR-head checkout (dco.yml,ref: github.event.pull_request.head.sha) runs onpull_request, which the block does not cover.Stale pin comment
build-staging.ymlpinnedactions/cache@27d5ce7fwith a# v4.3.0comment, whilepush.yamlannotated the same SHA as# v5.0.5. The GitHub tag API confirms 27d5ce7f is v5.0.5; the v4.3.0 comment was wrong and made the pin look two majors older than it was. Corrected as part of the bump.Two findings Dependabot could not see
1.
caddy.Dockerfileshipped a binary one patch behind its own base imageThe file header says "Bumping requires editing all three '2.11.x' sites below (two FROMs + xcaddy)". Both
FROMlines were oncaddy:2.11.4, butxcaddy build "v2.11.3"was left behind, and the built binary is whatCOPY --from=builder /usr/bin/caddyputs in the final image. So the shipped Caddy was 2.11.3 and still carried CVE-2026-52844 + CVE-2026-52845. Dependabot tracksFROMlines, notxcaddyarguments, so this class of drift is invisible to it. Verified after the fix:2. Published images do not match the Dockerfiles that supposedly built them
simplecontainer/caddy:latestis byte-identical to:2026.8.3(bothsha256:83b0e6bb…, pushed 2026-08-10 11:52 UTC, today). What is inside it:Three things are wrong at once: alpine 3.20.4 where the pinned base resolves to 3.23.5, Caddy v2.8.4 where the Dockerfile builds 2.11.x, a
/usr/bin/caddytimestamped Apr 27, andhttp.handlers.rate_limitabsent. That last one is decisive:caddy.Dockerfileasserts on that module at build time (caddy list-modules | grep -qE '^http\.handlers\.rate_limit$'), so the published image cannot be the output of that Dockerfile. Itsapkdatabase also reports alpine 3.20.4 while a fresh build of the same file reports 3.23.5.Cost of that in the artifact consumers actually pull (
trivy image, published:latesttags):simplecontainer/caddy:latestsimplecontainer/github-actions:latestsimplecontainer/cloud-helpers:aws-latestsimplecontainer/kubectl:latestAmong caddy's 6 CRITICALs:
smallstep/certificatesv0.26.1 (CVE-2025-44005, CVE-2026-30836),grpcv1.64.0 (CVE-2026-33186),libcrypto3/libssl33.3.2-r1 (CVE-2026-31789), Gostdlibv1.23.4 (CVE-2025-68121) — plus the four Caddy admin-socket / fastcgi auth-bypass HIGHs (CVE-2026-27586/27587/27588/27590) thatcaddy.Dockerfile's own header claims to have closed. This matters more than usual because the SC composite actions run these images by floating tag rather than digest, so consumers inherit whatever:latestpoints at.Probable mechanism, and the change here. Every
docker/build-push-actionstep in the repo usedcache-from: type=gha/cache-to: type=gha,mode=maxwith noscope:, so all builds shared one cache namespace: the 5-way image matrix inpush.yaml(all writingmode=maxconcurrently), both images inbuild-staging.yml, and the preview matrix inbranch-preview.yaml. Concurrentmode=maxwriters into a single GHA cache scope is a known way to get cache-index collisions across unrelated Dockerfiles. This PR scopes the cache per build — see Round 2 below, which corrects the first attempt at this: scoping per image still letpush.yamlandbranch-preview.yamlcollide ongithub-actions, so the final design keys scopes by trust tier.I want to be precise about confidence: the observation above is proven by direct execution, and unscoped shared cache is the most plausible mechanism, but I have not reproduced the collision inside GitHub's cache backend. If the next release still publishes a stale caddy after this lands, the next place to look is the welder image-build path rather than buildx. Either way scoping the cache is correct on its own merits.
Documented unfixable (12 remaining, 0 CRITICAL)
Every residual finding lives in a third-party prebuilt binary that we do not compile, each already at the newest published version. No
.trivyignore, no VEX statement added for any of these — a scanner finding against a current upstream artifact is honest signal and should keep showing until upstream ships./usr/local/bin/kubectl(8) — upstream Kubernetes v1.36.3.golang.org/x/netv0.49.0 (CVE-2026-25681, CVE-2026-27136, CVE-2026-39821, CVE-2026-33814 HIGH; CVE-2026-25680, CVE-2026-42502, CVE-2026-42506 MEDIUM) andgolang.org/x/textv0.33.0 (CVE-2026-56852). Reachability:kubectlhere is a CI-driven CLI speaking TLS to a trusted, authenticated API server endpoint; the x/net HTTP/2 and proxy parsing paths need a hostile server or hostile URL, and the x/text issue is an infinite loop on invalid input (DoS of a short-lived CI process).alpine/kubectl:latestis already the newest digest. Closes when: upstream k8s rebuilds against x/net ≥ 0.55.0./usr/bin/caddy(3) — vendored into Caddy v2.11.4's own module graph.x/textv0.37.0 (CVE-2026-56852),grpcv1.81.0 (GHSA-hrxh-6v49-42gf, xDS RBAC fail-open + HTTP/2),cel-gov0.28.1 (GHSA-gcjh-h69q-9w9g,json:"-"fields readable from CEL). Reachability: Caddy is genuinely internet-facing, so these deserve the least benefit of the doubt — but both non-x/textfindings sit in features this build does not use. The grpc advisory is scoped tointernal/xds/rbacand the HTTP/2 server transport; Caddy links grpc as a client for its own internals and has no xDS RBAC authorization engine.cel-gois reached only throughext.NativeTypes(ParseStructTag("json"))over user-submitted CEL, which requires a CEL expression surface this build does not expose (the plugin set iscertmagic-gcs+caddy-ratelimit). Overriding Caddy's module graph via xcaddy would mean shipping a Caddy built against dependency versions upstream has not tested, which trades a narrow unreachable finding for a broad untested one. Closes when: Caddy 2.11.5+ ships./opt/google-cloud-sdk/bin/gke-gcloud-auth-plugin(1) — Google-built, gcloud 579.0.0 (newest).x/textv0.38.0, CVE-2026-56852. Reachability: a short-lived credential helper parsing Google's own token responses, not attacker-supplied text; the advisory is an infinite loop on invalid input. Closes when: Google rebuilds the plugin against x/text ≥ 0.39.0./usr/local/bin/aws-lambda-rie(4, grype only) — AWS-built, part oflambda/provided:al2023.x/sysv0.21.0 (GO-2026-5024),go-chi/chi/v5v5.2.4 (GO-2026-5774/5775/5777). Reachability: the Runtime Interface Emulator is a local-testing shim AWS ships in the base image; it is not the entrypoint (ENTRYPOINT ["/cloud-helpers"]) and never runs in Lambda. Closes when: AWS refreshes the base image.py3-cryptography47.0.0 (4, grype only) — Alpine's newest, ingithub-actions.GHSA-537c-gmf6-5ccf,GHSA-jwv3-5hgf-82ww,GHSA-g6cj-pr64-35w5(HIGH),GHSA-m2h6-j472-rp4c(MEDIUM). The fixes need 48.0.1 / 49.0.0 / 50.0.0, and Alpine ships 47.0.0-r0 on both 3.24 and edge — there is no branch to bump to. Reachability: pulled in by apk-managedaws-cliand used by gcloud auth; the PKCS#7 Bleichenbacher oracle and thepermittedSubtreeswildcard escape need attacker-controlled PKCS#7 blobs or hostile certificate chains, neither of which is on the CI credential path. Why not force it:pip install cryptography>=48over the apk package would break Alpine'sexternally-managed-environmentmarker and desynchronise theaws-cli/gcloud dependency set — worse than the finding. The 3.23 → 3.24 bump in this PR already moved it 46.0.7 → 47.0.0. Closes when: Alpine packages 48.0.1+.Note this is a real trivy/grype split worth knowing: trivy scores
py3-cryptographyas an Alpine package with no distro fix and stays quiet, grype catalogues the same files as a PyPI dist-info and matches the GHSA advisories. Neither is wrong. Both tools are run here for exactly this reason.VEX re-triage
vex/openvex.jsonv2 → v3. Nothing was added; two statements were corrected and one re-confirmed.fixednot_affected/component_not_presentfixednot_affected/component_not_presentnot_affected/vulnerable_code_not_presentx/cryptov0.54.0 is the latest releaseThe two
fixedstatements were not fixable, and that made them indefinite suppressions. OSV lists both aws-sdk-go advisories with{"introduced": "0"}and no fix event — AWS never patched the v1s3cryptoclient, the remediation is migrating to the V2 encryption client. Sofixeddescribed a state that could never be reached, while still suppressing the finding in any VEX-aware scanner. The priorimpact_statementalso asserted the module had "leftgo.modentirely through Go module pruning", which is not what the tree shows:component_not_presentis the accurate justification: the module is a requirement-graph edge from a transitivego.mod, no package from it reaches the linker, ands3cryptospecifically is never imported (S3 goes through aws-sdk-go-v2). Neithergovulncheck -mode=sourcenorosv-scannerreports these against the repo, so noosv-scanner.tomlmirror entry is needed; the header comment there is updated to say why they stay out and under what condition they would come back.osv-scanner.tomlkeeps exactly oneIgnoredVulnsentry (GO-2026-5932), unchanged.CODEOWNERSalready gates/vex/and/osv-scanner.toml.Dependabot reconciliation
All 7 open bot PRs are superseded by this one. Note
.github/dependabot.ymlis deliberately configured so majors fall outside the version groups and open individual PRs "for isolated review/testing" — that config is working as designed and is left untouched; this PR is the isolated review.go-git/v55.19.1 → 5.19.2 (gomod-security)actions/cache5.0.5 → 6.1.0# v4.3.0comment it would have left behindactions/cache/save5.0.5 → 6.1.0SBOM + Dependency Scan,Security Status) on the go-git baseline, which this PR clearsactions/checkout6.0.3 → 7.0.0--unsetescaping fixalpine3.23 → 3.2428bd5fe8…caddydigestf2b9891→ea6e54f198d47ea…/844f60b6…insteadTwo Dependabot alerts (#75 HIGH, #76 MEDIUM) are the only open ones and both close on merge.
Follow-ups, not done here
reecetech/version-incrementis pinned at2024.10.1;2026.8.4is out (28d33de033e97a304f77238d6a5db26039ca15d6). Not bumped on purpose: no CVE, and the diff touchesversion-increment.sh+shared.sh, the calver logic that decides every release tag inpush.yamlandbranch-preview.yaml. Changing release versioning inside an SCA PR is the wrong blast radius. Worth its own PR with a dry-run.simple-container-com/actionsrefs are inconsistent: 8 pins at0af5a697…andsemgrep.ymlat5061c0a2…, both commented# main. Not a vulnerability, but the drift is worth a sweep.Evidence
Source scanners, this branch
Base-image layers, old digest vs new
python base image comparison (welder build-docs)
3.12-slim over 3.13-slim on purpose:
docs/requirements.txtispip-compiled for Python 3.12 with--generate-hashes, so 3.12 is the version the lockfile was resolved against. The 67-finding gap is all LOW/MEDIUM distro noise. Build verified end to end against the real lockfile:(The pre-existing
ai-assistant/examples/*broken-link warnings are unchanged and unrelated.)mkdocs.ymluses onlysearch+mermaid2, no git-dependent plugins, so-slimis sufficient.Test plan
go mod tidyclean;go build ./cmd/github-actions ./cmd/cloud-helperssucceeds. Our owndist/github-actionslinksgolang.org/x/text v0.40.0(patched) pergo version -m.origin/mainand this branch; the before/after tables above come from those builds, not from published tags.caddyimage smoke-verified post-bump: v2.11.4, alpine 3.23.5, bothcaddy.storage.gcsandhttp.handlers.rate_limitregistered, so the Dockerfile's build-time module assertion passes.github-actionsimage build-time smoke test (pulumi version,gcloud version,gke-gcloud-auth-pluginpresent,aws --version,scsymlink) passes on alpine 3.24 + gcloud 579.0.0.python:3.12-slimagainst the real hashed lockfile.Round 2: multi-model review + preview build
Six independent reviewers (four Claude lenses, OpenAI Codex, Google Gemini). Every claim below was re-verified before acting on it; two findings were defects in round 1's own diff, and one review claim turned out to be a probe artifact.
Verified in a real pipeline
branch-preview.yamldispatched twice, once per commit. Both 13/13 jobs green, including the docker builds — the second run with fully cold caches, since every scope name changed.35cde9a)64ddbee)v2026.8.4-pre.35cde9a-preview.35cde9av2026.8.4-pre.64ddbee-preview.64ddbeegithub-actionsimagecloud-helpersimageThe CI-built image reports
alpine 3.24.1,Google Cloud SDK 579.0.0,pulumi v3.245.0,gke-gcloud-auth-pluginpresent. Against the published:latestfrom main (128 findings, 2 CRITICAL) that is 128 → 1, and the one residual is the documentedx/text v0.38.0inside Google's auth plugin. The gcloudSHA256pin verified inside a real build, which is the authoritative check on that value.Two defects in round 1's own diff
1. The cache scoping was wrong, not merely inconsistent. Round 1 scoped per image — but
github-actionsis a matrix value in bothpush.yaml(matrix.image) andbranch-preview.yaml(matrix.target), so they collided on one scope.branch-previewis dispatchable from any branch andmode=maxexports builder stages, so a preview build could seed the very layer a release build restores — and a cache hit means the SHA-256-verified gcloud and Pulumi downloads never execute. Round 1 separated staging but not preview, which made the gap easy to miss.Scopes are now keyed by trust tier: releases read and write
prod-*only; staging and preview write their own tier and readprod-*as a warm fallback, which is the safe direction (reading higher-trust cannot poison it).branch-previewgained an explicitcache_scopeso its fallback matches push.yaml's image naming (cloud-helpers-aws, notcloud-helpers) — Gemini and two Claude lenses independently flagged that mismatch. Expect one cold release build after merge; that is the scope rename, not a regression.2.
welder.yamlweakened a pin. Round 1 replacedpython:3.9.18with a floatingpython:3.12-slimand a barepip install, against this repo's own documented digest-pin +--require-hashespolicy — whilepush.yaml:376already pinned the same tool by digest. Now digest-pinned and hash-enforced, identical to the CI docs build, and both refreshed to the current digest (round 1 left push.yaml's three months stale).Pre-existing defects the panel surfaced
The Pulumi integrity gate could not fail the build.
... && sha256sum -c - && ... && strip … || true && upx … || trueparses as((chain || true) && upx) || true:&&and||are equal precedence and left-associative, and errexit does not apply to non-final commands in an AND-OR list. Verified both ways — with a deliberately wrong expected hash, the old shape exits 0, the brace-grouped shape now fails:The gcloud chain terminates on a real command and was already fail-closed, so the gcloud claim in this PR was accurate. Fixed in both github-actions Dockerfiles.
simplecontainer/cloud-helpers:aws-latestcannot start.actions/upload-artifactdoes not preserve the executable bit, andpush.yamlhas nochmodfor this binary —branch-preview.yaml:324does. The published image has/cloud-helpersat-rw-r--r--withENTRYPOINT ["/cloud-helpers"]. Asserted in the Dockerfile rather than a workflow so it holds whichever path builds it; the CI-built preview image now reports-rwxr-xr-x.Docs example images carried the CVEs this PR claims to close.
docs/DEPENDENCIES.mdlists example dirs in the tracked Docker surface, butdependabot.ymlscanned only the root level and rationalised the gap in a comment.blog-platform/caddy.Dockerfilepinned caddy 2.11.3 — the exact version whose CVEs this PR fixes at the root — and six files pinned node 22.22.3 (CVE-2026-48618, CVE-2026-48933, both HIGH; fixed in 22.23.0). All bumped to digests re-resolved against the live registry, the docker ecosystem now globsdocs/docs/examples/**, and one example moves off EOLpython:3.9.Caddy: version now single-sourced from the base image
Rather than keep three
2.11.xliterals guarded by a comment,xcaddynow builds"${CADDY_VERSION}"— the env var the caddy base images set themselves. There is no second literal to forget, which is precisely what shipped a 2.11.3 binary on a 2.11.4 base. Both stages assert the built binary against their own base's version, andcertmagic-gcsjoinsrate_limitin the module assertions (a silently dropped storage plugin means per-pod ACME state and Let's Encrypt lockout).Worth recording how this landed: my first attempt compared the binary to a hand-maintained
ARG, and the negative test showed it passing on a deliberate skew — self-consistent by construction, proving nothing. My second negative test was also invalid, because the digest I picked for "2.11.3" was actually the old 2.11.4 rebuild. Only the third attempt, against the genuinecaddy:2.11.3digest, demonstrated the gate firing:VEX corrections
The GO-2026-5932 statement claimed x/crypto was "a direct dependency for chacha20poly1305 only" while stamped re-confirmed against the current tree. It is not: 24 x/crypto packages link, including
ssh,ssh/agent,ssh/knownhosts,pkcs12andocsp, andpkg/api/secretsimportssshdirectly. The conclusion is unchanged — openpgp linkage is 0 — but understating the linked surface on the one artifact an auditor reads is worse than not writing it, andx/crypto/sshis the subpackage with the CVE history. Two reviewers caught this independently.The evidence commands now specify
-buildvcs=false: a plaingo list -depscan exit non-zero on a VCS error and print nothing, which greps identically to a clean result — the same masking failure mode as|| true.On the aws-sdk-go statements, one reviewer argued
component_not_presentcontradicts an impact_statement that mentionsgo list -m all, and proposedvulnerable_code_not_present. I keptcomponent_not_presentand made the scope explicit instead: for the shipped artifact the component genuinely is absent — 0 packages linked, 0go.sumentries, 0 in the built binary's BuildInfo — and the residualgo list -m alledge is a requirement-graph reference from a transitivego.mod.vulnerable_code_not_presentwould wrongly imply the component ships and only the vulnerable function is absent.Doc contracts this pass contradicted
DEPENDENCIES.mdstated that everynot_affectedis mirrored intoosv-scanner.toml, and that a superseded one gets flipped tostatus: fixed— the rule that produced the bug round 1 reverted. Both are now qualified: the mirror covers only advisories osv-scanner actually reports (an unused ignore is itself a finding), and an advisory withintroduced: 0and no fix event can never reachfixed.One review claim that did not survive
Codex reported a different gcloud SHA-256 than the pin. That was its own probe artifact: it fetched with
curl -C -(resume) against a leftover file, producing 97,127,837 bytes andgzip: trailing garbage ignored. A clean download is 96,066,973 bytes hashing toa9a7fbe5…, matching the pin — and CI's own verification passed inside the preview build. No change needed. Codex otherwise reported clean.Deliberately deferred
These are real but wrong to fold into a dependency PR:
AddFileToGitnow rejects a path whose leading component is a symlink (pkg/provisioner/common.gopasses.sc/cfg.yaml.template), where 5.19.1 accepted it — and that the test suite passes on both versions, so nothing would catch it. The repo has zeroos.Symlinkusage in tests. Reverting would reintroduce the CVEs, so the fix is a test plus an actionable error message, and it needs a decision on whether a symlinked.scis a supported layout. Worth its own issue.reecetech/version-incrementat2024.10.1(latest2026.8.4, SHA28d33de0). Its diff touches the calver logic that names every release tag.github-actions-staging.Dockerfileduplicates ~95 lines of its sibling under a "keep in sync" comment; this PR had to edit the alpine digest and both gcloud ARGs twice.# vX.Y.Zcomment, gcloud version/SHA parity across the two Dockerfiles). Round 1 found a# v4.3.0comment on a v5.0.5 SHA by hand; a 20-linegh apicheck would have caught it.# v4on the codeql pins is corrected to# v4.37.6here.DEPENDENCIES.mdclaimstrivy imageruns per published image — no trivy/grype step exists in any workflow; the shared scan is source-tree only. That is why the stale caddy binary went unnoticed for months.push.yaml. Adocker build --loadjob on a path filter would close it.certmagic-gcsv0.1.7→v0.1.8,golangci-lintv1→v2, pulumi SDK 11 minors,mermaid10.6.1 in the docs site.