Repository navigation
v0.22.0
Overview
Request conditions: control what an agent sends, not only where (#78, #79)
Credential rules and MCP tool rules can now check the content of a request: the JSON body of an HTTP request, or the arguments of an MCP tool call. A host, method and path can't tell a draft from a sent email, or creating an issue from closing one. Conditions can.
# Inject MAIL_KEY only into drafts to listed recipients, with no other fields.
[[secrets.MAIL_KEY.rules]]
effect = "allow"
hosts = ["api.mail.example"]
methods = ["POST"]
paths = ["/v1/messages"]
body = { send = false, to = ["support@acme.com", "ops@acme.com"] }
allow_fields = ["subject", "text"]# Allow Linear's save_issue only for creating issues in one team.
[[mcp_servers.linear.tool_rules]]
effect = "allow"
tools = ["save_issue"]
arguments = { team = ["Engineering"], id = { absent = true } }
allow_fields = ["title", "description", "priority"]-
bodyon[[secrets.*.rules]]and[[personal_credentials.*.rules]], andargumentson the new[[mcp_servers.*.tool_rules]]. Both use the same four conditions:Condition Holds when the field send = falseequals the value, with the same type to = ["a", "b"]is one of the values, or a non-empty array of only those values amount = { min = 1, max = 5000 }is a number in the range (inclusive; either bound optional) id = { absent = true }is missing or nullDotted paths (
"destination.type") reach nested fields. All conditions in a rule must hold, separate rules are alternatives, and a matching deny always wins. -
allow_fieldslists the only other fields a request may contain. Without it, fields the rule doesn't mention pass unchecked; with it, any unlisted field (abcc, anassignees) is refused. Allow rules only. -
Fails closed. When a matching rule has conditions, the proxy reads the body before injecting the credential. It must be JSON, uncompressed, at most 1 MiB, an object, and have no repeated keys. Anything else, including no body, can't satisfy an allow rule with conditions. The upstream receives exactly the bytes that were checked. Rules without conditions work as before, and their bodies are never read.
-
Denials name the field, never the value. The 403 says
The supplied credential is not allowed for this request (rule 1: unlisted body.bcc). The audit log records reasons such asallow_condition_failed:body.send,unlisted_field:body.bcc,deny_condition_matched:…andbody_unreadable:json. -
agent logs,logs listandlogs summary --reason <code>filter by those reasons. A bare code likeallow_condition_failedalso matches the variants that name a field. -
Testable without requests.
[[policy_tests]]cases accept a JSONbody, andagent policy testnow prints its results in color. -
Tooling:
agent validaterejects malformed conditions andallow_fieldson deny rules. It warns when an allow rule without conditions makes others pointless, and that deny rules with conditions are best-effort.agent explainreports requests that depend on the body as "eligible only if the request body meets the rule's body conditions".agent mcp tools --tool <name>shows a tool's arguments, types and the rules for it, and warns about rule fields the tool doesn't declare. An unknown server or tool is now a JSON input error.
-
Works with
--remote. The remote Agent Proxy enforces the same conditions with the same messages and audit reasons. -
Guide: Request conditions, with examples for the GitHub REST API and httpbin. GraphQL endpoints need an exact-query allowlist; see the guide's limits.
Changes
- Credential rule hosts no longer need to be in
egress_hosts(#75). A host in a secret's rules is reachable by requests that carry that secret and match its rules.egress_hostsnow only covers requests without a credential. Before, every credential host had to be listed inegress_hosts, which opened it to any request. - The Docker sandbox uses the repository's git identity (#76). Commits inside the container used your global
user.nameanduser.emaileven when the repository sets its own. The identity is now resolved likegit commitresolves it on the host: worktree, repo-local, global (includingincludeIf), then system.
Compatibility
- Profiles using
bodyorallow_fieldsneed CLI 0.22.0 or newer. Older CLIs ignore these keys and would apply such a rule to every request it names. MCPtool_rulesare refused by older CLIs. - Unknown keys in credential rules are now an error. A typo like
methds = [...]used to be silently ignored. - The policy fingerprint changes once for profiles with HTTP rules or MCP tool rules, because conditions are now part of it.
- JSON output changes in
agent explainandagent policy test(#75):agent explain:connection: "no_egress_restriction"is removed.allowed_with_credential,egress_hosts_configuredandreachable_hostsare new.agent policy test: reasondenied_by_egress_hostsis removed.