tractatus/scripts/test-framework-enforcement.js
TheFlow 2298d36bed fix(submissions): restructure Economist package and fix article display
- Create Economist SubmissionTracking package correctly:
  * mainArticle = full blog post content
  * coverLetter = 216-word SIR— letter
  * Links to blog post via blogPostId
- Archive 'Letter to The Economist' from blog posts (it's the cover letter)
- Fix date display on article cards (use published_at)
- Target publication already displaying via blue badge

Database changes:
- Make blogPostId optional in SubmissionTracking model
- Economist package ID: 68fa85ae49d4900e7f2ecd83
- Le Monde package ID: 68fa2abd2e6acd5691932150

Next: Enhanced modal with tabs, validation, export

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-24 08:47:42 +13:00

433 lines
13 KiB
JavaScript
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env node
/**
* Framework Enforcement Test Suite
*
* Systematically tests all framework enforcement mechanisms to verify
* they prevent governance violations as designed.
*
* Tests:
* 1. Bash write redirect blocking (inst_064)
* 2. Deployment directory structure (inst_025)
* 3. CrossReferenceValidator integration
* 4. Token checkpoint monitoring
* 5. Instruction database integrity
*
* Copyright 2025 Tractatus Project
* Licensed under Apache License 2.0
*/
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const colors = {
reset: '\x1b[0m',
bright: '\x1b[1m',
green: '\x1b[32m',
yellow: '\x1b[33m',
blue: '\x1b[34m',
red: '\x1b[31m',
cyan: '\x1b[36m'
};
function log(message, color = 'reset') {
console.log(`${colors[color]}${message}${colors.reset}`);
}
function header(message) {
console.log('');
log('═'.repeat(70), 'cyan');
log(` ${message}`, 'bright');
log('═'.repeat(70), 'cyan');
console.log('');
}
function section(message) {
console.log('');
log(`${message}`, 'blue');
}
function success(message) {
log(`${message}`, 'green');
}
function failure(message) {
log(`${message}`, 'red');
}
function info(message) {
log(` ${message}`, 'cyan');
}
const testResults = {
passed: 0,
failed: 0,
skipped: 0,
tests: []
};
function recordTest(name, passed, reason = '') {
testResults.tests.push({ name, passed, reason });
if (passed) {
testResults.passed++;
success(`PASS: ${name}`);
} else {
testResults.failed++;
failure(`FAIL: ${name}`);
if (reason) {
log(` Reason: ${reason}`, 'yellow');
}
}
}
function skipTest(name, reason) {
testResults.tests.push({ name, passed: null, reason });
testResults.skipped++;
log(` ⊘ SKIP: ${name}`, 'yellow');
log(` Reason: ${reason}`, 'yellow');
}
// Test helper: Run bash validator hook
function testBashValidator(command, shouldBlock) {
const hookScript = path.join(__dirname, 'hook-validators/validate-bash-command.js');
if (!fs.existsSync(hookScript)) {
return { error: 'Bash validator not found' };
}
try {
// Create hook input
const hookInput = JSON.stringify({
tool_name: 'Bash',
tool_input: { command }
});
// Run validator
const result = execSync(`echo '${hookInput}' | node ${hookScript}`, {
encoding: 'utf8',
stdio: 'pipe'
});
return { blocked: false, output: result };
} catch (err) {
// Non-zero exit = blocked
return { blocked: true, output: err.stdout || err.stderr };
}
}
header('Framework Enforcement Test Suite');
// TEST SUITE 1: Bash Write Redirect Blocking
section('1. Bash Write Redirect Blocking (inst_064)');
info('Testing bash commands that should be BLOCKED...');
const blockedCommands = [
{ cmd: 'cat > /tmp/test.txt', desc: 'cat > file' },
{ cmd: 'cat >> /tmp/test.txt', desc: 'cat >> file' },
{ cmd: 'cat > /tmp/test.txt << EOF\ntest\nEOF', desc: 'cat heredoc' },
{ cmd: 'echo "test" > /tmp/test.txt', desc: 'echo > file' },
{ cmd: 'echo "test" >> /tmp/test.txt', desc: 'echo >> file' },
{ cmd: 'printf "test" > /tmp/test.txt', desc: 'printf > file' },
{ cmd: 'tee /tmp/test.txt', desc: 'tee file' }
];
blockedCommands.forEach(({ cmd, desc }) => {
const result = testBashValidator(cmd, true);
if (result.error) {
skipTest(`Block ${desc}`, result.error);
} else if (result.blocked) {
recordTest(`Block ${desc}`, true);
} else {
recordTest(`Block ${desc}`, false, 'Command was not blocked but should have been');
}
});
info('Testing bash commands that should be ALLOWED...');
const allowedCommands = [
{ cmd: 'ls -la', desc: 'ls command' },
{ cmd: 'git status', desc: 'git status' },
{ cmd: 'echo "test" > /dev/null', desc: 'redirect to /dev/null' },
{ cmd: 'npm test 2>&1', desc: 'stderr redirect' },
{ cmd: 'curl https://example.com', desc: 'curl command' }
];
allowedCommands.forEach(({ cmd, desc }) => {
const result = testBashValidator(cmd, false);
if (result.error) {
skipTest(`Allow ${desc}`, result.error);
} else if (!result.blocked) {
recordTest(`Allow ${desc}`, true);
} else {
recordTest(`Allow ${desc}`, false, 'Command was blocked but should have been allowed');
}
});
// TEST SUITE 2: Deployment Pattern Validation
section('2. Deployment Pattern Validation (inst_025)');
info('Testing rsync commands...');
// Test directory flattening detection
const rsyncFlatten = 'rsync -avz /path/to/file1.txt /path/to/sub/file2.txt ubuntu@server:/var/www/';
const rsyncResult = testBashValidator(rsyncFlatten, true);
if (rsyncResult.error) {
skipTest('Detect directory flattening', rsyncResult.error);
} else if (rsyncResult.blocked) {
recordTest('Detect directory flattening', true);
} else {
recordTest('Detect directory flattening', false, 'Directory flattening not detected');
}
// Test single file rsync (should pass)
const rsyncSingle = 'rsync -avz /path/to/file.txt ubuntu@server:/var/www/';
const rsyncSingleResult = testBashValidator(rsyncSingle, false);
if (rsyncSingleResult.error) {
skipTest('Allow single-file rsync', rsyncSingleResult.error);
} else if (!rsyncSingleResult.blocked) {
recordTest('Allow single-file rsync', true);
} else {
recordTest('Allow single-file rsync', false, 'Single file rsync was blocked');
}
// TEST SUITE 3: Instruction Database Integrity
section('3. Instruction Database Integrity');
const instructionPath = path.join(__dirname, '../.claude/instruction-history.json');
try {
const history = JSON.parse(fs.readFileSync(instructionPath, 'utf8'));
// Test 1: Active instruction count
const active = history.instructions.filter(i => i.active);
recordTest(
'Active instruction count <50',
active.length < 50,
active.length >= 50 ? `Too many active: ${active.length}` : ''
);
// Test 2: HIGH persistence ratio
const highPersistence = active.filter(i => i.persistence === 'HIGH');
const ratio = (highPersistence.length / active.length) * 100;
recordTest(
'HIGH persistence ratio >90%',
ratio > 90,
ratio <= 90 ? `Ratio too low: ${ratio.toFixed(1)}%` : ''
);
// Test 3: No duplicate IDs
const ids = history.instructions.map(i => i.id);
const uniqueIds = new Set(ids);
recordTest(
'No duplicate instruction IDs',
ids.length === uniqueIds.size,
ids.length !== uniqueIds.size ? 'Duplicate IDs found' : ''
);
// Test 4: All active instructions have required fields
const requiredFields = ['id', 'text', 'quadrant', 'persistence', 'temporal_scope'];
const incomplete = active.filter(inst =>
requiredFields.some(field => !inst[field])
);
recordTest(
'All active instructions complete',
incomplete.length === 0,
incomplete.length > 0 ? `${incomplete.length} incomplete instructions` : ''
);
// Test 5: inst_075 exists and active (token checkpoints)
const inst_075 = history.instructions.find(i => i.id === 'inst_075' && i.active);
recordTest(
'inst_075 (token checkpoints) active',
!!inst_075,
!inst_075 ? 'inst_075 not found or inactive' : ''
);
// Test 6: inst_024_CONSOLIDATED exists (series consolidation)
const inst_024_consolidated = history.instructions.find(i => i.id === 'inst_024_CONSOLIDATED' && i.active);
recordTest(
'inst_024_CONSOLIDATED active',
!!inst_024_consolidated,
!inst_024_consolidated ? 'Consolidation not found' : ''
);
} catch (err) {
skipTest('Instruction database tests', `Error reading database: ${err.message}`);
}
// TEST SUITE 4: Token Checkpoint Monitoring
section('4. Token Checkpoint Monitoring');
const checkpointPath = path.join(__dirname, '../.claude/token-checkpoints.json');
try {
const checkpoints = JSON.parse(fs.readFileSync(checkpointPath, 'utf8'));
// Test 1: Checkpoints defined
recordTest(
'Token checkpoints defined',
checkpoints.checkpoints && checkpoints.checkpoints.length === 3,
checkpoints.checkpoints?.length !== 3 ? 'Unexpected checkpoint count' : ''
);
// Test 2: Checkpoint thresholds correct
const expectedThresholds = [50000, 100000, 150000];
const actualThresholds = checkpoints.checkpoints.map(c => c.tokens);
const thresholdsMatch = expectedThresholds.every((t, i) => t === actualThresholds[i]);
recordTest(
'Checkpoint thresholds correct (50k, 100k, 150k)',
thresholdsMatch,
!thresholdsMatch ? `Actual: ${actualThresholds.join(', ')}` : ''
);
// Test 3: Next checkpoint tracking
recordTest(
'Next checkpoint tracked',
checkpoints.next_checkpoint !== undefined,
!checkpoints.next_checkpoint ? 'next_checkpoint field missing' : ''
);
// Test 4: Checkpoint script exists
const checkpointScript = path.join(__dirname, 'check-token-checkpoint.js');
recordTest(
'Checkpoint monitor script exists',
fs.existsSync(checkpointScript),
!fs.existsSync(checkpointScript) ? 'Script not found' : ''
);
} catch (err) {
skipTest('Token checkpoint tests', `Error reading checkpoints: ${err.message}`);
}
// TEST SUITE 5: Framework Component Files
section('5. Framework Component Files');
const componentFiles = [
'src/services/ContextPressureMonitor.service.js',
'src/services/InstructionPersistenceClassifier.service.js',
'src/services/CrossReferenceValidator.service.js',
'src/services/BoundaryEnforcer.service.js',
'src/services/MetacognitiveVerifier.service.js',
'src/services/PluralisticDeliberationOrchestrator.service.js'
];
componentFiles.forEach(file => {
const filepath = path.join(__dirname, '..', file);
const exists = fs.existsSync(filepath);
recordTest(
`${path.basename(file, '.service.js')} exists`,
exists,
!exists ? 'File not found' : ''
);
});
// TEST SUITE 6: Hook Validators
section('6. Hook Validator Scripts');
const hookFiles = [
'scripts/hook-validators/validate-file-edit.js',
'scripts/hook-validators/validate-file-write.js',
'scripts/hook-validators/validate-bash-command.js'
];
hookFiles.forEach(file => {
const filepath = path.join(__dirname, '..', file);
const exists = fs.existsSync(filepath);
if (exists) {
// Check if executable
try {
fs.accessSync(filepath, fs.constants.X_OK);
recordTest(`${path.basename(file)} executable`, true);
} catch (err) {
recordTest(`${path.basename(file)} executable`, false, 'Not executable');
}
} else {
recordTest(`${path.basename(file)} exists`, false, 'File not found');
}
});
// TEST SUITE 7: Settings Configuration
section('7. Settings Configuration');
const settingsPath = path.join(__dirname, '../.claude/settings.local.json');
try {
const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
// Test 1: Hooks defined
recordTest(
'PreToolUse hooks defined',
settings.hooks && settings.hooks.PreToolUse,
!settings.hooks?.PreToolUse ? 'PreToolUse hooks missing' : ''
);
// Test 2: Bash hook configured
const bashHook = settings.hooks?.PreToolUse?.find(h => h.matcher === 'Bash');
recordTest(
'Bash validator hook configured',
!!bashHook,
!bashHook ? 'Bash hook not found in settings' : ''
);
// Test 3: Edit hook configured
const editHook = settings.hooks?.PreToolUse?.find(h => h.matcher === 'Edit');
recordTest(
'Edit validator hook configured',
!!editHook,
!editHook ? 'Edit hook not found in settings' : ''
);
// Test 4: Write hook configured
const writeHook = settings.hooks?.PreToolUse?.find(h => h.matcher === 'Write');
recordTest(
'Write validator hook configured',
!!writeHook,
!writeHook ? 'Write hook not found in settings' : ''
);
} catch (err) {
skipTest('Settings configuration tests', `Error reading settings: ${err.message}`);
}
// FINAL SUMMARY
header('Test Summary');
const total = testResults.passed + testResults.failed + testResults.skipped;
const passRate = total > 0 ? ((testResults.passed / total) * 100).toFixed(1) : 0;
console.log('');
log(` Total Tests: ${total}`, 'cyan');
log(` Passed: ${testResults.passed}`, 'green');
log(` Failed: ${testResults.failed}`, testResults.failed === 0 ? 'green' : 'red');
log(` Skipped: ${testResults.skipped}`, 'yellow');
log(` Pass Rate: ${passRate}%`, parseFloat(passRate) >= 90 ? 'green' : parseFloat(passRate) >= 70 ? 'yellow' : 'red');
console.log('');
if (testResults.failed === 0 && testResults.skipped === 0) {
success('✓ ALL TESTS PASSED - Framework enforcement working perfectly!');
} else if (testResults.failed === 0) {
log(` ✓ All executed tests passed (${testResults.skipped} skipped)`, 'yellow');
} else {
failure(`${testResults.failed} test(s) failed - review enforcement mechanisms`);
console.log('');
log(' Failed tests:', 'red');
testResults.tests
.filter(t => t.passed === false)
.forEach(t => {
log(` - ${t.name}: ${t.reason}`, 'red');
});
}
console.log('');
log('═'.repeat(70), 'cyan');
// Exit code based on results
process.exit(testResults.failed === 0 ? 0 : 1);