mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-08-28 16:45:22 +00:00
feat: vendor permission system source
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
---
|
||||
issue: 73
|
||||
issue_title: "node -e command triggers permission prompt despite \"*\": \"allow\" global fallback"
|
||||
---
|
||||
|
||||
# Wildcard matcher fails on multiline bash commands
|
||||
|
||||
## Problem Statement
|
||||
|
||||
When a bash command contains newlines (e.g., `node -e "\nimport(...)\n"`), the wildcard matcher's compiled regex `/^.*$/` fails because `.` does not match `\n` by default in JavaScript.
|
||||
This causes `evaluate()` to find no matching rule — not even the universal `{ surface: "*", pattern: "*" }` catch-all — and fall through to the hard-coded `"ask"` default, producing a spurious permission prompt.
|
||||
|
||||
## Goals
|
||||
|
||||
- Make `wildcardMatch` (and all callers via `compileWildcardPattern`) correctly match values containing newline characters.
|
||||
- Zero behavior change for single-line values — this is a strict bug fix.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- Changing the permission evaluation model or rule precedence.
|
||||
- Addressing shell-quote tokenization (covered by #72, already landed).
|
||||
- Adding multiline-aware pattern syntax (e.g., `**` for newlines) — the existing `*` should simply match everything including newlines.
|
||||
|
||||
## Background
|
||||
|
||||
- **Permission surface**: `bash` (but the fix is in the generic wildcard module, affecting all surfaces).
|
||||
- **Module**: `src/wildcard-matcher.ts` — `compileWildcardPattern()` builds a `RegExp` by escaping literal segments and joining with `.*`.
|
||||
The regex uses no flags, so `.` does not match `\n`.
|
||||
- **Call path**: `evaluate()` in `src/rule.ts` calls `wildcardMatch(rule.pattern, value)` for both `surface` and `pattern` fields.
|
||||
A multiline bash command is the `value` argument to the pattern match.
|
||||
|
||||
## Design Overview
|
||||
|
||||
Add the `s` (dotAll) flag to the regex constructed in `compileWildcardPattern`.
|
||||
With `dotAll`, `.` matches any character including line terminators (`\n`, `\r`, `\u2028`, `\u2029`).
|
||||
|
||||
```typescript
|
||||
return {
|
||||
pattern,
|
||||
state,
|
||||
regex: new RegExp(`^${escaped}$`, "s"),
|
||||
};
|
||||
```
|
||||
|
||||
This is the minimal, correct fix.
|
||||
No new types, no data-shape changes, no config changes.
|
||||
|
||||
## Module-Level Changes
|
||||
|
||||
| File | Change |
|
||||
| ---------------------------------- | --------------------------------------------------------------------------------- |
|
||||
| `src/wildcard-matcher.ts` | Add `"s"` flag to `new RegExp(...)` in `compileWildcardPattern()`. |
|
||||
| `tests/wildcard-matcher.test.ts` | Add test cases for multiline values matching `*` and literal-prefix-`*` patterns. |
|
||||
| `tests/permission-manager.test.ts` | Add integration test: multiline bash command with `"*": "allow"` returns allow. |
|
||||
|
||||
## TDD Order
|
||||
|
||||
1. **test: multiline value fails to match wildcard `*` pattern (red)**
|
||||
Add tests in `tests/wildcard-matcher.test.ts`:
|
||||
- `wildcardMatch("*", "line1\nline2")` → expected `true`
|
||||
- `wildcardMatch("node *", "node -e \"\nfoo\n\"")` → expected `true`
|
||||
- `compileWildcardPattern("*", "allow").regex.test("a\nb")` → expected `true`
|
||||
|
||||
Commit: `test: cover multiline values in wildcardMatch`
|
||||
|
||||
2. **feat: add dotAll flag to wildcard regex** In `src/wildcard-matcher.ts`, change `new RegExp(...)` to include `"s"` flag.
|
||||
Tests from step 1 go green.
|
||||
|
||||
Commit: `fix: add dotAll flag so wildcard`*`matches newlines (#73)`
|
||||
|
||||
3. **test: integration — multiline bash command resolves to allow**
|
||||
Add a test in `tests/permission-manager.test.ts`:
|
||||
- Config: `{ "*": "allow", bash: { "rm -rf *": "deny" } }`
|
||||
- `checkPermission("bash", { command: "node -e \"\nimport(...)\n\"" })` → `state: "allow"`
|
||||
|
||||
Commit: `test: multiline bash command resolves allow via universal fallback`
|
||||
|
||||
## Risks and Mitigations
|
||||
|
||||
| Risk | Mitigation |
|
||||
| --------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Could this silently weaken a permission? | No. The `s` flag only makes `*` match what users already expect it to match. A pattern like `rm -rf *` still only matches strings starting with `rm -rf` — it does not gain the ability to match unrelated multiline strings because the literal prefix anchors it. |
|
||||
| Over-broad match for patterns containing literal newlines | No user would put literal `\n` in a pattern string in JSON config. The patterns are single-line strings; only values (commands) can be multiline. |
|
||||
| Breaks existing tests | Existing tests use single-line values. Adding `s` has no effect on strings without newlines. |
|
||||
|
||||
## Open Questions
|
||||
|
||||
None — the fix is unambiguous.
|
||||
Reference in New Issue
Block a user