From 2f63e6610828935746f7162b59d422090837c33a Mon Sep 17 00:00:00 2001 From: Ben Phillips Date: Fri, 27 Jun 2025 12:24:27 +0100 Subject: [PATCH] Fix macOS extended attributes error in Docker container operations Resolves issue where macOS extended attributes (like com.apple.provenance) caused Docker putArchive operations to fail with "operation not supported" errors. Simplifies tar command construction to reliably exclude extended attributes on macOS using --no-xattrs and --no-fflags flags. Fixes #21 --- src/container.ts | 73 +++++++++++++++++------------------------------- 1 file changed, 25 insertions(+), 48 deletions(-) diff --git a/src/container.ts b/src/container.ts index 4b2fa92..d8536d0 100644 --- a/src/container.ts +++ b/src/container.ts @@ -502,18 +502,6 @@ exec claude --dangerously-skip-permissions' > /start-claude.sh && \\ const { execSync } = require("child_process"); const fs = require("fs"); - // Helper function to get tar flags safely - const getTarFlags = () => { - try { - // Test if --no-xattrs is supported by checking tar help - execSync("tar --help 2>&1 | grep -q no-xattrs", { stdio: "pipe" }); - return "--no-xattrs"; - } catch { - // --no-xattrs not supported, use standard tar - return ""; - } - }; - try { // Get list of git-tracked files (including uncommitted changes) const trackedFiles = execSync("git ls-files", { @@ -590,19 +578,18 @@ exec claude --dangerously-skip-permissions' > /start-claude.sh && \\ // Also copy .git directory to preserve git history console.log(chalk.blue("• Copying git history...")); const gitTarFile = `/tmp/claude-sandbox-git-${Date.now()}.tar`; - // Exclude macOS resource fork files and .DS_Store when creating git archive - // Also strip extended attributes to prevent macOS xattr issues in Docker - const tarFlags = getTarFlags(); - // On macOS, also exclude extended attributes that cause Docker issues - const additionalFlags = (process.platform as string) === "darwin" ? "--no-xattrs --no-fflags" : ""; - const combinedFlags = `${tarFlags} ${additionalFlags}`.trim(); - execSync( - `tar -cf "${gitTarFile}" --exclude="._*" --exclude=".DS_Store" ${combinedFlags} .git`, - { - cwd: workDir, - stdio: "pipe", - }, - ); + + // On macOS, use --no-xattrs and --no-fflags to prevent extended attribute issues + let tarCommand = `tar -cf "${gitTarFile}" --exclude="._*" --exclude=".DS_Store"`; + if (process.platform === "darwin") { + tarCommand += " --no-xattrs --no-fflags"; + } + tarCommand += " .git"; + + execSync(tarCommand, { + cwd: workDir, + stdio: "pipe", + }); try { const gitStream = fs.createReadStream(gitTarFile); @@ -636,18 +623,6 @@ exec claude --dangerously-skip-permissions' > /start-claude.sh && \\ const path = require("path"); const { execSync } = require("child_process"); - // Helper function to get tar flags safely - const getTarFlags = () => { - try { - // Test if --no-xattrs is supported by checking tar help - execSync("tar --help 2>&1 | grep -q no-xattrs", { stdio: "pipe" }); - return "--no-xattrs"; - } catch { - // --no-xattrs not supported, use standard tar - return ""; - } - }; - try { // First, try to get credentials from macOS Keychain if on Mac if (process.platform === "darwin") { @@ -779,24 +754,26 @@ exec claude --dangerously-skip-permissions' > /start-claude.sh && \\ // Copy .claude directory if it exists (but skip if we already copied from Keychain) const claudeDir = path.join(os.homedir(), ".claude"); + const skipClaudeDir = process.platform === "darwin"; if ( fs.existsSync(claudeDir) && fs.statSync(claudeDir).isDirectory() && - process.platform !== "darwin" + !skipClaudeDir ) { console.log(chalk.blue("• Copying .claude directory...")); const tarFile = `/tmp/claude-dir-${Date.now()}.tar`; - const tarFlags = getTarFlags(); - // On macOS, also exclude extended attributes that cause Docker issues - const additionalFlags = (process.platform as string) === "darwin" ? "--no-xattrs --no-fflags" : ""; - const combinedFlags = `${tarFlags} ${additionalFlags}`.trim(); - execSync( - `tar -cf "${tarFile}" ${combinedFlags} -C "${os.homedir()}" .claude`, - { - stdio: "pipe", - }, - ); + + // On macOS, use --no-xattrs and --no-fflags to prevent extended attribute issues + let tarCommand = `tar -cf "${tarFile}"`; + if (process.platform === "darwin") { + tarCommand += " --no-xattrs --no-fflags"; + } + tarCommand += ` -C "${os.homedir()}" .claude`; + + execSync(tarCommand, { + stdio: "pipe", + }); const stream = fs.createReadStream(tarFile); await container.putArchive(stream, {