From ec8d2538a9e0ebde6de6165470c3237b1156996e Mon Sep 17 00:00:00 2001 From: letur Date: Thu, 10 Sep 2026 08:54:51 +0200 Subject: [PATCH] feat(queue): add thurbox to the auto-merge set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `AUTO_MERGE_REPOS` now names `github.com/Thurbeen/thurbox` alongside fleet and thurview, host-qualified like its neighbours. It joins on the stated test rather than on the fleet having work there: thurbox carries its own `.no-mistakes.yaml` — `just lint` plus a rustdoc build with warnings denied — and four CI workflows, so the attestation gate has a pipeline behind it and the checks gate has checks behind it. The comment above the set records that, in the same terms the thurview paragraph uses. No gate is loosened. `queue-selftest.sh`'s new section 9i drives the shepherd over two thurbox pull requests through the existing fake GitHub: the attested, green one is squash-merged unattended, the one nothing vetted is still handed back, and a bare `Thurbeen/thurbox` in `FLEET_AUTO_MERGE_REPOS` is refused rather than matched against the slug — the host-qualification rule this addition could quietly weaken. Claude-Session: https://claude.ai/code/session_01EuJuuMUd9NjJKCDHecNQ3Y --- .agents/skills/fleet-queue/SKILL.md | 8 +-- scripts/lib/queue.py | 14 ++++- scripts/queue-selftest.sh | 93 +++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+), 5 deletions(-) diff --git a/.agents/skills/fleet-queue/SKILL.md b/.agents/skills/fleet-queue/SKILL.md index f705c83..78a1bc5 100644 --- a/.agents/skills/fleet-queue/SKILL.md +++ b/.agents/skills/fleet-queue/SKILL.md @@ -743,10 +743,10 @@ Three things it will not do, and they are what make it safe to run: **On merging, which is the part that runs unattended.** `Thurbeen/fleet` is public and has a fork, so "merge every open PR on a timer" has to survive a stranger opening one. Fleet merges only in the repos on `AUTO_MERGE_REPOS` in -`scripts/lib/queue.py` — `github.com/Thurbeen/fleet` and -`github.com/Thurbeen/thurview` — and only when **all** of these hold. Entries -there are HOST-QUALIFIED and one that names no forge is refused rather than -matched: `Thurbeen/fleet` on github.com and `Thurbeen/fleet` on a self-hosted +`scripts/lib/queue.py` — `github.com/Thurbeen/fleet`, +`github.com/Thurbeen/thurbox` and `github.com/Thurbeen/thurview` — and only +when **all** of these hold. Entries there are HOST-QUALIFIED and one that names +no forge is refused rather than matched: `Thurbeen/fleet` on github.com and `Thurbeen/fleet` on a self-hosted instance are not the same repository. - **The head branch is in that repository**, not a fork. A stranger cannot diff --git a/scripts/lib/queue.py b/scripts/lib/queue.py index 284641d..02308b3 100644 --- a/scripts/lib/queue.py +++ b/scripts/lib/queue.py @@ -4018,7 +4018,19 @@ def cmd_refuel(args) -> int: # those would be a repo where every gate but `author_can_push` is vacuous — # that is the test for adding the next one, not whether the fleet happens to # have work there. -AUTO_MERGE_REPOS = {"github.com/Thurbeen/fleet", "github.com/Thurbeen/thurview"} +# +# `Thurbeen/thurbox` was added on the same instruction and passes the same +# test: its own `.no-mistakes.yaml` runs `just lint` and a rustdoc build with +# warnings denied, and its CI is four workflows. So the attestation gate has a +# pipeline behind it there and the checks gate has checks behind it, which is +# the whole of what the test asks. Nothing was relaxed for it — thurbox pull +# requests clear the same five gates fleet's own do, and +# `queue-selftest.sh`'s 9i is where that is checked. +AUTO_MERGE_REPOS = { + "github.com/Thurbeen/fleet", + "github.com/Thurbeen/thurbox", + "github.com/Thurbeen/thurview", +} # The one way to say it somewhere other than here, and it REPLACES the set # rather than adding to it: a fleet driving somebody else's repositories is a diff --git a/scripts/queue-selftest.sh b/scripts/queue-selftest.sh index bd195a9..7f9ca48 100755 --- a/scripts/queue-selftest.sh +++ b/scripts/queue-selftest.sh @@ -2422,6 +2422,99 @@ refute "and nothing from it is merged" "pr merge" "$(cat "$shep/many.log")" refute "and it is not reported as having zero open pull requests either" \ "no open pull requests" "$out" +# --- 9i. thurbox is on the allowlist, on the same gates as fleet ------------- +# +# The allowlist grew, so the claim under test is that adding a repository adds +# a REPOSITORY and not a looser rule. Two pull requests on thurbox, both green +# and mergeable and both on branches that are ours: the attested one merges the +# way fleet's own do, and the one nothing vetted is still handed back. +# +# The third claim is the one this addition could quietly weaken. The allowlist +# is matched HOST-QUALIFIED, so `Thurbeen/thurbox` — the way a person writes it +# and the way the operator asked for it — is refused rather than matched +# against the bare slug. 13e proves that for a forge that is not GitHub; this +# proves it for the repo that was just added, where the bare slug is the +# plausible typo. + +ttopic="$($QUEUE topic add thurbox-allowlist --title 'Auto-merge in thurbox' \ + --prompt 'thurbox merges on the same gates as fleet, and only host-qualified' 2>/dev/null)" +$QUEUE add "$ttopic" attested --title 'A thurbox PR the pipeline vetted' \ + --repo "$srepo" --branch tbx/attested --number 01 >/dev/null +cat >"$FLEET_QUEUE_DIR/$ttopic/01-attested/result.md" <<'EOF' +--- +outcome: shipped +artifact: https://github.com/Thurbeen/thurbox/pull/201 +--- +Shipped it. +EOF +git -C "$srepo" branch tbx/attested + +python3 - "$shep/gh" <<'PY' +import json +import sys + +out = sys.argv[1] +green = {"__typename": "CheckRun", "name": "CI", "status": "COMPLETED", + "conclusion": "SUCCESS"} +STEPS = [ + {"step": s, "status": "completed"} + for s in ("intent", "rebase", "review", "test", "document", "lint", "push") +] + [{"step": "pr", "status": "running"}, {"step": "ci", "status": "pending"}] + + +def pr(n, branch, body): + sha = f"{n:040d}" + json.dump({ + "number": n, "state": "OPEN", "title": f"PR {n}", "isDraft": False, + "url": f"https://github.com/Thurbeen/thurbox/pull/{n}", + "mergeable": "MERGEABLE", "reviewDecision": "", "statusCheckRollup": [green], + "body": body, "headRefName": branch, "baseRefName": "main", + "headRefOid": sha, "author": {"login": "LeTuR", "is_bot": False}, + "headRepositoryOwner": {"login": "Thurbeen"}, "isCrossRepository": False, + }, open(f"{out}/{n}.json", "w")) + + +payload = json.dumps({"head_sha": f"{201:040d}", "steps": STEPS}) +pr(201, "tbx/attested", + f"\n\nShipped it.\n") +# Green in every way the forge can see, and nothing vetted the head that would +# land. No task records it either, so nothing here spawns a fixer. +pr(202, "tbx/unvetted", "Reviewed, tested, linted, and opened through the pipeline.\n") +PY + +# The artifact reaches the record through `collect`, the same way every +# other task's does, and the shepherd derives the repository from it. +env PATH="$shep/bin:$base_path" $QUEUE collect >/dev/null + +out="$(env PATH="$shep/bin:$base_path" $QUEUE shepherd --topic "$ttopic" 2>&1)" +expect "the shepherd reaches thurbox at all" "Thurbeen/thurbox" "$out" +if grep -qx 201 "$shep/merged" 2>/dev/null; then + pass "an attested, green thurbox pull request is merged unattended" +else + fail "an attested, green thurbox pull request is merged unattended" \ + "$out$nl$(cat "$shep/merged" 2>/dev/null)" +fi +expect "and by the same squash fleet's own are merged by" \ + "pr merge https://github.com/Thurbeen/thurbox/pull/201 --squash --delete-branch" \ + "$(cat "$shep/gh.log")" + +if grep -qx 202 "$shep/merged" 2>/dev/null; then + fail "joining the allowlist loosens no gate: an unattested one is not merged" \ + "$(cat "$shep/merged")" +else + pass "joining the allowlist loosens no gate: an unattested one is not merged" +fi +expect "and it is named for what it lacks, not passed over" \ + "the body carries no no-mistakes attestation" "$out" + +# The typo the operator's own words invite: the allowlist is host-qualified, +# and `Thurbeen/thurbox` names no forge. +out="$(env PATH="$shep/bin:$base_path" FLEET_AUTO_MERGE_REPOS="Thurbeen/thurbox" \ + $QUEUE shepherd --topic "$ttopic" --dry-run 2>&1)" +expect "a bare Thurbeen/thurbox is refused, not matched against the slug" \ + "must name its forge" "$out" +refute "and nothing in thurbox would be merged under it" "would-merge" "$out" + # --- 10. the shepherd writes down the publish state it already saw ----------- # # Every fact below arrived in the ONE `gh pr list` the pass already makes, and