Repository navigation
ci(fleet-write): grant permission-contents: write to the mint step so the relay can arm auto-merge - #19767
Conversation
…can arm auto-merge GitHub's enablePullRequestAutoMerge / disablePullRequestAutoMerge mutations require contents: write on the App token; the relay's first live automerge_enable answered "Resource not accessible by integration" with the token narrowed to issues, pull-requests and metadata alone. The mint step (actions/create-github-app-token@v2) gains permission-contents: write beside the three existing permission-* inputs, with a comment naming the one consumer and that the op table has no contents op. PERMISSIONS in ops.mjs gains contents: 'write', and the automerge_enable / automerge_disable rows spend it, so the validator's permission read stays truthful. The validator's self-test pins the map entry by entry, the two rows, that no other row spends contents, that every contents spender is an auto-merge GraphQL mutation, and that the workflow's permission-* inputs mirror PERMISSIONS exactly. Nothing else changes: no new op, the sender gate, caps and ceilings untouched. Claude-Session: https://claude.ai/code/session_01GnJon4xkRvphn4w28xx3An Co-authored-by: Claude <noreply@anthropic.com>
维护者速读(终稿)席位:总监席(summon #27, 改了什么: 为什么改:#19755 落地后第一笔真实使用实测:中继翻 ready 成功,开 auto-merge 被拒「Resource not accessible by integration」——正是 #19701 里「先不预授、被拒再加」的那一条。没有它,车队入队的最后一步仍要用席位自己的用户身份。 风险与代价:token 多一项 席位意见:通过。CI 绿( 你要做的:合并本 PR(Squash)。合并后我用下一张入队的 PR 回读 Generated by Claude Code |
Fixes #19762
What changed
Touches
.github/workflows/**, so this is a draft the maintainer merges by hand.permission-contents: write. In.github/workflows/fleet-write.yml,actions/create-github-app-token@v2gainspermission-contents: writebeside the three existingpermission-*inputs, with a comment naming the one consumer — GitHub'senablePullRequestAutoMerge/disablePullRequestAutoMergemutations requirecontents: writeon the token (measured on the relay's first liveautomerge_enable: "Resource not accessible by integration") — and stating that the op table has no contents op, so the grant is spent only by those two mutations. The header's permission list says the same.PERMISSIONSinscripts/pm/fleet-write/ops.mjsgainscontents: 'write'; theautomerge_enableandautomerge_disablerows carrypermission: 'contents', so the validator's permission read stays a true statement of what each row spends. The header paragraph on permissions is updated.validate.mjs --self-test, the refused-by-construction battery, 9 → 14 pinned cases): the map is exactlyissues/pull-requests/contentswrite andmetadataread; the two auto-merge rows spendcontents; no other row does; everycontentsspender is an auto-merge GraphQL mutation, never a REST path; and the workflow'spermission-*inputs, read from the file on disk, mirrorPERMISSIONSexactly — a grant added on one side without the other reds.Verification record
Batteries, each run alone with its exit captured before any pipe (worktree at 182209b, base
origin/maindc1b986):pnpm check:pm-fleet-write-validatepnpm check:pm-fleet-write-executepnpm check:pm-fleet-write-dispatchpnpm check:pm-with-fleetpnpm check:pm-post-stampedpnpm check:pm-label-writepnpm check:pm-issue-createpnpm check:pm-close-cardspnpm check:pm-write-pacepnpm check:workflow-status-functionspnpm check:workflow-step-name-quotingpnpm check:required-contextsnpx eslint --no-inline-configon the two changed.mjsfiles: exit 0.Gates —
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandson the edited tree derived 54 families (3 paths vs merge base dc1b986; 52 changed lines, under the human-merge threshold). Each was run alone with its exit code captured before any pipe; all 54 exited 0.--ranwith the codes recorded:54 derived famil(ies) accounted for — 54 run, 0 NOT-MEASURED (a DERIVED zero — all 54 recorded an exit code and none of them is 3). Repo-widepnpm lintis CI's run; the changed files were linted directly (above).The live grant itself cannot be proven before merge (a workflow change runs only once it is on
main); the card's post-merge verification is the director seat's: a two-action relay request (pr_draft+pr_ready, orautomerge_enableon the next queued PR) reading backenabledBy=objectstack-fleet[bot].Changeset
None:
.github/workflows/**andscripts/pm/**publish nothing from any released package, soskip-changesetapplies. This dispatch forbids label writes, so the label is the seat's to apply.Acceptance notes
origin/mainat dc1b986, not on top of the fleet-write: derive the seat session from the container (CLAUDE_CODE_REMOTE_SESSION_ID) so the allowed command spelling routes through the relay; the workflow's Actions state is the kill switch #19755 branch; PR fix(pm): fleet-write derives the seat session from the container; the workflow’s Actions state is the kill switch; size-routed direct for post-stamped #19760 is still landing and is not touched here. Both editscripts/pm/fleet-write/ops.mjsin disjoint regions (the session constants there, the permission map and two rows here), so no textual conflict is expected once fix(pm): fleet-write derives the seat session from the container; the workflow’s Actions state is the kill switch; size-routed direct for post-stamped #19760 merges; if one appears, this branch rebases ontomain.Generated by Claude Code