feat: route-issue reusable workflow + template (public dispatch leg)#57
Conversation
Public dispatch leg for org-wide issue auto-routing. A thin caller in any participating repo forwards issues:[field_added,field_removed] events to the reusable workflow, which mints the low-priv OPS_DISPATCH app token and sends a repository_dispatch to the private geolonia-operations repo. No project IDs, routing logic, or privileged credentials live here. Mirrors the reusable-sync-team-access.yml dispatch-to-central pattern. Refs #56
|
Important Review skippedThis PR was authored by the user configured for CodeRabbit reviews. CodeRabbit does not review PRs authored by this user. It's recommended to use a dedicated user account to post CodeRabbit review feedback. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
WalkthroughAdds a reusable GitHub Actions workflow that mints a low-privilege app token and repository_dispatches issue field events to a central operations repo, plus a one-click workflow template, properties, and documentation with prerequisites and troubleshooting. ChangesIssue routing via dispatch
Sequence Diagram(s)sequenceDiagram
participant ParticipatingRepo as Participating Repo
participant ReusableWorkflow as Reusable Workflow
participant AppToken as actions/create-github-app-token
participant OperationsRepo as geolonia-operations
ParticipatingRepo->>ReusableWorkflow: Call with issue event
ReusableWorkflow->>AppToken: Generate low-privilege token
AppToken-->>ReusableWorkflow: App token
ReusableWorkflow->>OperationsRepo: repository_dispatch (issue context)
OperationsRepo-->>ReusableWorkflow: dispatch accepted
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related issues
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
Secret Leak CheckOK No secrets detected in this PR's diff. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/reusable-route-issue.yml:
- Around line 65-72: The GitHub App token created by the "Generate dispatch
token" step (id: app_token, uses: actions/create-github-app-token) currently
inherits full installation permissions; restrict it by adding permission inputs
so it only has Metadata: read and Contents: read/write — i.e., add
permission-metadata: read and permission-contents: write to the step inputs to
minimize token scope for the repos/{owner}/{repo}/dispatches call.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 0fd47d3a-4913-4d3f-a171-e03b2fe16d20
📒 Files selected for processing (6)
.github/workflows/reusable-route-issue.ymldocs/workflows.mddocs/workflows/route-issue.mdmkdocs.ymlworkflow-templates/route-issue.properties.jsonworkflow-templates/route-issue.yml
Per-repo opt-in: when a repo sets remove_on_field_removed: true, a cleared Department field also removes the issue from its board. Default false (keep on board). The flag is forwarded in the dispatch payload; the central receiver in geolonia-operations performs the removal. Refs #56
Secret Leak CheckOK No secrets detected in this PR's diff. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/workflows/route-issue.md`:
- Around line 47-50: The sentence "A configured master board is never removed
from" is unclear to public readers; either replace it with a brief definition of
"configured master board" (e.g., "a board designated in routing settings as the
authoritative source for items, set in the private geolonia-operations repo") or
remove the sentence if it's an internal implementation detail. Update the
sentence near the line that currently reads "A configured master board is never
removed from" to include the short definition or delete it so the doc only
describes observable user behavior (that moving between Department options
triggers field_added on the new board but not field_removed on the old).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 3981e5ca-2083-4116-8449-ccb27fa2d7c9
📒 Files selected for processing (3)
.github/workflows/reusable-route-issue.ymldocs/workflows/route-issue.mdworkflow-templates/route-issue.yml
Default behavior is now: an issue lives on only the board for its current Department. Changing the department removes the issue from the other department boards; clearing it removes from all of them. This fixes accidental double-add when a mis-set department is corrected (field_added on update no longer leaves the stale board item behind). Renames the per-repo input remove_on_field_removed -> exclusive_routing (default true; set false for additive routing). Only department boards listed in routing.yml are ever touched -- never a master board or unrelated project. Refs #56
Secret Leak CheckOK No secrets detected in this PR's diff. |
No master/all-work board exists or is planned. Reword the exclusive_routing docs to say only department boards are ever removed from (any other project is left alone), without referencing a master board. Refs #56
Secret Leak CheckOK No secrets detected in this PR's diff. |
repository_dispatch needs only Metadata: read + Contents: write, so request exactly those on the minted token instead of inheriting the OPS_DISPATCH app's full installation permissions. Refs #56
|
@coderabbitai review Addressed the dispatch-token least-privilege finding (now requests |
Secret Leak CheckOK No secrets detected in this PR's diff. |
🧩 Analysis chain🏁 Script executed: #!/bin/bash
echo "=== .github/workflows/reusable-route-issue.yml ==="
cat .github/workflows/reusable-route-issue.yml
echo ""
echo "=== workflow-templates/route-issue.yml ==="
cat workflow-templates/route-issue.yml
echo ""
echo "=== workflow-templates/route-issue.properties.json ==="
cat workflow-templates/route-issue.properties.json
echo ""
echo "=== docs/workflows/route-issue.md ==="
cat docs/workflows/route-issue.md
echo ""
echo "=== docs/workflows.md (tail) ==="
tail -30 docs/workflows.md
echo ""
echo "=== mkdocs.yml (relevant section) ==="
cat mkdocs.ymlLength of output: 13355 🏁 Script executed: #!/bin/bash
# Check the create-github-app-token action's action.yml to see if permission-* inputs are declared
gh api \
"repos/actions/create-github-app-token/contents/action.yml?ref=bcd2ba49218906704ab6c1aa796996da409d3eb1" \
--jq '.content' | base64 -d | grep -A2 'permission'Length of output: 10646
One real bug remains before merge: 🐛
|
| Item | Status |
|---|---|
permission-metadata: read + permission-contents: write supported at pinned SHA bcd2ba49 |
✅ |
Token scoped to operations_repo only (repositories: input) |
✅ |
--argjson exclusive for boolean |
✅ |
set -euo pipefail + ISSUE_NODE_ID guard |
✅ |
| No master board references in docs | ✅ |
mkdocs.yml nav + docs/workflows.md table entry |
✅ |
workflow-templates template properties |
✅ |
✅ Action performed
Review finished.
Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.github/workflows/reusable-route-issue.yml (1)
108-126:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winUse
--argjsonforissue_numberto emit an integer instead of a string.Line 111 uses
--arg number, which serializesissue_numberas a JSON string ("123") rather than an integer (123). The receiver ingeolonia-operationsmay expect the native integer type. Note thatexclusive_routingon line 115 already uses--argjsoncorrectly for the same reason.Proposed fix
REQUEST_BODY=$(jq -n \ --arg event_type "$EVENT_TYPE" \ --arg repo "$SOURCE_REPO" \ - --arg number "$ISSUE_NUMBER" \ + --argjson number "$ISSUE_NUMBER" \ --arg node_id "$ISSUE_NODE_ID" \ --arg url "$ISSUE_URL" \ --arg action "$ACTION" \ --argjson exclusive "$EXCLUSIVE_ROUTING" \🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.github/workflows/reusable-route-issue.yml around lines 108 - 126, The REQUEST_BODY construction currently uses --arg number "$ISSUE_NUMBER" which makes issue_number a JSON string; change that to --argjson number "$ISSUE_NUMBER" so the issue_number field is emitted as a native integer. Update the jq arg for issue_number in the REQUEST_BODY block (the --arg/---argjson invocations around event_type, repo, number, node_id, url, action, exclusive) to use --argjson for number (and only number) while leaving other --arg calls unchanged so issue_number becomes an integer in the produced JSON.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In @.github/workflows/reusable-route-issue.yml:
- Around line 108-126: The REQUEST_BODY construction currently uses --arg number
"$ISSUE_NUMBER" which makes issue_number a JSON string; change that to --argjson
number "$ISSUE_NUMBER" so the issue_number field is emitted as a native integer.
Update the jq arg for issue_number in the REQUEST_BODY block (the
--arg/---argjson invocations around event_type, repo, number, node_id, url,
action, exclusive) to use --argjson for number (and only number) while leaving
other --arg calls unchanged so issue_number becomes an integer in the produced
JSON.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: 2d886cda-0e84-4d4d-bad7-b5e11965ea58
📒 Files selected for processing (1)
.github/workflows/reusable-route-issue.yml
Closes #56
What
Public dispatch leg for org-wide issue auto-routing (Phase 1). Lets any
Geolonia repo opt in to having its issues auto-added to a team project board
based on the org
Departmentissue field — without exposing any credential orrouting config publicly.
Files
.github/workflows/reusable-route-issue.yml— reusable workflow: mints thelow-priv
OPS_DISPATCHapp token andrepository_dispatches the issue togeolonia-operations.workflow-templates/route-issue.yml+.properties.json— one-click adoptionin the New workflow picker (thin caller on
issues:[field_added,field_removed]).docs/workflows/route-issue.md+ nav/table entry.Why dispatch-to-central
Mirrors the existing
sync-team-accesspattern — individual repos never seethe org token. This public side is a dumb forwarder: no project IDs, no routing
logic, no privileged token. All of that lives in private
geolonia-operations(see geolonia/geolonia-operations#156, the receiver half).
Notes
OPS_DISPATCH_CLIENT_ID/OPS_DISPATCH_APP_PRIVATE_KEYorg secrets (already wired for
sync-team-access).create-github-app-tokenSHA the repo already uses (pinactclean).@v1— av1tag must exist before consumers adopt it (cut after merge, perrelease-auto-on-tag).Not in this PR
routing.yml, and the "Issue Router" GitHub App live ingeolonia-operations.Summary by CodeRabbit
New Features
Documentation