Changes: v1.0.0 → v2.0.0
Public-release hardening pass. Four parallel tracks — security, distribution, scoring, docs — plus a dogfood-fixture fix. The scoring change is the reason this is a major bump.
Breaking
| Change | What it does |
|---|
| Continuous coverage scaling | The step at totalApplicableWeight < 50 is gone. Scaling is now scale = min(1, totalApplicableWeight / 100), applied always. Closes a gameable cliff where projects at applicable weight 48 scored visibly differently from projects at 50 despite representing the same coverage. Overall scores will shift downward for projects with applicable weight between 50 and 100. --fail-under thresholds calibrated against the old formula may need adjustment. |
Security
| Change | What it does |
|---|
| ANSI escape injection closed | stripAnsi applied to every file-sourced title / detail / evidence / remediation / learnMore before Chalk wrapping. Blocks terminal-hijack payloads (OSC 8, clear-screen, set-title) planted in scanned skill files. |
Atomic saveState | State writes go to <path>.<pid>.<hex>.tmp and are rename()’d in place. Prevents SIGINT / concurrent-scan corruption of .rigscore-state.json and the silent loss of MCP pin hashes that followed. |
| Strict config parsing | New ConfigParseError + readJsonStrict. loadConfig, diff, and saveState propagate the structured error. CLI exits 2 with rigscore: <file> is not valid JSON (<err>). Fix and retry. instead of a raw Node stack. |
| Symlink-loop defense | Shared walkDirSafe with lstat + visited-inode set + maxDepth (default 50, overridable via config.limits.maxWalkDepth). deep-secrets, skill-files, and the k8s/ enumeration in docker-security all use it. An info finding surfaces once per scan when a cycle is skipped. |
| Network timeout + per-file cap | fetch calls in src/http.js and src/mcp-registry.js wrap an AbortController with a 5s default (config.limits.networkTimeoutMs); the deep scanner skips files over 512 KB (config.limits.maxFileBytes) with an info finding. |
windows-security desynced | Synchronous execSync replaced with the promisified execSafe used elsewhere. Same 5s timeout, no event-loop blocking. |
Distribution
| Change | What it does |
|---|
| Lockfile regenerated | Built against package.json 1.0.0 — npm ci is reproducible again. |
| Runtime + dev deps pinned to exact versions | Caret ranges on chalk, yaml, vitest gone. Closes the self-own of a supply-chain scanner re-resolving deps on every install. |
engines.node floor → >=18.17.0 | fs.promises.readdir({ recursive: true }) guaranteed available. |
User-Agent derived from package.json | createRequire at module load. No more hardcoded rigscore/0.8.0 drift across releases. |
--init-hook pins @v${pkg.version} | Writes the current version’s tag into .git/hooks/pre-commit. Older pinned versions during re-install warn rather than silently append. |
| CI matrix expanded | Node 18.17, 20, 22 across ubuntu-latest and macos-latest, with a lockfile-drift guard (npm ci && git diff --exit-code package-lock.json) to prevent future lockfile regressions. |
| Dockerfile hardened | Non-root rigscore user runs the scan. ARG VERSION + org.opencontainers.image.* labels replace the stale v1.1.0 comment. Image no longer reads mounted /workspace as root. |
action.yml stops swallowing crashes | `2>/dev/null |
Docs
| Change | What it does |
|---|
| README — Platform notes + Exit codes | WSL / macOS / Git Bash / Docker Desktop behaviour documented honestly. CI authors can branch on exit codes without reading the source. |
docs/FINDING_IDS.md | Enumerates every explicitly-emitted findingId, documents the <check>/<slug> schema, states the stability contract (explicit findingIds do not change within a major version). |
| README — Advisory escalation, First run, Documentation sections | New. |
docs/TROUBLESHOOTING.md | New. |
docs/examples/ starter governance templates | Cursor, Cline, Continue, Windsurf, Aider. |
Scoring & checks
| Change | What it does |
|---|
claude-md → NOT_APPLICABLE on non-AI dirs | Returns NOT_APPLICABLE (not CRITICAL) when no AI tooling markers are present in cwd. Banner printed at the top of the terminal report when every AI-tooling check is NOT_APPLICABLE, pointing the user to --include-home-skills or adding a governance file. Generic hygiene checks still score. |
Narrowed claude-md anti-injection keyword | Bare injection (which gave “dependency injection” anti-injection credit) rejected in favour of prompt.?injection, instruction.?override, injection.?attack, ignore previous, disregard.?instructions. |
skill-files — defensive-context suppression in shell-exec | Fixes false fires on Do not use curl http:// etc. No longer stops at first match in the shell-exec / escalation / persistence / indirect-injection loops. Findings now carry a matches: N count; escalates to CRITICAL when ≥ 3 distinct patterns match the same file. |
deep-secrets — no blanket dotfile skip | config/.env.production and similar are now scanned. SKIP_DIRS extended with common machine-generated dotfolders (.cache, .idea, .turbo, .tox, .pytest_cache, .svelte-kit, .terraform) so that lifting the blanket guard doesn’t cause noise. |
Test hygiene
test/fixture-dogfood.test.js scrubs .rigscore-state.json from the fixture dir beforeEach / afterEach; fixture .gitignore lists the state file. A prior run’s per-user mode-0600 state file can no longer mask the mcp-config check and drift the locked finding count.
Install
1npx github:Back-Road-Creative/rigscore
No accounts, no telemetry, no network calls. MIT licensed.
github.com/Back-Road-Creative/rigscore