#!/bin/bash # minimax init — stage the api_key for the agent user and wire apiKeyHelper. # # Threat model: keep the ESO mount root-only (mode 0400) so the agent user # cannot directly `cat` /run/agent/secrets/minimax/api_key. init.sh runs as # root (in uid-wrapper.sh, before the gosu drop) and stages a per-secret # copy into the agent's home with mode 0600 owned by agent. apiKeyHelper # points at the COPY. This is the gitea-ssh pattern — only the file the # harness explicitly grants is reachable by the runtime. # # Rotation handling: this is a one-shot copy at container start. For # ephemeral container agents (one task = one container) every task starts # with the latest secret. Long-running sessions don't refresh the copy # until a future scripts.control_loop hook lands (planning E1-M3). # # Auth wire-up: apiKeyHelper output is sent as `Authorization: Bearer # ` when ANTHROPIC_BASE_URL is non-anthropic.com — exactly what # api.minimaxi.chat/anthropic requires. The secret value never enters this # process' env, the claude subprocess' env, or /proc//environ. set -euo pipefail ESO_API_KEY="/run/agent/secrets/minimax/api_key" if [ ! -r "$ESO_API_KEY" ]; then echo "ERROR: $ESO_API_KEY not readable. Check ESO ExternalSecret acct-." >&2 exit 1 fi # Resolve the agent user's home (init.sh's $HOME is /root before gosu drop). 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 # Stage the api_key into a per-secret path owned by agent, mode 0600. # install(1) handles ownership/mode atomically; the destination is outside # the read-only ESO mount so we can chmod/chown freely. STAGED_KEY_DIR="$AGENT_HOME/.claude/secrets" STAGED_KEY="$STAGED_KEY_DIR/minimax-api-key" mkdir -p "$STAGED_KEY_DIR" chown "$AGENT_USER:" "$STAGED_KEY_DIR" 2>/dev/null || true chmod 0700 "$STAGED_KEY_DIR" install -m 0600 -o "$AGENT_USER" -g "$AGENT_USER" "$ESO_API_KEY" "$STAGED_KEY" # Wire apiKeyHelper to the staged copy in the agent's settings.json. 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" # Merge into an existing settings.json (from another harness layer) when # possible; otherwise create a fresh one. if [ -f "$SETTINGS_FILE" ] && command -v jq >/dev/null 2>&1; then TMP=$(mktemp) jq --arg helper "cat $STAGED_KEY" \ '. + {apiKeyHelper: $helper}' \ "$SETTINGS_FILE" > "$TMP" mv "$TMP" "$SETTINGS_FILE" else cat > "$SETTINGS_FILE" </dev/null || true chmod 0644 "$SETTINGS_FILE" echo "minimax api_key staged at $STAGED_KEY (0600 $AGENT_USER:$AGENT_USER)" echo "minimax apiKeyHelper wired in $SETTINGS_FILE"