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

@ -21,14 +21,16 @@
import { readFileSync } from 'node:fs';
import { scanForInjection } from '../../scanners/lib/injection-patterns.mjs';
import { getPolicyValue } from '../../scanners/lib/policy-loader.mjs';
// ---------------------------------------------------------------------------
// Mode configuration
// Mode configuration (env var takes precedence over policy file)
// ---------------------------------------------------------------------------
const VALID_MODES = new Set(['block', 'warn', 'off']);
const policyMode = getPolicyValue('injection', 'mode', 'block');
const mode = VALID_MODES.has(process.env.LLM_SECURITY_INJECTION_MODE)
? process.env.LLM_SECURITY_INJECTION_MODE
: 'block';
: VALID_MODES.has(policyMode) ? policyMode : 'block';
// Off mode: skip scanning entirely
if (mode === 'off') {