pi-auto-permissions 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +6 -0
  3. package/README.md +304 -0
  4. package/THIRD_PARTY_NOTICES.md +70 -0
  5. package/docs/implementation-plan.md +311 -0
  6. package/docs/invariants.md +555 -0
  7. package/package.json +59 -0
  8. package/src/canonical.ts +314 -0
  9. package/src/commands/index.ts +362 -0
  10. package/src/domain.ts +198 -0
  11. package/src/extension.ts +430 -0
  12. package/src/guardian/circuit-breaker.ts +102 -0
  13. package/src/guardian/index.ts +74 -0
  14. package/src/guardian/policy.ts +135 -0
  15. package/src/guardian/prompt.ts +379 -0
  16. package/src/guardian/reviewer.ts +599 -0
  17. package/src/guardian/types.ts +149 -0
  18. package/src/guardian/verdict.ts +211 -0
  19. package/src/pi/index.ts +13 -0
  20. package/src/pi/model-reviewer.ts +235 -0
  21. package/src/pi/transcript.ts +524 -0
  22. package/src/policy/dangerous-command.ts +312 -0
  23. package/src/policy/path-policy.ts +501 -0
  24. package/src/runtime/index.ts +1 -0
  25. package/src/runtime/permission-engine.ts +474 -0
  26. package/src/sandbox/config.ts +188 -0
  27. package/src/sandbox/controller.ts +354 -0
  28. package/src/sandbox/index.ts +26 -0
  29. package/src/sandbox/runtime.ts +28 -0
  30. package/src/sandbox/types.ts +125 -0
  31. package/src/state/config-store.ts +580 -0
  32. package/src/state/index.ts +2 -0
  33. package/src/tools/bash.ts +101 -0
  34. package/src/tools/gate.ts +74 -0
  35. package/src/tools/index.ts +2 -0
  36. package/vendor/openai-codex/NOTICE +6 -0
  37. package/vendor/openai-codex/README.md +17 -0
  38. package/vendor/openai-codex/guardian/policy.md +42 -0
  39. package/vendor/openai-codex/guardian/policy_template.md +58 -0
@@ -0,0 +1,311 @@
1
+ # Proof-linked implementation plan
2
+
3
+ Status: normative construction and verification plan for the current
4
+ implementation. Every step below names the invariants it supports, and the
5
+ release claims are limited to the executable evidence listed in Sections 3-5.
6
+
7
+ ## 1. Architecture
8
+
9
+ The package has eight narrow components:
10
+
11
+ 1. `state/`: atomic global configuration and per-session requested mode;
12
+ 2. `policy/`: canonical requests, path classification, dangerous-command rules,
13
+ and admission routing;
14
+ 3. `guardian/` and `pi/`: pinned Guardian prompt, transcript projection, model invocation,
15
+ strict verdict parser, deadlines, and denial circuit breaker;
16
+ 4. `sandbox/`: a fixed macOS/Linux shell sandbox plus ReviewOnly fallback;
17
+ 5. `runtime/`: the non-executing admission state machine and exact review binding;
18
+ 6. `tools/`: Pi tool interception and the sandbox-aware `bash` override;
19
+ 7. `commands/`: `/perm`, `/perm-auto-model`, and `/perm-enabled`;
20
+ 8. `extension.ts`: lifecycle wiring only.
21
+
22
+ No component may open a human approval dialog. UI selection belongs only to the
23
+ three explicit command handlers.
24
+
25
+ ## 2. Stepwise construction
26
+
27
+ ### Step 1: reproducible package and provenance
28
+
29
+ - Target `@earendil-works/pi-coding-agent` `0.80.10` and Node `>=22.19`.
30
+ - License the package Apache-2.0.
31
+ - Pin runtime dependencies exactly and commit the lockfile.
32
+ - Vendor the minimum Codex Guardian policy/prompt material from revision
33
+ `0fb559f0f6e231a88ac02ea002d3ecd248e2b515`.
34
+ - Record source paths, revision, modifications, Apache notice, and Pi MIT
35
+ attribution for any adapted Pi example code.
36
+ - Add a CI test that verifies vendored hashes and attribution entries.
37
+
38
+ Guarantees supported: I13 and reproducible policy semantics.
39
+
40
+ ### Step 2: canonical data model
41
+
42
+ - Define closed TypeScript unions for modes, backend, config health, and
43
+ decisions; represent lifecycle invalidation with revisioned session state and
44
+ the final admission/executor boundary.
45
+ - Implement deterministic, bounded canonical JSON with sorted keys.
46
+ - Reject unsupported values, excessive depth, cycles, non-finite numbers, and
47
+ requests beyond the transcript/action budget.
48
+ - Bind every review to the canonical action, exact reviewer model and thinking
49
+ level, plus global/session/backend revision.
50
+
51
+ Guarantees supported: I1, I8, I9, I10, I14, I15.
52
+
53
+ ### Step 3: durable global state
54
+
55
+ - Store one private extension-owned JSON file under `getAgentDir()`; it is an
56
+ implementation detail, never a user-edited configuration surface.
57
+ - Serialize writers with a cross-process lock.
58
+ - Allocate revisions through primary and recovery copies of one private
59
+ monotonic watermark so a config fault plus one metadata fault cannot recreate
60
+ an approval-visible revision.
61
+ - Under the same cross-process reader/writer lock, write mode `0600` temporary
62
+ files in the same directory, file-sync, rename, and best-effort sync the
63
+ directory; publish recovery watermark, primary watermark, then config.
64
+ - Reserve Missing for the all-three-absent first-run state. Treat every partial
65
+ artifact set, malformed or unequal watermark pair, or watermark below the
66
+ config revision as Fault. Repair above the greatest surviving valid
67
+ watermark/config hint, and refuse repair when neither watermark is
68
+ valid.
69
+ - Reread state at every tool gate so Off/model changes affect existing processes.
70
+ - Treat malformed or unknown config schemas as Fault.
71
+ - Permit explicit management commands to repair Fault.
72
+
73
+ Guarantees supported: I2, I4, I10, I13, I14.
74
+
75
+ ### Step 4: session state
76
+
77
+ - Initialize requested mode to Auto for every runtime.
78
+ - Initialize backend to an unbound `null` value and form no Guardian binding
79
+ until startup installs `sandboxed`, `review-only`, or `unavailable`.
80
+ - Store a non-model-visible custom session entry on mode changes solely so
81
+ `session_start(reason="reload")` can reconstruct the same logical runtime.
82
+ - Ignore that entry for startup/resume/new/fork so privilege never persists into
83
+ another runtime.
84
+ - Increment a session revision on each mode or lifecycle change.
85
+
86
+ Guarantees supported: I1, I2, I3, I8, I12, I14.
87
+
88
+ ### Step 5: static file policy
89
+
90
+ - Normalize relative/absolute paths without shell interpretation.
91
+ - Resolve existing targets with `realpath`; for creation, walk to the nearest
92
+ existing ancestor and append unresolved components without accepting `..`.
93
+ - Materialize workspace and temporary writable roots.
94
+ - Detect `.git` directories and gitdir pointer files; protect resolved Git data.
95
+ - Protect top-level `.git`, `.agents`, `.codex`, and `.pi` recursively.
96
+ - Statically deny the extension's durable state and lock roots before review.
97
+ - Auto-admit in-root non-protected `write`/`edit`; review all others.
98
+ - Auto-admit the known read-only built-ins.
99
+ - If policy construction fails, install a narrow fallback that admits only those
100
+ read-only built-ins and denies every direct mutation.
101
+
102
+ Guarantees supported: I5, I8, I10, I14.
103
+
104
+ ### Step 6: shell backends
105
+
106
+ - Pin and initialize the chosen Apache-2.0 sandbox runtime with a fixed policy:
107
+ broad read, workspace/temp write, protected metadata read-only, no network.
108
+ - Support macOS and Linux after an actual capability probe.
109
+ - Override `bash` while retaining Pi's renderer and output/truncation behavior.
110
+ - Add optional `sandbox_permissions: "use_default" | "require_escalated"`.
111
+ - Run default non-dangerous calls exactly once inside the sandbox.
112
+ - Review default Codex-dangerous calls, then run an exact allow once inside the
113
+ sandbox; approval alone never removes containment.
114
+ - Run approved escalations exactly once using Pi's ordinary local bash backend.
115
+ - On an unsupported platform, use ReviewOnly and review every bash call.
116
+ - On macOS/Linux dependency, initialization, capability-probe, or strong-sandbox
117
+ failure, deny Auto bash calls; never weaken to ReviewOnly.
118
+ - On ambiguous runtime failure, never replay the same call; degrade only future
119
+ calls when infrastructure failure is established.
120
+ - Serialize ownership of Sandbox Runtime's supported-host process-global
121
+ manager. Convert an additional same-process owner attempt to an unavailable
122
+ backend, release ownership only after drain and successful reset, and poison
123
+ reuse until process restart if final reset fails.
124
+ - Do not sandbox explicit user `!`/`!!` commands.
125
+
126
+ Guarantees supported: I5-I10, I14, I17.
127
+
128
+ ### Step 7: Codex-compatible reviewer
129
+
130
+ - Use the globally selected Pi model and explicitly selected supported thinking
131
+ level without changing the main session model or its thinking level.
132
+ - Resolve credentials through Pi's model registry; never persist credentials.
133
+ - Disable tools in the review request.
134
+ - Provide a bounded compact transcript and exact canonical action.
135
+ - Use the pinned Codex risk taxonomy and verdict schema, modified only to remove
136
+ human override/request paths.
137
+ - Enforce one aggregate 90-second deadline and at most three attempts.
138
+ - Parse exact JSON; normalize no prose and never infer an allow.
139
+ - Treat every non-allow/failure as denial and return one fixed denial string.
140
+ - Track three consecutive and ten-of-fifty per-turn denial breakers.
141
+
142
+ Guarantees supported: I5, I6, I8-I11, I14-I16.
143
+
144
+ ### Step 8: commands and status
145
+
146
+ - `/perm` accepts `auto` or `unrestricted`; no argument opens a two-item selector
147
+ only when interactive.
148
+ - Reject `/perm auto` without a configured reviewer, leaving state unchanged.
149
+ - `/perm-auto-model` accepts an exact `provider/model` plus thinking level or
150
+ uses interactive model and supported-level pickers; validate model existence,
151
+ level support, and auth before one durable tuple commit; set the current
152
+ requested mode to Auto after success.
153
+ - `/perm-enabled on|off` commits globally and affects other processes at their
154
+ next gate.
155
+ - Keep all commands available while disabled or in Fault.
156
+ - Report `Auto`, `Auto (review-only)`, `Auto (sandbox unavailable)`,
157
+ `Auto (configuration fault)`, `Unrestricted`, or `Off` for an active engine;
158
+ backends are not selectable.
159
+ - If engine construction catastrophically fails, retain the already-registered
160
+ fail-closed tool gates, publish `Auto (unavailable)`, and leave commands
161
+ non-mutating until a later successful session initialization.
162
+
163
+ Guarantees supported: I1-I4, I11-I13, I17.
164
+
165
+ ### Step 9: Pi lifecycle integration
166
+
167
+ - Register one handler per event and make repeated reload initialization
168
+ idempotent.
169
+ - Capture the final action as seen by this extension and compare it again before
170
+ returning allow.
171
+ - Abort pending reviews on same-runtime session shutdown, local mode/global
172
+ command changes, backend failure, or Pi cancellation. Detect sibling-process
173
+ global commits at the next pre-model, post-model, or final binding read; they
174
+ cannot push an abort signal into another process.
175
+ - Treat final admission as the permission linearization point. A policy commit
176
+ after that point does not revoke an action already admitted once.
177
+ - Never hold the state lock while calling a model, spawning a process, or waiting
178
+ for UI.
179
+
180
+ Guarantees supported: I8-I10, I14, I15.
181
+
182
+ ## 3. Test strategy
183
+
184
+ Tests form four concentric layers. A release requires all applicable layers.
185
+
186
+ ### 3.1 Unit and deterministic boundary tests
187
+
188
+ - Exhaustive effective-mode truth table.
189
+ - Session revision/liveness transitions and denial-before-executor boundaries.
190
+ - Stable canonicalization across object order and Unicode inputs.
191
+ - Deterministic boundary cases for cycles, accessors, sparse arrays, depth,
192
+ nodes, bytes, non-finite numbers, and unsupported values.
193
+ - Path corpus: relative, absolute, `..`, prefix collisions, symlinks, dangling
194
+ symlinks, missing ancestors, temp roots, gitdir files, and protected paths.
195
+ - Pinned Codex dangerous-command corpus: forced `rm`, wrappers, depth limit,
196
+ chains, pipes, substitutions, control flow, malformed shell, and false-positive
197
+ cases.
198
+ - Strict verdict matrix: allow, deny, ask, empty/missing/extra/wrong fields,
199
+ prose, fences, duplicate JSON, multiple JSON values, and oversized output.
200
+ - Circuit-breaker consecutive and rolling-window boundary sequences.
201
+ - Sandbox-controller state tests for singleton ownership, command leases,
202
+ runtime failure, successful reset, and permanent process poison after a
203
+ failed final reset.
204
+
205
+ ### 3.2 Component integration tests
206
+
207
+ - Real atomic writes with multiple processes racing reviewer-tuple updates.
208
+ - Missing, malformed, truncated, wrong-version, wrong-shape, and repeatedly
209
+ repaired config, including two-watermark monotonicity and disagreement.
210
+ - Injected first-watermark, between-watermark, and first-config rename failures
211
+ assert old-config preservation, explicit Fault, cleanup, and monotonic repair
212
+ as applicable. An instrumented filesystem verifies file-sync, rename, and
213
+ best-effort directory-sync ordering for recovery watermark, primary watermark,
214
+ and config.
215
+ - Fake Pi model provider: allow, deny, malformed, transient failures, timeout,
216
+ cancellation, missing auth, and unavailable model.
217
+ - Binding races: reviewer/thinking revision change, Auto -> Unrestricted ->
218
+ Auto, backend change, session shutdown, argument mutation, and delayed static
219
+ classification.
220
+ - Assert action denials do not call confirmation, free-form-input, editor, or
221
+ selector UI.
222
+
223
+ ### 3.3 Real sandbox tests
224
+
225
+ On macOS and Linux CI hosts, run actual child processes and assert:
226
+
227
+ - workspace and temporary writes succeed;
228
+ - outside and protected writes fail;
229
+ - network access fails;
230
+ - descendant shell processes inherit restrictions;
231
+ - symlink escapes, shell substitutions, and a Node interpreter cannot escape the
232
+ same boundary;
233
+ - workspace policy remains valid when the Pi session cwd differs from the Node
234
+ process cwd.
235
+
236
+ Controlled controller/integration tests, rather than the native process test,
237
+ cover dependency/probe/runtime failure, shutdown draining, no replay after an
238
+ ambiguous execution failure, and approved/denied escalation counts.
239
+
240
+ Unsupported-platform behavior is tested with injected platform probes: every
241
+ bash call is reviewed, allow executes once, and every other outcome executes zero
242
+ times. Deterministic supported-platform dependency, initialization, and probe
243
+ failures assert that Auto bash executes zero times; runtime-failure cases assert
244
+ that no later call executes and a possibly started call is never replayed.
245
+
246
+ ### 3.4 Black-box Pi E2E tests
247
+
248
+ Use Pi's public `ExtensionRunner`/`DefaultResourceLoader` and a real
249
+ `AgentSession` bound in print mode, with deterministic faux providers and
250
+ temporary agent/workspace directories. These tests do not claim packaged CLI,
251
+ RPC, JSON-mode, or live TUI coverage.
252
+
253
+ Cover:
254
+
255
+ - empty first run and unavailable Auto;
256
+ - first model/thinking-level selection and immediate Auto; command unit tests
257
+ separately cover level-only changes and interactive selection;
258
+ - reload restoration and fresh `startup`, `resume`, `fork`, and `new` event
259
+ reasons, including independent child/grandchild runtime simulations;
260
+ - Auto, Unrestricted, and Off routing, plus configured/unconfigured reviewer and
261
+ sandboxed/review-only/unavailable backend cases;
262
+ - every built-in tool and a representative custom tool;
263
+ - model-authored slash-like text cannot change settings;
264
+ - explicit user commands can change settings;
265
+ - Off/on and reviewer changes observed by already-running sibling runtime
266
+ simulations;
267
+ - denial is an `isError` tool result visible to the model, with no UI dialog;
268
+ - the model can continue with a safer call after denial;
269
+ - the shipped TypeScript entrypoint loads through Pi's resource loader and the
270
+ no-dialog path completes in print mode.
271
+
272
+ ## 4. Invariant-to-test traceability
273
+
274
+ | Invariant | Required evidence |
275
+ |---|---|
276
+ | I1-I4 | mode/state truth table, extension-runner session cases, and multi-process config writers |
277
+ | I5 | route/executor assertions and a real `AgentSession` denial whose custom executor remains uncalled |
278
+ | I6-I7 | real process/network/filesystem sandbox test, controller tests, and ReviewOnly E2E |
279
+ | I8-I9 | canonical binding, revision race, and exactly-once sentinel tests |
280
+ | I10 | deterministic config/model/classification/sandbox failure cases |
281
+ | I11-I12 | UI spies and model-authored command tests |
282
+ | I13 | multi-process writers, rename-failure preservation, and durable-I/O ordering |
283
+ | I14 | reviewer/thinking, mode-ABA, backend, lifecycle, and action-mutation race tests |
284
+ | I15-I16 | aggregate-deadline tests, queue bounds, parallel denial races, and breaker sequences |
285
+ | I17 | capability/init-failure status and execution-path assertions |
286
+
287
+ An explicit manifest maps every invariant `I1` through `I17` to an exact test
288
+ file and title fragment. The traceability test checks the complete key set, each
289
+ file's existence, and each named witness; deleting or renaming claimed evidence
290
+ therefore fails CI. The substantive evidence remains the assertions summarized
291
+ in the table above.
292
+
293
+ ## 5. Release gates
294
+
295
+ A release is blocked unless:
296
+
297
+ 1. type checking plus deterministic unit, integration, and Pi E2E tests pass;
298
+ 2. the opt-in real sandbox test passes on the configured Ubuntu 22.04 and macOS
299
+ 14 CI hosts;
300
+ 3. unsupported-platform ReviewOnly and supported-platform fail-closed tests pass;
301
+ 4. vendored policy hashes and all third-party notices are current;
302
+ 5. dependency audit and SBOM generation complete;
303
+ 6. the explicit invariant-to-named-test traceability manifest passes;
304
+ 7. README limitations match Section 7 of the invariant specification;
305
+ 8. no-dialog unit/E2E assertions pass and the action-review modules retain no UI
306
+ dependency.
307
+
308
+ The project may be shipped from tests without an informal manual trial only when
309
+ these executable release gates are satisfied on the release commit. This plan
310
+ does not represent absent fuzzing, packaged-CLI matrices, or manual TUI/RPC/JSON
311
+ exercises as completed evidence.