extractRBACMethodRoles matched only a map literal named MethodRoles. The CMS now keeps its RBAC table behind an atomic-pointer copy-on-write live table, with the static literal renamed to methodRolesSeed -- so the validator read an empty table and reported 641 phantom "missing RBAC entry" methods, blinding the gate to any genuine unregistered RPC. Match methodRolesSeed as well as MethodRoles, and add a regression test (TestExtractRBACMethodRolesParsesSeedTable). resolveScanRoots: also resolve a `backend` directory containing go.mod whose parent holds buf.yaml or proto/, so the checker targets that layout correctly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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
useStatefor 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
- Add a
check_<name>.gofile with arunCheck<Name>func - Wire it into
main.go's check sequence - Add a goldens case in
golden_test.goif the output is deterministic - Run
make test-updateto regenerate goldens
Description
Languages
Go
99.9%