返回 CodeWhale
AUTHORIZATION_ORDER.md
根目录 / docs / AUTHORIZATION_ORDER.md
1 # Authorization order
2
3 > 阅读简体中文版:[zh_hans/AUTHORIZATION_ORDER.md](zh_hans/AUTHORIZATION_ORDER.md)。
4
5 Codewhale combines tool availability, hooks, typed permission rules, approval
6 posture, repository policy, and sandboxing. An approval from one layer is not a
7 universal bypass: a later safety layer can still require review or block the
8 call, and an approval is not an operating-system sandbox grant.
9
10 This page records the order implemented by the interactive engine's
11 model-requested tool path. Entrypoints that use only part of that path, such as
12 the core runtime's direct tool API, keep the relative order of the layers they
13 do use.
14
15 ## Model tool-call pipeline
16
17 The interactive engine evaluates a model-requested tool call in this order:
18
19 | Order | Layer | Result |
20 |---:|---|---|
21 | 1 | Effective configuration and posture | User settings, command/runtime overrides, and the project overlay resolve before the turn. A project overlay may tighten `approval_policy`, `sandbox_mode`, or shell availability, but may not loosen them. |
22 | 2 | Mode and tool admission | Plan-mode restrictions, input parse errors, per-command tool deny/allow lists, caller restrictions, and missing execution registrations fail before policy rules are considered. A tool present in both command lists is denied. |
23 | 3 | Preparation, then `tool_call_before` hooks | Registry preparation is side-effect free. Foreground hooks then fold as `deny > ask > allow`, and a strict matching hook that produces no verdict fails closed. The last `updatedInput` wins; the engine prepares the rewritten input again before later gates inspect it. |
24 | 4 | Registered-tool baseline | The prepared tool's `ApprovalRequirement` establishes its ordinary approval need. A hook `ask` is applied after that assignment so the baseline cannot erase it. Non-bypassable registered holds remain forced in postures that can prompt; Full Access auto-approves them instead of opening a contradictory modal. Plan mode also blocks write-capable tools here. |
25 | 5 | Typed `permissions.toml` rule | A matching `deny` blocks. A matching `allow` may clear only ordinary registry approval; it cannot clear a hook `ask` or a non-bypassable registered hold. A matching `ask` forces review only in a posture that can prompt. Full Access/auto-approval is not downgraded into a prompt, while an explicit typed `deny` still blocks. |
26 | 6 | Auto-review policy and built-in safety floor | Configured block rules run before the built-in floor, then configured allow rules and the deterministic fallback. This layer runs after typed permissions and can add a prompt or block, but cannot remove an earlier hold. Full Access deliberately skips the interactive publish hold; catastrophic destructive background/headless actions remain protected. |
27 | 7 | Repository law | Protected path invariants can only add a prompt or block. A repo-law prompt becomes a hard block in Full Access, which has no contradictory approval modal. |
28 | 8 | Human approval | A remaining prompt is sent to the approval channel. Denial stops the call. Approval authorizes this planned call; session and persistent choices affect later matching calls but do not erase a later gate from this call. |
29 | 9 | Tool authority and execution sandbox | Worker authority envelopes, native tool path checks, and the selected OS or external sandbox still apply during execution. A sandbox denial remains a denial unless the user separately authorizes a supported elevation path. |
30
31 The ordering is intentionally monotonic after the typed permission layer:
32 auto-review and repository law can tighten a result, not turn a previous block
33 or prompt into an unreviewed execution. There are explicit posture choices
34 inside those layers—for example, Full Access does not create an interactive
35 publish prompt—but those choices do not let an earlier remembered grant erase
36 a hold that the layer actually produced.
37
38 ## Typed permission-rule selection
39
40 `permissions.toml` is currently a sibling of the active user `config.toml`.
41 There is no project-local permission-rule source today. An optional `workspace`
42 field scopes one user rule to a repository; it does not create a project
43 overlay. `/permissions` reports that source, matcher, scope, and whether the
44 scope applies to the current workspace.
45
46 The execution-policy engine evaluates matching rules as follows:
47
48 1. Normalize the tool, command, workspace, and any workspace-relative path.
49 Unsafe or external paths do not become matchable file rules.
50 2. Check denied command prefixes against the whole command and every chained
51 segment. These hard prefix denies are merged across rulesets and always win.
52 3. Compute a trusted-prefix candidate for an unchained shell command. This is a
53 candidate for the approval-mode fallback, not an immediate decision.
54 4. Select one matching typed rule by this lexicographic precedence:
55 1. higher source layer: `User > Agent > BuiltinDefault`;
56 2. stronger action inside that layer: `deny > ask > allow`;
57 3. the more specific matcher when layer and action tie.
58 5. Apply the selected typed action. `deny` forbids the call, `allow` skips the
59 execution-policy approval, and `ask` requires approval. A typed `ask`
60 overrides a trusted prefix.
61 6. If no typed action decides the result, apply the approval-mode fallback
62 using the trusted-prefix candidate.
63
64 Source layer is compared before typed action. Consequently, a user-layer typed
65 `allow` can override an agent-layer typed `deny`; inside the same layer, `deny`
66 still beats `ask`, which beats `allow`, regardless of file order or matcher
67 specificity. Hard denied prefixes are the exception: they are checked before
68 typed-layer selection and cannot be overridden by a typed allow.
69
70 Specificity is only a tie-breaker after source and action. A constrained
71 command, exact-command, path, or workspace matcher beats a tool-wide rule with
72 the same action in the same layer. Specificity never lets a narrow allow beat a
73 same-layer deny.
74
75 For chained shell commands, a trusted prefix never approves the whole chain. A
76 typed deny that wins for any individual segment blocks the full invocation.
77
78 ## Approval posture and missing prompts
79
80 The execution-policy result is combined with the registered-tool baseline; the
81 two should not be interpreted independently.
82
83 - Ask and Auto-Review may surface tool safety approvals. Model-authored user
84 questions (`request_user_input`) are a separate channel and reach the user in
85 every interactive posture, Auto-Review included. Only headless `exec` runs,
86 which have no responder, withhold the tool. Runtime threads (app
87 conversations, background tasks and automations) keep it: a question parks
88 the turn until someone answers or cancels it through the app or runtime API,
89 or until a positive `tools.user_input_timeout_seconds` expires. An omitted or
90 zero timeout waits indefinitely, the same way an Ask-posture approval parks.
91 - Full Access and YOLO-compatible auto-approval paths do not let a typed `ask`
92 downgrade the session into prompting. Non-bypassable registered holds
93 auto-approve in Full Access. Typed deny, catastrophic background/headless
94 safety holds, and repository law still fail closed where their respective
95 layers apply.
96 - With `approval_policy = "never"`, a matching typed `ask` is forbidden because
97 the required prompt cannot be shown.
98
99 Runtime adapters may transport an approval decision differently from the
100 interactive modal. That transport and any continuation protocol are separate
101 from this ordering contract; see [Runtime API](RUNTIME_API.md).
102
103 ## Project overlays
104
105 The project config overlay at `<workspace>/.codewhale/config.toml` is not a
106 permission-rule layer. It can only move approval and sandbox posture toward
107 more restrictive values:
108
109 - approval: `auto` → `on-request`/`untrusted` → `never`;
110 - sandbox: `danger-full-access` → `workspace-write` → `read-only`;
111 - shell availability: `true` may become `false`, never the reverse.
112
113 Project config cannot add credentials, hooks, provider authority, or a
114 project-local `permissions.toml`. See
115 [Configuration](CONFIGURATION.md#per-project-overlay-485) for the complete
116 overlay allow-list.
117
118 ## Regression coverage
119
120 The contract is exercised by tests at the layers that own each decision:
121
122 - `authorization_order_contract_matches_documented_precedence` covers hard
123 prefix denial and the typed `layer → action → specificity → approval-mode`
124 sequence through the public execution-policy API.
125 - `hook_fold_deny_wins_over_ask_and_allow` covers foreground hook folding.
126 - `non_bypassable_registered_tools_auto_approve_in_full_access` covers
127 registered holds.
128 - `full_access_permission_allow_cannot_bypass_background_catastrophic_floor`
129 and `full_access_permission_allow_cannot_bypass_repo_law` cover later safety
130 layers overriding a remembered allow.
131 - `project_merge_only_tightens_approval_and_sandbox_policy` covers project
132 overlay monotonicity.
133
134 Focused commands:
135
136 ```bash
137 cargo test -p codewhale-execpolicy --test authorization_order --locked
138 cargo test -p codewhale-tui --lib --locked full_access_permission_allow_cannot_bypass
139 cargo test -p codewhale-config --locked project_merge_only_tightens_approval_and_sandbox_policy
140 ```
141
142 ## Related references
143
144 - [Configuration](CONFIGURATION.md) — rule schema, `/permissions`, hooks, and
145 project overlays
146 - [Modes](MODES.md) — Plan/Act/Operate and permission posture
147 - [Sandbox threat model](SANDBOX.md) — platform enforcement and fallbacks
148 - [Runtime API](RUNTIME_API.md) — approval events and remote resolution
149
149 lines MARKDOWN