Alex Dunmow 0e8d0e6d1c fix(scan-roots): detect consolidated CMS layout (backend/go.mod + web/src)
The old detection keyed on backend/cmd/check-safety, which left the CMS
tree when check-safety was hoisted standalone. Since then the CMS
resolved as its own backend: web/ was classified as a plugin frontend
(strict rules, allowedFrontendFiles bypassed — audit F2's check-5 noise),
check 2 demanded RBAC entries for client-only orchestrator protos
(audit F3), check 2c flagged a bogus missing go.mod, and checks 3/3b
silently SKIPPED. Recognize backend/go.mod + web/src as the CMS shape
so backendDir resolves to backend/ and web/src scans under core rules.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 14:52:35 +08:00

check-safety

Static safety checker for the BlockNinja codebase. Walks a target tree, runs ~25 invariant checks across Go and frontend sources, and exits non-zero on violations.

Lives at ~/src/blockninja/check-safety/ as a standalone Go module, alongside cms/, orchestrator/, core/, etc.

Run

# Scan CMS (default target)
make run

# Scan something else
make run TARGET=../orchestrator

# Direct
go run . ../sites/bidbuddy

Install globally

make install   # → $GOPATH/bin/check-safety
check-safety ~/src/blockninja/cms

Test

make test         # all tests (some shell out to npm/tsc/golangci-lint and may skip if absent)
make test-short   # skip the long ones
make test-update  # regenerate golden snapshots after intentional output changes

What it checks

See the comment block at the top of main.go for the canonical list. Highlights:

  • Secret env-var reads happen only inside config.Load()
  • All RPC methods are registered in the RBAC interceptor
  • Frontend uses generated ConnectRPC hooks, no hand-crafted clients
  • No hardcoded colors, no useState for tab state, no npm/yarn lockfiles
  • No raw SQL outside sqlc/Bob, no err.Error() leaked to HTTP clients
  • Plugin presets validate against theme.Theme
  • Standalone plugins stay on the published SDK boundary

How it stays in sync with CMS

internal/helpers/deferlog.go and internal/theme/*.go are vendored copies from CMS (cms/backend/internal/{helpers,theme}/). Go's internal/ rule blocks direct imports across modules, so they live here. When CMS changes the theme schema or LogDeferredError, re-copy them — that drift is the point of the preset-validation check.

Adding a new check

  1. Add a check_<name>.go file with a runCheck<Name> func
  2. Wire it into main.go's check sequence
  3. Add a goldens case in golden_test.go if the output is deterministic
  4. Run make test-update to regenerate goldens
Description
No description provided
Readme 436 KiB
Languages
Go 99.9%