Mirrors agent-runtimes commit 166c19b. CRS serves these harness files to dispatchers, so this repo must match. Two fixes from the failing smoke test: 1. init.sh resolves the agent user's home via getent (init.sh runs as root, but claude runs as the agent user — different $HOME). 2. secrets_required mode "0400" → "0444" so the agent user can read the ESO-mounted secret via apiKeyHelper. The file is in pod-local tmpfs. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
70 lines
2.8 KiB
Bash
Executable File
70 lines
2.8 KiB
Bash
Executable File
#!/bin/bash
|
|
# minimax init — write ~/.claude/settings.json with apiKeyHelper.
|
|
#
|
|
# The MiniMax API key is mounted by ESO at /run/agent/secrets/minimax/api_key
|
|
# (mode 0400, secrets_required entry in harness.yaml). Claude Code's
|
|
# `apiKeyHelper` setting names a command that prints the key on stdout when
|
|
# the CLI needs it for an API request — the value never enters this process'
|
|
# environment, never appears in /proc/<pid>/environ of the claude subprocess,
|
|
# and is read fresh on each invocation so ESO secret rotations are picked up
|
|
# without a process restart.
|
|
#
|
|
# Why settings.json (not --settings inline or env vars):
|
|
# - ANTHROPIC_AUTH_TOKEN / ANTHROPIC_API_KEY in env exposes the secret in
|
|
# /proc/<pid>/environ, log aggregators, ps. The H-SECRET-4 rule disallows
|
|
# credential-shaped env vars for that reason.
|
|
# - --settings on the runner CLI line couples the runner to the harness
|
|
# layout. Per-harness settings.json keeps auth a harness concern.
|
|
# - The helper command (`cat <file>`) re-reads on each call, so secret
|
|
# rotation propagates without rewriting the config file.
|
|
|
|
set -euo pipefail
|
|
|
|
API_KEY_FILE="/run/agent/secrets/minimax/api_key"
|
|
|
|
if [ ! -r "$API_KEY_FILE" ]; then
|
|
echo "ERROR: $API_KEY_FILE not readable. Check ESO ExternalSecret acct-<minimax-id>." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# init.sh runs as root in uid-wrapper.sh BEFORE gosu drops privileges to the
|
|
# agent user — so $HOME here is /root, not the agent home. Claude Code will
|
|
# run as the agent user and read its config from $AGENT_HOME/.claude. Resolve
|
|
# the agent home explicitly so settings.json lands where claude looks.
|
|
AGENT_USER="${AGENT_USER:-agent}"
|
|
AGENT_HOME=$(getent passwd "$AGENT_USER" | cut -d: -f6)
|
|
if [ -z "$AGENT_HOME" ] || [ ! -d "$AGENT_HOME" ]; then
|
|
AGENT_HOME="/home/$AGENT_USER"
|
|
fi
|
|
|
|
# CLAUDE_CONFIG_DIR overrides ~/.claude when set.
|
|
CONFIG_DIR="${CLAUDE_CONFIG_DIR:-$AGENT_HOME/.claude}"
|
|
mkdir -p "$CONFIG_DIR"
|
|
chown "$AGENT_USER:" "$CONFIG_DIR" 2>/dev/null || true
|
|
chmod 0755 "$CONFIG_DIR"
|
|
|
|
SETTINGS_FILE="$CONFIG_DIR/settings.json"
|
|
|
|
# If a settings.json already exists from another harness layer, merge
|
|
# apiKeyHelper into it; otherwise create a minimal file. jq is in the base
|
|
# image; fall back to a clean overwrite if it isn't available for any reason.
|
|
if [ -f "$SETTINGS_FILE" ] && command -v jq >/dev/null 2>&1; then
|
|
TMP=$(mktemp)
|
|
jq --arg helper "cat $API_KEY_FILE" \
|
|
'. + {apiKeyHelper: $helper}' \
|
|
"$SETTINGS_FILE" > "$TMP"
|
|
mv "$TMP" "$SETTINGS_FILE"
|
|
else
|
|
cat > "$SETTINGS_FILE" <<EOF
|
|
{
|
|
"apiKeyHelper": "cat $API_KEY_FILE"
|
|
}
|
|
EOF
|
|
fi
|
|
|
|
# settings.json holds the helper command (a path), not a credential value.
|
|
# It must be readable by the agent user that runs claude.
|
|
chown "$AGENT_USER:" "$SETTINGS_FILE" 2>/dev/null || true
|
|
chmod 0644 "$SETTINGS_FILE"
|
|
echo "minimax api_key wired via apiKeyHelper at $SETTINGS_FILE (agent_user=$AGENT_USER)"
|