The CMS registry browse tab and new Phase-5 detail view call the
orchestrator's public Connect endpoints (PluginRegistryService /
PluginReviewService) on a different origin. The CMS transport and generated
hooks only cover the CMS's own proto surface, so these are plain JSON POSTs
to the registry URL — same rationale routes/admin/plugins.tsx carried before
the BrowseRegistryTab extraction.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
calcomblock was extracted from cms/backend/internal/plugins/calcomblock into a
standalone repo at plugins/calcomblock. The allowedPluginRESTFiles entries were
pinned to the old bundled path, so the standalone plugin's web/{settings,editor}.tsx
(which legitimately call the plugin's own HTTPHandler REST routes — no ConnectRPC
surface exists) tripped no-fetch-in-plugin. Switch to the suffix
plugins/calcomblock/web/... which matches both the standalone and legacy bundled
locations (pluginRESTFileAllowed uses HasSuffix).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- resolveScanRoots recognizes the orchestrator layout (backend/go.mod +
frontend/src) so backendDir resolves to backend/ — fixes the go.mod check,
classifies the frontend as a standalone app (not a plugin), and routes tsc
through the plain typecheck. Clears three orchestrator false-positives.
- check 2 (RBAC): only require MethodRoles for proto services a target actually
serves (mounted connect handler). The orchestrator carries but does not serve
the blockninja.v1 surface (714 false 'missing' -> 0). Exclude cli
(definitions-only, vendors a registry client) from check 2.
- Skip buf-generated gen/ output in the placeholder check (real proto enum
COMING_SOON values are not TODO debt).
- Normalize the color allowlist path so theme-card.tsx swatch previews match
regardless of scan root.
- Whitelist the gitignored, tool-regenerated styles/package-lock.json.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The CMS skill-install card now reads the instance-derived skill name from
the public /.well-known/skills/index.json discovery index — a well-known
endpoint with no ConnectRPC surface, so it warns instead of failing.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A codeless .bnp repo has no go.mod by design — mirror the ninja CLI
classifier (core bnp.IsCodelessRepo) and skip both the standalone-plugin
go.mod checks and the backend replace-directive parse for such roots.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Check 2 (RPC methods registered in RBAC interceptor) fired FAIL on core,
flagging all 926 shared procedures as "NOT in MethodRoles". Core is the
shared Go SDK: it carries the canonical proto (blockninja.v1, orchestrator.v1,
helpdesk.v1) but serves nothing and has no interceptor, so there is no
MethodRoles map to match against and every procedure looked missing.
RBAC is genuinely enforced where these procedures are actually served, and
check 2 already validates it there: cms covers blockninja.v1 (green) and
orchestrator covers orchestrator.v1 (0 missing). The abi.v1 protos declare no
services, and helpdesk.v1 is unmounted definitions. So scanning the SDK in
isolation is a not-applicable result, not a finding.
Detect the core SDK target (no serving package prefix, no interceptor.go,
module path == core) and SKIP check 2 for it instead of folding its shared
procedures into the missing-set. Serving backends (cms/orchestrator) and
plugins are untouched — the guard short-circuits the moment a target has a
package prefix or an interceptor.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Drop the stray em-dash (envreads) and arrow (reinvented) separators so all
findings use the two canonical shapes: "file:line snippet" and
"file:line [rule] detail".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Reporter is now a collector: checks declare a verdict (OK/Skip/Warn/Fail/
Fatal) plus findings, and a single central render() prints output. Default
output is silent on pass/skip — only FAIL/WARN/ERR checks print, followed by
one tally line, so a clean run is two lines. --verbose restores full per-check
output. All ~30 checks were converted to this API; orphaned guidance/label
helpers (printPerTargetOKLines, per-check *Help blocks, colors_format.go) were
removed.
The any-usage check (2e) now defaults to only the unstaged working-tree diff
(changed lines), via a new per-repo git-diff index in changedlines.go; --all-any
restores the full scan. Not-a-git-repo / no-diff warns on nothing.
Golden fixtures regenerated; integration tests updated to the new format; added
unit tests for the diff index.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds check 29: ported plugin repos must not carry a `-buildmode=plugin` build
target (the legacy .so compile the wasm migration retires). Lands DISABLED
behind a per-check const toggle (enableBuildmodePluginCheck=false) so it emits
no output and never fails while the fleet is still porting; WO-WZ-017 flips it
on. Scans plugin Makefiles/*.sh only. Unit-tested; golden snapshots unaffected.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The wasm per-plugin role provisioner (cms role_provisioner.go, WO-WZ-007)
checks role existence with a parameterized `SELECT ... FROM pg_roles`.
That is a Postgres administrative catalog lookup (DCL provisioning, not
sqlc-able), the same category as the already-allowed `FROM pg_database`.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
SiteAgentService.SendMessage is a Connect server-streaming RPC consumed
with for-await; generated Connect Query hooks are unary-only (same
justification as use-restart-operation).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Directory walkers pruned .git/vendor/node_modules but not .worktrees/, so a repo scan descended into nested git worktrees (e.g. an orchestrator worktree under cms/.worktrees/). Their Go/TS files surfaced as false positives in the standalone-plugin import check and noise in the any-usage warnings.
Add ".worktrees" to the skip set across the implicated and common walkers: proto RBAC proto-scan, standalone-plugin imports, frontend extras, go-lint, sqlc-uuid, presets.json, and plugin segmentation.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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>
New AST check scans handler render functions that build site settings
(getSiteSettings + doc["site_settings"]) and fails if they don't also set
siteSettings["toolbar"], so admin-toolbar injection can't silently regress
when a new public page type is added.
- toolbar.go: AST scanner; exempts renderListingPage (auto SEO pages) and
renderVersionPreview (carries its own preview banner).
- check_toolbar.go: registration at Seq 280 (ID "28").
- registry_test.go: +1 expected check; golden fixtures regenerated.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Helpdesk attachment upload/download is multipart HTTP by design — ConnectRPC
has no multipart support — so the frontend fetch gets the same WARN-not-FAIL
treatment as /api/plugins/ and the other sanctioned REST endpoints.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New rules no-raw-button / no-raw-button-in-plugin ride inside Check 5's
walkers, same as the browser-confirm rules. Raw buttons bypass the
action=/entity= automation attributes (docs/BUTTON_AUTOMATION.md), so
MCP/Puppeteer can't target them.
Scope: .tsx/.jsx only (plain .ts builds DOM strings for non-React
surfaces), components/ui/ exempt (defines the primitives — same
carve-out as the button-automation check).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
use-entity-search reason expanded per 2026-06-10 work order Task 11
(Gate C: allowlist with documented reason). /api/support/ (CMS widget)
and /api/helpdesk/upload (orchestrator) are multipart FormData uploads
connect-query cannot express — WARN, not FAIL.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
CMS Go module renamed from git.dev.alexdunmow.com/block/ninja to
git.dev.alexdunmow.com/block/cms (along with the git remote rename
on gitea). All import paths, string-literal rules, test fixtures,
and doc references updated; (historical 'ninja-orchestrator' refs
preserved). go mod tidy regenerated checksums.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
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>