GH Auth Guard
Run a preflight before any workflow that depends on gh.
Workflow
- Run
$HOME/.codex/skills/private/gh-auth-guard/scripts/ensure-gh-auth.sh. - Treat
gh api user --jq .loginas the primary auth check when network is available. - Do not use
gh auth statusas the primary check inside a sandboxed Codex session.
Set GH_AUTH_PROFILE=classic before the guard when a workflow needs GitHub APIs that fine-grained PATs cannot access, such as repository check-runs.
Outcomes
ok: LOGINContinue with the requestedghworkflow.ok: LOGIN (rehydrated from .../codex-token.env)The session was missingGH_TOKEN; the script repaired it by sourcing$HOME/.config/gh/codex-token.env.missing_profile_token: ...GH_AUTH_PROFILEwas set, but the matching token variable was not present in the session or persisted env file.missing_token: ...There is no token in the session and no persisted token file. Rungh auth login -h github.com --git-protocol https --web, then refresh$HOME/.config/gh/codex-token.env.token_invalid: ...A token was loaded, but GitHub rejected it. Re-authenticate and refresh$HOME/.config/gh/codex-token.env.network_unavailable: ...This is a network reachability problem for the current session, not an auth failure. Retry outside the sandbox or with network access.auth_check_failed: ...Thegh apicheck failed in a way the script did not classify. Inspect stderr and retry with network access.
Rules
- Prefer
gh api user --jq .loginovergh auth statusfor the primary health check. - Never print tokens.
- Treat
$HOME/.config/gh/codex-token.envas the canonical local source forGH_TOKEN. - Load
$HOME/.config/gh/codex-token.envbefore declaring the session unauthenticated. - Use
GH_AUTH_PROFILEto select a persisted token profile:defaultor unset: use the current effectiveGH_TOKEN.classic: exportGH_TOKEN_CLASSICas the effectiveGH_TOKEN.finegrainedorfg: exportGH_TOKEN_FINEGRAINEDas the effectiveGH_TOKEN.
- Use
GH_AUTH_PROFILE=classicfor flows that read GitHub check-runs. Fine-grained PATs do not expose the Checks API permissions needed for those endpoints. - If
git push https://github.com/...fails withCould not resolve host: github.comwhilecurl https://github.comor direct top-levelgh apiworks, treat that as a sandbox or session network limitation, not as bad GitHub credentials.
Repair Flow
If the script reports missing_token or token_invalid, use:
gh auth login -h github.com --git-protocol https --web
TOKEN="$(gh auth token)"
umask 077
printf "export GH_TOKEN='%s'\nexport GITHUB_TOKEN=\"\$GH_TOKEN\"\n" "$TOKEN" > "$HOME/.config/gh/codex-token.env"
chmod 600 "$HOME/.config/gh/codex-token.env"
Ensure $HOME/.zshenv sources the persisted token:
[ -r "$HOME/.config/gh/codex-token.env" ] && . "$HOME/.config/gh/codex-token.env"
For multiple token profiles, persist explicit variables and choose the effective token:
export GH_TOKEN_FINEGRAINED='...'
export GH_TOKEN_CLASSIC='...'
export GH_TOKEN="$GH_TOKEN_CLASSIC"
export GITHUB_TOKEN="$GH_TOKEN"
Then run a profile-specific check when needed:
GH_AUTH_PROFILE=classic $HOME/.codex/skills/private/gh-auth-guard/scripts/ensure-gh-auth.sh
Validation
Run the unit-style mock tests with:
$HOME/.codex/skills/private/gh-auth-guard/scripts/test-ensure-gh-auth.sh