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.
- package/LICENSE +201 -0
- package/NOTICE +6 -0
- package/README.md +304 -0
- package/THIRD_PARTY_NOTICES.md +70 -0
- package/docs/implementation-plan.md +311 -0
- package/docs/invariants.md +555 -0
- package/package.json +59 -0
- package/src/canonical.ts +314 -0
- package/src/commands/index.ts +362 -0
- package/src/domain.ts +198 -0
- package/src/extension.ts +430 -0
- package/src/guardian/circuit-breaker.ts +102 -0
- package/src/guardian/index.ts +74 -0
- package/src/guardian/policy.ts +135 -0
- package/src/guardian/prompt.ts +379 -0
- package/src/guardian/reviewer.ts +599 -0
- package/src/guardian/types.ts +149 -0
- package/src/guardian/verdict.ts +211 -0
- package/src/pi/index.ts +13 -0
- package/src/pi/model-reviewer.ts +235 -0
- package/src/pi/transcript.ts +524 -0
- package/src/policy/dangerous-command.ts +312 -0
- package/src/policy/path-policy.ts +501 -0
- package/src/runtime/index.ts +1 -0
- package/src/runtime/permission-engine.ts +474 -0
- package/src/sandbox/config.ts +188 -0
- package/src/sandbox/controller.ts +354 -0
- package/src/sandbox/index.ts +26 -0
- package/src/sandbox/runtime.ts +28 -0
- package/src/sandbox/types.ts +125 -0
- package/src/state/config-store.ts +580 -0
- package/src/state/index.ts +2 -0
- package/src/tools/bash.ts +101 -0
- package/src/tools/gate.ts +74 -0
- package/src/tools/index.ts +2 -0
- package/vendor/openai-codex/NOTICE +6 -0
- package/vendor/openai-codex/README.md +17 -0
- package/vendor/openai-codex/guardian/policy.md +42 -0
- 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.
|