Skip to content

fix(enable-auto-merge): gate-lookup token mint assumes scope intersection, but create-github-app-token 422s #646

Description

@devantler

🤖 Generated by the Daily AI Engineer

Evidence

#626 (fixing #559) established a behaviour of actions/create-github-app-token that contradicts an
assumption still encoded elsewhere in the same workflow:

An installation WITHOUT the Workflows grant cannot mint a Workflows-scoped token —
create-github-app-token 422s rather than intersecting the scope away — which would fail the
required check for EVERY PR there before the arming step's graceful-degrade could run.

#626 hardened the arming mint accordingly: id: app-token is now continue-on-error: true, backed
by a base-scoped app-token-base fallback gated on steps.app-token.outcome == 'failure'.

The gate-lookup mint in the same job was not touched and still assumes the opposite. In
.github/workflows/enable-auto-merge.yaml:

# ... If a consumer's App installation
# lacks Checks/Actions read, the mint silently intersects them away and
# the gate's lookups fail, which fails the gate step CLOSED (no arming),
# never open.
- name: 🔑 Generate gate-lookup token (enforced runs only)
  id: gate-token          # no continue-on-error, no fallback
  with:
    permission-checks: read
    permission-actions: read
    ...

Both claims cannot be true. Per #626, the 422 behaviour is the real one.

Impact

On a consumer whose App installation lacks Checks or Actions read, with enforcement enabled
(enforce-review-gates input or ENFORCE_MERGE_GATES variable):

  • the gate-token mint 422s, the step has no continue-on-error, so the job fails;
  • the result is a permanently-red required auto-merge check on every PR in that repo — the exact
    symptom Enable Auto-Merge fails on PRs that modify workflow files (App token lacks workflows permission) #559 was filed for, on the enforced path instead of the arming path;
  • the comment's promised behaviour ("fails the gate step CLOSED (no arming), never open") does not
    happen as described — nothing is armed, so the security posture is not weakened, but the operator
    sees a red check rather than a clean decline.

Latent, not live: it needs enforcement on at a consumer lacking those grants. Enforcement is
default-off and flipped per repo after validation, so this bites the next repo that enables it.

The stale comment is itself a hazard — it is load-bearing documentation about a security gate, and it
misled an agent into designing a fix on the wrong premise during this run.

Expected behaviour

An installation that cannot mint the gate-lookup scopes must produce a clean, loud decline — no
arming, no red required check — and must never arm on unverified gates.

Constraint — do not weaken the gate

AGENTS.md and the step's own comment are explicit that this fail-closed review/pre-merge gate must
never become warn-only. A naive continue-on-error: true here would be a regression: the gates
step falls back to steps.app-token.outputs.token, whose scope carries no checks:read, so its
lookups would fail on a token that silently differs — the failure must keep aborting the gate
(armable never set), never proceed on an empty snapshot.

Acceptance criteria

  • A missing Checks/Actions grant no longer fails the auto-merge job; the run declines cleanly
    (warning + no arming) instead of leaving a red required check.
  • Enforced mode still cannot arm when the gate's lookups cannot be proven green — the
    fail-closed contract in test-enable-auto-merge-pentad-gate.sh stays green and is extended to
    cover this path.
  • The misleading "silently intersects them away" comment is corrected to the verified 422
    behaviour, so the next reader/agent is not misled.
  • Both states covered per the repo's convention (installation with the grants; installation
    without).

Rough size

S–M — one mint step plus its fallback/decline wiring, a comment correction, and an added assertion in
the existing pentad-gate self-test. Mirrors the shape #626 already landed for the arming mint.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    ✅ Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions