Skip to content

fix(guardrails): resolve team single-task deadlock and permission deny ordering#88

Merged
terisuke merged 4 commits intodevfrom
fix/permission-deny-ordering
Apr 6, 2026
Merged

fix(guardrails): resolve team single-task deadlock and permission deny ordering#88
terisuke merged 4 commits intodevfrom
fix/permission-deny-ordering

Conversation

@terisuke
Copy link
Copy Markdown

@terisuke terisuke commented Apr 6, 2026

Issue for this PR

Closes #32
Closes #29
Addresses #31

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What does this PR do?

Fixes three guardrails profile bugs that block day-to-day workflow:

team.ts (#32, #29):

  • team.ts:483: Hardcoded minimum 2 tasks changed to 1 — enables single-task delegation for isolated worker pattern
  • team.ts:168-173: big() function added readOnly exemption — read verbs (investigate|review|audit|inspect|...) lacking write-intent (fix|add|edit|write|modify|...) bypass the parallel gate
  • team.ts:746: Hook injection text updated from "at least two" to "at least one worker task"
  • guardrail.ts:440: Context budget error message now suggests team tool delegation

Permission ordering (#31):

  • profile/opencode.json + managed/opencode.json: Deny rules (rm -rf, sudo, git push --force) placed after wildcard "*": "ask" — ensures findLast returns deny
  • profile/agents/implement.md: Added "*": ask before deny rules + missing deny rules
  • read section: *.env.example (allow) after *.env.* (deny) so findLast returns allow

Root cause for #31: upstream Permission.evaluate() uses findLast and Permission.merge() uses rulesets.flat(). Profile-layer workaround via rule ordering; upstream issue to be filed separately.

How did you verify your code works?

  • git diff dev..HEAD --stat: 5 files changed, 52 insertions, 5 deletions
  • Verified team.ts:483 reads if (args.tasks.length < 1)
  • Verified team.ts:746 reads "at least one worker task"
  • Verified opencode.json:96-98 has correct findLast order: *.env deny, *.env.* deny, *.env.example allow
  • code-reviewer agent: CRITICAL=0 HIGH=0
  • Codex CLI review (path A): PASS
  • typecheck: PASS (bun turbo typecheck all 13 packages)

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

🤖 Generated with Claude Code

terisuke and others added 3 commits April 6, 2026 08:53
…atibility

Permission.evaluate() uses findLast semantics where the LAST matching
rule wins. When deny rules appeared immediately after the wildcard,
a project-level merge could append additional wildcards that override
the denies. Moving all deny rules to the end of each permission section
ensures they always take precedence regardless of merge order.

Changes:
- profile/opencode.json: bash deny rules after wildcard+allow, read deny after allow
- managed/opencode.json: same reordering applied
- profile/agents/implement.md: add wildcard before deny rules, add missing deny rules

Fixes #31

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ves #32

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…atibility

Restores permission ordering fix that was accidentally reverted during
team.ts amend. Deny rules must appear AFTER wildcards for findLast to
return deny for dangerous commands.

Fixes #31

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 6, 2026 02:07
@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 6, 2026

Thanks for updating your PR! It now meets our contributing guidelines. 👍

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the Guardrails profile to avoid “team tool” dead-ends during large-request enforcement and to adjust permission rule ordering so last-match precedence behaves as intended.

Changes:

  • Allow single-task team delegations and exempt clearly read-only investigation prompts from the “big request” parallel gate.
  • Improve the context-budget exceeded error to explicitly recommend delegating via team.
  • Rework Guardrails profile/managed permission rules (notably bash/read) to better align with last-match (findLast) precedence.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/guardrails/profile/plugins/team.ts Permits 1-task team runs; adds read-only investigation exemption in big(); updates enforcement message text.
packages/guardrails/profile/plugins/guardrail.ts Updates context-budget error message to explicitly recommend team delegation.
packages/guardrails/profile/opencode.json Updates bash/read permission rules and ordering in the Guardrails profile config.
packages/guardrails/profile/agents/implement.md Adds missing default bash permission and additional deny patterns for implement agent frontmatter.
packages/guardrails/managed/opencode.json Mirrors permission rule updates for the managed Guardrails config.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 114 to 116
"*.env.example": "allow",
"*.env": "deny",
"*.env.*": "deny",
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

read permission rules are ordered such that *.env.example will still be denied: it matches both *.env.example and the later *.env.*, and evaluate() uses findLast(), so the later deny wins. Move the *.env.example allow rule after the *.env / *.env.* deny rules (or otherwise ensure the allow is the last match).

Suggested change
"*.env.example": "allow",
"*.env": "deny",
"*.env.*": "deny",
"*.env": "deny",
"*.env.*": "deny",
"*.env.example": "allow",

Copilot uses AI. Check for mistakes.
Comment on lines 107 to 109
"*.env.example": "allow",
"*.env": "deny",
"*.env.*": "deny",
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

read permission rules are ordered such that *.env.example will still be denied: it matches both *.env.example and the later *.env.*, and evaluate() uses findLast(), so the later deny wins. Move the *.env.example allow rule after the *.env / *.env.* deny rules (or otherwise ensure the allow is the last match).

Suggested change
"*.env.example": "allow",
"*.env": "deny",
"*.env.*": "deny",
"*.env": "deny",
"*.env.*": "deny",
"*.env.example": "allow",

Copilot uses AI. Check for mistakes.
Comment on lines +91 to +94
"git branch*": "allow",
"git remote*": "allow",
"git stash*": "allow",
"gh *": "allow",
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

The bash allow patterns git branch*, git remote*, and git stash* also match mutating/destructive subcommands (e.g. git branch -D, git remote add/remove, git stash drop/pop) and will bypass permission prompting. Consider narrowing these patterns to read-only forms or changing them to ask to keep guardrails conservative.

Suggested change
"git branch*": "allow",
"git remote*": "allow",
"git stash*": "allow",
"gh *": "allow",
"git branch*": "ask",
"git remote*": "ask",
"git stash*": "ask",
"gh *": "ask",

Copilot uses AI. Check for mistakes.
"git branch*": "allow",
"git remote*": "allow",
"git stash*": "allow",
"gh *": "allow",
Copy link

Copilot AI Apr 6, 2026

Choose a reason for hiding this comment

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

The bash allow patterns git branch*, git remote*, and git stash* also match mutating/destructive subcommands (e.g. git branch -D, git remote add/remove, git stash drop/pop) and will bypass permission prompting. Consider narrowing these patterns to read-only forms or changing them to ask to keep guardrails conservative.

Suggested change
"gh *": "allow",
"gh *": "ask",

Copilot uses AI. Check for mistakes.
…31

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@terisuke terisuke merged commit 59dec33 into dev Apr 6, 2026
4 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants