[infra-lead-agent] feat(workspace): add /configs/.github-token static-token fallback #140

Open
infra-lead wants to merge 2 commits from infra-lead/molecule-core:feat/github-token-file-fallback into main

View File

@ -46,7 +46,11 @@
# 2. Fetch fresh token from platform API.
# 3. If platform is unreachable, fall back to GITHUB_TOKEN / GH_TOKEN
# env var (set at container start, valid for up to 60 min).
# 4. If all fail, exit 1 so git falls through to the next credential
# 4. If env var is unset, read static-token file at
# ${CONFIGS_DIR}/.github-token. Operator escape hatch for incidents
# when the platform endpoint is broken; not managed by the platform.
# Never auto-cached, so API recovery is detected immediately.
# 5. If all fail, exit 1 so git falls through to the next credential
# helper in the chain (if any).
#
# # gh CLI integration
@ -197,7 +201,25 @@ _fetch_token_from_api() {
echo "${token}"
}
# _fetch_token — return a fresh token using cache > API > env fallback chain.
# _read_static_token — output static-token-file contents if present and
# non-empty. Returns 1 if file missing or empty. Never writes to cache —
# operator escape hatch; we want API recovery to be detected on the very
# next call without 50-min stale-cache stickiness on the workaround.
_read_static_token() {
local static_file="${CONFIGS_DIR}/.github-token"
if [ ! -f "${static_file}" ]; then
return 1
fi
local static_token
static_token=$(cat "${static_file}" 2>/dev/null | tr -d '[:space:]')
if [ -z "${static_token}" ]; then
return 1
fi
echo "${static_token}"
return 0
}
# _fetch_token — return a fresh token using cache > API > env > static fallback chain.
# Outputs the raw token string on success; exits non-zero if all sources fail.
_fetch_token() {
# 1. Try cache first.
@ -222,6 +244,16 @@ _fetch_token() {
return 0
fi
# 4. Static-token file fallback — operator escape hatch for when
# the platform API is broken AND no env var is set.
# Manually written by infra; never auto-cached so API recovery
# is detected on the very next call.
static_token=$(_read_static_token 2>/dev/null) && {
echo "[molecule-git-token-helper] API + env exhausted, using static-token file" >&2
echo "${static_token}"
return 0
}
echo "[molecule-git-token-helper] all token sources exhausted" >&2
return 1
}
@ -240,20 +272,38 @@ case "${ACTION}" in
# No-op — the platform manages token lifecycle.
;;
_fetch_token)
# Return raw token (cache > API > env fallback).
# Return raw token (cache > API > env > static fallback).
_fetch_token
;;
_refresh_gh)
# Refresh cache AND update gh CLI auth in one shot.
# Called by molecule-gh-token-refresh.sh background daemon.
# Force-bypass cache to get a definitely fresh token.
api_token=$(_fetch_token_from_api) || {
echo "[molecule-git-token-helper] _refresh_gh: API fetch failed" >&2
exit 1
}
_write_cache "${api_token}"
# On API failure, fall through env → static-file like _fetch_token does,
# but do NOT write the cache (those aren't API-issued tokens).
api_token=$(_fetch_token_from_api) || api_token=""
chosen_token=""
if [ -n "${api_token}" ]; then
_write_cache "${api_token}"
chosen_token="${api_token}"
else
env_token="${GITHUB_TOKEN:-${GH_TOKEN:-}}"
if [ -n "${env_token}" ]; then
chosen_token="${env_token}"
echo "[molecule-git-token-helper] _refresh_gh: API failed, using env GITHUB_TOKEN" >&2
else
static_token=$(_read_static_token 2>/dev/null) && {
chosen_token="${static_token}"
echo "[molecule-git-token-helper] _refresh_gh: API failed + env unset, using static-token file" >&2
}
fi
if [ -z "${chosen_token}" ]; then
echo "[molecule-git-token-helper] _refresh_gh: API fetch failed and no fallback available" >&2
exit 1
fi
fi
# Update gh CLI auth — gh auth login reads token from stdin.
echo "${api_token}" | gh auth login --hostname github.com --with-token 2>/dev/null || {
echo "${chosen_token}" | gh auth login --hostname github.com --with-token 2>/dev/null || {
echo "[molecule-git-token-helper] _refresh_gh: gh auth login failed (non-fatal)" >&2
}
# Also update GH_TOKEN file for scripts that source it.
@ -265,7 +315,7 @@ case "${ACTION}" in
# function); shadow with a uniquely-named global instead.
_gh_prev_umask=$(umask)
umask 077
printf '%s' "${api_token}" > "${gh_token_file}.tmp"
printf '%s' "${chosen_token}" > "${gh_token_file}.tmp"
mv -f "${gh_token_file}.tmp" "${gh_token_file}"
umask "${_gh_prev_umask}"
unset _gh_prev_umask