Add security CI baseline and adversarial recovery evals#80
Merged
Conversation
CI baseline (pinned official actions): - security.yml: CodeQL (Go), gosec SAST, govulncheck, gitleaks - dependency-review.yml on PRs - ci.yml test gate now uses -parallel 4 (port/socket exhaustion) - bump toolchain to go1.25.11 (clears GO-2026-5039/5037 stdlib vulns) - .gosec.json excludes accepted rule classes with per-rule justification Adversarial evals for the registry security logic: - FuzzRecoveryWireDecode: fuzz submit_badge/enroll_recovery/ recover_identity decode path; assert no panic and fail-closed - recovery exp beyond 30-min window rejected before nonce consume - binary lookup path does not leak external_id (privacy guard) Fix pre-existing go vet finding in dashboard public-stats test.
|
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. |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
The gitleaks GitHub Action needs a paid GITLEAKS_LICENSE for org repos; run the MIT-licensed binary directly instead (same scan, no license). dependency-review-action requires the repo Dependency Graph to be enabled; mark it continue-on-error so the prerequisite does not red CI, with instructions to gate it once the graph is on.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Hardens CI security and adds adversarial/fuzz EVAL coverage for the registry's
badge / identity-recovery security logic. No behavior change to the registry
beyond a Go toolchain bump.
Security CI baseline (new gating jobs)
New
security.yml(push + PR to main), official actions pinned to commit SHAs:codeqlgosec SAST-conf .gosec.json -severity medium -confidence mediumgovulncheckgitleaks secret scanNew
dependency-review.yml(PR only):actions/dependency-review-action,fail-on-severity: high..github/dependabot.yml(gomod + github-actionsweekly) already existed and is left as-is.
ci.yml: the existing test gate now runsgo test -race -parallel 4 ...(project convention — unbounded parallelism exhausts ephemeral ports/sockets
in the registry integration tests).
Suggested required status checks
test(existing),CodeQL (Go),gosec SAST,govulncheck,gitleaks secret scan,Dependency Review.Scanner findings + resolutions
GO-2026-5039(net/textproto) andGO-2026-5037(crypto/x509), both stdlib, both fixed in go1.25.11. Resolved by bumping the
toolchaindirective togo1.25.11; govulncheck then reports clean.a registry server; excluded in
.gosec.jsonwith per-rule justification(nothing blanket-disabled, no inline
#nosec). The-severity mediumgatestill fails the job on any future finding outside these classes.
G104(50, LOW) — unhandled errors on best-effort socket tuning /Close()in defers / error frames on connections already being dropped.
G115(9, HIGH) —uint32(len(...))of frames capped at 64KB(
wire.MaxMessageSize) and bounded JSON-decoded ids; cannot overflow.G304(6, MEDIUM) — reads of operator-supplied config/WAL/whitelist paths.G306(2, MEDIUM) —registry.json/ dashboard snapshot written 0644 bydesign (operator-readable, no secrets).
G114(1, MEDIUM) — dashboardhttp.Servewithout per-request timeouts;enforced at the proxy/breaker layer.
dashboard/zz_public_stats_test.go(
respused before error check — nil-deref onhttp.Getfailure). Fixed.Adversarial / fuzz evals added
Extends the PR #79 suite (no duplication):
FuzzRecoveryWireDecode(identity) — fuzzes the JSON decode +argument-extraction path of
submit_badge/enroll_recovery/recover_identity. Asserts no input panics and that, with verifiers stubbedto reject, no handler ever returns success (fail-closed) and the pinned
key/badge are never mutated. ~19k execs clean locally.
TestHandleRecoverIdentityRejectsExpiryBeyondWindow+ positive control —a recovery
Exppast the 30-minmaxRecoveryWindowis rejected before thenonce is consumed or the binding touched; an in-window
Expstill succeeds.TestHandleBinaryLookup_DoesNotLeakExternalID(directory) — privacyregression guard for the BINARY lookup path (the JSON path was already
covered): the decoded
LookupRespcarries an emptyexternal_ideven whenthe node holds a raw external identity.
Already covered by PR #79 (confirmed present, not duplicated): unauthenticated
owner-reclaim pubkey-rebind rejected with binding unchanged; same-key
re-register no-regression; nonce single-use + replay-across-reload; recovered
identity badge cleared (incl. WAL key-rotation delta replay path).
Validation (local, GOWORK=off, go1.25.11)
go build ./...clean;go vet ./...clean; new files gofmt-clean.go test -race -parallel 4 ./...— all packages pass.gosec -conf .gosec.json -severity medium -confidence medium ./...— 0 issues.govulncheck ./...— no vulnerabilities.FuzzRecoveryWireDecode— ran 10s, no panics, no fail-open.Repo-wide pre-existing gofmt drift (unrelated files) is intentionally left
untouched; no gofmt gate is added so CI stays green.