Skip to content

fix(ci): restore green CI -- bump Go to 1.26.6 and fix the stale e2e expectations - #25

Merged
jbrahy merged 2 commits into
mainfrom
fix/e2e-trust-base-expectations
Sep 12, 2026
Merged

fix(ci): restore green CI -- bump Go to 1.26.6 and fix the stale e2e expectations#25
jbrahy merged 2 commits into
mainfrom
fix/e2e-trust-base-expectations

Conversation

@jbrahy

@jbrahy jbrahy commented Sep 12, 2026

Copy link
Copy Markdown
Contributor

Two commits, both required to get main green. Neither is sufficient alone.

What was actually failing, and a correction

I initially attributed main's red CI to the stale e2e test. That was wrong, and the real cause matters more.

CI fails at govulncheck, on five Go standard library vulnerabilities in 1.26.5 (fixed in 1.26.6), reached through net/http, encoding/asn1 and crypto/tls.

The consequence is the important part. Step order in the workflow is:

success  go build
failure  govulncheck
skipped  go test (race + cover)   <- never runs

govulncheck runs before the tests, and its failure skips them entirely. Every CI run since those advisories landed has reported a failure without executing a single Go test.

That is how the stale expectation in 52184d5 (#23) reached main. Its description says "The DB-backed tests were not run locally (no MySQL); CI covers those." CI had already stopped running the tests it was said to cover. The test breakage was real and is reproducible locally -- it just was never what CI was reporting.

1. build: bump the Go toolchain to 1.26.6

go.mod pins the version and CI reads it via go-version-file, so one line moves both. Verified locally under 1.26.6: govulncheck reports no vulnerabilities.

Worth fixing separately: a security scanner that silently disables the test suite when it trips is the wrong ordering. Running go test before govulncheck, or continue-on-error on the scan, keeps test results visible while a stdlib advisory is outstanding. I have not changed the workflow here.

2. fix(api): restore the e2e block path

#23 changed new-device trust_weight from 1.00 to trust.TrustBase (0.50) but left TestEndToEnd_FullLifecycle asserting the old arithmetic:

3 x (BaseWeight 1.0 x trust 0.5 x scam 2.0) = 3.0  ->  "label", not "block"

The assertion message even said 3 fresh scam x trust 1.0 = 6.0, naming a constant that no longer existed.

Why not simply expect "label"

That would go green and delete the coverage. numberA reaching blocked is the only end-to-end exercise of the scoring block path -- numberC reaches block through an admin override, which bypasses scoring entirely. So this gives numberA enough reporters to block for real.

  • Six devices, not three. At TrustBase one scam report contributes 1.0 x 0.5 x 2.0 = 1.0, so six score 6.0 against a threshold of 5.0.
  • Not five. Five hits the threshold exactly, which is unsafe: reports age a fraction of a second before recompute reads them, so decay is a hair under 1.0 and 5.0 lands just below the >= test.
  • numberB goes from two reporters to three for the same reason. Two scored exactly SuspectThreshold -- a latent flake sitting on main today, one second of timing from failing.
  • Token distinctness becomes a set membership test rather than hand-enumerated pairs, which does not scale past three.
  • A guard up front fails loudly naming the constant that moved, if TrustBase, BaseWeight, BlockThreshold or SuspectThreshold change again.

The behaviour change #23 was hiding

A number now needs five fresh-device scam reports to auto-block, up from three. That is a consequence of #23, not of this PR, but it was invisible while both the assertion was stale and CI was skipping tests. If five is not the intended product behaviour, the fix belongs in the scoring constants rather than in this test.

Verification

Under Go 1.26.6, the full CI gate locally: govulncheck clean, gofmt clean, go vet clean, go test ./... -race -cover green.

Unrelated and untouched: SpamFilterUITests.testLookupFlow also fails on a pristine main.

jbrahy and others added 2 commits September 11, 2026 21:44
CI has been red on main since 52184d5 (#23). That commit changed
new-device trust_weight from 1.00 to trust.TrustBase (0.50) but left
TestEndToEnd_FullLifecycle asserting the old arithmetic: three fresh
scam reports scored 3.0, not 6.0, so numberA came back "label" and the
"want block" assertion failed. Its own message said "3 fresh scam x
trust 1.0 = 6.0", naming a constant that no longer existed.

Flipping the expectation to "label" would have gone green, but it would
have deleted the coverage: numberA reaching "blocked" is the only
end-to-end exercise of the scoring block path, since numberC reaches
"block" through an admin override that bypasses scoring entirely. So
give numberA enough reporters to block for real instead.

- Six devices, not three. At TrustBase one scam report contributes
  BaseWeight(1.0) * 0.5 * scam(2.0) = 1.0, so six score 6.0 against a
  threshold of 5.0. Five would hit the threshold EXACTLY, which is not
  safe: reports age a fraction of a second before recompute reads them,
  so decay is a hair under 1.0 and 5.0 lands just below the >= test.
- numberB moves from two reporters to three for the same reason. Two
  scored exactly SuspectThreshold and were one second from flaking.
- The token-distinctness check becomes a set membership test rather
  than hand-enumerated pairs, which does not scale past three.
- A guard up front fails loudly, naming the constant that moved, if
  TrustBase, BaseWeight, BlockThreshold or SuspectThreshold change
  again. #23 produced a bare "want block" that pointed at neither the
  cause nor the constant; this is what would have caught it.

Worth stating plainly, because the stale assertion was hiding it: a
number now needs FIVE fresh-device scam reports to auto-block, up from
three. That is a consequence of #23, not of this commit.

Verified: go test ./... -race -cover is green, twice, which is the exact
command CI runs. gofmt and go vet clean.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PBmEXErCWYt3WZCZKaS7m9
CI's govulncheck step fails on five Go standard library vulnerabilities
present in 1.26.5 and fixed in 1.26.6: GO-2026-6089, GO-2026-5972,
GO-2026-5026 and two others reached through net/http, encoding/asn1 and
crypto/tls from cmd/server, internal/push, internal/attest and
internal/api.

This is what has actually been failing CI, and it matters more than a
red badge: govulncheck runs BEFORE "go test (race + cover)", and its
failure SKIPS the test step entirely. Every run since these advisories
landed reported a failure without ever executing a single Go test. That
is how the stale e2e expectation in 52184d5 (#23) reached main claiming
"CI covers those" -- CI had stopped running the tests it was said to
cover.

Worth considering separately: a security scanner that silently disables
the test suite when it trips is the wrong ordering. Running go test
before govulncheck, or continue-on-error on the scan, would keep test
results visible while a stdlib advisory is outstanding.

go.mod pins the version and CI reads it via go-version-file, so this one
line moves both.

Verified under 1.26.6: govulncheck reports no vulnerabilities, gofmt and
go vet are clean, and go test ./... -race -cover passes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PBmEXErCWYt3WZCZKaS7m9
@jbrahy jbrahy changed the title fix(api): restore the e2e block path after the TrustBase change fix(ci): restore green CI -- bump Go to 1.26.6 and fix the stale e2e expectations Sep 12, 2026
@jbrahy
jbrahy merged commit cd21cd9 into main Sep 12, 2026
2 checks passed
@jbrahy
jbrahy deleted the fix/e2e-trust-base-expectations branch September 12, 2026 04:51
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.

1 participant