tractatus/scripts/check-prohibited-terms.js
TheFlow e7efdc7810 feat(governance): second wave enforcement - 64% improvement (28% → 46%)
Implements 7 additional architectural enforcement mechanisms:

 Prohibited Terms Detection (inst_016/017/018):
- scripts/check-prohibited-terms.js
- Scans for absolute assurance terms ("guarantee", "100% secure")
- Detects maturity claims without evidence ("production-ready", "battle-tested")
- Checks statistics require citation or [NEEDS VERIFICATION]
- Integrated into .git/hooks/pre-commit (Check 2)

 Credential Exposure Prevention (inst_069/070):
- scripts/check-credential-exposure.js
- Detects real API keys, secrets, passwords in documentation
- Validates example credentials use proper patterns (EXAMPLE/REDACTED)
- CRITICAL: Runs first in pre-commit (Check 0)

 Confidential Document Protection (inst_012/015):
- scripts/check-confidential-docs.js
- Prevents deployment of internal/session-handoff documents
- Scans filenames and content for [CONFIDENTIAL]/[INTERNAL] markers
- Integrated into scripts/deploy.sh pre-flight checks

 Enhanced Pre-Commit Hook:
Now runs 4 checks in order:
0. Credential exposure (CRITICAL)
1. CSP compliance
2. Prohibited terms
3. Test requirements

 Enhanced Deployment Script:
- Added confidential document check to deploy.sh
- Scans public/ and docs/ before deployment
- Blocks deployment if confidential markers found

 Updated Enforcement Map:
- Added all new mechanisms to audit-enforcement.js
- Updated inst_008_CONSOLIDATED mapping
- New mappings: inst_012, inst_015, inst_016, inst_017, inst_018, inst_069, inst_070

📊 Enforcement Progress:
- Wave 1: 11/39 imperative instructions enforced (28%)
- Wave 2: 18/39 imperative instructions enforced (46%)
- Improvement: +7 instructions = +64% increase
- Remaining gaps: 21/39 (54%)

🎯 Next Priority Gaps:
- inst_013/043/045: API security validation
- inst_019: Context pressure comprehensive accounting
- inst_025: Deployment file mapping
- inst_039/040: Batch operation verification
- inst_079/080/081: Values/principles (process-based)

🔒 Security Posture:
- CRITICAL security checks now run first (credential exposure)
- All text files scanned before commit
- All deployment candidates scanned before rsync

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-25 13:26:33 +13:00

167 lines
5 KiB
JavaScript
Executable file

#!/usr/bin/env node
/**
* Prohibited Terms Scanner - Enforces inst_016, inst_017, inst_018
*
* Scans files for prohibited language that violates governance rules
*/
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
// inst_017: Prohibited absolute assurance terms
const PROHIBITED_ABSOLUTE_TERMS = [
/\bguarantee(s|d)?\b/i,
/\bensures?\s+(100%|complete|total|absolute)/i,
/\beliminates?\s+all\b/i,
/\bcompletely\s+(prevents?|eliminates?|removes?)\b/i,
/\bnever\s+fails?\b/i,
/\b100%\s+(safe|secure|reliable|accurate)\b/i,
/\babsolutely\s+(prevents?|guarantees?)\b/i
];
// inst_018: Prohibited maturity claims without evidence
const PROHIBITED_MATURITY_CLAIMS = [
/\b(production-ready|battle-tested|enterprise-proven)\b/i,
/\bvalidated\s+by\s+\d+\s+(companies|organizations|teams)\b/i,
/\bwidely\s+adopted\b/i,
/\bmarket\s+(leader|validated)\b/i,
/\bcustomer\s+base\s+of\b/i
];
// inst_016: Requires citation or [NEEDS VERIFICATION]
const STATS_PATTERNS = [
/\d+%\s+(improvement|increase|reduction|faster|better)/i,
/\d+x\s+(faster|better|more)/i,
/ROI\s+of\s+\d+/i,
/reduces?\s+(cost|time|effort)\s+by\s+\d+/i
];
function checkFile(filePath) {
const content = fs.readFileSync(filePath, 'utf8');
const lines = content.split('\n');
const violations = [];
lines.forEach((line, idx) => {
const lineNum = idx + 1;
// Check inst_017: Absolute assurance terms
PROHIBITED_ABSOLUTE_TERMS.forEach(pattern => {
if (pattern.test(line)) {
violations.push({
file: filePath,
line: lineNum,
type: 'inst_017',
severity: 'HIGH',
text: line.trim(),
rule: 'Prohibited absolute assurance term detected'
});
}
});
// Check inst_018: Maturity claims
PROHIBITED_MATURITY_CLAIMS.forEach(pattern => {
if (pattern.test(line)) {
violations.push({
file: filePath,
line: lineNum,
type: 'inst_018',
severity: 'HIGH',
text: line.trim(),
rule: 'Prohibited maturity claim without evidence'
});
}
});
// Check inst_016: Statistics without citation
STATS_PATTERNS.forEach(pattern => {
if (pattern.test(line)) {
// Check if line has citation or [NEEDS VERIFICATION]
if (!line.includes('[') && !line.includes('(source:') && !line.includes('Citation:')) {
violations.push({
file: filePath,
line: lineNum,
type: 'inst_016',
severity: 'MEDIUM',
text: line.trim(),
rule: 'Statistic without citation or [NEEDS VERIFICATION] marker'
});
}
}
});
});
return violations;
}
function scanFiles(files) {
const allViolations = [];
files.forEach(file => {
if (!fs.existsSync(file)) return;
// Only scan text files (markdown, HTML, text)
const ext = path.extname(file).toLowerCase();
if (!['.md', '.html', '.txt', '.json'].includes(ext)) return;
const violations = checkFile(file);
allViolations.push(...violations);
});
return allViolations;
}
function main() {
const args = process.argv.slice(2);
let files = [];
if (args.length === 0) {
// Scan staged git files
try {
const staged = execSync('git diff --cached --name-only --diff-filter=ACM', {
encoding: 'utf8'
});
files = staged.trim().split('\n').filter(f => f.length > 0);
} catch (err) {
console.error('Not in a git repository or no staged files');
process.exit(0);
}
} else {
files = args;
}
if (files.length === 0) {
console.log('✅ No files to scan');
process.exit(0);
}
console.log(`\n🔍 Scanning ${files.length} file(s) for prohibited terms...\n`);
const violations = scanFiles(files);
if (violations.length === 0) {
console.log('✅ No prohibited terms detected\n');
process.exit(0);
}
// Report violations
console.log(`❌ Found ${violations.length} violation(s):\n`);
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
violations.forEach(v => {
console.log(`${v.severity === 'HIGH' ? '🔴' : '🟡'} ${v.file}:${v.line}`);
console.log(` Rule: ${v.type} - ${v.rule}`);
console.log(` Text: ${v.text.substring(0, 80)}${v.text.length > 80 ? '...' : ''}`);
console.log('');
});
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
console.log('Fix violations before committing/deploying:\n');
console.log(' inst_016: Add citation or [NEEDS VERIFICATION] to statistics');
console.log(' inst_017: Replace absolute terms with evidence-based language');
console.log(' inst_018: Remove maturity claims or add documented evidence\n');
process.exit(1);
}
main();