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:
parent
425724bb45
commit
86d7042f42
6 changed files with 585 additions and 4 deletions
150
docs/ENFORCEMENT_AUDIT.md
Normal file
150
docs/ENFORCEMENT_AUDIT.md
Normal 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
135
scripts/audit-enforcement.js
Executable 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();
|
||||
|
|
@ -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)`);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
97
scripts/track-background-process.js
Executable file
97
scripts/track-background-process.js
Executable 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]');
|
||||
}
|
||||
81
scripts/verify-security-logging.js
Executable file
81
scripts/verify-security-logging.js
Executable 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);
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue