Files
agent-runtime-framework/harnesses/contexts/z-ai/v1/init.sh
Paul O'Reilly d68d1b0f6b fix(minimax,z-ai): write apiKeyHelper to agent home, mode 0444 for read
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>
2026-05-07 15:42:20 +12:00

67 lines
2.5 KiB
Bash
Executable File

#!/bin/bash
# z-ai init — write ~/.claude/settings.json with apiKeyHelper.
#
# The Z.ai auth_token is mounted by ESO at
# /run/agent/secrets/z-ai/auth_token (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 the claude
# subprocess' /proc/<pid>/environ, and is read fresh on each invocation so
# ESO secret rotations are picked up without a process restart.
#
# When ANTHROPIC_BASE_URL points at a non-anthropic.com host (set in
# harness.yaml to https://api.z.ai/api/anthropic), Claude Code routes
# apiKeyHelper output to `Authorization: Bearer <value>`, which is the
# header shape the Z.ai proxy requires.
#
# The K8s Secret may also contain a `base_url` file (legacy from the
# wrapper-script era) — it is intentionally ignored. The base URL is not a
# credential; it lives in harness.yaml.
set -euo pipefail
API_KEY_FILE="/run/agent/secrets/z-ai/auth_token"
if [ ! -r "$API_KEY_FILE" ]; then
echo "ERROR: $API_KEY_FILE not readable. Check ESO ExternalSecret acct-<z-ai-id>." >&2
exit 1
fi
# init.sh runs as root in uid-wrapper.sh BEFORE gosu drops privileges to the
# agent user. $HOME here is /root, not the agent home — so resolve the agent
# user's home explicitly and write settings.json there.
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
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 $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.
chown "$AGENT_USER:" "$SETTINGS_FILE" 2>/dev/null || true
chmod 0644 "$SETTINGS_FILE"
echo "z-ai auth_token wired via apiKeyHelper at $SETTINGS_FILE (agent_user=$AGENT_USER)"