feat(workflows): add closed-PR comment redirect#1328
Conversation
Add closed-pr-comment.yml: detects comments on closed PRs by non-maintainers, posts a redirect to the issue tracker, and pages oncall via the existing SLACK_WEBHOOK_URL. Update slack-issue-notification.yml: switch to injection-safe env+toJSON pattern and emit a uniform 20-key payload (with event_type discriminator) so the Slack workflow can branch on event type. COE AI-7: an external user reported the SDK SPII OTEL leak by commenting on a closed revert PR; oncall does not monitor closed-PR comments, so the report was missed for ~20 hours.
Package TarballHow to installgh release download pr-1328-tarball --repo aws/agentcore-cli --pattern "*.tgz" --dir /tmp/pr-tarball
npm install -g /tmp/pr-tarball/aws-agentcore-0.14.1.tgz |
agentcore-cli-automation
left a comment
There was a problem hiding this comment.
Two correctness concerns around the dedup logic and oncall paging volume — see inline comments. The env/toJSON hardening on the existing notification workflow looks good.
| script: | | ||
| // PRs surface as `issue` events; merged_at is null when closed-not-merged. | ||
| const mergedAt = context.payload.issue.pull_request && | ||
| context.payload.issue.pull_request.merged_at; |
There was a problem hiding this comment.
Slack notification is not deduped per PR/commenter, so oncall will be paged on every external comment.
The Post redirect comment step is gated by steps.existing.outputs.already_posted != 'true' (correct — we don't want to spam the PR with redirect replies), but Notify Slack is gated only on steps.perm.outputs.skip != 'true'. The result is:
- A back-and-forth thread from one external user on a closed PR pages oncall on every comment.
- A single user spamming a closed PR with N comments produces N pages.
- Once the redirect comment has been posted, subsequent comments still page (despite the redirect having explicitly told them to open an issue).
Given this workflow exists specifically to close a detection gap, some over-paging is probably acceptable, but unbounded paging from a single thread is not. Options:
- Also gate
Notify Slackonsteps.existing.outputs.already_posted != 'true'— pages once per (PR, external commenter) cohort, but risks missing genuinely new info posted after the redirect. - Keep the current behavior on the GitHub side and dedup on the Slack workflow side (e.g., suppress alerts where
comment_authoralready alerted on the samepr_numberwithin N hours). This is mentioned as a side-channel change, so the hook is already there. - Track per-commenter dedup with a second marker comment scoped to the commenter login (similar to how
existingworks, but keyed oncomment.user.login).
Whichever you pick, please document the chosen behavior in the comment block above this step — right now the comment says "Slack alert is the load-bearing part" but doesn't address repeat-comment volume.
| issues: read | ||
|
|
||
| jobs: | ||
| redirect: |
There was a problem hiding this comment.
Missing concurrency control makes the marker-comment dedup racy.
The Check for existing redirect comment step relies on a marker (<!-- closed-pr-comment-redirect -->) being present in a previously posted comment. If two external comments arrive within the time it takes for the first workflow run to post its redirect (a few seconds), both runs will see no marker and both will post a redirect comment — defeating the dedup.
This is a realistic scenario: someone posts two follow-up comments back-to-back, or two different external users comment around the same time.
Suggest adding a per-PR concurrency group at the workflow or job level, e.g.:
concurrency:
group: closed-pr-comment-${{ github.event.issue.number }}
cancel-in-progress: falseThis serializes runs for the same PR so the marker check is reliable. cancel-in-progress: false is important here — we still want the second run to execute (to page Slack for the second comment), just after the first has finished posting its marker.
| PR_CLOSED_AT: ${{ github.event.issue.closed_at }} | ||
| PR_MERGED_AT: ${{ github.event.issue.pull_request.merged_at }} | ||
| COMMENT_ID: ${{ github.event.comment.id }} | ||
| COMMENT_URL: ${{ github.event.comment.html_url }} |
There was a problem hiding this comment.
pr_state env var will be empty in the payload because of step ordering / env: evaluation.
The env: block on this step references ${{ steps.pr_state.outputs.state }}, which is fine — that step runs before this one. But please double-check by running the workflow once: in some env: evaluation paths, steps.<id>.outputs.<x> is only available within with:/run: and not in step-level env:. If it does come through empty, the fix is either:
- Inline the expression directly in the payload:
pr_state: "${{ steps.pr_state.outputs.state }}"(safe — values aremerged/closed, not user input). - Promote
pr_stateto a job-level output and reference it vianeeds/jobs(overkill for a single job).
Not a blocker if you've verified it works end-to-end on a test repo, but worth confirming since the manual test plan is post-merge.
|
Claude Security Review: no high-confidence findings. (run) |
Coverage Report
|
- Gate Slack notification on already_posted so oncall is paged only on the first external comment per PR. Subsequent comments don't page — the redirect comment has already directed the commenter to issues. - Add per-PR concurrency group so the marker-comment dedup is race-free (cancel-in-progress: false to ensure later runs still execute against the just-posted marker). - Inline steps.pr_state.outputs.state in the Slack payload directly rather than routing it through env: to avoid step-level evaluation ambiguity. The value is enum-typed (merged|closed) so injection-safe.
|
Claude Security Review: no high-confidence findings. (run) |
agentcore-cli-automation
left a comment
There was a problem hiding this comment.
Reviewed the latest revision (57a2506). All three concerns from the prior automated review (Slack paging volume, marker-comment race, pr_state step-output evaluation) have been addressed in this commit:
Notify Slackis now gated onsteps.existing.outputs.already_posted != 'true', so paging is bounded to the first external comment per PR.- A workflow-level
concurrencygroup keyed ongithub.event.issue.numberwithcancel-in-progress: falsemakes the marker-comment dedup race-free. pr_stateis inlined directly in the Slack payload ("${{ steps.pr_state.outputs.state }}"), avoiding any step-levelenv:evaluation ambiguity. The value is enum-typed (merged|closed), so injection-safe.
No new blocking issues found. Schemas in both workflows match (20 keys, event_type discriminator), attacker-controlled fields (*_TITLE, *_BODY) route through env: + toJSON(), the job-level if correctly filters to closed PRs and excludes bot comments (so the bot's own redirect reply won't recurse), and the permission-lookup catch defaults to "non-maintainer" which is the right safe default.
Looks good to merge.
Description
Add a workflow that responds to comments on closed PRs by external users — posts a redirect asking them to open a new issue, and pages oncall via Slack so closed-PR comments are not missed.
Also hardens the existing
slack-issue-notification.ymlto use injection-safeenv:+toJSON()and emits a uniform 20-key payload (withevent_typediscriminator) so the Slack workflow can branch on event type.Why: COE AI-7 (Bedrock AgentCore SDK SPII OTEL leak). An external user reported the v1.4.8 SPII leak by commenting on a closed revert PR; oncall does not monitor closed-PR comments, so the report was missed for ~20 hours. This closes that detection gap.
Quip: https://quip-amazon.com/SmCwABMBwzgH
Related Issue
Documentation PR
N/A (workflow-only change, no user-facing docs)
Type of Change
Testing
How have you tested the change?
Workflow-only change — no app-code tests apply. Manual test plan once merged:
Checklist
Slack-side change (out of band)
The shared Slack workflow `GitHub Issue Response - Moab` was updated separately to:
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.