diff --git a/harnesses/contexts/cp-service-token/v1/harness.yaml b/harnesses/contexts/cp-service-token/v1/harness.yaml index 4dfc374..116e115 100644 --- a/harnesses/contexts/cp-service-token/v1/harness.yaml +++ b/harnesses/contexts/cp-service-token/v1/harness.yaml @@ -5,16 +5,23 @@ description: "CP-internal service bearer token — authenticates agent-container requires: [] provides: [] -# AU-51b: static env pointing at the ESO-mounted secret file. No init.sh -# needed — the mount path is fixed at harness-authoring time (unlike -# anthropic-cloud-paul-oauth/v1, which transforms its secret into a -# different file format and therefore needs a staging script), and -# decompose_work_items_action reads CP_SERVICE_TOKEN_FILE directly. +# AU-51b: the ESO-mounted secret is root-owned mode 0400 (init.sh runs as +# root, before the gosu drop to the agent user, uid 1000) — unreadable by +# the agent process directly. Confirmed live 2026-09-03: a real agent +# session hit exactly this ("cp-cli invocation can't proceed... token is +# root-owned mode 0400 so it's not readable by the agent user"). Mirrors +# anthropic-cloud-paul-oauth/v1's pattern: init.sh restages a 0600 +# agent-owned copy outside the ESO mount. CP_SERVICE_TOKEN_FILE points at +# the restaged copy, not the raw mount. +# # The value at this path MUST match the CP's CP_INTERNAL_BEARER_TOKEN # (same account: cp-decompose-service-token, account_id # 1d963673-6ac9-4f85-875a-2ce5323e76ad, owner (cp, cp)). env: - CP_SERVICE_TOKEN_FILE: /run/agent/secrets/cp-service-token/value + CP_SERVICE_TOKEN_FILE: /run/agent/cp-service-token/token + +scripts: + init: "./init.sh" secrets_required: - name: cp-service-token diff --git a/harnesses/contexts/cp-service-token/v1/init.sh b/harnesses/contexts/cp-service-token/v1/init.sh new file mode 100755 index 0000000..238c69e --- /dev/null +++ b/harnesses/contexts/cp-service-token/v1/init.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# cp-service-token init — restage the ESO-mounted secret to an agent-owned +# copy. +# +# Threat model: keep the ESO mount root-only (mode 0400) so the agent user +# cannot directly `cat` /run/agent/secrets/cp-service-token/*. init.sh runs +# as root (in uid-wrapper.sh, before the gosu drop) and writes a restaged +# copy at /run/agent/cp-service-token/token with mode 0600 owned by the +# agent user. This mirrors anthropic-cloud-paul-oauth/v1/init.sh's pattern. +# +# Bug discovered live 2026-09-03: without this restaging step, cp-cli +# (invoked by the agent user, uid 1000) could not read the raw 0400 +# root-owned mount at all — "cp_cli invocation can't proceed... token is +# root-owned mode 0400 so it's not readable by the agent user". The context +# originally set CP_SERVICE_TOKEN_FILE directly at the raw ESO mount path, +# which is the mistake this init.sh fixes. + +set -euo pipefail + +ESO_TOKEN="/run/agent/secrets/cp-service-token/value" + +if [ ! -r "$ESO_TOKEN" ]; then + echo "ERROR: $ESO_TOKEN not readable. Check ESO ExternalSecret acct-1d963673." >&2 + exit 1 +fi + +AGENT_USER="${AGENT_USER:-agent}" + +DEST_DIR="/run/agent/cp-service-token" +mkdir -p "$DEST_DIR" + +DEST_FILE="$DEST_DIR/token" +cp "$ESO_TOKEN" "$DEST_FILE" + +chown "$AGENT_USER:" "$DEST_DIR" "$DEST_FILE" 2>/dev/null || true +chmod 0700 "$DEST_DIR" +chmod 0600 "$DEST_FILE" + +echo "cp-service-token: restaged into $DEST_FILE (0600 $AGENT_USER:$AGENT_USER)"