@schuettc/pi-auto-review 0.15.2-schuettc.1
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/CHANGELOG.md +7 -0
- package/LICENSE +21 -0
- package/README.md +441 -0
- package/package.json +61 -0
- package/src/broker/broker.ts +336 -0
- package/src/broker/circuit-breaker.ts +61 -0
- package/src/broker/grants.ts +105 -0
- package/src/broker/index.ts +30 -0
- package/src/broker/overrides.ts +216 -0
- package/src/broker/service.ts +50 -0
- package/src/broker/types.ts +146 -0
- package/src/config.json +19 -0
- package/src/index.ts +2778 -0
- package/src/integrations/sandbox.ts +99 -0
- package/src/path-surfaces.ts +31 -0
- package/src/policy-audit/classifier.ts +216 -0
- package/src/policy-audit/index.ts +174 -0
- package/src/policy-audit/report.ts +337 -0
- package/src/policy-audit/store.ts +358 -0
- package/src/policy.ts +1808 -0
- package/src/ui-auto-confirm.ts +355 -0
- package/src/user-feedback.ts +757 -0
package/CHANGELOG.md
ADDED
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,441 @@
|
|
|
1
|
+
# @erichll/pi-auto-review
|
|
2
|
+
|
|
3
|
+
A fail-closed, model-backed boundary reviewer for the Pi coding agent.
|
|
4
|
+
|
|
5
|
+
The extension participates in `@gotgenes/pi-permission-system` as the
|
|
6
|
+
`pi-auto-review` authorizer and exposes a process-local broker for OS sandbox
|
|
7
|
+
adapters. It is an authorizer *inside* the permission system, so installing
|
|
8
|
+
that dependency is a hard prerequisite (see [Install and enable](#install-and-enable)). The npm package and reviewer model have separate names:
|
|
9
|
+
|
|
10
|
+
- package: `@erichll/pi-auto-review`
|
|
11
|
+
- authorizer: `pi-auto-review`
|
|
12
|
+
- default reviewer model: `codex-auto-review`
|
|
13
|
+
|
|
14
|
+
## Contents
|
|
15
|
+
|
|
16
|
+
- [Install and enable](#install-and-enable)
|
|
17
|
+
- [Security model](#security-model)
|
|
18
|
+
- [Configuration](#configuration)
|
|
19
|
+
- [Deadlines and retries](#deadlines-and-retries)
|
|
20
|
+
- [Operator feedback and exact retry](#operator-feedback-and-exact-retry)
|
|
21
|
+
- [Boundary broker API](#boundary-broker-api)
|
|
22
|
+
- [Reviewer context and token budgets](#reviewer-context-and-token-budgets)
|
|
23
|
+
- [Sandbox integration](#sandbox-integration)
|
|
24
|
+
- [Trust boundary](#trust-boundary)
|
|
25
|
+
- [Permission policy audit](#permission-policy-audit)
|
|
26
|
+
- [Telemetry](#telemetry)
|
|
27
|
+
- [Real-model smoke test](#real-model-smoke-test)
|
|
28
|
+
|
|
29
|
+
## Install and enable
|
|
30
|
+
|
|
31
|
+
> **Prerequisite:** pi-auto-review is an authorizer inside
|
|
32
|
+
> `@gotgenes/pi-permission-system`. Pi does not auto-install peer packages, so
|
|
33
|
+
> install the permission system separately (once per machine) before this
|
|
34
|
+
> extension. This release line supports permission-system 28.x and 29.x:
|
|
35
|
+
|
|
36
|
+
Node.js 22.13.0 or newer is required. Permission auditing uses Node's built-in
|
|
37
|
+
`node:sqlite`; it does not require a SQLite CLI, system SQLite library, or npm
|
|
38
|
+
SQLite package.
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
pi install npm:@gotgenes/pi-permission-system
|
|
42
|
+
pi install npm:@erichll/pi-auto-review
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Install the package outside the agent-writable workspace (see
|
|
46
|
+
[Trust boundary](#trust-boundary)):
|
|
47
|
+
|
|
48
|
+
Add it to the permission-system authorizer chain:
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"authorizerChain": ["pi-auto-review"]
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
The configured reviewer provider and model must also be registered in Pi.
|
|
57
|
+
|
|
58
|
+
## Security model
|
|
59
|
+
|
|
60
|
+
Requests pass through these controls in order:
|
|
61
|
+
|
|
62
|
+
1. deterministic hard denies;
|
|
63
|
+
2. bounded model review;
|
|
64
|
+
3. the local permission terminal when required; and
|
|
65
|
+
4. an exact, expiring, one-use grant for an external sandbox adapter.
|
|
66
|
+
|
|
67
|
+
The model cannot override hard denies or grant authority directly. External
|
|
68
|
+
adapters must consume the exact grant before retrying an operation. Changing
|
|
69
|
+
the command, path, resolved path, destination, cwd, agent, or tool input
|
|
70
|
+
invalidates that grant.
|
|
71
|
+
|
|
72
|
+
Permission-system downgrades authorizer allows on `path` and
|
|
73
|
+
`external_directory` to `defer`. In an interactive TUI,
|
|
74
|
+
`autoConfirmBoundedAllows` can bind the exact model allow to the immediately
|
|
75
|
+
following recognized permission dialog. The bridge is request-ID-bound,
|
|
76
|
+
expires after ten seconds, and is consumed once. Mode, component, request, or
|
|
77
|
+
event-order mismatches leave the original human dialog in place.
|
|
78
|
+
|
|
79
|
+
Automatic review stops for the current turn after three consecutive denials or
|
|
80
|
+
ten denials in the last fifty reviews. An explicit denial tells the agent that
|
|
81
|
+
automatic policy denied the request (not a human click), not to rephrase or
|
|
82
|
+
circumvent the same action, and points to `/auto-review-approve` for an exact
|
|
83
|
+
non-critical reviewer retry or `/auto-review-break-glass` for a critical model
|
|
84
|
+
denial. Local deterministic hard denies never offer an override command.
|
|
85
|
+
|
|
86
|
+
Deterministic hard denies cover recursive forced wipes of `/`, `~`, and
|
|
87
|
+
`$HOME`. A named path under `/home/...` is reviewed by the model as high-risk,
|
|
88
|
+
not treated as a home-directory wipe.
|
|
89
|
+
|
|
90
|
+
## Configuration
|
|
91
|
+
|
|
92
|
+
Configuration is resolved in this order:
|
|
93
|
+
|
|
94
|
+
1. package defaults in `src/config.json`;
|
|
95
|
+
2. optional trusted user overlay at
|
|
96
|
+
`~/.pi/agent/extensions/pi-auto-review/config.json`; and
|
|
97
|
+
3. optional project tighten-only settings at `.pi/pi-auto-review.json`.
|
|
98
|
+
|
|
99
|
+
Use the user-global file for normal customization. It may set any legal key:
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"model": "provider/reviewer-model",
|
|
104
|
+
"autoConfirmBoundedAllows": ["external_directory", "path"]
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
For a complete `@gotgenes/pi-permission-system` config that wires
|
|
109
|
+
`pi-auto-review` into the authorizer chain — a copyable baseline covering
|
|
110
|
+
read/write/edit, a read-only bash allowlist, an MCP discovery policy, and a
|
|
111
|
+
`path` deny block for secret and credential files — see
|
|
112
|
+
[`examples/pi-permission-system.config.example.json`](examples/pi-permission-system.config.example.json).
|
|
113
|
+
|
|
114
|
+
Package defaults:
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
{
|
|
118
|
+
"model": "codex-auto-review",
|
|
119
|
+
"reasoning": "low",
|
|
120
|
+
"timeoutMs": 90000,
|
|
121
|
+
"maxTokens": 256,
|
|
122
|
+
"retries": 2,
|
|
123
|
+
"maxUserTranscriptTokens": 1200,
|
|
124
|
+
"maxToolTranscriptTokens": 1200,
|
|
125
|
+
"maxRelevantResultTokens": 800,
|
|
126
|
+
"maxReviewerInputTokens": 8192,
|
|
127
|
+
"breakGlassEnabled": true,
|
|
128
|
+
"failureMode": "deny",
|
|
129
|
+
"grantTtlMs": 60000,
|
|
130
|
+
"autoConfirmBoundedAllows": ["external_directory", "path"],
|
|
131
|
+
"policyAudit": {
|
|
132
|
+
"enabled": true,
|
|
133
|
+
"retentionDays": 180
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
`failureMode: "deny"` is the default. `"defer"` falls through to the human
|
|
139
|
+
terminal. Set `autoConfirmBoundedAllows` to `[]` to keep every bounded allow
|
|
140
|
+
manual.
|
|
141
|
+
|
|
142
|
+
Project configuration may only lower timeouts, token/evidence limits, retries,
|
|
143
|
+
and grant TTL, set `failureMode` to `"deny"`, set `breakGlassEnabled` to
|
|
144
|
+
`false`, or remove auto-confirmed surfaces. It cannot re-enable break glass,
|
|
145
|
+
select a model, raise a trusted limit, or weaken fail-closed behavior. Invalid
|
|
146
|
+
configuration disables the reviewer for that session.
|
|
147
|
+
|
|
148
|
+
The trusted user config may set `policyAudit.enabled` and a retention of
|
|
149
|
+
1–3,650 days. Project config may only set `enabled: false` or shorten the
|
|
150
|
+
inherited retention; it cannot re-enable globally disabled collection or
|
|
151
|
+
extend retention.
|
|
152
|
+
|
|
153
|
+
### Deadlines and retries
|
|
154
|
+
|
|
155
|
+
`timeoutMs` is one deadline shared by model resolution, authentication, model
|
|
156
|
+
attempts, and retry delays. Each attempt receives only the remaining time.
|
|
157
|
+
Provider-internal retries are disabled, and a review makes at most two actual
|
|
158
|
+
model calls even when the public `retries` value is higher.
|
|
159
|
+
|
|
160
|
+
Valid decisions, output-length stops, timeouts, aborts, authentication/model/
|
|
161
|
+
request errors, and unknown failures do not retry. Empty, non-JSON, or
|
|
162
|
+
schema-invalid output and recognized connection, temporary 5xx, or 429
|
|
163
|
+
failures may retry once when the retry budget and deadline allow it. A
|
|
164
|
+
`Retry-After` above five seconds or beyond the remaining deadline fails closed.
|
|
165
|
+
Format retries preserve the canonical request and selected evidence and append
|
|
166
|
+
only a fixed, budget-checked schema correction.
|
|
167
|
+
|
|
168
|
+
## Operator feedback and exact retry
|
|
169
|
+
|
|
170
|
+
Interactive sessions show the current permission check in a single widget
|
|
171
|
+
above the editor. Each check first shows its surface, compact target, and the
|
|
172
|
+
dynamically configured reviewer model, then replaces that content in place
|
|
173
|
+
with the outcome, target and rationale, model, token usage, duration, and any
|
|
174
|
+
extra call count. A new check replaces the previous result; the latest result
|
|
175
|
+
remains visible until then and is cleared when the session changes or shuts
|
|
176
|
+
down. Concurrent older checks cannot overwrite the most recently started one.
|
|
177
|
+
|
|
178
|
+
Every request still has its own model call, verdict, grant, local confirmation,
|
|
179
|
+
and audit record. No new review-result transcript entries are written. Existing
|
|
180
|
+
`pi-auto-review` entries in historical sessions remain renderable. Non-TUI
|
|
181
|
+
modes retain best-effort notifications, and a failed TUI widget update falls
|
|
182
|
+
back to the same notification path. UI delivery never changes the authorization
|
|
183
|
+
result.
|
|
184
|
+
|
|
185
|
+
In an interactive TUI, `/auto-review-approve` lists up to ten recent
|
|
186
|
+
non-critical model denials from the current session. Selecting one asks the
|
|
187
|
+
agent to retry exactly that request. The old `/approve` command is not
|
|
188
|
+
registered.
|
|
189
|
+
The host-generated override:
|
|
190
|
+
|
|
191
|
+
- binds the complete request hash;
|
|
192
|
+
- expires after 60 seconds and is consumed once;
|
|
193
|
+
- remains separate from untrusted user/tool evidence;
|
|
194
|
+
- still goes through deterministic hard denies and model review; and
|
|
195
|
+
- cannot be reissued while a previous authorization for it is pending, or
|
|
196
|
+
again after consumption until the same action is denied afresh (one approval
|
|
197
|
+
per denial).
|
|
198
|
+
|
|
199
|
+
It is authorization evidence, not a direct allow.
|
|
200
|
+
|
|
201
|
+
`/auto-review-break-glass` is a separate, high-friction path for model denials
|
|
202
|
+
whose risk level is `critical`. It lists only critical model denials from the
|
|
203
|
+
same session made in the last five minutes. After showing the rationale,
|
|
204
|
+
surface, cwd, command or target summary, and request-hash fingerprint, it
|
|
205
|
+
requires an explicit confirmation and a random `BREAK-GLASS <CODE>` phrase
|
|
206
|
+
within 60 seconds. Successful confirmation creates a 60-second, one-use
|
|
207
|
+
authorization bound to the complete request hash, session, and original
|
|
208
|
+
request ID. The request hash deliberately excludes the per-attempt `id` and
|
|
209
|
+
`toolCallId` fields: the exact retry is a brand-new model tool call issued in
|
|
210
|
+
a later turn, so retry-minted identifiers cannot participate in the match.
|
|
211
|
+
The exact retry reruns local hard-deny checks, then allows directly without
|
|
212
|
+
calling the reviewer and, for sandbox adapters, still issues the normal
|
|
213
|
+
one-shot grant. A break-glass allow resets the turn circuit breaker (a human
|
|
214
|
+
re-authorized the scope), and break glass can be disabled in trusted or
|
|
215
|
+
project configuration with `breakGlassEnabled: false`.
|
|
216
|
+
|
|
217
|
+
## Boundary broker API
|
|
218
|
+
|
|
219
|
+
The extension publishes a process-local service at:
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
Symbol.for("pi-auto-review:boundary-approval-broker")
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
Adapters should use the exported helper:
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
import {
|
|
229
|
+
getBoundaryBroker,
|
|
230
|
+
type BoundaryRequest,
|
|
231
|
+
} from "@erichll/pi-auto-review";
|
|
232
|
+
|
|
233
|
+
const request: BoundaryRequest = {
|
|
234
|
+
id: "sandbox-runtime-query-id",
|
|
235
|
+
source: "sandbox-runtime",
|
|
236
|
+
surface: "network",
|
|
237
|
+
operation: "connect",
|
|
238
|
+
cwd: "/workspace/project",
|
|
239
|
+
command: "npm install",
|
|
240
|
+
destination: "registry.npmjs.org:443",
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
const broker = getBoundaryBroker();
|
|
244
|
+
const decision = await broker?.review(request, {
|
|
245
|
+
sessionId: "pi-session-id",
|
|
246
|
+
scopeKey: "pi-session-id:turn-id",
|
|
247
|
+
issueGrant: true,
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
// A break-glass allow includes structured provenance:
|
|
251
|
+
// decision.authorization = {
|
|
252
|
+
// kind: "break-glass",
|
|
253
|
+
// originalRequestId: "...",
|
|
254
|
+
// confirmedAt: 0,
|
|
255
|
+
// };
|
|
256
|
+
|
|
257
|
+
if (
|
|
258
|
+
decision?.kind === "allow" &&
|
|
259
|
+
decision.grant &&
|
|
260
|
+
broker?.consumeGrant(request, "pi-session-id", decision.grant.token)
|
|
261
|
+
) {
|
|
262
|
+
// Retry this exact operation once inside the OS sandbox.
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Grants expire after `grantTtlMs` and cannot be reused.
|
|
267
|
+
|
|
268
|
+
## Reviewer context and token budgets
|
|
269
|
+
|
|
270
|
+
The reviewer receives one compact canonical request plus bounded, explicitly
|
|
271
|
+
untrusted evidence. Selection is deterministic rather than semantic:
|
|
272
|
+
|
|
273
|
+
- the latest raw user message is the authorization anchor;
|
|
274
|
+
- older user messages require an exact request/tool/requester association or an
|
|
275
|
+
exact trusted retry;
|
|
276
|
+
- tool calls require an exact tool-call ID, exact structured request fields, a
|
|
277
|
+
surface profile, or a security-combination classification; and
|
|
278
|
+
- selected results stay paired with their producer and are limited to exact
|
|
279
|
+
results, deletion prechecks, Git push context, matching branch protection,
|
|
280
|
+
and Sandbox Runtime process evidence.
|
|
281
|
+
|
|
282
|
+
Unrelated reads, directory listings, builds, tests, assistant prose, and old
|
|
283
|
+
task history are excluded. Compaction and branch summaries are labeled as
|
|
284
|
+
non-authorization context and are never injected as user intent. The host does
|
|
285
|
+
not rewrite a model allow from regex matches on user text, vague continuations,
|
|
286
|
+
or a computed authorization ceiling; those judgments stay with the reviewer
|
|
287
|
+
model. Hard denies still terminate before the model.
|
|
288
|
+
|
|
289
|
+
The current operation appears once as stable, key-sorted JSON. Duplicate exact
|
|
290
|
+
tool-call arguments collapse to an ID/name/reason linkage shell, while fields
|
|
291
|
+
not represented by the request remain available as evidence. This compact
|
|
292
|
+
reviewer representation does not affect request hashes, grants, overrides, or
|
|
293
|
+
audit evidence.
|
|
294
|
+
|
|
295
|
+
`maxReviewerInputTokens` covers the fixed policy, canonical request, override,
|
|
296
|
+
evidence, omissions, JSON framing, and a 64-token provider-framing reserve. Its
|
|
297
|
+
legal range is 2,048–32,768. Because no matching tokenizer is bundled, the
|
|
298
|
+
`conservative:utf8` estimator counts every UTF-8 byte as one token.
|
|
299
|
+
|
|
300
|
+
When over budget, the host removes secondary reasons, older structured tool
|
|
301
|
+
matches, then optional producer/result units, re-estimating after each step. It
|
|
302
|
+
never silently removes the canonical request, exact override, latest user
|
|
303
|
+
evidence, security-combination evidence, exact tool linkage, or a required
|
|
304
|
+
surface profile. If mandatory evidence does not fit, review fails closed before
|
|
305
|
+
calling the model. More than four security-combination candidates also fails
|
|
306
|
+
closed locally.
|
|
307
|
+
|
|
308
|
+
## Sandbox integration
|
|
309
|
+
|
|
310
|
+
This package exposes the broker contract but does not intercept OS sandbox
|
|
311
|
+
events itself. Adapters translate a concrete boundary into a `BoundaryRequest`
|
|
312
|
+
and consume the exact grant before allowing it.
|
|
313
|
+
|
|
314
|
+
This monorepo's `pi-sandbox` adapter uses Anthropic Sandbox Runtime. Filesystem
|
|
315
|
+
policy is static and fail-closed; unmatched public network destinations use the
|
|
316
|
+
broker for one connection. Each Bash command or built-in subagent session owns
|
|
317
|
+
an independent Sandbox Runtime broker process. Adapter implementations should
|
|
318
|
+
use the package's `./sandbox` export and must not create broad permanent rules
|
|
319
|
+
in `.pi/sandbox.json`.
|
|
320
|
+
|
|
321
|
+
## Trust boundary
|
|
322
|
+
|
|
323
|
+
Production copies must live outside the agent-writable workspace. Pi installs
|
|
324
|
+
user npm and Git packages under `~/.pi/agent/npm/` and `~/.pi/agent/git/`.
|
|
325
|
+
Workspace-loaded copies are rejected unless local development explicitly opts
|
|
326
|
+
in:
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
PI_AUTO_REVIEW_ALLOW_UNTRUSTED_DEV=1 pi --approve
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
Writes to the installed reviewer package, its user-global configuration,
|
|
333
|
+
project and global security configuration, and the global audit directory are
|
|
334
|
+
deterministically denied.
|
|
335
|
+
|
|
336
|
+
## Permission policy audit
|
|
337
|
+
|
|
338
|
+
The extension observes terminal `permissions:decision` broadcasts and stores
|
|
339
|
+
only daily, redacted aggregates. Collection is enabled by default and retains
|
|
340
|
+
180 days. It starts when this version first initializes successfully; no
|
|
341
|
+
permission-system JSONL or RTK history is read or imported.
|
|
342
|
+
|
|
343
|
+
Before storage, Bash values become observed command templates such as
|
|
344
|
+
`git status --short`, `cat *`, or `npm test * --token *`. URLs, paths,
|
|
345
|
+
assignments, quoted values, and option values are replaced with `*`; safe bare
|
|
346
|
+
command words remain in plaintext so the report can emit a matching rule.
|
|
347
|
+
Paths used for path-surface statistics become only
|
|
348
|
+
`workspace`, `temp`, `home`, `external`, `sensitive`, or `unknown`. Request IDs,
|
|
349
|
+
project locations, and matched-rule patterns are HMACed. Syntactically valid
|
|
350
|
+
custom tool names are also retained in plaintext; invalid names stay anonymous
|
|
351
|
+
as `<custom-tool>`. The database never stores raw commands, raw paths,
|
|
352
|
+
URLs, credentials, or non-Bash tool arguments and inputs. Because safe bare Bash
|
|
353
|
+
words are retained, command templates can contain non-secret filenames or
|
|
354
|
+
project-specific labels; inspect suggestions before copying them.
|
|
355
|
+
|
|
356
|
+
Data lives at
|
|
357
|
+
`~/.pi/agent/extensions/pi-auto-review/policy-audit.sqlite`, beside an
|
|
358
|
+
owner-only HMAC key. The directory is mode `0700`; the key, database, WAL, and
|
|
359
|
+
SHM are mode `0600`. Initialization, lock, write, or corruption failures disable
|
|
360
|
+
auditing and warn once without changing any permission result. A corrupt
|
|
361
|
+
database is not deleted or rebuilt automatically. Disable new collection with:
|
|
362
|
+
|
|
363
|
+
```json
|
|
364
|
+
{
|
|
365
|
+
"policyAudit": { "enabled": false }
|
|
366
|
+
}
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
Run `/auto-review-policy-audit` for a durable TUI report that is not sent to the
|
|
370
|
+
LLM. Options are `--days 1..retention`, `--top 1..50`, `--min-count >=1`, and
|
|
371
|
+
`--scope current|all`; defaults are `30`, `20`, `5`, and `current`.
|
|
372
|
+
|
|
373
|
+
In addition to the redacted statistics, the report proposes copyable
|
|
374
|
+
permission-system fragments. `--scope current` targets
|
|
375
|
+
`.pi/extensions/pi-permission-system/config.json`; `--scope all` targets
|
|
376
|
+
`~/.pi/agent/extensions/pi-permission-system/config.json`. The extension never
|
|
377
|
+
reads, edits, or rewrites either file. Merge suggested Bash patterns into the
|
|
378
|
+
existing `permission.bash` map and place the narrow allow entries after broader
|
|
379
|
+
matching ask entries, because permission-system uses last-match-wins.
|
|
380
|
+
|
|
381
|
+
Suggestions are discovered entirely from observed audit data; there is no
|
|
382
|
+
built-in tool, executable, Git action, package-manager action, or read-only
|
|
383
|
+
command catalog. Every valid observed permission surface and reliably templated
|
|
384
|
+
Bash command can qualify, including previously unknown tools and write
|
|
385
|
+
operations. Environment prefixes, compound syntax, pipelines, redirection,
|
|
386
|
+
path executables, and unreliable parsing block that Bash template. Forwarded
|
|
387
|
+
requests are statistics-only because the requester's cwd is not available. A
|
|
388
|
+
candidate needs at least `--min-count` successful ask-path approvals and no
|
|
389
|
+
denial, gate error, unavailable confirmation, blocked structural variant, or
|
|
390
|
+
forwarded-only evidence in the selected window. Existing policy/infrastructure
|
|
391
|
+
allows do not count as evidence of user friction. Repeated approval is evidence
|
|
392
|
+
of user preference, not independent proof that a capability is safe.
|
|
393
|
+
|
|
394
|
+
Schema v2 migrates v1 aggregates transactionally. Old totals remain visible,
|
|
395
|
+
`collecting_since` is preserved, and `recommendations_since` records when safe
|
|
396
|
+
recommendation evidence began; pre-migration data cannot produce a suggestion.
|
|
397
|
+
|
|
398
|
+
The report is an extension-owned custom entry. It is deliberately not exposed
|
|
399
|
+
as an Agent tool or packaged skill, so neither a tool schema nor skill metadata
|
|
400
|
+
is added to the model context. Permission changes remain a separate, explicit
|
|
401
|
+
user operation.
|
|
402
|
+
|
|
403
|
+
`PI_AUTO_REVIEW_AUDIT_FILE` remains a test/release observation sink. It is not
|
|
404
|
+
an input to this audit and supplies no RTK token or parsing metrics.
|
|
405
|
+
|
|
406
|
+
## Telemetry
|
|
407
|
+
|
|
408
|
+
Every actual model call emits an internal `review_attempt`; each approval emits
|
|
409
|
+
one `review_complete`. Events contain stable status/error classes, timings,
|
|
410
|
+
usage counters, evidence metadata, and prompt-part counts. They do not contain
|
|
411
|
+
prompt or response text, provider errors, credentials, headers, or URL query
|
|
412
|
+
values. Usage is marked `unknown_provenance` when pi-ai cannot distinguish
|
|
413
|
+
provider counters from initialized values, and `unavailable` when absent.
|
|
414
|
+
|
|
415
|
+
## Real-model smoke test
|
|
416
|
+
|
|
417
|
+
For a controlled real-model smoke test, load only the provider, reviewer,
|
|
418
|
+
sandbox, and audit listener:
|
|
419
|
+
|
|
420
|
+
```bash
|
|
421
|
+
PI_AUTO_REVIEW_ALLOW_UNTRUSTED_DEV=1 \
|
|
422
|
+
PI_AUTO_REVIEW_SMOKE_AUDIT_PATH=/tmp/pi-auto-review-smoke-audit.jsonl \
|
|
423
|
+
PI_AUTO_REVIEW_BASELINE_ID=reviewer-check \
|
|
424
|
+
PI_AUTO_REVIEW_BASELINE_CACHE_STATE=cold \
|
|
425
|
+
PI_AUTO_REVIEW_BASELINE_RUN_ORDER=1 \
|
|
426
|
+
PI_AUTO_REVIEW_BASELINE_SAMPLE_SET=reviewer-v1 \
|
|
427
|
+
PI_AUTO_REVIEW_SMOKE_TRIGGER=baseline-v1 \
|
|
428
|
+
pi --no-extensions --no-skills --no-prompt-templates --no-context-files \
|
|
429
|
+
--no-builtin-tools --no-session --print \
|
|
430
|
+
--extension /trusted/path/to/provider/extensions/index.ts \
|
|
431
|
+
--extension ./packages/pi-auto-review/src/index.ts \
|
|
432
|
+
--extension ./packages/pi-sandbox/src/index.ts \
|
|
433
|
+
--extension ./scripts/real-model-smoke-audit.ts \
|
|
434
|
+
--model provider/reviewer-model \
|
|
435
|
+
"Run the configured synthetic reviewer baseline sample, then reply done."
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
The listener submits filesystem-write, network, delete, Git-push, and forwarded
|
|
439
|
+
subagent boundaries. No represented operation is executed; the main-agent
|
|
440
|
+
request is aborted after the samples finish. `--no-builtin-tools` ensures Bash
|
|
441
|
+
comes from `pi-sandbox` rather than Pi's built-in implementation.
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@schuettc/pi-auto-review",
|
|
3
|
+
"version": "0.15.2-schuettc.1",
|
|
4
|
+
"description": "Fail-closed, model-backed approval broker for Pi: deterministically hard-denies dangerous operations, reviews dangerous boundaries with a reviewer model, and issues one-shot expiring grants that OS sandbox adapters must consume before retrying.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"pi-package",
|
|
9
|
+
"pi-extension",
|
|
10
|
+
"pi",
|
|
11
|
+
"security",
|
|
12
|
+
"sandbox"
|
|
13
|
+
],
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/erichll/pi-packages.git",
|
|
17
|
+
"directory": "packages/pi-auto-review"
|
|
18
|
+
},
|
|
19
|
+
"homepage": "https://github.com/erichll/pi-packages/tree/main/packages/pi-auto-review",
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/erichll/pi-packages/issues"
|
|
22
|
+
},
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"engines": {
|
|
27
|
+
"node": ">=22.13.0"
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"src",
|
|
31
|
+
"CHANGELOG.md",
|
|
32
|
+
"README.md",
|
|
33
|
+
"LICENSE"
|
|
34
|
+
],
|
|
35
|
+
"exports": {
|
|
36
|
+
".": "./src/index.ts",
|
|
37
|
+
"./broker": "./src/broker/index.ts",
|
|
38
|
+
"./sandbox": "./src/integrations/sandbox.ts"
|
|
39
|
+
},
|
|
40
|
+
"pi": {
|
|
41
|
+
"extensions": [
|
|
42
|
+
"./src/index.ts"
|
|
43
|
+
]
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"check": "tsc -p tsconfig.json --noEmit",
|
|
47
|
+
"test": "node --disable-warning=ExperimentalWarning --experimental-loader ./test/typescript-loader.mjs --test test/*.test.ts"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"@earendil-works/pi-ai": "^0.84.4",
|
|
51
|
+
"@earendil-works/pi-coding-agent": "^0.84.4",
|
|
52
|
+
"@gotgenes/pi-permission-system": ">=29.3.0 <31.0.0"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@earendil-works/pi-ai": "^0.84.4",
|
|
56
|
+
"@earendil-works/pi-coding-agent": "^0.84.4",
|
|
57
|
+
"@gotgenes/pi-permission-system": "29.3.0",
|
|
58
|
+
"@types/node": "^26.2.0",
|
|
59
|
+
"typescript": "^6.0.3"
|
|
60
|
+
}
|
|
61
|
+
}
|