#!/usr/bin/env node /** * Credential & Attribution Validator * * Prevents unauthorized changes to: * - Copyright attribution * - GitHub repository URLs * - Contact emails * - Domain names * - API keys/credentials * - Legal entity names * * Architectural enforcement to prevent Claude from arbitrarily changing * important credentials without human confirmation. * * Created: 2025-10-18 * Incident: Footer component overwrote copyright from "John G Stroh" to "Tractatus AI Safety Framework" */ const fs = require('fs'); const path = require('path'); // IMMUTABLE CREDENTIALS - These values MUST NOT be changed without human approval const PROTECTED_VALUES = { copyright_holder: 'John G Stroh', github_org: 'AgenticGovernance', github_repo: 'tractatus-framework', primary_email: 'hello@agenticgovernance.digital', support_email: 'support@agenticgovernance.digital', domain: 'agenticgovernance.digital', license: 'Apache License 2.0', }; // File patterns that commonly contain credentials const CREDENTIAL_FILES = [ 'public/js/components/footer.js', 'LICENSE', 'package.json', 'public/**/*.html', 'docs/**/*.md', ]; /** * Validate that protected values haven't been arbitrarily changed */ function validateCredentials(filePath, fileContent) { const violations = []; // Check for incorrect copyright attribution const copyrightRegex = /©.*?(\d{4})\s+([^.\n<]+)/g; let match; while ((match = copyrightRegex.exec(fileContent)) !== null) { const holder = match[2].trim(); // Allow "John G Stroh" or "John G. Stroh" (with period) if (!holder.includes('John G') && !holder.includes(PROTECTED_VALUES.copyright_holder)) { violations.push({ type: 'COPYRIGHT_MISMATCH', line: getLineNumber(fileContent, match.index), found: holder, expected: PROTECTED_VALUES.copyright_holder, message: `Copyright holder must be "${PROTECTED_VALUES.copyright_holder}" (from LICENSE file)` }); } } // Check for incorrect GitHub URLs const githubRegex = /github\.com\/([^\/\s"']+)\/([^\/\s"'<]+)/g; while ((match = githubRegex.exec(fileContent)) !== null) { const org = match[1]; const repo = match[2]; // Check if it's supposed to be our repo but has wrong values if ((org !== PROTECTED_VALUES.github_org || repo !== PROTECTED_VALUES.github_repo) && (org.includes('tractatus') || repo.includes('tractatus'))) { violations.push({ type: 'GITHUB_URL_INCORRECT', line: getLineNumber(fileContent, match.index), found: `${org}/${repo}`, expected: `${PROTECTED_VALUES.github_org}/${PROTECTED_VALUES.github_repo}`, message: `GitHub repository must be "${PROTECTED_VALUES.github_org}/${PROTECTED_VALUES.github_repo}"` }); } } // Check for placeholder GitHub URLs if (fileContent.includes('github.com/yourusername') || fileContent.includes('github.com/your-org')) { violations.push({ type: 'GITHUB_PLACEHOLDER', message: 'GitHub URL contains placeholder - must use actual repository URL', expected: `https://github.com/${PROTECTED_VALUES.github_org}/${PROTECTED_VALUES.github_repo}` }); } // Check for incorrect domain references const domainRegex = /https?:\/\/([a-z0-9-]+\.)+[a-z]{2,}/gi; while ((match = domainRegex.exec(fileContent)) !== null) { const url = match[0]; // Skip CDNs, external services, etc. if (url.includes('tractatus') && !url.includes(PROTECTED_VALUES.domain)) { violations.push({ type: 'DOMAIN_INCORRECT', line: getLineNumber(fileContent, match.index), found: url, expected: `https://${PROTECTED_VALUES.domain}`, message: `Domain must be "${PROTECTED_VALUES.domain}"` }); } } return violations; } /** * Get line number from character index */ function getLineNumber(content, index) { return content.substring(0, index).split('\n').length; } /** * Main validation function */ function validate(filePath, operation) { // Only validate files that might contain credentials const shouldValidate = CREDENTIAL_FILES.some(pattern => { if (pattern.includes('*')) { const regex = new RegExp(pattern.replace(/\*/g, '.*')); return regex.test(filePath); } return filePath.includes(pattern); }); if (!shouldValidate) { return { valid: true }; } // Read file content let content; try { content = fs.readFileSync(filePath, 'utf-8'); } catch (error) { // File doesn't exist yet (being created) return { valid: true }; } // Validate credentials const violations = validateCredentials(filePath, content); if (violations.length > 0) { return { valid: false, violations, message: formatViolations(filePath, violations) }; } return { valid: true }; } /** * Format violations for human-readable output */ function formatViolations(filePath, violations) { let message = `\n❌ CREDENTIAL VIOLATION in ${filePath}\n\n`; message += `PROTECTED CREDENTIALS ENFORCEMENT:\n`; message += `The following values are IMMUTABLE and require human approval to change:\n\n`; for (const violation of violations) { message += ` ⚠️ ${violation.type}:\n`; if (violation.line) { message += ` Line: ${violation.line}\n`; } if (violation.found) { message += ` Found: "${violation.found}"\n`; } message += ` Expected: "${violation.expected}"\n`; message += ` Reason: ${violation.message}\n\n`; } message += `\n`; message += `RESOLUTION:\n`; message += `1. This change requires EXPLICIT human approval\n`; message += `2. Verify the change is intentional and authorized\n`; message += `3. If correcting an error, update to the protected values above\n`; message += `4. If legitimately changing credentials, update PROTECTED_VALUES in:\n`; message += ` scripts/hook-validators/validate-credentials.js\n`; message += `\n`; message += `Protected values are defined in LICENSE and package.json.\n`; message += `Copyright holder: John G Stroh (LICENSE:189)\n`; message += `GitHub repository: AgenticGovernance/tractatus-framework\n`; return message; } // Export for use as module module.exports = { validate, validateCredentials, PROTECTED_VALUES }; // CLI usage if (require.main === module) { const args = process.argv.slice(2); if (args.length < 2) { console.error('Usage: validate-credentials.js '); process.exit(1); } const [filePath, operation] = args; const result = validate(filePath, operation); if (!result.valid) { console.error(result.message); process.exit(1); } process.exit(0); }