feat(security): require nox/taint-analysis plugin - #95
Conversation
The shared CI installs the taint plugin with continue-on-error, so a registry outage produced zero taint findings — indistinguishable from a clean scan. Declaring the plugin as required makes nox record the miss in meta.degradations, which the shared go-ci gate now fails on (klarlabs-studio/.github#57). Part of klarlabs-studio/.github#14. Claude-Session: https://claude.ai/code/session_01LMVPJFeTCEtUk2CSNBBBdK
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
Holding this PR — red CI, but not from the degradation gate
1. The red is pre-existing on
|
| run | nox | baselined | outcome |
|---|---|---|---|
main 2026-07-25 (original) |
1.16.1 | 10 | green |
main a287c3c1 re-run today |
1.23.0 | 0 | red — drift |
| this PR | 1.23.0 | 0 | red — drift |
main is red right now on its own. The other three repos in this sweep
(vorhut, kraftsport-coach, lexora) also ran 1.23.0 and their baselines matched
fine (482 / 310 / 57), so this is rollops-specific re-fingerprinting, not a
fleet-wide baseline wipe.
Fix (separate PR, needs a triage decision): nox baseline migrate --prune
to re-fingerprint the 5 entries while preserving their triage reasons.
2. This PR surfaces a real, previously invisible taint finding
This is the more interesting part, and it is exactly what
klarlabs-studio/.github#14 predicted — though via a different mechanism than
expected.
Diffing the nox-results artifacts between the main re-run and this branch
(same commit content, same nox 1.23.0, only .nox.yaml differs):
PR-only findings: 1
+ TAINT-004 high internal/pluginhost/cosign.go:32
MAIN-only findings: 0
main(plugin installed, not declared):taint findings = 0- this PR (plugin declared required):
taint findings = 1
Both logs show Installed nox/taint-analysis@0.7.0 (community) and both have
meta.degradations absent. So installing the plugin was not sufficient to
make it contribute findings — and nothing recorded a degradation. The assumed
failure mode was "registry outage -> missing plugin -> degradation recorded".
The mode actually observed here is quieter: plugin installs fine, contributes
nothing, no degradation, green check. Worth noting on
klarlabs-studio/.github#14 for the other repos that were relying on the CI
install step alone.
The finding itself — likely a false positive, but your call
TAINT-004 (CWE-22) high/high confidence
Path Traversal: keyPath flows from env_var (line 32) to os.ReadFile (line 36)
in VerifyArtifact
keyPath := os.Getenv(PublicKeyEnv) // ROLLOPS_PLUGIN_PUBLIC_KEY
if keyPath == "" { return nil }
pubPEM, err := os.ReadFile(keyPath)Reading a file at an operator-supplied path is the documented purpose of
ROLLOPS_PLUGIN_PUBLIC_KEY — it names the cosign public key. The source is a
process env var, not remote input, and it crosses no privilege boundary:
anyone who can set it can already read files as that process. I read it as a
false positive that wants an OpenVEX waiver with that reason rather than a code
change — but I have not baselined it, since (a) that is a triage call for you
and (b) the baseline needs migrate --prune first anyway.
Suggested order
nox baseline migrate --prune+ triage TAINT-004 → separate PR, turns
maingreen again.- Rebase and merge this one.
The .nox.yaml change itself is 9 insertions, 0 deletions, YAML-validated with
a duplicate-key-rejecting loader. It is not what is red.
Declares
nox/taint-analysisas a required plugin so a missing taint analyzeris visible instead of silent.
Why
The org is making nox the single owner of code-level SAST (source-to-sink
taint: injection, SSRF, path traversal) so
goseccan be dropped — tracked inklarlabs-studio/.github#14.
The shared CI installs the plugin with
continue-on-error: true, deliberately:a registry 404 that aborts the job would disable security scanning entirely
(as happened fleet-wide on 2026-07-19). The side effect was that nothing
downstream noticed when the plugin was absent — zero taint findings looked
exactly like a clean scan.
Two changes close that gap:
meta.degradationsinfindings.jsongo-ci.ymlgate fails whenmeta.degradationsis non-empty(feat(ci): fail the security gate when nox ran degraded .github#57, merged)
This PR supplies the declaration that makes the first one fire.
Change
Appends a
plugins.requiredblock to.nox.yaml. Purely additive — 9insertions, 0 deletions; the existing
scan.excludeblock and its comments areuntouched, and no
plugins:key existed before, so there is no duplicatemapping key.
Validated with a YAML loader that rejects duplicate keys (
yaml.safe_loadaccepts them silently, which has bitten this org before), asserting that the
parsed document actually contains
nox/taint-analysisunderplugins.required.Expected CI
ci / Security (nox)should stay green — the plugin installs normally, so thenew degradation gate must not fire. Reference: klarlabs-studio/axi-go#38.
Part of klarlabs-studio/.github#14.