mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-10-26 10:45:22 +00:00
feat(permission): integrate auto-review and hard guards
This commit is contained in:
@@ -2,29 +2,21 @@
|
||||
|
||||
## Config File Locations
|
||||
|
||||
One unified config file per scope:
|
||||
Pi Permission System has an ordinary JSONC policy and an independent global hard-guard JSONC policy:
|
||||
|
||||
| Scope | Path |
|
||||
| ------- | ------------------------------------------------------------------------------------------ |
|
||||
| Global | `~/.pi/agent/extensions/pi-permission-system/config.json` (respects `PI_CODING_AGENT_DIR`) |
|
||||
| Project | `<cwd>/.pi/extensions/pi-permission-system/config.json` |
|
||||
| Purpose | Scope | Path |
|
||||
| ------- | ----- | ---- |
|
||||
| Ordinary policy + runtime | Global | `~/.pi/agent/extensions/pi-permission-system/policy.jsonc` |
|
||||
| Ordinary policy override | Project | `<cwd>/.pi/extensions/pi-permission-system/policy.jsonc` |
|
||||
| Hard guards | Global only | `~/.pi/agent/extensions/pi-permission-system/hard-guards.jsonc` |
|
||||
|
||||
Project config overrides global config; per-agent frontmatter overrides both.
|
||||
All paths respect `PI_CODING_AGENT_DIR`. The bundle creates missing global files once with owner-only permissions. It does not overwrite an existing file. If `policy.jsonc` is absent but the old global `config.json` exists, the bundle copies the old content into `policy.jsonc` and leaves the source file intact.
|
||||
|
||||
**Project config requires project trust.**
|
||||
Project and project-agent scopes (both permission policy and runtime config such as `yoloMode`) are loaded only when Pi reports the project as trusted (`ctx.isProjectTrusted()`).
|
||||
In an untrusted directory, only global (and global-agent) config applies, so an untrusted repository cannot loosen your global policy; the extension surfaces a loud warning plus a `project_trust.skipped` review-log entry when it skips a project scope.
|
||||
Grant project trust (or configure `defaultProjectTrust`) to load the project's config; a trust grant reloads project policy on the next `resources_discover` reload.
|
||||
See [migration/0644-project-trust-gating.md](migration/0644-project-trust-gating.md).
|
||||
Project policy overrides global ordinary policy and per-agent YAML frontmatter overrides both. Project policy and project agent definitions are loaded only when Pi reports that project as trusted.
|
||||
|
||||
> **Coming from OpenCode?**
|
||||
> This extension's permission model was inspired by OpenCode's.
|
||||
> See [OpenCode Compatibility](opencode-compatibility.md) for shared concepts, divergences, and a porting guide.
|
||||
Hard guards are deliberately outside this merge. They are global-only and evaluated first, without session rules. A matching hard `deny` is final and cannot be loosened by project policy, per-agent policy, a session grant, or AutoReview. A hard-file `allow` can only form a narrower exception to another pattern in that same hard-guard file. `ask` is invalid in the hard-guard file.
|
||||
|
||||
<!-- -->
|
||||
|
||||
> **Tip:** All `~/.pi/agent` paths shown in this document are defaults.
|
||||
> If the `PI_CODING_AGENT_DIR` environment variable is set, Pi uses that directory instead.
|
||||
> `~/.pi/agent` is the default. When `PI_CODING_AGENT_DIR` is set, Pi uses that directory instead.
|
||||
|
||||
## Merge Precedence
|
||||
|
||||
@@ -65,8 +57,22 @@ This clamp is deny-preserving and, like `yoloMode`, applied at composition; when
|
||||
"exec_command": { "commandArgument": "cmd", "workdirArgument": "workdir" }
|
||||
},
|
||||
|
||||
// Ordered names of registered live-authority chain links (empty = none)
|
||||
"authorizerChain": [],
|
||||
// Unmatched ordinary asks are reviewed before the terminal human prompt.
|
||||
"authorizerChain": ["auto-review"],
|
||||
"autoReview": {
|
||||
"enabled": true,
|
||||
"provider": "openai-codex",
|
||||
"model": "codex-auto-review",
|
||||
"reasoning": "low",
|
||||
"timeoutMs": 90000,
|
||||
"includeBaselinePolicy": true
|
||||
},
|
||||
"analysis": {
|
||||
"enabled": true,
|
||||
"threshold": 500,
|
||||
"retainAnalyzedBatches": 2,
|
||||
"timeoutMs": 90000
|
||||
},
|
||||
|
||||
// Flat permission policy
|
||||
"permission": {
|
||||
@@ -95,6 +101,18 @@ This clamp is deny-preserving and, like `yoloMode`, applied at composition; when
|
||||
> **Note:** Trailing commas are **not** supported.
|
||||
> If parsing fails, the extension falls back to `ask` for all categories.
|
||||
|
||||
## Built-in AutoReview and Count-Based Analysis
|
||||
|
||||
`autoReview.enabled` controls the built-in authorizer named `auto-review`. It only receives requests that ordinary policy resolved to `ask`; it cannot bypass a hard deny. Add `"auto-review"` to `authorizerChain` to make it the primary case-by-case authority. An `allow` or `deny` verdict is final for that request. `defer` continues to the next authorizer and ultimately the human permission dialog.
|
||||
|
||||
The reviewer uses only trusted direct-user transcript evidence and recognized structured answers. Assistant, tool, compaction, and cancelled-answer content cannot authorize an operation. Model lookup, authentication, timeout, malformed output, or internal errors all return `defer`.
|
||||
|
||||
`analysis.threshold` counts completed automatic verdicts, not Pi turns and not deferrals. Each `allow` or `deny` appends one sanitized record under the global extension state directory. Records contain bounded surface/pattern fingerprints and risk/authorization classifications; they omit rationale, raw payload, transcript, and credentials.
|
||||
|
||||
When the count since the last accepted checkpoint reaches the threshold (500 by default), the ledger marks analysis pending. At the next `agent_settled` boundary the extension starts an isolated AgentSession with no tools, extensions, skills, prompt templates, themes, or project context. Its JSON proposal is schema-validated and filtered so authorization-dependent, denied, or high-risk evidence cannot become an unconditional allow candidate.
|
||||
|
||||
A successful proposal advances the checkpoint, is retained according to `retainAnalyzedBatches`, and is delivered with `deliverAs: "followUp"` and `triggerTurn: true` to this conversation. The proposal is advisory only. Neither `policy.jsonc` nor `hard-guards.jsonc` is modified until the user explicitly chooses and confirms rules. Shutdown aborts the running worker but leaves the pending checkpoint durable for the next session.
|
||||
|
||||
## Runtime Knobs
|
||||
|
||||
| Key | Default | Description |
|
||||
@@ -1010,18 +1028,11 @@ Practical guidance:
|
||||
|
||||
## Schema Validation
|
||||
|
||||
Validate your config against the included schema:
|
||||
The package includes two schemas:
|
||||
|
||||
```bash
|
||||
npx --yes ajv-cli@5 validate \
|
||||
-s ./schemas/permissions.schema.json \
|
||||
-d ./config.json
|
||||
```
|
||||
- `schemas/permissions.schema.json` for `policy.jsonc`;
|
||||
- `schemas/hard-guards.schema.json` for `hard-guards.jsonc`.
|
||||
|
||||
**Editor tip:** Add the hosted schema URL as the `$schema` key in your config for autocomplete and validation support:
|
||||
Associate those packaged files with the corresponding JSONC filenames in your editor. Command-line validators that only accept JSON must receive a comment-stripped temporary copy; do not rewrite the user's JSONC merely to validate it.
|
||||
|
||||
```json
|
||||
"$schema": "https://raw.githubusercontent.com/gotgenes/pi-packages/main/packages/pi-permission-system/schemas/permissions.schema.json"
|
||||
```
|
||||
|
||||
The schema is generated from the extension's zod source of truth (`src/config-schema.ts`); regenerate it with `pnpm run gen:schema` after changing the config shape.
|
||||
The ordinary policy schema is generated from `src/config-schema.ts`; regenerate it with `npm run gen:schema` after changing that shape. Keep the hard-guard schema synchronized with `HardGuardPolicyLoader` whenever its accepted document changes.
|
||||
|
||||
Reference in New Issue
Block a user