feat(security): declarative policy compiler for tool call authorization#1870
Merged
feat(security): declarative policy compiler for tool call authorization#1870
Conversation
…on (#1695) Implements PolicyEnforcer — a deterministic pre-execution layer that evaluates TOML-based access-control rules before any tool executes, independently of prompt content. Addresses the shell blocklist bypass class (SEC-1525) with a structured, auditable enforcement layer. Key changes: - PolicyEnforcer with deny-wins semantics, lexical path normalization (prevents path traversal via ../ chains), and tool name normalization (case/whitespace) - PolicyGateExecutor wraps TrustGateExecutor as the outermost executor in the chain; generic error to LLM, trace details to audit log only - [tools.policy] config section with enabled/default_effect/rules/policy_file - policy-enforcer feature flag (optional, included in full) - --policy-file CLI flag, /policy check|status slash commands - --init wizard step, --migrate-config step for existing configs - docs/src/advanced/policy-enforcer.md with full configuration reference
This was referenced Mar 15, 2026
bug-ops
added a commit
that referenced
this pull request
Mar 15, 2026
The variant was declared in PR #1870 but evaluated identically to Allow in the policy engine (deny-wins check: `rule.effect != Deny`). This made it misleading for users writing TOML policy rules. Remove AllowIf and update the inline comment in the evaluator. Conditions on allow rules are already expressed via rule fields (tool_matcher, params, trust, etc.) — no separate variant is needed. Closes #1871
3 tasks
bug-ops
added a commit
that referenced
this pull request
Mar 15, 2026
The variant was declared in PR #1870 but evaluated identically to Allow in the policy engine (deny-wins check: `rule.effect != Deny`). This made it misleading for users writing TOML policy rules. Remove AllowIf and update the inline comment in the evaluator. Conditions on allow rules are already expressed via rule fields (tool_matcher, params, trust, etc.) — no separate variant is needed. Closes #1871
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #1695
Summary
PolicyEnforcer— a deterministic pre-execution layer that evaluates TOML-based access-control rules before any tool executes, independently of prompt contentPolicyGateExecutorwrapsTrustGateExecutoras the outermost executor; generic error to LLM, trace details to audit log onlydefault_effectPath::components()prevents../traversal bypass (CRIT-01)policy-enforcerfeature flag (optional, included infull)Integration points
[tools.policy]config section withenabled,default_effect,rules,policy_file--policy-file <path>CLI flag/policy check <tool> <args>and/policy statusslash commands--initwizard step for policy configuration--migrate-configstep inserts empty[tools.policy]in existing configsdocs/src/advanced/policy-enforcer.md— full configuration referenceTest plan
cargo nextest run -p zeph-tools --features policy-enforcer --lib— 670 tests pass..chain traversal test:/a/b/c/d/../../../../../../etc/passwd→/etc/passwd→ Denycargo nextest run --workspace --features full --lib --bins— 5868 tests passFollow-up issues filed
IMP-ALLOWIF-NOOP:PolicyEffect::AllowIfdeclared but behaves asAllow— implement or removeSEC-POLICY-FILE:load_policy_file()lacks symlink boundary checkMED-ENV-LEAK-IN-TRACE:/policy checkinjects real env vars into trace contextMED-POLICY-CHECK-TRUST-HARDCODED: hardcodedTrustLevel::Trustedin check commandGAP-03/04/05: additional test coverage gaps forpolicy_fileand boundary conditions