Mirror: feat: Add auto-triage GitHub Action for issues and PRs (#5050)#26
Mirror: feat: Add auto-triage GitHub Action for issues and PRs (#5050)#26jeremylongshore merged 1 commit intomainfrom
Conversation
Summary of ChangesHello @jeremylongshore, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! The primary purpose of this mirrored pull request is to integrate an auto-triage GitHub Action for issues and PRs, as indicated by the title. However, the actual file changes provided in the patch are limited to the addition of several '.beads' local state and configuration files. These files seem to capture the state of a local development environment or tool, including version information, process IDs, and synchronization status. The impact of the stated feature would be improved repository management, while the impact of the actual changes is the introduction of these local development artifacts. Highlights
Changelog
Ignored Files
Activity
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
📝 WalkthroughWalkthroughThis pull request adds configuration and state files to the Changes
Sequence DiagramsequenceDiagram
participant GitHub as GitHub<br/>(Webhook)
participant Runner as Workflow<br/>Runner
participant Node as Node.js<br/>Environment
participant Kilocode as Kilocode<br/>CLI
participant Labels as Issue/PR<br/>Labels
GitHub->>Runner: Trigger on issue/PR opened
Runner->>Runner: Checkout code
Runner->>Node: Setup Node.js 20
Node-->>Runner: Node.js ready
Runner->>Kilocode: Install kilocode CLI
Kilocode-->>Runner: CLI installed
Runner->>Runner: Build environment from event data<br/>(type, number, title, body)
Runner->>Kilocode: Execute auto-triage template<br/>with event details
Kilocode->>Kilocode: Analyze event and determine<br/>appropriate labels
Kilocode->>Labels: Apply labels<br/>(component, type, platform, etc.)
Labels-->>GitHub: Labels updated
Estimated code review effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 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 |
Review Summary by QodoAdd auto-triage GitHub Action for issues and pull requests
WalkthroughsDescription• Adds auto-triage GitHub Action workflow for issues and PRs • Uses Kilo Code CLI to automatically label issues and pull requests • Integrates with Kilo Code API for intelligent triage classification • Skips bot-created issues and PRs to avoid redundant processing Diagramflowchart LR
A["GitHub Issue/PR Opened"] -->|Triggers Workflow| B["Auto Triage Action"]
B -->|Checks Event Type| C["Skip if Bot Created"]
C -->|Setup Environment| D["Install Kilo Code CLI"]
D -->|Extract Metadata| E["Issue/PR Details"]
E -->|Send to Kilo Code| F["AI Classification"]
F -->|Generate Labels| G["Apply Labels via gh CLI"]
File Changes1. .github/workflows/auto-triage.yml
|
There was a problem hiding this comment.
Code Review
This pull request introduces files under the .beads/ directory. These files appear to be generated by a local development tool, containing environment-specific data like process IDs and local file paths. Such files should not be committed to the repository as they can cause conflicts for other developers and expose local environment details. It is strongly recommended to add the .beads/ directory to your .gitignore file. Additionally, there is a significant discrepancy between the pull request title, which mentions adding a GitHub Action for auto-triage, and the actual file changes, which are unrelated to this feature.
| { | ||
| "pid": 171809, | ||
| "parent_pid": 171784, | ||
| "database": "/home/jeremy/000-projects/kilo/.beads/beads.db", | ||
| "version": "0.49.1", | ||
| "started_at": "2026-02-14T20:52:39.38617748Z" | ||
| } |
There was a problem hiding this comment.
The files within the .beads/ directory appear to be generated by a local development tool and contain environment-specific information (like process IDs and local paths). These files should not be checked into version control. Please add the .beads/ directory to the project's .gitignore file to prevent them from being committed in the future.
|
Failed to generate code suggestions for PR |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In @.beads/last-touched:
- Line 1: The PR accidentally includes local state under the .beads directory
(e.g., .beads/last-touched and other machine-specific artifacts); remove all
committed .beads files from the PR and add .beads/ to .gitignore so they are
never tracked. Specifically, remove entries like .beads/last-touched, beads.db*,
daemon.pid, daemon.lock, beads.left*.json, issues.jsonl, sync-state.json from
the index/commit (unstage/delete them from the branch) and add a .gitignore line
for ".beads/" (and optionally patterns like ".beads/*.db" and ".beads/*.jsonl")
before committing the fix. Ensure the change shows the files removed from the
commit and the updated .gitignore in a follow-up commit.
In @.github/workflows/auto-triage.yml:
- Around line 46-52: Sanitize ITEM_TITLE the same way ITEM_BODY is sanitized:
create SAFE_TITLE by truncating to 2000 chars, stripping shell metacharacters
and collapsing newlines (same transformations applied to SAFE_BODY) and then use
SAFE_TITLE in the command invocation (the kilocode --auto call that currently
consumes ITEM_TITLE). Update the environment handling where ITEM_TITLE is read
and where the command is constructed so SAFE_TITLE replaces ITEM_TITLE
(mirroring the SAFE_BODY logic) to prevent unmatched quotes/backslashes or
prompt-injection-like content from breaking the run step.
- Around line 3-7: Update the workflow trigger so forked PRs can use repository
secrets by replacing the pull_request event with pull_request_target: change the
event key named "pull_request" to "pull_request_target" (keeping the same types:
[opened]); ensure the rest of the job only uses safe operations (labels via gh
pr edit / gh issue edit and sanitized PR body) and does not execute code from
the PR branch to avoid executing untrusted code while allowing access to
KILOCODE_INTEGRATION_TOKEN and KILOCODE_INTEGRATION_ORGANIZATION_ID.
🧹 Nitpick comments (1)
.github/workflows/auto-triage.yml (1)
30-31: Pin the@kilocode/cliversion to avoid supply-chain risk.Installing without a version pin (
npm install -g@kilocode/cli``) means every workflow run can pull a different version. Pin to a specific version for reproducibility and security. Use@kilocode/cli@0.18.0or the latest version available at the time of implementation.Proposed fix
- name: Install Kilo Code CLI - run: npm install -g `@kilocode/cli` + run: npm install -g `@kilocode/cli`@0.18.0
| @@ -0,0 +1 @@ | |||
| kilo-ko9 | |||
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Explore .beads directory
echo "=== Checking if .beads directory exists ==="
ls -la .beads/ 2>/dev/null || echo ".beads directory not found"
echo ""
echo "=== Listing all files in .beads/ ==="
fd -H '.' .beads/ 2>/dev/null || echo "No .beads directory found"
echo ""
echo "=== Checking .gitignore for .beads ==="
if [ -f .gitignore ]; then
grep -n 'beads' .gitignore || echo ".beads not found in .gitignore"
else
echo "No .gitignore found"
fi
echo ""
echo "=== Full root .gitignore ==="
cat .gitignore 2>/dev/null || echo "No .gitignore found"Repository: jeremylongshore/kilocode
Length of output: 2216
🏁 Script executed:
#!/bin/bash
# Read the contents of each .beads/ file mentioned in the review
echo "=== Contents of .beads/last-touched ==="
cat .beads/last-touched 2>/dev/null || echo "File not found"
echo ""
echo "=== Contents of .beads/beads.left.meta.json ==="
cat .beads/beads.left.meta.json 2>/dev/null || echo "File not found"
echo ""
echo "=== Contents of .beads/.local_version ==="
cat .beads/.local_version 2>/dev/null || echo "File not found"
echo ""
echo "=== Contents of .beads/daemon.pid ==="
cat .beads/daemon.pid 2>/dev/null || echo "File not found"
echo ""
echo "=== Contents of .beads/sync-state.json ==="
cat .beads/sync-state.json 2>/dev/null || echo "File not found"Repository: jeremylongshore/kilocode
Length of output: 666
Remove all .beads/ directory from the PR and add it to .gitignore.
All files in .beads/ are local development and daemon state artifacts that should not be committed. This includes:
- Database files:
beads.db,beads.db-shm,beads.db-wal - State files:
last-touched,daemon.pid,daemon.lock,beads.left.meta.json,.local_version - Tracking files:
issues.jsonl,beads.left.jsonl - Sync state:
sync-state.json(exposes internal failure details:"git pull failed: exit status 1\nfatal: couldn't find remote ref review/PR-5667\n"and timestamps)
These files contain machine-specific data (PIDs like 171809, timestamps, commit hashes, and internal sync errors) that vary per developer and should never be in version control.
🤖 Prompt for AI Agents
In @.beads/last-touched at line 1, The PR accidentally includes local state
under the .beads directory (e.g., .beads/last-touched and other machine-specific
artifacts); remove all committed .beads files from the PR and add .beads/ to
.gitignore so they are never tracked. Specifically, remove entries like
.beads/last-touched, beads.db*, daemon.pid, daemon.lock, beads.left*.json,
issues.jsonl, sync-state.json from the index/commit (unstage/delete them from
the branch) and add a .gitignore line for ".beads/" (and optionally patterns
like ".beads/*.db" and ".beads/*.jsonl") before committing the fix. Ensure the
change shows the files removed from the commit and the updated .gitignore in a
follow-up commit.
| on: | ||
| issues: | ||
| types: [opened] | ||
| pull_request: | ||
| types: [opened] |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
cat -n .github/workflows/auto-triage.ymlRepository: jeremylongshore/kilocode
Length of output: 5847
🌐 Web query:
GitHub Actions pull_request event fork repository secrets unavailable
💡 Result:
For pull_request workflows triggered by a PR from a fork, GitHub intentionally does not expose repository/organization/environment secrets to the runner (to prevent exfiltration by untrusted code in the fork). The only exception is GITHUB_TOKEN, which is read-only for fork PRs. [1]
What you can do instead (depending on your risk tolerance):
- Keep using
pull_requestfor CI that doesn’t need secrets (safe default). Secrets won’t be available. [1] - Use
pull_request_targetif you must access secrets—but it runs in the base repo context and can access secrets, so do not check out / build / run untrusted PR code or you can leak secrets. [1][2] - If this is a private repo, you can change repo/org settings to send secrets (and/or write tokens) to fork PR workflows, optionally requiring approval—this is configurable in GitHub Actions settings. [3]
- Use a two-workflow pattern (e.g.,
pull_requestfor untrusted tests, then a trusted follow-up viaworkflow_runor maintainer-triggered job) so secrets only run after review/approval. (Common mitigation;pull_request_targetis the built-in “trusted context” option but has sharp edges.) [2]
Sources: GitHub Docs on fork PR restrictions and token/secrets behavior [1], GitHub’s security guidance on minimal privileges for fork PRs [2], and GitHub Docs on the private-repo fork policies (“Send secrets to workflows from pull requests”, approvals, etc.) [3].
References: [1] GitHub Docs – Events that trigger workflows (fork PR secrets/token restrictions) (docs.github.com), [2] GitHub Blog – securing Actions / fork PR minimal privileges & risks (github.blog), [3] GitHub Docs – Managing GitHub Actions settings (fork PR policies) (docs.github.com)
Citations:
- 1: https://docs.github.com/actions/learn-github-actions/events-that-trigger-workflows?utm_source=openai
- 2: https://github.blog/security/supply-chain-security/four-tips-to-keep-your-github-actions-workflows-secure/?utm_source=openai
- 3: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository?utm_source=openai
pull_request trigger won't work for fork PRs — secrets are unavailable.
The pull_request event from forked repositories does not have access to repository secrets (KILOCODE_INTEGRATION_TOKEN, KILOCODE_INTEGRATION_ORGANIZATION_ID). This means the triage step will fail for community PRs from forks because the kilocode CLI will receive empty credential values.
If fork PRs need triage support, consider using pull_request_target instead (which runs in the base repo context and has access to secrets). Since this workflow only adds labels via gh pr edit and gh issue edit without executing code from the PR branch, pull_request_target is safe here — the PR body is already sanitized before use, and no untrusted code is executed.
🤖 Prompt for AI Agents
In @.github/workflows/auto-triage.yml around lines 3 - 7, Update the workflow
trigger so forked PRs can use repository secrets by replacing the pull_request
event with pull_request_target: change the event key named "pull_request" to
"pull_request_target" (keeping the same types: [opened]); ensure the rest of the
job only uses safe operations (labels via gh pr edit / gh issue edit and
sanitized PR body) and does not execute code from the PR branch to avoid
executing untrusted code while allowing access to KILOCODE_INTEGRATION_TOKEN and
KILOCODE_INTEGRATION_ORGANIZATION_ID.
| EVENT_TYPE: ${{ github.event_name }} | ||
| ITEM_NUMBER: ${{ github.event_name == 'issues' && github.event.issue.number || github.event.pull_request.number }} | ||
| ITEM_TITLE: ${{ github.event_name == 'issues' && github.event.issue.title || github.event.pull_request.title }} | ||
| ITEM_BODY: ${{ github.event_name == 'issues' && github.event.issue.body || github.event.pull_request.body }} | ||
| run: | | ||
| # Sanitize body - remove shell metacharacters | ||
| SAFE_BODY=$(echo "$ITEM_BODY" | head -c 2000 | tr -d '`$(){}[]|;&<>\\' | tr '\n' ' ') |
There was a problem hiding this comment.
ITEM_TITLE is not sanitized, unlike ITEM_BODY.
Line 52 sanitizes ITEM_BODY (truncation, stripping metacharacters, collapsing newlines), but ITEM_TITLE is used raw at Line 66. While there's no shell injection risk (these are env vars, not ${{ }} interpolation in run:), the title could contain characters (unmatched quotes, backslashes, etc.) that break the argument string passed to kilocode --auto or enable prompt injection.
Apply comparable sanitization to ITEM_TITLE:
Proposed fix
# Sanitize body - remove shell metacharacters
SAFE_BODY=$(echo "$ITEM_BODY" | head -c 2000 | tr -d '`$(){}[]|;&<>\\' | tr '\n' ' ')
+ SAFE_TITLE=$(echo "$ITEM_TITLE" | head -c 200 | tr -d '`$(){}[]|;&<>\\')Then use ${SAFE_TITLE} instead of ${ITEM_TITLE} on Line 66.
🤖 Prompt for AI Agents
In @.github/workflows/auto-triage.yml around lines 46 - 52, Sanitize ITEM_TITLE
the same way ITEM_BODY is sanitized: create SAFE_TITLE by truncating to 2000
chars, stripping shell metacharacters and collapsing newlines (same
transformations applied to SAFE_BODY) and then use SAFE_TITLE in the command
invocation (the kilocode --auto call that currently consumes ITEM_TITLE). Update
the environment handling where ITEM_TITLE is read and where the command is
constructed so SAFE_TITLE replaces ITEM_TITLE (mirroring the SAFE_BODY logic) to
prevent unmatched quotes/backslashes or prompt-injection-like content from
breaking the run step.
Code Review by Qodo
1. kilocode --auto uses untrusted input
|
| KILO_AUTO_APPROVAL_ENABLED: "true" | ||
| KILO_AUTO_APPROVAL_EXECUTE_ENABLED: "true" | ||
| KILO_AUTO_APPROVAL_EXECUTE_ALLOWED: "gh issue edit,gh pr edit" | ||
| KILO_AUTO_APPROVAL_EXECUTE_DENIED: "gh issue close,gh issue delete,gh issue transfer,gh issue lock,gh issue unlock,gh pr close,gh pr merge,gh repo,gh auth,gh secret,gh variable,rm,sudo,curl,wget,bash,sh,python,node,npm,npx" | ||
| KILO_TELEMETRY: "false" | ||
| # Determine event type and extract data | ||
| EVENT_TYPE: ${{ github.event_name }} | ||
| ITEM_NUMBER: ${{ github.event_name == 'issues' && github.event.issue.number || github.event.pull_request.number }} | ||
| ITEM_TITLE: ${{ github.event_name == 'issues' && github.event.issue.title || github.event.pull_request.title }} | ||
| ITEM_BODY: ${{ github.event_name == 'issues' && github.event.issue.body || github.event.pull_request.body }} | ||
| run: | | ||
| # Sanitize body - remove shell metacharacters | ||
| SAFE_BODY=$(echo "$ITEM_BODY" | head -c 2000 | tr -d '`$(){}[]|;&<>\\' | tr '\n' ' ') | ||
|
|
||
| # Determine gh command based on event type | ||
| if [ "$EVENT_TYPE" = "issues" ]; then | ||
| GH_CMD="gh issue edit" | ||
| ITEM_TYPE="issue" | ||
| else | ||
| GH_CMD="gh pr edit" | ||
| ITEM_TYPE="pull request" | ||
| fi | ||
|
|
||
| kilocode --auto "Triage this GitHub ${ITEM_TYPE}: | ||
|
|
||
| Number: ${ITEM_NUMBER} | ||
| Title: ${ITEM_TITLE} | ||
| Body: ${SAFE_BODY} |
There was a problem hiding this comment.
1. kilocode --auto uses untrusted input 📘 Rule violation ⛨ Security
The workflow feeds untrusted issue/PR content (ITEM_TITLE, ITEM_BODY) into an LLM prompt while enabling command execution (KILO_AUTO_APPROVAL_EXECUTE_ENABLED), creating a prompt-injection path to unintended gh issue edit/gh pr edit actions. This lacks strict validation/allowlisting of the model-produced operations and user-generated inputs before acting on them.
Agent Prompt
## Issue description
The workflow enables automated command execution (`KILO_AUTO_APPROVAL_EXECUTE_ENABLED`) while embedding untrusted issue/PR content into the LLM prompt, which can be exploited via prompt-injection to cause unintended `gh issue edit` / `gh pr edit` actions.
## Issue Context
User-controlled GitHub issue/PR titles and bodies are external inputs. Even if shell injection is not occurring, prompt injection can coerce the model into producing harmful/undesired commands when execution is enabled.
## Fix Focus Areas
- .github/workflows/auto-triage.yml[40-67]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| @@ -0,0 +1 @@ | |||
| 171809 | |||
There was a problem hiding this comment.
2. Committed .beads state files 🐞 Bug ⛯ Reliability
This PR commits machine-specific .beads/ runtime/state files (pid, sqlite shm/wal, sync state, timestamps) that will constantly change and create noisy diffs/merge conflicts. These files should be removed from version control and ignored at the repo root.
Agent Prompt
### Issue description
Several `.beads/` runtime/state artifacts (pid files, sqlite shm/wal, sync-state, timestamps) were added to the repo. These are machine-generated and will churn constantly, creating noisy diffs and merge conflicts.
### Issue Context
A subproject already ignores `.beads/`, but the repo root does not, so it’s easy to accidentally commit these files.
### Fix Focus Areas
- .gitignore[1-90]
- .beads/daemon.pid[1-1]
- .beads/sync-state.json[1-7]
- .beads/beads.left.meta.json[1-1]
- .beads/.local_version[1-1]
- .beads/beads.db-shm[1-5]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| KILO_AUTO_APPROVAL_ENABLED: "true" | ||
| KILO_AUTO_APPROVAL_EXECUTE_ENABLED: "true" | ||
| KILO_AUTO_APPROVAL_EXECUTE_ALLOWED: "gh issue edit,gh pr edit" | ||
| KILO_AUTO_APPROVAL_EXECUTE_DENIED: "gh issue close,gh issue delete,gh issue transfer,gh issue lock,gh issue unlock,gh pr close,gh pr merge,gh repo,gh auth,gh secret,gh variable,rm,sudo,curl,wget,bash,sh,python,node,npm,npx" |
There was a problem hiding this comment.
3. Allowlist too broad 🐞 Bug ⛨ Security
The workflow enables auto-approved command execution but only allowlists the prefix gh issue edit / gh pr edit. Because command approval uses prefix matching, this permits any `gh issue/pr edit ...` operation (not just adding labels), increasing blast radius if the model deviates from instructions.
Agent Prompt
### Issue description
`KILO_AUTO_APPROVAL_EXECUTE_ALLOWED` currently allowlists `gh issue edit` and `gh pr edit` as prefixes. The CLI’s approval logic uses prefix matching, so the agent can run *any* `gh issue/pr edit ...` command once auto-approval is enabled.
### Issue Context
The workflow’s intent is label-only triage, but the allowlist permits broader edits than intended.
### Fix Focus Areas
- .github/workflows/auto-triage.yml[40-43]
- cli/src/services/approvalDecision.ts[29-56]
- cli/src/services/approvalDecision.ts[209-235]
### Suggested direction
- Add a small repo script (e.g., `scripts/triage-add-label.sh`) that only accepts: (issue|pr) number + label and calls `gh ... --add-label` safely.
- Set `KILO_AUTO_APPROVAL_EXECUTE_ALLOWED` to only that script (e.g., `./scripts/triage-add-label.sh`).
- Update the prompt to instruct the model to call only the wrapper script (not raw `gh issue edit`).
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
Mirror of upstream PR #5050
Verdict: APPROVE | Tier 3
Review: kilocode-5050-review.md
Summary by CodeRabbit