@koda-sl/baker-bridge 0.109.0-dev.9779e8b49 → 0.109.0-dev.d6e55699d
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +89 -46
- package/dist/broker/baker-api.d.ts +23 -0
- package/dist/broker/baker-api.d.ts.map +1 -0
- package/dist/broker/baker-api.js +55 -0
- package/dist/broker/baker-api.js.map +1 -0
- package/dist/broker/broker-client.d.ts +10 -0
- package/dist/broker/broker-client.d.ts.map +1 -0
- package/dist/broker/broker-client.js +60 -0
- package/dist/broker/broker-client.js.map +1 -0
- package/dist/broker/broker-process.d.ts +10 -0
- package/dist/broker/broker-process.d.ts.map +1 -0
- package/dist/broker/broker-process.js +20 -0
- package/dist/broker/broker-process.js.map +1 -0
- package/dist/broker/broker-process.test.d.ts +2 -0
- package/dist/broker/broker-process.test.d.ts.map +1 -0
- package/dist/broker/broker-process.test.js +13 -0
- package/dist/broker/broker-process.test.js.map +1 -0
- package/dist/broker/ca.d.ts +38 -0
- package/dist/broker/ca.d.ts.map +1 -0
- package/dist/broker/ca.js +80 -0
- package/dist/broker/ca.js.map +1 -0
- package/dist/broker/ca.test.d.ts +2 -0
- package/dist/broker/ca.test.d.ts.map +1 -0
- package/dist/broker/ca.test.js +58 -0
- package/dist/broker/ca.test.js.map +1 -0
- package/dist/broker/credential-cache.d.ts +24 -0
- package/dist/broker/credential-cache.d.ts.map +1 -0
- package/dist/broker/credential-cache.js +76 -0
- package/dist/broker/credential-cache.js.map +1 -0
- package/dist/broker/credential-cache.test.d.ts +2 -0
- package/dist/broker/credential-cache.test.d.ts.map +1 -0
- package/dist/broker/credential-cache.test.js +136 -0
- package/dist/broker/credential-cache.test.js.map +1 -0
- package/dist/broker/credential-text.d.ts +45 -0
- package/dist/broker/credential-text.d.ts.map +1 -0
- package/dist/broker/credential-text.js +103 -0
- package/dist/broker/credential-text.js.map +1 -0
- package/dist/broker/credential-text.test.d.ts +2 -0
- package/dist/broker/credential-text.test.d.ts.map +1 -0
- package/dist/broker/credential-text.test.js +54 -0
- package/dist/broker/credential-text.test.js.map +1 -0
- package/dist/broker/env.d.ts +21 -0
- package/dist/broker/env.d.ts.map +1 -0
- package/dist/broker/env.js +20 -0
- package/dist/broker/env.js.map +1 -0
- package/dist/broker/main.d.ts +3 -0
- package/dist/broker/main.d.ts.map +1 -0
- package/dist/broker/main.js +57 -0
- package/dist/broker/main.js.map +1 -0
- package/dist/broker/proxy.d.ts +24 -0
- package/dist/broker/proxy.d.ts.map +1 -0
- package/dist/broker/proxy.integration.test.d.ts +2 -0
- package/dist/broker/proxy.integration.test.d.ts.map +1 -0
- package/dist/broker/proxy.integration.test.js +197 -0
- package/dist/broker/proxy.integration.test.js.map +1 -0
- package/dist/broker/proxy.js +147 -0
- package/dist/broker/proxy.js.map +1 -0
- package/dist/broker/rewrite.d.ts +44 -0
- package/dist/broker/rewrite.d.ts.map +1 -0
- package/dist/broker/rewrite.js +291 -0
- package/dist/broker/rewrite.js.map +1 -0
- package/dist/broker/rewrite.test.d.ts +2 -0
- package/dist/broker/rewrite.test.d.ts.map +1 -0
- package/dist/broker/rewrite.test.js +171 -0
- package/dist/broker/rewrite.test.js.map +1 -0
- package/dist/broker/socket-service.d.ts +18 -0
- package/dist/broker/socket-service.d.ts.map +1 -0
- package/dist/broker/socket-service.js +113 -0
- package/dist/broker/socket-service.js.map +1 -0
- package/dist/broker/socket-service.test.d.ts +2 -0
- package/dist/broker/socket-service.test.d.ts.map +1 -0
- package/dist/broker/socket-service.test.js +80 -0
- package/dist/broker/socket-service.test.js.map +1 -0
- package/dist/broker/supervisor-main.d.ts +3 -0
- package/dist/broker/supervisor-main.d.ts.map +1 -0
- package/dist/broker/supervisor-main.js +70 -0
- package/dist/broker/supervisor-main.js.map +1 -0
- package/dist/broker/supervisor.d.ts +25 -0
- package/dist/broker/supervisor.d.ts.map +1 -0
- package/dist/broker/supervisor.js +88 -0
- package/dist/broker/supervisor.js.map +1 -0
- package/dist/broker/supervisor.test.d.ts +2 -0
- package/dist/broker/supervisor.test.d.ts.map +1 -0
- package/dist/broker/supervisor.test.js +161 -0
- package/dist/broker/supervisor.test.js.map +1 -0
- package/dist/broker/token-bucket.d.ts +9 -0
- package/dist/broker/token-bucket.d.ts.map +1 -0
- package/dist/broker/token-bucket.js +18 -0
- package/dist/broker/token-bucket.js.map +1 -0
- package/dist/broker/usage-reporter.d.ts +18 -0
- package/dist/broker/usage-reporter.d.ts.map +1 -0
- package/dist/broker/usage-reporter.js +31 -0
- package/dist/broker/usage-reporter.js.map +1 -0
- package/dist/broker/usage-reporter.test.d.ts +2 -0
- package/dist/broker/usage-reporter.test.d.ts.map +1 -0
- package/dist/broker/usage-reporter.test.js +20 -0
- package/dist/broker/usage-reporter.test.js.map +1 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -0
- package/dist/cli.js.map +1 -1
- package/dist/hono/agent-session.d.ts +3 -0
- package/dist/hono/agent-session.d.ts.map +1 -1
- package/dist/hono/agent-session.js +15 -0
- package/dist/hono/agent-session.js.map +1 -1
- package/dist/hono/agent-tasks.js +4 -4
- package/dist/hono/agent-tasks.js.map +1 -1
- package/dist/hono/agent.d.ts +2 -0
- package/dist/hono/agent.d.ts.map +1 -1
- package/dist/hono/agent.js +11 -2
- package/dist/hono/agent.js.map +1 -1
- package/dist/hono/agent.test.js +8 -2
- package/dist/hono/agent.test.js.map +1 -1
- package/dist/hono/avatar-accent.d.ts +23 -5
- package/dist/hono/avatar-accent.d.ts.map +1 -1
- package/dist/hono/avatar-accent.js +54 -63
- package/dist/hono/avatar-accent.js.map +1 -1
- package/dist/hono/avatar-accent.test.js +64 -35
- package/dist/hono/avatar-accent.test.js.map +1 -1
- package/dist/hono/avatar-casting.d.ts +1 -0
- package/dist/hono/avatar-casting.d.ts.map +1 -1
- package/dist/hono/avatar-casting.js +18 -4
- package/dist/hono/avatar-casting.js.map +1 -1
- package/dist/hono/avatar-casting.test.js +5 -0
- package/dist/hono/avatar-casting.test.js.map +1 -1
- package/dist/hono/avatar-face-question.d.ts +23 -6
- package/dist/hono/avatar-face-question.d.ts.map +1 -1
- package/dist/hono/avatar-face-question.js +48 -59
- package/dist/hono/avatar-face-question.js.map +1 -1
- package/dist/hono/avatar-face-question.test.js +46 -101
- package/dist/hono/avatar-face-question.test.js.map +1 -1
- package/dist/hono/baker-ui-tool-schemas.test.js +30 -4
- package/dist/hono/baker-ui-tool-schemas.test.js.map +1 -1
- package/dist/hono/blocking-card.d.ts +12 -0
- package/dist/hono/blocking-card.d.ts.map +1 -0
- package/dist/hono/blocking-card.js +12 -0
- package/dist/hono/blocking-card.js.map +1 -0
- package/dist/hono/bridge-job.d.ts +48 -2
- package/dist/hono/bridge-job.d.ts.map +1 -1
- package/dist/hono/bridge-job.js +202 -34
- package/dist/hono/bridge-job.js.map +1 -1
- package/dist/hono/bridge-job.test.js +344 -20
- package/dist/hono/bridge-job.test.js.map +1 -1
- package/dist/hono/check-content.d.ts +49 -0
- package/dist/hono/check-content.d.ts.map +1 -0
- package/dist/hono/check-content.js +182 -0
- package/dist/hono/check-content.js.map +1 -0
- package/dist/hono/check-content.test.d.ts +2 -0
- package/dist/hono/check-content.test.d.ts.map +1 -0
- package/dist/hono/check-content.test.js +87 -0
- package/dist/hono/check-content.test.js.map +1 -0
- package/dist/hono/connection-input.d.ts +165 -12
- package/dist/hono/connection-input.d.ts.map +1 -1
- package/dist/hono/connection-input.js +160 -18
- package/dist/hono/connection-input.js.map +1 -1
- package/dist/hono/connection-input.test.js +89 -9
- package/dist/hono/connection-input.test.js.map +1 -1
- package/dist/hono/convex.d.ts +8 -0
- package/dist/hono/convex.d.ts.map +1 -1
- package/dist/hono/convex.js +8 -0
- package/dist/hono/convex.js.map +1 -1
- package/dist/hono/convex.test.js +4 -1
- package/dist/hono/convex.test.js.map +1 -1
- package/dist/hono/credential-input.d.ts +39 -0
- package/dist/hono/credential-input.d.ts.map +1 -0
- package/dist/hono/credential-input.js +78 -0
- package/dist/hono/credential-input.js.map +1 -0
- package/dist/hono/credential-scrub.d.ts +42 -0
- package/dist/hono/credential-scrub.d.ts.map +1 -0
- package/dist/hono/credential-scrub.js +173 -0
- package/dist/hono/credential-scrub.js.map +1 -0
- package/dist/hono/credential-scrub.test.d.ts +2 -0
- package/dist/hono/credential-scrub.test.d.ts.map +1 -0
- package/dist/hono/credential-scrub.test.js +130 -0
- package/dist/hono/credential-scrub.test.js.map +1 -0
- package/dist/hono/env.d.ts +1 -0
- package/dist/hono/env.d.ts.map +1 -1
- package/dist/hono/env.js +2 -0
- package/dist/hono/env.js.map +1 -1
- package/dist/hono/flow-crypto.d.ts +2 -1
- package/dist/hono/flow-crypto.d.ts.map +1 -1
- package/dist/hono/flow-crypto.js +50 -26
- package/dist/hono/flow-crypto.js.map +1 -1
- package/dist/hono/flow-crypto.test.js +32 -0
- package/dist/hono/flow-crypto.test.js.map +1 -1
- package/dist/hono/flow-input-card-fields.test.d.ts +10 -0
- package/dist/hono/flow-input-card-fields.test.d.ts.map +1 -0
- package/dist/hono/flow-input-card-fields.test.js +26 -0
- package/dist/hono/flow-input-card-fields.test.js.map +1 -0
- package/dist/hono/flow-input-fields.test.js +1 -1
- package/dist/hono/flow-input-fields.test.js.map +1 -1
- package/dist/hono/flow-input.d.ts +23 -2
- package/dist/hono/flow-input.d.ts.map +1 -1
- package/dist/hono/flow-input.js +63 -14
- package/dist/hono/flow-input.js.map +1 -1
- package/dist/hono/flow-input.test.js +67 -11
- package/dist/hono/flow-input.test.js.map +1 -1
- package/dist/hono/jev.d.ts +16 -0
- package/dist/hono/jev.d.ts.map +1 -0
- package/dist/hono/jev.js +60 -0
- package/dist/hono/jev.js.map +1 -0
- package/dist/hono/jev.test.d.ts +2 -0
- package/dist/hono/jev.test.d.ts.map +1 -0
- package/dist/hono/jev.test.js +15 -0
- package/dist/hono/jev.test.js.map +1 -0
- package/dist/hono/knowledge-content.d.ts.map +1 -1
- package/dist/hono/knowledge-content.js +4 -2
- package/dist/hono/knowledge-content.js.map +1 -1
- package/dist/hono/knowledge-content.test.js +6 -5
- package/dist/hono/knowledge-content.test.js.map +1 -1
- package/dist/hono/mcp-servers.d.ts +8 -1
- package/dist/hono/mcp-servers.d.ts.map +1 -1
- package/dist/hono/mcp-servers.js +17 -6
- package/dist/hono/mcp-servers.js.map +1 -1
- package/dist/hono/mcp-servers.test.js +25 -0
- package/dist/hono/mcp-servers.test.js.map +1 -1
- package/dist/hono/model-capabilities.d.ts.map +1 -1
- package/dist/hono/model-capabilities.js +20 -9
- package/dist/hono/model-capabilities.js.map +1 -1
- package/dist/hono/model-capabilities.test.js +16 -8
- package/dist/hono/model-capabilities.test.js.map +1 -1
- package/dist/hono/oom-priority.agent.test.d.ts +2 -0
- package/dist/hono/oom-priority.agent.test.d.ts.map +1 -0
- package/dist/hono/oom-priority.agent.test.js +138 -0
- package/dist/hono/oom-priority.agent.test.js.map +1 -0
- package/dist/hono/oom-priority.d.ts +39 -0
- package/dist/hono/oom-priority.d.ts.map +1 -0
- package/dist/hono/oom-priority.js +138 -0
- package/dist/hono/oom-priority.js.map +1 -0
- package/dist/hono/oom-priority.test.d.ts +2 -0
- package/dist/hono/oom-priority.test.d.ts.map +1 -0
- package/dist/hono/oom-priority.test.js +52 -0
- package/dist/hono/oom-priority.test.js.map +1 -0
- package/dist/hono/openrouter-session.d.ts.map +1 -1
- package/dist/hono/openrouter-session.js +12 -1
- package/dist/hono/openrouter-session.js.map +1 -1
- package/dist/hono/openrouter-session.test.js +9 -3
- package/dist/hono/openrouter-session.test.js.map +1 -1
- package/dist/hono/prompt-context.d.ts +8 -1
- package/dist/hono/prompt-context.d.ts.map +1 -1
- package/dist/hono/prompt-context.js +45 -7
- package/dist/hono/prompt-context.js.map +1 -1
- package/dist/hono/prompt-context.test.js +32 -1
- package/dist/hono/prompt-context.test.js.map +1 -1
- package/dist/hono/publish-recovery.d.ts +1 -1
- package/dist/hono/publish-recovery.d.ts.map +1 -1
- package/dist/hono/publish-recovery.js +9 -6
- package/dist/hono/publish-recovery.js.map +1 -1
- package/dist/hono/publish-recovery.test.js +11 -2
- package/dist/hono/publish-recovery.test.js.map +1 -1
- package/dist/hono/relay.d.ts +10 -1
- package/dist/hono/relay.d.ts.map +1 -1
- package/dist/hono/relay.js +6 -0
- package/dist/hono/relay.js.map +1 -1
- package/dist/hono/sandbox-content.d.ts +2 -0
- package/dist/hono/sandbox-content.d.ts.map +1 -1
- package/dist/hono/sandbox-content.js +8 -4
- package/dist/hono/sandbox-content.js.map +1 -1
- package/dist/hono/sandbox-content.test.js +20 -1
- package/dist/hono/sandbox-content.test.js.map +1 -1
- package/dist/hono/server.d.ts.map +1 -1
- package/dist/hono/server.js +32 -0
- package/dist/hono/server.js.map +1 -1
- package/dist/hono/server.test.js +21 -1
- package/dist/hono/server.test.js.map +1 -1
- package/dist/hono/session-continuity.integration.test.js +10 -1
- package/dist/hono/session-continuity.integration.test.js.map +1 -1
- package/dist/hono/tag-fields.d.ts.map +1 -1
- package/dist/hono/tag-fields.js +2 -0
- package/dist/hono/tag-fields.js.map +1 -1
- package/dist/hono/tag-input.d.ts +124 -3
- package/dist/hono/tag-input.d.ts.map +1 -1
- package/dist/hono/tag-input.js +27 -17
- package/dist/hono/tag-input.js.map +1 -1
- package/dist/hono/tag-input.test.js +19 -1
- package/dist/hono/tag-input.test.js.map +1 -1
- package/dist/hono/tool-mentions.d.ts.map +1 -1
- package/dist/hono/tool-mentions.js +1 -0
- package/dist/hono/tool-mentions.js.map +1 -1
- package/dist/hono/tool-mentions.test.js +5 -0
- package/dist/hono/tool-mentions.test.js.map +1 -1
- package/dist/hono/types.d.ts +8 -0
- package/dist/hono/types.d.ts.map +1 -1
- package/dist/hono/workspace-script.d.ts +10 -0
- package/dist/hono/workspace-script.d.ts.map +1 -0
- package/dist/hono/workspace-script.js +19 -0
- package/dist/hono/workspace-script.js.map +1 -0
- package/dist/hono/workspace-settle.d.ts +1 -1
- package/dist/hono/workspace-settle.d.ts.map +1 -1
- package/dist/hono/workspace-settle.js +12 -8
- package/dist/hono/workspace-settle.js.map +1 -1
- package/dist/review/digest.d.ts +8 -1
- package/dist/review/digest.d.ts.map +1 -1
- package/dist/review/digest.js +10 -43
- package/dist/review/digest.js.map +1 -1
- package/dist/review/digest.test.js +11 -6
- package/dist/review/digest.test.js.map +1 -1
- package/dist/review/evidence-block.js +1 -1
- package/dist/review/evidence-block.js.map +1 -1
- package/dist/review/evidence-block.test.js +0 -10
- package/dist/review/evidence-block.test.js.map +1 -1
- package/dist/review/shell-policy.d.ts +6 -0
- package/dist/review/shell-policy.d.ts.map +1 -1
- package/dist/review/shell-policy.js +240 -72
- package/dist/review/shell-policy.js.map +1 -1
- package/dist/review/shell-policy.test.js +114 -0
- package/dist/review/shell-policy.test.js.map +1 -1
- package/package.json +9 -5
- package/dist/hono/latitude-telemetry.d.ts +0 -17
- package/dist/hono/latitude-telemetry.d.ts.map +0 -1
- package/dist/hono/latitude-telemetry.js +0 -52
- package/dist/hono/latitude-telemetry.js.map +0 -1
- package/dist/hono/latitude-telemetry.test.d.ts +0 -2
- package/dist/hono/latitude-telemetry.test.d.ts.map +0 -1
- package/dist/hono/latitude-telemetry.test.js +0 -18
- package/dist/hono/latitude-telemetry.test.js.map +0 -1
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* top of it: the shell is the one surface where "everything except what I
|
|
17
17
|
* thought of" is not a defensible default.
|
|
18
18
|
*/
|
|
19
|
+
import { parse } from "unbash";
|
|
19
20
|
/** Binaries the reviewer may invoke. Every one of them reads. */
|
|
20
21
|
const ALLOWED_BINARIES = new Set([
|
|
21
22
|
"cat",
|
|
@@ -60,109 +61,276 @@ const ALLOWED_GIT_VERBS = new Set([
|
|
|
60
61
|
"reflog",
|
|
61
62
|
]);
|
|
62
63
|
/**
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
64
|
+
* Binaries worth naming when refused. The allowlist already refuses every one
|
|
65
|
+
* of them; the reason tells the reviewer what the command would have done, so
|
|
66
|
+
* it reports the refusal instead of trying a neighbour. Matched on the command
|
|
67
|
+
* that runs, never on a word anywhere in the line — a path such as
|
|
68
|
+
* `docs/tools/agent-browser.md` is something to read, not a browser.
|
|
66
69
|
*/
|
|
67
|
-
const
|
|
68
|
-
[
|
|
69
|
-
[
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
[
|
|
75
|
-
[
|
|
76
|
-
|
|
77
|
-
[/\b(rm|mv|cp|mkdir|touch|chmod|chown|ln|truncate|dd)\b/, "changes the workspace"],
|
|
78
|
-
[/\b(npm|pnpm|npx|yarn|node|tsx|bun|deno|python3?|bash|sh|zsh)\b/, "runs arbitrary code"],
|
|
79
|
-
[/\b(curl|wget|nc|ssh|scp|rsync)\b/, "reaches the network"],
|
|
80
|
-
[/\bnohup\b/, "outlives the turn"],
|
|
81
|
-
[/\bagent-browser\b/, "drives a browser"],
|
|
82
|
-
[/&\s*$/, "backgrounds the command"],
|
|
83
|
-
[/\$\(/, "substitutes a command the policy never saw"],
|
|
84
|
-
[/`/, "substitutes a command the policy never saw"],
|
|
85
|
-
];
|
|
86
|
-
/** `sed`/`awk` in place is an edit wearing a reader's name. */
|
|
87
|
-
const IN_PLACE_EDIT = /\bsed\b[^|;]*\s-[a-zA-Z]*i\b|\bsed\b[^|;]*--in-place/;
|
|
70
|
+
const DENIED_BINARIES = new Map([
|
|
71
|
+
["tee", "writes to a file"],
|
|
72
|
+
["xargs", "runs whatever it is piped"],
|
|
73
|
+
["sudo", "escalates"],
|
|
74
|
+
...["rm", "mv", "cp", "mkdir", "touch", "chmod", "chown", "ln", "truncate", "dd"].map((name) => [name, "changes the workspace"]),
|
|
75
|
+
...["npm", "pnpm", "npx", "yarn", "node", "tsx", "bun", "deno", "python", "python3", "bash", "sh", "zsh"].map((name) => [name, "runs arbitrary code"]),
|
|
76
|
+
...["curl", "wget", "nc", "ssh", "scp", "rsync"].map((name) => [name, "reaches the network"]),
|
|
77
|
+
["nohup", "outlives the turn"],
|
|
78
|
+
["agent-browser", "drives a browser"],
|
|
79
|
+
]);
|
|
88
80
|
/**
|
|
89
|
-
*
|
|
81
|
+
* Arguments that turn an allowed reader into a writer or a runner, checked per
|
|
82
|
+
* binary on the dequoted word so a quote cannot hide one and another command's
|
|
83
|
+
* pattern cannot trip one.
|
|
84
|
+
*
|
|
85
|
+
* `find` reads, and its action flags are a second command inside the first:
|
|
86
|
+
* `-delete` removes, `-exec`/`-execdir`/`-ok` run anything at all, and
|
|
87
|
+
* `-fprintf`/`-fls`/`-fprint` write a file without a redirect to see.
|
|
88
|
+
*
|
|
89
|
+
* awk and sed take a program rather than data, so their operands are read as
|
|
90
|
+
* code: awk runs a command with `system()` or a `|` and writes with `>`; sed
|
|
91
|
+
* writes with `w`/`W` (a command or an `s///` flag) and runs one with `e`.
|
|
92
|
+
* awk's own `||` and `>=` pass; the odd false refusal that is left is the
|
|
93
|
+
* right side to be wrong on. Their flags edit in place (`sed -i`, gawk's
|
|
94
|
+
* `-i inplace`), load code (`-l`), or read the program from a file (`-f`),
|
|
95
|
+
* where none of this can see it — and the workspace under review is the one
|
|
96
|
+
* whose agent could have written that file.
|
|
90
97
|
*
|
|
91
|
-
*
|
|
92
|
-
* one-liner, and without it only the first line was ever checked — the whole
|
|
93
|
-
* policy read `git log\ngit push` as a `git log`. A lone `&` is in here for the
|
|
94
|
-
* same reason: the denial below catches a trailing one, which backgrounds, but
|
|
95
|
-
* `ls & git push` backgrounds the *first* command and runs the second in front.
|
|
96
|
-
* Its lookarounds spare `2>&1` and `&>`, where the `&` is part of a redirect
|
|
97
|
-
* rather than a separator, and `&&` is consumed by the earlier alternative.
|
|
98
|
+
* `sort -o` and `git --output` write a file with no redirect in sight.
|
|
98
99
|
*/
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
100
|
+
const ARGUMENT_RULES = new Map([
|
|
101
|
+
["find", [{ flag: /^-(delete|exec|execdir|ok|okdir|fprintf|fprint0?|fls)$/, reason: "turns a read into a write" }]],
|
|
102
|
+
[
|
|
103
|
+
"sed",
|
|
104
|
+
[
|
|
105
|
+
{ flag: /^-[^-]*i|^--in-place/, reason: "edits the file in place" },
|
|
106
|
+
{ flag: /^-[^-]*f|^--file/, reason: "runs a program this review cannot read" },
|
|
107
|
+
{ program: /(^|[\s;{}!\d$/=-])[gpiImM\d]*[wWe](\s|$|[;}])/, reason: "writes a file or runs a command" },
|
|
108
|
+
],
|
|
109
|
+
],
|
|
110
|
+
[
|
|
111
|
+
"awk",
|
|
112
|
+
[
|
|
113
|
+
{ flag: /^-(i|l|-include|-load)/, reason: "loads code into the program" },
|
|
114
|
+
{ flag: /^-(f|E|-file|-exec)/, reason: "runs a program this review cannot read" },
|
|
115
|
+
{ program: /\bsystem\s*\(|(?<!\|)\|(?!\|)|>(?!=)|@load\b/, reason: "writes a file or runs a command" },
|
|
116
|
+
],
|
|
117
|
+
],
|
|
118
|
+
["sort", [{ flag: /^-[^-]*o|^--output/, reason: "writes a file" }]],
|
|
119
|
+
["git", [{ flag: /^--output(=|$)/, reason: "writes a file" }]],
|
|
120
|
+
]);
|
|
121
|
+
/**
|
|
122
|
+
* Options whose value is data, never the program: awk's field separator and
|
|
123
|
+
* variables. Read as code, `awk -F'|'` — the ordinary way to split a markdown
|
|
124
|
+
* table — was refused for its "pipe".
|
|
125
|
+
*/
|
|
126
|
+
const DATA_OPTIONS = new Map([["awk", /^(-[Fv]|--field-separator|--assign)/]]);
|
|
127
|
+
/**
|
|
128
|
+
* The words a program rule reads: every operand except an option, and except
|
|
129
|
+
* the value an option carries as data, attached (`-F'|'`) or separate
|
|
130
|
+
* (`-F '|'`). Options that carry the program itself (`sed -e`) stay in.
|
|
131
|
+
*/
|
|
132
|
+
function programWords(binary, words) {
|
|
133
|
+
const data = DATA_OPTIONS.get(binary);
|
|
134
|
+
const out = [];
|
|
135
|
+
for (let index = 0; index < words.length; index += 1) {
|
|
136
|
+
const value = words[index]?.value ?? "";
|
|
137
|
+
if (data?.test(value)) {
|
|
138
|
+
// A bare `-F` / `-v` takes the next word as its value.
|
|
139
|
+
if (/^-[Fv]$|^--(field-separator|assign)$/.test(value)) {
|
|
140
|
+
index += 1;
|
|
141
|
+
}
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (!BARE_OPTION.test(value)) {
|
|
145
|
+
out.push(value);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return out;
|
|
115
149
|
}
|
|
150
|
+
/** A bare option such as `-n` or `--quiet`, which carries no program text. */
|
|
151
|
+
const BARE_OPTION = /^-{1,2}[A-Za-z-]+$/;
|
|
116
152
|
/**
|
|
117
|
-
*
|
|
153
|
+
* The only `VAR=value` prefixes a reader may carry: locale, time zone, colour
|
|
154
|
+
* and width, which change how output looks and nothing else. Any other name is
|
|
155
|
+
* a lever — `git diff` runs `GIT_EXTERNAL_DIFF`, a pager variable names a
|
|
156
|
+
* program — and a value is a second command wearing an assignment's name.
|
|
157
|
+
*/
|
|
158
|
+
const ALLOWED_ENVIRONMENT = /^(LC_[A-Z]+|LANG|LANGUAGE|TZ|NO_COLOR|COLUMNS)$/;
|
|
159
|
+
const READ_ONLY = "this review is read-only and";
|
|
160
|
+
const UNREADABLE = "could not tell what that command runs";
|
|
161
|
+
/**
|
|
162
|
+
* Every simple command one Bash call runs, read the way the shell reads it.
|
|
118
163
|
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
164
|
+
* A real parser rather than a split on `|`, `;` and newlines, because a split
|
|
165
|
+
* cannot tell an operator from the same character inside quotes: it read jq's
|
|
166
|
+
* own `|` and grep's `\|` alternation as pipes and refused the brief's own
|
|
167
|
+
* transcript projection. What the parser cannot read is refused rather than
|
|
168
|
+
* guessed at, and so is any shape other than commands joined by pipes, `&&`,
|
|
169
|
+
* `||`, `;` and newlines — a loop or a group is a second grammar to police.
|
|
121
170
|
*/
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
171
|
+
function readScript(command) {
|
|
172
|
+
const script = parse(command);
|
|
173
|
+
if (script.errors && script.errors.length > 0) {
|
|
174
|
+
return { refused: UNREADABLE };
|
|
175
|
+
}
|
|
176
|
+
if (substitutesACommand(script)) {
|
|
177
|
+
return { refused: `${READ_ONLY} that command substitutes a command the policy never saw` };
|
|
178
|
+
}
|
|
179
|
+
const commands = [];
|
|
180
|
+
const redirects = [];
|
|
181
|
+
const pending = [...script.commands];
|
|
182
|
+
for (let node = pending.shift(); node; node = pending.shift()) {
|
|
183
|
+
switch (node.type) {
|
|
184
|
+
case "Statement":
|
|
185
|
+
if (node.background) {
|
|
186
|
+
return { refused: `${READ_ONLY} that command backgrounds the command` };
|
|
187
|
+
}
|
|
188
|
+
pending.push(node.command);
|
|
189
|
+
redirects.push(...node.redirects);
|
|
190
|
+
break;
|
|
191
|
+
case "Pipeline":
|
|
192
|
+
case "AndOr":
|
|
193
|
+
pending.push(...node.commands);
|
|
194
|
+
break;
|
|
195
|
+
case "Command":
|
|
196
|
+
commands.push(node);
|
|
197
|
+
redirects.push(...node.redirects);
|
|
198
|
+
break;
|
|
199
|
+
default:
|
|
200
|
+
return { refused: UNREADABLE };
|
|
127
201
|
}
|
|
128
202
|
}
|
|
129
|
-
|
|
130
|
-
|
|
203
|
+
return { commands, redirects };
|
|
204
|
+
}
|
|
205
|
+
/** The parse nodes that run a nested script: `$(…)`, backticks, `<(…)`, `>(…)`. */
|
|
206
|
+
const SUBSTITUTIONS = new Set(["CommandExpansion", "ProcessSubstitution", "ArithmeticCommandExpansion"]);
|
|
207
|
+
/**
|
|
208
|
+
* Whether anything in the parse runs a command the policy never saw. Searched
|
|
209
|
+
* over the serialised tree because unbash computes word parts lazily and only
|
|
210
|
+
* `toJSON` materialises all of them — a walk over own keys finds no expansion
|
|
211
|
+
* at all, and says nothing while missing it. A substitution hides anywhere a
|
|
212
|
+
* word does: an argument, a heredoc body, a `${x:-…}` default, an array index.
|
|
213
|
+
*/
|
|
214
|
+
function substitutesACommand(script) {
|
|
215
|
+
let found = false;
|
|
216
|
+
JSON.stringify(script, (key, value) => {
|
|
217
|
+
if (key === "type" && typeof value === "string" && SUBSTITUTIONS.has(value)) {
|
|
218
|
+
found = true;
|
|
219
|
+
}
|
|
220
|
+
return value;
|
|
221
|
+
});
|
|
222
|
+
return found;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* A redirect that only reads or discards. Input (`<`, heredocs) reads; `2>&1`
|
|
226
|
+
* duplicates a descriptor; `/dev/null` is the one file an output may name, so
|
|
227
|
+
* `2>/dev/null` keeps its place in a grep. Anything else — `>`, `>>`, `&>`,
|
|
228
|
+
* `>&file`, `<>` — opens a file for writing.
|
|
229
|
+
*/
|
|
230
|
+
function redirectReads(redirect) {
|
|
231
|
+
const target = redirect.target?.value;
|
|
232
|
+
switch (redirect.operator) {
|
|
233
|
+
case "<":
|
|
234
|
+
case "<<":
|
|
235
|
+
case "<<-":
|
|
236
|
+
case "<<<":
|
|
237
|
+
return true;
|
|
238
|
+
case ">&":
|
|
239
|
+
case "<&":
|
|
240
|
+
return target !== undefined && /^(\d+|-)$/.test(target);
|
|
241
|
+
case ">":
|
|
242
|
+
case ">>":
|
|
243
|
+
case ">|":
|
|
244
|
+
case "&>":
|
|
245
|
+
case "&>>":
|
|
246
|
+
return target === "/dev/null";
|
|
247
|
+
default:
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
function binaryOf(command) {
|
|
252
|
+
// The dequoted word, so `'rm'` or `$'\x72m'` is read as the `rm` it runs.
|
|
253
|
+
return command.name?.value.replace(/^.*\//, "") || undefined;
|
|
254
|
+
}
|
|
255
|
+
/** The per-binary argument rules: find's actions, awk's and sed's programs. */
|
|
256
|
+
function refuseArguments(binary, command) {
|
|
257
|
+
const program = programWords(binary, command.suffix);
|
|
258
|
+
for (const rule of ARGUMENT_RULES.get(binary) ?? []) {
|
|
259
|
+
const hit = "flag" in rule
|
|
260
|
+
? command.suffix.some(({ value }) => rule.flag.test(value))
|
|
261
|
+
: program.some((value) => rule.program.test(value));
|
|
262
|
+
if (hit) {
|
|
263
|
+
return { allowed: false, reason: `${READ_ONLY} that ${binary} ${rule.reason}` };
|
|
264
|
+
}
|
|
131
265
|
}
|
|
132
266
|
return undefined;
|
|
133
267
|
}
|
|
134
|
-
/**
|
|
135
|
-
|
|
136
|
-
|
|
268
|
+
/**
|
|
269
|
+
* The subcommand `git` will run. `-C <dir>` only says where, so it is skipped
|
|
270
|
+
* and the verb after it decides — `git -C repo log` reads, `git -C repo push`
|
|
271
|
+
* does not. Every other option before the verb is returned as the verb and so
|
|
272
|
+
* refused: `-c` sets config and `--exec-path` moves where git finds its own
|
|
273
|
+
* programs, and either can make a read run something else.
|
|
274
|
+
*/
|
|
275
|
+
function gitVerb(args) {
|
|
276
|
+
let index = 0;
|
|
277
|
+
while (args[index]?.value === "-C") {
|
|
278
|
+
index += 2;
|
|
279
|
+
}
|
|
280
|
+
return args[index]?.value;
|
|
281
|
+
}
|
|
282
|
+
/** One simple command: is the thing it runs one of the readers? */
|
|
283
|
+
function refuseCommand(command) {
|
|
284
|
+
const binary = binaryOf(command);
|
|
137
285
|
if (!binary) {
|
|
138
|
-
return { allowed: false, reason:
|
|
286
|
+
return { allowed: false, reason: UNREADABLE };
|
|
287
|
+
}
|
|
288
|
+
const assignment = command.prefix.find((prefix) => !prefix.name || !ALLOWED_ENVIRONMENT.test(prefix.name));
|
|
289
|
+
if (assignment) {
|
|
290
|
+
return {
|
|
291
|
+
allowed: false,
|
|
292
|
+
reason: `${READ_ONLY} \`${assignment.name ?? assignment.text}\` can hand a reader a program to run`,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
const denied = DENIED_BINARIES.get(binary);
|
|
296
|
+
if (denied) {
|
|
297
|
+
return { allowed: false, reason: `${READ_ONLY} that command ${denied}` };
|
|
139
298
|
}
|
|
140
299
|
if (!ALLOWED_BINARIES.has(binary)) {
|
|
141
|
-
return { allowed: false, reason:
|
|
300
|
+
return { allowed: false, reason: `${READ_ONLY} \`${binary}\` is not one of the read commands` };
|
|
142
301
|
}
|
|
143
302
|
if (binary !== "git") {
|
|
144
|
-
return
|
|
303
|
+
return refuseArguments(binary, command);
|
|
145
304
|
}
|
|
146
|
-
const verb =
|
|
305
|
+
const verb = gitVerb(command.suffix);
|
|
147
306
|
if (!verb || !ALLOWED_GIT_VERBS.has(verb)) {
|
|
148
307
|
return {
|
|
149
308
|
allowed: false,
|
|
150
|
-
reason:
|
|
309
|
+
reason: `${READ_ONLY} \`git ${verb ?? ""}\` is not one of the read subcommands`,
|
|
151
310
|
};
|
|
152
311
|
}
|
|
153
|
-
return
|
|
312
|
+
return refuseArguments(binary, command);
|
|
154
313
|
}
|
|
314
|
+
/**
|
|
315
|
+
* Decide one `Bash` call.
|
|
316
|
+
*
|
|
317
|
+
* Returns the reason on a refusal so the bridge can tell the reviewer what it
|
|
318
|
+
* tried and why, rather than a bare deny it will try to work around.
|
|
319
|
+
*/
|
|
155
320
|
export function reviewBashPolicy(command) {
|
|
156
321
|
const trimmed = command.trim();
|
|
157
322
|
if (trimmed.length === 0) {
|
|
158
323
|
return { allowed: false, reason: "empty command" };
|
|
159
324
|
}
|
|
160
|
-
const
|
|
161
|
-
if (
|
|
162
|
-
return
|
|
325
|
+
const script = readScript(trimmed);
|
|
326
|
+
if ("refused" in script) {
|
|
327
|
+
return { allowed: false, reason: script.refused };
|
|
328
|
+
}
|
|
329
|
+
if (!script.redirects.every(redirectReads)) {
|
|
330
|
+
return { allowed: false, reason: `${READ_ONLY} that command writes to a file` };
|
|
163
331
|
}
|
|
164
|
-
for (const
|
|
165
|
-
const refusal =
|
|
332
|
+
for (const simple of script.commands) {
|
|
333
|
+
const refusal = refuseCommand(simple);
|
|
166
334
|
if (refusal) {
|
|
167
335
|
return refusal;
|
|
168
336
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell-policy.js","sourceRoot":"","sources":["../../src/review/shell-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,iEAAiE;AACjE,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;IAC/B,KAAK;IACL,MAAM;IACN,MAAM;IACN,IAAI;IACJ,IAAI;IACJ,MAAM;IACN,IAAI;IACJ,MAAM;IACN,IAAI;IACJ,KAAK;IACL,KAAK;IACL,MAAM;IACN,MAAM;IACN,KAAK;IACL,IAAI;IACJ,MAAM;IACN,MAAM;IACN,IAAI;IACJ,MAAM;IACN,MAAM;IACN,UAAU;IACV,SAAS;IACT,UAAU;IACV,OAAO;IACP,KAAK;CACN,CAAC,CAAC;AAEH,mFAAmF;AACnF,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;IAChC,KAAK;IACL,MAAM;IACN,MAAM;IACN,QAAQ;IACR,OAAO;IACP,UAAU;IACV,WAAW;IACX,UAAU;IACV,4EAA4E;IAC5E,8CAA8C;IAC9C,cAAc;IACd,QAAQ;CACT,CAAC,CAAC;AAEH
|
|
1
|
+
{"version":3,"file":"shell-policy.js","sourceRoot":"","sources":["../../src/review/shell-policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -84,6 +84,82 @@ describe("reviewBashPolicy", () => {
|
|
|
84
84
|
expect(decision.allowed === false && decision.reason).toContain("read-only");
|
|
85
85
|
});
|
|
86
86
|
});
|
|
87
|
+
describe("quoted arguments, which are data rather than shell", () => {
|
|
88
|
+
it("allows a jq program or a grep pattern whose own `|` sits inside quotes", () => {
|
|
89
|
+
// The brief prescribes the jq projection to read a transcript without its
|
|
90
|
+
// thinking blocks; a `|` inside quotes is jq's or grep's, not the shell's.
|
|
91
|
+
for (const command of [
|
|
92
|
+
`jq -c 'del(.message.content[]?.thinking) | select(.type=="assistant")' ~/.claude/projects/p/s.jsonl`,
|
|
93
|
+
"grep -n -i 'inspiration\\|scrape' src/content/brief.md",
|
|
94
|
+
`grep -E "experiment|execFile" src/lib/run.ts | head -20`,
|
|
95
|
+
"grep -n '[^]]*' src/pages/index.astro",
|
|
96
|
+
]) {
|
|
97
|
+
expect(allows(command), command).toBe(true);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
it("still starts a new command at a pipe, `;` or newline outside quotes", () => {
|
|
101
|
+
for (const command of ["cat f | sh", "ls; git push", "jq '.a | .b' f | xargs rm", "grep 'a;b' f\ngit push"]) {
|
|
102
|
+
expect(allows(command), command).toBe(false);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
it("reads a quoted `>` as the argument's own, and an unquoted one as a write", () => {
|
|
106
|
+
expect(allows(`jq -c 'select(.costUsd > 1)' s.jsonl`)).toBe(true);
|
|
107
|
+
expect(allows("grep -n '=> ' src/lib/a.ts 2>/dev/null")).toBe(true);
|
|
108
|
+
expect(allows("grep -rn foo src 2>errors.txt")).toBe(false);
|
|
109
|
+
expect(allows("cat a.txt >> b.txt")).toBe(false);
|
|
110
|
+
expect(allows("jq . s.json >©.json")).toBe(false);
|
|
111
|
+
});
|
|
112
|
+
it("refuses every substitution the shell would run, and none it would not", () => {
|
|
113
|
+
for (const command of [
|
|
114
|
+
"cat <(rm -rf dist)",
|
|
115
|
+
`cat "$(which node)"`,
|
|
116
|
+
"grep x `echo f`",
|
|
117
|
+
"cat <<EOF\n$(rm -rf dist)\nEOF",
|
|
118
|
+
`ls \${HOME:-$(rm -rf dist)}`,
|
|
119
|
+
]) {
|
|
120
|
+
expect(allows(command), command).toBe(false);
|
|
121
|
+
}
|
|
122
|
+
expect(allows("grep -n '$(' scripts/build.sh")).toBe(true);
|
|
123
|
+
expect(allows("grep -c '`' src/content/post.md")).toBe(true);
|
|
124
|
+
});
|
|
125
|
+
it("refuses an environment prefix that hands a reader a program to run", () => {
|
|
126
|
+
// `git diff` runs `GIT_EXTERNAL_DIFF`, and a pager variable names one too.
|
|
127
|
+
expect(allows("GIT_EXTERNAL_DIFF=sh git diff")).toBe(false);
|
|
128
|
+
expect(allows("PAGER=./x git log")).toBe(false);
|
|
129
|
+
expect(allows("LC_ALL=C sort names.txt")).toBe(true);
|
|
130
|
+
});
|
|
131
|
+
it("still polices the quoted text of awk and sed, which is a program rather than data", () => {
|
|
132
|
+
for (const command of [
|
|
133
|
+
`awk 'BEGIN { system("curl https://example.com") }' f`,
|
|
134
|
+
`awk '{ print | "sh" }' f`,
|
|
135
|
+
`awk '{ print > "copy.txt" }' f`,
|
|
136
|
+
"sed -n 'w copy.txt' f",
|
|
137
|
+
"sed 's/a/b/w copy.txt' f",
|
|
138
|
+
"sed '1e id' f",
|
|
139
|
+
]) {
|
|
140
|
+
expect(allows(command), command).toBe(false);
|
|
141
|
+
}
|
|
142
|
+
expect(allows("sed -n '10,40p' src/pages/index.astro")).toBe(true);
|
|
143
|
+
expect(allows("awk -F, '{ print $1 }' data.csv")).toBe(true);
|
|
144
|
+
});
|
|
145
|
+
it("reads a denied name as a command only where it runs, not in a path", () => {
|
|
146
|
+
expect(allows("grep -n screenshot __tooling__/docs/tools/agent-browser.md")).toBe(true);
|
|
147
|
+
expect(reviewBashPolicy("agent-browser open https://example.com")).toEqual({
|
|
148
|
+
allowed: false,
|
|
149
|
+
reason: expect.stringContaining("drives a browser"),
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
describe("git, which reads or moves the branch depending on its verb", () => {
|
|
154
|
+
it("finds the verb after `-C <dir>`, so a read elsewhere is still a read", () => {
|
|
155
|
+
expect(allows("git -C /home/user/repo log --oneline -5")).toBe(true);
|
|
156
|
+
expect(allows("git -C repo push")).toBe(false);
|
|
157
|
+
});
|
|
158
|
+
it("refuses the other options before the verb, which can run a program", () => {
|
|
159
|
+
expect(allows("git -c core.pager=sh log")).toBe(false);
|
|
160
|
+
expect(allows("git --exec-path=/tmp log")).toBe(false);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
87
163
|
describe("find, which is a reader with writers bolted onto it", () => {
|
|
88
164
|
it("refuses the actions that delete or run something", () => {
|
|
89
165
|
// `find` is allowlisted because it reads. Its action flags are a second
|
|
@@ -104,5 +180,43 @@ describe("find, which is a reader with writers bolted onto it", () => {
|
|
|
104
180
|
it("still allows a plain find", () => {
|
|
105
181
|
expect(allows("find src -name '*.astro' -type f")).toBe(true);
|
|
106
182
|
});
|
|
183
|
+
it("reads those flags on find, not in another command's pattern", () => {
|
|
184
|
+
expect(allows("grep -rn -e ' -exec' __tooling__/checks")).toBe(true);
|
|
185
|
+
expect(allows("find . -name x '-delete'")).toBe(false);
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
describe("awk and sed programs the policy cannot read", () => {
|
|
189
|
+
it("refuses a program loaded from a file, whose code it never sees", () => {
|
|
190
|
+
// The workspace under review is the reviewed Session's own: a script file
|
|
191
|
+
// its agent wrote can call `system()` or `w` with nothing here to see it.
|
|
192
|
+
for (const command of [
|
|
193
|
+
"awk -f prog.awk data.txt",
|
|
194
|
+
"awk --file=prog.awk data.txt",
|
|
195
|
+
"awk -E prog.awk",
|
|
196
|
+
"sed -f script.sed file.md",
|
|
197
|
+
"sed --file=script.sed file.md",
|
|
198
|
+
]) {
|
|
199
|
+
expect(allows(command), command).toBe(false);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
202
|
+
it("reads an option's value as data, not as the program", () => {
|
|
203
|
+
// Splitting a markdown table on `|` is the ordinary way to read one.
|
|
204
|
+
expect(allows("awk -F'|' '{print $2}' digest/tools.md")).toBe(true);
|
|
205
|
+
expect(allows("awk -F '|' -v col=2 '{print $col}' digest/tools.md")).toBe(true);
|
|
206
|
+
expect(allows("awk -F'|' '{print $2 | \"sh\"}' digest/tools.md")).toBe(false);
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
describe("readers with an output flag", () => {
|
|
210
|
+
it("refuses the flags that write a file without a redirect", () => {
|
|
211
|
+
for (const command of [
|
|
212
|
+
"sort -o out.txt in.txt",
|
|
213
|
+
"sort --output=out.txt in.txt",
|
|
214
|
+
"git log --output=log.txt",
|
|
215
|
+
"git diff --output log.txt",
|
|
216
|
+
]) {
|
|
217
|
+
expect(allows(command), command).toBe(false);
|
|
218
|
+
}
|
|
219
|
+
expect(allows("sort -u in.txt")).toBe(true);
|
|
220
|
+
});
|
|
107
221
|
});
|
|
108
222
|
//# sourceMappingURL=shell-policy.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shell-policy.test.js","sourceRoot":"","sources":["../../src/review/shell-policy.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"shell-policy.test.js","sourceRoot":"","sources":["../../src/review/shell-policy.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@koda-sl/baker-bridge",
|
|
3
|
-
"version": "0.109.0-dev.
|
|
3
|
+
"version": "0.109.0-dev.d6e55699d",
|
|
4
4
|
"description": "HTTP server wrapping the Claude Agent SDK. Persists chat events to Convex; the dashboard subscribes via Convex realtime",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
|
-
"baker-bridge": "dist/cli.js"
|
|
8
|
+
"baker-bridge": "dist/cli.js",
|
|
9
|
+
"baker-credential-broker": "dist/broker/main.js",
|
|
10
|
+
"baker-credential-broker-supervisor": "dist/broker/supervisor-main.js"
|
|
9
11
|
},
|
|
10
12
|
"exports": {
|
|
11
13
|
"./hono": {
|
|
@@ -39,20 +41,22 @@
|
|
|
39
41
|
"unlink:local": "bash scripts/unlink-local.sh"
|
|
40
42
|
},
|
|
41
43
|
"dependencies": {
|
|
42
|
-
"@anthropic-ai/claude-agent-sdk": "^0.3.
|
|
44
|
+
"@anthropic-ai/claude-agent-sdk": "^0.3.295",
|
|
43
45
|
"@hono/node-server": "^1.19.14",
|
|
44
|
-
"@latitude-data/claude-code-telemetry": "0.0.15",
|
|
45
46
|
"@t3-oss/env-core": "^0.13.10",
|
|
46
47
|
"hono": "^4.12.25",
|
|
47
48
|
"image-size": "^2.0.2",
|
|
49
|
+
"mockttp": "4.6.3",
|
|
50
|
+
"unbash": "4.0.11",
|
|
48
51
|
"zod": "^4.3.6"
|
|
49
52
|
},
|
|
50
53
|
"devDependencies": {
|
|
51
54
|
"@types/node": "25.3.0",
|
|
52
55
|
"tsx": "^4.0.0",
|
|
53
56
|
"typescript": "^7.0.2",
|
|
57
|
+
"undici": "7.29.0",
|
|
54
58
|
"vite": "7.3.2",
|
|
55
|
-
"vitest": "^
|
|
59
|
+
"vitest": "^5.0.3"
|
|
56
60
|
},
|
|
57
61
|
"repository": {
|
|
58
62
|
"type": "git",
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import type { Settings } from "@anthropic-ai/claude-agent-sdk";
|
|
2
|
-
type LatitudeHook = {
|
|
3
|
-
readonly node: string;
|
|
4
|
-
readonly entry: string;
|
|
5
|
-
};
|
|
6
|
-
type LatitudeHooks = NonNullable<Settings["hooks"]>;
|
|
7
|
-
/**
|
|
8
|
-
* `Stop` reports each turn without delaying it; `SessionEnd` is synchronous
|
|
9
|
-
* because it is the one that still fires when the CLI exits right after a turn,
|
|
10
|
-
* which is how the bridge closes a query. The hook's own offset lock keeps the
|
|
11
|
-
* two from reporting a turn twice.
|
|
12
|
-
*/
|
|
13
|
-
export declare function latitudeTelemetryFor(env: Record<string, string | undefined>, hook: LatitudeHook | undefined): LatitudeHooks | undefined;
|
|
14
|
-
/** Where the installed hook lives; undefined turns tracing off rather than failing the turn. */
|
|
15
|
-
export declare function installedLatitudeHook(): LatitudeHook | undefined;
|
|
16
|
-
export {};
|
|
17
|
-
//# sourceMappingURL=latitude-telemetry.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"latitude-telemetry.d.ts","sourceRoot":"","sources":["../../src/hono/latitude-telemetry.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAE/D,KAAK,YAAY,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtE,KAAK,aAAa,GAAG,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;AAEpD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,EACvC,IAAI,EAAE,YAAY,GAAG,SAAS,GAC7B,aAAa,GAAG,SAAS,CAS3B;AAED,gGAAgG;AAChG,wBAAgB,qBAAqB,IAAI,YAAY,GAAG,SAAS,CAOhE"}
|