feat(governance): add policy-as-code — .llm-security/policy.json for distributable hook configuration

New policy-loader.mjs reads .llm-security/policy.json with deep-merge against
defaults that exactly match existing hardcoded values. Integrated into all 7 hooks:
- pre-prompt-inject-scan: injection.mode (env var still takes precedence)
- post-session-guard: trifecta.mode, window_size, long_horizon_window
- pre-edit-secrets: secrets.additional_patterns
- pre-bash-destructive: destructive.additional_blocked
- pre-write-pathguard: pathguard.additional_protected
- pre-install-supply-chain: supply_chain.additional_blocked_packages
- post-mcp-verify: mcp.volume_threshold_bytes, mcp.trusted_servers

Backward compatible: no policy file = identical behavior to v5.1.0.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Kjell Tore Guttormsen 2026-04-10 13:37:02 +02:00
commit 8ec320f40c
9 changed files with 300 additions and 13 deletions

View file

@ -14,6 +14,7 @@
import { readFileSync } from 'node:fs';
import { normalize } from 'node:path';
import { getPolicyValue } from '../../scanners/lib/policy-loader.mjs';
// ---------------------------------------------------------------------------
// Secret detection patterns (union of global, kiur, llm-security, ms-ai-architect)
@ -32,6 +33,11 @@ const SECRET_PATTERNS = [
{ name: 'Generic credential assignment', pattern: /(?:password|passwd|secret|token|api[_-]?key)\s*[=:]\s*['"][^'"]{8,}['"]/i },
{ name: 'Authorization header with token', pattern: /[Bb]earer [A-Za-z0-9\-._~+/]{20,}/ },
{ name: 'Database connection string', pattern: /(?:postgres|mysql|mongodb|redis):\/\/[^\s]+@[^\s]+/i },
// Policy-defined additional patterns
...getPolicyValue('secrets', 'additional_patterns', []).map((p, i) => ({
name: `Custom pattern ${i + 1}`,
pattern: new RegExp(p),
})),
];
// ---------------------------------------------------------------------------