mirror of
https://github.com/SikongJueluo/pi-extensions.git
synced 2026-10-05 11:52:55 +08:00
feat(pi-permission-inner-cmd): recognize bare time wrapper as transparent
- add time handler that unwraps the bare reserved-word form time <command> and re-evaluates the full de-wrapped compound like timeout (ADR 0009) - defer fail-closed on dash-leading modifiers, bare time, and nested wrappers in both directions - generalize isRecognizedWrapper to timeout and time, and classifyWrapper to recognized/unsupported/other with a wrapper name - rename defer events to inner_cmd.nested_wrapper and inner_cmd.unsupported_wrapper_syntax with a wrapper field - extract stripWrapperUnit into handlers/strip.ts for shared use
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
---
|
||||
status: accepted
|
||||
---
|
||||
|
||||
# The bare `time` wrapper unwraps like `timeout` (ADR 0009)
|
||||
|
||||
`pi-permission-inner-cmd` recognized only `timeout <duration> <command>`
|
||||
(ADR 0001). `time <command>` poses the same authorization question — a
|
||||
wrapper around an inner command — and appears routinely in agent Bash calls
|
||||
(`time pnpm build`). A wrapper qualifies for unwrapping only when its
|
||||
modifier args are transparent (CONTEXT.md, Wrappers).
|
||||
|
||||
## Decision
|
||||
|
||||
Recognize exactly the bare reserved-word form:
|
||||
|
||||
```regex
|
||||
^time[ \t]+(?![-\s])(.+)$
|
||||
```
|
||||
|
||||
It is transparent: `time` runs the inner command unchanged and only adds
|
||||
timing, so the `timeout` unwrap pipeline applies verbatim — strip the wrapper
|
||||
from the FULL command (scaffold included) and re-evaluate the whole de-wrapped
|
||||
compound, so sibling commands stay under judgment. An inner `allow` allows,
|
||||
anything else defers fail-closed.
|
||||
|
||||
Everything else that begins with `time` defers with
|
||||
`inner_cmd.unsupported_wrapper_syntax`:
|
||||
|
||||
- **any dash-leading modifier** (`time -p ls`, `time -- ls`, `time -o FILE ls`).
|
||||
The command string cannot distinguish the Bash reserved word (which accepts
|
||||
only `-p`) from `/usr/bin/time` (whose `-o FILE` writes a file and `-v`
|
||||
dumps environment-bearing stats), and the lookahead also blocks regex
|
||||
backtracking from smuggling a leading space past a wide separator. A
|
||||
modifier arg is therefore treated as potentially non-transparent until
|
||||
individually proven otherwise.
|
||||
- **a bare `time`** — it times the shell itself; there is no inner command to
|
||||
re-evaluate.
|
||||
|
||||
`/usr/bin/time cmd` (full path) is not claimed by any handler and defers
|
||||
silently like any unrecognized command.
|
||||
|
||||
## Generalizations that ride along
|
||||
|
||||
- `isRecognizedWrapper` now covers timeout ∪ time, so `time timeout 10 cmd`,
|
||||
`timeout 10 time cmd`, and `time time cmd` all defer at most-one-level
|
||||
nested wrappers (previously the check was timeout-only).
|
||||
- The defer events generalize from `inner_cmd.nested_timeout` /
|
||||
`inner_cmd.unsupported_timeout_syntax` to `inner_cmd.nested_wrapper` /
|
||||
`inner_cmd.unsupported_wrapper_syntax`, each carrying a `wrapper:
|
||||
"timeout" | "time"` field, so future wrapper handlers reuse the same event
|
||||
names. Downstream analysis joins only on the decisive
|
||||
`inner_cmd.allow|deny` markers and is unaffected.
|
||||
|
||||
## Consequences
|
||||
|
||||
- `time pnpm test` no longer reaches the human dialog / AI judge when the
|
||||
inner command is already allowed.
|
||||
- Handler precedence stays irrelevant: `timeout` and `time` prefixes are
|
||||
disjoint, and both are tried before the claiming non-transparent handlers
|
||||
(`env`, `xargs`).
|
||||
- If `time -p` transparency is ever wanted, it is a one-line grammar change
|
||||
plus tests — recorded here as deliberately out of scope for v0.1.
|
||||
Reference in New Issue
Block a user