From 69b2464ec3f9ce382052fad9a44d439ec1f108d3 Mon Sep 17 00:00:00 2001 From: Fahad <71817337+fahad-ali7@users.noreply.github.com> Date: Tue, 8 Sep 2026 14:59:12 +0200 Subject: [PATCH 1/5] chore: require exactly one type: label on every PR --- .github/workflows/pr-type-label.yml | 62 +++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 .github/workflows/pr-type-label.yml diff --git a/.github/workflows/pr-type-label.yml b/.github/workflows/pr-type-label.yml new file mode 100644 index 0000000..854c48b --- /dev/null +++ b/.github/workflows/pr-type-label.yml @@ -0,0 +1,62 @@ +# Canonical source: redpine-ai/redpine-cc-plugin +# plugins/redpine-eng/skills/redpine-pr-standard/assets/pr-type-label.yml +# Re-sync with: scripts/sync-pr-standard.sh +# +# SOC2 change-management control. `pr-type-label` is a REQUIRED status check on +# main in every Redpine repo. Never add a paths or paths-ignore filter to this +# workflow, and never let a CI-scoping script skip it: a required check that does +# not run leaves every PR unmergeable forever. +name: PR type label + +on: + pull_request: + types: [opened, edited, reopened, synchronize, labeled, unlabeled, ready_for_review] + +permissions: + contents: read + +concurrency: + group: pr-type-label-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + # Job name is the required-status-check context. Do not rename it. + pr-type-label: + name: pr-type-label + runs-on: ubuntu-latest + steps: + - name: Require exactly one type label + env: + # Read through env, never interpolated into the shell, so a label + # containing shell metacharacters cannot inject into this script. + PR_LABELS: ${{ toJSON(github.event.pull_request.labels.*.name) }} + run: | + set -euo pipefail + + ALLOWED="type:feature type:bugfix type:hotfix type:chore type:docs type:security" + + types=$(printf '%s' "$PR_LABELS" | jq -r '.[] | select(startswith("type:"))') + count=$(printf '%s' "$types" | grep -c . || true) + + if [ "$count" -eq 0 ]; then + echo "::error::This PR has no type label. Add exactly one of: $ALLOWED" + exit 1 + fi + + if [ "$count" -gt 1 ]; then + echo "::error::This PR has $count type labels ($(printf '%s' "$types" | tr '\n' ' ')). Exactly one is allowed." + exit 1 + fi + + # Exact match against each allowed value. A substring test would accept a + # single label literally named "type:feature type:bugfix". + ok=0 + for a in $ALLOWED; do + if [ "$types" = "$a" ]; then ok=1; break; fi + done + if [ "$ok" -ne 1 ]; then + echo "::error::'$types' is not a valid type label. Use one of: $ALLOWED" + exit 1 + fi + + echo "OK: $types" From 8d8a6e10ea05817d6e4544a774634093a6aa5ef0 Mon Sep 17 00:00:00 2001 From: Fahad <71817337+fahad-ali7@users.noreply.github.com> Date: Tue, 8 Sep 2026 14:59:13 +0200 Subject: [PATCH 2/5] chore: PR template stating the type label and review gates --- .github/PULL_REQUEST_TEMPLATE.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..aa4bef1 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,27 @@ + + +## What changed + + + +## How it was verified + + + +--- + +**Before this can merge** (both are enforced, not suggestions): + +- [ ] Exactly one `type:` label is applied. The `pr-type-label` check fails without it. + - `type:feature` — new capability or user-visible behaviour + - `type:bugfix` — corrects behaviour that was already meant to work + - `type:hotfix` — urgent production fix, expedited + - `type:chore` — dependencies, tooling, refactors, config, release plumbing + - `type:docs` — documentation, runbooks, changelog + - `type:security` — vulnerability fix, hardening, secret rotation +- [ ] Approved by someone other than the author. Self-merge is blocked for everyone, admins included. + +These two gates are Redpine's SOC2 change-management control. If one is blocking something genuinely urgent, get a second person to approve — do not ask for the control to be disabled. From 3a442ffaae5cfbf654bc3099ef15f7cb6baca429 Mon Sep 17 00:00:00 2001 From: Fahad <71817337+fahad-ali7@users.noreply.github.com> Date: Tue, 8 Sep 2026 14:59:15 +0200 Subject: [PATCH 3/5] docs: state the PR type label and independent review gates --- AGENTS.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index c3dfdef..cee987f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -83,3 +83,29 @@ See `CONTRIBUTING.md` for build/test/lint commands and the PR checklist. blocks would be silently dropped. - Assisted search and the quota endpoint are REST-only on the server; the CLI has no MCP route to them. + + +## Pull requests + +Two gates are enforced on the default branch and are not optional. They are +Redpine's SOC2 change-management control. + +1. **Every PR carries exactly one `type:` label.** The `pr-type-label` status check + fails without it, and the PR cannot merge. Apply the label when you open the PR, + not afterwards: + + | Label | Use for | + |---|---| + | `type:feature` | New capability or user-visible behaviour | + | `type:bugfix` | Corrects behaviour that was already meant to work | + | `type:hotfix` | Urgent production fix, expedited | + | `type:chore` | Dependencies, tooling, refactors, config, release plumbing | + | `type:docs` | Documentation, runbooks, changelog | + | `type:security` | Vulnerability fix, hardening, secret rotation | + +2. **Every PR is approved by someone other than its author.** Self-merge is blocked + for everyone, repository admins included. An automated review is useful evidence + but does not satisfy this gate; a human other than the author must approve. + +If you are an agent opening a PR: apply the `type:` label in the same command that +creates the PR (`gh pr create --label type:...`), and never merge your own PR. From 1cba4fa791eb86ce3613e6a7a3ee0f98170c6518 Mon Sep 17 00:00:00 2001 From: Fahad <71817337+fahad-ali7@users.noreply.github.com> Date: Tue, 8 Sep 2026 15:01:22 +0200 Subject: [PATCH 4/5] chore: require exactly one type: label on every PR From 1cdd51111b74e553c2ebde009a2320aeeb9ebc2e Mon Sep 17 00:00:00 2001 From: Fahad <71817337+fahad-ali7@users.noreply.github.com> Date: Tue, 8 Sep 2026 15:01:23 +0200 Subject: [PATCH 5/5] chore: PR template stating the type label and review gates