-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Github action for enforcing Subject Matter Expert (SME) checks on labeled PRs #74076
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
base: master
Are you sure you want to change the base?
Changes from all commits
00a3616
5d26d4d
a914bc7
a72557e
2fdfa5b
473d60f
5ec96b7
94edeb9
9c58d14
97852e6
1e25e55
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,212 @@ | ||
| # SME Label Reviewers Automation | ||
|
|
||
| This automation ensures that pull requests touching specialized domains or | ||
| carrying designated GitHub labels receive formal approval from at least one | ||
| designated Subject Matter Expert (SME) before merging. | ||
|
|
||
| Because GitHub's standard `CODEOWNERS` and branch protection review rules | ||
| require dedicated GitHub Enterprise seats for every code owner, this automation | ||
| runs as a **standard GitHub Actions status check** (`Check SME Approvals`). It | ||
| enforces SME approvals on designated labels with **zero seat license overhead**. | ||
|
|
||
| --- | ||
|
|
||
| ## Table of Contents | ||
|
|
||
| 1. [How to Add a New Label](#1-how-to-add-a-new-label) | ||
| 2. [How to Manage the YAML Reviewer List](#2-how-to-manage-the-yaml-reviewer-list) | ||
| 3. [How to Re-Run the Workflow Once Review is Complete](#3-how-to-re-run-the-workflow-once-review-is-complete) | ||
| 4. [Branch Protection Integration](#4-branch-protection-integration) | ||
| 5. [Local CLI Verification](#5-local-cli-verification) | ||
|
|
||
| --- | ||
|
|
||
| ## 1. How to Add a New Label | ||
|
|
||
| You do **not** need to manually create labels on GitHub or have repository admin | ||
| permissions. | ||
|
|
||
| **New labels are created automatically on GitHub whenever a pull request with | ||
| changes to [`.github/label_reviewers.yaml`](./label_reviewers.yaml) is merged | ||
| into `master`.** | ||
|
|
||
| ### Steps to Add a Label: | ||
|
|
||
| 1. Open a pull request that adds your new label and its designated SME usernames | ||
| to [`.github/label_reviewers.yaml`](./label_reviewers.yaml). | ||
| 2. Once the PR is reviewed and merged into `master`, GitHub Actions | ||
| automatically detects the new label and creates it in the repository. | ||
|
|
||
| _(Optional)_ To have GitHub automatically attach this label to future PRs based | ||
| on touched file paths, add matching path rules to | ||
| [`.github/labeler.yml`](./labeler.yml): | ||
|
|
||
| ```yaml | ||
| # Example entry in .github/labeler.yml: | ||
| security: | ||
| - changed-files: | ||
| - any-glob-to-any-file: | ||
| - "src/crypto/*" | ||
| - "src/crypto/**/*" | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## 2. How to Manage the YAML Reviewer List | ||
|
|
||
| The reviewer list is managed in | ||
| [`.github/label_reviewers.yaml`](./label_reviewers.yaml). | ||
|
|
||
| ### File Format | ||
|
|
||
| The YAML file is strictly structured as a mapping of label names to lists of | ||
| GitHub usernames: | ||
|
|
||
| ```yaml | ||
| <label_name>: | ||
| - <github_username_1> | ||
| - <github_username_2> | ||
| ``` | ||
|
|
||
| ### Rules & Behaviors | ||
|
|
||
| - **Case-Insensitive**: Both label names and usernames are matched | ||
| case-insensitively (`Security` matches `security`, `Cecille` matches | ||
| `cecille`). | ||
| - **No Leading `@`**: Usernames must not include leading `@` (use `username`, | ||
| not `@username`). | ||
| - **Quotes Optional**: Usernames can be unquoted or enclosed in quotes | ||
| (`username`, `'username'`, or `"username"`). Quotes are not required for | ||
| standard GitHub usernames. | ||
| - **OR-Logic per Label**: At least **one** listed reviewer from the label's | ||
| list must approve the PR. | ||
| - **AND-Logic across Labels**: If a PR has multiple designated labels attached | ||
| (e.g., both `security` and `certification`), **every** attached label | ||
| requires at least one approval from its respective reviewer list (approval | ||
| required for each domain). | ||
| - **Author Self-Approval Exclusion**: A PR author **cannot approve their own | ||
| PR**. Even if the author is listed as an SME for a label, another reviewer | ||
| from that label's list must provide the approval. | ||
| - **State Transition Awareness**: The check accurately tracks current review | ||
| states. If an SME approves, but later submits `CHANGES_REQUESTED` or the | ||
| approval is `DISMISSED`, the approval is no longer valid until re-approved. | ||
|
|
||
| ### Example Configuration | ||
|
|
||
| ```yaml | ||
| # Core architecture & SDK infrastructure | ||
| core: | ||
| - cecille | ||
| - andy31415 | ||
|
|
||
| # Security & Cryptography reviews | ||
| security: | ||
| - cecille | ||
| - bzbarsky-apple | ||
|
|
||
| # Data Model & Cluster XML specifications | ||
| data-model: | ||
| - bzbarsky-apple | ||
| - Boris-Virk | ||
| ``` | ||
|
|
||
| ### Adding or Updating Reviewers | ||
|
|
||
| 1. Create a branch: | ||
| ```bash | ||
| git checkout -b update-sme-reviewers | ||
| ``` | ||
| 2. Edit [`.github/label_reviewers.yaml`](./label_reviewers.yaml) to add the | ||
| label and username(s). | ||
| 3. Commit and submit a PR: | ||
| ```bash | ||
| git add .github/label_reviewers.yaml | ||
| git commit -m "Update SME reviewers for <domain>" | ||
| git push origin update-sme-reviewers | ||
| ``` | ||
| 4. Once merged into `master`, all future and open PRs will use the updated | ||
| reviewer list. | ||
|
|
||
| --- | ||
|
|
||
| ## 3. How to Re-Run the Workflow Once Review is Complete | ||
|
|
||
| Once the designated SME has reviewed and submitted an **APPROVED** review, you | ||
| have several quick ways to update the check: | ||
|
|
||
| ### Method 1: Automatic Re-evaluation (Zero Action Required) | ||
|
|
||
| The workflow actively listens to GitHub's `pull_request_review` events | ||
| (`submitted`, `edited`, `dismissed`). | ||
| **As soon as the SME submits an "Approved" review, the workflow automatically | ||
| re-runs and updates to green without any manual intervention.** | ||
|
|
||
| ### Method 2: PR Comment Command (`/check-sme`) | ||
|
|
||
| You can trigger an immediate re-evaluation directly from the PR conversation | ||
| page: | ||
|
|
||
| 1. Open the PR. | ||
| 2. Type the following comment and submit: | ||
| ```text | ||
| /check-sme | ||
| ``` | ||
| 3. GitHub Actions will detect the command and trigger the `Check SME Approvals` | ||
| check immediately. | ||
|
|
||
| ### Method 3: Re-Run from the PR "Checks" Tab | ||
|
|
||
| 1. On the pull request page, click on the **Checks** tab (or click **Details** | ||
| next to `Check SME Approvals` in the status checks list at the bottom of the | ||
| **Conversation** tab). | ||
| 2. Select **Check SME Approvals** from the left panel. | ||
| 3. In the top-right corner, click **Re-run jobs** (or **Re-run**). | ||
|
|
||
| ### Method 4: Label Toggling | ||
|
|
||
| Removing and re-adding the monitored label (or adding any other label) triggers | ||
| the `labeled` / `unlabeled` PR event and immediately re-evaluates the check. | ||
|
|
||
| --- | ||
|
|
||
| ## 4. Branch Protection Integration | ||
|
|
||
| To prevent pull requests from merging until the SME review check passes: | ||
|
|
||
| 1. Open repository **Settings** -> **Branches**. | ||
| 2. Under **Branch protection rules**, edit your target branch (e.g. `master`). | ||
| 3. Check **Require status checks to pass before merging**. | ||
| 4. In the search box under "Status checks that are required", search for and | ||
| select: | ||
| ```text | ||
| Check SME Approvals | ||
| ``` | ||
| 5. Click **Save changes**. | ||
|
|
||
| > [!NOTE] Unlike standard GitHub "Require review from Code Owners", setting | ||
| > `Check SME Approvals` as a required status check does **not** consume any | ||
| > GitHub Enterprise seats or require external subscription services. | ||
|
|
||
| --- | ||
|
|
||
| ## 5. Local CLI Verification | ||
|
|
||
| The underlying verification script uses the GitHub CLI (`gh`) and can also be | ||
| run locally on a developer workstation or cloudtop: | ||
|
|
||
| ```bash | ||
| # Ensure GitHub CLI is authenticated (via gh auth login or GH_TOKEN) | ||
| gh auth status | ||
|
|
||
| # Run unit tests | ||
| python3 -m unittest scripts/tools/tests/test_check_label_reviewers.py | ||
|
|
||
| # Validate YAML configuration syntax and format locally | ||
| python3 scripts/tools/check_label_reviewers.py --validate-config | ||
|
|
||
| # Run check on a specific PR | ||
| python3 scripts/tools/check_label_reviewers.py --pr 30000 | ||
|
|
||
| # Test with a custom config file | ||
| python3 scripts/tools/check_label_reviewers.py --pr 30000 --config /path/to/custom_reviewers.yaml | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| # | ||
| # Copyright (c) 2026 Project CHIP Authors | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
| # | ||
|
|
||
| # ============================================================================== | ||
| # Subject Matter Expert (SME) Reviewers by Pull Request Label | ||
| # ============================================================================== | ||
| # This configuration maps GitHub PR labels to lists of designated Subject Matter | ||
| # Expert (SME) reviewers. | ||
| # | ||
| # When a pull request has one or more of these labels attached, the | ||
| # "check-label-reviewers" GitHub Action verifies that at least one reviewer from | ||
| # EACH matching label's list has submitted an APPROVED review. | ||
| # | ||
| # Documentation: See .github/LABEL_REVIEWERS.md for complete instructions on: | ||
| # - Creating labels on GitHub | ||
| # - Managing reviewer lists | ||
| # - Re-running the check from within PRs (via comment, UI, or events) | ||
| # | ||
| # Key Features: | ||
| # - Usernames and labels are case-insensitive. | ||
| # - Usernames must NOT include leading '@' (e.g. 'username', not '@username'). | ||
| # - Quotes around usernames are optional (e.g. username, 'username', or "username"). | ||
| # - PR authors cannot approve their own PRs (author approvals are ignored). | ||
| # - If a PR has no designated labels attached, the check passes automatically. | ||
| # - If multiple designated labels are attached, EVERY label requires at least one | ||
| # approval from its respective reviewer list. | ||
| # | ||
| # Format: | ||
| # <label_name>: | ||
| # - <github_username_1> | ||
| # - <github_username_2> | ||
| # | ||
| # Example (uncomment and customize to add new SME review labels): | ||
| # # my-label: | ||
| # # - github-username1 | ||
| # # - github-username2 | ||
| # ============================================================================== | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| # | ||
| # Copyright (c) 2026 Project CHIP Authors | ||
| # | ||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||
| # you may not use this file except in compliance with the License. | ||
| # You may obtain a copy of the License at | ||
| # | ||
| # http://www.apache.org/licenses/LICENSE-2.0 | ||
| # | ||
| # Unless required by applicable law or agreed to in writing, software | ||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| # See the License for the specific language governing permissions and | ||
| # limitations under the License. | ||
| # | ||
|
|
||
| name: Check SME Label Reviewers | ||
|
|
||
| on: | ||
| pull_request_target: | ||
| types: [opened, synchronize, reopened, labeled, unlabeled] | ||
| pull_request_review: | ||
| types: [submitted, edited, dismissed] | ||
| issue_comment: | ||
| types: [created] | ||
| push: | ||
| branches: [master] | ||
| paths: | ||
| - ".github/label_reviewers.yaml" | ||
| workflow_dispatch: | ||
|
|
||
| concurrency: | ||
| group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.event.issue.number || github.sha }} | ||
| cancel-in-progress: true | ||
|
|
||
| jobs: | ||
| check-sme-review: | ||
| name: Check SME Approvals | ||
| runs-on: ubuntu-latest | ||
| if: | | ||
| github.event_name != 'issue_comment' || | ||
| (github.event.issue.pull_request != null && contains(github.event.comment.body, '/check-sme')) | ||
| permissions: | ||
| contents: read | ||
| pull-requests: read | ||
| issues: write | ||
|
|
||
| steps: | ||
| - name: Checkout Repository | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Setup Python | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: "3.12" | ||
|
|
||
| - name: Install Dependencies | ||
| run: | | ||
| pip install --no-cache-dir pyyaml | ||
|
|
||
| - name: Determine PR Number and Options | ||
| id: params | ||
| run: | | ||
| if [ "${{ github.event_name }}" = "workflow_dispatch" ] || [ "${{ github.event_name }}" = "push" ]; then | ||
| echo "pr_number=" >> "$GITHUB_OUTPUT" | ||
| echo "sync_labels=true" >> "$GITHUB_OUTPUT" | ||
| elif [ "${{ github.event_name }}" = "issue_comment" ]; then | ||
| echo "pr_number=${{ github.event.issue.number }}" >> "$GITHUB_OUTPUT" | ||
| echo "sync_labels=false" >> "$GITHUB_OUTPUT" | ||
| else | ||
| echo "pr_number=${{ github.event.pull_request.number }}" >> "$GITHUB_OUTPUT" | ||
| echo "sync_labels=false" >> "$GITHUB_OUTPUT" | ||
| fi | ||
|
|
||
| - name: Fetch PR Configuration | ||
| if: steps.params.outputs.pr_number != '' | ||
| run: | | ||
| git fetch origin "refs/pull/${{ steps.params.outputs.pr_number }}/head" --depth=1 | ||
| git checkout FETCH_HEAD -- .github/label_reviewers.yaml || true | ||
|
Comment on lines
+78
to
+79
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🔒 Security & Privacy | 🛡️ Analyzed with Security Review | 🔴 Critical | ⚡ Quick win 🧩 Analysis chain🤖 get_repo_knowledge executed:
Length of output: 4555 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- workflow ---'
sed -n '1,180p' .github/workflows/check_label_reviewers.yaml
printf '%s\n' '--- related files ---'
git ls-files '.github' | grep -E 'label_reviewers|check_label|reviewer' || true
printf '%s\n' '--- references ---'
rg -n --glob '!node_modules' --glob '!dist' 'label_reviewers|check_label_reviewers|pull_request_target|issue_comment' .githubRepository: project-chip/connectedhomeip Length of output: 6738 🏁 Script executed: #!/bin/bash
set -eu
sed -n '1,180p' .github/workflows/check_label_reviewers.yaml
printf '%s\n' '--- related files ---'
git ls-files '.github' | grep -E 'label_reviewers|check_label|reviewer' || true
printf '%s\n' '--- references ---'
rg -n --glob '!node_modules' --glob '!dist' 'label_reviewers|check_label_reviewers|pull_request_target|issue_comment' .githubRepository: project-chip/connectedhomeip Length of output: 6721 🌐 Web query:
💡 Result: In the Citations:
🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- checker outline ---'
ast-grep outline scripts/tools/check_label_reviewers.py
printf '%s\n' '--- checker source ---'
sed -n '1,280p' scripts/tools/check_label_reviewers.py
printf '%s\n' '--- policy ---'
cat .github/label_reviewers.yaml
printf '%s\n' '--- relevant tests ---'
rg -n -C 4 'no monitored|no label|success|review|config|label' scripts/tools/tests/test_check_label_reviewers.py | head -240Repository: project-chip/connectedhomeip Length of output: 21977 🏁 Script executed: #!/bin/bash
set -eu
sed -n '285,390p' scripts/tools/check_label_reviewers.py
sed -n '221,310p' scripts/tools/tests/test_check_label_reviewers.pyRepository: project-chip/connectedhomeip Length of output: 7645 🏁 Script executed: #!/bin/bash
set -eu
sed -n '390,470p' scripts/tools/check_label_reviewers.pyRepository: project-chip/connectedhomeip Length of output: 2586 Authorization Bypass Reachability: External Use the trusted branch configuration for enforcement. The workflow replaces its policy with the pull request's Use the default-branch configuration for enforcement. Validate proposed configuration changes in a separate read-only path. 🧰 Tools🪛 zizmor (1.29.0)[info] 78-78: code injection via template expansion (template-injection): may expand into attacker-controllable code (template-injection) 🤖 Prompt for AI Agents |
||
|
|
||
| - name: Run Unit Tests | ||
| run: | | ||
| python3 -m unittest scripts/tools/tests/test_check_label_reviewers.py | ||
|
|
||
| - name: Validate Configuration File | ||
| run: | | ||
| python3 scripts/tools/check_label_reviewers.py \ | ||
| --config .github/label_reviewers.yaml \ | ||
| --validate-config | ||
|
|
||
| - name: Execute SME Reviewer Check | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| if [ "${{ steps.params.outputs.sync_labels }}" = "true" ]; then | ||
| python3 scripts/tools/check_label_reviewers.py \ | ||
| --repo "${{ github.repository }}" \ | ||
| --config .github/label_reviewers.yaml \ | ||
| --sync-labels | ||
| fi | ||
|
|
||
| if [ -n "${{ steps.params.outputs.pr_number }}" ]; then | ||
| python3 scripts/tools/check_label_reviewers.py \ | ||
| --pr "${{ steps.params.outputs.pr_number }}" \ | ||
| --repo "${{ github.repository }}" \ | ||
| --config .github/label_reviewers.yaml | ||
| fi | ||
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.
🩺 Stability & Availability | 🟠 Major | 🏗️ Heavy lift
🔎 Supported by static analysis
🤖 get_repo_knowledge executed:
get_repo_knowledge project-chip/connectedhomeip /tmp/coderabbit-repo-knowledge/project-chip-connectedhomeip-172a5ad8/learningsLength of output: 4555
🏁 Script executed:
Repository: project-chip/connectedhomeip
Length of output: 9015
🏁 Script executed:
Repository: project-chip/connectedhomeip
Length of output: 21081
🏁 Script executed:
Repository: project-chip/connectedhomeip
Length of output: 21057
🏁 Script executed:
Repository: project-chip/connectedhomeip
Length of output: 12776
🌐 Web query:
site:docs.github.com GitHub Actions pull_request_target GITHUB_SHA pull_request_review issue_comment required status checks latest commit pull request💡 Result:
The
pull_request_targetevent is a specialized GitHub Actions trigger designed to allow workflows to run with elevated privileges (access to secrets and a read/writeGITHUB_TOKEN) when responding to activity on pull requests, particularly those originating from forks [1][2]. Key considerations and behaviors include: Context and Security: Unlike thepull_requestevent, which runs in the context of the merge commit (an ephemeral state that includes the PR's changes),pull_request_targetworkflows execute in the context of the base repository's default branch [2]. Because the workflow code itself is sourced from the trusted base repository rather than the untrusted pull request, it is safe to grant these workflows access to secrets and repository write permissions [1][3]. GITHUB_SHA and Checkout: Because the workflow runs from the base branch, theGITHUB_SHAenvironment variable defaults to the commit hash of the base branch's latest commit, not the pull request's head [2]. To interact with the pull request's content, you must explicitly check it out using theactions/checkoutaction. You can target the PR's specific commit using the following syntax [3]: steps: - uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} Security Warning: You must exercise extreme caution when checking out untrusted code from a pull request in apull_request_targetworkflow. If you execute scripts, build commands (likemake), or load configuration files from the checked-out PR code, you are effectively running untrusted code with the elevated permissions of your base branch [1][4]. GitHub documentation strongly advises against this pattern unless you have fully secured your execution environment [1]. Status Checks and Automation:pull_request_targetis commonly used for automation that requires write access, such as labeling pull requests, posting comments, or setting status checks [1][2]. Since these workflows run with base-branch credentials, they can authenticate against the GitHub API to update pull request status checks, even if the PR originated from an external fork [1]. Status Checks vs. Event Types: Whilepull_request_targetcan trigger on various activity types (likeopened,synchronize, orreopened), it is independent of the PR's merge status and will run even if there are merge conflicts [2]. Status checks set by these workflows behave similarly to other status checks and are managed via the GitHub Checks API [5]. For security-sensitive workflows, prioritizepull_requestfor CI tasks that build code andpull_request_targetonly for repository-level management tasks that do not execute code from the PR [4].Citations:
🏁 Script executed:
Repository: project-chip/connectedhomeip
Length of output: 10934
🌐 Web query:
site:docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows issue_comment GITHUB_SHA default branch pull_request_review GITHUB_SHA merge commit💡 Result:
The value of GITHUB_SHA in GitHub Actions workflows varies depending on the triggering event [1]: For the issue_comment event: GITHUB_SHA is the last commit on the default branch of the repository [1]. For the pull_request_review event: GITHUB_SHA is the last merge commit of the pull request merge branch (refs/pull/PULL_REQUEST_NUMBER/merge) [1]. If you need the commit ID for the actual head of the pull request branch rather than the merge commit, you should use github.event.pull_request.head.sha instead [1].
Citations:
🌐 Web query:
site:docs.github.com/en/pull-requests/reference/status-checks required status checks latest commit pull request head SHA💡 Result:
To determine the required status checks for a pull request's head commit, you must interact with the branch protection settings for the target branch, as GitHub defines required status checks at the branch protection level rather than the commit level [1]. The list of required status checks for a specific branch can be retrieved using the GitHub REST API endpoint for branch protection. To fetch the required status checks for a branch: GET /repos/{owner}/{repo}/branches/{branch}/protection/required_status_checks This endpoint returns the configuration for required status checks, including the list of checks that must pass before a pull request can be merged into that branch. Once you have the list of required checks, you can compare them against the actual status of the checks for the pull request head SHA. You can retrieve the status of checks for a specific commit using the following API endpoints: 1. Check Runs: GET /repos/{owner}/{repo}/commits/{ref}/check-runs 2. Commit Statuses: GET /repos/{owner}/{repo}/statuses/{ref} By correlating the required checks identified from the branch protection settings with the results from the check runs or commit statuses associated with the head SHA, you can determine if all necessary validations have passed [1].
Citations:
🌐 Web query:
site:docs.github.com pull_request_target required status check check run associated pull request base branch commit github.sha💡 Result:
In a GitHub Actions workflow triggered by the pull_request_target event, the default context variable github.sha is not the commit SHA of the pull request's head branch [1]. Instead, because the workflow runs in the context of the base repository's default branch, github.sha represents the latest commit of that base branch [1]. To reference the commit SHA of the pull request head in a pull_request_target workflow, you must use the following context property: ${{ github.event.pull_request.head.sha }} [1][2] When configuring status checks for a pull request, remember the following: 1. Consistency: If you are using actions/checkout to build or test the pull request code, you should explicitly check out the head SHA to ensure you are operating on the correct commit [2]: - uses: actions/checkout@v6 with: ref: ${{ github.event.pull_request.head.sha }} 2. GitHub Checks API: Status checks and check runs are associated with a specific Git reference [3]. If you are creating a check run via the REST API for a pull request, you should associate it with the head SHA (${{ github.event.pull_request.head.sha }}) to ensure the check appears correctly in the pull request UI [3][4]. 3. Security: The pull_request_target event is designed to run in the context of the base repository's default branch, which allows you to safely use secrets and a read/write GITHUB_TOKEN [1][2]. Always use the head SHA to pull the untrusted code, but be cautious about executing any build scripts or configuration files from that checked-out commit, as they could contain malicious commands that access those secrets [2][5].
Citations:
🌐 Web query:
site:github.com/orgs/community/discussions pull_request_target required status checks base commit pull request💡 Result:
The pull_request_target event in GitHub Actions is designed to run workflows in the context of the base repository, even when triggered by pull requests from forks. It is specifically intended to allow access to repository secrets or other privileged resources that would otherwise be restricted for pull requests from forks. Regarding required status checks and the base commit: 1. Context of Execution: When a workflow uses pull_request_target, the workflow runs on the base repository's version of the workflow file, and it is executed against the base commit of the pull request by default. This ensures that the code running in the workflow is trusted by the repository maintainers. 2. Interaction with Required Status Checks: Required status checks are configured to enforce that specific jobs must complete successfully before a pull request can be merged. Because pull_request_target workflows execute in the context of the base repository, they are often used to define custom automation or checks. However, if a workflow triggered by pull_request_target is set as a required status check, it will run for every pull request event and must succeed to allow merging. 3. Base vs. Head Commit: Unlike the standard pull_request event, which checks out the head commit of the pull request (the code submitted by the contributor), pull_request_target provides the base commit of the pull request in the default context. If you need to access or test the code submitted in the pull request (the head commit), you must explicitly configure your checkout step to fetch the head commit instead of the default base commit. For example, using the official actions/checkout action, you would typically specify: - name: Checkout the pull request head uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} This distinction is critical for security: by defaulting to the base commit, pull_request_target prevents malicious code in a fork from being executed automatically with elevated permissions or access to repository secrets. Always ensure that any workflow using pull_request_target carefully validates the content of the pull request if it intends to act on the head commit.
Citations:
Keep the SME policy on the trusted branch.
pull_request_targetfetches.github/label_reviewers.yamlfrom the pull request, andcheck_label_reviewers.pyuses that file to determine required reviewers. A contributor can remove the mappings, causing the check to pass automatically without SME approval. Load the policy only from the trusted base branch.🧰 Tools
🪛 zizmor (1.29.0)
[error] 19-30: use of fundamentally insecure workflow trigger (dangerous-triggers): pull_request_target is almost always used insecurely
(dangerous-triggers)
🤖 Prompt for AI Agents