Skip to content

feat: make reviewer-to-assignee bot dynamic with removal support#2391

Draft
Mounil2005 wants to merge 10 commits into
hiero-ledger:mainfrom
Mounil2005:bot/dynamic-reviewer-assignees
Draft

feat: make reviewer-to-assignee bot dynamic with removal support#2391
Mounil2005 wants to merge 10 commits into
hiero-ledger:mainfrom
Mounil2005:bot/dynamic-reviewer-assignees

Conversation

@Mounil2005

Copy link
Copy Markdown
Contributor

Description:

Make the reviewer-to-assignee bot dynamic: reviewers are added when requested and removed when they submit their review, with no artificial cap on assignee count.

  • Add pull_request_review: submitted trigger to on-review.yml
  • Update concurrency group to resolve PR number from both event payloads
  • Split bot into addReviewersAsAssignees and removeReviewerFromAssignees, routing by eventName + action
  • Remove MAX_ASSIGNEES=2 cap — all requested reviewers are now assigned
  • Remove logAssigneeCapWarning and maxNewAssignees cap logic
  • Mirror existing 403 guard on the removal path
  • Add removeAssignees mock to test helpers
  • Drop cap assertion; add removal flow tests (happy path, non-assignee no-op, 403, rethrow)
  • Add workflow_dispatch routing test confirming it targets the add flow only

Related issue(s):

Fixes #2349

Notes for reviewer:

The removal fires on any review state (approved, changes_requested, commented) — any submission signals the reviewer has completed their work.

Checklist

[x] Documented (Code comments, README, etc.)
[x]Tested (unit, integration, etc.)

@github-actions github-actions Bot added approved Issue has been approved by team member skill: beginner Achievable by a fairly new comer that has already completed a couple of good first issues labels Jun 28, 2026
@Mounil2005
Mounil2005 marked this pull request as ready for review June 28, 2026 12:41
@Mounil2005
Mounil2005 requested review from a team as code owners June 28, 2026 12:41
@coderabbitai

coderabbitai Bot commented Jun 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

The bot now adds all requested individual reviewers as assignees, removes reviewers after submitted reviews, and uses review artifacts to connect the capture and removal workflows. Tests cover routing, no-op cases, uncapped additions, and permission errors.

Changes

Reviewer-as-Assignee Bot: Add/Remove Flow

Layer / File(s) Summary
Workflow trigger and review artifact routing
.github/workflows/capture-pr-review.yml, .github/workflows/on-review.yml
Captures submitted review metadata, uploads it as a short-retention artifact, triggers removal after successful workflow completion, restricts add execution, and checks out the pull request base revision when available.
Script: uncapped add/remove flows and routing
.github/scripts/bot-pr-add-reviewers-as-assignees.js, .github/scripts/shared/helpers/constants.js, .github/scripts/shared/helpers/reviewers-assignee-index.js
Removes MAX_ASSIGNEES, adds all requested individual reviewers, removes submitted reviewers when currently assigned, and routes supported events to the matching flow.
Tests: add/remove flows and error handling
.github/scripts/__tests__/jest/bot-pr-add-reviewers-as-assignees.test.js
Covers uncapped additions, event routing, removal and no-op cases, removal calls, and 403/non-403 error behavior.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant PullRequestReview
  participant CapturePRReview
  participant OnReviewWorkflow
  participant ReviewerAssigneeBot
  participant GitHubREST
  PullRequestReview->>CapturePRReview: submitted review event
  CapturePRReview->>OnReviewWorkflow: upload reviewer and PR metadata
  OnReviewWorkflow->>ReviewerAssigneeBot: invoke removal flow
  ReviewerAssigneeBot->>GitHubREST: fetch live pull request state
  ReviewerAssigneeBot->>GitHubREST: remove assigned reviewer
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the main change: dynamic reviewer-to-assignee behavior with removal support.
Description check ✅ Passed The description accurately describes the add/remove flow, cap removal, and test updates in the changeset.
Linked Issues check ✅ Passed The changes satisfy #2349 by adding reviewers without a cap and removing reviewers after they submit a review.
Out of Scope Changes check ✅ Passed The added workflows, helpers, and tests all support the dynamic assignee flow and fork-safety goals.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
📋 Issue Planner

Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).

View plan for ticket: #2349

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2f7400ed-ff5b-474b-b35b-7c101d490c33

📥 Commits

Reviewing files that changed from the base of the PR and between 891808a and d20d374.

📒 Files selected for processing (3)
  • .github/scripts/__tests__/jest/bot-pr-add-reviewers-as-assignees.test.js
  • .github/scripts/bot-pr-add-reviewers-as-assignees.js
  • .github/workflows/on-review.yml

Comment thread .github/scripts/bot-pr-add-reviewers-as-assignees.js Outdated
Comment thread .github/workflows/on-review.yml Outdated
@github-actions github-actions Bot added open to community review PR is open for community review and feedback queue:junior-committer PR awaiting initial quality review labels Jun 28, 2026
@manishdait

Copy link
Copy Markdown
Contributor

@Mounil2005, thanks for the PR! The overall changes look good. Could you also add a link to your testing on your fork for these changes?

@aceppaluni aceppaluni added status: update branch developer needs to click update branch status: Needs Developer Revision Author needs to apply suggested changes/improvements and removed approved Issue has been approved by team member labels Jun 29, 2026
@hiero-ledger hiero-ledger deleted a comment from github-actions Bot Jun 29, 2026
@github-actions github-actions Bot added the approved Issue has been approved by team member label Jun 29, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/on-review.yml (1)

7-9: 🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Don't execute checked-out PR code on the new pull_request_review path.

Adding this trigger makes the later actions/checkout + local require('./.github/scripts/bot-pr-add-reviewers-as-assignees.js') run against the PR’s checked-out contents on review submissions. For forked PRs, that lets untrusted contributors influence the JS this workflow executes, which violates the fork-safety requirement.

Suggested fix
       - name: Checkout repository
         uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
         with:
+          ref: ${{ github.event_name == 'pull_request_review' && github.event.pull_request.base.sha || github.sha }}
           persist-credentials: false

As per path instructions, workflows must behave safely when executed from forks.

Source: Path instructions


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 58dfad66-38da-4641-97d3-2ef5995ee9e8

📥 Commits

Reviewing files that changed from the base of the PR and between d9970b6 and 97e2dd2.

📒 Files selected for processing (1)
  • .github/workflows/on-review.yml

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown

Hello, this is the OfficeHourBot.

This is a reminder that the Hiero Python SDK Office Hours will begin in approximately 2 hours and 57 minutes (14:00 UTC).

This session provides an opportunity to ask questions regarding this Pull Request.

Details:

Disclaimer: This is an automated reminder. Please verify the schedule here for any changes.

From,
The Python SDK Team

@Mounil2005

Copy link
Copy Markdown
Contributor Author

@Mounil2005, thanks for the PR! The overall changes look good. Could you also add a link to your testing on your fork for these changes?

Mounil2005#41

Link to the testing! Sorry for the delay!

@Mounil2005

Copy link
Copy Markdown
Contributor Author

Once everything looks good, pls do let me know, i will then reset my main and rebase

@Mounil2005

Copy link
Copy Markdown
Contributor Author

@manishdait @aceppaluni @exploreriii Can you pls review this and let me know if this is alright?
After that i will revert some changes on my fork and then rebase it for merge!
Thank you

@aceppaluni aceppaluni left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it intentional that a reviewer who leaves only a comment (without approving or requesting changes) is considered "done"?

@aceppaluni aceppaluni removed the approved Issue has been approved by team member label Jul 6, 2026
@Mounil2005

Copy link
Copy Markdown
Contributor Author

Is it intentional that a reviewer who leaves only a comment (without approving or requesting changes) is considered "done"?

Yes, intentional. The rationale is that any review submission whether approval, changes requested, or comment signals the reviewer has actively engaged with the PR. The assignee field is used to track who still needs to act; once they've submitted any review, the ball is back in the author's court regardless of the review type.

@exploreriii exploreriii left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Mounil2005
Most of the code looks pretty good but have another check through the logic of the permissions

Comment thread .github/workflows/on-review.yml Outdated
Comment thread .github/scripts/bot-pr-add-reviewers-as-assignees.js Outdated
Comment thread .github/scripts/bot-pr-add-reviewers-as-assignees.js
Comment thread .github/workflows/on-review.yml Outdated
Comment thread .github/workflows/on-review.yml
@exploreriii
exploreriii marked this pull request as draft July 10, 2026 08:51
@exploreriii exploreriii removed the status: update branch developer needs to click update branch label Jul 10, 2026
@Mounil2005

Mounil2005 commented Jul 11, 2026

Copy link
Copy Markdown
Contributor Author

@exploreriii Thanks for the review! Addressing the permissions concerns:

  1. pull_request_review token scope for fork PRs : pull_request_review events always run the workflow from the base repository (not the fork), so the GITHUB_TOKEN retains the write permissions declared in the workflow (pull-requests: write, issues: write) regardless of whether the PR originates from a fork. The removal call should succeed. A 403 guard is in place as a defensive fallback in case this ever behaves unexpectedly in an edge case.

  2. Fork code execution (checkout safety) : CodeRabbit separately flagged that for pull_request_review, github.sha resolves to the PR head (the fork's branch), meaning actions/checkout with defaults would pull untrusted code and require() would execute the fork's copy of the script. Fixed in the latest commit (3ff5678) by explicitly pinning the checkout ref:

    ref: ${{ github.event.pull_request.base.sha || github.sha }}

    This ensures the workflow always executes the base-branch script, not the contributor's.

The end-to-end add + remove flow was verified on a fork PR here: Mounil2005#41

@exploreriii

Copy link
Copy Markdown
Contributor

Note the real test will have to be a fork of a given repository, creating a pull request to your repository. So if the repo is called alice.python, the pr will need to be made from alice.python.fork.
A fork of python sdk, with a pull request to itself is thus not testing a fork of python sdk trying to merge to python sdk
This way we can verify if this is accurate " The GITHUB_TOKEN has read-only permissions in pull requests from forked repositories. " https://docs.github.com/en/actions/reference/workflows-and-actions/events-that-trigger-workflows#pull_request_review

Comment thread .github/workflows/on-review.yml Fixed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: af8779b2-0c78-4cbf-b7da-2adee557ad51

📥 Commits

Reviewing files that changed from the base of the PR and between 3ff5678 and 41df037.

📒 Files selected for processing (4)
  • .github/scripts/__tests__/jest/bot-pr-add-reviewers-as-assignees.test.js
  • .github/scripts/bot-pr-add-reviewers-as-assignees.js
  • .github/workflows/capture-pr-review.yml
  • .github/workflows/on-review.yml

Comment thread .github/workflows/capture-pr-review.yml Outdated
Comment thread .github/workflows/capture-pr-review.yml Outdated
Comment thread .github/workflows/on-review.yml Outdated
Comment thread .github/workflows/on-review.yml Fixed
@Mounil2005
Mounil2005 marked this pull request as draft July 12, 2026 06:19
@Mounil2005
Mounil2005 marked this pull request as ready for review July 12, 2026 08:06
@Mounil2005
Mounil2005 force-pushed the bot/dynamic-reviewer-assignees branch from 9c1ad79 to 1de64a6 Compare July 12, 2026 08:13
@aceppaluni
aceppaluni requested a review from manishdait July 13, 2026 16:36
Comment thread .github/workflows/on-review.yml Outdated
Comment thread .github/workflows/on-review.yml
Comment thread .github/workflows/on-review.yml Fixed
@aceppaluni aceppaluni added the status: update branch developer needs to click update branch label Jul 13, 2026
@hiero-ledger hiero-ledger deleted a comment from github-actions Bot Jul 13, 2026
@manishdait

Copy link
Copy Markdown
Contributor

@Mounil2005 can you please update the branch

@Mounil2005
Mounil2005 force-pushed the bot/dynamic-reviewer-assignees branch from 3d4dc5e to dbe0e46 Compare July 14, 2026 11:35
@aceppaluni aceppaluni removed the approved Issue has been approved by team member label Jul 14, 2026
- Add pull_request_review: submitted trigger to on-review.yml so the
  workflow fires when a reviewer submits their feedback
- Split the bot into addReviewersAsAssignees / removeReviewerFromAssignees
  functions, routing by eventName + action
- Remove the MAX_ASSIGNEES=2 cap so all requested reviewers are assigned
- Mirror the existing 403 guard on the new removal path
- Update tests: drop the cap assertion, add removal flow coverage (happy
  path, no-op, 403, rethrow) and workflow_dispatch routing check

Signed-off-by: Mounil Kanakhara <mounilkankhara@gmail.com>
…iewer

- In removeReviewerFromAssignees, replace the stale event-payload
  assignee snapshot with a live pulls.get call so a concurrent
  review_requested run that adds the assignee after the event fires
  does not cause the reviewer to remain assigned permanently
- Give pull_request_review runs a reviewer-scoped concurrency key
  (reviewer-removal-{PR}-{login}) so concurrent review submissions
  from different reviewers are not cancelled by each other
- Update removal-flow tests to populate state.currentPrData.assignees
  so the mock pulls.get returns the correct live assignee list; fix
  error-path mocks to return { data: { assignees: [...] } }

Signed-off-by: Mounil Kanakhara <mounilkankhara@gmail.com>
Give pull_request_review runs a per-reviewer concurrency slot
(reviewer-removal-{PR}-{login}) so simultaneous review submissions
from multiple reviewers are not cancelled by each other.

Signed-off-by: Mounil Kanakhara <mounilkankhara@gmail.com>
- Remove MAX_ASSIGNEES from constants.js and reviewers-assignee-index.js;
  it was dead code since nothing reads it after the cap was removed
- Unify the concurrency group to reviewer-assignee-{PR} for all event
  types so an add and remove for the same PR cannot race
- Skip the job entirely when the actor is a bot (contains '[bot]') to
  avoid triggering on dependabot or other automated review requests

Signed-off-by: Mounil Kanakhara <mounilkankhara@gmail.com>
For pull_request_review events github.sha resolves to the PR head
commit (i.e. the fork's branch), so the default actions/checkout
would pull untrusted contributor code and the subsequent require()
call would execute the fork's copy of the bot script.

Explicitly set ref to github.event.pull_request.base.sha so the
checkout always lands on the verified base-branch code. Falls back
to github.sha for workflow_dispatch where pull_request is absent.

Signed-off-by: Mounil Kanakhara <mounilkankhara@gmail.com>
pull_request_review events receive a read-only GITHUB_TOKEN for PRs
from forked repositories, so removeAssignees would silently 403 for
every real contribution. The workflow_run pattern is the standard
GitHub-recommended fix: a lightweight capture workflow fires on
pull_request_review (read-only token is sufficient — it only writes
an artifact), and the main workflow's workflow_run job picks it up
with a full write token regardless of fork status.

Changes:
- Add capture-pr-review.yml: triggered by pull_request_review, writes
  reviewer login and PR number to a JSON artifact, uploads with a 1-day
  retention so workflow_run can consume it
- on-review.yml: remove pull_request_review trigger; add workflow_run
  trigger and a new remove-reviewer-from-assignees job that downloads
  the artifact, checks out base-branch code, and calls the named export
  directly; add actions: read permission for artifact download;
  tighten add job if-condition to exclude workflow_run events
- bot-pr-add-reviewers-as-assignees.js: accept optional explicit
  reviewer/prNumber params in removeReviewerFromAssignees so it can be
  called from the workflow_run job without a pull_request_review context;
  export the function as a named export; drop pull_request_review routing
  from the entry point (now dead code)
- Tests: call removeReviewerFromAssignees via named export with explicit
  params matching the new production path; add missing/invalid param
  guard tests; add routing test for the now-unhandled pull_request_review
  event

Signed-off-by: Mounil Kanakhara <mounilkankhara@gmail.com>
CodeQL flagged the download-artifact + require() pattern as artifact
poisoning: data written by an external user in the capture workflow
flows into a write-token context without validation. Validate reviewer
login against the GitHub login charset (alphanumeric and hyphens) and
confirm pr_number is a positive integer before passing either value to
the removal function. Fails the step with a clear message if contents
are unexpected.

Signed-off-by: Mounil Kanakhara <mounilkankhara@gmail.com>
…ror with explicit pre-check

- capture-pr-review.yml: validate reviewer login and PR number before
  writing the artifact; throw with a clear message if the payload is
  malformed so the capture job fails visibly instead of publishing a
  bad artifact downstream
- on-review.yml: remove continue-on-error on the download step;
  add an explicit artifact pre-check step that lists artifacts for the
  triggering run and sets an output; all subsequent steps gate on that
  output so a missing artifact (bot actor skip) is logged as a notice
  and the job exits cleanly, while an unexpected download failure now
  surfaces as a proper job failure

Signed-off-by: Mounil Kanakhara <mounilkankhara@gmail.com>
Signed-off-by: Mounil Kanakhara <mounilkankhara@gmail.com>
…ts on remove job

- Move checkout before artifact download so project files are
  established in the workspace before any untrusted artifact data
  lands, preventing potential file overwrites
- Add path: artifact to download-artifact so the JSON file is scoped
  to a subdirectory instead of the workspace root; update readFileSync
  path accordingly
- Add bot-skip condition to the remove job using
  workflow_run.triggering_actor.login so the job exits early for bot
  actors even if an artifact somehow exists

Signed-off-by: Mounil Kanakhara <mounilkankhara@gmail.com>
@Mounil2005
Mounil2005 force-pushed the bot/dynamic-reviewer-assignees branch from dbe0e46 to 0b0d4af Compare July 15, 2026 20:54
@github-actions github-actions Bot added the approved Issue has been approved by team member label Jul 15, 2026

@exploreriii exploreriii left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @Mounil2005
Thanks for splitting this up, I think its quite safe now and should work.

Only small suggestions which I would like to hold you to as this one is an important workflow

await script({ github, context });

remove-reviewer-from-assignees:
name: Remove Reviewer from Assignees

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can give this workflow its own set of permissions so it doesn't inherit any top level ones, in case they change

contents: read
pull-requests: write
issues: write
actions: read

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think only the remove-reviewer requires actions read, so you can remove it here

const reviewer = explicitReviewer ?? context.payload?.review?.user?.login;
const prNumber = explicitPrNumber ?? context.payload?.pull_request?.number;

if (!reviewer || !Number.isInteger(prNumber) || prNumber <= 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can tighten this up to check it is a string and in the regex pattern matching github logins
i.e. at the top add
const VALID_LOGIN_REGEX ..

@@ -5,9 +5,12 @@

describe('Bot: Add Reviewers as Assignees', () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

now that you'd have a regex parse for the reviewer, you can test it will skip an invalid github name for the reviewer

@exploreriii
exploreriii marked this pull request as draft July 18, 2026 13:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Issue has been approved by team member open to community review PR is open for community review and feedback queue:junior-committer PR awaiting initial quality review skill: beginner Achievable by a fairly new comer that has already completed a couple of good first issues status: update branch developer needs to click update branch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dynamic add/remove to the assign review flow

7 participants