Repository navigation
chore: enforce PR type labels and independent review (SOC2) #11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
69b2464
chore: require exactly one type: label on every PR
fahad-ali7 8d8a6e1
chore: PR template stating the type label and review gates
fahad-ali7 3a442ff
docs: state the PR type label and independent review gates
fahad-ali7 1cba4fa
chore: require exactly one type: label on every PR
fahad-ali7 1cdd511
chore: PR template stating the type label and review gates
fahad-ali7 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| <!-- Canonical source: redpine-ai/redpine-cc-plugin | ||
| plugins/redpine-eng/skills/redpine-pr-standard/assets/PULL_REQUEST_TEMPLATE.md | ||
| Re-sync with: scripts/sync-pr-standard.sh --> | ||
|
|
||
| ## What changed | ||
|
|
||
| <!-- One or two sentences. What does this do, and why now? --> | ||
|
|
||
| ## How it was verified | ||
|
|
||
| <!-- The command you ran and its output, the test that passed, the page you loaded. | ||
| "Should work" is not verification. --> | ||
|
|
||
| --- | ||
|
|
||
| **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. | ||
|
|
||
| <sub>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.</sub> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🔒 Security & Privacy | 🛡️ Analyzed with Security Review | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
Repository: redpine-ai/connect-cli
Length of output: 4779
🏁 Script executed:
Repository: redpine-ai/connect-cli
Length of output: 4787
🌐 Web query:
GitHub Actions pull_request workflow file merge commit pull_request_target base branch workflow security official documentation💡 Result:
In GitHub Actions, the
pull_requestandpull_request_targetevent triggers differ fundamentally in their security posture and context [1][2][3]. Key Differences and Security Implications pull_request - Context: Runs the workflow file from the merge commit of the pull request [1][2]. - Security: Considered unprivileged and safe for untrusted code [1][4]. GitHub automatically restricts these workflows by providing a read-only GITHUB_TOKEN, withholding access to repository secrets, and preventing access to privileged caches [1][3]. - Best Practice: Use this for building and testing code from pull requests [2][3]. pull_request_target - Context: Runs the workflow file from the base repository's default branch [1][2]. - Security: Considered a privileged context [5][4]. Because it runs using trusted code from your default branch, it is granted access to repository secrets and read/write permissions for the GITHUB_TOKEN [1][6][3]. - Risk: If you use actions/checkout to fetch the head of an untrusted pull request within a pull_request_target workflow, you may unintentionally execute malicious code with your repository's full privileges—a vulnerability known as a "pwn request" [5][7]. Recent Security Enhancements As of June 2026, actions/checkout (version 7 and later) includes built-in protection for pull_request_target workflows [7]. It will refuse to check out the head of a pull request from a fork unless you explicitly opt out by setting allow-unsafe-pr-checkout: true [1][7]. This flag is intentionally named to be highly visible during code reviews [1][7]. Recommended Secure Workflow Pattern To perform operations that require both untrusted pull request data and elevated permissions (such as posting comments or labeling), follow this two-stage approach: 1. Unprivileged Workflow: Triggered by pull_request. This workflow processes the untrusted code, runs tests, and saves the results as artifacts [4][8]. 2. Privileged Workflow: Triggered by workflow_run. This workflow waits for the first workflow to complete, then downloads the verified artifacts and performs the necessary privileged actions (using repository secrets or write permissions) [5][4][8]. This pattern ensures that untrusted code is never executed in an environment that has access to secrets or write tokens [4][8].Citations:
Authorization Bypass (CWE-862): Missing Authorization
Reachability: External · Exploitability: Moderate
Run the required check from trusted workflow code.
pull_requestloads this workflow from the pull request's merge commit. A pull request can change the validation logic while preserving the requiredpr-type-labeljob. Usepull_request_targetunless changes to this workflow are separately protected.Keep the current no-checkout design, least-privilege permissions, and no execution of pull-request code.
Proposed trigger change
📝 Committable suggestion
🤖 Prompt for AI Agents
Source: MCP tools