Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion scripts/install-harness.sh
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,20 @@ case "$H" in
# steps and exits — the actual run then goes through run-harness grok, on
# grok's own auth. Keeping the pin + restore in one place is why this shells
# out rather than inlining an `npm install -g @xai-official/grok`.
# run-grok.sh setup exits 0 even when the OAuth refresh degrades (a stale
# on-disk token may still have some life), so its exit code cannot tell us
# whether auth is healthy. Hand it a marker path instead: if it comes back
# touched, the refresh failed and printing "auth staged" would be a lie.
GROK_DEGRADED_MARKER="${RUNNER_TEMP:-${TMPDIR:-/tmp}}/grok-auth-degraded.$$"
export GROK_DEGRADED_MARKER
rm -f "$GROK_DEGRADED_MARKER"
bash "${GITHUB_WORKSPACE:-$(pwd)}/scripts/run-grok.sh" setup
echo "grok: CLI + auth staged (auth: ${AUTH_MODE:-native})" ;;
if [ -f "$GROK_DEGRADED_MARKER" ]; then
rm -f "$GROK_DEGRADED_MARKER"
echo "grok: CLI installed, auth DEGRADED (OAuth refresh failed; using the existing on-disk token, which may be expired) (auth: ${AUTH_MODE:-native})"
else
echo "grok: CLI + auth staged (auth: ${AUTH_MODE:-native})"
fi ;;
codex)
# PINNED, like aeon pins claude-code. Unpinned, this step silently tracked
# latest: two cells that passed on 2026-07-21 failed hours later with an
Expand Down
26 changes: 22 additions & 4 deletions scripts/run-grok.sh
Original file line number Diff line number Diff line change
Expand Up @@ -161,13 +161,14 @@ grok_oauth_refresh() {
--data-urlencode "client_id=$cid" \
--data-urlencode "refresh_token=$rt" 2>/dev/null)
if [ -z "$resp" ]; then
log "::warning::grok oauth: refresh request to $ep failed (empty/timeout) - falling through to the on-disk token"; return 0
log "::warning::grok oauth: refresh request to $ep failed (empty/timeout) - falling through to the on-disk token"
GROK_OAUTH_DEGRADED=1; return 0
fi
access=$(jq -r '.access_token // empty' <<<"$resp" 2>/dev/null)
if [ -z "$access" ]; then
local oerr; oerr=$(jq -r '[.error,.error_description]|map(select(.!=null and .!=""))|join(": ")' <<<"$resp" 2>/dev/null)
log "::warning::grok oauth: refresh failed${oerr:+ ($oerr)} - the stored refresh token was likely rotated/consumed by an earlier run and not saved. Re-connect the X account in the dashboard, and set a secrets-write PAT (GH_SECRETS_PAT / GH_GLOBAL) so future rotations persist. See docs/harnesses.md."
return 0
GROK_OAUTH_DEGRADED=1; return 0
fi
new_rt=$(jq -r '.refresh_token // empty' <<<"$resp" 2>/dev/null)
expires_in=$(jq -r '.expires_in // 21600' <<<"$resp" 2>/dev/null) # default 6h
Expand All @@ -180,7 +181,8 @@ grok_oauth_refresh() {
mv "$tmp" "$auth"; chmod 600 "$auth" 2>/dev/null || true
log "::debug::grok oauth: refreshed access token (expires $new_exp)"
else
rm -f "$tmp"; log "::warning::grok oauth: could not rewrite auth.json after refresh - using the on-disk token"; return 0
rm -f "$tmp"; log "::warning::grok oauth: could not rewrite auth.json after refresh - using the on-disk token"
GROK_OAUTH_DEGRADED=1; return 0
fi
# Persist the rotated refresh token so the NEXT run stays valid. Needs a
# secrets-write PAT (the default GITHUB_TOKEN cannot). LOUD on failure - an
Expand All @@ -200,7 +202,23 @@ grok_oauth_refresh() {
}
# Only meaningful on the CI OAuth path (a GROK_CREDENTIALS secret was restored above);
# a local `grok login` session (no GROK_CREDENTIALS) is deliberately left untouched.
GROK_OAUTH_DEGRADED=0
[ -n "${GROK_CREDENTIALS:-}" ] && grok_oauth_refresh

log "::debug::grok setup complete (CLI + auth staged); runs go through run-harness grok"
# exit 0 either way (a refresh failure is not fatal here - the on-disk access token
# may still have some life left) but "auth staged" is a lie when we just warned
# refresh failed. that false-positive is what lets an auth problem masquerade as a
# clean setup right before the run dies downstream on an already-expired token.
if [ "$GROK_OAUTH_DEGRADED" = 1 ]; then
log "::warning::grok setup complete but auth is DEGRADED (OAuth refresh failed - see warning above); proceeding with the existing on-disk token, which may already be expired"
# Signal the degraded state across the process boundary. The caller
# (install-harness.sh) runs this script as a subprocess, so the shell flag
# above cannot reach it. When the caller hands us a marker path, touch it so
# it can print an honest "auth DEGRADED" line instead of a false "auth staged".
[ -n "${GROK_DEGRADED_MARKER:-}" ] && : > "$GROK_DEGRADED_MARKER"
else
log "::debug::grok setup complete (CLI + auth staged); runs go through run-harness grok"
# Clear any stale marker so a healthy run never reports as degraded.
[ -n "${GROK_DEGRADED_MARKER:-}" ] && rm -f "$GROK_DEGRADED_MARKER"
fi
exit 0
29 changes: 29 additions & 0 deletions scripts/tests/test_run_grok.sh
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,35 @@ HOME="$OHOME" PATH="$OBIN:$PATH" GROK_CREDENTIALS="$CREDS" GH_SECRETS_PAT="pat-t
{ [ "$rc" = 0 ] && [ "$(authf key)" = "OLDACCESS" ] && grep -q "invalid_grant" "$OHOME/e4"; } \
&& pass "oauth: invalid_grant → warns, keeps token, rc 0" || bad "oauth invalid_grant (rc=$rc key=$(authf key) err=$(cat "$OHOME/e4"))"

# 3d2. poc: rc=0 is correct (3d, unchanged) but the setup-complete line must not
# claim "staged" when we just warned refresh failed - that false-positive is what
# lets a dead credential masquerade as a healthy setup. reuses the 3d fixture.
{ grep -q "DEGRADED" "$OHOME/e4" && ! grep -q "auth staged" "$OHOME/e4"; } \
&& pass "oauth: invalid_grant → setup message is honestly DEGRADED, not falsely staged" \
|| bad "oauth invalid_grant should not claim staged (err=$(cat "$OHOME/e4"))"
# ...and the happy path (3a's successful refresh) must NOT cry wolf - no DEGRADED line.
! grep -q "DEGRADED" "$OHOME/e1" \
&& pass "oauth: successful refresh → no false DEGRADED warning" \
|| bad "oauth successful refresh wrongly flagged DEGRADED (err=$(cat "$OHOME/e1"))"

# 3d3. the degraded state must cross the process boundary via GROK_DEGRADED_MARKER
# so install-harness.sh (which runs this script as a subprocess) can print an
# honest line. Reuses the 3d invalid_grant fixture; the marker must be touched.
MARK="$OHOME/degraded.marker"; rm -f "$MARK"
HOME="$OHOME" PATH="$OBIN:$PATH" GROK_CREDENTIALS="$CREDS" GH_SECRETS_PAT="pat-test" \
CURL_FAKE_OUT='{"error":"invalid_grant","error_description":"Refresh token has been revoked"}' \
GROK_DEGRADED_MARKER="$MARK" bash "$RABS" setup >/dev/null 2>/dev/null
[ -f "$MARK" ] \
&& pass "oauth: degraded refresh touches GROK_DEGRADED_MARKER for the caller" \
|| bad "oauth degraded did not write the marker file"
# ...and a healthy setup (valid token, refresh skipped) must leave no marker.
CREDS_OK="$(seed_auth "2099-01-01T00:00:00.000000Z")"; MARK_OK="$OHOME/healthy.marker"; rm -f "$MARK_OK"
HOME="$OHOME" PATH="$OBIN:$PATH" GROK_CREDENTIALS="$CREDS_OK" GH_SECRETS_PAT="pat-test" \
GROK_DEGRADED_MARKER="$MARK_OK" bash "$RABS" setup >/dev/null 2>/dev/null
[ ! -f "$MARK_OK" ] \
&& pass "oauth: healthy setup leaves no degraded marker" \
|| bad "oauth healthy path wrongly wrote the degraded marker"

# 3e. XAI_API_KEY path (no GROK_CREDENTIALS) → the OAuth refresh never runs
CURL_LOG="$OHOME/curl2.log"; : >"$CURL_LOG"
HOME="$OHOME" PATH="$OBIN:$PATH" XAI_API_KEY=xai-test CURL_LOG="$CURL_LOG" bash "$RABS" setup >/dev/null 2>&1
Expand Down
Loading