**no more vouching! let's see how it goes for a week :)**

This commit is contained in:
can1357
2026-07-23 02:35:36 +02:00
parent 1f7d2ff9ea
commit bb15939414
13 changed files with 79 additions and 673 deletions
-262
View File
@@ -1,262 +0,0 @@
# The list of vouched (or actively denounced) users for this repository.
#
# Only vouched users can open PRs here; unvouched/denounced PRs are
# auto-closed by .github/workflows/vouch-pr.yml (mitchellh/vouch check-pr).
# Issues are intentionally NOT gated here — robomp triages those.
#
# Write-access collaborators and bots are auto-allowed and need no entry.
# A denounced user ("-handle") is always blocked, even if also listed.
#
# Syntax:
# - One handle per line (without @), sorted alphabetically.
# - Optional platform prefix: `platform:username` (default platform: github).
# - Denounce by prefixing with minus: `-username` / `-platform:username`.
# - Optional free-text reason after a space following the handle.
#
# Maintainers manage this list by commenting `!vouch` / `!denounce [user]`
# on a discussion (see .github/workflows/vouch-manage.yml).
#
# Seed (2026-06-19): authors with >=2 merged PRs in the prior 6 months.
# Audit found 0 denounce-worthy actors; all reverts were maintainer
# technical rollbacks, not abuse. See the PR/commit history for provenance.
0ttik
21307369
35844493
381181295
a-glapinski
adrastopoulos
ak4153
alias8818
alloevil
alvorithm
anasinno
andrew-pynch
antonlvovych
any-victor
apoc
arg3t
art1kz
asafmah
asterisksf
atyrode
audreyt
azais-corentin
aznikline
bannert1337
barisdemirdelen
basedcorp99
baylee4
belchetz
bjin
blockedpath
brainage04
cagedbird043
cexll
chan1103
chrys4lisfag
chuaaron
chuzui
ckumar1
cloudsmithbrandon
codelonesomest
coderredlab
codertcy
comicchang
corrm
courtgpt
cyjaysong
czxtm
daandden
daaximus
danvincent
danzaio
darkphilosophy
defaceroot
deprecatedluke
derekszen
devnewbie1826
dexhunter
disco-trooper
djdembeck
dkeken
dmarsh-gusto
dragonbaba
dylanbohlender
echopi
eggpeat
elikoga
enieuwy
eugenelo
eyycheev
fettpl
flare576
foreveryoungpp
freespace8
fryuni
gareth-rouse
gratefuldave
h4vc
habibpro1999
handlecusion
haosenwang1018
harshav167
hellisotherpeople
heyitsgilbert
hezhiyang2000
hheei
hobostay
hoishing
honsunrise
hpost
iacore
ig0rsky
igasmi
incloon
infernix
inprealpha
insodimension
isaac-sun
itertea
itzrnvr
jaaneek
jaeyeopme
jagravnaik
jasonw22
jchristman
jdavv
jeffscottward
jfblaine
jiwangyihao
jorgoose
joswha
justmao945
jwmacd
kamafozilov
kamijotoma
kenmege
kevcube
khanetor
korenkrita
korri123
kukkerem
lance0
larkinwc
larrygf
ldx
lederniermagicien
lee-si-yoon
lemeb
linqijin
liwuhou
llvm-x86
loftiskg
loneexile
luceat-lux-vestra
lunarecl
luojiyin1987
lyc-aon
m-005
m3ridian-zero
m8than
maatheusgois-dd
makomakogo
masonc15
mastertyko
mathews-tom
mattwilkinsonn
maximhar
maxvisionai
mayask
memvu
metaphorics
mgpai22
mikeei
mmkzer0
mokto
moutazhaq
mouyase
mq1n
mrshu
mumutw
muness
nasko25
nibblebot
niklasschaeffer
nnk97
nszceta
ogrodev
oldschoola
ondrejsojka
panosathdbx
paolomazzitti
paralin
parsifa1
peterrauscher
pgupta-git
phanthh
pidevxplay
piedpiper911
pppobear
qfrtt
ravshansbox
rburketaylor
rcbran
renstillmann
reqx
riverpilot
romanalexander
rysiuwroc
rznmkx
salmonumbrella
samy-mohsen-111
scarthread
segmentationf4u1t
selimsandal
serejaris
serverinspector
shauryaswarup
shoucandanghehe
shyndman
silentknight87
sit
slact
smileynet
sorphwer
sundbp
superhedge22
svankina
szavadsky
tbui17
tc97222
tcf909
tdiant
techdufus
tjboudreaux
tsagi2045
turbomolli
tyrliang
unravl
usr-bin-roygbiv
ve3xone
vincent-huang-2000
vmcall
voidchecksum
voiys
wahidinaji
watzon
will-bogusz will-bogusz
wodenjay
wolfiesch
wonjun3991
wtergan
wuchengzu
xaviergmail
xiue233
xoltus
yashnark
yingliang-zhang
zakhar-kogan
zamorakpds
zekdevs
zommiommy
+4 -6
View File
@@ -3,14 +3,12 @@ name: CI
on:
push:
branches: [main]
# Vouch bookkeeping commits (mitchellh/vouch writes VOUCHED.td back to
# main on !vouch/!denounce/!unvouch) only edit the vouch list and need no
# build. Skip CI when a main push changes nothing but the vouch file; a
# push that also touches anything else still runs the full matrix.
paths-ignore:
- .github/VOUCHED.td
paths:
- "packages/**"
pull_request:
branches: [main]
paths:
- "packages/**"
workflow_dispatch:
inputs:
skip_npm:
-44
View File
@@ -1,44 +0,0 @@
name: Vouch (manage)
# Let maintainers vouch/denounce/unvouch by commenting on a Discussion:
# !vouch vouch the discussion author
# !vouch @user [reason] vouch a specific user
# !denounce [@user] [reason]
# !unvouch [@user]
# Only collaborators with admin/maintain/write are honored (triage EXCLUDED;
# upstream's default `roles` includes triage, which we override below).
#
# Commits the VOUCHED.td change back to the default branch using the stock
# GITHUB_TOKEN (no GitHub App needed). NOTE: this works only while the default
# branch is UNPROTECTED — GITHUB_TOKEN cannot bypass branch protection. If you
# protect the branch later, switch back to a GitHub App token on a bypass list.
on:
discussion_comment:
types: [created]
# Serialize writes to VOUCHED.td so concurrent vouches don't clobber.
concurrency:
group: vouch-manage
cancel-in-progress: false
permissions:
contents: write # commit VOUCHED.td
discussions: write # read the comment / acknowledge
jobs:
manage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: mitchellh/vouch/action/manage-by-discussion@v1
with:
discussion-number: ${{ github.event.discussion.number }}
comment-node-id: ${{ github.event.comment.node_id }}
vouch-keyword: "!vouch"
denounce-keyword: "!denounce"
unvouch-keyword: "!unvouch"
roles: admin,maintain,write
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-51
View File
@@ -1,51 +0,0 @@
name: Vouch (PR gate)
# Auto-close PRs from unvouched or denounced users. Issues are left alone
# (robomp triages those). Runs under `pull_request_target` so the token can
# act on fork PRs; this job does NO checkout and runs NO PR code — it only
# reads .github/VOUCHED.td from the base repo and calls the GitHub API.
on:
pull_request_target:
types: [opened, reopened, ready_for_review]
permissions:
contents: read # read VOUCHED.td from the base branch
pull-requests: write # close + comment
issues: write # add the `vouched` label (labels use the Issues API)
concurrency:
group: vouch-pr-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
check:
runs-on: ubuntu-latest
steps:
- id: vouch
uses: mitchellh/vouch/action/check-pr@v1
with:
pr-number: ${{ github.event.pull_request.number }}
auto-close: true
require-vouch: true # block unvouched, not only denounced
# vouched-file: .github/VOUCHED.td (default)
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Survivors of the gate (vouched, or auto-allowed collaborators/bots) get
# a FRESH `vouched` label on every (re)open / ready-for-review. robomp
# reviews ONLY on that label event (ROBOMP_PR_REVIEW_TRIGGER=vouched_label),
# so review is always triggered by a just-validated PR, never a stale label.
- name: Label vouched PRs for robomp review
if: ${{ steps.vouch.outputs.status == 'vouched' || steps.vouch.outputs.status == 'allowed' }}
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO: ${{ github.repository }}
PR: ${{ github.event.pull_request.number }}
run: |
gh label create vouched --repo "$REPO" --color 2da44e --description "Passed the vouch gate" --force
# remove+add so a fresh `labeled` event fires even when the label
# persisted across close/reopen (re-adding an existing label emits no
# event). The check above just re-validated, so trust is never stale.
gh pr edit "$PR" --repo "$REPO" --remove-label vouched || true
gh pr edit "$PR" --repo "$REPO" --add-label vouched
+68 -38
View File
@@ -1,54 +1,84 @@
# Contributing to oh-my-pi
Thanks for your interest in contributing. This project uses a lightweight
**vouch** system to decide who can open pull requests. Please read this before
opening a PR.
Pull requests are welcome. Keep them focused, understand the work you submit,
and be prepared to explain and maintain it.
## TL;DR
## Before you start
- **Issues are open to everyone.** File bugs, feature requests, and questions
freely — they are triaged automatically.
- **Pull requests require a vouch.** A PR whose author is not vouched (or is
denounced) is **closed automatically**. If you are not yet vouched, do **not**
open a PR to get noticed — it will be closed on sight. Start a Discussion and
ask to be vouched first (see below).
### Small changes
## Who can open PRs
Bug fixes, documentation updates, and narrowly scoped improvements can go
straight to a pull request.
A pull request is accepted when its author is any of:
### Major changes
- a repository collaborator (write access or above), or a bot; or
- listed — without a leading `-` — in [`.github/VOUCHED.td`](.github/VOUCHED.td).
Discuss major features and broad architectural or behavioral changes in
[Discord](https://discord.gg/4NMW9cdXZa) **before writing the implementation**.
This includes new subsystems, large UI changes, new dependencies, and changes
that span several packages. A GitHub issue is not a substitute for this
discussion, and prior discussion does not guarantee that a pull request will be
merged.
Anyone **denounced** (prefixed with `-` in that file) is always blocked.
### Do not open an issue for work you are about to submit
## Getting vouched
If you intend to implement a change yourself, **do not create an issue for it
first**. robomp treats actionable issues as work to pick up and may start the
same fix in parallel, wasting compute and maintainer time.
1. Open a [Discussion](../../discussions) (or comment on an existing one)
describing what you'd like to contribute.
2. A maintainer vouches you by commenting **`!vouch`** (vouches the discussion
author) or **`!vouch @your-handle`** on that discussion.
3. Once you appear in `.github/VOUCHED.td`, open your PR — it stays open and is
reviewed.
Open an issue when you are reporting a problem or proposing work that you are
not already turning into a pull request. If a relevant issue already exists,
link it from your pull request instead of creating another one.
Maintainers may also `!denounce [@user]` and `!unvouch [@user]`. Only
collaborators with admin/maintain/write can run these commands.
## AI-assisted contributions
## What happens to your PR
AI agents are welcome as tools, not as unattended contributors. Do not give an
agent a vague goal and submit whatever it produces.
| You are… | Result |
| --- | --- |
| Vouched (or a collaborator) | PR stays open → automated review → human review |
| Not vouched | PR closed with a comment — get vouched, then reopen or open a new PR |
| Denounced | PR closed |
Before opening a pull request, you must:
Pushing more commits to an open, vouched PR is fine — it remains vouched.
- constrain the agent to the agreed scope and reject unrelated changes;
- review every changed file and understand the resulting behavior;
- run the relevant checks and exercise the changed behavior yourself; and
- submit the pull request only after that review, rather than letting an agent
publish it autonomously.
## The VOUCHED.td file
You are responsible for the code, regardless of who or what generated it.
[`.github/VOUCHED.td`](.github/VOUCHED.td) is the source of truth: one handle per
line, sorted alphabetically, optionally `platform:handle`, with `-` marking a
denouncement and an optional reason after the handle. The format follows
[mitchellh/vouch](https://github.com/mitchellh/vouch); the denouncement list is
intentionally public so other projects can reuse our prior knowledge of bad
actors.
## Pull request requirements
Every pull request body **MUST include at least one sentence written by you, in
your own words**, explaining what changed and why. A generated summary, pasted
agent transcript, or checklist alone does not satisfy this requirement.
One honest line is enough:
> I reviewed the full diff; this change fixes duplicate PR reviews by reusing
> the existing delivery guard.
You **MUST verify that the change works as intended**. `bun check` and automated
tests are expected where relevant, but they are not proof that the behavior
works. Exercise the changed path yourself and report the exact scenario and
result in the pull request:
- for a bug fix, reproduce the bug and confirm the same reproduction no longer
fails;
- for a feature, launch the product and use the feature end to end; and
- for a UI change, interact with it and inspect the rendered result.
“`bun check` passes” by itself is not sufficient verification. For coding-agent
development commands and repository structure, see
[`packages/coding-agent/DEVELOPMENT.md`](packages/coding-agent/DEVELOPMENT.md).
Keep each pull request to one logical change. Avoid unrelated cleanup,
drive-by refactors, generated noise, or features that were not part of the
agreed scope.
## Review
Maintainers review the submitted behavior and the contributor's understanding
of it—not the volume of generated code. Respond to review feedback yourself,
and only apply suggestions you have checked.
Pull requests may be closed when they skip required prior discussion, lack the
human-written explanation, contain unreviewed agent output, or mix unrelated
changes.
+1 -6
View File
@@ -592,12 +592,7 @@ For architecture and contribution guidelines, see [packages/coding-agent/DEVELOP
## Contributing
Issues are open to everyone. **Pull requests require a vouch** — PRs from
unvouched or denounced authors are closed automatically. If you're not yet
vouched, open a [Discussion](https://github.com/can1357/oh-my-pi/discussions)
and ask a maintainer to `!vouch` you rather than opening a PR (which would be
closed on sight). See **[CONTRIBUTING.md](CONTRIBUTING.md)** and
[`.github/VOUCHED.td`](.github/VOUCHED.td) for the full policy.
Issues and pull requests are open to everyone. See **[CONTRIBUTING.md](CONTRIBUTING.md)** for guidelines on contributing.
---
+2 -15
View File
@@ -117,23 +117,10 @@ ROBOMP_REQUEST_TIMEOUT_SECONDS=120
# =============================================================================
# --- PR review / vouch gate ---
# --- PR review ---
# =============================================================================
# robomp reviews incoming contributor PRs. When PRs are gated by the vouch
# GitHub Action (.github/workflows/vouch-pr.yml), set the trigger to
# `vouched_label` so robomp reviews ONLY the PRs the gate let through (the
# workflow labels survivors with ROBOMP_VOUCH_REVIEW_LABEL) instead of racing
# the gate on PR open. Set ROBOMP_PR_REVIEW_ENABLED=false to disable robomp PR
# review entirely.
# Set ROBOMP_PR_REVIEW_ENABLED=false to disable robomp PR review entirely.
ROBOMP_PR_REVIEW_ENABLED=true
# open | vouched_label
ROBOMP_PR_REVIEW_TRIGGER=open
ROBOMP_VOUCH_REVIEW_LABEL=vouched
# In vouched_label mode only `labeled` events from this actor trigger review,
# so a manual triage/maintainer label cannot bypass the gate. Default matches
# the stock GITHUB_TOKEN actor; set to your App's bot login if the vouch
# workflow labels via a GitHub App token.
ROBOMP_VOUCH_REVIEW_LABELER=github-actions[bot]
# =============================================================================
+1 -8
View File
@@ -44,15 +44,8 @@ services:
ROBOMP_MAINTAINER_LOGINS: ${ROBOMP_MAINTAINER_LOGINS:-}
ROBOMP_REVIEWER_BOTS: ${ROBOMP_REVIEWER_BOTS:-}
# --- PR review / vouch gate ---
# When PRs are gated by the vouch GitHub Action, set the trigger to
# `vouched_label` so robomp reviews ONLY PRs that survive the gate
# (the workflow labels survivors `ROBOMP_VOUCH_REVIEW_LABEL`), instead
# of racing the gate on PR open. `vouched_label` keeps review ENABLED.
# --- PR review ---
ROBOMP_PR_REVIEW_ENABLED: ${ROBOMP_PR_REVIEW_ENABLED:-true}
ROBOMP_PR_REVIEW_TRIGGER: ${ROBOMP_PR_REVIEW_TRIGGER:-open}
ROBOMP_VOUCH_REVIEW_LABEL: ${ROBOMP_VOUCH_REVIEW_LABEL:-vouched}
ROBOMP_VOUCH_REVIEW_LABELER: ${ROBOMP_VOUCH_REVIEW_LABELER:-github-actions[bot]}
# --- model selection ---
ROBOMP_MODEL: ${ROBOMP_MODEL:-anthropic/claude-sonnet-4-6}
-12
View File
@@ -38,18 +38,6 @@ class Settings(BaseSettings):
git_author_email: str = Field(..., alias="ROBOMP_GIT_AUTHOR_EMAIL")
repo_allowlist_raw: str = Field("", alias="ROBOMP_REPO_ALLOWLIST")
pr_review_enabled: bool = Field(True, alias="ROBOMP_PR_REVIEW_ENABLED")
# PR review trigger. "open" (default) reviews incoming PRs on
# opened/reopened/ready_for_review. "vouched_label" DEFERS review until the
# vouch GitHub Action labels the PR `vouch_review_label`, so robomp reviews
# only PRs that survive the vouch gate. `pr_review_enabled` remains the
# master switch (False disables review under either trigger).
pr_review_trigger: Literal["open", "vouched_label"] = Field("open", alias="ROBOMP_PR_REVIEW_TRIGGER")
vouch_review_label: str = Field("vouched", alias="ROBOMP_VOUCH_REVIEW_LABEL")
# In vouched_label mode, only `labeled` events from this actor trigger a
# review, so a manual label by a triage/maintainer cannot bypass the gate.
# Default is the actor for the stock GITHUB_TOKEN; set to your App's bot
# login (e.g. "vouch-bot[bot]") if the vouch workflow labels via an App.
vouch_review_labeler: str = Field("github-actions[bot]", alias="ROBOMP_VOUCH_REVIEW_LABELER")
# gh-proxy. Set BOTH to route GitHub through the proxy; leave both empty
# to keep PAT-on-orchestrator behavior. Mixing the two (PAT + proxy) is
-23
View File
@@ -226,9 +226,6 @@ def route(
reviewer_bots: frozenset[str] = frozenset(),
resolve_issue_from_pr: PrIssueResolver = None,
pr_review_enabled: bool = True,
pr_review_trigger: str = "open",
vouch_review_label: str = "vouched",
vouch_review_labeler: str = "github-actions[bot]",
) -> RouteDecision:
"""Decide whether and how to handle a webhook event.
@@ -362,28 +359,8 @@ def route(
if not pr_review_enabled:
return RouteDecision("skip", None, repo, None, "PR review disabled")
pr = payload.get("pull_request") or {}
if pr_review_trigger == "vouched_label":
# Defer to the vouch gate. robomp reviews ONLY on the `labeled`
# event the workflow emits AFTER a fresh check (it re-applies the
# vouch label on every opened/reopened/ready_for_review). Never
# trust a persisted label here: a since-denounced author must not
# slip through on reopen.
return RouteDecision("skip", None, repo, None, "deferred to vouch label")
return _pr_review_pr(pr, repo, action, bot_login)
if event_type == "pull_request" and action == "labeled" and pr_review_trigger == "vouched_label":
if not pr_review_enabled:
return RouteDecision("skip", None, repo, None, "PR review disabled")
label = payload.get("label")
label_name = str(label.get("name") or "") if isinstance(label, Mapping) else ""
if label_name.lower() != vouch_review_label.lower():
return RouteDecision("skip", None, repo, None, f"label {label_name!r} not vouch label")
sender = payload.get("sender")
labeler = str(sender.get("login") or "") if isinstance(sender, Mapping) else ""
if labeler.lower() != vouch_review_labeler.lower():
return RouteDecision("skip", None, repo, None, f"vouch label not from trusted labeler ({labeler!r})")
return _pr_review_pr(payload.get("pull_request") or {}, repo, action, bot_login)
if event_type == "pull_request_review_comment" and action == "created":
comment = payload.get("comment") or {}
rb_login = _reviewer_bot_login(comment.get("user"))
-3
View File
@@ -356,9 +356,6 @@ def create_app(settings: Settings | None = None) -> FastAPI:
maintainers=cfg.maintainer_logins,
reviewer_bots=cfg.reviewer_bots,
pr_review_enabled=cfg.pr_review_enabled,
pr_review_trigger=cfg.pr_review_trigger,
vouch_review_label=cfg.vouch_review_label,
vouch_review_labeler=cfg.vouch_review_labeler,
resolve_issue_from_pr=_resolve,
)
-192
View File
@@ -956,195 +956,3 @@ def test_route_non_directive_comment_carries_no_pragmas() -> None:
assert decision.directive_pragmas == ()
# ---------- vouched-label deferred PR review ----------
def test_route_vouched_label_defers_pr_open() -> None:
decision = route(
"pull_request",
{
"action": "opened",
"pull_request": {"number": 9, "draft": False, "user": {"login": "alice", "type": "User"}},
"repository": {"full_name": "octo/widget"},
},
allowlist=ALLOWLIST,
bot_login=BOT,
pr_review_trigger="vouched_label",
)
assert not decision.should_queue
assert decision.reason == "deferred to vouch label"
def test_route_vouched_label_reviews_on_label() -> None:
decision = route(
"pull_request",
{
"action": "labeled",
"label": {"name": "vouched"},
"pull_request": {
"number": 9,
"draft": False,
"user": {"login": "alice", "type": "User"},
"author_association": "CONTRIBUTOR",
},
"repository": {"full_name": "octo/widget"},
"sender": {"login": "github-actions[bot]"},
},
allowlist=ALLOWLIST,
bot_login=BOT,
pr_review_trigger="vouched_label",
)
assert decision.should_queue
assert decision.task == "review_pr"
assert decision.issue_key == "octo/widget#9"
assert decision.submitter == "alice"
def test_route_vouched_label_ignores_other_labels() -> None:
decision = route(
"pull_request",
{
"action": "labeled",
"label": {"name": "bug"},
"pull_request": {"number": 9, "user": {"login": "alice"}},
"repository": {"full_name": "octo/widget"},
},
allowlist=ALLOWLIST,
bot_login=BOT,
pr_review_trigger="vouched_label",
)
assert not decision.should_queue
def test_route_vouched_label_ready_for_review_defers_even_with_label() -> None:
# Persisted labels are NOT trusted; the workflow re-applies the label (a
# fresh `labeled` event) after re-validating, so ready_for_review defers.
decision = route(
"pull_request",
{
"action": "ready_for_review",
"pull_request": {
"number": 9,
"draft": False,
"user": {"login": "alice", "type": "User"},
"labels": [{"name": "vouched"}],
},
"repository": {"full_name": "octo/widget"},
},
allowlist=ALLOWLIST,
bot_login=BOT,
pr_review_trigger="vouched_label",
)
assert not decision.should_queue
assert decision.reason == "deferred to vouch label"
def test_route_vouched_label_labeled_skips_draft() -> None:
decision = route(
"pull_request",
{
"action": "labeled",
"label": {"name": "vouched"},
"pull_request": {"number": 9, "draft": True, "user": {"login": "alice", "type": "User"}},
"repository": {"full_name": "octo/widget"},
"sender": {"login": "github-actions[bot]"},
},
allowlist=ALLOWLIST,
bot_login=BOT,
pr_review_trigger="vouched_label",
)
assert not decision.should_queue
assert decision.reason == "draft PR"
def test_route_default_trigger_ignores_labeled() -> None:
# Backward-compat: the default "open" trigger does not route `labeled`.
decision = route(
"pull_request",
{
"action": "labeled",
"label": {"name": "vouched"},
"pull_request": {"number": 9, "user": {"login": "alice"}},
"repository": {"full_name": "octo/widget"},
},
allowlist=ALLOWLIST,
bot_login=BOT,
)
assert not decision.should_queue
def test_route_vouched_label_reopened_defers_even_with_label() -> None:
# A since-denounced author must not slip through on reopen via a stale
# label; reopened always defers to a fresh gate check + re-label.
decision = route(
"pull_request",
{
"action": "reopened",
"pull_request": {
"number": 9,
"draft": False,
"user": {"login": "alice", "type": "User"},
"labels": [{"name": "vouched"}],
},
"repository": {"full_name": "octo/widget"},
},
allowlist=ALLOWLIST,
bot_login=BOT,
pr_review_trigger="vouched_label",
)
assert not decision.should_queue
assert decision.reason == "deferred to vouch label"
def test_route_vouched_label_reopened_without_label_defers() -> None:
decision = route(
"pull_request",
{
"action": "reopened",
"pull_request": {"number": 9, "draft": False, "user": {"login": "alice", "type": "User"}},
"repository": {"full_name": "octo/widget"},
},
allowlist=ALLOWLIST,
bot_login=BOT,
pr_review_trigger="vouched_label",
)
assert not decision.should_queue
assert decision.reason == "deferred to vouch label"
def test_route_vouched_label_rejects_manual_labeler() -> None:
# A triage/maintainer hand-adding the label must NOT trigger review.
decision = route(
"pull_request",
{
"action": "labeled",
"label": {"name": "vouched"},
"pull_request": {"number": 9, "draft": False, "user": {"login": "alice", "type": "User"}},
"repository": {"full_name": "octo/widget"},
"sender": {"login": "evilmaintainer"},
},
allowlist=ALLOWLIST,
bot_login=BOT,
pr_review_trigger="vouched_label",
)
assert not decision.should_queue
assert "trusted labeler" in decision.reason
def test_route_vouched_label_skips_closed_pr() -> None:
# `labeled` can fire on a closed PR; never review one.
decision = route(
"pull_request",
{
"action": "labeled",
"label": {"name": "vouched"},
"pull_request": {"number": 9, "state": "closed", "user": {"login": "alice", "type": "User"}},
"repository": {"full_name": "octo/widget"},
"sender": {"login": "github-actions[bot]"},
},
allowlist=ALLOWLIST,
bot_login=BOT,
pr_review_trigger="vouched_label",
)
assert not decision.should_queue
assert decision.reason == "PR not open"
+3 -13
View File
@@ -1,11 +1,4 @@
"""Dispatch action -> task mapping in WorkerPool._dispatch.
Regression guard for the route<->dispatch contract: `github_events.route`
queues a `pull_request.labeled` event as a `review_pr` task in `vouched_label`
mode, so `_dispatch` MUST invoke `tasks.review_pr` for that action. It
previously only handled `opened/reopened/ready_for_review`, so every vouched
PR fell through to the no-op branch and was silently marked `done`.
"""
"""Dispatch action -> task mapping in WorkerPool._dispatch."""
from __future__ import annotations
@@ -55,15 +48,12 @@ def _pr_row(action: str, *, delivery: str = "pr1") -> EventRow:
)
@pytest.mark.parametrize("action", ["opened", "reopened", "ready_for_review", "labeled"])
@pytest.mark.parametrize("action", ["opened", "reopened", "ready_for_review"])
@pytest.mark.asyncio
async def test_dispatch_routes_pr_review_actions_to_review_pr(
settings: Settings, db: Database, monkeypatch: pytest.MonkeyPatch, action: str
) -> None:
"""Every PR action `route` can queue for review MUST reach `tasks.review_pr`.
`labeled` is the vouched-label trigger; the others are the `open` trigger.
"""
"""Every PR action `route` can queue for review MUST reach `tasks.review_pr`."""
seen: list[str] = []
async def fake_review_pr(*, payload, **_kwargs) -> None: