Comment with Kernel testing results on pull requests #3709
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
| # NOTE: This has read-write repo token and access to secrets, so this must | |
| # not run any untrusted code. | |
| # see: https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ | |
| name: Comment with Kernel testing results on pull requests | |
| on: | |
| workflow_run: | |
| workflows: ["Drivers CI Build"] | |
| types: | |
| - completed | |
| jobs: | |
| upload: | |
| runs-on: ubuntu-24.04 | |
| if: github.event.workflow_run.event == 'pull_request' && !github.event.repository.fork | |
| steps: | |
| - name: 'Download artifact' | |
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | |
| with: | |
| script: | | |
| var artifacts = await github.rest.actions.listWorkflowRunArtifacts({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| run_id: ${{github.event.workflow_run.id }}, | |
| }); | |
| var matchArtifacts = artifacts.data.artifacts.filter((artifact) => { | |
| return artifact.name == "pr-kernel-testing" | |
| }); | |
| if (!Array.isArray(matchArtifacts) || !matchArtifacts.length) { | |
| var process = require('process'); | |
| process.exit(); | |
| } | |
| var matchArtifact = matchArtifacts[0]; | |
| var download = await github.rest.actions.downloadArtifact({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| artifact_id: matchArtifact.id, | |
| archive_format: 'zip', | |
| }); | |
| var fs = require('fs'); | |
| fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(download.data)); | |
| - name: 'Unpack artifact' | |
| run: | | |
| if [ -f pr.zip ]; then | |
| unzip pr.zip | |
| fi | |
| - name: 'Comment on PR' | |
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| # Taken from https://github.com/actions/github-script/blob/main/.github/workflows/pull-request-test.yml | |
| script: | | |
| var fs = require('fs'); | |
| if (!fs.existsSync('./NR')) { | |
| var process = require('process'); | |
| process.exit(); | |
| } | |
| var issue_number = Number(fs.readFileSync('./NR')); | |
| // Validate artifact PR number against the workflow_run context | |
| // to prevent artifact poisoning (cross-issue comment injection). | |
| // | |
| // For same-repo PRs, workflow_run.pull_requests is populated. | |
| // For fork PRs, pull_requests is always empty, so we fall back | |
| // to searching for PRs by head repo owner and branch name. | |
| const run_prs = context.payload.workflow_run.pull_requests; | |
| let valid_pr_numbers = run_prs.map(pr => pr.number); | |
| if (valid_pr_numbers.length === 0) { | |
| // Fork PR: search using the head repo owner and branch from the | |
| // workflow_run payload (these fields are set by GitHub, not the fork). | |
| const head_owner = context.payload.workflow_run.head_repository.owner.login; | |
| const head_branch = context.payload.workflow_run.head_branch; | |
| const {data: matching_prs} = await github.rest.pulls.list({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| state: 'all', | |
| head: `${head_owner}:${head_branch}`, | |
| per_page: 10, | |
| }); | |
| valid_pr_numbers = matching_prs.map(pr => pr.number); | |
| } | |
| if (!valid_pr_numbers.includes(issue_number)) { | |
| core.setFailed(`Artifact PR number ${issue_number} does not match any PR for head ${context.payload.workflow_run.head_repository.owner.login}:${context.payload.workflow_run.head_branch}. Aborting to prevent artifact poisoning.`); | |
| return; | |
| } | |
| var comment_body = fs.readFileSync('./COMMENT'); | |
| // Get the existing comments. | |
| const {data: comments} = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issue_number, | |
| }); | |
| // Find any comment already made by the bot. | |
| const botComment = comments.find(comment => comment.user.id === 41898282 && comment.body.includes('# X64 kernel testing matrix')); | |
| if (botComment) { | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: botComment.id, | |
| body: comment_body.toString('utf8') | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: issue_number, | |
| body: comment_body.toString('utf8') | |
| }); | |
| } |