From e721ad5b6a0c922f73e70ee056b901c0cc226ea1 Mon Sep 17 00:00:00 2001 From: m4nt0de4 Date: Tue, 3 Feb 2026 10:48:39 +0100 Subject: [PATCH] fix: Use proper file permissions in INSTALL.ts for Linux/WSL The fixPermissions() function was running chmod -R 755 on the entire ~/.claude directory, making every file executable including configs, markdown, and JSON files. This is incorrect on Linux/WSL where only directories and scripts should have the execute bit. Replaces the blanket chmod -R 755 with granular permissions: - Directories: 750 (rwxr-x---) - Regular files: 640 (rw-r-----) - Scripts (.ts, .sh, .py): 750 (rwxr-x---) Also uses find -exec ... + instead of \; for better performance. Fixes #484 Co-Authored-By: Claude Opus 4.5 --- Releases/v2.5/.claude/INSTALL.ts | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/Releases/v2.5/.claude/INSTALL.ts b/Releases/v2.5/.claude/INSTALL.ts index 4393bb86..9afd0247 100755 --- a/Releases/v2.5/.claude/INSTALL.ts +++ b/Releases/v2.5/.claude/INSTALL.ts @@ -103,7 +103,7 @@ async function promptChoice(question: string, choices: string[], defaultIdx = 0) } // ============================================================================ -// PERMISSIONS (chmod → chown → chmod) +// PERMISSIONS (chown → chmod dirs → chmod files → chmod scripts) // ============================================================================ function fixPermissions(targetDir: string): void { @@ -114,25 +114,25 @@ function fixPermissions(targetDir: string): void { print(`${c.gray}─────────────────────────────────────────────────${c.reset}`); try { - // Step 1: chmod first - make files accessible - execSync(`chmod -R 755 "${targetDir}"`, { stdio: 'pipe' }); - printSuccess('Step 1: chmod -R 755 (make accessible)'); - - // Step 2: chown - change ownership to current user + // Step 1: chown - change ownership to current user execSync(`chown -R ${info.uid}:${info.gid} "${targetDir}"`, { stdio: 'pipe' }); - printSuccess(`Step 2: chown -R to ${info.username}`); + printSuccess(`Ownership set to ${info.username} (${info.uid}:${info.gid})`); + + // Step 2: directories get rwxr-x--- (750) + execSync(`find "${targetDir}" -type d -exec chmod 750 {} +`, { stdio: 'pipe' }); + printSuccess('Directories set to 750 (rwxr-x---)'); - // Step 3: chmod again - set final permissions - execSync(`chmod -R 755 "${targetDir}"`, { stdio: 'pipe' }); - printSuccess('Step 3: chmod -R 755 (final permissions)'); + // Step 3: regular files get rw-r----- (640) + execSync(`find "${targetDir}" -type f -exec chmod 640 {} +`, { stdio: 'pipe' }); + printSuccess('Files set to 640 (rw-r-----)'); - // Make scripts executable - for (const pattern of ['*.ts', '*.sh', '*.hook.ts']) { + // Step 4: scripts get rwxr-x--- (750) + for (const pattern of ['*.ts', '*.sh', '*.py']) { try { - execSync(`find "${targetDir}" -name "${pattern}" -exec chmod 755 {} \\;`, { stdio: 'pipe' }); + execSync(`find "${targetDir}" -type f -name "${pattern}" -exec chmod 750 {} +`, { stdio: 'pipe' }); } catch (e) { /* ignore */ } } - printSuccess('Set executable permissions on scripts'); + printSuccess('Scripts (.ts, .sh, .py) set to 750 (rwxr-x---)'); } catch (err: any) { printError(`Permission fix failed: ${err.message}`);