Skip to content

fix(deps): bump github.com/go-git/go-git/v5 from 5.19.1 to 5.19.2 in the gomod-security group across 1 directory - #374

Closed
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/go_modules/gomod-security-b1fbbbfa24
Closed

fix(deps): bump github.com/go-git/go-git/v5 from 5.19.1 to 5.19.2 in the gomod-security group across 1 directory#374
dependabot[bot] wants to merge 1 commit into
mainfrom
dependabot/go_modules/gomod-security-b1fbbbfa24

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Aug 9, 2026

Copy link
Copy Markdown
Contributor

Bumps the gomod-security group with 1 update in the / directory: github.com/go-git/go-git/v5.

Updates github.com/go-git/go-git/v5 from 5.19.1 to 5.19.2

Release notes

Sourced from github.com/go-git/go-git/v5's releases.

v5.19.2

What's Changed

Full Changelog: go-git/go-git@v5.19.1...v5.19.2

Commits
  • 3eeb238 Merge pull request #2277 from go-git/checkout-v5
  • 008a78f git: worktree, make the filesystem wrapper a symlink-safe boundary
  • 2263fb5 Merge pull request #2268 from go-git/renovate/releases/v5.x-go-golang.org-x-t...
  • 77b7625 build: Update module golang.org/x/text to v0.39.0 [SECURITY]
  • 85ea767 Merge pull request #2267 from go-git/renovate/releases/v5.x-go-golang.org-x-n...
  • 198675a build: Update module golang.org/x/net to v0.56.0 [SECURITY]
  • 4a0e66d Merge pull request #2254 from pjbgf/v5-dotgit-ref-name-containment
  • 3b306ef storage: dotgit, align reference-name safety with refname_is_safe
  • f3d0cc1 storage: dotgit, reject path traversal in reference names
  • 979cfe9 Merge pull request #2262 from joshblum/joshblum/to-slash-v5
  • Additional commits viewable in compare view

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore <dependency name> major version will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself)
  • @dependabot ignore <dependency name> minor version will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself)
  • @dependabot ignore <dependency name> will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself)
  • @dependabot unignore <dependency name> will remove all of the ignore conditions of the specified dependency
  • @dependabot unignore <dependency name> <ignore condition> will remove the ignore condition of the specified dependency and ignore conditions
    You can disable automated security fix PRs for this repo from the Security Alerts page.

Bumps the gomod-security group with 1 update in the / directory: [github.com/go-git/go-git/v5](https://github.com/go-git/go-git).


Updates `github.com/go-git/go-git/v5` from 5.19.1 to 5.19.2
- [Release notes](https://github.com/go-git/go-git/releases)
- [Changelog](https://github.com/go-git/go-git/blob/main/HISTORY.md)
- [Commits](go-git/go-git@v5.19.1...v5.19.2)

---
updated-dependencies:
- dependency-name: github.com/go-git/go-git/v5
  dependency-version: 5.19.2
  dependency-type: direct:production
  dependency-group: gomod-security
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file priority: high High priority security Security-advisory dependency fix — merge-first labels Aug 9, 2026
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file security Security-advisory dependency fix — merge-first priority: high High priority labels Aug 9, 2026
@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

Semgrep Scan Results

Repository: api | Commit: 11f5089

Check Status Details
⚠️ Semgrep Warning 1 warning(s), 5 total

Scanned at 2026-08-09 04:37 UTC

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

Security Scan Results

Repository: api | Commit: 11f5089

Check Status Details
✅ Secret Scan Pass No secrets detected
✅ Dependencies (Trivy) Pass 1 total (no critical/high)
✅ Dependencies (Grype) Pass 1 total (no critical/high)
📦 SBOM Generated 523 components (CycloneDX)

Scanned at 2026-08-09 04:37 UTC

@github-actions

github-actions Bot commented Aug 9, 2026

Copy link
Copy Markdown

📊 Statement coverage

Measured on the documented included set (see docs/TESTING.md → Coverage scope). Observe-only — no regression gate is enforced yet.

Scope This PR main baseline Δ
Included set (Gold-tier denominator) 90.4% 90.4% +0.0 pp
Full set (whole repo, transparency) 28.3% 28.3% +0.0 pp

Baseline: main @ 442f351

@Cre-eD

Cre-eD commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Superseded by #377, a consolidated SCA pass that includes this bump. The same 5.19.1 -> 5.19.2 bump is in #377, which also closes Dependabot alerts #75 and #76.

Closing to keep the queue consistent with what landed. Full before/after scan evidence and per-finding reachability analysis are in #377.

@Cre-eD Cre-eD closed this Aug 10, 2026
@dependabot @github

dependabot Bot commented on behalf of github Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

This pull request was built based on a group rule. Closing it will not ignore any of these versions in future pull requests.

To ignore these dependencies, configure ignore rules in dependabot.yml

@dependabot
dependabot Bot deleted the dependabot/go_modules/gomod-security-b1fbbbfa24 branch August 10, 2026 15:30
Cre-eD added a commit that referenced this pull request Aug 11, 2026
…nd CI pins (#377)

## 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.

| | Fixed | Deferred | Documented unfixable |
|---|---|---|---|
| CRITICAL | 0 | 0 | 0 |
| HIGH | 1 source + 102 image | 0 | 8 |
| MEDIUM | 1 source + 32 image | 0 | 4 |
| LOW | 0 + 1 image | 0 | 0 |

Locally-built images, `origin/main` vs this branch, identical build
inputs:

| image | trivy (main → branch) | grype `--only-fixed` (main → branch) |
|---|---|---|
| `kubectl` | 21 → **8** | 39 → **11** |
| `caddy` | 28 → **3** | 37 → **9** |
| `cloud-helpers` | 64 → **0** | 27 → **4** |
| `github-actions` | 34 → **1** | 44 → **5** |
| **total** | **147 → 12** (−92%) | **147 → 29** (−80%) |

Every 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.

> **Read Round 2 at the bottom too.** A six-model review panel plus two
real preview builds followed this round; it corrected two defects in the
diff below (cache scoping, and a weakened pin in `welder.yaml`) and
found three pre-existing ones, including a Pulumi checksum gate that
could not fail and a published image that cannot start.

## Fixed

| Package | Old → New | CVE / advisory | Sev | Source |
|---|---|---|---|---|
| `github.com/go-git/go-git/v5` | 5.19.1 → 5.19.2 | CVE-2026-71556
(`GHSA-hc8v-wwc9-vgxm`) worktree ops follow symlinks | HIGH | trivy fs,
osv-scanner, Dependabot alert #75 |
| `github.com/go-git/go-git/v5` | 5.19.1 → 5.19.2 | CVE-2026-71557
(`GHSA-qgq7-7hm3-q39j`) malicious ref names write outside ref storage |
MEDIUM | trivy fs, osv-scanner, Dependabot alert #76 |
| Caddy binary (`xcaddy build`) | v2.11.3 → v2.11.4 | CVE-2026-52844,
CVE-2026-52845 (HIGH), CVE-2026-52846 (MEDIUM) | H×2 M×1 | trivy image |
| `alpine` base (×4 stages) | 3.23 → 3.24 | 30 distro CVEs → 0; also
lifts `py3-cryptography` 46.0.7 → 47.0.0 | H2 M8 L20 | trivy image |
| `caddy:2.11.4` + `-builder` | digest refresh | 55 → 25 in the base
layer | H12 M23 L20 | trivy image |
| `alpine/kubectl:latest` | digest refresh | 68 → 8 in the base layer |
H20 M28 L20 | trivy image |
| `lambda/provided:al2023` | digest refresh | 64 → 0 in the base layer |
H58 M5 L1 | trivy image |
| gcloud CLI | 567.0.0 → 579.0.0 | rolls up vendored Go deps in the
bundled binaries; SHA-256 recomputed from the real tarball | — | trivy
image |
| `python:3.9.18` → `python@sha256:229a2c5b` (3.12-slim) (welder
`build-docs`) | EOL runtime | 10110 → 213 image vulns (C248→4, H2293→23)
| C/H/M/L | trivy image |

### CI pin bumps

`actions/checkout` v6.0.3 → **v7.0.1** (Dependabot proposed v7.0.0;
v7.0.1 adds the `--unset` escaping and default-input fixes) ·
`actions/cache` + `actions/cache/save` v5.0.5 → **v6.1.0** ·
`actions/setup-go` v6 → **v7.0.0** · `actions/attest-build-provenance`
v4.1.0 → **v4.2.2** · `docker/setup-buildx-action` v4.1.0 → **v4.2.0** ·
`docker/build-push-action` v7.2.0 → **v7.3.0** · `ossf/scorecard-action`
v2.4.3 → **v2.4.4** · `github/codeql-action` v4 SHA refresh (comment
corrected to `# v4.37.6` in round 2).

All SHAs resolved through the GitHub git-ref API, annotated tags
dereferenced to commits. Compatibility checked before applying:

- **ESM majors are safe here.** `checkout` v7, `cache` v6 and `setup-go`
v7 are all "migrate to ESM" releases. Both the old and new versions
declare `using: node24`, so no runner requirement changes on
`blacksmith-8vcpu-ubuntu-2204`, `ubuntu-24.04` or `ubuntu-latest`.
- **`checkout` v7's fork-PR block does not bite.** v7 refuses to check
out fork PR code under `pull_request_target` / `workflow_run` unless
`allow-unsafe-pr-checkout` is set. This repo has no
`pull_request_target` at all; the three `workflow_run` workflows either
do not check out (`security-scan-comment.yml`, `semgrep-comment.yml`) or
check out the base repo with no `ref:` (`verify-attestations.yml`). The
one PR-head checkout (`dco.yml`, `ref:
github.event.pull_request.head.sha`) runs on `pull_request`, which the
block does not cover.

### Stale pin comment

`build-staging.yml` pinned `actions/cache@27d5ce7f` with a `# v4.3.0`
comment, while `push.yaml` annotated 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.Dockerfile` shipped a binary one patch behind its own base
image

The file header says *"Bumping requires editing all three '2.11.x' sites
below (two FROMs + xcaddy)"*. Both `FROM` lines were on `caddy:2.11.4`,
but `xcaddy build "v2.11.3"` was left behind, and the built binary is
what `COPY --from=builder /usr/bin/caddy` puts in the final image. So
the shipped Caddy was 2.11.3 and still carried CVE-2026-52844 +
CVE-2026-52845. Dependabot tracks `FROM` lines, not `xcaddy` arguments,
so this class of drift is invisible to it. Verified after the fix:

```
$ docker run --rm --entrypoint sh <built> -c 'cat /etc/alpine-release; caddy version; caddy list-modules | grep -E "rate_limit|gcs"'
3.23.5
v2.11.4 h1:XKxkMTgNSizEvKG6QHue6cAsFOteU2qA61w2tKkCWi0=
caddy.storage.gcs
http.handlers.rate_limit
```

### 2. Published images do not match the Dockerfiles that supposedly
built them

`simplecontainer/caddy:latest` is byte-identical to `:2026.8.3` (both
`sha256:83b0e6bb…`, pushed 2026-08-10 11:52 UTC, today). What is inside
it:

```
$ docker run --rm --entrypoint sh simplecontainer/caddy:latest -c \
    'cat /etc/alpine-release; caddy version; ls -la /usr/bin/caddy; caddy list-modules | grep -E "rate_limit|gcs"'
3.20.4
v2.8.4 h1:q3pe0wpBj1OcHFZ3n/1nl4V4bxBrYoSoab7rL9BMYNk=
-rwxr-xr-x 1 root root 41582744 Apr 27 08:56 /usr/bin/caddy
caddy.storage.gcs
```

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/caddy` timestamped **Apr 27**, and
**`http.handlers.rate_limit` absent**. That last one is decisive:
`caddy.Dockerfile` asserts 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. Its `apk`
database 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 `:latest` tags):

| published image | C | H | M | L | total |
|---|---|---|---|---|---|
| `simplecontainer/caddy:latest` | **6** | 69 | 68 | 27 | 170 |
| `simplecontainer/github-actions:latest` | **2** | 67 | 51 | 8 | 128 |
| `simplecontainer/cloud-helpers:aws-latest` | 0 | 73 | 13 | 1 | 87 |
| `simplecontainer/kubectl:latest` | 0 | 21 | 38 | 24 | 83 |

Among caddy's 6 CRITICALs: `smallstep/certificates` v0.26.1
(CVE-2025-44005, CVE-2026-30836), `grpc` v1.64.0 (CVE-2026-33186),
`libcrypto3`/`libssl3` 3.3.2-r1 (CVE-2026-31789), Go `stdlib` v1.23.4
(CVE-2025-68121) — plus the four Caddy admin-socket / fastcgi
auth-bypass HIGHs (CVE-2026-27586/27587/27588/27590) that
`caddy.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 `:latest` points
at.

**Probable mechanism, and the change here.** Every
`docker/build-push-action` step in the repo used `cache-from: type=gha`
/ `cache-to: type=gha,mode=max` with **no `scope:`**, so all builds
shared one cache namespace: the 5-way image matrix in `push.yaml` (all
writing `mode=max` concurrently), both images in `build-staging.yml`,
and the preview matrix in `branch-preview.yaml`. Concurrent `mode=max`
writers 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 let `push.yaml` and `branch-preview.yaml`
collide on `github-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/net` v0.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) and `golang.org/x/text` v0.33.0 (CVE-2026-56852).
*Reachability:* `kubectl` here 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:latest` is 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/text` v0.37.0 (CVE-2026-56852), `grpc` v1.81.0
(`GHSA-hrxh-6v49-42gf`, xDS RBAC fail-open + HTTP/2), `cel-go` v0.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/text` findings sit in
features this build does not use. The grpc advisory is scoped to
`internal/xds/rbac` and the HTTP/2 *server* transport; Caddy links grpc
as a client for its own internals and has no xDS RBAC authorization
engine. `cel-go` is reached only through
`ext.NativeTypes(ParseStructTag("json"))` over user-submitted CEL, which
requires a CEL expression surface this build does not expose (the plugin
set is `certmagic-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/text` v0.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 of
`lambda/provided:al2023`.** `x/sys` v0.21.0 (`GO-2026-5024`),
`go-chi/chi/v5` v5.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-cryptography` 47.0.0 (4, grype only) — Alpine's newest, in
`github-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-managed `aws-cli` and used by gcloud auth; the PKCS#7 Bleichenbacher
oracle and the `permittedSubtrees` wildcard 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>=48` over the apk package would break Alpine's
`externally-managed-environment` marker and desynchronise the
`aws-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-cryptography` as 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.json` v2 → v3. Nothing was added; two statements were
corrected and one re-confirmed.

| advisory | was | now | why |
|---|---|---|---|
| GO-2022-0635 (CVE-2020-8911) | `fixed` | `not_affected` /
`component_not_present` | see below |
| GO-2022-0646 (CVE-2020-8912) | `fixed` | `not_affected` /
`component_not_present` | see below |
| GO-2026-5932 (x/crypto/openpgp) | `not_affected` /
`vulnerable_code_not_present` | unchanged, evidence re-verified | grep
and call-path evidence still hold; `x/crypto` v0.54.0 is the latest
release |

**The two `fixed` statements 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 v1
`s3crypto` client, the remediation is migrating to the V2 encryption
client. So `fixed` described a state that could never be reached, while
still suppressing the finding in any VEX-aware scanner. The prior
`impact_statement` also asserted the module had "left `go.mod` entirely
through Go module pruning", which is not what the tree shows:

```
$ go list -m all | grep '^github.com/aws/aws-sdk-go '
github.com/aws/aws-sdk-go v1.55.8              # present in the requirement graph
$ go list -deps ./... | grep -c '^github.com/aws/aws-sdk-go/'
0                                              # zero packages linked into any binary
$ go mod why -m github.com/aws/aws-sdk-go
(main module does not need module github.com/aws/aws-sdk-go)
```

`component_not_present` is the accurate justification: the module is a
requirement-graph edge from a transitive `go.mod`, no package from it
reaches the linker, and `s3crypto` specifically is never imported (S3
goes through aws-sdk-go-v2). Neither `govulncheck -mode=source` nor
`osv-scanner` reports these against the repo, so no `osv-scanner.toml`
mirror 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.toml` keeps exactly one `IgnoredVulns` entry
(GO-2026-5932), unchanged. `CODEOWNERS` already gates `/vex/` and
`/osv-scanner.toml`.

## Dependabot reconciliation

All 7 open bot PRs are superseded by this one. Note
`.github/dependabot.yml` is 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.

| PR | What it proposed | Action | Why |
|---|---|---|---|
| #374 | `go-git/v5` 5.19.1 → 5.19.2 (`gomod-security`) | superseded |
identical bump; also closes Dependabot alerts #75/#76 |
| #371 | github-actions group, 8 updates | superseded | all 8 included,
same SHAs |
| #352 | `actions/cache` 5.0.5 → 6.1.0 | superseded | included; also
fixes the stale `# v4.3.0` comment it would have left behind |
| #351 | `actions/cache/save` 5.0.5 → 6.1.0 | superseded | included. Its
checks were red (`SBOM + Dependency Scan`, `Security Status`) on the
go-git baseline, which this PR clears |
| #334 | `actions/checkout` 6.0.3 → 7.0.0 | superseded, **improved** |
went to v7.0.1 instead; v7.0.0 predates the `--unset` escaping fix |
| #333 | `alpine` 3.23 → 3.24 | superseded | same digest `28bd5fe8…` |
| #326 | `caddy` digest `f2b9891` → `ea6e54f` | superseded, **improved**
| that digest was already stale (opened Jun 15; upstream rebuilt Jul 7).
Used the current `198d47ea…` / `844f60b6…` instead |

Two Dependabot alerts (#75 HIGH, #76 MEDIUM) are the only open ones and
both close on merge.

## Follow-ups, not done here

- **`reecetech/version-increment` is pinned at `2024.10.1`; `2026.8.4`
is out** (`28d33de033e97a304f77238d6a5db26039ca15d6`). Not bumped on
purpose: no CVE, and the diff touches `version-increment.sh` +
`shared.sh`, the calver logic that decides every release tag in
`push.yaml` and `branch-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/actions` refs are inconsistent**: 8 pins at
`0af5a697…` and `semgrep.yml` at `5061c0a2…`, both commented `# main`.
Not a vulnerability, but the drift is worth a sweep.

## Evidence

<details><summary>Source scanners, this branch</summary>

```
$ trivy fs --severity CRITICAL,HIGH,MEDIUM,LOW .
main:   HIGH   github.com/go-git/go-git/v5 v5.19.1 -> 5.19.2  CVE-2026-71556
        MEDIUM github.com/go-git/go-git/v5 v5.19.1 -> 5.19.2  CVE-2026-71557
branch: 0 findings

$ govulncheck -mode=source ./...
0 reachable; 1 module-level (GO-2026-5932, VEX not_affected)

$ osv-scanner scan source -L go.mod
main:   2 vulnerabilities (1 HIGH, 1 MEDIUM), 2 fixable
branch: No issues found   (GO-2026-5932 filtered, justified)

$ pip-audit -r docs/requirements.txt
No known vulnerabilities found
```
</details>

<details><summary>Base-image layers, old digest vs new</summary>

```
alpine:3.23 (old)   C=0 H=2  M=8  L=20  total=30
alpine:3.24 (new)   C=0 H=0  M=0  L=0   total=0
caddy:2.11.4 (old)  C=0 H=12 M=23 L=20  total=55
caddy:2.11.4 (new)  C=0 H=10 M=15 L=0   total=25
alpine/kubectl old  C=0 H=20 M=28 L=20  total=68
alpine/kubectl new  C=0 H=5  M=3  L=0   total=8
lambda al2023 old   C=0 H=58 M=5  L=1   total=64
lambda al2023 new   C=0 H=0  M=0  L=0   total=0
                                        217 -> 33
```
</details>

<details><summary>python base image comparison (welder
build-docs)</summary>

```
python:3.9.18     C=248 H=2293 M=5849 L=1720   total=10110   (EOL Oct 2025)
python:3.12       C=60  H=334  M=687  L=1178   total=2259
python:3.12-slim  C=4   H=23   M=86   L=99     total=212     <- chosen
python:3.13-slim  C=4   H=19   M=56   L=66     total=145
```

3.12-slim over 3.13-slim on purpose: `docs/requirements.txt` is
`pip-compile`d 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:

```
$ docker run --rm -v "$PWD/docs:/w" -w /w python:3.12-slim sh -c \
    'pip install -r requirements.txt && mkdocs build'
INFO - Documentation built in 2.86 seconds
```

(The pre-existing `ai-assistant/examples/*` broken-link warnings are
unchanged and unrelated.) `mkdocs.yml` uses only `search` + `mermaid2`,
no git-dependent plugins, so `-slim` is sufficient.
</details>

## Test plan

- `go mod tidy` clean; `go build ./cmd/github-actions
./cmd/cloud-helpers` succeeds. Our own `dist/github-actions` links
`golang.org/x/text v0.40.0` (patched) per `go version -m`.
- All 5 images build from a clean context on both `origin/main` and this
branch; the before/after tables above come from those builds, not from
published tags.
- `caddy` image smoke-verified post-bump: v2.11.4, alpine 3.23.5, both
`caddy.storage.gcs` and `http.handlers.rate_limit` registered, so the
Dockerfile's build-time module assertion passes.
- `github-actions` image build-time smoke test (`pulumi version`,
`gcloud version`, `gke-gcloud-auth-plugin` present, `aws --version`,
`sc` symlink) passes on alpine 3.24 + gcloud 579.0.0.
- docs build verified in `python:3.12-slim` against the real hashed
lockfile.
- Action SHAs verified against the GitHub git-ref API with annotated
tags dereferenced; no pin was hand-written.

---

# 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.yaml` dispatched 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.

| | round 1 (`35cde9a`) | round 2 (`64ddbee`) |
|---|---|---|
| preview version | `v2026.8.4-pre.35cde9a-preview.35cde9a` |
`v2026.8.4-pre.64ddbee-preview.64ddbee` |
| `github-actions` image | C0 **H1** M0 — total 1 | C0 **H1** M0 — total
1 |
| `cloud-helpers` image | — | C0 H0 M0 — **total 0** |

The CI-built image reports `alpine 3.24.1`, `Google Cloud SDK 579.0.0`,
`pulumi v3.245.0`, `gke-gcloud-auth-plugin` present. Against the
published `:latest` from main (128 findings, 2 CRITICAL) that is **128 →
1**, and the one residual is the documented `x/text v0.38.0` inside
Google's auth plugin. The gcloud `SHA256` pin 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-actions` is a matrix value in *both*
`push.yaml` (`matrix.image`) and `branch-preview.yaml`
(`matrix.target`), so they collided on one scope. `branch-preview` is
dispatchable from any branch and `mode=max` exports 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 read `prod-*` as a
warm fallback, which is the safe direction (reading higher-trust cannot
poison it). `branch-preview` gained an explicit `cache_scope` so its
fallback matches push.yaml's image naming (`cloud-helpers-aws`, not
`cloud-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.yaml` weakened a pin.** Round 1 replaced `python:3.9.18`
with a floating `python:3.12-slim` and a bare `pip install`, against
this repo's own documented digest-pin + `--require-hashes` policy —
while `push.yaml:376` already 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 … || true` parses 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**:

```
#8 1.650 sha256sum: WARNING: 1 of 1 computed checksums did NOT match
#8 ERROR: process "/bin/sh -c set -euo pipefail ..." did not complete successfully: exit code: 1
```

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-latest` cannot start.**
`actions/upload-artifact` does not preserve the executable bit, and
`push.yaml` has no `chmod` for this binary — `branch-preview.yaml:324`
does. The published image has `/cloud-helpers` at `-rw-r--r--` with
`ENTRYPOINT ["/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.md` lists example dirs in the tracked Docker surface,
but `dependabot.yml` scanned only the root level and rationalised the
gap in a comment. `blog-platform/caddy.Dockerfile` pinned 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 globs
`docs/docs/examples/**`, and one example moves off EOL `python:3.9`.

## Caddy: version now single-sourced from the base image

Rather than keep three `2.11.x` literals guarded by a comment, `xcaddy`
now 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, 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).

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 genuine `caddy:2.11.3` digest, demonstrated the gate firing:

```
ERROR: process "/bin/sh -c test -n \"${CADDY_VERSION}\" && caddy version | grep -qF \"${CADDY_VERSION} \"" did not complete successfully: exit code: 1
```

## 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`, `pkcs12` and `ocsp`, and
`pkg/api/secrets` imports `ssh` directly. 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, and
`x/crypto/ssh` is the subpackage with the CVE history. Two reviewers
caught this independently.

The evidence commands now specify `-buildvcs=false`: a plain `go list
-deps` can 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_present` contradicts an impact_statement that mentions
`go list -m all`, and proposed `vulnerable_code_not_present`. I kept
`component_not_present` and made the scope explicit instead: for the
shipped artifact the component genuinely is absent — 0 packages linked,
**0 `go.sum` entries**, 0 in the built binary's BuildInfo — and the
residual `go list -m all` edge is a requirement-graph reference from a
transitive `go.mod`. `vulnerable_code_not_present` would wrongly imply
the component ships and only the vulnerable function is absent.

## Doc contracts this pass contradicted

`DEPENDENCIES.md` stated that every `not_affected` is mirrored into
`osv-scanner.toml`, and that a superseded one gets flipped to `status:
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 with
`introduced: 0` and no fix event can never reach `fixed`.

## 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 and `gzip: trailing garbage
ignored`. A clean download is 96,066,973 bytes hashing to `a9a7fbe5…`,
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:

- **go-git 5.19.2 hardens worktree paths.** One lens demonstrated that
`AddFileToGit` now rejects a path whose leading component is a symlink
(`pkg/provisioner/common.go` passes `.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 zero `os.Symlink` usage 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 `.sc` is a supported layout. Worth its own issue.
- **`reecetech/version-increment`** at `2024.10.1` (latest `2026.8.4`,
SHA `28d33de0`). Its diff touches the calver logic that names every
release tag.
- **`github-actions-staging.Dockerfile` duplicates ~95 lines** of its
sibling under a "keep in sync" comment; this PR had to edit the alpine
digest and both gcloud ARGs twice.
- **A pin-consistency CI gate** (action SHA vs its `# vX.Y.Z` comment,
gcloud version/SHA parity across the two Dockerfiles). Round 1 found a
`# v4.3.0` comment on a v5.0.5 SHA by hand; a 20-line `gh api` check
would have caught it. `# v4` on the codeql pins is corrected to `#
v4.37.6` here.
- **`DEPENDENCIES.md` claims `trivy image` runs 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.
- **No PR-time build of any Dockerfile**; the first build happens
post-merge on `push.yaml`. A `docker build --load` job on a path filter
would close it.
- `certmagic-gcs` v0.1.7→v0.1.8, `golangci-lint` v1→v2, pulumi SDK 11
minors, `mermaid` 10.6.1 in the docs site.

---------

Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file priority: high High priority security Security-advisory dependency fix — merge-first

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant