bb9c9d9bda0bfd1c97f3bd7ae8a5e131a4768e6e

Author
TheEdgeOfRage <git@theedgeofrage.com>
Committer
TheEdgeOfRage <git@theedgeofrage.com>
Date

Message

Fix deterministic matching in cases where | is quoted

Diff

This diff is truncated to protect this page.

 1diff --git a/AGENTS.md b/AGENTS.md
 2new file mode 100644
 3index 0000000000000000000000000000000000000000..34c0d084c186965aa543cf3e77c140a8e1b397cb
 4--- /dev/null
 5+++ b/AGENTS.md
 6@@ -0,0 +1,33 @@
 7+# Policy Engine - Agent Instructions
 8+
 9+## Overview
10+
11+Security policy engine for OpenCode. Evaluates tool calls (primarily bash commands) against deterministic regex patterns and an LLM fallback (Haiku) to decide allow/deny/ask.
12+
13+## Project Structure
14+
15+- `src/rules.ts` — Regex patterns (`HARD_ALLOW_PATTERNS`, `CONFIG_ALLOW_PATTERNS`, `ASK_PATTERNS`) and `SHELL_CONTROL_RE`
16+- `src/deterministic.ts` — Pattern matching logic against the rules
17+- `src/haiku.ts` — LLM fallback for commands that don't match deterministic patterns
18+- `src/normalizer.ts` — Command normalization before evaluation
19+- `src/cache.ts` — Decision caching
20+- `src/permissions.ts` — User-granted permission tracking
21+
22+## Commands
23+
24+- **Tests:** `bun test`
25+- **Lint:** `bunx eslint src/`
26+- **Typecheck:** `bunx tsc --noEmit`
27+
28+## Policy Version
29+
30diff --git a/src/deterministic.ts b/src/deterministic.ts
31index a8af5cbfa13323e02d4c67c1a3d26a2a3b69cedf..7438429f5f9f823da0de51ba2d75f7cc2ab9ae65 100644
32--- a/src/deterministic.ts
33+++ b/src/deterministic.ts
34@@ -1,9 +1,13 @@
35 import type { Decision } from "./types"
36 import { HARD_ALLOW_PATTERNS, CONFIG_ALLOW_PATTERNS, ASK_PATTERNS, SHELL_CONTROL_RE } from "./rules"
37 
38+function hasShellControl(cmd: string): boolean {
39+  return SHELL_CONTROL_RE.test(cmd.replace(/"[^"]*"|'[^']*'/g, '""'))
40+}
41+
42 function checkHardAllow(command: string): Decision | undefined {
43   const cmd = command.trim()
44-  if (!cmd || SHELL_CONTROL_RE.test(cmd)) return undefined
45+  if (!cmd || hasShellControl(cmd)) return undefined
46   for (const pat of HARD_ALLOW_PATTERNS) {
47     if (pat.test(cmd)) {
48       return {
49@@ -31,7 +35,7 @@ function checkAskPatterns(command: string): Decision | undefined {
50 
51 function checkConfigAllow(command: string): Decision | undefined {
52   const cmd = command.trim()
53-  if (!cmd || SHELL_CONTROL_RE.test(cmd)) return undefined
54+  if (!cmd || hasShellControl(cmd)) return undefined
55   for (const pat of CONFIG_ALLOW_PATTERNS) {
56     if (pat.test(cmd)) {
57       return {
58diff --git a/src/rules.ts b/src/rules.ts
59index a66eeb4dc00e7ec87b72057aa65b22393ecef526..ed5c34fafc296e15309ec53aadf99918f7aa4118 100644
60--- a/src/rules.ts
61+++ b/src/rules.ts
62@@ -1,5 +1,5 @@
63 // Bump to invalidate all cached decisions when rules change.
64-export const POLICY_VERSION = "3.3.0";
65+export const POLICY_VERSION = "3.4.0";
66 
67 // Matched with test() on anchored patterns (equivalent to Python fullmatch).
68 // Purely a performance optimization — these would pass LLM review anyway.