From a3ecd1edb1e27ff53b5b5b11cc57dc2b6235cae3 Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Fri, 17 Jul 2026 17:43:05 -0400 Subject: [PATCH] Clarify PR-reopen flow and fix label-race that broke auto-reopen (#4518) Co-authored-by: Claude Opus 4.8 Co-authored-by: Claude --- .github/scripts/triage-label.sh | 73 +++++++++++++++++++++++ .github/workflows/marvin-label-triage.yml | 19 +++--- .github/workflows/require-issue-link.yml | 23 +++---- CONTRIBUTING.md | 9 ++- 4 files changed, 104 insertions(+), 20 deletions(-) create mode 100755 .github/scripts/triage-label.sh diff --git a/.github/scripts/triage-label.sh b/.github/scripts/triage-label.sh new file mode 100755 index 000000000..88081766f --- /dev/null +++ b/.github/scripts/triage-label.sh @@ -0,0 +1,73 @@ +#!/usr/bin/env bash +# Locked-down label helper for the Marvin triage workflow. +# +# Marvin runs on untrusted issue/PR bodies from non-write users, so it must +# NOT be handed raw `gh api` (that would expose every endpoint the app token +# can reach). This helper is the ONLY GitHub write it is allowed to perform: +# it adds or removes repository labels on the one issue/PR being triaged. +# +# The target repo and number come from the environment set by the workflow — +# never from the model — and the operation is fixed to the additive labels +# endpoint (POST/DELETE /repos/{repo}/issues/{n}/labels), which works for both +# issues and PRs and cannot clobber labels applied by other workflows. +set -euo pipefail + +repo="${TRIAGE_REPO:?TRIAGE_REPO not set}" +number="${TRIAGE_NUMBER:?TRIAGE_NUMBER not set}" + +if [[ ! "$number" =~ ^[0-9]+$ ]]; then + echo "TRIAGE_NUMBER must be numeric, got: $number" >&2 + exit 1 +fi + +op="${1:-}" +shift || true +case "$op" in + add) method=POST ;; + remove) method=DELETE ;; + *) + echo "usage: triage-label.sh