Skip to content

antigravity/gemini review workflows use SUBMODULES_TOKEN to check out the caller's own repo, which fails for cross-owner consumers #442

Description

@d-morrison

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions