diff --git a/.claude/skills/debug/SKILL.md b/.claude/skills/debug/SKILL.md index 4b348be..68e18b2 100644 --- a/.claude/skills/debug/SKILL.md +++ b/.claude/skills/debug/SKILL.md @@ -82,7 +82,7 @@ cat .env # Should show one of: **Apple Container Bug:** Environment variables passed via `-e` are lost when using `-i` (interactive/piped stdin). -**Workaround:** The system mounts `.env` as a file and sources it inside the container. +**Workaround:** The system extracts only authentication variables (`CLAUDE_CODE_OAUTH_TOKEN`, `ANTHROPIC_API_KEY`) from `.env` and mounts them for sourcing inside the container. Other env vars are not exposed. To verify env vars are reaching the container: ```bash diff --git a/SPEC.md b/SPEC.md index f0ca5a8..2668f0a 100644 --- a/SPEC.md +++ b/SPEC.md @@ -230,7 +230,7 @@ The token can be extracted from `~/.claude/.credentials.json` if you're logged i ANTHROPIC_API_KEY=sk-ant-api03-... ``` -The `.env` file is automatically mounted into the container at `/workspace/env-dir/env` and sourced by the entrypoint script. This workaround is needed because Apple Container loses `-e` environment variables when using `-i` (interactive mode with piped stdin). +Only the authentication variables (`CLAUDE_CODE_OAUTH_TOKEN` and `ANTHROPIC_API_KEY`) are extracted from `.env` and mounted into the container at `/workspace/env-dir/env`, then sourced by the entrypoint script. This ensures other environment variables in `.env` are not exposed to the agent. This workaround is needed because Apple Container loses `-e` environment variables when using `-i` (interactive mode with piped stdin). ### Changing the Assistant Name diff --git a/src/container-runner.ts b/src/container-runner.ts index 3c6c783..2802e85 100644 --- a/src/container-runner.ts +++ b/src/container-runner.ts @@ -111,16 +111,29 @@ function buildVolumeMounts(group: RegisteredGroup, isMain: boolean): VolumeMount }); // Environment file directory (workaround for Apple Container -i env var bug) + // Only expose specific auth variables needed by Claude Code, not the entire .env const envDir = path.join(DATA_DIR, 'env'); fs.mkdirSync(envDir, { recursive: true }); const envFile = path.join(projectRoot, '.env'); if (fs.existsSync(envFile)) { - fs.copyFileSync(envFile, path.join(envDir, 'env')); - mounts.push({ - hostPath: envDir, - containerPath: '/workspace/env-dir', - readonly: true - }); + const envContent = fs.readFileSync(envFile, 'utf-8'); + const allowedVars = ['CLAUDE_CODE_OAUTH_TOKEN', 'ANTHROPIC_API_KEY']; + const filteredLines = envContent + .split('\n') + .filter(line => { + const trimmed = line.trim(); + if (!trimmed || trimmed.startsWith('#')) return false; + return allowedVars.some(v => trimmed.startsWith(`${v}=`)); + }); + + if (filteredLines.length > 0) { + fs.writeFileSync(path.join(envDir, 'env'), filteredLines.join('\n') + '\n'); + mounts.push({ + hostPath: envDir, + containerPath: '/workspace/env-dir', + readonly: true + }); + } } if (group.containerConfig?.additionalMounts) {