diff --git a/.github/workflows/format-command.yml b/.github/workflows/format-command.yml index f33478f5..97eec769 100644 --- a/.github/workflows/format-command.yml +++ b/.github/workflows/format-command.yml @@ -1,48 +1,28 @@ -name: Format Command +name: format-command +# This workflow no longer triggers on issue_comment directly. It only runs +# after .github/workflows/slash-command-dispatch.yml has verified that the +# commenter has write access to the repository and created a +# "format-command" repository_dispatch event. This removes the unauthenticated +# pwn-request path: untrusted commenters never reach this job. on: - issue_comment: - types: [created] + repository_dispatch: + types: [format-command] jobs: format: - name: "Format code via comment" + name: "Format code via /format command" runs-on: ubuntu-latest - # Only run if it's a PR and the comment contains /format - if: github.event.issue.pull_request != '' && contains(github.event.comment.body, '/format') permissions: contents: write pull-requests: write issues: write steps: - - name: React to comment - uses: actions/github-script@v7 - with: - script: | - github.rest.reactions.createForIssueComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: context.payload.comment.id, - content: '+1' - }) - - - name: Get PR details - id: pr - uses: actions/github-script@v7 - with: - script: | - const { data: pr } = await github.rest.pulls.get({ - owner: context.repo.owner, - repo: context.repo.repo, - pull_number: context.issue.number - }); - return pr; - - - name: Checkout PR code + - name: Checkout PR branch uses: actions/checkout@v4 with: - repository: ${{ fromJSON(steps.pr.outputs.result).head.repo.full_name }} - ref: ${{ fromJSON(steps.pr.outputs.result).head.ref }} + repository: ${{ github.event.client_payload.pull_request.head.repo.full_name }} + ref: ${{ github.event.client_payload.pull_request.head.ref }} token: ${{ secrets.GITHUB_TOKEN }} - name: Setup Node.js @@ -65,8 +45,21 @@ jobs: with: script: | github.rest.issues.createComment({ - issue_number: context.issue.number, + issue_number: context.payload.client_payload.github.payload.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: "I have successfully run Prettier and pushed the formatting fixes to this PR.\n\n**Note for Contributors:** Because this commit was pushed by a bot, GitHub will not automatically re-run the CI checks. To trigger them to pass, you must either:\n- Push an empty commit locally (`git commit --allow-empty -m \"Trigger builds\"` and push)\n- Close and immediately reopen this Pull Request." + }) + + - name: Post failure comment + if: failure() + uses: actions/github-script@v7 + with: + script: | + const runUrl = `${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; + github.rest.issues.createComment({ + issue_number: context.payload.client_payload.github.payload.issue.number, owner: context.repo.owner, repo: context.repo.repo, - body: 'I have successfully run Prettier and pushed the formatting fixes to this PR.\n\n **Note for Contributors:** Because this commit was pushed by a bot, GitHub will not automatically re-run the CI checks. To trigger them to pass, you must either:\n- Push an empty commit locally (`git commit --allow-empty -m "Trigger builds"` and push)\n- Close and immediately reopen this Pull Request.' + body: `I tried to run Prettier on this PR but the run failed. Please check the [workflow logs](${runUrl}) or run \`npx prettier --write .\` locally instead.` }) diff --git a/.github/workflows/slash-command-dispatch.yml b/.github/workflows/slash-command-dispatch.yml new file mode 100644 index 00000000..d8722fca --- /dev/null +++ b/.github/workflows/slash-command-dispatch.yml @@ -0,0 +1,21 @@ +name: Slash Command Dispatch + +on: + issue_comment: + types: [created] + +jobs: + slashCommandDispatch: + runs-on: ubuntu-latest + steps: + # peter-evans/slash-command-dispatch checks the commenter's repository + # permission (default: "write") BEFORE any dispatch event is created. + # No PR/fork code is checked out in this job, so untrusted commenters + # can never reach a step that holds write-scoped credentials. + - name: Slash Command Dispatch + uses: peter-evans/slash-command-dispatch@v5 + with: + token: ${{ secrets.PAT }} + commands: format + permission: write + issue-type: pull-request