Skip to content

fix(deps): SCA hardening — close every fixable dep vuln, lift coverage to 90.5 % - #387

Merged
Cre-eD merged 1 commit into
mainfrom
fix/sca-vulnerable-deps
Aug 21, 2026
Merged

fix(deps): SCA hardening — close every fixable dep vuln, lift coverage to 90.5 %#387
Cre-eD merged 1 commit into
mainfrom
fix/sca-vulnerable-deps

Conversation

@Cre-eD

@Cre-eD Cre-eD commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes every fixable dependency vulnerability in the repo across all severities, and lifts included-set statement coverage over the Gold-tier bar it was documented as already meeting.

before after
OpenSSF Scorecard Vulnerabilities 3 advisories (GO-2026-6238, GO-2026-6179, GO-2026-6180) 0
osv-scanner on go.mod 3 (2 packages) 0
trivy fs 2 HIGH + 1 LOW 0
Dependabot open alerts 1 (LOW) closes on merge
simplecontainer/caddy image 11 HIGH + 1 MEDIUM 1 MEDIUM
simplecontainer/cloud-helpers image 8 HIGH 0
simplecontainer/github-actions image 17 HIGH unchanged (upstream binaries)
simplecontainer/kubectl image 14 HIGH + 3 MEDIUM unchanged (upstream binary)
Included-set statement coverage 89.6 % 90.5 %

Deferred: 1 (cel-go, needs an upstream Caddy code change). Documented unfixable: 4 classes, all upstream-owned binaries.

The Scorecard Vulnerabilities check was the trigger, and all three advisories it reported land on dev-tool-only dependencies (delve and gofumpt via tools.go) — go list -deps ./... links zero packages from either module into anything we ship. They are still fixed rather than VEX'd, because a fix exists upstream and is non-breaking; VEX is for findings that cannot be fixed.

Fixed

Go modules

Package Old → New Advisory Sev Reported by
golang.org/x/mod v0.38.0 → v0.40.0 GO-2026-6179 / CVE-2026-56865 — tlog tile verification bypass HIGH Scorecard, osv-scanner, trivy fs
golang.org/x/mod v0.38.0 → v0.40.0 GO-2026-6180 / CVE-2026-56864 — unauthenticated hashes honoured in sumdb.Lookup HIGH Scorecard, osv-scanner, trivy fs
github.com/cilium/ebpf v0.11.0 → v0.22.0 GO-2026-6238 / CVE-2026-10722 / GHSA-xhgw-qwwf-pg32 — integer overflow in BTF parsing LOW Scorecard, osv-scanner, trivy fs, Dependabot

Neither could be fixed by bumping its parent: mvdan.cc/gofumpt v0.11.0 (latest) still requires x/mod v0.38.0, and go-delve/delve v1.27.1 (latest) still requires cilium/ebpf v0.11.0. Both are therefore raised by an explicit indirect requirement.

MVS collateral, no advisory of its own, listed for review completeness:

golang.org/x/crypto v0.54.0 → v0.55.0 · golang.org/x/net v0.57.0 → v0.58.0 · golang.org/x/text v0.40.0 → v0.41.0 · golang.org/x/tools v0.48.0 → v0.49.0 · golang.org/x/exp/typeparams · golang.org/x/telemetry · github.com/sirupsen/logrus v1.9.3 → v1.9.4

caddy.Dockerfile — 11 HIGH closed

Two independent causes, both fixed:

  1. Builder digest refresh 198d47e4bdeabce (same 2.11.4-builder tag, rebuilt 2026-08-20). The pinned digest carried Go 1.26.5; the current one carries Go 1.26.7. Since xcaddy build in the builder stage produces the binary that COPY --from=builder puts into the runtime image, the builder's toolchain is the shipped binary's stdlib — this alone closed 8 stdlib CVEs (CVE-2026-33818, -39821, -46600, -56853, -56858, -56859, -56860, -56862). Runtime digest refreshed alongside it (844f60b6df7f1c2f) so builder and runtime stay on the same tag push.
  2. Three xcaddy --replace directives lifting Caddy 2.11.4's own vendored deps past CVE-2026-46600 (x/net → v0.58.0), CVE-2026-56852 (x/text → v0.41.0) and GHSA-hrxh-6v49-42gf (grpc → v1.82.1). --replace and not --with: --with also writes a blank import, and none of these modules has a package at its module root, so it fails with cannot find module providing package.

The Dockerfile's existing build-time gates (caddy version | grep, caddy list-modules | grep for rate_limit and storage.gcs) all still pass, so a silently dropped plugin or a version skew would have failed the build.

cloud-helpers.aws.Dockerfile — 8 HIGH closed, image now clean

Every finding in this image came from /usr/local/bin/aws-lambda-rie, the base image's local-testing Runtime Interface Emulator: 9 MB of Go that AWS builds with an older toolchain (Go 1.26.5 at the pinned digest → 8 HIGH, all fixed in Go ≥ 1.26.6).

It is not reachable in this image. /lambda-entrypoint.sh execs it only when AWS_LAMBDA_RUNTIME_API is unset, and our ENTRYPOINT ["/cloud-helpers"] replaces that script outright. Nothing links it and no workflow invokes it — welder run debug-aws-cloud-helpers is runOn: host and uses the host's aws-lambda-rie, not the image's copy. So it is deleted, which is a fix rather than a suppression.

What this removes is docker run --entrypoint /lambda-entrypoint.sh <image> /cloud-helpers; the welder task is the supported path. Verified after the change: the image scans clean and /cloud-helpers still starts (it exits with the expected "did you pass SIMPLE_CONTAINER_CLOUD_HELPER_TYPE" error).

honnef.co/go/tools pinned to v0.6.1 via replace

cilium/ebpf v0.22.0 names honnef.co/go/tools v0.7.0 in its own go.mod, so MVS raises it. golangci-lint v1.64.8 does not compile against v0.7.0's analysis API and panics mid-run, exit 7:

typedness: panic during analysis: interface conversion: interface {} is nil, not *buildir.IR
  honnef.co/go/tools@v0.7.0/analysis/facts/typedness/typedness.go:59

That fails the golangci-lint run step in branch.yaml / push.yaml / branch-preview.yaml. ebpf needs staticcheck for its CI, not for any code we compile, and v0.22.0 is the fix for GO-2026-6238 so it cannot be held back — and a require line loses to ebpf's, so only replace pins it. honnef.co/go/tools v0.6.1 carries no advisories (checked against osv.dev). Removal condition is in the go.mod comment: golangci-lint v2 builds against v0.7.x, but that is a separate migration (module path rename + .golangci.yml schema change).

This is the reason to supersede Dependabot #385 rather than merge it#385 makes exactly this bump and would have broken lint on main on its own.

Deferred (breaking change, needs upstream)

GHSA-gcjh-h69q-9w9ggithub.com/google/cel-go v0.28.1 → v0.29.0, MEDIUM, inside the shipped caddy binary.

Not a version bump: v0.29.0 renames interpreter.Interpretable to InterpretableV2, and Caddy 2.11.4's modules/caddyhttp/celmatcher.go does not compile against it. Verified by attempting it:

caddy/v2@v2.11.4/modules/caddyhttp/celmatcher.go:506:5: cannot use []interpreter.Interpretable{…}
  (value of type []interpreter.Interpretable) as []interpreter.InterpretableV2 value in argument to interpreter.NewCall
caddy/v2@v2.11.4/modules/caddyhttp/celmatcher.go:529:5: (same)

Reachability: cel-go backs Caddy's expression request matcher. SC's generated Caddyfiles never emit expression (0 occurrences across the Caddyfile templates in pkg/clouds/pulumi/kubernetes/), so the CEL evaluator is only reachable if a consumer writes one by hand into lbConfig.extraHelpers / siteExtraHelpers. Closing condition: a Caddy release that adopts cel-go ≥ 0.29.0 — then drop this note and rebuild. Deliberately called out in a caddy.Dockerfile comment so the next digest refresh does not silently add it to the --replace list and break the build.

Documented unfixable (upstream-owned binaries, no action available)

  1. alpine/kubectl/usr/local/bin/kubectl — 8 HIGH stdlib@v1.26.5, 5 HIGH + 3 MEDIUM x/net@v0.49.0, 1 HIGH x/text@v0.33.0. kubectl is built by the Kubernetes release process; we cannot rebuild it. Refreshing the digest gains nothing and was measured, not assumed: the pinned digest 5d380d18 and the current latest (dae26110, = tag 1.36.3) are both kubectl v1.36.3 and produce identical finding counts, so the pin is left alone rather than churned. The Dockerfile's apk upgrade already clears all OS-package findings (0 alpine findings on a fresh build). Closing condition: a Kubernetes patch release rebuilt with Go ≥ 1.26.6, then refresh the digest.
  2. Google Cloud SDK binaries in github-actions — 8 HIGH in gcloud-crc32c (stdlib@v1.26.5) and 9 HIGH in gke-gcloud-auth-plugin (8 × stdlib@v1.26.5 + x/text@v0.38.0 / CVE-2026-56852). That is the image's entire finding set: base OS packages scan 0 and root/github-actions scans 0. gke-gcloud-auth-plugin is fetched by gcloud components install at build time, so it is already the freshest version Google publishes. Bumping the pin does not help, also measured rather than assumed: GCLOUD_VERSION 579.0.0 (pinned) and 581.0.0 (latest) both ship gcloud-crc32c built with go1.26.5 (go version on the extracted binaries). The pin stays at 579.0.0 and its GCLOUD_SHA256 was re-verified correct against a fresh download. Reachability: gcloud-crc32c is a checksum helper for gcloud storage / gsutil transfers, and no SC code path shells out to either (0 matches for gsutil across pkg/; GCP static-site uploads go through the Pulumi SDK's storage.BucketObject). Not deleted the way the Lambda RIE was, because a consumer-authored deploy hook can invoke gcloud storage, so the execute path is not provably empty. Candidate for an image-scope VEX statement once this repo has a convention for one — today vex/openvex.json covers Go-module advisories only.
  3. public.ecr.aws/lambda/provided:al2023 digest is deliberately NOT refreshed. The currently-tagged digest is worse than the pinned one: 30 HIGH vs 8. Anyone rebasing a Dependabot docker-digest bump onto this image should check the scan before taking it.
  4. GO-2026-5932 (golang.org/x/crypto/openpgp unmaintained) — unchanged not_affected, re-triaged below.

VEX re-triage

All three statements in vex/openvex.json re-checked against the current tree this pass; document bumped to version: 4, timestamp: 2026-08-21. No statement flipped, and each was re-confirmed with fresh evidence rather than carried forward by default:

Advisory Status This pass
GO-2022-0635 (aws-sdk-go v1 s3crypto) not_affected / component_not_present Re-confirmed. Still 0 matches in go.mod and go.sum; go mod why -m still reports "main module does not need"; go list -m all still resolves v1.55.8 only through a transitive go.mod.
GO-2022-0646 (same module) not_affected / component_not_present Re-confirmed, same evidence.
GO-2026-5932 (x/crypto/openpgp) not_affected / vulnerable_code_not_present Re-confirmed. go list -buildvcs=false -deps ./... still links 24 x/crypto packages and 0 openpgp packages; OpenPGP still goes through ProtonMail/go-crypto; no fix event upstream (introduced: 0, permanent "unmaintained" notice). Impact statement updated for the x/crypto v0.54.0 → v0.55.0 bump in this PR.

osv-scanner.toml needs no change: its single mirrored entry (GO-2026-5932) is still the only one of the three that osv-scanner actually reports, and it still filters correctly (Filtered 1 vulnerability from output). No new suppressions were added anywhere — no .trivyignore, no new VEX statement, no new IgnoredVulns entry.

Coverage: 89.6 % → 90.5 %

docs/TESTING.md claimed the Gold-tier test_statement_coverage90 criterion was Met. It was not: the main baseline artifact reads included=89.6, reproduced exactly locally. This PR closes the gap and makes the doc honest — the status column now carries the number, so the next drift is visible.

The included set is 5,975 statements, so 90 % needed 29 more covered statements. Seven test files add ~60, all of them exercising real logic with assertions that fail on a real regression rather than padding the denominator:

Test What it guards
pkg/security/tools/cosigntest/cosigntest_test.go (new, 208 lines) The whole package was at 0 % — see below.
pkg/clouds/gcloud/auth_test.go ReadSecretsProviderConfig must reject a bad keyRotationPeriod at read time (4 shapes), and must ignore it when provision: false. This is the contract the function's own comment describes: an already-provisioned secrets-provider stack is skipped by the provisioner, so a provisioner-only check never runs and a bad value would surface at a DR rebuild. Plus EffectiveNoncurrentVersionRetentionDays — nil means "apply the 30-day default", explicit zero means "disable the rule"; collapsing the two would silently drop the rollback horizon on every state bucket that never set the field.
pkg/clouds/compose/compose_test.go An absolute composeFilePath must re-root workingDir onto the file's own directory (relative build contexts resolve against workingDir, so honouring the caller's would point them at the wrong tree); ${VAR} interpolation must still read the process env under SkipResolveEnvironment; a missing file must not return a half-built project.
pkg/clouds/fs/fs_state_test.go init()'s two registrations, asserted through api.ReadProvisionerFieldConfig — the same lookup the descriptor reader uses. A typo'd key or a reader wired to the wrong struct otherwise only shows up as unknown provisioner field config type at read time.
pkg/clouds/docker/types_test.go RegistryRequiresAuth gates whether an imagePullSecret is generated at all: username-without-password must read as "no auth" rather than produce a half-formed secret, while both-present-but-empty must still count as "auth requested" so the deploy fails on a bad credential instead of silently pulling anonymously.
pkg/clouds/cloudflare/cloudflare_test.go ReadRegistrarConfig happy + error path, including that dnsRecords survives the yaml round-trip ConvertConfig performs.
pkg/clouds/mongodb/mongodb_test.go ReadAtlasConfig happy + error path, with the *float64 / *int fields asserted specifically: they distinguish "unset" from "explicitly zero" and must survive the round-trip, and unset ones must stay nil so downstream defaults apply.

Why cosigntest got tests instead of an exclusion

pkg/security/tools/cosigntest was the single largest uncovered block in the included set (42 statements, 0 %) because Go attributes coverage per test binary, and this package is a harness consumed only by other packages' tests (pkg/security/provenance, pkg/security/sbom).

Adding it to the pkg/util/test/* exclusion category would have been the cheap way to clear the number, and it would have been wrong. The 0 % is a real gap: the package generates a /bin/sh script, and three retry suites silently depend on its shell quoting, its cross-process invocation counter, and which stream it writes the Rekor conflict marker to. A break there turns those suites green for the wrong reason. So the new tests drive the stub through tools.ExecCommand — the exact function signing.RunCosignWithRetry calls — so stdout and stderr stay separated the way they do in production, and they include:

  • the ConflictOnStdout case asserting stderr is non-empty but does not contain the marker, so a stdout-classification bug cannot pass because the marker leaked onto both streams;
  • a FailStderr body containing a single quote — the exact input that broke an earlier harness by terminating the generated script early;
  • shellQuote round-tripped through /bin/sh itself, including a metacharacter payload, because string equality alone would not catch a quoting form the shell re-splits or expands;
  • DelayEach vs DelayFirst asserted per invocation, which is what distinguishes a fresh per-attempt timeout from one budget shared across attempts;
  • RekorConflictStderr checked against the [POST /api/v1/log/entries][409] shape the retry classifier actually anchors on, so a drifted fixture cannot quietly stop exercising the retry path.

docs/TESTING.md records why it is not excluded, next to the exclusion table.

Also in this PR

pkg/clouds/aws/helpers/ct_enrichment_test.go — two staticcheck SA1012 findings (never pass a nil Context) that surface on this branch but not on main. Fixed properly rather than silenced: the cases assert that lookupTriggeringEvents short-circuits before any AWS call, so they now pass an already-cancelled context instead of nil — a regression that stops short-circuiting fails with context.Canceled instead of reaching the network.

Pre-existing lint drift, deliberately left alone: golangci-lint run --fix (the exact CI invocation) rewrites 19 unrelated files on main today — gci import ordering plus missing goheader SPDX headers in pkg/api/secrets/ciphers/x25519.go, x25519_test.go and pkg/clouds/pulumi/aws/permissions_boundary.go. CI is green because --fix repairs them in the workspace and never commits them. Worth a separate cleanup PR; folding 19 files of import churn into an SCA diff would only make this one harder to review.

Dependabot reconciliation

PR Action
#385 bump github.com/cilium/ebpf 0.11.0 → 0.22.0 Superseded — close. Same bump, plus the honnef/golangci-lint fallout it would have hit alone (see above).
#382 bump caddy from 198d47e to c7ae802 Close or rebase. Already stale: the caddy tags were rebuilt 2026-08-20 and this PR pins the resulting digests directly (4bdeabce builder / df7f1c2f runtime), so #382 conflicts and targets an older push.
#380 github-actions group, #381 reecetech/version-increment, #378 node 22-alpine → 26-alpine Left open. Separate docker / actions version stream per .github/dependabot.yml; no overlap with this diff.

Open Dependabot alerts: 1 (github.com/cilium/ebpf, LOW, fix 0.22.0). Closes automatically once this lands on main. The two x/mod advisories never opened an alert — Dependabot did not surface them — which is precisely why the Scorecard / osv-scanner / trivy cross-check matters and why alert state alone is not the source of truth.

.github/dependabot.yml needs no change: both language ecosystems (gomod at /, pip at /docs) and both version ecosystems (docker, github-actions) are already configured.

Evidence

Source scans, before → after
# osv-scanner scan source --lockfile=go.mod     (the scanner OpenSSF Scorecard uses)
BEFORE  github.com/cilium/ebpf@0.11.0   GO-2026-6238, GHSA-xhgw-qwwf-pg32
        golang.org/x/mod@0.38.0         GO-2026-6179, GO-2026-6180
        (+ GO-2026-5932 filtered by osv-scanner.toml)
AFTER   CLEAN
        (+ GO-2026-5932 filtered by osv-scanner.toml — still the only mirrored entry)

# trivy fs --severity CRITICAL,HIGH,MEDIUM,LOW
BEFORE  HIGH  golang.org/x/mod@v0.38.0      CVE-2026-56864   fix=0.40.0
        HIGH  golang.org/x/mod@v0.38.0      CVE-2026-56865   fix=0.40.0
        LOW   github.com/cilium/ebpf@v0.11.0 CVE-2026-10722  fix=0.22.0
AFTER   CLEAN   (0 findings; docs/requirements.txt also 0)

# reachability of the two fixed modules — neither links into anything we ship
go list -buildvcs=false -deps ./... | grep -c '^golang.org/x/mod'        -> 0
go list -buildvcs=false -deps ./... | grep -c '^github.com/cilium/ebpf'  -> 0
Image scans — built locally from this branch vs from origin/main

Both sides built from the same Dockerfiles at the same moment, so this is apples to apples rather than a comparison against the published :latest tags (which lag the current Dockerfiles and are much worse — caddy 178 findings, cloud-helpers 72, github-actions 151, kubectl 92; the next release build closes that gap regardless).

All four images rebuilt with docker build --no-cache. That matters: a first pass reported 48 phantom python3 findings in github-actions because BuildKit reused a cached apk update && apk upgrade && apk add layer (the layers came into the local store from pulling the published image for the "before" scan), so the image kept python3 3.14.5-r0 while alpine v3.24/main already served 3.14.7-r1. Fresh builds — and CI runners — install the current package. Worth knowing before trusting any local image scan in this repo.

caddy — docker build -f caddy.Dockerfile
  origin/main   HIGH=11 MEDIUM=1
                x/net@v0.55.0     CVE-2026-46600
                x/text@v0.37.0    CVE-2026-56852
                grpc@v1.81.0      GHSA-hrxh-6v49-42gf
                stdlib@v1.26.5    CVE-2026-33818 -39821 -46600 -56853 -56858 -56859 -56860 -56862
                cel-go@v0.28.1    GHSA-gcjh-h69q-9w9g  (MEDIUM)
  this branch   MEDIUM=1
                cel-go@v0.28.1    GHSA-gcjh-h69q-9w9g  <- deferred, upstream-breaking
  gates:        caddy version -> v2.11.4 ; http.handlers.rate_limit + caddy.storage.gcs present
  OS packages:  0 both sides (apk upgrade already handled it)

cloud-helpers — docker build -f cloud-helpers.aws.Dockerfile
  origin/main   HIGH=8      all in usr/local/bin/aws-lambda-rie (stdlib@v1.26.5)
  this branch   0 findings  amazon OS 0 ; /cloud-helpers 0 ; RIE removed
  smoke:        /cloud-helpers starts (exits on missing SIMPLE_CONTAINER_CLOUD_HELPER_TYPE)

kubectl — docker build -f kubectl.Dockerfile
  this branch   HIGH=14 MEDIUM=3   all in usr/local/bin/kubectl (upstream)
                alpine OS packages: 0
  digest check  pinned 5d380d18 and latest dae26110 are both kubectl v1.36.3,
                identical finding counts -> pin left alone

github-actions — docker build -f github-actions.Dockerfile
  this branch   HIGH=17     alpine OS 0 ; root/github-actions 0
                gcloud-crc32c            8 HIGH  stdlib@v1.26.5      (upstream)
                gke-gcloud-auth-plugin   9 HIGH  stdlib@v1.26.5 + x/text@v0.38.0  (upstream)
  unchanged vs origin/main — neither the alpine base nor the gcloud pin moved,
  and our binary scans 0 on both sides.
  smoke:        pulumi version / gcloud version / gke-auth-plugin present /
                aws --version / sc symlink all pass in-build

our own Go binaries, scanned directly (trivy rootfs + grype --only-fixed)
  dist/github-actions   go1.26.6   trivy 0 / grype 0
  dist/cloud-helpers    go1.26.6   trivy 0 (in-image scan)
Coverage
# main baseline (coverage.yml artifact, run 32352899068, sha ec0f628)
included=89.6
full=28.9

# this branch, same filter as coverage.yml / welder.yaml
included: 90.5%
full:     29.0%

# gap arithmetic
included set = 5,975 statements ; 5,348 covered = 89.506%
90.0% needed +29 covered statements ; this PR adds ~60

Test plan

  • go build ./... — passes (locally with -p 2; the pulumi-gcp / pulumi-aws SDK packages want several GB per compile process, so full parallelism OOMs on a 19 GB machine).
  • go test ./... — passes except one pre-existing, environment-only failure: TestDetectRootDir/WithDetectRootDir_errors_when_no_git_repo_is_found_above_cwd. It asserts that WithDetectRootDir() errors when no git repo exists above cwd, and this machine has a .git above every temp dir (/home/creed/.git, plus a stray /tmp/.git from an unrelated worktree). Untouched by this PR — no file under pkg/api/git/ is in the diff — and CI runners have neither, so Run tests should be green.
  • golangci-lint run --fix --timeout 20m (the CI invocation) — exit 0.
  • bin/gofumpt -l — clean on every file in this diff.
  • go build of all five tools.go targets against the bumped deps — dlv (the risky one: cilium/ebpf v0.11.0 → v0.22.0 is a 11-minor jump and delve pins the old one), gofumpt, golangci-lint, mockery, go-jsonschema — all build.
  • docker build of caddy.Dockerfile, cloud-helpers.aws.Dockerfile, kubectl.Dockerfile, github-actions.Dockerfile — all succeed, with the in-Dockerfile smoke tests (caddy version, plugin greps, pulumi version, gcloud version, gke-auth-plugin presence, aws --version, sc symlink) passing.
  • govulncheck -mode=source ./...not run locally: it peaks around 13.5 GB RSS on this module. The govulncheck workflow gates this PR and scans unconditionally on a Go-touching diff, which this is.

CI on this PR

All checks green: Build Setup (clean, tools, schemas, lint, fmt), Run tests, govulncheck (reachability-aware), Analyze Go (go) / CodeQL, security / SBOM + Dependency Scan, security / Secret Scan, semgrep, Measure statement coverage, all five Build * jobs, and Fuzz HMAC cache parse path.

Two notes for anyone reading the run history:

  • TestDetectRootDir fails on my machine but passes in Run tests, exactly as expected — the assertion needs a temp dir with no git repo above it, and this laptop has one above every temp dir. Nothing under pkg/api/git/ is in the diff.
  • Fuzz HMAC cache parse path failed on the first attempt and passed on re-run. It was not a discovered crash: FuzzCacheGetPath reported context deadline exceeded at exactly the 30.10 s -fuzztime boundary and no crash corpus was written (No files were found with the provided path: pkg/security/testdata/fuzz/), which is Go's fuzz coordinator missing its shutdown grace period on a loaded runner. Reproduced locally on this branch at 2.1 M execs — PASS, no corpus. Nothing in pkg/security itself is in the diff; the only addition is a test in the pkg/security/tools/cosigntest subpackage, which pkg/security does not import.

The Scorecard Vulnerabilities check itself cannot run here — scorecard.yml triggers on push to main, the weekly cron, and branch_protection_rule, and the check queries osv.dev against the default branch. It clears on the next main push after merge. The same scanner (osv-scanner scan source --lockfile=go.mod, with osv-scanner.toml applied) is what reports 0 in the evidence above.

@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown

Semgrep Scan Results

Repository: api | Commit: 34bec3b

Check Status Details
⚠️ Semgrep Warning 2 warning(s), 6 total

Scanned at 2026-08-21 13:04 UTC

@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown

Security Scan Results

Repository: api | Commit: 34bec3b

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-21 13:05 UTC

@github-actions

github-actions Bot commented Aug 21, 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.5% 89.6% +0.9 pp
Full set (whole repo, transparency) 29.1% 28.9% +0.2 pp

Baseline: main @ 0e40fff

@Cre-eD
Cre-eD force-pushed the fix/sca-vulnerable-deps branch from c1abeda to 2966551 Compare August 21, 2026 13:02
…old bar it claimed

OpenSSF Scorecard's Vulnerabilities check reported three advisories. All
three land on dev-tool-only modules pulled in through tools.go, and all
three are fixable upstream, so they are fixed rather than VEX'd:

  golang.org/x/mod      v0.38.0 -> v0.40.0   GO-2026-6179, GO-2026-6180 (HIGH)
  github.com/cilium/ebpf v0.11.0 -> v0.22.0  GO-2026-6238 (LOW)

Neither could be fixed by bumping its parent: gofumpt v0.11.0 (latest)
still requires x/mod v0.38.0, and delve v1.27.1 (latest) still requires
ebpf v0.11.0. `go list -deps ./...` links zero packages from either
module into anything we ship, but a non-breaking upstream fix exists, and
VEX is for findings that cannot be fixed.

osv-scanner and trivy fs both go from 3 findings to 0.

The ebpf bump has fallout worth calling out. ebpf v0.22.0 names
honnef.co/go/tools v0.7.0 in its own go.mod, MVS raises it, and
golangci-lint v1.64.8 does not compile against v0.7.0's analysis API --
it panics mid-run ("typedness: panic during analysis: interface
conversion: interface {} is nil, not *buildir.IR") and exits 7, failing
the lint step in branch.yaml / push.yaml. ebpf needs staticcheck for ITS
CI, not for anything we compile, and a require line loses to ebpf's, so
honnef is pinned back with a replace directive. Dependabot #385 makes the
same ebpf bump and would have broken lint on main on its own.

Images, all four rebuilt with --no-cache and rescanned:

  caddy           11 HIGH + 1 MEDIUM -> 1 MEDIUM
  cloud-helpers   8 HIGH             -> 0
  github-actions  17 HIGH            -> unchanged (Google's gcloud binaries)
  kubectl         14 HIGH + 3 MEDIUM -> unchanged (upstream kubectl binary)

caddy: the pinned 2.11.4-builder digest shipped Go 1.26.5 and the tag has
since been rebuilt with Go 1.26.7. Since xcaddy in the builder stage
produces the binary COPY --from=builder puts into the runtime image, the
builder's toolchain IS the shipped stdlib -- refreshing the digest alone
closed 8 stdlib CVEs. Three xcaddy --replace directives lift Caddy's own
vendored x/net, x/text and grpc past CVE-2026-46600, CVE-2026-56852 and
GHSA-hrxh-6v49-42gf. --replace and not --with, because --with also writes
a blank import and none of those modules has a package at its root.

cloud-helpers: every finding was in /usr/local/bin/aws-lambda-rie, the
base image's local-testing Runtime Interface Emulator. /lambda-entrypoint.sh
execs it only when AWS_LAMBDA_RUNTIME_API is unset, and our ENTRYPOINT
replaces that script outright, so it never runs -- and the debug path that
does use a RIE (welder run debug-aws-cloud-helpers) is runOn: host and uses
the host's copy. Deleting it is the fix, not a suppression. Image now
scans clean and the binary still starts.

Deferred: cel-go 0.28.1 -> 0.29.0 (MEDIUM, GHSA-gcjh-h69q-9w9g) inside
the caddy binary. v0.29.0 renames interpreter.Interpretable to
InterpretableV2 and Caddy 2.11.4's celmatcher.go does not compile against
it -- an upstream code change. Reachability and the closing condition are
recorded in a caddy.Dockerfile comment so the next digest refresh does not
silently add it to the --replace list and break the build.

Documented unfixable, each measured rather than assumed: kubectl's own
binary (pinned digest and current latest are both v1.36.3 with identical
findings, so the pin is left alone), the gcloud SDK binaries (579.0.0 and
581.0.0 both ship gcloud-crc32c built with go1.26.5, so bumping the pin
buys nothing), and the lambda base digest, which is deliberately NOT
refreshed because the currently-tagged one is worse (30 HIGH vs 8).

VEX: all three statements re-triaged against the current tree with fresh
evidence, none flipped, document bumped to version 4. No new suppression
was added anywhere -- no .trivyignore, no new VEX statement, no new
osv-scanner.toml entry.

Coverage: docs/TESTING.md claimed the Gold-tier test_statement_coverage90
criterion was Met. It was not -- the main baseline reads 89.6%. Seven test
files take the included set to 90.5% and the doc now carries the number so
the next drift is visible.

The largest single gap was pkg/security/tools/cosigntest at 0%: Go
attributes coverage per test binary and that package is a harness consumed
only by other packages' tests. Excluding it would have cleared the number
and been wrong -- it generates a /bin/sh script whose quoting,
cross-process counter and stream selection three retry suites silently
depend on, so a break there turns those suites green for the wrong reason.
It gets tests instead, driven through tools.ExecCommand (the function
signing.RunCosignWithRetry actually calls) so stdout and stderr stay
separated the way they do in production.

Also fixes two staticcheck SA1012 findings (never pass a nil Context) that
surface on this branch but not on main, in the cases asserting
lookupTriggeringEvents short-circuits before any AWS call -- they now pass
an already-cancelled context, so a regression fails with context.Canceled
instead of reaching the network.

Signed-off-by: Dmitrii Creed <creeed22@gmail.com>
@Cre-eD
Cre-eD force-pushed the fix/sca-vulnerable-deps branch from 2966551 to cc6000c Compare August 21, 2026 13:04
@Cre-eD
Cre-eD merged commit 076224a into main Aug 21, 2026
23 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.

3 participants