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>
95 lines
2.7 KiB
JavaScript
Executable file
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();
|