Skip to content

Commit c4e94f7

Browse files
stainluclaude
andcommitted
fix(rotate-api-token): force image refresh so rotation picks up code
changes baked into the orchestrator image Caught during live smoke of the `local` path: the first invocation failed auth verification (expected 401 got 200) because `docker compose up -d` alone reuses the cached image, and the local cache predated the ea3a431 auth-middleware ship. Rotating the token wrote it into .env correctly but the orchestrator container was still running an older build that had no auth middleware at all, so every request still returned 200 unauthenticated. Fix is target-specific: - local: `docker compose up --build -d` forces a rebuild from the current src/ tree. Picks up any code change in the repo, not just the new env var. - hetzner / lightsail / gcp: `docker compose pull` before `up -d` so the remote grabs whatever's on GHCR before restarting. The `|| true` on the pull guards against transient GHCR hiccups; `up -d` still fires with whatever the remote already had cached. Second run, same `local` path, clean output: GET /v1/agents (no token) → 401 ✓ GET /v1/agents (Bearer token) → 200 ✓ GET /healthz (no token, bypass) → 200 ✓ Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 11fe45b commit c4e94f7

1 file changed

Lines changed: 12 additions & 2 deletions

File tree

scripts/rotate-api-token.sh

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -177,17 +177,27 @@ if [[ "${SSH_MODE}" == "local" ]]; then
177177
printf 'OPENCLAW_API_TOKEN=%s\n' "${TOKEN}" >> "${tmp}"
178178
mv "${tmp}" "${LOCAL_ENV_PATH}"
179179

180-
log "running docker compose up -d"
181-
( cd "$(dirname "${LOCAL_ENV_PATH}")" && docker compose up -d >/dev/null )
180+
# `--build` forces a rebuild from the local source tree, so a brand-new
181+
# auth middleware or any other src/ change is picked up. Without --build,
182+
# compose would reuse the cached image and silently skip the feature.
183+
log "running docker compose up --build -d"
184+
( cd "$(dirname "${LOCAL_ENV_PATH}")" && docker compose up --build -d >/dev/null )
182185
else
183186
log "rewriting /opt/openclaw/.env on remote"
184187
# Generate the remote script locally so ${TOKEN} expands here and
185188
# the remote bash receives a concrete literal. The remote script
186189
# uses `${REMOTE_SUDO}` for the write (Lightsail + GCP need sudo
187190
# because cloud-init ran as root; Hetzner doesn't).
191+
#
192+
# `docker compose pull` before `up -d` is load-bearing: the remote's
193+
# cached orchestrator image may predate the auth middleware (or any
194+
# other shipped feature) and `up -d` alone would silently reuse the
195+
# stale cache. Pulling first ensures the rotated token lands on a
196+
# build that actually enforces the header.
188197
cat <<REMOTE_SCRIPT | run_remote
189198
set -euo pipefail
190199
${REMOTE_SUDO} sh -c "grep -v '^OPENCLAW_API_TOKEN=' /opt/openclaw/.env > /opt/openclaw/.env.tmp 2>/dev/null || true; printf 'OPENCLAW_API_TOKEN=%s\n' '${TOKEN}' >> /opt/openclaw/.env.tmp; mv /opt/openclaw/.env.tmp /opt/openclaw/.env; chmod 0600 /opt/openclaw/.env"
200+
cd /opt/openclaw && ${REMOTE_SUDO} docker compose pull >/dev/null 2>&1 || true
191201
cd /opt/openclaw && ${REMOTE_SUDO} docker compose up -d >/dev/null
192202
REMOTE_SCRIPT
193203
fi

0 commit comments

Comments
 (0)