Repository navigation
item 3: policy effect: and resource: templates - #4
Merged
Merged
Conversation
SPEC-v0.2 §3, acceptance test T16. `schema: ctrlrun.policy/v2` adds `effect:`, `resource:` and `mcp:` to an action entry, because the gateway (item 6) has no decorator to carry an effect template and the policy file has to. v0.2 loads both schemas. A v2 key in a v1 document is a PolicyError naming the key and the required schema: v0.1 would ignore the template and execute with no duplicate protection at all, so a document that depends on one has to say so in a way v0.1 refuses. Templates are validated at load, not at first traffic — the same reason @Protect checks its own at decoration time — and `mcp.not_executed_on_error` must be a bool, defaulting to the fail-closed value. Precedence (§3.2): where both the decorator and the policy declare a template, the decorator's is in force. The policy is a deployment artefact and the decorator is a statement in the code that will run; substituting the policy's would change an effect identity without changing a line of the program. The mismatch is a warning naming both, once per decorated function, emitted at decoration time when `control=` was passed — so an operator adding templates for the gateway's sake hears about it at import and is not broken by it. The decorator now resolves its Control before building the Action, since the policy may be the only place a template is declared and `resource` is part of the canonical form. ARCHITECTURE §6 records the one new cross-module import: policy.py takes the template grammar from effect.py to validate at load, and still knows nothing of effect state. A second copy of a security-critical grammar is worse. One v0.1 test used `ctrlrun.policy/v2` as its example of an unsupported schema. The rule under test is unchanged, so the example moves to v3.
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.
Build-list item 3. SPEC-v0.2 §3, acceptance test T16.
schema: ctrlrun.policy/v2An action entry now accepts
effect:,resource:andmcp:alongsidedecisionandrules. The gateway (item 6) has no decorator to carry an effect template, so the policy file has to.v0.2 loads both schemas. Three refusals worth naming:
PolicyErrornaming the key and the required schema. Not a warning, not silently honoured. A v0.1 kernel reading that file would ignore the effect template and execute with no duplicate protection at all — the schema string is the only thing standing between those two outcomes, so it is neither optional nor inferred.PolicyErrorwhen the policy loads, never anEffectKeyErrorat the moment an agent reaches the action. Same reason@protectchecks its own at decoration time.mcp.not_executed_on_errormust be abool, and1is not one. It is an assertion about a remote that CTRLRun cannot check (§6.8), so it is made deliberately or not at all — and it defaults to the fail-closed value.New:
Policy.effect_template,Policy.resource_template,Policy.mcp_options,McpOptions(§11). Not re-exported fromctrlrun/__init__.py— §11's re-export block does not list them.Precedence (§3.2)
Where both the decorator and the policy declare a template, the decorator's is in force. The policy is a deployment artefact and the decorator is a statement in the code that will run; when they disagree, the code is what executes, and silently substituting the policy's template would change an effect identity without changing a line of the program.
The mismatch is a warning naming the action, both templates and which one won — once per decorated function, emitted when the function first resolves its
Control: at decoration time whencontrol=was passed, otherwise on the first call. A warning, not an error, because an operator adding templates to a policy for the gateway's sake must not break a running decorator-based deployment.T16 also pins the thing the gateway will depend on: an Action built the way §6.6 will build one — resource and effect key from the policy's templates — has the same
action_hashand the same effect key as the equivalent@protect(effect=…, resource=…)call. If those two ever diverge, an approval granted through one path would not authorize the other.Two changes outside §3 that you should see
policy.pynow imports fromeffect.py. ARCHITECTURE §6 said policy must not know about effects. Load-time template validation needs the grammar, and a second copy of a security-critical grammar is worse than the import. I took the import and amended §6 in this PR, perCLAUDE.md's rule about changing an architectural constraint in the same PR — policy still knows nothing of effect state, andeffect.pydoes not importpolicy.py, so there is no cycle. Say the word if you would rather the grammar moved down intoaction.pyinstead.One v0.1 test used
ctrlrun.policy/v2as its example of an unsupported schema, which §3.1 has now made supported. The rule under test is unchanged — an unsupported schema is refused — so the example moved tov3, with a comment saying why.Mutation table — every MUST in §3
effect/resource/mcpctrlrun.policy/v2PolicyErrornaming the schemanot_executed_on_errorMUST be a boolmcpkey set is closedmcpmust be a mappingcontrol=was passedVerification
839 tests pass (812 → 839),
mypy --strict src/,ruff checkandruff format --checkclean. Every SPEC-v0.1 §7 acceptance test still passes, andctrlrun.example.yaml— a v1 document — loads unchanged.