Tighten workflow for posting PR comments (#451)

- In post_summaries.yaml, fall back to querying the GitHub API for PRs
  associated with the workflow run commit SHA when
  workflow_run.pull_requests is empty (which is the case for PRs from
  forks).
- When validating commentId, verify that comment.data.user.login is
  github-actions[bot] before updating or deleting comments.
- Update firehose README with a note on zizmor compatibility and
  permissions.
diff --git a/.github/workflows/post_summaries.yaml b/.github/workflows/post_summaries.yaml
index a92a76b..fcb068e 100644
--- a/.github/workflows/post_summaries.yaml
+++ b/.github/workflows/post_summaries.yaml
@@ -4,7 +4,7 @@
   # Trigger this workflow after the Health workflow completes. This workflow will have permissions to
   # do things like create comments on the PR, even if the original workflow couldn't.
   workflow_call:
-  workflow_run:
+  workflow_run: # zizmor: ignore[dangerous-triggers]
     workflows:
       - Publish:Internal
       - Health:Internal
@@ -63,7 +63,19 @@
             var fs = require('fs');
 
             const prs = context.payload.workflow_run ? context.payload.workflow_run.pull_requests : [];
-            const issue_number = prs.length > 0 ? prs[0].number : (context.issue ? context.issue.number : null);
+            let issue_number = prs.length > 0 ? prs[0].number : (context.issue ? context.issue.number : null);
+
+            if (!issue_number && context.payload.workflow_run && context.payload.workflow_run.head_sha) {
+              const prList = await github.rest.repos.listPullRequestsAssociatedWithCommit({
+                owner: context.repo.owner,
+                repo: context.repo.repo,
+                commit_sha: context.payload.workflow_run.head_sha,
+              });
+              const pr = prList.data.find(p => p.state === 'open') || prList.data[0];
+              if (pr) {
+                issue_number = pr.number;
+              }
+            }
 
             if (!issue_number) {
               console.log('No PR number found in context. Aborting.');
@@ -71,7 +83,7 @@
             }
 
             if (fs.existsSync('./issueNumber')) {
-              const artifactIssue = Number(fs.readFileSync('./issueNumber', 'utf8'));
+              const artifactIssue = Number(fs.readFileSync('./issueNumber', 'utf8').trim());
               if (artifactIssue !== issue_number) {
                 console.log(`Artifact issueNumber (${artifactIssue}) does not match PR #${issue_number}. Aborting.`);
                 return;
@@ -79,7 +91,7 @@
             }
 
             if (fs.existsSync('./commentId')) {
-              const comment_number = Number(fs.readFileSync('./commentId', 'utf8'));
+              const comment_number = Number(fs.readFileSync('./commentId', 'utf8').trim());
               const comment = await github.rest.issues.getComment({
                 owner: context.repo.owner,
                 repo: context.repo.repo,
@@ -90,6 +102,10 @@
                 console.log(`Comment ID ${comment_number} belongs to PR #${commentIssueNumber}, not PR #${issue_number}. Aborting.`);
                 return;
               }
+              if (comment.data.user && comment.data.user.login !== 'github-actions[bot]') {
+                console.log(`Comment ID ${comment_number} was authored by ${comment.data.user.login}, not github-actions[bot]. Aborting.`);
+                return;
+              }
             }
 
             if (fs.existsSync('./comment.md')) {
diff --git a/pkgs/firehose/CHANGELOG.md b/pkgs/firehose/CHANGELOG.md
index 99f5e19..207567d 100644
--- a/pkgs/firehose/CHANGELOG.md
+++ b/pkgs/firehose/CHANGELOG.md
@@ -1,5 +1,8 @@
 ## 0.13.2-wip
 
+- Document Zizmor compatibility and ignore syntax for `post_summaries.yaml`.
+- Update `post_summaries.yaml` to resolve PR numbers for fork workflow runs via
+  commit SHA, and verify comment authorship when checking `commentId`.
 - Update `dependency_validator` pinned commit hash to 5.0.6 (`7582a808960d2170800bfbd7a83526619ce300ce`),
   enabling support for newer Dart syntax (up to analyzer 13).
 - Update existing publishing PR comments with accurate status when packages are
diff --git a/pkgs/firehose/README.md b/pkgs/firehose/README.md
index 88c1dbf..8a0d113 100644
--- a/pkgs/firehose/README.md
+++ b/pkgs/firehose/README.md
@@ -258,4 +258,14 @@
 or configure it further, for example
 ```
 dart pub global run firehose:health --check unused-dependencies,license --comment test.md
-```
\ No newline at end of file
+```
+
+## Zizmor compatibility
+
+The `post_summaries` workflow uses a `workflow_run` trigger which is
+flagged by zizmor as a risk (`dangerous-triggers`). The risk in this case is
+mitigated by not using `actions/checkout` to bring in code from the PR branch,
+and by strictly validating the target PR and comment IDs before acting on them.
+The elevated `pull-requests: write` permission is used to allow posting the
+results of PR health checks and publishing validations as a comment on the PR.
+Use a `# zizmor: ignore[dangerous-triggers]` comment to ignore.