Comment Check Amalgamation #1738
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
| name: Comment Check Amalgamation | |
| on: | |
| workflow_run: | |
| workflows: ["Check amalgamation"] | |
| types: | |
| - completed | |
| permissions: | |
| contents: read | |
| jobs: | |
| comment: | |
| if: ${{ github.event.workflow_run.conclusion == 'failure' }} | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| actions: read | |
| issues: read | |
| pull-requests: write | |
| steps: | |
| - name: Harden Runner | |
| uses: step-security/harden-runner@9af89fc71515a100421586dfdb3dc9c984fbf411 # v2.19.4 | |
| with: | |
| egress-policy: audit | |
| - name: 'Download artifact' | |
| id: download | |
| 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 matchArtifact = artifacts.data.artifacts.filter((artifact) => { | |
| return artifact.name == "pr" | |
| })[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)); | |
| var hasPatch = artifacts.data.artifacts.some((artifact) => artifact.name == "amalgamation-patch"); | |
| core.setOutput('has_patch', String(hasPatch)); | |
| # Extract the untrusted PR artifact into a dedicated empty directory and | |
| # read only the two expected files by fixed path afterwards. This avoids a | |
| # malicious archive overwriting workspace files or escaping via ../ paths. | |
| - run: unzip -o pr.zip -d ./pr_artifact | |
| - name: 'Comment on PR' | |
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | |
| with: | |
| github-token: ${{ secrets.GITHUB_TOKEN }} | |
| script: | | |
| var fs = require('fs'); | |
| // Both values come from a fork-triggered workflow and are therefore | |
| // attacker-controlled. Validate them strictly before use to prevent | |
| // Markdown/mention injection and bogus REST API filters. | |
| const author = fs.readFileSync('./pr_artifact/author', 'utf8').trim(); | |
| if (!/^[A-Za-z0-9-]{1,39}$/.test(author)) { | |
| core.setFailed(`Refusing to proceed: untrusted author value '${author}' is not a valid GitHub username.`); | |
| return; | |
| } | |
| const issue_number = Number(fs.readFileSync('./pr_artifact/number', 'utf8').trim()); | |
| if (!Number.isInteger(issue_number) || issue_number <= 0) { | |
| core.setFailed('Refusing to proceed: untrusted PR number is not a positive integer.'); | |
| return; | |
| } | |
| const opts = github.rest.issues.listForRepo.endpoint.merge({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| creator: author, | |
| state: 'all' | |
| }) | |
| let first = true | |
| const issues = await github.paginate(opts) | |
| for (const issue of issues) { | |
| if (issue.number === issue_number) { | |
| continue | |
| } | |
| if (issue.pull_request) { | |
| first = false | |
| break | |
| } | |
| } | |
| const hasPatch = '${{ steps.download.outputs.has_patch }}' === 'true'; | |
| const runUrl = '${{ github.event.workflow_run.html_url }}'; | |
| await github.rest.issues.createComment({ | |
| issue_number: issue_number, | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| body: '## 🔴 Amalgamation check failed! 🔴\nThe source code has not been amalgamated and/or formatted correctly.' | |
| + (hasPatch ? '\n\n📎 A ready-to-apply patch is attached to the [failed workflow run](' + runUrl + ') as the `amalgamation-patch` artifact.' | |
| + ' Download it, then apply it locally from the repository root with:' | |
| + '\n\n```shell\ngit apply amalgamation.patch\n```\n\n' | |
| + 'This does not require installing astyle yourself.' | |
| : '') | |
| + (first ? '\n\n@' + author + ' Please read and follow the [Contribution Guidelines]' | |
| + '(https://github.com/nlohmann/json/blob/develop/.github/CONTRIBUTING.md#files-to-change).' | |
| : '') | |
| }) |