check-safety/README.md
Alex Dunmow cd88c808b0 initial: standalone check-safety module hoisted from CMS
Static safety/lint runner for the BlockNinja codebase. ~25 invariant
checks across Go and frontend sources. Was at git.dev.alexdunmow.com:block/ninja
in backend/cmd/check-safety/ until the 2026-06-06 consolidation moved
the BlockNinja repos under a shared ~/src/blockninja/ parent.

This repo is the standalone extraction:
- Own go.mod (git.dev.alexdunmow.com/block/check-safety, go 1.26.4)
- Vendored internal/{helpers,theme} from CMS (Go's internal/ rule
  blocks cross-module imports; vendoring is the workaround)
- CLI contract unchanged: `check-safety <target-dir> [--flags]`
- CMS Makefile shells into ../check-safety for safety-check /
  install-safety-checker targets

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-06 13:04:02 +08:00

57 lines
1.9 KiB
Markdown

# 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
```bash
# Scan CMS (default target)
make run
# Scan something else
make run TARGET=../orchestrator
# Direct
go run . ../sites/bidbuddy
```
## Install globally
```bash
make install # → $GOPATH/bin/check-safety
check-safety ~/src/blockninja/cms
```
## Test
```bash
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