Uh oh!
There was an error while loading. Please reload this page.
chore(gosec): reviewed per-site #nosec waivers for the 8 reported findings (18 real sites) - #427
Conversation
…dings (18 real sites) Each gosec finding got an individually reviewed inline waiver with a site-specific justification, so the advisory golangci job can go to zero and backend#1305 can later drop --issues-exit-code=0. The advertised backlog of 8 was an artifact of golangci-lint's default issues.max-same-issues=3: the 13 G304s share one message text, so only 3 surfaced per run (which 3 flapped with cache state). The real, uncapped backlog is 18: 4x G204, 13x G304, 1x G115. All 18 are waived here; waiving only the visible 8 would have been whack-a-mole. Hardening was considered per site and deliberately not bolted on: the meaningful control (symlink rejection on the dataset walk, re-checked at stream time) already exists, and filepath.Clean wrappers would silence gosec without confining anything. Comment-only change; no behavior touched. Verified with the CI-pinned golangci-lint v2.12.2 (go1.26.3): 0 issues with --max-same-issues=0 --max-issues-per-linter=0. Part of tracebloc/backend#1305 (epic #930, Layer 1). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
LukasWodka
commented
Jul 29, 2026
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit dce4f3c. Configure here.
saadqbal
left a comment
There was a problem hiding this comment.
Approve — careful PR 👍 Every one of the 18 rationales checks out against the code: the rejectSymlink walks, the writeTarFile Lstat re-check, the LimitReader cap, the compile-time argv on both exec sites, and the guarded byte(r) in slug are all real. No waiver hides a site where its justification is false.
Two low-severity notes, neither blocking:
- The G204 waivers on the helm/nodeboot Runner seams sit at the choke point, so they blanket future callers too — the 'every caller passes the literal helm/k3d' property can't be enforced from there. Fine for now (all current callers are literal); a tiny allow-listed exec wrapper would be the durable fix if we ever want one.
- stream.go's Lstat→Open is technically a TOCTOU pair; a non-issue under the local-operator threat model, just noting the 'symlinks re-rejected at stream time' wording doesn't fully close that window.
Good to merge.
Uh oh!
There was an error while loading. Please reload this page.
…#1305) Backlog is zero after the reviewed #nosec waivers (#427): findings now fail the job. max-same-issues: 0 so repeated findings can never hide behind the default cap of 3 again (the '8 findings were really 18' lesson). Branch-protection required-flip follows once this merges. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…#1305) Backlog is zero after the reviewed #nosec waivers (#427): findings now fail the job. max-same-issues: 0 so repeated findings can never hide behind the default cap of 3 again (the '8 findings were really 18' lesson). Branch-protection required-flip follows once this merges. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* ci(golangci): drop the advisory flag + uncap max-same-issues (backend#1305) Backlog is zero after the reviewed #nosec waivers (#427): findings now fail the job. max-same-issues: 0 so repeated findings can never hide behind the default cap of 3 again (the '8 findings were really 18' lesson). Branch-protection required-flip follows once this merges. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * ci(golangci): drop the advisory flag + uncap max-same-issues (backend#1305) Backlog is zero after the reviewed #nosec waivers (#427): findings now fail the job. max-same-issues: 0 so repeated findings can never hide behind the default cap of 3 again (the '8 findings were really 18' lesson). Branch-protection required-flip follows once this merges. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * build: make ci runs lint-full — mirror the now-failing golangci gate (Bugbot) golangci-lint fails PRs on findings since this branch; make ci skipping it broke the 'make ci mirrors CI exactly' rule (green local, red PR). lint-full's guard already gives install instructions when the tool is missing, which is correct mirroring rather than a soft skip. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * build: pin lint-full to the CI golangci version via go run (Bugbot) lint-full ran whatever golangci-lint was on PATH while CI pins v2.12.2 -- with ci depending on lint-full, version drift could green a local run that reds the PR gate. Now runs the exact pinned version through the Makefile's own 'go run tool@version' pattern (like errcheck/ staticcheck/govulncheck): no PATH dependency, no brew-version drift. GOLANGCI_LINT var removed (unused); lockstep note added on both sides. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Summary
Per-site, individually reviewed inline
#nosecwaivers for the gosec backlog the advisory golangci job reports, so the job goes to 0 findings and the follow-up in tracebloc/backend#1305 can drop--issues-exit-code=0(and eventually flip the check to required). Comment-only change — no behavior touched.The 8 findings are actually 18
The "8 findings" sized on #423 are an artifact of golangci-lint's default
issues.max-same-issues: 3: all 13 G304s share the identical message text ("Potential file inclusion via variable"), so any given run surfaces only 3 of them — and which 3 flaps with analysis-cache state (reproduced locally: cold-cache runs consistently showed one triple, warm-cache reruns showed different triples; CI caches too, via golangci-lint-action). 3 G304 + 3 same-texted G204 + 1 differently-texted G204 + 1 G115 = the reported 8.Uncapped (
--max-same-issues=0 --max-issues-per-linter=0) the real backlog is 18: 4x G204, 13x G304, 1x G115. Waiving only the visible 8 would have been whack-a-mole — each waived G304 would just let the cap surface a previously hidden one. All 18 are reviewed and waived here.Recommendation for the backend#1305 follow-up that drops the advisory flag: consider also setting
issues.max-same-issues: 0(or a high cap) in.golangci.yml, so a future PR that introduces several instances of the same mistake shows all of them instead of 3.Threat model in one line
This is a customer-installed local CLI that runs with the invoking operator's privileges on the operator's own machine: every "variable" input at these sites is a compile-time constant, the operator's own flag/arg/env/config, or a path enumerated by our own walk of the operator-chosen dataset root — there is no privilege boundary for injection or traversal to cross.
Per-site review
internal/cli/prepare_host.go:113bash -c+installerRunScript("prepare-host"), built only from theinstallerURLconst. No runtime input.internal/cli/upgrade.go:123upgradePlanFor(runtime.GOOS)returns compile-time constants (bash -c installerRunScript("")); only the GOOS branch varies. gosec can't see through the struct.internal/helm/upgrade.go:56Runnervar; every caller passes the literal"helm"; args are the operator's own release/kubeconfig flags, exec'd as an argv array (no shell interpolation anywhere).internal/nodeboot/nodeboot.go:35k3d/helm/docker) with argv from package consts + the operator's own cluster/release names; no shell.internal/config/config.go:125config.jsonunder~/.traceblocor the operator's explicit$TRACEBLOC_CONFIG_DIRoverride, as the invoking user.internal/cli/home_local_fallback.go:113os.Executable()(thetb.cmdshim ownership probe); whoever controls that directory already controls the binary itself.internal/cli/ingest.go:78tracebloc ingest validate <path>).internal/cli/installlog.go:37internal/cli/update_check.go:167config.Dir()+ constant filename; contents JSON-validated before use.internal/push/detect.go:30internal/push/image_resolution.go:30internal/push/preflight.go:45internal/push/preflight.go:81internal/push/preflight.go:805LimitReader.internal/push/stream.go:472srccomes from the symlink-rejecting walk and theLstatguard directly above re-rejects symlinks at stream time (existing defense-in-depth, Bugbot r4/r8).internal/push/tabular.go:391DiscoverTabular's symlink-rejecting walk of the operator-chosen root.internal/push/text.go:165byBase/byStem, maps keyed only by files the symlink-vetted walk found on disk — a manifest entry can select among them but cannot point outside the dataset dir.internal/slug/slug.go:90r < 128guard bounds them, sobyte(r)is a lossless ASCII conversion.Hardening considered, none bolted on
Per-site hardening was weighed before each waiver (preferring a fix over a waiver where one was real):
rejectSymlinkon every Discover walk plus a stream-timeLstatre-check inwriteTarFile(added for Bugbot r4/r8 on the push PRs). The waivers cite it rather than duplicate it.filepath.Clean(...)would silence gosec without confining anything (most of these paths already flow throughfilepath.Join, which Cleans) — cosmetic linter-dodging, rejected in favor of honest, reviewable waivers.slug.gocould dodge G115 by switching tob.WriteRune(r), but that hides the deliberate ASCII-only byte write behind an equivalent call; the explicit waiver documents why the conversion is safe.Verification
.golangci.yml: 8 reported with default caps, 18 uncapped, membership flap across cache states confirmed.golangci-lint run --max-same-issues=0 --max-issues-per-linter=0→ 0 issues (exit 0).gofmt -lclean,go build ./...andgo test ./...green.This unblocks removing
--issues-exit-code=0from.github/workflows/golangci.yml— deliberately not done in this PR; that's the follow-up tracked in tracebloc/backend#1305.Part of tracebloc/backend#1305
🤖 Generated with Claude Code
Note
Low Risk
Comment-only linter suppressions with documented rationale; no logic, I/O, or exec behavior is modified.
Overview
Adds comment-only inline
#nosecannotations at 18 call sites so the advisory golangci-lint job (with gosec) can report 0 findings, paving the way to drop--issues-exit-code=0in a follow-up (backend#1305). No runtime behavior changes.The waivers cover the full backlog golangci’s default caps hide (4× G204, 13× G304, 1× G115): CLI config/install paths, dataset preflight reads, helm/nodeboot test
execseams, and a bounded ASCIIbyte(r)in slug. Each comment documents why the site is acceptable for a local operator-run CLI (fixed paths, operator-chosen files under symlink-vetted walks, compile-time shell scripts, argv-only helm/docker/k3d invocations).Reviewed by Cursor Bugbot for commit dce4f3c. Bugbot is set up for automated code reviews on this repo. Configure here.