Skip to content

pin job cannot push its bump branch — the broker's front-desk entry never requested contents, and the scope assertion did not check for it #87

Description

@bdelanghe

The pin job in org-defaults.yml cannot complete its bump. It fails on every push to main that changes a fetched .claude/ file, which means the pin never self-heals and main sits red on schema until someone bumps it by hand (as #86 does for #84).

The failure

Run 30703899767, on the merge of #84:

Switched to a new branch 'bootstrap-pin/bump'
[bootstrap-pin/bump 9c40f1c] chore(bootstrap): pin a7cb962f8920 and re-record digests
 1 file changed, 3 insertions(+), 3 deletions(-)
remote: Permission to bounded-systems/.github.git denied to bounded-systems-front-desk[bot].
fatal: unable to access 'https://github.com/bounded-systems/.github.git/': The requested URL returned error: 403
##[error]Process completed with exit code 128

The token minted fine and the generator did its work. The front-desk App installation is missing contents: write on this repo, so git push -f origin bootstrap-pin/bump 403s.

Two separate things to fix

1. The grant (needs a human)

Give the front-desk App installation contents: write on bounded-systems/.github, or point the job at an identity that has it.

Worth confirming which of the two wrangler.jsonc cases this is, since the repo already records the reading: mint succeeded + the call 403'd means the broker did not ask for the scope, and that is fixable in the registry. A missing installation grant would have failed the mint outright, which it did not. So this looks like the broker-side case.

2. The assertion is one scope short (fixable here)

The job has a step named "The minted token can actually open a PR" which asserts pull_requests: write before doing the work. Its comment explains exactly why:

Assert the scope BEFORE doing the work. […] until now nothing consumed it, so a missing scope surfaced only as a 403 at gh pr create, after the branch had already been pushed.

The same argument applies one step earlier and was not extended to it. Pushing the branch needs contents: write, that scope is never asserted, and so the failure arrived as a bare 403 and exit 128 — which killed the script before any of the carefully written ::error title=pin: branch pushed, PR not opened:: annotations below could run. The job comments predict a failure mode ("branch pushed, PR not opened") that cannot occur, because the branch cannot be pushed at all.

Adding contents to that check makes the next occurrence name itself instead of costing a log dig.

Impact while it stands

The pin is the fallback path's trust anchor, so this is invisible to anyone with .github attached — the attached checkout always wins — and only bites a session that does not have it. That is the same "works for me, fails for a session without .github" shape bootstrap-pin.test.mjs was written about after #71 and #72, now recurring one layer out: the gate correctly detects the stale pin, and the thing meant to act on that detection is broken.

Related: #85, on the setup-script field. Different mechanism, same theme — the automation around the bootstrap is less load-bearing than it reads.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Status
    Done

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions