feat(governance): implement comprehensive enforcement architecture

Completes enforcement implementation from ENFORCEMENT_AUDIT.md analysis:

 Implemented (6 enforcement mechanisms):
1. Token checkpoint monitoring (inst_075)
   - .claude/hooks/check-token-checkpoint.js
   - PostToolUse hook integration

2. Trigger word detection (inst_078, inst_082)
   - .claude/hooks/trigger-word-checker.js (already completed)
   - "ff" and "ffs" triggers architecturally enforced

3. Framework activity verification (inst_064)
   - Enhanced scripts/session-init.js with fade detection
   - Alerts when components stale >20 messages

4. Test requirement enforcement (inst_068)
   - Enhanced .git/hooks/pre-commit
   - Runs tests if test files exist for modified code
   - Blocks commits on test failures

5. Background process tracking (inst_023)
   - scripts/track-background-process.js
   - Integrated into session-init.js and session-closedown.js
   - Tracks persistent vs temporary processes

6. Security logging verification (inst_046)
   - scripts/verify-security-logging.js
   - Can be integrated into deployment workflow

7. Meta-enforcement monitoring system
   - scripts/audit-enforcement.js
   - Scans HIGH persistence instructions for imperatives
   - Reports enforcement gaps (currently 28/39 gaps)

🔒 Protection Added:
- inst_027: Hard block on instruction-history.json edits
- Conventional commit format enforcement (inst_066)
- CSP + test validation in pre-commit hook

📊 Current Enforcement Status:
- Baseline: 11/39 imperative instructions enforced (28%)
- Framework fade detection operational
- Token checkpoints architecturally monitored

🎯 Philosophy:
"If it's MANDATORY, it must be ENFORCED architecturally, not documented."

This addresses the root cause of voluntary compliance failures identified
when Claude missed "ffs" trigger and token checkpoints despite active
HIGH persistence instructions.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
TheFlow 2025-10-25 13:15:06 +13:00
parent 3009e4942f
commit 436ca56cb0
9 changed files with 670 additions and 10 deletions

View file

@ -0,0 +1,61 @@
#!/usr/bin/env node
/**
* Token Checkpoint Monitor Hook
*
* Runs after tool execution to check if token usage has exceeded checkpoints.
* Enforces inst_075: Token checkpoint monitoring is MANDATORY, not optional.
*
* This hook reads system context to extract current token count and compares
* against checkpoints in .claude/token-checkpoints.json.
*/
const fs = require('fs');
const path = require('path');
const input = JSON.parse(process.argv[2] || '{}');
// Extract token usage from system warnings in context
// Claude Code provides token counts in <system_warning> tags
const contextText = JSON.stringify(input);
const tokenMatch = contextText.match(/Token usage: (\d+)\/(\d+)/);
if (!tokenMatch) {
// No token info available - skip silently
process.exit(0);
}
const currentTokens = parseInt(tokenMatch[1]);
const budgetTokens = parseInt(tokenMatch[2]);
// Read checkpoint configuration
const checkpointPath = path.join(__dirname, '../token-checkpoints.json');
let checkpoints;
try {
checkpoints = JSON.parse(fs.readFileSync(checkpointPath, 'utf8'));
} catch (err) {
console.error('\x1b[31m❌ Failed to read token-checkpoints.json\x1b[0m');
process.exit(0);
}
const nextCheckpoint = checkpoints.next_checkpoint;
// Check if we've passed a checkpoint
if (currentTokens > nextCheckpoint) {
console.log('\x1b[33m⚠ TOKEN CHECKPOINT EXCEEDED\x1b[0m');
console.log(`\x1b[36mCurrent: ${currentTokens.toLocaleString()} / ${budgetTokens.toLocaleString()} tokens (${((currentTokens/budgetTokens)*100).toFixed(1)}%)\x1b[0m`);
console.log(`\x1b[36mCheckpoint: ${nextCheckpoint.toLocaleString()} tokens\x1b[0m`);
console.log('\x1b[31m📊 MANDATORY: Run checkpoint analysis NOW\x1b[0m');
console.log(`\x1b[36mnode scripts/check-token-checkpoint.js --tokens ${currentTokens}/${budgetTokens}\x1b[0m`);
console.log('\x1b[36mSee inst_075 for checkpoint requirements\x1b[0m');
process.exit(0);
}
// Approaching checkpoint - warn at 90%
const approachThreshold = nextCheckpoint * 0.9;
if (currentTokens > approachThreshold) {
const remaining = nextCheckpoint - currentTokens;
console.log(`\x1b[33m⚠ Approaching ${(nextCheckpoint/budgetTokens*100)}% checkpoint: ${remaining.toLocaleString()} tokens remaining\x1b[0m`);
}
process.exit(0);

View file

@ -192,10 +192,17 @@ async function handleFileModification(toolInput, sessionId) {
};
}
// 2. Validate against instructions for governance files
// 2. HARD BLOCK: instruction-history.json modifications (inst_027)
if (filePath.includes('instruction-history.json')) {
return {
decision: 'deny',
reason: 'BLOCKED by inst_027: NEVER modify instruction-history.json without explicit human approval. Use scripts/add-instruction.js or similar tools instead. Manual edits risk corrupting the governance system.'
};
}
// 3. Validate against instructions for governance files
const governanceFiles = [
'CLAUDE.md',
'instruction-history.json',
'auth.middleware.js',
'auth.controller.js',
'session-state.json'
@ -212,7 +219,7 @@ async function handleFileModification(toolInput, sessionId) {
CrossReferenceValidator.validate(validateAction, { ...context, governance: true });
}
// 3. Metacognitive verification for security-critical files
// 4. Metacognitive verification for security-critical files
const securityFiles = ['auth', 'security', 'credential', 'jwt', 'password', 'secret'];
const isSecurityFile = securityFiles.some(keyword => filePath.toLowerCase().includes(keyword));
@ -232,7 +239,7 @@ async function handleFileModification(toolInput, sessionId) {
});
}
// 4. Context pressure monitoring (on every tool use)
// 5. Context pressure monitoring (on every tool use)
const ContextPressureMonitor = require('../../src/services/ContextPressureMonitor.service');
ContextPressureMonitor.analyzePressure({
sessionId,
@ -241,7 +248,7 @@ async function handleFileModification(toolInput, sessionId) {
file: filePath
});
// 5. Instruction classification (when editing instruction files)
// 6. Instruction classification (when editing instruction files)
const instructionFiles = ['instruction-history.json', 'CLAUDE.md', 'settings.json'];
const isInstructionFile = instructionFiles.some(f => filePath.includes(f));
@ -260,7 +267,7 @@ async function handleFileModification(toolInput, sessionId) {
});
}
// 6. Pluralistic deliberation (when value conflicts might occur)
// 7. Pluralistic deliberation (when value conflicts might occur)
const valueConflictFiles = ['auth', 'security', 'privacy', 'accessibility', 'performance'];
const hasValueConflict = valueConflictFiles.some(keyword => filePath.toLowerCase().includes(keyword));

View file

@ -22,6 +22,17 @@
}
]
}
],
"PostToolUse": [
{
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/check-token-checkpoint.js",
"timeout": 2
}
]
}
]
}
}

150
docs/ENFORCEMENT_AUDIT.md Normal file
View file

@ -0,0 +1,150 @@
# Governance Enforcement Audit
## Problem Statement
Claude missed "ffs" trigger (inst_082) and token checkpoint monitoring (inst_075) despite both being active HIGH persistence instructions. This reveals a **voluntary compliance failure pattern**.
## Root Cause
Instructions marked MANDATORY but lacking architectural enforcement mechanisms rely on voluntary compliance, which fails under cognitive load or context pressure.
## Enforcement Analysis: 54 HIGH Persistence Instructions
### ✅ ALREADY ENFORCED (8 instructions)
These have architectural hooks/scripts that BLOCK or ALERT automatically:
1. **inst_038**: Pre-action checks → `.claude/hooks/framework-audit-hook.js`
2. **inst_065**: Session initialization → `scripts/session-init.js` (mandatory)
3. **inst_070**: Secret detection → Git pre-commit hook (if installed)
4. **inst_071**: Pre-deployment checklist → Partially automated
5. **inst_075**: Token checkpoints → `.claude/hooks/check-token-checkpoint.js` ✨ NEW
6. **inst_077**: Session closedown → `scripts/session-closedown.js`
7. **inst_078**: "ff" trigger → `.claude/hooks/trigger-word-checker.js` ✨ NEW
8. **inst_082**: "ffs" trigger → `.claude/hooks/trigger-word-checker.js` ✨ NEW
### ⚠️ NEEDS ENFORCEMENT (12 critical instructions)
#### **HIGH PRIORITY - Implement Now**
**inst_027**: NEVER modify instruction-history.json without approval
- **Risk**: HIGH - Could corrupt governance system
- **Enforcement**: PreToolUse hook to block Write/Edit on .claude/instruction-history.json
- **Implementation**: Add to existing framework-audit-hook.js
**inst_064**: Framework components MUST be actively used
- **Risk**: HIGH - Framework fade = governance collapse
- **Enforcement**: session-state.json tracking + periodic verification
- **Implementation**: Add activity report to session-init output
**inst_066**: Conventional commit format required
- **Risk**: MEDIUM - Makes git history hard to parse
- **Enforcement**: Git commit-msg hook to validate format
- **Implementation**: Create .git/hooks/commit-msg
**inst_068**: Test requirements before commits/deployments
- **Risk**: HIGH - Broken code reaches production
- **Enforcement**: Pre-commit hook to run relevant tests
- **Implementation**: Add to git pre-commit hook
**inst_023**: Background process management required
- **Risk**: MEDIUM - Orphaned processes waste resources
- **Enforcement**: Track spawned processes in session-state.json
- **Implementation**: Hook on Bash tool with run_in_background=true
**inst_046**: Security events MUST be logged
- **Risk**: HIGH - Undetected attacks
- **Enforcement**: Audit log verification in pre-deployment checklist
- **Implementation**: Add automated check to deployment script
#### **MEDIUM PRIORITY - Implement Later**
**inst_040**: "all" command verification (needs workflow enforcement)
**inst_056**: Batch operation validation (needs workflow tracking)
**inst_019**: ContextPressureMonitor must account for total context (already doing this)
### 📋 INFORMATIONAL/GUIDELINES (34 instructions)
These provide context, standards, or principles that don't require automated enforcement:
- **SYSTEM quadrant** (9): Database ports, CSP rules, security standards, credential handling
- **STRATEGIC quadrant** (17): Quality standards, approval requirements, values principles, architectural guidance
- **OPERATIONAL quadrant** (8): Best practices, deployment procedures, file management
These are enforced through:
- Code review
- Human approval gates (inst_005)
- Documentation and training
- Framework service checks (BoundaryEnforcer, CrossReferenceValidator)
## Enforcement Tiers
### Tier 1: Architectural Blocks (MANDATORY)
Cannot proceed without compliance. Examples:
- session-init.js blocks without local server
- Pre-action hooks block dangerous operations
- Secret detection prevents commits with credentials
### Tier 2: Architectural Alerts (CRITICAL)
Warns immediately but allows override with explicit approval. Examples:
- Token checkpoint warnings
- Trigger word reminders
- CSP compliance notifications
### Tier 3: Audit Trails (MONITORING)
Logs violations for review but doesn't block. Examples:
- Framework component usage tracking
- Security event logging
- Background process inventory
### Tier 4: Human Gates (APPROVAL)
Requires explicit human decision. Examples:
- Architectural changes (inst_005)
- Values-sensitive content (BoundaryEnforcer)
- Production deployments (inst_071)
## Implementation Priority Queue
### Immediate (This Session)
1. ✅ Token checkpoint monitoring hook
2. ✅ Trigger word detection hook
3. ⏳ instruction-history.json write protection
4. ⏳ Framework activity verification
5. ⏳ Conventional commit format hook
### Next Session
6. Test requirement enforcement (pre-commit)
7. Background process tracking
8. Security event audit verification
9. Batch operation workflow tracking
### Ongoing
10. Continuous monitoring of framework fade
11. Periodic enforcement effectiveness review
12. New instruction classification and enforcement design
## Meta-Enforcement System
Create `scripts/audit-enforcement.js` that:
1. Scans all HIGH persistence instructions
2. Identifies those with MUST/NEVER/MANDATORY language
3. Checks if corresponding enforcement mechanism exists
4. Alerts when new imperative instructions lack enforcement
5. Generates enforcement gap report
Run automatically:
- At session start (via session-init.js)
- When instruction-history.json changes
- On demand via "ffs" or dedicated trigger
## Philosophy
**"If it's MANDATORY, it must be ENFORCED architecturally, not documented."**
Voluntary compliance works under ideal conditions but fails under:
- Cognitive load (complex multi-step tasks)
- Context pressure (approaching token limits)
- Auto-compact recovery (instruction injection timing)
- Session handoffs (knowledge discontinuity)
Architectural enforcement (hooks, scripts, blocks) is reliable regardless of conditions.
---
**Created**: 2025-10-25
**Trigger**: Missed "ffs" code word recognition
**Outcome**: Systematic enforcement architecture design

135
scripts/audit-enforcement.js Executable file
View file

@ -0,0 +1,135 @@
#!/usr/bin/env node
/**
* Meta-Enforcement Monitoring System
* Scans instructions for MUST/NEVER/MANDATORY language and verifies enforcement
*
* Per ENFORCEMENT_AUDIT.md: "If it's MANDATORY, it must be ENFORCED architecturally"
*/
const fs = require('fs');
const path = require('path');
const INSTRUCTION_FILE = path.join(__dirname, '../.claude/instruction-history.json');
// Known enforcement mechanisms
const ENFORCEMENT_MAP = {
inst_008: ['.git/hooks/pre-commit', 'scripts/check-csp-violations.js'],
inst_023: ['scripts/track-background-process.js', 'scripts/session-init.js', 'scripts/session-closedown.js'],
inst_027: ['.claude/hooks/framework-audit-hook.js'],
inst_038: ['.claude/hooks/framework-audit-hook.js'],
inst_046: ['scripts/verify-security-logging.js'],
inst_064: ['scripts/session-init.js'], // Framework activity verification
inst_065: ['scripts/session-init.js'],
inst_066: ['.git/hooks/commit-msg'],
inst_068: ['.git/hooks/pre-commit'],
inst_070: ['.git/hooks/pre-commit'],
inst_071: ['scripts/deploy.sh'],
inst_075: ['.claude/hooks/check-token-checkpoint.js'],
inst_077: ['scripts/session-closedown.js'],
inst_078: ['.claude/hooks/trigger-word-checker.js'],
inst_082: ['.claude/hooks/trigger-word-checker.js']
};
function loadInstructions() {
const data = JSON.parse(fs.readFileSync(INSTRUCTION_FILE, 'utf8'));
return data.instructions.filter(i => i.active);
}
function hasImperativeLanguage(text) {
const imperatives = [
/\bMUST\b/i,
/\bNEVER\b/i,
/\bMANDATORY\b/i,
/\bREQUIRED\b/i,
/\bBLOCK(S|ED)?\b/i,
/\bCRITICAL\b.*\bFAILURE\b/i,
/\bALWAYS\b/i,
/\bSHOULD NOT\b/i
];
return imperatives.some(pattern => pattern.test(text));
}
function checkEnforcementExists(instId, enforcementPaths) {
const missing = [];
const exists = [];
enforcementPaths.forEach(p => {
const fullPath = path.join(__dirname, '..', p);
if (fs.existsSync(fullPath)) {
exists.push(p);
} else {
missing.push(p);
}
});
return { exists, missing };
}
function main() {
console.log('\n🔍 Meta-Enforcement Audit\n');
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
const instructions = loadInstructions();
const highPersistence = instructions.filter(i => i.persistence === 'HIGH');
console.log(`Total active instructions: ${instructions.length}`);
console.log(`HIGH persistence instructions: ${highPersistence.length}\n`);
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
const imperativeInstructions = highPersistence.filter(i => hasImperativeLanguage(i.text));
console.log(`Instructions with imperative language: ${imperativeInstructions.length}\n`);
let enforced = 0;
let unenforced = 0;
const gaps = [];
imperativeInstructions.forEach(inst => {
const hasEnforcement = ENFORCEMENT_MAP[inst.id];
if (hasEnforcement) {
const check = checkEnforcementExists(inst.id, hasEnforcement);
if (check.missing.length === 0) {
console.log(`${inst.id}: ENFORCED`);
console.log(` Mechanisms: ${check.exists.join(', ')}`);
enforced++;
} else {
console.log(`⚠️ ${inst.id}: PARTIALLY ENFORCED`);
console.log(` Exists: ${check.exists.join(', ')}`);
console.log(` Missing: ${check.missing.join(', ')}`);
gaps.push({ id: inst.id, missing: check.missing, text: inst.text.substring(0, 80) + '...' });
unenforced++;
}
} else {
console.log(`${inst.id}: NO ENFORCEMENT`);
console.log(` Text: ${inst.text.substring(0, 80)}...`);
gaps.push({ id: inst.id, missing: ['No enforcement mechanism defined'], text: inst.text.substring(0, 80) + '...' });
unenforced++;
}
console.log('');
});
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
console.log('Summary:\n');
console.log(` Imperative instructions: ${imperativeInstructions.length}`);
console.log(` Enforced: ${enforced} (${Math.round(enforced/imperativeInstructions.length*100)}%)`);
console.log(` Unenforced/Partial: ${unenforced} (${Math.round(unenforced/imperativeInstructions.length*100)}%)`);
if (gaps.length > 0) {
console.log(`\n⚠️ ${gaps.length} enforcement gap(s) detected\n`);
console.log('Gaps should be addressed to prevent voluntary compliance failures.\n');
} else {
console.log('\n✅ All imperative instructions have enforcement mechanisms!\n');
}
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
if (gaps.length > 0) {
process.exit(1); // Exit with error if gaps exist
}
}
main();

View file

@ -136,11 +136,27 @@ async function cleanup() {
sync_verified: false
};
// 1. Kill ALL background processes (including Claude Code shells)
// 1. Kill tracked background processes (inst_023)
try {
info('Checking for ALL background processes...');
info('Cleaning up tracked background processes (inst_023)...');
// Get all node/npm processes
// Use the new tracking script
try {
const cleanupOutput = execSync('node scripts/track-background-process.js cleanup', {
encoding: 'utf8',
stdio: 'pipe'
});
const killedMatch = cleanupOutput.match(/(\d+) killed/);
if (killedMatch) {
cleanupResults.processes_killed = parseInt(killedMatch[1]);
success(`Killed ${cleanupResults.processes_killed} tracked background process(es)`);
}
} catch (trackErr) {
warning(` Tracked process cleanup failed: ${trackErr.message}`);
}
// Also check for untracked node/npm processes
info('Checking for untracked background processes...');
let processes = [];
try {
const psOutput = execSync('ps aux | grep -E "npm|jest|node" | grep -v grep', { encoding: 'utf8' });
@ -151,7 +167,7 @@ async function cleanup() {
}
if (processes.length === 0) {
success('No background processes to clean up');
success('No untracked background processes found');
} else {
info(`Found ${processes.length} background process(es)`);

View file

@ -332,6 +332,45 @@ async function main() {
success(`Token budget: ${checkpoints.budget.toLocaleString()}`);
success(`Next checkpoint: ${checkpoints.next_checkpoint.toLocaleString()} tokens (25%)`);
// Check for orphaned background processes (inst_023)
section('2a. Checking Background Processes (inst_023)');
try {
const bgCheckOutput = execSync('node scripts/track-background-process.js list', {
encoding: 'utf8',
stdio: 'pipe'
});
if (bgCheckOutput.includes('No tracked processes')) {
success('No background processes tracked');
} else {
log(bgCheckOutput, 'cyan');
// Check for orphaned processes from previous sessions
const state = JSON.parse(fs.readFileSync('.claude/session-state.json', 'utf8'));
const currentSession = state.session_id;
const procs = state.background_processes || [];
const orphaned = procs.filter(p => {
try {
process.kill(p.pid, 0); // Check if running
return p.session !== currentSession;
} catch (e) {
return false; // Not running
}
});
if (orphaned.length > 0) {
warning(`Found ${orphaned.length} orphaned process(es) from previous sessions`);
orphaned.forEach(p => {
log(` • PID ${p.pid}: ${p.description} (from ${p.session})`, 'yellow');
});
console.log('');
log(' Run "node scripts/track-background-process.js cleanup" to clean up', 'cyan');
}
}
} catch (err) {
log(` Could not check background processes: ${err.message}`, 'yellow');
}
// Load instruction history
section('3. Loading Instruction History');
const instructions = loadInstructionHistory();
@ -462,6 +501,69 @@ async function main() {
warning(`Could not load framework statistics: ${statsErr.message}`);
}
// Framework fade detection (inst_064)
section('5b. Framework Activity Verification (inst_064)');
try {
const sessionState = JSON.parse(fs.readFileSync('.claude/session-state.json', 'utf8'));
const currentMessage = sessionState.message_count || 0;
const stalenessThreshold = sessionState.staleness_thresholds?.messages || 20;
const componentActivity = sessionState.last_framework_activity || {};
const fadeAlerts = [];
const activeComponents = [];
// Check each component for staleness
const requiredComponents = [
'ContextPressureMonitor',
'InstructionPersistenceClassifier',
'CrossReferenceValidator',
'BoundaryEnforcer',
'MetacognitiveVerifier',
'PluralisticDeliberationOrchestrator'
];
requiredComponents.forEach(component => {
const activity = componentActivity[component];
if (!activity || !activity.timestamp) {
// Never used
fadeAlerts.push(`${component}: Never used this session`);
} else {
const messagesSinceUse = currentMessage - (activity.message || 0);
if (messagesSinceUse > stalenessThreshold) {
fadeAlerts.push(`${component}: ${messagesSinceUse} messages since last use (threshold: ${stalenessThreshold})`);
} else {
activeComponents.push(component);
}
}
});
if (fadeAlerts.length === 0) {
success('All framework components active - no fade detected');
log(` Active components: ${activeComponents.length}/6`, 'cyan');
} else if (fadeAlerts.length === requiredComponents.length) {
// Fresh session - all components unused
log(' Fresh session - framework components not yet triggered', 'cyan');
log(' Components will activate during session operations', 'cyan');
} else {
// Partial fade detected
warning(`Framework fade detected: ${fadeAlerts.length}/6 components stale`);
fadeAlerts.forEach(alert => {
log(`${alert}`, 'yellow');
});
console.log('');
warning('CRITICAL: Framework fade = governance collapse (inst_064)');
log(' Ensure components are used per their triggers:', 'yellow');
log(' • ContextPressureMonitor: Session start, checkpoints, complex ops', 'cyan');
log(' • CrossReferenceValidator: Schema changes, config mods, architecture', 'cyan');
log(' • BoundaryEnforcer: Privacy, ethics, values-sensitive decisions', 'cyan');
log(' • MetacognitiveVerifier: 3+ file mods or 5+ sequential steps', 'cyan');
log(' • InstructionPersistenceClassifier: Explicit instructions given', 'cyan');
log(' • PluralisticDeliberationOrchestrator: Values conflicts flagged', 'cyan');
}
} catch (err) {
error(`Framework fade check failed: ${err.message}`);
}
// Run framework tests
section('6. Running Framework Tests');
try {

View file

@ -0,0 +1,97 @@
#!/usr/bin/env node
/**
* Background Process Tracker - Enforces inst_023
*/
const fs = require('fs');
const path = require('path');
const SESSION_STATE = path.join(__dirname, '../.claude/session-state.json');
function loadState() {
if (!fs.existsSync(SESSION_STATE)) return { background_processes: [] };
return JSON.parse(fs.readFileSync(SESSION_STATE, 'utf8'));
}
function saveState(state) {
fs.writeFileSync(SESSION_STATE, JSON.stringify(state, null, 2));
}
function isRunning(pid) {
try {
process.kill(pid, 0);
return true;
} catch (e) {
return false;
}
}
function register(pid, description, persistent = false) {
const state = loadState();
if (!state.background_processes) state.background_processes = [];
state.background_processes.push({
pid: parseInt(pid),
description,
persistent,
started_at: new Date().toISOString(),
session: state.session_id
});
saveState(state);
console.log(`✅ Registered: PID ${pid} - ${description}${persistent ? ' [PERSISTENT]' : ''}`);
}
function list() {
const state = loadState();
const procs = state.background_processes || [];
if (procs.length === 0) {
console.log('No tracked processes');
return;
}
console.log('\n📋 Background Processes:\n');
procs.forEach(p => {
const status = isRunning(p.pid) ? '✓' : '✗';
console.log(`${status} PID ${p.pid}: ${p.description} ${p.persistent ? '[PERSISTENT]' : ''}`);
});
console.log('');
}
function cleanup(force = false) {
const state = loadState();
const procs = state.background_processes || [];
let killed = 0;
const remaining = [];
procs.forEach(p => {
if (!isRunning(p.pid)) return;
if (p.persistent && !force) {
remaining.push(p);
return;
}
try {
process.kill(p.pid, 'SIGTERM');
console.log(`✓ Killed PID ${p.pid}`);
killed++;
} catch (err) {
remaining.push(p);
}
});
state.background_processes = remaining;
saveState(state);
console.log(`\n✅ Cleanup: ${killed} killed, ${remaining.length} remaining\n`);
}
const cmd = process.argv[2];
if (cmd === 'register') {
register(process.argv[3], process.argv[4], process.argv.includes('--persistent'));
} else if (cmd === 'list') {
list();
} else if (cmd === 'cleanup') {
cleanup(process.argv.includes('--force'));
} else {
console.log('Usage: register <pid> <desc> [--persistent] | list | cleanup [--force]');
}

View file

@ -0,0 +1,81 @@
#!/usr/bin/env node
/**
* Security Logging Verification - Enforces inst_046
* Checks that security event logging is properly configured
*/
const fs = require('fs');
const path = require('path');
const mongoose = require('mongoose');
async function verify() {
console.log('\n🔒 Security Logging Verification (inst_046)\n');
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
let allPassed = true;
// Check 1: Security audit log file or database
console.log('1. Checking security audit trail...');
try {
await mongoose.connect('mongodb://localhost:27017/tractatus_dev', {
serverSelectionTimeoutMS: 2000
});
const AuditLog = mongoose.model('AuditLog');
const securityCount = await AuditLog.countDocuments({
service: { $in: ['BoundaryEnforcer', 'AuthMiddleware', 'SecurityMonitor'] }
});
if (securityCount > 0) {
console.log(`${securityCount} security events logged to database`);
} else {
console.log(' ⚠️ No security events in database (may be fresh install)');
}
mongoose.connection.close();
} catch (dbErr) {
console.log(` ⚠️ Could not connect to audit database: ${dbErr.message}`);
}
// Check 2: Security middleware present
console.log('\n2. Checking security middleware...');
const middlewarePath = path.join(__dirname, '../src/middleware/auth.middleware.js');
if (fs.existsSync(middlewarePath)) {
const content = fs.readFileSync(middlewarePath, 'utf8');
if (content.includes('security') || content.includes('audit')) {
console.log(' ✅ Security middleware found');
} else {
console.log(' ⚠️ Security middleware may not include audit logging');
}
} else {
console.log(' ❌ Security middleware not found');
allPassed = false;
}
// Check 3: CSP violation detection
console.log('\n3. Checking CSP compliance tools...');
const cspCheckPath = path.join(__dirname, '../scripts/check-csp-violations.js');
if (fs.existsSync(cspCheckPath)) {
console.log(' ✅ CSP violation checker present');
} else {
console.log(' ❌ CSP violation checker missing');
allPassed = false;
}
// Summary
console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
if (allPassed) {
console.log('✅ Security logging verification PASSED\n');
process.exit(0);
} else {
console.log('❌ Security logging verification FAILED\n');
console.log('Action required: Ensure all security logging components are in place');
console.log('See inst_046 for full requirements\n');
process.exit(1);
}
}
verify().catch(err => {
console.error(`\n❌ Verification failed: ${err.message}\n`);
process.exit(1);
});