chore(ci): harden issue triage workflow with least-privilege split#1598
Conversation
decision(architecture): split triage into a read-only classify job and a separate no-AI apply job, so the step that reads issue content holds no write token and no shell access, and the step that writes labels runs fixed code rather than an agent. decision(classify-tools): disable Bash/Edit/Write/MultiEdit/NotebookEdit/WebFetch/WebSearch/Task and return the chosen labels via --json-schema structured output, keeping the agent to read-only file access. decision(apply-labels): validate the model-chosen labels against the real repository label list, cap at 5, and apply via the labels REST endpoint instead of an agent-built command. learned(claude-code-action): passing --json-schema in claude_args exposes the result as steps.<id>.outputs.structured_output, parsed downstream with fromJSON(). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Note Gemini is unable to generate a review for this pull request due to the file types involved not being currently supported. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThis PR refactors the GitHub Actions workflow for Claude-based issue triage to enforce least-privilege permissions and validation. The workflow splits from a single job with broad permissions into two isolated phases: a read-only ChangesLeast-Privilege Triage Architecture
Sequence DiagramssequenceDiagram
participant GH as GitHub
participant Classify as classify job
participant Claude as Claude action
participant REST as REST API
participant ApplyLabels as apply-labels job
GH->>Classify: trigger on issue.opened/edited
Classify->>GH: fetch issue JSON (gh api)
GH-->>Classify: issue title, body, labels
Classify->>GH: fetch repository labels (gh api)
GH-->>Classify: allowlist of valid labels
Classify->>Claude: structured output request<br/>(tools=disallowed)
Claude-->>Classify: JSON [label1, label2, ...]
Classify->>Classify: export labels output
ApplyLabels->>ApplyLabels: filter output by allowlist
ApplyLabels->>ApplyLabels: truncate to 5 labels
ApplyLabels->>REST: POST labels via API<br/>(JSON payload)
REST->>GH: apply labels to issue
Estimated Code Review Effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly Related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
⚡ Performance Benchmark
Details
|
Deploying repomix with
|
| Latest commit: |
8546d3d
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://60211698.repomix.pages.dev |
| Branch Preview URL: | https://fix-issue-triage-prompt-inje.repomix.pages.dev |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1598 +/- ##
=======================================
Coverage 90.86% 90.86%
=======================================
Files 121 121
Lines 4683 4683
Branches 1088 1088
=======================================
Hits 4255 4255
Misses 428 428 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Claude ReviewStrong hardening overall — the split cleanly removes the prompt-injection → write-token escalation path. The classify job has no write token and no execution/network tools, and apply-labels is deterministic shell that re-validates the model output against the authoritative label list. A few items worth considering before merge. Worth addressing1. --allowedTools "Read"(plus whatever explicit MCP-disable flag the action supports, if any). 2. Same prompt-injection pattern exists in MinorDetails
Nits (no change needed)
|
Summary
Refactor the Claude issue triage workflow to follow least-privilege and reduce the blast radius of the automated agent.
classify(read-only, no write token, no shell/network tools): decides labels and returns them via--json-schemastructured output.apply-labels(no AI): validates the chosen labels against the repository's real label list and applies them via the labels REST endpoint.Checklist
npm run testnpm run lint