Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions .context/DECISIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions .context/LEARNINGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ DO NOT UPDATE FOR:
<!-- INDEX:END -->

<!-- Add gotchas, tips, and lessons learned here -->
## [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.
Expand Down
10 changes: 5 additions & 5 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
32 changes: 16 additions & 16 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
67 changes: 67 additions & 0 deletions specs/vuln-remediation.md
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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.
Loading