State the Checks API gap instead of prescribing an impossible tick
Fine-grained tokens have no Checks permission. GitHub's permission reference lists no Checks section and no check-run endpoint, and checks is absent from the token form's pre-fill parameters, so the earlier instruction to tick Checks: Read asked for a box that does not exist. A token created with every listed permission still could not read check runs, which is what surfaced this. The prompt now states the consequence rather than offering a remedy: gh pr checks reports commit statuses only and gh run view returns no annotations. Both degrade to empty output rather than a permission error, so without the note they read as a broken CI integration. Job logs are unaffected; they fall under Actions, which is granted. secret_scanning_alerts and vulnerability_alerts move into the pre-filled URL, leaving nothing for the operator to tick beyond repository selection.
This commit is contained in:
@@ -186,15 +186,30 @@ workflows=write actions=write statuses=read security_events=write
|
|||||||
secret_scanning_alerts=read vulnerability_alerts=read
|
secret_scanning_alerts=read vulnerability_alerts=read
|
||||||
```
|
```
|
||||||
|
|
||||||
Two things the form cannot pre-fill, so the task prints them as a checklist:
|
One thing the form cannot pre-fill: **Repository access → Only select repositories
|
||||||
|
→ `api-portal`.** GitHub has no query parameter for repository selection.
|
||||||
|
|
||||||
1. **Repository access → Only select repositories → `api-portal`.** GitHub has no
|
### The Checks API is out of reach
|
||||||
query parameter for repository selection.
|
|
||||||
2. **Checks: Read.** The only permission the agent needs that is absent from
|
Fine-grained tokens cannot read check runs. This is not a permission you forgot to
|
||||||
GitHub's pre-fill parameter list. Without it `gh pr checks` reports no status
|
grant — GitHub's permission reference has no Checks section and lists no check-run
|
||||||
rollup and `gh run view` returns no annotations — both fail as empty results
|
endpoint, so there is no box to tick. Inside the sandbox:
|
||||||
rather than as permission errors, so a missed tick is easy to misread as a
|
|
||||||
broken CI integration.
|
| Command | Behaviour |
|
||||||
|
| --- | --- |
|
||||||
|
| `gh pr checks` | shows commit statuses only, not check runs |
|
||||||
|
| `gh run view` | returns no annotations |
|
||||||
|
| `gh run view --log` | works — job logs fall under Actions |
|
||||||
|
|
||||||
|
Both degrade to empty output rather than a permission error, so they read as a broken
|
||||||
|
CI integration unless you know why. A 403 names what it wanted in the
|
||||||
|
`X-Accepted-GitHub-Permissions` response header.
|
||||||
|
|
||||||
|
Only an installation token from a GitHub App can reach the Checks API. That was
|
||||||
|
evaluated and rejected for this workflow: minting one requires the App private key on
|
||||||
|
every developer's machine, and device-flow user tokens — the alternative that needs no
|
||||||
|
key — were measured and do **not** honour `repository_id`, so they reach every
|
||||||
|
repository in the installation.
|
||||||
|
|
||||||
Generate the token and paste it at the prompt. It is read with the terminal echo off
|
Generate the token and paste it at the prompt. It is read with the terminal echo off
|
||||||
and piped straight into the `sbx` secret store, so it never reaches your shell history.
|
and piped straight into the `sbx` secret store, so it never reaches your shell history.
|
||||||
|
|||||||
+17
-14
@@ -40,13 +40,13 @@ TOKEN_URL_PERMISSIONS=(
|
|||||||
vulnerability_alerts=read
|
vulnerability_alerts=read
|
||||||
)
|
)
|
||||||
|
|
||||||
# "checks" is the one permission the agent needs that GitHub omits from the
|
# Fine-grained tokens cannot reach the Checks API at all: GitHub's permission
|
||||||
# pre-fill parameters, so it has to be ticked by hand. Each entry names what
|
# reference has no Checks section and lists no check-run endpoint, so there is
|
||||||
# breaks without it, because an unticked box fails later as an empty result or
|
# no box to tick. Both calls below degrade to empty output rather than a
|
||||||
# a 403 rather than as a permission error.
|
# permission error, which reads as broken CI unless it is called out.
|
||||||
TOKEN_MANUAL_PERMISSIONS=(
|
TOKEN_LIMITATIONS=(
|
||||||
"Checks: Read - without it 'gh pr checks' reports no status rollup and"
|
"gh pr checks shows only commit statuses, not check runs"
|
||||||
" 'gh run view' returns no annotations"
|
"gh run view returns no annotations"
|
||||||
)
|
)
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
@@ -205,17 +205,20 @@ Create a fine-grained token for $REPOSITORY.
|
|||||||
Everything except the repository is pre-filled. On the page:
|
Everything except the repository is pre-filled. On the page:
|
||||||
|
|
||||||
1. Repository access -> Only select repositories -> ${REPOSITORY#*/}
|
1. Repository access -> Only select repositories -> ${REPOSITORY#*/}
|
||||||
2. Under Permissions -> Repository permissions, tick the one the form
|
2. Generate token, then paste it below.
|
||||||
cannot pre-fill:
|
|
||||||
|
Every permission is pre-filled. Fine-grained tokens cannot read check runs,
|
||||||
|
so inside the sandbox:
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
local permission
|
local limitation
|
||||||
for permission in "${TOKEN_MANUAL_PERMISSIONS[@]}"; do
|
for limitation in "${TOKEN_LIMITATIONS[@]}"; do
|
||||||
printf ' %s\n' "$permission" >&2
|
printf ' %s\n' "$limitation" >&2
|
||||||
done
|
done
|
||||||
|
|
||||||
cat >&2 <<EOF
|
cat >&2 <<'EOF'
|
||||||
3. Generate token, then paste it below.
|
|
||||||
|
A 403 will name what it wanted in the X-Accepted-GitHub-Permissions header.
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|||||||
@@ -69,11 +69,14 @@ for expected in secret_scanning_alerts=read vulnerability_alerts=read statuses=r
|
|||||||
fail "permission dropped out of the pre-filled URL: $expected"
|
fail "permission dropped out of the pre-filled URL: $expected"
|
||||||
done
|
done
|
||||||
|
|
||||||
((${#TOKEN_MANUAL_PERMISSIONS[@]})) ||
|
((${#TOKEN_LIMITATIONS[@]})) ||
|
||||||
fail "the manual checklist is empty; checks is not pre-fillable and must be listed"
|
fail "the limitations list is empty; the Checks gap must be stated"
|
||||||
|
|
||||||
printf '%s\n' "${TOKEN_MANUAL_PERMISSIONS[@]}" | grep -q 'Checks' ||
|
printf '%s\n' "${TOKEN_LIMITATIONS[@]}" | grep -q 'gh pr checks' ||
|
||||||
fail "the manual checklist must name Checks"
|
fail "the limitations must name gh pr checks"
|
||||||
|
|
||||||
|
printf '%s\n' "${TOKEN_LIMITATIONS[@]}" | grep -qi 'tick\|check the box' &&
|
||||||
|
fail "the limitations must not imply Checks can be granted"
|
||||||
|
|
||||||
if ((failures)); then
|
if ((failures)); then
|
||||||
printf '%d assertion(s) failed\n' "$failures" >&2
|
printf '%d assertion(s) failed\n' "$failures" >&2
|
||||||
|
|||||||
Reference in New Issue
Block a user