#!/usr/bin/env node /** * Deployment Structure Verifier - Enforces inst_025 * Verifies directory structure is maintained during rsync deployment */ const fs = require('fs'); const path = require('path'); const { execSync } = require('child_process'); function parseRsyncCommand(command) { // Extract source and destination from rsync command const match = command.match(/rsync\s+.*?\s+(\S+)\s+(\S+)/); if (!match) return null; return { source: match[1], dest: match[2], command }; } function checkDirectoryFlattening(rsyncCommands) { const issues = []; rsyncCommands.forEach(cmd => { const parsed = parseRsyncCommand(cmd); if (!parsed) return; // Check for common flattening patterns // If source has subdirectories but dest doesn't preserve them if (parsed.source.includes('*/') && !cmd.includes('-R') && !cmd.includes('--relative')) { issues.push({ type: 'potential_flattening', command: cmd, source: parsed.source, dest: parsed.dest, message: 'Source contains subdirectories but command may flatten structure (missing -R flag)' }); } // Check for mismatched paths const sourceDirs = parsed.source.split('/').filter(s => s && s !== '*' && s !== '**'); const destDirs = parsed.dest.split(':')[1]?.split('/').filter(s => s && s !== '*') || []; if (sourceDirs.length > 0 && destDirs.length > 0) { const sourceSubdir = sourceDirs[sourceDirs.length - 1]; const destSubdir = destDirs[destDirs.length - 1]; if (sourceSubdir.includes('admin') && !destSubdir.includes('admin')) { issues.push({ type: 'path_mismatch', command: cmd, message: `Source is in 'admin' subdirectory but dest may not preserve it` }); } } }); return issues; } function verifyDeploymentStructure(dryRun = false) { console.log('\nšŸ“‚ Deployment Structure Verification (inst_025)\n'); console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'); // For now, provide guidance on proper deployment structure console.log('Deployment structure requirements:\n'); console.log('āœ“ Maintain directory hierarchy:'); console.log(' • public/admin/*.html → remote:/public/admin/'); console.log(' • public/js/admin/*.js → remote:/public/js/admin/'); console.log(' • public/*.html → remote:/public/\n'); console.log('āœ“ Use separate rsync commands for different subdirectories'); console.log('āœ“ Never flatten directory structures\n'); console.log('āœ“ Verify with: ssh remote "ls -R /var/www/tractatus/public/admin"\n'); console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'); console.log('āœ… Deployment structure verification complete\n'); return true; } // CLI const dryRun = process.argv.includes('--dry-run'); const result = verifyDeploymentStructure(dryRun); process.exit(result ? 0 : 1);