#!/usr/bin/env node /** * Defense-in-Depth Audit - Enforces inst_072 * Verifies all 5 layers of credential protection exist * * Layers: * 1. Prevention: Never commit credentials to git (.gitignore) * 2. Mitigation: Redact credentials in docs (documentation check) * 3. Detection: Pre-commit secret scanning (git hooks) * 4. Backstop: GitHub secret scanning (repo setting) * 5. Recovery: Credential rotation procedures (documented) */ const fs = require('fs'); const path = require('path'); const { execSync } = require('child_process'); function checkLayer1_Prevention() { console.log('Layer 1: Prevention (.gitignore)\n'); if (!fs.existsSync('.gitignore')) { return { passed: false, details: '.gitignore file not found' }; } const gitignore = fs.readFileSync('.gitignore', 'utf8'); const requiredPatterns = [ '.env', '*.pem', '*.key', 'credentials.json', 'secrets', ]; const missing = requiredPatterns.filter(pattern => !gitignore.includes(pattern)); if (missing.length > 0) { return { passed: false, details: `Missing patterns: ${missing.join(', ')}` }; } return { passed: true, details: 'All critical patterns in .gitignore' }; } function checkLayer2_Mitigation() { console.log('Layer 2: Mitigation (Documentation Redaction)\n'); // Check deployment docs for credential exposure const docsToCheck = [ 'docs/DEPLOYMENT.md', 'docs/SETUP.md', 'README.md' ].filter(f => fs.existsSync(f)); if (docsToCheck.length === 0) { return { passed: true, details: 'No deployment docs found (OK)' }; } const violations = []; docsToCheck.forEach(doc => { const content = fs.readFileSync(doc, 'utf8'); // Check for potential credential patterns (not exhaustive) const suspiciousPatterns = [ /password\s*=\s*["'][^"']{8,}["']/i, /api[_-]?key\s*=\s*["'][^"']{20,}["']/i, /secret\s*=\s*["'][^"']{20,}["']/i, /token\s*=\s*["'][^"']{20,}["']/i, ]; suspiciousPatterns.forEach(pattern => { if (pattern.test(content)) { violations.push(`${doc}: Potential credential exposure`); } }); }); if (violations.length > 0) { return { passed: false, details: violations.join('\n ') }; } return { passed: true, details: `Checked ${docsToCheck.length} docs, no credentials found` }; } function checkLayer3_Detection() { console.log('Layer 3: Detection (Pre-commit Hook)\n'); const preCommitHook = '.git/hooks/pre-commit'; if (!fs.existsSync(preCommitHook)) { return { passed: false, details: 'Pre-commit hook not found' }; } const hookContent = fs.readFileSync(preCommitHook, 'utf8'); if (!hookContent.includes('check-credential-exposure.js') && !hookContent.includes('credential') && !hookContent.includes('secret')) { return { passed: false, details: 'Pre-commit hook exists but does not check credentials' }; } // Check if script exists if (!fs.existsSync('scripts/check-credential-exposure.js')) { return { passed: false, details: 'check-credential-exposure.js script not found' }; } return { passed: true, details: 'Pre-commit hook with credential scanning active' }; } function checkLayer4_Backstop() { console.log('Layer 4: Backstop (GitHub Secret Scanning)\n'); // Check if repo is public (GitHub secret scanning auto-enabled) try { const remoteUrl = execSync('git config --get remote.origin.url', { encoding: 'utf8' }).trim(); if (remoteUrl.includes('github.com')) { // Check if public repo (GitHub API would be needed for definitive check) // For now, assume if it's on GitHub, scanning is available return { passed: true, details: 'GitHub repository - secret scanning available', note: 'Verify in repo settings: Security > Code security and analysis' }; } else { return { passed: false, details: 'Not a GitHub repository - manual scanning needed' }; } } catch (e) { return { passed: false, details: 'Unable to determine remote repository' }; } } function checkLayer5_Recovery() { console.log('Layer 5: Recovery (Rotation Procedures)\n'); const docsToCheck = [ 'docs/SECURITY.md', 'docs/DEPLOYMENT.md', 'docs/INCIDENT_RESPONSE.md', 'docs/CREDENTIAL_ROTATION_PROCEDURES.md', 'README.md' ].filter(f => fs.existsSync(f)); if (docsToCheck.length === 0) { return { passed: false, details: 'No security documentation found' }; } let hasRotationDocs = false; docsToCheck.forEach(doc => { const content = fs.readFileSync(doc, 'utf8'); if (/rotation|rotate|credentials?.*expos/i.test(content)) { hasRotationDocs = true; } }); if (!hasRotationDocs) { return { passed: false, details: 'No credential rotation procedures documented' }; } return { passed: true, details: 'Credential rotation procedures documented' }; } function main() { console.log('\nšŸ›”ļø Defense-in-Depth Audit (inst_072)\n'); console.log('Verifying all 5 layers of credential protection\n'); console.log('━'.repeat(70) + '\n'); const layers = [ { name: 'Layer 1: Prevention', check: checkLayer1_Prevention }, { name: 'Layer 2: Mitigation', check: checkLayer2_Mitigation }, { name: 'Layer 3: Detection', check: checkLayer3_Detection }, { name: 'Layer 4: Backstop', check: checkLayer4_Backstop }, { name: 'Layer 5: Recovery', check: checkLayer5_Recovery } ]; let allPassed = true; const results = []; layers.forEach(layer => { const result = layer.check(); results.push({ name: layer.name, ...result }); const status = result.passed ? 'āœ…' : 'āŒ'; console.log(`${status} ${layer.name}`); console.log(` ${result.details}`); if (result.note) { console.log(` Note: ${result.note}`); } console.log(''); if (!result.passed) { allPassed = false; } }); console.log('━'.repeat(70) + '\n'); if (allPassed) { console.log('āœ… All 5 layers of defense-in-depth are in place\n'); console.log('Credential protection meets inst_072 requirements.\n'); process.exit(0); } else { const failedLayers = results.filter(r => !r.passed); console.log(`āŒ ${failedLayers.length}/5 layer(s) incomplete\n`); console.log('Multiple layers are required (defense-in-depth).'); console.log('If one layer fails, others should prevent catastrophic outcome.\n'); process.exit(1); } } main();