diff --git a/.context/DECISIONS.md b/.context/DECISIONS.md index 2e43443b..d4fb6e57 100644 --- a/.context/DECISIONS.md +++ b/.context/DECISIONS.md @@ -51,6 +51,20 @@ For significant decisions: ✗ No real alternatives existed --> +## [2026-07-25-194549] Vulnerability bar is zero CALLED findings, not zero total + +**Status**: Accepted + +**Context**: The 2026-06-13 remediation set the bar at 'zero vulnerabilities total, not merely zero called', clearing uncalled advisories too. GO-2026-5932 (golang.org/x/crypto/openpgp is unmaintained and unsafe by design) now makes that unreachable: it reports 'Fixed in: N/A' because the package is deprecated rather than patched, and it arrives transitively. + +**Decision**: Vulnerability bar is zero CALLED findings, not zero total + +**Rationale**: A criterion that cannot be met stops being a standard and starts being noise that gets waived by habit. Amending it explicitly keeps the gate meaningful. SPIKE does not call openpgp, so govulncheck exits 0 and CI passes with the finding present; vendoring or forking x/crypto to excise it costs more than the risk it removes. + +**Consequence**: The standing bar is zero CALLED vulnerabilities, plus a recorded justification in specs/vuln-remediation.md for every uncalled finding left in place. Clearing uncalled findings is still preferred wherever a fixed version exists. Revisit if an upstream stops depending on x/crypto/openpgp, or if the finding ever becomes reachable. + +--- + ## [2026-07-25-133218] Reserve spike/system/* namespaces against substring-matching policy patterns **Status**: Accepted diff --git a/.context/LEARNINGS.md b/.context/LEARNINGS.md index 4194ce8c..b4d6ebf9 100644 --- a/.context/LEARNINGS.md +++ b/.context/LEARNINGS.md @@ -22,6 +22,16 @@ DO NOT UPDATE FOR: +## [2026-07-25-194538] CI's Go - Lint job runs make audit, not make lint-go + +**Context**: CI on main failed at the 'Go - Lint' job while local 'make lint-go' was green throughout. The job name suggests golangci-lint, but .github/workflows/ci.yaml runs 'make audit'. + +**Lesson**: 'make audit' is a superset: go mod tidy -diff, go mod verify, gofmt check, go vet, staticcheck, govulncheck, and a CGO_ENABLED=0 golangci-lint run. 'make lint-go' is only the plain golangci-lint. A green 'make lint-go' therefore proves nothing about the CI lint job. Because govulncheck is in there, that job can also fail on a timer when a new advisory drops against an unchanged dependency graph, with no code change involved. + +**Application**: Run 'make audit' (not just 'make lint-go') before pushing anything that could touch the module graph, and when CI's lint job fails unexpectedly, check govulncheck first and compare go.mod between the passing and failing runs before assuming a code change caused it. + +--- + ## [2026-07-25-133240] Policy regex patterns are compiled at two sites, not one **Context**: Evaluating a proposed security patch that anchored policy patterns inside UpsertPolicy. It passed its own test but changed nothing in production. diff --git a/go.mod b/go.mod index c9b26ebe..92cfceba 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/spf13/cobra v1.10.2 github.com/spiffe/go-spiffe/v2 v2.6.0 github.com/spiffe/spike-sdk-go v0.19.9 - golang.org/x/term v0.43.0 + golang.org/x/term v0.44.0 gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.35.0 k8s.io/apimachinery v0.35.0 @@ -53,11 +53,11 @@ require ( github.com/x448/float16 v0.8.4 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/crypto v0.52.0 // indirect - golang.org/x/net v0.55.0 // indirect + golang.org/x/crypto v0.53.0 // indirect + golang.org/x/net v0.56.0 // indirect golang.org/x/oauth2 v0.34.0 // indirect - golang.org/x/sys v0.45.0 // indirect - golang.org/x/text v0.37.0 // indirect + golang.org/x/sys v0.46.0 // indirect + golang.org/x/text v0.39.0 // indirect golang.org/x/time v0.14.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20251222181119-0a764e51fe1b // indirect google.golang.org/grpc v1.79.3 // indirect diff --git a/go.sum b/go.sum index 2197488f..a4600605 100644 --- a/go.sum +++ b/go.sum @@ -157,47 +157,47 @@ go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc= go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= -golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc= +golang.org/x/crypto v0.53.0 h1:QZ4Muo8THX6CizN2vPPd5fBGHyogrdK9fG4wLPFUsto= +golang.org/x/crypto v0.53.0/go.mod h1:DNLU434OwVakk9PzuwV8w62mAJpRJL3vsgcfp4Qnsio= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= -golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= +golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ= +golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= -golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= +golang.org/x/net v0.56.0 h1:Rw8j/hFzGvJUZwNBXnAtf5sVDVt+65SK2C7IxCxZt5o= +golang.org/x/net v0.56.0/go.mod h1:D3Ku6r+V6JROoZK144D2XfMHFcMq/0zSfLelVTCFKec= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.34.0 h1:hqK/t4AKgbqWkdkcAeI8XLmbK+4m4G5YeQRrmiotGlw= golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4= -golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= +golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= -golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= -golang.org/x/term v0.43.0 h1:S4RLU2sB31O/NCl+zFN9Aru9A/Cq2aqKpTZJ6B+DwT4= -golang.org/x/term v0.43.0/go.mod h1:lrhlHNdQJHO+1qVYiHfFKVuVioJIheAc3fBSMFYEIsk= +golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= +golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc= +golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= -golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= +golang.org/x/text v0.39.0 h1:UbZz4pLOvn600D6Oh6GGEI6VAmndrEBLv8/6BEXzyus= +golang.org/x/text v0.39.0/go.mod h1:3UwRclnC2g0TU9x8PZiyfOajCd1zaUNHF9cvqcQZ+ZM= golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= -golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= +golang.org/x/tools v0.47.0 h1:7Kn5x/d1svx/PzryTsqeoZN4TZwqeH5pGWjefhLi/1Q= +golang.org/x/tools v0.47.0/go.mod h1:dFHnyTvFWY212G+h7ZY4Vsp/K3U4/7W9TyVaAul8uCA= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= diff --git a/specs/vuln-remediation.md b/specs/vuln-remediation.md index 0758376e..f54faeaa 100644 --- a/specs/vuln-remediation.md +++ b/specs/vuln-remediation.md @@ -1,5 +1,11 @@ # Spec: Remediate govulncheck-reported vulnerabilities +Advisories land on their own schedule, so this is a recurring exercise +rather than a one-off. Each round is recorded below with the advisory +that triggered it and what was done. + +# Round 1: toolchain and dependency sweep (2026-06-13) + ## Problem Statement `make audit` fails because `govulncheck` reports 10 vulnerabilities the @@ -61,3 +67,64 @@ Called vulnerabilities: require" residue (0 vulnerabilities total). - `make test` passes on the upgraded module graph (Go 1.26.4), including the grpc v1.79.3 minor bump. + +--- + +# Round 2: GO-2026-5970 (2026-07-25) + +## Problem Statement + +CI on `main` began failing at the "Go - Lint" job, which runs +`make audit`. The failure is not caused by any code change: run #300 +(2026-07-18) passed and run #301 (2026-07-25) failed, but the merge in +between never touched `go.mod` or `go.sum`, and `golang.org/x/text` +was `v0.37.0` on both sides. A new advisory was published in the +interval, so the build broke on a timer rather than on a commit. + +`GO-2026-5970` (infinite loop on invalid input in `golang.org/x/text`) +is **called** code, reached from +`recovery.sendShardsToKeepers` -> `net.Post` -> `norm.Form.*`, so +govulncheck exits non-zero. + +## Proposed Solution + +1. `golang.org/x/text` v0.37.0 -> v0.39.0 (fixes GO-2026-5970). +2. `golang.org/x/net` v0.55.0 -> v0.56.0 (clears the uncalled + GO-2026-5942 in the same pass). +3. `go mod tidy` to settle the graph, which transitively lifts + `x/crypto` v0.52.0 -> v0.53.0, `x/sys` v0.45.0 -> v0.46.0, and + `x/term` v0.43.0 -> v0.44.0. + +## File Surface + +- `go.mod`, `go.sum` (modified). No application-code changes. + +## Error / Edge Cases + +- **The "0 vulnerabilities total" bar from Round 1 is no longer + reachable.** `GO-2026-5932` reports that + `golang.org/x/crypto/openpgp` is unmaintained and unsafe by design, + with `Fixed in: N/A`. No version bump can clear it: the package is + deprecated rather than patched. It arrives transitively and SPIKE + does not call it, so govulncheck exits 0 and CI passes with it + present. + + Round 1's verification criterion is therefore amended, not merely + missed: the standing bar is **zero called vulnerabilities**, plus a + recorded justification for every uncalled one left behind. Clearing + uncalled findings remains preferred where a fixed version exists. + +## Non-Goals + +- Not vendoring or forking `x/crypto` to excise `openpgp`. It is + uncalled; the cost outweighs the benefit until an upstream drops it. +- No application-code changes. + +## Verification + +- `make audit` exits 0, including `go mod tidy -diff`, `go vet`, + staticcheck, govulncheck, and the `CGO_ENABLED=0` golangci-lint run. +- `govulncheck ./...` reports "No vulnerabilities found" under Symbol + Results; the only residue is the unfixable GO-2026-5932 under Module + Results. +- `make test` passes on the upgraded graph; `go build ./...` clean.