1name: Lintcheck summary23# The workflow_run event runs in the context of the Clippy repo giving it write4# access, needed here to create a PR comment when the PR originates from a fork5#6# The summary artifact is a JSON file that we verify in this action to prevent7# the creation of arbitrary comments8#9# This action must not checkout/run code from the originating workflow_run10# or directly interpolate ${{}} untrusted fields into code11#12# https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows#workflow_run13# https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions#understanding-the-risk-of-script-injections1415on:16 workflow_run:17 workflows: [Lintcheck]18 types: [completed]1920# Restrict the default permission scope https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions#defining-access-for-the-github_token-scopes21permissions:22 pull-requests: write2324jobs:25 download:26 runs-on: ubuntu-latest27 if: ${{ github.event.workflow_run.conclusion == 'success' }}28 steps:29 - name: Download artifact30 uses: actions/download-artifact@v831 with:32 name: summary33 path: untrusted34 run-id: ${{ github.event.workflow_run.id }}35 github-token: ${{ github.token }}3637 - name: Format comment38 uses: actions/github-script@v939 with:40 script: |41 const fs = require("fs");42 const assert = require("assert/strict");4344 function validateName(s) {45 assert.match(s, /^[a-z0-9_:]+$/);46 return s;47 }4849 function validateInt(i) {50 assert.ok(Number.isInteger(i));51 return i;52 }5354 function tryReadSummary() {55 try {56 return JSON.parse(fs.readFileSync("untrusted/summary.json"));57 } catch {58 return null;59 }60 }6162 const prNumber = parseInt(fs.readFileSync("untrusted/pr.txt"), 10);63 core.exportVariable("PR", prNumber.toString());6465 const untrustedSummary = tryReadSummary();66 if (!Array.isArray(untrustedSummary)) {67 return;68 }6970 let summary = `Lintcheck changes for ${context.payload.workflow_run.head_sha}71 72 | Lint | Added | Removed | Changed |73 | ---- | ----: | ------: | ------: |74 `;7576 for (const untrustedRow of untrustedSummary) {77 const name = validateName(untrustedRow.name);7879 const added = validateInt(untrustedRow.added);80 const removed = validateInt(untrustedRow.removed);81 const changed = validateInt(untrustedRow.changed);8283 const id = name.replace("clippy::", "user-content-").replaceAll("_", "-");84 const url = `https://github.com/${process.env.GITHUB_REPOSITORY}/actions/runs/${context.payload.workflow_run.id}#${id}`;8586 summary += `| [\`${name}\`](${url}) | ${added} | ${removed} | ${changed} |\n`;87 }8889 summary += "\nThis comment will be updated if you push new changes";9091 fs.writeFileSync("summary.md", summary);9293 - name: Create/update comment94 run: |95 if [[ -f summary.md ]]; then96 gh pr comment "$PR" --body-file summary.md --edit-last --create-if-none97 else98 # There were no changes detected by Lintcheck99 # - If a comment exists from a previous run that did detect changes, edit it (--edit-last)100 # - If no comment exists do not create one, the `gh` command exits with an error which101 # `|| true` ignores102 gh pr comment "$PR" --body "No changes for ${{ github.event.workflow_run.head_sha }}" --edit-last || true103 fi104 env:105 GH_TOKEN: ${{ github.token }}106 GH_REPO: ${{ github.repository }}
Findings
✓ No findings reported for this file.