Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 46 additions & 31 deletions containers/agent/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -147,46 +147,61 @@ echo "[entrypoint] iptables initialization complete"
/usr/local/bin/api-proxy-health-check.sh || exit 1

# Configure Claude Code API key helper
# This ensures the apiKeyHelper is properly configured in the config file
# The config file must exist before Claude Code starts for authentication to work
# In chroot mode, we write to /host$HOME/.claude.json so it's accessible after chroot
# This ensures the apiKeyHelper is properly configured in the config files
# The config files must exist before Claude Code starts for authentication to work
# We write to BOTH paths for compatibility:
# - ~/.claude.json (legacy path, used by older Claude Code versions)
# - ~/.claude/settings.json (used by Claude Code v2.1.81+)
# In chroot mode, we write to /host$HOME/... so files are accessible after chroot
if [ -n "$CLAUDE_CODE_API_KEY_HELPER" ]; then
echo "[entrypoint] Claude Code API key helper configured: $CLAUDE_CODE_API_KEY_HELPER"

# In chroot mode, write to /host path so file is accessible after chroot transition
# In chroot mode, write to /host path so files are accessible after chroot transition
if [ "${AWF_CHROOT_ENABLED}" = "true" ]; then
CONFIG_FILE="/host$HOME/.claude.json"
LEGACY_CONFIG_FILE="/host$HOME/.claude.json"
SETTINGS_DIR="/host$HOME/.claude"
else
CONFIG_FILE="$HOME/.claude.json"
LEGACY_CONFIG_FILE="$HOME/.claude.json"
SETTINGS_DIR="$HOME/.claude"
fi

if [ -f "$CONFIG_FILE" ]; then
# File exists - check if it has apiKeyHelper
if grep -q '"apiKeyHelper"' "$CONFIG_FILE"; then
# apiKeyHelper exists - validate it matches the environment variable
echo "[entrypoint] Claude Code config file exists with apiKeyHelper, validating..."
CONFIGURED_HELPER=$(grep -o '"apiKeyHelper":"[^"]*"' "$CONFIG_FILE" | cut -d'"' -f4)
if [ "$CONFIGURED_HELPER" != "$CLAUDE_CODE_API_KEY_HELPER" ]; then
echo "[entrypoint][ERROR] apiKeyHelper mismatch:"
echo "[entrypoint][ERROR] Environment variable: $CLAUDE_CODE_API_KEY_HELPER"
echo "[entrypoint][ERROR] Config file value: $CONFIGURED_HELPER"
exit 1
SETTINGS_FILE="$SETTINGS_DIR/settings.json"

# Helper: write or validate apiKeyHelper in a config file
write_api_key_helper() {
local config_file="$1"
local label="$2"

if [ -f "$config_file" ]; then
if grep -q '"apiKeyHelper"' "$config_file"; then
CONFIGURED_HELPER=$(grep -o '"apiKeyHelper":"[^"]*"' "$config_file" | cut -d'"' -f4)
if [ "$CONFIGURED_HELPER" != "$CLAUDE_CODE_API_KEY_HELPER" ]; then
echo "[entrypoint][ERROR] apiKeyHelper mismatch in $label:"
echo "[entrypoint][ERROR] Environment variable: $CLAUDE_CODE_API_KEY_HELPER"
echo "[entrypoint][ERROR] Config file value: $CONFIGURED_HELPER"
exit 1
fi
Comment on lines +174 to +182

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The grep -q '"apiKeyHelper"' check is looser than the subsequent extraction regex grep -o '"apiKeyHelper":"[^"]*"'. If the JSON is pretty-printed (e.g., whitespace around :) or uses escaped characters, the extraction can fail and, with set -e, may terminate the entrypoint unexpectedly. Consider using a JSON parser for both validation and update, or make the extraction robust to whitespace and handle parse failures by rewriting/updating the key instead of exiting due to a failed grep in a command substitution.

This issue also appears on line 185 of the same file.

Copilot uses AI. Check for mistakes.
echo "[entrypoint] ✓ $label apiKeyHelper validated"
else
echo "[entrypoint] $label exists but missing apiKeyHelper, writing..."
echo "{\"apiKeyHelper\":\"$CLAUDE_CODE_API_KEY_HELPER\"}" > "$config_file"
chmod 666 "$config_file"
echo "[entrypoint] ✓ Wrote apiKeyHelper to $label"
fi
echo "[entrypoint] ✓ Claude Code API key helper validated: $CLAUDE_CODE_API_KEY_HELPER"
else
# File exists but no apiKeyHelper - write it
echo "[entrypoint] Claude Code config file exists but missing apiKeyHelper, writing..."
echo "{\"apiKeyHelper\":\"$CLAUDE_CODE_API_KEY_HELPER\"}" > "$CONFIG_FILE"
chmod 666 "$CONFIG_FILE"
echo "[entrypoint] ✓ Wrote apiKeyHelper to $CONFIG_FILE"
echo "[entrypoint] Creating $label with apiKeyHelper..."
echo "{\"apiKeyHelper\":\"$CLAUDE_CODE_API_KEY_HELPER\"}" > "$config_file"
chmod 666 "$config_file"
echo "[entrypoint] ✓ Created $label with apiKeyHelper: $CLAUDE_CODE_API_KEY_HELPER"

Copilot AI Mar 24, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

chmod 666 on the config files makes them world-writable. Since these files control apiKeyHelper execution, leaving them writable by any user in the container is risky and also changes permissions on bind-mounted host files in chroot mode. Prefer chowning the file to the runtime user (awfuser / mapped UID) and using a least-privilege mode (e.g., 600/644 depending on whether Claude needs to update it).

This issue also appears on line 202 of the same file.

Copilot uses AI. Check for mistakes.
fi
else
# File doesn't exist - create it
echo "[entrypoint] Creating Claude Code config file with apiKeyHelper..."
echo "{\"apiKeyHelper\":\"$CLAUDE_CODE_API_KEY_HELPER\"}" > "$CONFIG_FILE"
chmod 666 "$CONFIG_FILE"
echo "[entrypoint] ✓ Created $CONFIG_FILE with apiKeyHelper: $CLAUDE_CODE_API_KEY_HELPER"
fi
}

# Write to legacy path (~/.claude.json)
write_api_key_helper "$LEGACY_CONFIG_FILE" "$LEGACY_CONFIG_FILE"

# Write to settings path (~/.claude/settings.json) for Claude Code v2.1.81+
mkdir -p "$SETTINGS_DIR"
chmod 777 "$SETTINGS_DIR" 2>/dev/null || true
write_api_key_helper "$SETTINGS_FILE" "$SETTINGS_FILE"
fi

# Pre-seed JVM build tool proxy configuration
Expand Down
3 changes: 2 additions & 1 deletion src/docker-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -762,7 +762,8 @@ export function generateDockerCompose(
// NOTE: ~/.claude.json is NOT bind-mounted as a file. File bind mounts on Linux
// prevent atomic writes (temp file + rename), which Claude Code requires.
// The writable home volume provides a writable $HOME, and entrypoint.sh
// creates ~/.claude.json with apiKeyHelper content from CLAUDE_CODE_API_KEY_HELPER.
// creates both ~/.claude.json (legacy) and ~/.claude/settings.json (v2.1.81+)
// with apiKeyHelper content from CLAUDE_CODE_API_KEY_HELPER.

// Mount ~/.cargo and ~/.rustup for Rust toolchain access
// On GitHub Actions runners, Rust is installed via rustup at $HOME/.cargo and $HOME/.rustup
Expand Down
Loading