@koda-sl/baker-bridge 0.119.0 → 0.121.0-dev.ba3f112da

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.
Files changed (140) hide show
  1. package/README.md +1 -19
  2. package/dist/hono/agent-session.d.ts +0 -3
  3. package/dist/hono/agent-session.d.ts.map +1 -1
  4. package/dist/hono/agent-session.js +0 -15
  5. package/dist/hono/agent-session.js.map +1 -1
  6. package/dist/hono/agent.d.ts +0 -2
  7. package/dist/hono/agent.d.ts.map +1 -1
  8. package/dist/hono/agent.js +2 -10
  9. package/dist/hono/agent.js.map +1 -1
  10. package/dist/hono/baker-ui-tool-schemas.test.js +0 -6
  11. package/dist/hono/baker-ui-tool-schemas.test.js.map +1 -1
  12. package/dist/hono/bridge-job.d.ts +1 -13
  13. package/dist/hono/bridge-job.d.ts.map +1 -1
  14. package/dist/hono/bridge-job.js +5 -69
  15. package/dist/hono/bridge-job.js.map +1 -1
  16. package/dist/hono/bridge-job.test.js +1 -113
  17. package/dist/hono/bridge-job.test.js.map +1 -1
  18. package/dist/hono/connection-input.d.ts +1 -8
  19. package/dist/hono/connection-input.d.ts.map +1 -1
  20. package/dist/hono/connection-input.js +1 -2
  21. package/dist/hono/connection-input.js.map +1 -1
  22. package/dist/hono/connection-input.test.js +8 -17
  23. package/dist/hono/connection-input.test.js.map +1 -1
  24. package/dist/hono/convex.d.ts +0 -8
  25. package/dist/hono/convex.d.ts.map +1 -1
  26. package/dist/hono/convex.js +0 -8
  27. package/dist/hono/convex.js.map +1 -1
  28. package/dist/hono/latitude-telemetry.d.ts.map +1 -1
  29. package/dist/hono/latitude-telemetry.js +2 -8
  30. package/dist/hono/latitude-telemetry.js.map +1 -1
  31. package/dist/hono/prompt-context.d.ts +1 -8
  32. package/dist/hono/prompt-context.d.ts.map +1 -1
  33. package/dist/hono/prompt-context.js +7 -45
  34. package/dist/hono/prompt-context.js.map +1 -1
  35. package/dist/hono/prompt-context.test.js +1 -35
  36. package/dist/hono/prompt-context.test.js.map +1 -1
  37. package/dist/hono/relay.d.ts +1 -10
  38. package/dist/hono/relay.d.ts.map +1 -1
  39. package/dist/hono/relay.js +0 -6
  40. package/dist/hono/relay.js.map +1 -1
  41. package/dist/hono/server.d.ts.map +1 -1
  42. package/dist/hono/server.js +0 -22
  43. package/dist/hono/server.js.map +1 -1
  44. package/dist/hono/tag-input.d.ts +3 -105
  45. package/dist/hono/tag-input.d.ts.map +1 -1
  46. package/dist/hono/tag-input.js +9 -20
  47. package/dist/hono/tag-input.js.map +1 -1
  48. package/dist/hono/tag-input.test.js +1 -19
  49. package/dist/hono/tag-input.test.js.map +1 -1
  50. package/dist/hono/types.d.ts +0 -8
  51. package/dist/hono/types.d.ts.map +1 -1
  52. package/package.json +2 -5
  53. package/dist/broker/baker-api.d.ts +0 -23
  54. package/dist/broker/baker-api.d.ts.map +0 -1
  55. package/dist/broker/baker-api.js +0 -55
  56. package/dist/broker/baker-api.js.map +0 -1
  57. package/dist/broker/broker-client.d.ts +0 -10
  58. package/dist/broker/broker-client.d.ts.map +0 -1
  59. package/dist/broker/broker-client.js +0 -60
  60. package/dist/broker/broker-client.js.map +0 -1
  61. package/dist/broker/ca.d.ts +0 -38
  62. package/dist/broker/ca.d.ts.map +0 -1
  63. package/dist/broker/ca.js +0 -80
  64. package/dist/broker/ca.js.map +0 -1
  65. package/dist/broker/ca.test.d.ts +0 -2
  66. package/dist/broker/ca.test.d.ts.map +0 -1
  67. package/dist/broker/ca.test.js +0 -58
  68. package/dist/broker/ca.test.js.map +0 -1
  69. package/dist/broker/credential-cache.d.ts +0 -24
  70. package/dist/broker/credential-cache.d.ts.map +0 -1
  71. package/dist/broker/credential-cache.js +0 -69
  72. package/dist/broker/credential-cache.js.map +0 -1
  73. package/dist/broker/credential-cache.test.d.ts +0 -2
  74. package/dist/broker/credential-cache.test.d.ts.map +0 -1
  75. package/dist/broker/credential-cache.test.js +0 -120
  76. package/dist/broker/credential-cache.test.js.map +0 -1
  77. package/dist/broker/credential-text.d.ts +0 -45
  78. package/dist/broker/credential-text.d.ts.map +0 -1
  79. package/dist/broker/credential-text.js +0 -103
  80. package/dist/broker/credential-text.js.map +0 -1
  81. package/dist/broker/credential-text.test.d.ts +0 -2
  82. package/dist/broker/credential-text.test.d.ts.map +0 -1
  83. package/dist/broker/credential-text.test.js +0 -54
  84. package/dist/broker/credential-text.test.js.map +0 -1
  85. package/dist/broker/env.d.ts +0 -19
  86. package/dist/broker/env.d.ts.map +0 -1
  87. package/dist/broker/env.js +0 -16
  88. package/dist/broker/env.js.map +0 -1
  89. package/dist/broker/main.d.ts +0 -3
  90. package/dist/broker/main.d.ts.map +0 -1
  91. package/dist/broker/main.js +0 -51
  92. package/dist/broker/main.js.map +0 -1
  93. package/dist/broker/proxy.d.ts +0 -24
  94. package/dist/broker/proxy.d.ts.map +0 -1
  95. package/dist/broker/proxy.integration.test.d.ts +0 -2
  96. package/dist/broker/proxy.integration.test.d.ts.map +0 -1
  97. package/dist/broker/proxy.integration.test.js +0 -201
  98. package/dist/broker/proxy.integration.test.js.map +0 -1
  99. package/dist/broker/proxy.js +0 -147
  100. package/dist/broker/proxy.js.map +0 -1
  101. package/dist/broker/rewrite.d.ts +0 -44
  102. package/dist/broker/rewrite.d.ts.map +0 -1
  103. package/dist/broker/rewrite.js +0 -291
  104. package/dist/broker/rewrite.js.map +0 -1
  105. package/dist/broker/rewrite.test.d.ts +0 -2
  106. package/dist/broker/rewrite.test.d.ts.map +0 -1
  107. package/dist/broker/rewrite.test.js +0 -171
  108. package/dist/broker/rewrite.test.js.map +0 -1
  109. package/dist/broker/socket-service.d.ts +0 -18
  110. package/dist/broker/socket-service.d.ts.map +0 -1
  111. package/dist/broker/socket-service.js +0 -103
  112. package/dist/broker/socket-service.js.map +0 -1
  113. package/dist/broker/socket-service.test.d.ts +0 -2
  114. package/dist/broker/socket-service.test.d.ts.map +0 -1
  115. package/dist/broker/socket-service.test.js +0 -73
  116. package/dist/broker/socket-service.test.js.map +0 -1
  117. package/dist/broker/token-bucket.d.ts +0 -9
  118. package/dist/broker/token-bucket.d.ts.map +0 -1
  119. package/dist/broker/token-bucket.js +0 -18
  120. package/dist/broker/token-bucket.js.map +0 -1
  121. package/dist/broker/usage-reporter.d.ts +0 -18
  122. package/dist/broker/usage-reporter.d.ts.map +0 -1
  123. package/dist/broker/usage-reporter.js +0 -31
  124. package/dist/broker/usage-reporter.js.map +0 -1
  125. package/dist/broker/usage-reporter.test.d.ts +0 -2
  126. package/dist/broker/usage-reporter.test.d.ts.map +0 -1
  127. package/dist/broker/usage-reporter.test.js +0 -20
  128. package/dist/broker/usage-reporter.test.js.map +0 -1
  129. package/dist/hono/credential-input.d.ts +0 -39
  130. package/dist/hono/credential-input.d.ts.map +0 -1
  131. package/dist/hono/credential-input.js +0 -78
  132. package/dist/hono/credential-input.js.map +0 -1
  133. package/dist/hono/credential-scrub.d.ts +0 -41
  134. package/dist/hono/credential-scrub.d.ts.map +0 -1
  135. package/dist/hono/credential-scrub.js +0 -152
  136. package/dist/hono/credential-scrub.js.map +0 -1
  137. package/dist/hono/credential-scrub.test.d.ts +0 -2
  138. package/dist/hono/credential-scrub.test.d.ts.map +0 -1
  139. package/dist/hono/credential-scrub.test.js +0 -105
  140. package/dist/hono/credential-scrub.test.js.map +0 -1
@@ -1,78 +0,0 @@
1
- /**
2
- * `request_credential` — the `baker_ui` blocking tool the agent uses when it
3
- * needs a secret the user owns (an API key, a token, a password).
4
- *
5
- * The value never passes through the model or this bridge: the dashboard
6
- * seals it straight into the company's Credentials, and the resolution that
7
- * comes back is only the placeholder the agent writes into requests
8
- * (`{{credential:<name>}}`), which the sandbox's credential broker swaps for the
9
- * value on the way out — and only toward the websites the user allowed.
10
- */
11
- import { tool } from "@anthropic-ai/claude-agent-sdk";
12
- import { z } from "zod";
13
- import { answeredInTheCard } from "./blocking-card.js";
14
- export const CREDENTIAL_INPUT_TOOL_NAME = "mcp__baker_ui__request_credential";
15
- const credentialRequestShape = z.object({
16
- label: z
17
- .string()
18
- .trim()
19
- .min(1)
20
- .max(80)
21
- .describe("What the credential is, in the user's words: 'Shopify admin API token', 'Klaviyo private key'"),
22
- reason: z
23
- .string()
24
- .trim()
25
- .min(1)
26
- .max(500)
27
- .describe("One short sentence, in the user's terms, saying what you'll do with it"),
28
- allowedHosts: z
29
- .array(z.string().max(253))
30
- .max(20)
31
- .describe("The websites the credential will be sent to, e.g. ['api.stripe.com'] or ['acme-store.myshopify.com']. Only these will ever receive it."),
32
- name: z
33
- .string()
34
- .regex(/^[a-z0-9][a-z0-9_-]{0,63}$/)
35
- .optional()
36
- .describe("The name you want to use in {{credential:<name>}}; Baker picks a free one if it is taken"),
37
- });
38
- export const credentialInputToolShape = {
39
- ...credentialRequestShape.shape,
40
- resolution: z
41
- .object({})
42
- .catchall(z.unknown())
43
- .optional()
44
- .describe("Internal — injected by the bridge after the user answers. Never set this yourself."),
45
- };
46
- export const credentialInputResultSchema = z.discriminatedUnion("status", [
47
- z.object({
48
- status: z.literal("stored"),
49
- name: z.string(),
50
- placeholder: z.string(),
51
- allowedHosts: z.array(z.string()),
52
- }),
53
- z.object({ status: z.literal("declined"), reason: z.string().optional() }),
54
- ]);
55
- /** Parse-at-boundary for the result posted to `POST /credential-input-decision`. */
56
- export function parseCredentialInputResult(value) {
57
- const parsed = credentialInputResultSchema.safeParse(value);
58
- return parsed.success ? parsed.data : null;
59
- }
60
- /** `canUseTool` sees the raw model input, before MCP validation. */
61
- export function normalizeCredentialInputToolInput(input) {
62
- const parsed = credentialRequestShape.safeParse(input);
63
- return parsed.success ? parsed.data : null;
64
- }
65
- const CREDENTIAL_INPUT_TOOL_DESCRIPTION = [
66
- "Ask the user for a credential they own — an API key, access token or password — through a secure field in the dashboard. BLOCKS until they answer.",
67
- "Use it whenever a task needs a secret you do not have. Never ask the user to paste a secret in the chat, and never ask for one Baker already connects (use request_connection for ad and data platforms).",
68
- "`reason` is shown to the user: say what you will do with it in their terms. `allowedHosts` are the only websites it will ever be sent to — name the API host(s) the task calls.",
69
- "You never see the value. A stored result gives you a placeholder such as {{credential:shopify-admin}}: put it exactly where the secret goes in an HTTPS request (header, URL, JSON body, or inside `-u user:{{credential:x}}`), and it is filled in on the way out. Never print, echo, save or try to read a credential.",
70
- "A declined result is not an error: carry on with what you can do without it and tell the user what stays unavailable.",
71
- ].join(" ");
72
- export function createCredentialInputTool() {
73
- return answeredInTheCard(tool("request_credential", CREDENTIAL_INPUT_TOOL_DESCRIPTION, credentialInputToolShape, (args) => {
74
- const resolution = args.resolution ?? { status: "declined", reason: "No answer" };
75
- return Promise.resolve({ content: [{ type: "text", text: JSON.stringify(resolution) }] });
76
- }));
77
- }
78
- //# sourceMappingURL=credential-input.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"credential-input.js","sourceRoot":"","sources":["../../src/hono/credential-input.ts"],"names":[],"mappings":"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"}
@@ -1,41 +0,0 @@
1
- /**
2
- * The last line between a credential value and the model: every tool result is
3
- * passed through the credential broker's scrub before the model reads it.
4
- *
5
- * The broker already swaps values out of HTTP responses; this catches what did
6
- * not travel through it (a value echoed by a tool that ignored the proxy, a
7
- * response too large to rewrite). The bridge never holds values — the broker
8
- * scrubs, over its socket. Without a broker (local dev, a company without
9
- * Credentials) it is a no-op.
10
- */
11
- import type { HookCallbackMatcher, HookEvent } from "@anthropic-ai/claude-agent-sdk";
12
- type Scrub = (text: string) => Promise<string>;
13
- /** Well under the broker socket's 2 MB cap, even after JSON escaping. */
14
- export declare const MAX_SCRUB_BATCH_BYTES: number;
15
- /**
16
- * The tool result with every credential value replaced by its placeholder,
17
- * walking every string in it. Long pure-base64 leaves are skipped; the rest go
18
- * to the broker in calls of at most 1 MB, and a text over 1 MB on its own is
19
- * withheld. Throws — so the caller withholds the result — when the broker fails.
20
- */
21
- export declare function scrubToolResponse(response: unknown, scrub: Scrub): Promise<{
22
- changed: boolean;
23
- response: unknown;
24
- }>;
25
- /**
26
- * The result with every text that could hold a value withheld, in the tool's
27
- * own shape: the SDK checks a rewrite against the tool's output schema and
28
- * falls back to the original — unscrubbed — output when it does not fit.
29
- */
30
- export declare function withheldToolResponse(response: unknown): unknown;
31
- /**
32
- * PostToolUse for every tool. The SDK runs PostToolUse hooks in parallel on
33
- * the original output and the last `updatedToolOutput` written wins; no other
34
- * hook sets `updatedToolOutput`, so this one's is the output the model reads.
35
- */
36
- export declare function credentialScrubHooks({ scrub, brokerRunning: running, }?: {
37
- scrub?: Scrub;
38
- brokerRunning?: () => boolean;
39
- }): Partial<Record<HookEvent, HookCallbackMatcher[]>>;
40
- export {};
41
- //# sourceMappingURL=credential-scrub.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"credential-scrub.d.ts","sourceRoot":"","sources":["../../src/hono/credential-scrub.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAGrF,KAAK,KAAK,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AA2B/C,yEAAyE;AACzE,eAAO,MAAM,qBAAqB,QAAc,CAAC;AA6CjD;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,OAAO,EACjB,KAAK,EAAE,KAAK,GACX,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAA;CAAE,CAAC,CAkBlD;AAKD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAS/D;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,EACnC,KAAsC,EACtC,aAAa,EAAE,OAA+B,GAC/C,GAAE;IACD,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,OAAO,CAAC;CAC1B,GAAG,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,mBAAmB,EAAE,CAAC,CAAC,CA2BzD"}
@@ -1,152 +0,0 @@
1
- import { brokerRunning, scrubViaBroker } from "../broker/broker-client.js";
2
- /** Joins string leaves for one broker call; a leaf that itself contains it is sent alone. */
3
- const SEPARATOR = "\u0000";
4
- function collectLeaves(value, key, into) {
5
- if (typeof value === "string")
6
- into.push({ text: value, key });
7
- else if (Array.isArray(value))
8
- for (const item of value)
9
- collectLeaves(item, key, into);
10
- else if (typeof value === "object" && value !== null)
11
- for (const [name, item] of Object.entries(value))
12
- collectLeaves(item, name, into);
13
- }
14
- /** `value` with its string leaves replaced in the order `collectLeaves` read them. */
15
- function replaceLeaves(value, next) {
16
- if (typeof value === "string")
17
- return next();
18
- if (Array.isArray(value))
19
- return value.map((item) => replaceLeaves(item, next));
20
- if (typeof value === "object" && value !== null) {
21
- return Object.fromEntries(Object.entries(value).map(([name, item]) => [name, replaceLeaves(item, next)]));
22
- }
23
- return value;
24
- }
25
- /** Media (a PDF or image read as base64): long and pure base64, so it cannot hold a value verbatim. */
26
- const MEDIA_MIN_LENGTH = 64 * 1024;
27
- const PURE_BASE64 = /^[A-Za-z0-9+/=\r\n]+$/;
28
- /** Well under the broker socket's 2 MB cap, even after JSON escaping. */
29
- export const MAX_SCRUB_BATCH_BYTES = 1024 * 1024;
30
- function isMedia(leaf) {
31
- if (!PURE_BASE64.test(leaf.text))
32
- return false;
33
- return leaf.text.length >= MEDIA_MIN_LENGTH || leaf.key === "base64";
34
- }
35
- const WITHHELD = "This output was withheld: Baker could not check it for saved credentials. Run the step again in a moment.";
36
- const TOO_LARGE = "This text was withheld: it is too large for Baker to check for saved credentials. Read it in smaller parts.";
37
- function cost(text) {
38
- return Buffer.byteLength(JSON.stringify(text));
39
- }
40
- /** Indexes of the leaves to scrub, grouped so each group fits one broker call, and those too large to check. */
41
- function batches(leaves) {
42
- const groups = [];
43
- const tooLarge = [];
44
- let current = [];
45
- let size = 0;
46
- leaves.forEach((leaf, index) => {
47
- if (leaf.text.length === 0 || (leaf.text.length >= MEDIA_MIN_LENGTH && isMedia(leaf)))
48
- return;
49
- const bytes = cost(leaf.text) + cost(SEPARATOR);
50
- if (bytes > MAX_SCRUB_BATCH_BYTES) {
51
- tooLarge.push(index);
52
- return;
53
- }
54
- if (leaf.text.includes(SEPARATOR)) {
55
- groups.push([index]);
56
- return;
57
- }
58
- if (size + bytes > MAX_SCRUB_BATCH_BYTES && current.length > 0) {
59
- groups.push(current);
60
- current = [];
61
- size = 0;
62
- }
63
- current.push(index);
64
- size += bytes;
65
- });
66
- if (current.length > 0)
67
- groups.push(current);
68
- return { groups, tooLarge };
69
- }
70
- /**
71
- * The tool result with every credential value replaced by its placeholder,
72
- * walking every string in it. Long pure-base64 leaves are skipped; the rest go
73
- * to the broker in calls of at most 1 MB, and a text over 1 MB on its own is
74
- * withheld. Throws — so the caller withholds the result — when the broker fails.
75
- */
76
- export async function scrubToolResponse(response, scrub) {
77
- const leaves = [];
78
- collectLeaves(response, undefined, leaves);
79
- const scrubbed = leaves.map((leaf) => leaf.text);
80
- const { groups, tooLarge } = batches(leaves);
81
- for (const index of tooLarge)
82
- scrubbed[index] = TOO_LARGE;
83
- for (const group of groups) {
84
- const joined = group.map((index) => leaves[index]?.text ?? "").join(SEPARATOR);
85
- const result = await scrub(joined);
86
- const parts = group.length === 1 ? [result] : result.split(SEPARATOR);
87
- if (parts.length !== group.length)
88
- throw new Error("scrubbed text no longer lines up with the tool result");
89
- group.forEach((index, position) => {
90
- scrubbed[index] = parts[position] ?? "";
91
- });
92
- }
93
- if (scrubbed.every((text, index) => text === leaves[index]?.text))
94
- return { changed: false, response };
95
- let index = 0;
96
- return { changed: true, response: replaceLeaves(response, () => scrubbed[index++] ?? "") };
97
- }
98
- /** Fields that name what a result is (`type: "text"`), never what it says; a tool's output schema requires them as-is. */
99
- const STRUCTURAL_KEYS = new Set(["type", "media_type", "mimeType", "status", "kind", "mode"]);
100
- /**
101
- * The result with every text that could hold a value withheld, in the tool's
102
- * own shape: the SDK checks a rewrite against the tool's output schema and
103
- * falls back to the original — unscrubbed — output when it does not fit.
104
- */
105
- export function withheldToolResponse(response) {
106
- const leaves = [];
107
- collectLeaves(response, undefined, leaves);
108
- let index = 0;
109
- return replaceLeaves(response, () => {
110
- const leaf = leaves[index++];
111
- if (leaf === undefined)
112
- return WITHHELD;
113
- return STRUCTURAL_KEYS.has(leaf.key ?? "") || isMedia(leaf) ? leaf.text : WITHHELD;
114
- });
115
- }
116
- /**
117
- * PostToolUse for every tool. The SDK runs PostToolUse hooks in parallel on
118
- * the original output and the last `updatedToolOutput` written wins; no other
119
- * hook sets `updatedToolOutput`, so this one's is the output the model reads.
120
- */
121
- export function credentialScrubHooks({ scrub = (text) => scrubViaBroker(text), brokerRunning: running = () => brokerRunning(), } = {}) {
122
- return {
123
- PostToolUse: [
124
- {
125
- hooks: [
126
- async (input) => {
127
- if (input.hook_event_name !== "PostToolUse" || !running())
128
- return {};
129
- try {
130
- const result = await scrubToolResponse(input.tool_response, scrub);
131
- if (!result.changed)
132
- return {};
133
- return {
134
- hookSpecificOutput: { hookEventName: "PostToolUse", updatedToolOutput: result.response },
135
- };
136
- }
137
- catch (error) {
138
- console.error("[credentials] could not scrub a tool result — withholding it", error);
139
- return {
140
- hookSpecificOutput: {
141
- hookEventName: "PostToolUse",
142
- updatedToolOutput: withheldToolResponse(input.tool_response),
143
- },
144
- };
145
- }
146
- },
147
- ],
148
- },
149
- ],
150
- };
151
- }
152
- //# sourceMappingURL=credential-scrub.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"credential-scrub.js","sourceRoot":"","sources":["../../src/hono/credential-scrub.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=credential-scrub.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"credential-scrub.test.d.ts","sourceRoot":"","sources":["../../src/hono/credential-scrub.test.ts"],"names":[],"mappings":""}
@@ -1,105 +0,0 @@
1
- import { describe, expect, it } from "vitest";
2
- import { credentialScrubHooks, scrubToolResponse } from "./credential-scrub.js";
3
- const fakeScrub = (text) => Promise.resolve(text.split("shpat_secret_value").join("{{credential:shop}}"));
4
- /** The broker socket refuses a body over 2 MB. */
5
- const socketScrub = (text) => Buffer.byteLength(JSON.stringify({ text })) > 2 * 1024 * 1024
6
- ? Promise.reject(new Error("credential broker /scrub answered 413"))
7
- : fakeScrub(text);
8
- describe("scrubToolResponse", () => {
9
- it("replaces a credential value anywhere in a tool result, keeping its shape", async () => {
10
- const response = { stdout: "token=shpat_secret_value\n", stderr: "", nested: [{ body: "x shpat_secret_value" }] };
11
- await expect(scrubToolResponse(response, fakeScrub)).resolves.toEqual({
12
- changed: true,
13
- response: { stdout: "token={{credential:shop}}\n", stderr: "", nested: [{ body: "x {{credential:shop}}" }] },
14
- });
15
- });
16
- it("reports no change when nothing in the result was a credential", async () => {
17
- await expect(scrubToolResponse({ stdout: "ok" }, fakeScrub)).resolves.toEqual({
18
- changed: false,
19
- response: { stdout: "ok" },
20
- });
21
- });
22
- it("leaves large media untouched instead of withholding the whole result", async () => {
23
- const media = Buffer.alloc(3 * 1024 * 1024, 7).toString("base64");
24
- const response = [
25
- { type: "image", source: { data: media } },
26
- { type: "text", text: "shpat_secret_value" },
27
- ];
28
- const result = await scrubToolResponse(response, socketScrub);
29
- expect(result).toEqual({
30
- changed: true,
31
- response: [
32
- { type: "image", source: { data: media } },
33
- { type: "text", text: "{{credential:shop}}" },
34
- ],
35
- });
36
- });
37
- it("checks a result larger than one broker call in several calls", async () => {
38
- const chunk = `${"log line\n".repeat(80_000)}shpat_secret_value`;
39
- const response = { outputs: [chunk, chunk, chunk] };
40
- const result = await scrubToolResponse(response, socketScrub);
41
- const scrubbedChunk = `${"log line\n".repeat(80_000)}{{credential:shop}}`;
42
- expect(result).toEqual({ changed: true, response: { outputs: [scrubbedChunk, scrubbedChunk, scrubbedChunk] } });
43
- });
44
- it("withholds only a text over 1 MB, and still checks the rest", async () => {
45
- const response = { stdout: "word ".repeat(210_000), stderr: "shpat_secret_value" };
46
- const result = await scrubToolResponse(response, socketScrub);
47
- expect(result).toEqual({
48
- changed: true,
49
- response: { stdout: expect.stringContaining("withheld"), stderr: "{{credential:shop}}" },
50
- });
51
- });
52
- it("scrubs a text that contains the separator byte without misaligning the others", async () => {
53
- const response = { stdout: "bin\u0000ary shpat_secret_value", stderr: "shpat_secret_value" };
54
- await expect(scrubToolResponse(response, fakeScrub)).resolves.toEqual({
55
- changed: true,
56
- response: { stdout: "bin\u0000ary {{credential:shop}}", stderr: "{{credential:shop}}" },
57
- });
58
- });
59
- });
60
- async function runHook(response, options) {
61
- const hook = credentialScrubHooks(options).PostToolUse?.[0]?.hooks[0];
62
- if (hook === undefined)
63
- throw new Error("no PostToolUse hook");
64
- const output = await hook({
65
- hook_event_name: "PostToolUse",
66
- tool_name: "Read",
67
- tool_input: {},
68
- tool_response: response,
69
- tool_use_id: "t1",
70
- session_id: "s",
71
- transcript_path: "",
72
- cwd: "/",
73
- }, "t1", { signal: new AbortController().signal });
74
- return "hookSpecificOutput" in output && output.hookSpecificOutput?.hookEventName === "PostToolUse"
75
- ? output.hookSpecificOutput.updatedToolOutput
76
- : undefined;
77
- }
78
- describe("credentialScrubHooks", () => {
79
- it("withholds a result it could not check in the tool's own shape, which the SDK only accepts", async () => {
80
- const read = {
81
- type: "text",
82
- file: { filePath: "/repo/.env", content: "TOKEN=shpat_secret_value", numLines: 1, startLine: 1, totalLines: 1 },
83
- };
84
- const output = await runHook(read, {
85
- scrub: () => Promise.reject(new Error("credential broker /scrub timed out")),
86
- brokerRunning: () => true,
87
- });
88
- expect(output).toEqual({
89
- type: "text",
90
- file: {
91
- filePath: expect.stringContaining("withheld"),
92
- content: expect.stringContaining("withheld"),
93
- numLines: 1,
94
- startLine: 1,
95
- totalLines: 1,
96
- },
97
- });
98
- });
99
- it("leaves a result alone when no broker runs, however large", async () => {
100
- const response = { stdout: "word ".repeat(210_000) };
101
- const output = await runHook(response, { scrub: fakeScrub, brokerRunning: () => false });
102
- expect(output).toBeUndefined();
103
- });
104
- });
105
- //# sourceMappingURL=credential-scrub.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"credential-scrub.test.js","sourceRoot":"","sources":["../../src/hono/credential-scrub.test.ts"],"names":[],"mappings":"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"}