Skip to content

fix(gate): mount canary uses optional admin token, not an invalid GITHUB_TOKEN scope#25

Merged
Antawari merged 1 commit into
mainfrom
cf-quality/canary-token-fix
Jun 28, 2026
Merged

fix(gate): mount canary uses optional admin token, not an invalid GITHUB_TOKEN scope#25
Antawari merged 1 commit into
mainfrom
cf-quality/canary-token-fix

Conversation

@Antawari

Copy link
Copy Markdown
Contributor

What & why

The self-verifying required-mount canary declared administration: read in the reusable workflow's permissions: block (and in the caller stub). administration is not one of the scopes grantable to the automatic GITHUB_TOKEN — declaring it makes the reusable-workflow YAML invalid, so the gate job dies at 0s and never emits a gate / gate status check. That silently broke the gate for consumers wiring this kit (a downstream gauge PR has been sitting blocked with no gate check at all).

administration is a valid permission for fine-grained PATs / GitHub Apps — just not for GITHUB_TOKEN. So the canary must read branch protection with a separate, optional token.

The fix

  • Drop the invalid scope. administration: read removed from the gate's top-level permissions: and from templates/quality.caller.yml; both now declare only grantable scopes (contents: read).
  • Optional admin token. The canary reads protection via secrets.CI_KIT_TOKEN (a fine-grained PAT / GitHub App installation token carrying repo Administration: read), forwarded by the caller's existing secrets: inherit. GH_TOKEN falls back to github.token so the CLI always has a host token.
  • Degrade-vs-strict. With no CI_KIT_TOKEN: the canary emits a ::warning:: and passes — un-provisioned consumers are not bricked, and the out-of-band Constable sweep + check-required-mount.sh remain the enforcement. With the token: it runs the strict proof and refuses (exit 1) when the gate cannot prove it is a required, non-bypassable check.

Tests (the planted-violation goes red on main)

  • A GITHUB_TOKEN permission allowlist test + a regression guard asserting no workflow/caller declares administration again — both fail on the pre-fix tree and pass here.
  • Coverage of the optional-token env wiring and the degrade path.
  • Full suite: 36/36 in test_workflows.py; the deterministic battery (ruff, ruff-format, mypy, complexipy, file-budget, import-contract) is green on this tree.

Follow-ups (operator gates — not in this PR)

  1. To give the canary teeth, provision a CI_KIT_TOKEN org/repo secret (admin:read PAT/App). Until then the leg degrades to a warning by design.
  2. Open question for the maintainer: once the token is provisioned org-wide, should the absent-token default flip from warn to fail-hard? (Raised to the operator.)
  3. Consumers re-pin to this kit SHA after merge to pick up the fix (a downstream caller is blocked on it).

🔒 Law-pending — open for the operator's gate; do not auto-merge.

…t an invalid GITHUB_TOKEN scope

The self-verifying required-mount canary declared `administration: read` in the
workflow (and caller stub) permissions. `administration` is not a grantable
GITHUB_TOKEN scope — declaring it makes the reusable-workflow YAML invalid, so
the gate job dies at 0s and never emits a `gate / gate` status check. That broke
the gate for every consumer wiring this kit (a downstream gauge PR sat blocked
with no gate check at all).

Fix:
- Drop `administration: read` from the gate's top-level permissions and from the
  caller stub; keep `contents: read`. Both now declare only grantable scopes.
- Route the canary's branch-protection read through an OPTIONAL `CI_KIT_TOKEN`
  secret (a fine-grained PAT / GitHub App installation token carrying repo
  Administration:read), forwarded by the caller's existing `secrets: inherit`.
- Degrade-vs-strict: with no token the canary emits a warning and passes (the
  out-of-band Constable sweep + check-required-mount.sh remain the enforcement,
  so un-provisioned consumers are not bricked); with the token it runs the strict
  proof and refuses (exit 1) when the gate cannot prove it is required.
- Tests: add a GITHUB_TOKEN permission allowlist + a regression guard that fails
  if any workflow/caller declares the non-grantable `administration` scope again
  (this guard goes red on the pre-fix tree), plus coverage of the optional-token
  wiring and the degrade path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Antawari Antawari merged commit 86c9e0b into main Jun 28, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant