mirror of
https://github.com/SikongJueluo/pi-extensions.git
synced 2026-10-05 11:52:55 +08:00
fix(pi-permission-inner-cmd): unwrap timeout in real-world command forms
- accept GNU timeout durations without a unit suffix and with decimals (timeout 240 …) - detect the wrapper on details.command and strip it from the full command so scaffolded inputs (cd … && timeout … | tail) unwrap - re-evaluate the full de-wrapped compound so sibling commands cannot hide behind the wrapper allow - defer fail-closed when the unit is not a unique substring of the full command - amend ADR 0001 with the relaxed grammar and the scaffolded-command handling
This commit is contained in:
@@ -15,17 +15,40 @@ Proceed only when all evidence agrees:
|
||||
- the request and recovered tool call both identify the native `bash` tool;
|
||||
- the tool-call ID has exactly one match within the latest assistant message that contains it (a cross-message reuse resolves to the latest, which is the call being authorized);
|
||||
- `arguments.command` is a string;
|
||||
- the complete input matches the strict wrapper grammar;
|
||||
- the ask-triggering unit (`details.command`) matches the wrapper grammar;
|
||||
- the inner command is not another recognized wrapper.
|
||||
|
||||
V0.1 recognizes only:
|
||||
V0.1 recognizes:
|
||||
|
||||
```regex
|
||||
^timeout[ \t]+([1-9][0-9]*[smhd])[ \t]+(.+)$
|
||||
^timeout[ \t]+([1-9][0-9]*(?:\.[0-9]+)?[smhd]?)[ \t]+(.+)$
|
||||
```
|
||||
|
||||
The duration follows GNU timeout's grammar: a positive number (integer or
|
||||
decimal) with an optional unit `s`/`m`/`h`/`d` (default seconds), so a bare
|
||||
integer such as `timeout 240 cmd` is accepted. The duration format is irrelevant
|
||||
to unwrap soundness — the duration is discarded and only the inner command is
|
||||
re-evaluated — so the full numeric grammar is allowed. `0`/leading-zero, `ms`,
|
||||
and flags remain excluded. (Amended from the original unit-required grammar
|
||||
after `timeout 240 …` was seen in real usage.)
|
||||
|
||||
The complete inner command is re-evaluated through the Deterministic Permission Policy. Map `allow` to `allow`, `deny` to `deny`, and `ask` to `defer`. Missing or ambiguous session evidence, forwarded requests, shell aliases, unsupported `timeout` options, nested wrappers, parse failures, and exceptions all produce `defer`.
|
||||
|
||||
**Scaffolded commands (amended).** The recovered full command may be a compound
|
||||
that does not start with the wrapper — e.g. a subagent scaffold
|
||||
`cd … && timeout … | tail; echo EXIT`. Detection therefore runs on
|
||||
`details.command` (the unit the permission system isolated, always
|
||||
wrapper-leading). The wrapper is stripped from the *full* command (the unit
|
||||
text is replaced by its unwrapped inner, required to occur exactly once) and the
|
||||
entire de-wrapped compound is re-evaluated through the Deterministic Permission
|
||||
Policy, which decomposes it into units and keeps the most restrictive — so
|
||||
sibling commands are still judged and cannot hide behind the wrapper's allow. If
|
||||
the unit is not a recognized wrapper, cannot be located exactly once, or the
|
||||
re-evaluation is not `allow`, the authorizer defers fail-closed. (The original
|
||||
design detected on the full command only, which missed every scaffolded command;
|
||||
`details.command` is now used for *detection and locating* only — judgment still
|
||||
runs on the full command, preserving the "never trust a truncated unit" rule.)
|
||||
|
||||
## Consequences
|
||||
|
||||
This avoids changing permission-system and avoids parsing authorization evidence from the human-facing `details.message`. It deliberately supports fewer contexts: forwarded and non-native shell calls continue through the existing authority chain.
|
||||
|
||||
Reference in New Issue
Block a user