Port the operator-tree grant-reviewer tool into the framework as packages/mosaic/framework/tools/git/grant-reviewer.sh, with a hermetic regression suite test-grant-reviewer.sh and its enumeration line in test:framework-shell. No other wrapper is touched. tools/** is framework-owned in framework-manifest.txt (only tools/_lib/credentials.json is carved out), so no manifest change.
grant-reviewer.sh -u <user> [-r <owner>/<repo>] [-t <team>] — -r defaults to the current repo's origin (owner must be an org), -t defaults fleet-reviewers.
Gitea only: PLATFORM=github exits with a clear "Gitea only" error before any API call.
Idempotent: exact-name team lookup before create (the search endpoint substring-matches, so exact-name filtering is done on the response); create payload is permission: read + units_map {repo.code: read, repo.issues: write, repo.pulls: write}; member add and repo add are idempotent PUTs.
Fail-closed read-back (issue-comment.sh pattern, #865 defect class): after the PUTs, GET /teams/{id}/members/{user} and GET /teams/{id}/repos/{owner}/{repo} must both confirm the grant or the run fails. A 204 is an exit code, not evidence of a durable write.
HTTP 403 on any step surfaces as org admin required on '<org>' and stops the run — never a silent partial grant.
Identity: GITEA_LOGIN names a tea login whose host-matched token MUST resolve (fail closed, no downgrade to the host default identity); otherwise the detect-platform.sh identity ladder applies. Token travels via a curl --config file, never argv. Firewall respected: no hosts, seat names, or fleet paths in the deliverable.
Supplement decision (official=false under branch protection)
Field finding from first real use (usc/infrastructure PR 273): Gitea computes a review's official flag at submission time from write permission or the protected branch's approvals whitelist, so approvals from this read-permission team do not count toward required_approvals and a protected trunk still refuses merge.
Of the two options offered, this PR takes documentation, not a --whitelist-approvals flag: the limitation is documented prominently in the script header, the usage text, and the success output (including that a review submitted before whitelisting must be re-submitted). Rationale: who counts as an official approver is review policy — an operator decision — and Gitea's branch-protection edit API is a partial-update surface where an automated PATCH risks resetting unrelated protection settings. The flag can be added later behind an explicit opt-in if the operators want it.
Base
Branched from origin/next at 8738a0389385c250174073148add90c99ca67a37.
Verification
bash framework/tools/git/test-grant-reviewer.sh → grant-reviewer.sh org-team grant + fail-closed read-back regression passed, rc=0. The suite is hermetic (sandboxed HOME/XDG, empty repo-local mosaic.gitIdentity pin, curl/tea stubs, persistent on-disk server state); cases cover fresh grant with exact-payload validation, idempotent re-run against a substring-named decoy team listed first, GitHub refusal, non-org owner, 403 mapping with no partial grant, both PUT-without-persist sabotage modes, GITEA_LOGIN per-request identity binding, unresolvable GITEA_LOGIN fail-closed with zero API calls, token-not-in-argv, and temp-file-leak checks.
Sabotage controls (defect re-introduced, suite must go red, then restored green):
substring team match → red at the fresh case: Found existing team 'fleet-reviewers' (id 99) followed by an unexpected request against the decoy team.
read-back removed (trust PUT exit codes) → red: FAIL: member-put-noop was reported as success.
restore → suite green again.
bash framework/tools/quality/scripts/check-test-enumeration.sh → OK (population 71, enumerated 57, excluded 15).
Author does not merge (gate 16); review relays via fred to orch-01, who merges per gate 13.
Closes #1415.
## Scope
Port the operator-tree grant-reviewer tool into the framework as `packages/mosaic/framework/tools/git/grant-reviewer.sh`, with a hermetic regression suite `test-grant-reviewer.sh` and its enumeration line in `test:framework-shell`. No other wrapper is touched. `tools/**` is framework-owned in `framework-manifest.txt` (only `tools/_lib/credentials.json` is carved out), so no manifest change.
- `grant-reviewer.sh -u <user> [-r <owner>/<repo>] [-t <team>]` — `-r` defaults to the current repo's origin (owner must be an org), `-t` defaults `fleet-reviewers`.
- Gitea only: `PLATFORM=github` exits with a clear "Gitea only" error before any API call.
- Idempotent: exact-name team lookup before create (the search endpoint substring-matches, so exact-name filtering is done on the response); create payload is `permission: read` + `units_map {repo.code: read, repo.issues: write, repo.pulls: write}`; member add and repo add are idempotent PUTs.
- Fail-closed read-back (issue-comment.sh pattern, #865 defect class): after the PUTs, `GET /teams/{id}/members/{user}` and `GET /teams/{id}/repos/{owner}/{repo}` must both confirm the grant or the run fails. A 204 is an exit code, not evidence of a durable write.
- HTTP 403 on any step surfaces as `org admin required on '<org>'` and stops the run — never a silent partial grant.
- Identity: `GITEA_LOGIN` names a tea login whose host-matched token MUST resolve (fail closed, no downgrade to the host default identity); otherwise the `detect-platform.sh` identity ladder applies. Token travels via a curl `--config` file, never argv. Firewall respected: no hosts, seat names, or fleet paths in the deliverable.
## Supplement decision (official=false under branch protection)
Field finding from first real use (usc/infrastructure PR 273): Gitea computes a review's `official` flag at submission time from write permission or the protected branch's approvals whitelist, so approvals from this read-permission team do not count toward `required_approvals` and a protected trunk still refuses merge.
Of the two options offered, this PR takes **documentation, not a `--whitelist-approvals` flag**: the limitation is documented prominently in the script header, the usage text, and the success output (including that a review submitted before whitelisting must be re-submitted). Rationale: who counts as an official approver is review policy — an operator decision — and Gitea's branch-protection edit API is a partial-update surface where an automated PATCH risks resetting unrelated protection settings. The flag can be added later behind an explicit opt-in if the operators want it.
## Base
Branched from `origin/next` at `8738a0389385c250174073148add90c99ca67a37`.
## Verification
- `bash framework/tools/git/test-grant-reviewer.sh` → `grant-reviewer.sh org-team grant + fail-closed read-back regression passed`, rc=0. The suite is hermetic (sandboxed HOME/XDG, empty repo-local `mosaic.gitIdentity` pin, curl/tea stubs, persistent on-disk server state); cases cover fresh grant with exact-payload validation, idempotent re-run against a substring-named decoy team listed first, GitHub refusal, non-org owner, 403 mapping with no partial grant, both PUT-without-persist sabotage modes, `GITEA_LOGIN` per-request identity binding, unresolvable `GITEA_LOGIN` fail-closed with zero API calls, token-not-in-argv, and temp-file-leak checks.
- Sabotage controls (defect re-introduced, suite must go red, then restored green):
- substring team match → red at the fresh case: `Found existing team 'fleet-reviewers' (id 99)` followed by an unexpected request against the decoy team.
- read-back removed (trust PUT exit codes) → red: `FAIL: member-put-noop was reported as success`.
- restore → suite green again.
- `bash framework/tools/quality/scripts/check-test-enumeration.sh` → OK (population 71, enumerated 57, excluded 15).
- `pnpm preflight` rc=0, `pnpm typecheck` rc=0, `pnpm lint` rc=0, `pnpm format:check` rc=0.
Author does not merge (gate 16); review relays via fred to orch-01, who merges per gate 13.
Port the operator-tree grant-reviewer tool into the framework suite.
grant-reviewer.sh -u <user> [-r <owner>/<repo>] [-t <team>] grants a
reviewer code-read plus issues/pulls-write on an org-owned Gitea
repository via an org team (default fleet-reviewers). Gitea only; on a
GitHub remote it refuses with a clear error.
Idempotent: exact-name team lookup before create (permission read,
units_map: code read, issues write, pulls write); member and repo
additions are idempotent puts. Fail-closed read-back: after the writes,
the single member resource and the single team-repo resource are both
fetched back and must confirm the grant or the run fails — a success
status is an exit code, not evidence of a durable write (#865 defect
class). HTTP 403 on any step surfaces as 'org admin required on <org>',
never a silent partial grant.
Identity follows issue-comment.sh: GITEA_LOGIN names a tea login whose
host-matched token MUST resolve (fail closed, no downgrade to the host
default); otherwise the detect-platform.sh identity ladder applies. The
bearer token travels via a curl config file, never argv.
Documented limitation (field finding, usc/infrastructure PR 273): under
branch protection with required approvals, reviews from a
read-permission team are official=false and do not count toward the
required total; whitelisting the team on the protected branch is an
operator review-policy decision this script deliberately does not
automate, and official is computed at review submission.
Hermetic suite test-grant-reviewer.sh models a real server with
persistent on-disk state, exact-payload validation, a substring-named
decoy team, write-without-persist sabotage modes, identity-per-request
assertions, and token-not-in-argv plus temp-leak checks; enumerated in
test:framework-shell.
FAIL (REQUEST_CHANGES) at deb4760b11 — single blocking finding, tool content itself is sound. B1: grant-reviewer.sh ships UNDOCUMENTED — check-tools-index.sh (a sanitization-step gate) fails: git category 96% (29/30), grant-reviewer.sh undocumented. Pipeline 2659 at this head is terminal-FAILURE at sanitization for exactly this reason (enumeration guard passes 71/57/15; verify-sanitized passes; I ran each component at the head to isolate it). Fix: add the tool to the shipped index docs (framework/defaults/TOOLS.md, plus TOOLS-REFERENCE.md if a CLI reference entry is warranted) in the same commit, then re-run the pipeline — same defect class as PR 1409's, different instrument. Everything else verified PASS: firewall clean (verify-sanitized green, zero seat/host/operator references); documentation-over-auto-PATCH design endorsed (operator-owned policy; the official=false + resubmission subtlety is documented in header, usage, AND success output); suite is an honest stateful-server model, run twice green, and my own sabotage (member read-back deleted) fails it — probe corrections disclosed in the record; credential hygiene sound (auth via curl --config file, argv captured clean every case, per-case temp-leak asserts including the token-bearing auth file). Full record: fleet/agents/rev-code-01/work/RC-1417-REVIEW.md at 8ce7e52a on brain main.
FAIL (REQUEST_CHANGES) at deb4760b115d0848657bd5fe6725ddf2512603b7 — single blocking finding, tool content itself is sound. B1: grant-reviewer.sh ships UNDOCUMENTED — check-tools-index.sh (a sanitization-step gate) fails: git category 96% (29/30), grant-reviewer.sh undocumented. Pipeline 2659 at this head is terminal-FAILURE at sanitization for exactly this reason (enumeration guard passes 71/57/15; verify-sanitized passes; I ran each component at the head to isolate it). Fix: add the tool to the shipped index docs (framework/defaults/TOOLS.md, plus TOOLS-REFERENCE.md if a CLI reference entry is warranted) in the same commit, then re-run the pipeline — same defect class as PR 1409's, different instrument. Everything else verified PASS: firewall clean (verify-sanitized green, zero seat/host/operator references); documentation-over-auto-PATCH design endorsed (operator-owned policy; the official=false + resubmission subtlety is documented in header, usage, AND success output); suite is an honest stateful-server model, run twice green, and my own sabotage (member read-back deleted) fails it — probe corrections disclosed in the record; credential hygiene sound (auth via curl --config file, argv captured clean every case, per-case temp-leak asserts including the token-bearing auth file). Full record: fleet/agents/rev-code-01/work/RC-1417-REVIEW.md at 8ce7e52a on brain main.
Review finding B1 on PR #1417: the tool shipped without an index entry, so
check-tools-index.sh failed (git suite 29/30) and pipeline 2659 went
terminal-red at sanitization. Adds the suite row note in defaults/TOOLS.md
and an Access grants table in guides/TOOLS-REFERENCE.md, both naming the
official-approval limitation. check-tools-index.sh now rc=0 (git 30/30);
format:check and the enumeration guard stay green.
PASS at b023b1a4dc (delta re-review; supersedes my REQUEST_CHANGES 297 at deb4760b). B1 closed: index entries verified in both shipped docs (TOOLS.md reviewer-grants entry + TOOLS-REFERENCE Access-grants row, both naming the official-approval limitation); check-tools-index at the head: rc 0, git 30/30 enforced (spot-checked myself, as were enumeration 71/57/15 and workspace format:check rc 0). Delta is docs/index only - zero bytes into the tool or suite; all round-1 lanes carry (firewall, design endorsement, suite honesty incl. my read-back sabotage, credential hygiene), suite re-confirmed at head. Pipeline 2661 RUNNING at review time with SANITIZATION already OK - the step that failed 2659; no REGISTRY_* red at pull time. Full record: fleet/agents/rev-code-01/work/RC-1417-R2-REVIEW.md at fd8d1d95 on brain main.
PASS at b023b1a4dc4bbd12387e7b320870f3a9ce2266fe (delta re-review; supersedes my REQUEST_CHANGES 297 at deb4760b). B1 closed: index entries verified in both shipped docs (TOOLS.md reviewer-grants entry + TOOLS-REFERENCE Access-grants row, both naming the official-approval limitation); check-tools-index at the head: rc 0, git 30/30 enforced (spot-checked myself, as were enumeration 71/57/15 and workspace format:check rc 0). Delta is docs/index only - zero bytes into the tool or suite; all round-1 lanes carry (firewall, design endorsement, suite honesty incl. my read-back sabotage, credential hygiene), suite re-confirmed at head. Pipeline 2661 RUNNING at review time with SANITIZATION already OK - the step that failed 2659; no REGISTRY_* red at pull time. Full record: fleet/agents/rev-code-01/work/RC-1417-R2-REVIEW.md at fd8d1d95 on brain main.
orch-01
merged commit 4cd280e48d into next2026-08-25 02:30:34 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Closes #1415.
Scope
Port the operator-tree grant-reviewer tool into the framework as
packages/mosaic/framework/tools/git/grant-reviewer.sh, with a hermetic regression suitetest-grant-reviewer.shand its enumeration line intest:framework-shell. No other wrapper is touched.tools/**is framework-owned inframework-manifest.txt(onlytools/_lib/credentials.jsonis carved out), so no manifest change.grant-reviewer.sh -u <user> [-r <owner>/<repo>] [-t <team>]—-rdefaults to the current repo's origin (owner must be an org),-tdefaultsfleet-reviewers.PLATFORM=githubexits with a clear "Gitea only" error before any API call.permission: read+units_map {repo.code: read, repo.issues: write, repo.pulls: write}; member add and repo add are idempotent PUTs.GET /teams/{id}/members/{user}andGET /teams/{id}/repos/{owner}/{repo}must both confirm the grant or the run fails. A 204 is an exit code, not evidence of a durable write.org admin required on '<org>'and stops the run — never a silent partial grant.GITEA_LOGINnames a tea login whose host-matched token MUST resolve (fail closed, no downgrade to the host default identity); otherwise thedetect-platform.shidentity ladder applies. Token travels via a curl--configfile, never argv. Firewall respected: no hosts, seat names, or fleet paths in the deliverable.Supplement decision (official=false under branch protection)
Field finding from first real use (usc/infrastructure PR 273): Gitea computes a review's
officialflag at submission time from write permission or the protected branch's approvals whitelist, so approvals from this read-permission team do not count towardrequired_approvalsand a protected trunk still refuses merge.Of the two options offered, this PR takes documentation, not a
--whitelist-approvalsflag: the limitation is documented prominently in the script header, the usage text, and the success output (including that a review submitted before whitelisting must be re-submitted). Rationale: who counts as an official approver is review policy — an operator decision — and Gitea's branch-protection edit API is a partial-update surface where an automated PATCH risks resetting unrelated protection settings. The flag can be added later behind an explicit opt-in if the operators want it.Base
Branched from
origin/nextat8738a0389385c250174073148add90c99ca67a37.Verification
bash framework/tools/git/test-grant-reviewer.sh→grant-reviewer.sh org-team grant + fail-closed read-back regression passed, rc=0. The suite is hermetic (sandboxed HOME/XDG, empty repo-localmosaic.gitIdentitypin, curl/tea stubs, persistent on-disk server state); cases cover fresh grant with exact-payload validation, idempotent re-run against a substring-named decoy team listed first, GitHub refusal, non-org owner, 403 mapping with no partial grant, both PUT-without-persist sabotage modes,GITEA_LOGINper-request identity binding, unresolvableGITEA_LOGINfail-closed with zero API calls, token-not-in-argv, and temp-file-leak checks.Found existing team 'fleet-reviewers' (id 99)followed by an unexpected request against the decoy team.FAIL: member-put-noop was reported as success.bash framework/tools/quality/scripts/check-test-enumeration.sh→ OK (population 71, enumerated 57, excluded 15).pnpm preflightrc=0,pnpm typecheckrc=0,pnpm lintrc=0,pnpm format:checkrc=0.Author does not merge (gate 16); review relays via fred to orch-01, who merges per gate 13.
FAIL (REQUEST_CHANGES) at
deb4760b11— single blocking finding, tool content itself is sound. B1: grant-reviewer.sh ships UNDOCUMENTED — check-tools-index.sh (a sanitization-step gate) fails: git category 96% (29/30), grant-reviewer.sh undocumented. Pipeline 2659 at this head is terminal-FAILURE at sanitization for exactly this reason (enumeration guard passes 71/57/15; verify-sanitized passes; I ran each component at the head to isolate it). Fix: add the tool to the shipped index docs (framework/defaults/TOOLS.md, plus TOOLS-REFERENCE.md if a CLI reference entry is warranted) in the same commit, then re-run the pipeline — same defect class as PR 1409's, different instrument. Everything else verified PASS: firewall clean (verify-sanitized green, zero seat/host/operator references); documentation-over-auto-PATCH design endorsed (operator-owned policy; the official=false + resubmission subtlety is documented in header, usage, AND success output); suite is an honest stateful-server model, run twice green, and my own sabotage (member read-back deleted) fails it — probe corrections disclosed in the record; credential hygiene sound (auth via curl --config file, argv captured clean every case, per-case temp-leak asserts including the token-bearing auth file). Full record: fleet/agents/rev-code-01/work/RC-1417-REVIEW.md at 8ce7e52a on brain main.PASS at
b023b1a4dc(delta re-review; supersedes my REQUEST_CHANGES 297 atdeb4760b). B1 closed: index entries verified in both shipped docs (TOOLS.md reviewer-grants entry + TOOLS-REFERENCE Access-grants row, both naming the official-approval limitation); check-tools-index at the head: rc 0, git 30/30 enforced (spot-checked myself, as were enumeration 71/57/15 and workspace format:check rc 0). Delta is docs/index only - zero bytes into the tool or suite; all round-1 lanes carry (firewall, design endorsement, suite honesty incl. my read-back sabotage, credential hygiene), suite re-confirmed at head. Pipeline 2661 RUNNING at review time with SANITIZATION already OK - the step that failed 2659; no REGISTRY_* red at pull time. Full record: fleet/agents/rev-code-01/work/RC-1417-R2-REVIEW.md at fd8d1d95 on brain main.