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
28 changes: 28 additions & 0 deletions .github/workflows/_selftest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
contents: read
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

Check warning on line 31 in .github/workflows/_selftest.yml

View workflow job for this annotation

GitHub Actions / lint-yaml

31:73 [comments] too few spaces before comment: expected 2
- name: Lint YAML
uses: ./lint-yaml
lint-markdown:
Expand All @@ -38,7 +38,7 @@
contents: read
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

Check warning on line 41 in .github/workflows/_selftest.yml

View workflow job for this annotation

GitHub Actions / lint-yaml

41:73 [comments] too few spaces before comment: expected 2
- name: Lint Markdown
uses: ./lint-markdown
lint-qmd:
Expand All @@ -48,7 +48,7 @@
contents: read
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

Check warning on line 51 in .github/workflows/_selftest.yml

View workflow job for this annotation

GitHub Actions / lint-yaml

51:73 [comments] too few spaces before comment: expected 2
- name: Lint QMD prose
uses: ./lint-qmd
with:
Expand All @@ -66,7 +66,7 @@
contents: read
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

Check warning on line 69 in .github/workflows/_selftest.yml

View workflow job for this annotation

GitHub Actions / lint-yaml

69:73 [comments] too few spaces before comment: expected 2
- name: Set up R
uses: r-lib/actions/setup-r@d3c5be51b12e724e68f33216ca3c148b66d5f0b6 # v2.12.1
with:
Expand Down Expand Up @@ -1487,6 +1487,34 @@
fi
echo "claude.yml's SENSITIVE_PATHS mirror matches claude-code-action@${sha}."

# gha#442: SUBMODULES_TOKEN authenticates a cross-owner SUBMODULE fetch
# (via the checkout-submodules composite's `submodules-token:` input) and
# must never gate the caller's own repo checkout --- a consumer that sets
# it correctly for its own submodule is exactly the consumer whose main
# checkout then fails, since the token has no reason to be able to read the
# caller's repo. The anchor is `^\s*token:`, not a bare `token:` substring
# match, so this does not also flag `submodules-token:` (which legitimately
# carries the secret) --- a trimmed line starting with "submodules-token:"
# never matches a pattern requiring "token:" immediately after the leading
# whitespace.
lint-checkout-tokens:
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: read
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Assert no workflow passes SUBMODULES_TOKEN to a top-level checkout's token input
shell: bash
run: |
set -euo pipefail
if grep -rnE '^\s*token:\s*\$\{\{[^}]*SUBMODULES_TOKEN' .github/workflows/*.yml; then
echo "::error::A workflow above passes SUBMODULES_TOKEN to a top-level actions/checkout 'token:' input (see gha#442) --- it authenticates a cross-owner submodule fetch, not the caller's own repo. Use the checkout-submodules composite's 'submodules-token:' input instead."
exit 1
fi
echo "No workflow passes SUBMODULES_TOKEN to a top-level checkout token: input."

# Covers the open-failure-issue action. report-failure.yml is its only
# caller so far; check-links.yml's migration onto it is deferred to gha#327,
# since a @v2 reference to a not-yet-released action fails at job-prepare
Expand Down
15 changes: 13 additions & 2 deletions .github/workflows/antigravity-code-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,13 +102,24 @@ jobs:
echo "blocked=false" >> "$GITHUB_OUTPUT"
fi

# The caller's own repo is checked out with the runner's default
# github.token, never SUBMODULES_TOKEN --- that secret authenticates a
# CROSS-OWNER submodule fetch and has no reason to (and, when a
# consumer sets it correctly for its own submodule, frequently cannot)
# read the caller's own repo (gha#442). Submodule auth is handled below
# by the shared checkout-submodules composite, the same one
# claude-code-review.yml already uses.
- name: Checkout repository
if: success() && steps.dispatch-guard.outputs.blocked != 'true'
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
submodules: ${{ inputs.checkout-submodules }}
token: ${{ secrets.SUBMODULES_TOKEN || github.token }}

- name: Checkout submodules
if: success() && steps.dispatch-guard.outputs.blocked != 'true' && inputs.checkout-submodules
uses: Morrison-Lab/gha/.github/actions/checkout-submodules@v2
with:
submodules-token: ${{ secrets.SUBMODULES_TOKEN }}

- name: Run Antigravity Action
if: success() && steps.dispatch-guard.outputs.blocked != 'true'
Expand Down
14 changes: 12 additions & 2 deletions .github/workflows/gemini-code-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -162,12 +162,22 @@ jobs:
# the guard step is skipped entirely, so its output is the empty string;
# there the job `if:` has already applied the equivalent checks from the
# event payload.
# The caller's own repo is checked out with the runner's default
# github.token, never SUBMODULES_TOKEN --- that secret authenticates a
# CROSS-OWNER submodule fetch and has no reason to (and, when a
# consumer sets it correctly for its own submodule, frequently cannot)
# read the caller's own repo (gha#442). Submodule auth is handled below
# by the shared checkout-submodules composite, the same one
# claude-code-review.yml already uses.
- name: Checkout repository
if: success() && steps.dispatch-guard.outputs.blocked != 'true'
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Checkout submodules
if: success() && steps.dispatch-guard.outputs.blocked != 'true' && inputs.checkout-submodules
uses: Morrison-Lab/gha/.github/actions/checkout-submodules@v2
with:
submodules: ${{ inputs.checkout-submodules }}
token: ${{ secrets.SUBMODULES_TOKEN || github.token }}
submodules-token: ${{ secrets.SUBMODULES_TOKEN }}

# Pinned to a release SHA per README's "Pinning third-party actions".
# run-gemini-cli publishes v0 / v0.1.x and has no v1 tag, so a `@v1` ref
Expand Down
14 changes: 12 additions & 2 deletions .github/workflows/gemini.yml
Original file line number Diff line number Diff line change
Expand Up @@ -278,12 +278,22 @@ jobs:
echo "thread_line=This is an unattended run in $REPO with no associated issue or pull request, so there is no thread to read or reply to." >> "$GITHUB_OUTPUT"
fi

# The caller's own repo is checked out with the runner's default
# github.token, never SUBMODULES_TOKEN --- that secret authenticates a
# CROSS-OWNER submodule fetch and has no reason to (and, when a
# consumer sets it correctly for its own submodule, frequently cannot)
# read the caller's own repo (gha#442). Submodule auth is handled below
# by the shared checkout-submodules composite, the same one claude.yml
# already uses.
- name: Checkout repository
if: steps.gate.outputs.skip != 'true'
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Checkout submodules
if: steps.gate.outputs.skip != 'true' && inputs.checkout-submodules
uses: Morrison-Lab/gha/.github/actions/checkout-submodules@v2
with:
submodules: ${{ inputs.checkout-submodules }}
token: ${{ secrets.SUBMODULES_TOKEN || github.token }}
submodules-token: ${{ secrets.SUBMODULES_TOKEN }}

# Passed via env rather than inlined into the script, so a caller's value
# is a shell word list and never interpreted as script.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
- **`antigravity-code-review.yml`, `gemini-code-review.yml`, and `gemini.yml`
no longer fail to check out the CALLER's own repo when `SUBMODULES_TOKEN`
is set for a cross-owner submodule** (#442).
All three passed
`${{ secrets.SUBMODULES_TOKEN || github.token }}` as the top-level
`actions/checkout` `token:` input --- the same input `claude-code-review.yml`
leaves at the runner's default `github.token`.
`SUBMODULES_TOKEN` exists
precisely because a submodule lives under a different owner than the
consumer, so a token scoped to read the submodule has no reason to be able
to read the caller's own repo, and in `ucdavis/bcs` it could not: the main
checkout failed with `fatal: could not read Username for
'https://github.com': terminal prompts disabled` on every run, so a repo
that configured `SUBMODULES_TOKEN` correctly for its submodule got a red
check and zero automated review from two of its three configured agents.
All three now check out the caller with the runner's own token and
authenticate the submodule fetch (when `checkout-submodules` is set)
through the shared `checkout-submodules` composite action, matching
`claude-code-review.yml`.
A new `lint-checkout-tokens` selftest job asserts
no workflow in this repo passes `SUBMODULES_TOKEN` to a top-level
`actions/checkout` `token:` input, so the conflation can't recur silently.
Loading