antigravity-code-review.yml and gemini-code-review.yml pass
SUBMODULES_TOKEN as the token for checking out the caller's own
repository. When that token is scoped to a different owner --- which is the
only reason a repo sets it --- the checkout fails before the reviewer runs.
Observed
ucdavis/bcs#612, run
31338714703, job
review / antigravity-review:
Syncing repository: ucdavis/bcs
persist-credentials: false
submodules: true
token: ***
[command]/usr/bin/git remote add origin https://github.com/ucdavis/bcs
##[group]Fetching the repository
##[error]fatal: could not read Username for 'https://github.com': terminal prompts disabled
The process '/usr/bin/git' failed with exit code 128
Three attempts, all identical. The failure is on the main repository fetch,
not the submodule.
Mechanism
The three review workflows do not agree on what SUBMODULES_TOKEN is for.
| Workflow |
Main-repo checkout token |
Submodule handling |
claude-code-review.yml |
default github.token (no token: input) |
separate checkout-submodules composite action, given submodules-token |
antigravity-code-review.yml |
${{ secrets.SUBMODULES_TOKEN || github.token }} |
submodules: input on the same checkout |
gemini-code-review.yml |
${{ secrets.SUBMODULES_TOKEN || github.token }} |
same |
claude-code-review.yml has it right: the caller's own repo is checked out with
the token the runner already has, and SUBMODULES_TOKEN is used only where a
cross-owner fetch actually needs it. Its own comment says so.
The other two conflate the two roles. SUBMODULES_TOKEN exists precisely
because the submodule lives under a different owner than the consumer --- in
ucdavis/bcs it reaches Morrison-Lab/ai-config --- so a token that can read
the submodule has no reason to be able to read ucdavis/bcs, and here it
cannot.
Note the || fallback does not help and actively hides the problem: it fires
only when SUBMODULES_TOKEN is unset. A repo that sets it correctly for its
submodule is exactly the repo that breaks, so the workflows work fine until
someone configures them the way the docs ask.
Blast radius
antigravity-code-review.yml has run once, ever, and that run is the
failure above:
gh run list -R ucdavis/bcs --workflow antigravity-code-review.yml --limit 30 \
--json conclusion,createdAt,headBranch
#=> a single row: 2026-08-09T22:10 failure ci/check-secrets-610
It has never succeeded because no PR had drawn it before --- ai-code-review.yml
picks one agent per PR at random from claude, gemini, antigravity, so a broken
agent stays invisible until its number comes up. That is worth fixing
independently of the token: a selector that can route a PR to an agent which has
never worked will keep producing a red check and no review, on a random third of
PRs.
I have not verified the Gemini path empirically --- it may or may not have been
drawn in ucdavis/bcs --- but it carries the identical token: line, so treat
it as affected by inspection rather than as untested.
Suggested fix
Drop the token: input from both checkouts so the main repo uses the runner's
own token, and move submodule authentication to the same
.github/actions/checkout-submodules composite claude-code-review.yml
already uses. That makes all three consistent and removes the conflation
outright.
A regression test would need a fixture whose SUBMODULES_TOKEN is valid for a
different owner than the caller, which is awkward; a cheaper guard is a lint
asserting that no review workflow passes SUBMODULES_TOKEN to a top-level
actions/checkout token: input.
Found while wiring up check-secrets in ucdavis/bcs (PR #612), which is the
PR that drew Antigravity.
antigravity-code-review.ymlandgemini-code-review.ymlpassSUBMODULES_TOKENas the token for checking out the caller's ownrepository. When that token is scoped to a different owner --- which is the
only reason a repo sets it --- the checkout fails before the reviewer runs.
Observed
ucdavis/bcs#612, run31338714703, job
review / antigravity-review:Three attempts, all identical. The failure is on the main repository fetch,
not the submodule.
Mechanism
The three review workflows do not agree on what
SUBMODULES_TOKENis for.claude-code-review.ymlgithub.token(notoken:input)checkout-submodulescomposite action, givensubmodules-tokenantigravity-code-review.yml${{ secrets.SUBMODULES_TOKEN || github.token }}submodules:input on the same checkoutgemini-code-review.yml${{ secrets.SUBMODULES_TOKEN || github.token }}claude-code-review.ymlhas it right: the caller's own repo is checked out withthe token the runner already has, and
SUBMODULES_TOKENis used only where across-owner fetch actually needs it. Its own comment says so.
The other two conflate the two roles.
SUBMODULES_TOKENexists preciselybecause the submodule lives under a different owner than the consumer --- in
ucdavis/bcsit reachesMorrison-Lab/ai-config--- so a token that can readthe submodule has no reason to be able to read
ucdavis/bcs, and here itcannot.
Note the
||fallback does not help and actively hides the problem: it firesonly when
SUBMODULES_TOKENis unset. A repo that sets it correctly for itssubmodule is exactly the repo that breaks, so the workflows work fine until
someone configures them the way the docs ask.
Blast radius
antigravity-code-review.ymlhas run once, ever, and that run is thefailure above:
gh run list -R ucdavis/bcs --workflow antigravity-code-review.yml --limit 30 \ --json conclusion,createdAt,headBranch #=> a single row: 2026-08-09T22:10 failure ci/check-secrets-610It has never succeeded because no PR had drawn it before ---
ai-code-review.ymlpicks one agent per PR at random from
claude, gemini, antigravity, so a brokenagent stays invisible until its number comes up. That is worth fixing
independently of the token: a selector that can route a PR to an agent which has
never worked will keep producing a red check and no review, on a random third of
PRs.
I have not verified the Gemini path empirically --- it may or may not have been
drawn in
ucdavis/bcs--- but it carries the identicaltoken:line, so treatit as affected by inspection rather than as untested.
Suggested fix
Drop the
token:input from both checkouts so the main repo uses the runner'sown token, and move submodule authentication to the same
.github/actions/checkout-submodulescompositeclaude-code-review.ymlalready uses. That makes all three consistent and removes the conflation
outright.
A regression test would need a fixture whose
SUBMODULES_TOKENis valid for adifferent owner than the caller, which is awkward; a cheaper guard is a lint
asserting that no review workflow passes
SUBMODULES_TOKENto a top-levelactions/checkouttoken:input.Found while wiring up
check-secretsinucdavis/bcs(PR #612), which is thePR that drew Antigravity.