Skip to content

workflows: Consolidate pr-subscriber and issue-subscriber#200503

Open
tstellar wants to merge 1 commit into
llvm:mainfrom
tstellar:subscriber-rewrite
Open

workflows: Consolidate pr-subscriber and issue-subscriber#200503
tstellar wants to merge 1 commit into
llvm:mainfrom
tstellar:subscriber-rewrite

Conversation

@tstellar
Copy link
Copy Markdown
Contributor

This consolidates duplicate logic from the pr-subscriber and issue-subscriber workflows into a new workflow called subscriber-write. This workflow uses the workflow_run trigger and is triggered by another new workflow called subscriber.

The subscriber workflow collects the label name and issue number from the labeled issue/pull requests and sends it to the subscriber-write workflow via artifacts.

Besides removing some duplicate code this change also allows us to switch from using the pull_request_target event to the pull_request event for handling pull request subscribers. pull_request executes in an untrusted context and helps protect us from some security risks.

This consolidates duplicate logic from the pr-subscriber and
issue-subscriber workflows into a new workflow called
subscriber-write.  This workflow uses the workflow_run trigger
and is triggered by another new workflow called subscriber.

The subscriber workflow collects the label name and issue number
from the labeled issue/pull requests and sends it to the
subscriber-write workflow via artifacts.

Besides removing some duplicate code this change also allows us to
switch from using the pull_request_target event to the pull_request
event for handling pull request subscribers.  pull_request executes
in an untrusted context and helps protect us from some security risks.
@llvmorg-github-actions
Copy link
Copy Markdown

@llvm/pr-subscribers-github-workflow

Author: Tom Stellard (tstellar)

Changes

This consolidates duplicate logic from the pr-subscriber and issue-subscriber workflows into a new workflow called subscriber-write. This workflow uses the workflow_run trigger and is triggered by another new workflow called subscriber.

The subscriber workflow collects the label name and issue number from the labeled issue/pull requests and sends it to the subscriber-write workflow via artifacts.

Besides removing some duplicate code this change also allows us to switch from using the pull_request_target event to the pull_request event for handling pull request subscribers. pull_request executes in an untrusted context and helps protect us from some security risks.


Full diff: https://github.com/llvm/llvm-project/pull/200503.diff

4 Files Affected:

  • (removed) .github/workflows/issue-subscriber.yml (-52)
  • (removed) .github/workflows/pr-subscriber.yml (-52)
  • (added) .github/workflows/subscriber-write.yml (+114)
  • (added) .github/workflows/subscriber.yml (+36)
diff --git a/.github/workflows/issue-subscriber.yml b/.github/workflows/issue-subscriber.yml
deleted file mode 100644
index 4af255b4f8039..0000000000000
--- a/.github/workflows/issue-subscriber.yml
+++ /dev/null
@@ -1,52 +0,0 @@
-name: Issue Subscriber
-
-on:
-  issues:
-    types:
-      - labeled
-
-permissions:
-  contents: read
-
-jobs:
-  auto-subscribe:
-    environment:
-      name: main-branch-only
-      deployment: false
-    runs-on: ubuntu-24.04
-    if: github.repository == 'llvm/llvm-project'
-    steps:
-      - name: Checkout Automation Script
-        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
-        with:
-          persist-credentials: false
-          sparse-checkout: llvm/utils/git/
-          ref: main
-
-      - name: Setup Automation Script
-        working-directory: ./llvm/utils/git/
-        run: |
-          pip install --require-hashes -r requirements.txt
-
-      - id: app-token
-        uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3  # v3.1.1
-        with:
-          client-id: ${{ secrets.LLVM_TOKEN_GENERATOR_CLIENT_ID }}
-          private-key: ${{ secrets.LLVM_TOKEN_GENERATOR_PRIVATE_KEY }}
-          owner: ${{ github.repository_owner }}
-          permission-members: read
-          permission-contents: read
-          permission-issues: write
-
-      - name: Update watchers
-        working-directory: ./llvm/utils/git/
-        # https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable
-        env:
-          LABEL_NAME: ${{ github.event.label.name }}
-          ISSUE_SUBSCRIBER_TOKEN: ${{ steps.app-token.outputs.token }}
-        run: |
-          python3 ./github-automation.py \
-            --token "$ISSUE_SUBSCRIBER_TOKEN" \
-            issue-subscriber \
-            --issue-number '${{ github.event.issue.number }}' \
-            --label-name "$LABEL_NAME"
diff --git a/.github/workflows/pr-subscriber.yml b/.github/workflows/pr-subscriber.yml
deleted file mode 100644
index 04a5e2cfb0d29..0000000000000
--- a/.github/workflows/pr-subscriber.yml
+++ /dev/null
@@ -1,52 +0,0 @@
-name: PR Subscriber
-
-on:
-  pull_request_target:
-    types:
-      - labeled
-
-permissions:
-  contents: read
-
-jobs:
-  auto-subscribe:
-    # See https://github.blog/changelog/2025-11-07-actions-pull_request_target-and-environment-branch-protections-changes/
-    environment:
-      name: main-branch-only
-      deployment: false
-    runs-on: ubuntu-24.04
-    if: github.repository == 'llvm/llvm-project'
-    steps:
-      - name: Checkout Automation Script
-        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
-        with:
-          persist-credentials: false
-          sparse-checkout: llvm/utils/git/
-          ref: main
-
-      - name: Setup Automation Script
-        working-directory: ./llvm/utils/git/
-        run: |
-          pip install --require-hashes -r requirements.txt
-
-      - id: app-token
-        uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3  # v3.1.1
-        with:
-          client-id: ${{ secrets.LLVM_TOKEN_GENERATOR_CLIENT_ID }}
-          private-key: ${{ secrets.LLVM_TOKEN_GENERATOR_PRIVATE_KEY }}
-          owner: ${{ github.repository_owner }}
-          permission-members: read
-          permission-contents: read
-          permission-pull-requests: write
-
-      - name: Update watchers
-        working-directory: ./llvm/utils/git/
-        env:
-          LABEL_NAME: ${{ github.event.label.name }}
-          PR_SUBSCRIBER_TOKEN: ${{ steps.app-token.outputs.token }}
-        run: |
-          python3 ./github-automation.py \
-            --token "$PR_SUBSCRIBER_TOKEN" \
-            pr-subscriber \
-            --issue-number "${{ github.event.number }}" \
-            --label-name "$LABEL_NAME"
diff --git a/.github/workflows/subscriber-write.yml b/.github/workflows/subscriber-write.yml
new file mode 100644
index 0000000000000..a0b4c7866f437
--- /dev/null
+++ b/.github/workflows/subscriber-write.yml
@@ -0,0 +1,114 @@
+name: Subscriber Write
+
+on:
+  workflow_run:
+    workflows:
+      - "Subscriber"
+    types:
+      - completed
+
+permissions:
+  contents: read
+
+jobs:
+  subscriber-write:
+    environment:
+      name: main-branch-only
+      deployment: false
+    runs-on: ubuntu-24.04
+    if: >-
+      github.event.workflow_run.conclusion == 'success'
+    steps:
+      - name: Checkout Scripts
+        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+        with:
+          persist-credentials: false
+          sparse-checkout: |
+            llvm/utils/git/
+            .github/workflows/unprivileged-download-artifact/
+
+      - name: Download Data
+        uses: ./.github/workflows/unprivileged-download-artifact
+        id: download-artifact
+        with:
+          run-id: ${{ github.event.workflow_run.id }}
+          artifact-name: subscriber-data
+
+      - name: Collect Data
+        id: data
+        env:
+          DATA_FILE: subscriber-data
+        run: |
+          echo "issue-number=$(head -n1 $DATA_FILE)" >> $GITHUB_OUTPUT
+          echo "label-name=$(tail -n1 $DATA_FILE)" >> $GITHUB_OUTPUT
+
+      # Data coming from the pull_request event should be consider untrusted
+      # since the PR author will have full control of the information in the
+      # subscriber-data file.  To validate the data we just need to check that
+      # the label actually exists on the given PR.  We probably don't need to
+      # do this for the issues event, but we do it in anyway just to be
+      # extra safe.
+      - name: Validate Data
+        id: validated-label
+        uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
+        env:
+          ISSUE_NUMBER: ${{ steps.data.outputs.issue-number }}
+          LABEL_NAME: ${{ steps.data.outputs.label-name }}
+        with:
+          github-token: ${{ secrets.GITHUB_TOKEN }}
+          result-encoding: string
+          script: |
+            let labels = await github.rest.issues.listLabelsOnIssue({
+              owner: context.repo.owner,
+              repo: context.repo.repo,
+              issue_number: process.env.ISSUE_NUMBER
+            });
+
+            const hasLabel = labels.data.some((label) => label.name === process.env.LABEL_NAME);
+            if (hasLabel) {
+              return process.env.LABEL_NAME;
+            }
+            throw new Error(`Label ${process.env.LABEL_NAME} does not exist on issue ${process.env.ISSUE_NUMBER}.`);
+
+      - name: Setup Automation Script
+        working-directory: ./llvm/utils/git/
+        run: |
+          pip install --require-hashes -r requirements.txt
+
+      - id: app-token
+        uses: actions/create-github-app-token@1b10c78c7865c340bc4f6099eb2f838309f1e8c3  # v3.1.1
+        with:
+          client-id: ${{ secrets.LLVM_TOKEN_GENERATOR_CLIENT_ID }}
+          private-key: ${{ secrets.LLVM_TOKEN_GENERATOR_PRIVATE_KEY }}
+          owner: ${{ github.repository_owner }}
+          repositories: llvm-project
+          permission-members: read
+          permission-contents: read
+          permission-issues: write
+          permission-pull-requests: write
+
+      - name: Update subscribers
+        working-directory: ./llvm/utils/git/
+        env:
+          EVENT_TRIGGER: ${{ github.event.workflow_run.event }}
+          ISSUE_SUBSCRIBER_TOKEN: ${{ steps.app-token.outputs.token }}
+          LABEL_NAME: ${{ steps.validated-label.outputs.result }}
+          ISSUE_NUMBER: ${{ steps.data.outputs.issue-number }}
+        run: |
+          case "$EVENT_TRIGGER" in
+            pull_request)
+              command="pr-subscriber"
+              ;;
+            issues)
+              command="issue-subscriber"
+              ;;
+            *)
+              echo "Unknown event trigger: $EVENT_TRIGGER"
+              exit 1
+              ;;
+          esac
+          python3 ./github-automation.py \
+            --token "$ISSUE_SUBSCRIBER_TOKEN" \
+            "$command" \
+            --issue-number "$ISSUE_NUMBER" \
+            --label-name "$LABEL_NAME"
diff --git a/.github/workflows/subscriber.yml b/.github/workflows/subscriber.yml
new file mode 100644
index 0000000000000..b98a4a8c6cc18
--- /dev/null
+++ b/.github/workflows/subscriber.yml
@@ -0,0 +1,36 @@
+name: Subscriber
+
+on:
+  pull_request:
+    types:
+      - labeled
+  issues:
+    types:
+      - labeled
+
+permissions:
+  contents: read
+
+jobs:
+  subscriber:
+    runs-on: ubuntu-24.04
+    if: github.repository == 'llvm/llvm-project'
+    steps:
+      - id: data
+        env:
+          # github.event.number is for pull_request events and
+          # github.event.issue.number is for issues events.
+          ISSUE_NUMBER: ${{ github.event.number || github.event.issue.number }}
+          LABEL_NAME: ${{ github.event.label.name }}
+        run: |
+          filename=subscriber-data
+          echo "$ISSUE_NUMBER" >> $filename
+          echo "$LABEL_NAME" >> $filename
+          echo "filename=$filename" >> $GITHUB_OUTPUT
+
+
+      - name: Upload data
+        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+        with:
+          name: subscriber-data
+          path: ${{ steps.data.outputs.filename }}

Comment on lines +3 to +8
on:
workflow_run:
workflows:
- "Subscriber"
types:
- completed
Copy link
Copy Markdown
Contributor Author

@tstellar tstellar May 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GitHub recommends using workflow_run as a more secure alternative to pull_request_target. I disagree with this review.

@tstellar
Copy link
Copy Markdown
Contributor Author

One thing to note is that we merge this as-is, then existing pull requests will not trigger this new workflow and so it won't send out the notifications for new labels.

We could temporarily add support for the pull_request_target event to workaround this, but I felt that the chances of a PR being updated and having a new label added without it being also rebased or merge origin/main was low.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants