fix(guardrails): address review follow-up findings (#104-107)#109
Conversation
|
This PR doesn't fully meet our contributing guidelines and PR template. What needs to be fixed:
Please edit this PR description to address the above within 2 hours, or it will be automatically closed. If you believe this was flagged incorrectly, please let a maintainer know. |
There was a problem hiding this comment.
Pull request overview
This PR applies four follow-up fixes to the Guardrails profile to close identified bypasses and correctness issues in command blocking, agent permissions, and edit-triggered reminders.
Changes:
- Update the protected-branch
git pushdetection regex to account for flags betweenpushand the remote. - Tighten
security-engineerpermissions by replacing blanketgrep: allowwith a structured rule block. - Reorder
incident-respondercurlrules to align with last-match-wins permission evaluation. - Gate the auto-format reminder behind a
code(file)check so it only triggers on source edits.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| packages/guardrails/profile/plugins/guardrail.ts | Adjusts protected-branch push detection and gates the auto-format reminder on code(file). |
| packages/guardrails/profile/agents/security-engineer.md | Replaces broad grep permission with allow + deny patterns intended to block sensitive files. |
| packages/guardrails/profile/agents/incident-responder.md | Reorders curl/pipe-to-shell rules to ensure deny wins under last-match-wins semantics. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const protectedBranch = /^(main|master|develop|dev)$/ | ||
| if (/\bgit\s+push\b/i.test(cmd)) { | ||
| // Check explicit branch target | ||
| const explicitMatch = cmd.match(/\bgit\s+push\s+\S+\s+(?:HEAD:)?(\S+)/i) | ||
| const explicitMatch = cmd.match(/\bgit\s+push\s+(?:(?:-\w+|--[\w-]+)\s+)*\S+\s+(?:HEAD:)?(\S+)/i) | ||
| if (explicitMatch && protectedBranch.test(explicitMatch[1])) { |
There was a problem hiding this comment.
The new git push regex still treats many valid flag forms as the remote name, so protected-branch pushes can still bypass the block (e.g., git push --push-option=ci.skip origin main where --push-option=... doesn’t match --[\w-]+, or flags that take a separate argument like -o ci.skip). Consider tokenizing the command (shellwords) and skipping all leading options (handling --opt=value and --opt value / -o value) before extracting <remote> <refspec> and checking the refspec/branch.
| // Plain `git push` with no branch — check current branch | ||
| if (!/\bgit\s+push\s+\S+\s+\S+/i.test(cmd)) { | ||
| if (!/\bgit\s+push\s+(?:(?:-\w+|--[\w-]+)\s+)*\S+\s+\S+/i.test(cmd)) { | ||
| try { |
There was a problem hiding this comment.
Same issue for the “plain git push” detection regex: options with attached or separate values (e.g. -o ci.skip, --push-option=...) won’t be consumed by the flag group and can cause the pattern to mis-detect whether a branch was provided, which may skip the intended protected-branch checks. Using the same tokenization-based approach here would avoid regex edge cases.
| "*": allow | ||
| "*.env*": deny | ||
| "*credentials*": deny | ||
| "*.pem": deny | ||
| "*.key": deny | ||
| "*secret*": deny |
There was a problem hiding this comment.
These grep deny patterns won’t actually prevent reading .env/key material via the grep tool, because GrepTool asks permission against params.pattern (the regex searched for), not the file paths being scanned. As a result, grep "DATABASE_URL" over a repo will still return matches from .env files. To fix #105 you likely need to (a) remove/disable grep for this agent, or (b) update the grep tool/permission model to authorize based on searched file paths (or at least exclude sensitive globs in the tool itself before returning matches).
| "*": allow | |
| "*.env*": deny | |
| "*credentials*": deny | |
| "*.pem": deny | |
| "*.key": deny | |
| "*secret*": deny | |
| "*": deny |
The push block regex now skips optional flags (-u, --force, --set-upstream) between `push` and the remote/branch arguments. Fixes #104 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The formatter reminder now only fires for source code edits, not docs/config/markdown. Consistent with the doc-update reminder above it. Fixes #107 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2563c31 to
be3a4e4
Compare
Summary
Closes #104, Closes #105, Closes #106, Closes #107
Type of change
Changes
4 atomic commits, each fixing one review follow-up finding:
(?:(?:-\w+|--[\w-]+)\s+)*to push block regex sogit push -u origin mainis correctly blockedgrep: allowwith pattern-based deny list mirroring read deny rules (.env, credentials, pem, key, secret)curl *: askbeforecurl * | sh*: denyso pipe-to-shell is denied under last-match-wins semanticscode(file)guard to auto-format reminder so it only fires for source code edits, not docs/configVerification
bun turbo typecheck— 13/13 passgit push -u origin mainblocked.envdeniedcurl X | shdenied.md3x does not trigger format reminderChecklist