From 51be52e3b89b74ba0a07d1d429e034f79696c765 Mon Sep 17 00:00:00 2001 From: beardthelion <56458543+beardthelion@users.noreply.github.com> Date: Fri, 26 Jun 2026 08:48:44 -0500 Subject: [PATCH 1/5] ci(triage): run PR triage on pull_request_target so fork PRs can be labeled Fork PRs run the triage job with a read-only GITHUB_TOKEN under the pull_request event regardless of the workflow's declared write permissions, so addLabels/createComment fail with 403 'Resource not accessible by integration' for every external contributor (e.g. #103). Switch the trigger to pull_request_target, which runs in the base-repo context with the declared write token. The job never checks out or runs PR head code (it only reads context.payload and the pulls/files API and manages labels), so it carries none of the untrusted-code-execution risk that makes pull_request_target dangerous. --- .github/workflows/pr-triage.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr-triage.yml b/.github/workflows/pr-triage.yml index 2b65853..75424ce 100644 --- a/.github/workflows/pr-triage.yml +++ b/.github/workflows/pr-triage.yml @@ -1,7 +1,11 @@ name: PR Triage +# Runs on pull_request_target, not pull_request: fork PRs get a read-only +# GITHUB_TOKEN under pull_request regardless of the permissions below, so the +# label/comment writes 403. This job never checks out or runs PR head code (it +# only reads context.payload and the files API), so pull_request_target is safe. on: - pull_request: + pull_request_target: types: [opened, edited, synchronize, reopened] permissions: From 8b40407752b89a4d40266551e6fc8bec3b73cc91 Mon Sep 17 00:00:00 2001 From: beardthelion <56458543+beardthelion@users.noreply.github.com> Date: Fri, 26 Jun 2026 09:10:35 -0500 Subject: [PATCH 2/5] ci(stale): drop needs-issue from auto-close trigger, keep it advisory needs-issue flags PRs that link no issue, but linking one is a SHOULD in CONTRIBUTING (required only for protocol-level changes), and many legitimate small PRs (docs, obvious fixes) have none. Coupling it to the 14/21-day auto-close was overreach: a substantive, well-described PR could be closed purely for missing an issue reference. Keep needs-issue as an advisory label and guidance nudge; leave only needs-description (an empty/thin body, a far stronger low-effort signal) as the auto-close trigger. --- .github/workflows/stale.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 0ecebc7..a91dbc7 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -23,8 +23,10 @@ jobs: # Act on PRs only; never on issues. days-before-issue-stale: -1 days-before-issue-close: -1 - # Only PRs the triage step flagged as needing an author response. - only-pr-labels: "needs-issue,needs-description" + # Only PRs the triage step flagged as missing a real description. + # needs-issue is advisory-only (linking an issue is a SHOULD, and many + # legitimate small PRs have none) so it does not drive auto-close. + only-pr-labels: "needs-description" stale-pr-label: "stale" exempt-pr-labels: "workflow-change,security,pinned" remove-stale-when-updated: true From 2f850bb4d3ef0c75dbc3f7f8f0947e15572329d5 Mon Sep 17 00:00:00 2001 From: beardthelion <56458543+beardthelion@users.noreply.github.com> Date: Fri, 26 Jun 2026 09:18:07 -0500 Subject: [PATCH 3/5] ci(stale): align stale message with description-only close condition The auto-close trigger narrowed to needs-description, but the stale message still told contributors a PR could close for a missing linked issue. Drop that clause so the warning matches what actually closes a PR. --- .github/workflows/stale.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index a91dbc7..fd95f9d 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -31,10 +31,9 @@ jobs: exempt-pr-labels: "workflow-change,security,pinned" remove-stale-when-updated: true stale-pr-message: > - This PR has been inactive for 14 days and is still missing a linked issue - or a description. It will be closed in 7 days if there's no update. Push a - change or leave a comment to keep it open — no hard feelings, you can reopen - anytime. + This PR has been inactive for 14 days and is still missing a description. + It will be closed in 7 days if there's no update. Push a change or leave a + comment to keep it open — no hard feelings, you can reopen anytime. close-pr-message: > Closing due to inactivity. Reopen whenever you're ready to update it — see CONTRIBUTING.md for what helps us review quickly. From 5ab628a31629a526d6852c365f09129751ac5eee Mon Sep 17 00:00:00 2001 From: beardthelion <56458543+beardthelion@users.noreply.github.com> Date: Fri, 26 Jun 2026 09:23:00 -0500 Subject: [PATCH 4/5] style(ci): replace em dashes in triage/stale contributor messages --- .github/workflows/pr-triage.yml | 6 +++--- .github/workflows/stale.yml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/pr-triage.yml b/.github/workflows/pr-triage.yml index 75424ce..8d5a933 100644 --- a/.github/workflows/pr-triage.yml +++ b/.github/workflows/pr-triage.yml @@ -68,8 +68,8 @@ jobs: if (isFork && touchesWorkflows) want.add("workflow-change"); const changedRust = names.some(n => n.startsWith("crates/") && n.endsWith(".rs")); - // A test can live in a tests/ dir, a *_test.rs file, or — the common Rust - // pattern — an inline #[test] / #[cfg(test)] block added inside the source file. + // A test can live in a tests/ dir, a *_test.rs file, or (the common Rust + // pattern) an inline #[test] / #[cfg(test)] block added inside the source file. const addsInlineTest = files.some(f => f.filename.endsWith(".rs") && f.patch && /^\+.*#\[(test\]|cfg\(test\))/m.test(f.patch)); @@ -108,7 +108,7 @@ jobs: const reasons = { "needs-issue": "Link the issue this addresses (`Closes #123`). For protocol changes, open an issue first.", - "needs-description": "Add a short summary of what changes and why — the template's Summary and Motivation sections.", + "needs-description": "Add a short summary of what changes and why: the template's Summary and Motivation sections.", "needs-tests": "This changes Rust source but no tests changed. Tests are required for fixes and strongly encouraged for features.", }; const lines = advisory.map(l => `- ${reasons[l]}`).join("\n"); diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index fd95f9d..2d2b21c 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -33,8 +33,8 @@ jobs: stale-pr-message: > This PR has been inactive for 14 days and is still missing a description. It will be closed in 7 days if there's no update. Push a change or leave a - comment to keep it open — no hard feelings, you can reopen anytime. + comment to keep it open. No hard feelings, you can reopen anytime. close-pr-message: > - Closing due to inactivity. Reopen whenever you're ready to update it — see + Closing due to inactivity. Reopen whenever you're ready to update it. See CONTRIBUTING.md for what helps us review quickly. ascending: true From 374ef75acfea3b724dfe5a465ae890ab45e4168f Mon Sep 17 00:00:00 2001 From: beardthelion <56458543+beardthelion@users.noreply.github.com> Date: Fri, 26 Jun 2026 11:12:48 -0500 Subject: [PATCH 5/5] docs(contributing): match stale close policy to description-only trigger Auto-close is driven by needs-description only; a missing issue link stays advisory. Align the contributor docs with the workflow so the OR wording no longer implies a missing issue link can close a PR. --- CONTRIBUTING.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d4ff77d..fd939c9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -69,9 +69,10 @@ expected to clear a basic quality bar: - **A real description.** Say what changes and why. "Update code" is not a description. A triage bot labels PRs that are missing these and leaves a short note. Nothing is closed -automatically while you're engaging. A flagged PR that goes 14 days with no linked issue or -description gets a stale warning, and is closed 7 days later if still untouched. Closed PRs can -be reopened at any time once updated. +automatically while you're engaging. A flagged PR still missing a description after 14 days of +inactivity gets a stale warning, and is closed 7 days later if still untouched. A missing issue +link alone never triggers closure; that label stays advisory. Closed PRs can be reopened at any +time once updated. ## Development environment