tractatus/scripts/check-file-permissions.js
TheFlow 4773c8bb95 feat(governance): third wave enforcement - 22% improvement (46% → 56%)
Implements 4 additional architectural enforcement mechanisms:

 All Command Detection (inst_040) - .claude/hooks/all-command-detector.js
 Deployment Structure Validation (inst_025) - scripts/verify-deployment-structure.js
 File Permissions Check (inst_020_CONSOLIDATED) - scripts/check-file-permissions.js
 Environment Variable Standards (inst_026) - scripts/check-env-var-standards.js

📊 Progress: 22/39 enforced (56%), +4 from wave 2, 17 gaps remaining

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

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

95 lines
2.7 KiB
JavaScript
Executable file

#!/usr/bin/env node
/**
* File Permissions Checker - Enforces inst_020_CONSOLIDATED
* Verifies correct file permissions for web deployment
*/
const fs = require('fs');
const path = require('path');
const { execSync } = require('child_process');
const EXPECTED_PERMISSIONS = {
html: 0o644, // rw-r--r--
css: 0o644,
js: 0o644,
json: 0o644,
md: 0o644,
txt: 0o644,
sh: 0o755, // rwxr-xr-x (executable scripts)
};
function checkPermissions(directory) {
const issues = [];
function scanDir(dir) {
const entries = fs.readdirSync(dir, { withFileTypes: true });
entries.forEach(entry => {
const fullPath = path.join(dir, entry.name);
const relativePath = path.relative(process.cwd(), fullPath);
if (entry.isDirectory()) {
if (!entry.name.startsWith('.') && entry.name !== 'node_modules') {
scanDir(fullPath);
}
} else if (entry.isFile()) {
const ext = path.extname(entry.name).slice(1);
const stats = fs.statSync(fullPath);
const perms = stats.mode & 0o777;
const expected = EXPECTED_PERMISSIONS[ext];
if (expected && perms !== expected) {
issues.push({
file: relativePath,
current: perms.toString(8),
expected: expected.toString(8),
ext
});
}
}
});
}
scanDir(directory);
return issues;
}
function main() {
const targetDir = process.argv[2] || 'public';
console.log(`\n📋 File Permissions Check (inst_020_CONSOLIDATED)\n`);
console.log(`Scanning: ${targetDir}\n`);
if (!fs.existsSync(targetDir)) {
console.log(`⚠️ Directory not found: ${targetDir}\n`);
process.exit(0);
}
const issues = checkPermissions(targetDir);
if (issues.length === 0) {
console.log('✅ All file permissions correct\n');
process.exit(0);
}
console.log(`❌ Found ${issues.length} permission issue(s):\n`);
console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
issues.slice(0, 20).forEach(i => {
console.log(` ${i.file}`);
console.log(` Current: ${i.current} | Expected: ${i.expected} (${i.ext} files)`);
});
if (issues.length > 20) {
console.log(`\n ... and ${issues.length - 20} more\n`);
}
console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
console.log('Fix with:');
console.log(` chmod 644 ${targetDir}/**/*.{html,css,js,json,md,txt}`);
console.log(` chmod 755 ${targetDir}/**/*.sh\n`);
process.exit(1);
}
main();