Skip to content

feat(kiro): widen triage issue access, machine-generate permissions - #4868

Merged
kddejong merged 1 commit into
aws-cloudformation:mainfrom
kddejong:feat/kiro-agent-permissions-gh-write
Oct 23, 2026
Merged

kddejong merged 1 commit into
aws-cloudformation:mainfrom
kddejong:feat/kiro-agent-permissions-gh-write

Conversation

@kddejong

@kddejong kddejong commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Configuration-only change to the three local .kiro/agents configs. No src/ or test/ changes, so there are no unit tests to run; the verification below is a policy-evaluation harness plus pre-commit.

What changed

1. issue-triage gets full issue-write access

Previously it could comment and apply labels only. It can now:

  • gh issue comment
  • gh issue edit with any flags — title, body, labels, milestone, assignees. The label-flags-only allowlist entry and the matching --title/--body/--milestone/assignee/project denies are gone.
  • gh issue close
  • gh issue reopen

gh issue create stays denied — filing new issues is a separate capability and was not requested.

The prompt and description are rewritten to match. This matters more than the allowlist: the prompt previously said the agent "never closes or reopens an issue, never edits an issue's title or body", and an agent follows its prompt over its permissions. It still never writes code (that goes to issue-worker) and still presents a draft for approval rather than acting unprompted.

Addition beyond the request, flagged for veto: gh issue reopen was not asked for. I added it because granting close without reopen means the agent cannot undo its own wrong close, and reopen is strictly the reversal of a power already granted. Delete the two gh issue reopen allowlist entries to drop it.

2. The permissions block is now machine-generated

The hand-written permissions.rules glob block duplicated toolsSettings.execute_bash. Because it was hand-written, agent upgrade treated all three files as out of sync and refused to touch them:

$ kiro-cli agent upgrade --dry-run .kiro/agents
  ↷ skipped  issue-triage.json  out of sync (not rebuilt)
  ↷ skipped  issue-worker.json  out of sync (not rebuilt)
  ↷ skipped  pr-reviewer.json   out of sync (not rebuilt)
0 would upgrade · 3 unchanged/skipped · 0 errors

Deleting the block and running kiro-cli agent upgrade --no-backup .kiro/agents regenerates it from the regexes and adds a kiroUpgrade fingerprint. Acceptance test now passes:

$ kiro-cli agent upgrade --dry-run .kiro/agents
  = unchanged  issue-triage.json  already universal
  = unchanged  issue-worker.json  already universal
  = unchanged  pr-reviewer.json   already universal
0 would upgrade · 3 unchanged/skipped · 0 errors

No policies field is emitted, so there is no behaviour change from that direction. toolsSettings.execute_bash is preserved as-is and remains the single source. The diff is large (+782/-126) because the generator reformats to two-space indent and expands each glob onto its own line.

One regex was changed to survive conversion. (-P |--no-pager )* is a regex repetition, which the glob format cannot express; the converter emitted git -P *status *, matching arbitrary text between the prefix and the subcommand — a real widening, and git -P ; curl http://x ; status y passed the glob check. Changing * to ? converts cleanly to git -P status *, removes the conversion warning entirely, and is strictly narrower (it only drops repeated prefixes like git -P -P log, which nothing issues). That probe is now PROMPT.

Two conversion warnings remain on issue-worker, both unfixable in the glob format and both reported by the tool itself:

regex generated glob effect
^git push -u origin [A-Za-z0-9/._-]+$ git push -u origin * character class widened to a wildcard
.*push +-f.* *push *-f* + widened to *; still denies

3. pre-commit run narrowed to issue-worker

Removed from issue-triage and pr-reviewer, kept on issue-worker. The "it writes, use a scratch worktree" note is removed from the two read-only prompts along with the permission.

Two facts worth weighing before this sticks:

  • pr-reviewer already had pre-commit run before this PR, so this narrows a pre-existing permission rather than declining a new one.
  • The rationale is that CI covers it on the PR. In today's review round that did not hold: 8 of 10 open PRs had no CI run at all (statusCheckRollup empty — first-time contributors need workflow approval), and two had CI-detectable defects that only a local -m data run surfaced.

Re-adding one allowlist line per agent reverses this. Implemented as asked.

Verification

Both policy blocks evaluated independently with DENY > ALLOW > PROMPT — regexes as anchored full matches against toolsSettings.execute_bash, globs as fnmatch against permissions.rules.

agent command regex glob
issue-triage gh issue comment 4771 --body-file /tmp/x.md ALLOW ALLOW ✅
issue-triage gh issue edit 4771 --add-label bug ALLOW ALLOW ✅
issue-triage gh issue edit 4771 --title "new title" ALLOW ALLOW ✅
issue-triage gh issue edit 4771 --body "rewritten" ALLOW ALLOW ✅
issue-triage gh issue close 4771 ALLOW ALLOW ✅
issue-triage gh issue reopen 4771 ALLOW ALLOW ✅
issue-triage gh issue create --title x DENY DENY ✅
issue-triage gh pr merge 4868 DENY DENY ✅
issue-triage gh pr ready 4868 DENY DENY ✅
issue-triage gh pr review 4868 --approve DENY DENY ✅
issue-triage gh api repos/x DENY DENY ✅
issue-triage git push origin main DENY DENY ✅
issue-triage gh issue comment 1 --body x; rm -rf / DENY DENY ✅
issue-triage pre-commit run --all-files PROMPT PROMPT ✅
pr-reviewer gh issue comment 1 --body x DENY DENY ✅
pr-reviewer gh issue edit 1 --title x DENY DENY ✅
pr-reviewer gh pr review 4868 --approve DENY DENY ✅
pr-reviewer pre-commit run --all-files PROMPT PROMPT ✅
issue-worker gh pr create --draft --title x --body y ALLOW ALLOW ✅
issue-worker gh issue comment 4771 --body hi ALLOW ALLOW ✅
issue-worker pre-commit run --all-files ALLOW ALLOW ✅
issue-worker gh pr create --title x --body y PROMPT PROMPT ✅
issue-worker gh pr create --title "x --draft y" --body z PROMPT PROMPT ✅
issue-worker gh pr ready 4868 DENY DENY ✅
issue-worker gh pr merge 4868 DENY DENY ✅
issue-worker gh api repos/x DENY DENY ✅

26 cases, 0 failing.

pre-commit run --all-files for the two read-only agents is PROMPT, not DENY — it is no longer auto-approved, but it is not blocked either, so a human can still approve it case by case. Making it DENY would need an explicit deny entry; say the word if that is preferred.

Does the metacharacter looseness survive?

Yes, and it is a format limitation rather than something introduced here. The glob format has no way to express "no shell metacharacters", which the regexes do with [^;|&\$]. The tool flags every such conversion itself as regex-shell-pattern`.

probe (issue-triage) regex glob
gh issue view 1; curl http://x PROMPT ALLOW
git status; curl http://x PROMPT PROMPT
git -P ; curl http://x ; status y PROMPT PROMPT

Regeneration moved two of these in the safe direction, because a trailing cmd* became cmd * plus cmd — so git status; curl http://x is now PROMPT where the hand-written git status* allowed it. The first row is unchanged and still loose. No claim of parity between the two blocks is being made.

Could the permissions block be dropped entirely?

Recommendation: no, do not drop it. Two findings:

  1. Its absence is itself drift. With permissions removed, agent upgrade --dry-run reports the file as would upgrade rather than clean. Dropping the block permanently is therefore not a stable state while agent upgrade is the maintenance path — the tool wants to re-add it, so drift detection would be permanently noisy, which is exactly what this PR set out to fix.

  2. I could not establish that the second engine is unused, only that this repo never invokes either. agent upgrade --help says the universal format is what "both engines load". The regex block is demonstrably the one in force for CLI sessions: a blocked command reports the regex verbatim (.*rm -rf.*), not the glob. But these agents are referenced nowhere in the repo — no CI, no scripts, nothing outside .kiro/agents/ — so they are launched interactively, and I cannot rule out this repo being opened in an editor-hosted runtime that reads permissions instead.

Given it is now generated and fingerprinted, keeping it costs a stale-free regeneration step and nothing else. Dropping it would close the metacharacter looseness for good, so it is worth revisiting — but it needs someone who can confirm the second engine is unused, which I could not do from here. Not acted on.

Commands run

kiro-cli agent upgrade --dry-run .kiro/agents    # before: 3x out of sync
kiro-cli agent upgrade --no-backup .kiro/agents  # 3 upgraded, 0 errors
kiro-cli agent upgrade --dry-run .kiro/agents    # after: 3x already universal
pre-commit run --files .kiro/agents/*.json       # passed
pre-commit run --all-files                       # passed, exit 0, nothing rewritten

All three files are valid JSON with a trailing newline. kiro-cli on PATH here is 2.34.0 (both PATH entries resolve to it; a 2.33.1 install exists but nothing links to it).

@kddejong kddejong changed the title feat(kiro): let triage comment and label, worker open draft PRs feat(kiro): widen triage issue access, machine-generate permissions Oct 23, 2026
@kddejong
kddejong force-pushed the feat/kiro-agent-permissions-gh-write branch from 463f5fa to 0238444 Compare October 23, 2026 22:40
@kddejong
kddejong marked this pull request as ready for review October 23, 2026 23:18
@kddejong
kddejong force-pushed the feat/kiro-agent-permissions-gh-write branch from 0238444 to d69aa27 Compare October 23, 2026 23:21
@kddejong
kddejong merged commit e2a3637 into aws-cloudformation:main Oct 23, 2026
21 of 22 checks passed
@kddejong
kddejong deleted the feat/kiro-agent-permissions-gh-write branch October 23, 2026 23:23
@codecov

codecov Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.68%. Comparing base (8f7e485) to head (d69aa27).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #4868   +/-   ##
=======================================
  Coverage   94.68%   94.68%           
=======================================
  Files         439      439           
  Lines       16004    16004           
  Branches     3108     3108           
=======================================
  Hits        15153    15153           
  Misses        468      468           
  Partials      383      383           
Flag Coverage Δ
unittests 94.67% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant