@intutic/mcp-governance-proxy 2.1.0 → 2.3.0
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 +34 -18
- package/dist/agentTools.d.ts +68 -0
- package/dist/agentTools.d.ts.map +1 -0
- package/dist/agentTools.js +150 -0
- package/dist/agentTools.js.map +1 -0
- package/dist/anomaly/detectors.js +1 -1
- package/dist/anomaly/detectors.js.map +1 -1
- package/dist/anomaly/index.d.ts +2 -1
- package/dist/anomaly/index.d.ts.map +1 -1
- package/dist/anomaly/index.js.map +1 -1
- package/dist/approvalHold.d.ts +66 -0
- package/dist/approvalHold.d.ts.map +1 -0
- package/dist/approvalHold.js +143 -0
- package/dist/approvalHold.js.map +1 -0
- package/dist/budget.d.ts +133 -0
- package/dist/budget.d.ts.map +1 -0
- package/dist/budget.js +191 -0
- package/dist/budget.js.map +1 -0
- package/dist/config.d.ts +7 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -2
- package/dist/config.js.map +1 -1
- package/dist/daemon/healthMonitor.d.ts +2 -0
- package/dist/daemon/healthMonitor.d.ts.map +1 -1
- package/dist/daemon/healthMonitor.js +60 -27
- package/dist/daemon/healthMonitor.js.map +1 -1
- package/dist/daemon/index.d.ts +0 -2
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +0 -2
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/instrumentation.d.ts +2 -2
- package/dist/daemon/instrumentation.js +2 -2
- package/dist/daemon/policyCache.d.ts +38 -3
- package/dist/daemon/policyCache.d.ts.map +1 -1
- package/dist/daemon/policyCache.js +64 -22
- package/dist/daemon/policyCache.js.map +1 -1
- package/dist/daemon/socketServer.d.ts +0 -1
- package/dist/daemon/socketServer.d.ts.map +1 -1
- package/dist/daemon/socketServer.js +0 -1
- package/dist/daemon/socketServer.js.map +1 -1
- package/dist/daemon/statusReporter.d.ts.map +1 -1
- package/dist/daemon/statusReporter.js +0 -1
- package/dist/daemon/statusReporter.js.map +1 -1
- package/dist/daemon/telemetryBatcher.d.ts.map +1 -1
- package/dist/daemon/telemetryBatcher.js +0 -1
- package/dist/daemon/telemetryBatcher.js.map +1 -1
- package/dist/daemonClient.d.ts.map +1 -1
- package/dist/daemonClient.js +0 -1
- package/dist/daemonClient.js.map +1 -1
- package/dist/dlp.d.ts +32 -3
- package/dist/dlp.d.ts.map +1 -1
- package/dist/dlp.js +116 -18
- package/dist/dlp.js.map +1 -1
- package/dist/dlpPii.d.ts +66 -0
- package/dist/dlpPii.d.ts.map +1 -0
- package/dist/dlpPii.js +235 -0
- package/dist/dlpPii.js.map +1 -0
- package/dist/emitter.d.ts +68 -10
- package/dist/emitter.d.ts.map +1 -1
- package/dist/emitter.js +29 -43
- package/dist/emitter.js.map +1 -1
- package/dist/guardedValkey.d.ts +40 -0
- package/dist/guardedValkey.d.ts.map +1 -0
- package/dist/guardedValkey.js +84 -0
- package/dist/guardedValkey.js.map +1 -0
- package/dist/httpJson.d.ts +19 -0
- package/dist/httpJson.d.ts.map +1 -0
- package/dist/httpJson.js +62 -0
- package/dist/httpJson.js.map +1 -0
- package/dist/identity.d.ts +27 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +36 -0
- package/dist/identity.js.map +1 -0
- package/dist/injection.js +1 -1
- package/dist/interceptor.d.ts +135 -8
- package/dist/interceptor.d.ts.map +1 -1
- package/dist/interceptor.js +284 -45
- package/dist/interceptor.js.map +1 -1
- package/dist/policy.d.ts +105 -2
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +188 -40
- package/dist/policy.js.map +1 -1
- package/dist/proxy.d.ts +35 -11
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +183 -66
- package/dist/proxy.js.map +1 -1
- package/dist/refusals.d.ts +26 -0
- package/dist/refusals.d.ts.map +1 -0
- package/dist/refusals.js +43 -0
- package/dist/refusals.js.map +1 -0
- package/dist/registryObserver.d.ts +37 -0
- package/dist/registryObserver.d.ts.map +1 -0
- package/dist/registryObserver.js +70 -0
- package/dist/registryObserver.js.map +1 -0
- package/dist/session.d.ts +1 -1
- package/dist/session.js +1 -1
- package/dist/sessionScope.d.ts +1 -1
- package/dist/sessionScope.js +1 -1
- package/dist/sessionStore.d.ts +10 -23
- package/dist/sessionStore.d.ts.map +1 -1
- package/dist/sessionStore.js +17 -76
- package/dist/sessionStore.js.map +1 -1
- package/dist/version.d.ts +12 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +13 -0
- package/dist/version.js.map +1 -0
- package/dist/wasm/context.d.ts +10 -0
- package/dist/wasm/context.d.ts.map +1 -1
- package/dist/wasm/context.js +27 -0
- package/dist/wasm/context.js.map +1 -1
- package/dist/wasm/hostImports.d.ts +3 -3
- package/dist/wasm/hostImports.d.ts.map +1 -1
- package/dist/wasm/hostImports.js +8 -7
- package/dist/wasm/hostImports.js.map +1 -1
- package/dist/wasm/loader.d.ts +8 -1
- package/dist/wasm/loader.d.ts.map +1 -1
- package/dist/wasm/loader.js +2 -0
- package/dist/wasm/loader.js.map +1 -1
- package/dist/wasm/referencedFiles.d.ts +29 -4
- package/dist/wasm/referencedFiles.d.ts.map +1 -1
- package/dist/wasm/referencedFiles.js +48 -21
- package/dist/wasm/referencedFiles.js.map +1 -1
- package/dist/wasm/runner.d.ts +106 -22
- package/dist/wasm/runner.d.ts.map +1 -1
- package/dist/wasm/runner.js +194 -74
- package/dist/wasm/runner.js.map +1 -1
- package/dist/wasm/watch.js +1 -1
- package/dist/wasm/worker.d.ts +10 -6
- package/dist/wasm/worker.d.ts.map +1 -1
- package/dist/wasm/worker.js +93 -9
- package/dist/wasm/worker.js.map +1 -1
- package/package.json +5 -4
- package/dist/toolPoison.d.ts +0 -32
- package/dist/toolPoison.d.ts.map +0 -1
- package/dist/toolPoison.js +0 -81
- package/dist/toolPoison.js.map +0 -1
- package/dist/wasm/fuel.d.ts +0 -35
- package/dist/wasm/fuel.d.ts.map +0 -1
- package/dist/wasm/fuel.js +0 -299
- package/dist/wasm/fuel.js.map +0 -1
- package/dist/wasm/memoryCap.d.ts +0 -21
- package/dist/wasm/memoryCap.d.ts.map +0 -1
- package/dist/wasm/memoryCap.js +0 -54
- package/dist/wasm/memoryCap.js.map +0 -1
- package/dist/wasm/wasmBinary.d.ts +0 -25
- package/dist/wasm/wasmBinary.d.ts.map +0 -1
- package/dist/wasm/wasmBinary.js +0 -100
- package/dist/wasm/wasmBinary.js.map +0 -1
package/dist/refusals.js
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* refusals.ts — the stable code every refusal this proxy gives carries.
|
|
3
|
+
*
|
|
4
|
+
* A JSON-RPC refusal is `-32603` with a message, and a message is for a
|
|
5
|
+
* person: an agent or client that wants to tell a held call from a blocked
|
|
6
|
+
* one, or a used-up budget from a disabled tool, should not have to parse it.
|
|
7
|
+
* So every refusal frame also carries `error.data`: `code` (one of
|
|
8
|
+
* {@link MCP_REFUSAL_CODES}), `ruleId` (the rule, setting or detector that
|
|
9
|
+
* decided) and, where there is more to say, more fields — the hold's
|
|
10
|
+
* `holdId` and `status`, a budget's `budgetId`, `limit`, `used` and
|
|
11
|
+
* `resetAt`.
|
|
12
|
+
*
|
|
13
|
+
* Held to `packages/shared-types/fixtures/refusal-codes.json` (`mcp`) by a
|
|
14
|
+
* test, as the MCP proxy reference's table is.
|
|
15
|
+
*
|
|
16
|
+
* @module
|
|
17
|
+
*/
|
|
18
|
+
export const MCP_REFUSAL_CODES = [
|
|
19
|
+
'REGISTRY_UNAVAILABLE',
|
|
20
|
+
'SERVER_BLOCKED',
|
|
21
|
+
'SERVER_HELD',
|
|
22
|
+
'SERVER_NOT_APPROVED',
|
|
23
|
+
'TOOL_DISABLED',
|
|
24
|
+
'SERVER_NOT_ALLOWED',
|
|
25
|
+
'TOOL_NOT_ALLOWED',
|
|
26
|
+
'SSO_GROUP',
|
|
27
|
+
'DLP',
|
|
28
|
+
'SOP_RULE',
|
|
29
|
+
'HELD',
|
|
30
|
+
'INJECTION',
|
|
31
|
+
'ANOMALY',
|
|
32
|
+
'WASM_RULE',
|
|
33
|
+
'REASK',
|
|
34
|
+
'REASK_EXHAUSTED',
|
|
35
|
+
'BUDGET_EXCEEDED',
|
|
36
|
+
'BUDGET_UNAVAILABLE',
|
|
37
|
+
'GOVERNANCE_UNAVAILABLE',
|
|
38
|
+
'TOFU_UNAVAILABLE',
|
|
39
|
+
'TOOL_DEFINITIONS_CHANGED',
|
|
40
|
+
'RESULT_WITHHELD_DLP',
|
|
41
|
+
'RESULT_WITHHELD_INJECTION',
|
|
42
|
+
];
|
|
43
|
+
//# sourceMappingURL=refusals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"refusals.js","sourceRoot":"","sources":["../src/refusals.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,sBAAsB;IACtB,gBAAgB;IAChB,aAAa;IACb,qBAAqB;IACrB,eAAe;IACf,oBAAoB;IACpB,kBAAkB;IAClB,WAAW;IACX,KAAK;IACL,UAAU;IACV,MAAM;IACN,WAAW;IACX,SAAS;IACT,WAAW;IACX,OAAO;IACP,iBAAiB;IACjB,iBAAiB;IACjB,oBAAoB;IACpB,wBAAwB;IACxB,kBAAkB;IAClB,0BAA0B;IAC1B,qBAAqB;IACrB,2BAA2B;CACnB,CAAA"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* registryObserver.ts — tells the control plane which MCP server this proxy
|
|
3
|
+
* fronts, and which tools it declares.
|
|
4
|
+
*
|
|
5
|
+
* The MCP daemon's heartbeat reports the servers it finds in harness configs,
|
|
6
|
+
* but a per-session proxy runs without the daemon on most machines, and only
|
|
7
|
+
* the proxy ever sees a server's tools/list. So the proxy reports its own
|
|
8
|
+
* server: once at start (so a server refused under a `deny` default still
|
|
9
|
+
* reaches the approval queue, even if its tools/list never gets through) and
|
|
10
|
+
* again whenever the tools it sees change — a tool added or removed, or a
|
|
11
|
+
* description or input schema changed. The report carries the tool names (for
|
|
12
|
+
* the registry's per-tool toggles) and the definitions as the server declared
|
|
13
|
+
* them, before curation, which the control plane compares with the last ones
|
|
14
|
+
* it stored to score the change's risk. The control plane creates a candidate
|
|
15
|
+
* on first sight and notifies the workspace.
|
|
16
|
+
*
|
|
17
|
+
* Best-effort and quiet: a failed report costs one registry refresh, never a
|
|
18
|
+
* tool call.
|
|
19
|
+
*
|
|
20
|
+
* @module
|
|
21
|
+
*/
|
|
22
|
+
import type { McpToolDefinition } from '@intutic/shared-types';
|
|
23
|
+
export declare class RegistryObserver {
|
|
24
|
+
private readonly controlPlaneUrl;
|
|
25
|
+
private readonly apiKey;
|
|
26
|
+
private readonly serverName;
|
|
27
|
+
private readonly transport;
|
|
28
|
+
private lastReported;
|
|
29
|
+
constructor(controlPlaneUrl: string, apiKey: string, serverName: string, transport: 'stdio' | 'http' | 'sse');
|
|
30
|
+
/**
|
|
31
|
+
* Reports the server, with its tools when known. A report identical to the
|
|
32
|
+
* last successful one is skipped. Without an API key, or without a
|
|
33
|
+
* `--server-name` to report, there is nothing the registry could record.
|
|
34
|
+
*/
|
|
35
|
+
observe(tools?: readonly McpToolDefinition[]): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=registryObserver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registryObserver.d.ts","sourceRoot":"","sources":["../src/registryObserver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAA;AAM9D,qBAAa,gBAAgB;IAIzB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAN5B,OAAO,CAAC,YAAY,CAAsB;gBAGvB,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,OAAO,GAAG,MAAM,GAAG,KAAK;IAGtD;;;;OAIG;IACG,OAAO,CAAC,KAAK,CAAC,EAAE,SAAS,iBAAiB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAsBnE"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* registryObserver.ts — tells the control plane which MCP server this proxy
|
|
3
|
+
* fronts, and which tools it declares.
|
|
4
|
+
*
|
|
5
|
+
* The MCP daemon's heartbeat reports the servers it finds in harness configs,
|
|
6
|
+
* but a per-session proxy runs without the daemon on most machines, and only
|
|
7
|
+
* the proxy ever sees a server's tools/list. So the proxy reports its own
|
|
8
|
+
* server: once at start (so a server refused under a `deny` default still
|
|
9
|
+
* reaches the approval queue, even if its tools/list never gets through) and
|
|
10
|
+
* again whenever the tools it sees change — a tool added or removed, or a
|
|
11
|
+
* description or input schema changed. The report carries the tool names (for
|
|
12
|
+
* the registry's per-tool toggles) and the definitions as the server declared
|
|
13
|
+
* them, before curation, which the control plane compares with the last ones
|
|
14
|
+
* it stored to score the change's risk. The control plane creates a candidate
|
|
15
|
+
* on first sight and notifies the workspace.
|
|
16
|
+
*
|
|
17
|
+
* Best-effort and quiet: a failed report costs one registry refresh, never a
|
|
18
|
+
* tool call.
|
|
19
|
+
*
|
|
20
|
+
* @module
|
|
21
|
+
*/
|
|
22
|
+
import { createStderrLogger as createLogger } from './stderrLog.js';
|
|
23
|
+
import { postJson } from './httpJson.js';
|
|
24
|
+
const log = createLogger('mcp-proxy-registry');
|
|
25
|
+
export class RegistryObserver {
|
|
26
|
+
controlPlaneUrl;
|
|
27
|
+
apiKey;
|
|
28
|
+
serverName;
|
|
29
|
+
transport;
|
|
30
|
+
lastReported = null;
|
|
31
|
+
constructor(controlPlaneUrl, apiKey, serverName, transport) {
|
|
32
|
+
this.controlPlaneUrl = controlPlaneUrl;
|
|
33
|
+
this.apiKey = apiKey;
|
|
34
|
+
this.serverName = serverName;
|
|
35
|
+
this.transport = transport;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Reports the server, with its tools when known. A report identical to the
|
|
39
|
+
* last successful one is skipped. Without an API key, or without a
|
|
40
|
+
* `--server-name` to report, there is nothing the registry could record.
|
|
41
|
+
*/
|
|
42
|
+
async observe(tools) {
|
|
43
|
+
if (!this.apiKey || this.serverName === 'unknown')
|
|
44
|
+
return;
|
|
45
|
+
let definitions;
|
|
46
|
+
if (tools) {
|
|
47
|
+
// One entry per name, the first declared — the rule the risk score matches by.
|
|
48
|
+
const byName = new Map();
|
|
49
|
+
for (const t of tools)
|
|
50
|
+
if (!byName.has(t.name))
|
|
51
|
+
byName.set(t.name, t);
|
|
52
|
+
definitions = [...byName.values()].sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
53
|
+
}
|
|
54
|
+
const key = JSON.stringify(definitions ?? null);
|
|
55
|
+
if (key === this.lastReported || (definitions === undefined && this.lastReported !== null))
|
|
56
|
+
return;
|
|
57
|
+
try {
|
|
58
|
+
await postJson(`${this.controlPlaneUrl}/api/v1/mcp/servers/observe`, this.apiKey, {
|
|
59
|
+
serverName: this.serverName,
|
|
60
|
+
transport: this.transport,
|
|
61
|
+
...(definitions ? { tools: definitions.map((t) => t.name), toolDefinitions: definitions } : {}),
|
|
62
|
+
});
|
|
63
|
+
this.lastReported = key;
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
log.debug({ action: 'registry_observe_failed', err: err.message }, 'Could not report this MCP server to the registry');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=registryObserver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registryObserver.js","sourceRoot":"","sources":["../src/registryObserver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAGH,OAAO,EAAE,kBAAkB,IAAI,YAAY,EAAE,MAAM,gBAAgB,CAAA;AACnE,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAExC,MAAM,GAAG,GAAG,YAAY,CAAC,oBAAoB,CAAC,CAAA;AAE9C,MAAM,OAAO,gBAAgB;IAIR;IACA;IACA;IACA;IANX,YAAY,GAAkB,IAAI,CAAA;IAE1C,YACmB,eAAuB,EACvB,MAAc,EACd,UAAkB,EAClB,SAAmC;QAHnC,oBAAe,GAAf,eAAe,CAAQ;QACvB,WAAM,GAAN,MAAM,CAAQ;QACd,eAAU,GAAV,UAAU,CAAQ;QAClB,cAAS,GAAT,SAAS,CAA0B;IACnD,CAAC;IAEJ;;;;OAIG;IACH,KAAK,CAAC,OAAO,CAAC,KAAoC;QAChD,IAAI,CAAC,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,UAAU,KAAK,SAAS;YAAE,OAAM;QACzD,IAAI,WAA4C,CAAA;QAChD,IAAI,KAAK,EAAE,CAAC;YACV,+EAA+E;YAC/E,MAAM,MAAM,GAAG,IAAI,GAAG,EAA6B,CAAA;YACnD,KAAK,MAAM,CAAC,IAAI,KAAK;gBAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;oBAAE,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAA;YACrE,WAAW,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QACrG,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,WAAW,IAAI,IAAI,CAAC,CAAA;QAC/C,IAAI,GAAG,KAAK,IAAI,CAAC,YAAY,IAAI,CAAC,WAAW,KAAK,SAAS,IAAI,IAAI,CAAC,YAAY,KAAK,IAAI,CAAC;YAAE,OAAM;QAClG,IAAI,CAAC;YACH,MAAM,QAAQ,CAAC,GAAG,IAAI,CAAC,eAAe,6BAA6B,EAAE,IAAI,CAAC,MAAM,EAAE;gBAChF,UAAU,EAAE,IAAI,CAAC,UAAU;gBAC3B,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,eAAe,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAChG,CAAC,CAAA;YACF,IAAI,CAAC,YAAY,GAAG,GAAG,CAAA;QACzB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,EAAE,MAAM,EAAE,yBAAyB,EAAE,GAAG,EAAG,GAAa,CAAC,OAAO,EAAE,EAAE,kDAAkD,CAAC,CAAA;QACnI,CAAC;IACH,CAAC;CACF"}
|
package/dist/session.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* process (`mcpAutoWrite.ts`'s `wrapWithProxy`, in both `per-session` and
|
|
9
9
|
* `daemon` mode), so one harness session runs one proxy per wrapped server.
|
|
10
10
|
* This class holds the tool-call sequence and the per-detector reask counters
|
|
11
|
-
* the anomaly detectors read. Until Wave 5.3
|
|
11
|
+
* the anomaly detectors read. Until Wave 5.3 that state was
|
|
12
12
|
* per-process only — a cross-server ping-pong was invisible, a reask budget
|
|
13
13
|
* reset per server and per restart — and the module doc claimed there was
|
|
14
14
|
* "no second instance to share state with", which was never true of the
|
package/dist/session.js
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* process (`mcpAutoWrite.ts`'s `wrapWithProxy`, in both `per-session` and
|
|
9
9
|
* `daemon` mode), so one harness session runs one proxy per wrapped server.
|
|
10
10
|
* This class holds the tool-call sequence and the per-detector reask counters
|
|
11
|
-
* the anomaly detectors read. Until Wave 5.3
|
|
11
|
+
* the anomaly detectors read. Until Wave 5.3 that state was
|
|
12
12
|
* per-process only — a cross-server ping-pong was invisible, a reask budget
|
|
13
13
|
* reset per server and per restart — and the module doc claimed there was
|
|
14
14
|
* "no second instance to share state with", which was never true of the
|
package/dist/sessionScope.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* sessionScope.ts — the shared-window scope a proxy process derives for
|
|
3
|
-
* itself (
|
|
3
|
+
* itself (Wave 5.3).
|
|
4
4
|
*
|
|
5
5
|
* The sync daemon wraps EACH MCP server entry with its own proxy process, so
|
|
6
6
|
* one harness session runs several `McpGovernanceProxy` processes at once —
|
package/dist/sessionScope.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* sessionScope.ts — the shared-window scope a proxy process derives for
|
|
3
|
-
* itself (
|
|
3
|
+
* itself (Wave 5.3).
|
|
4
4
|
*
|
|
5
5
|
* The sync daemon wraps EACH MCP server entry with its own proxy process, so
|
|
6
6
|
* one harness session runs several `McpGovernanceProxy` processes at once —
|
package/dist/sessionStore.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* sessionStore.ts — the Valkey-backed session window the sibling proxy
|
|
3
|
-
* processes of one harness session share (
|
|
3
|
+
* processes of one harness session share (Wave 5.3).
|
|
4
4
|
*
|
|
5
5
|
* The Rust LLM proxy keeps a session's tool-call history in Valkey
|
|
6
6
|
* (`store/valkey.rs`: a capped LIST for the sequence, a ZSET for the 60 s
|
|
@@ -12,15 +12,15 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Never a hard dependency. Every operation fails open to `undefined`/`false`
|
|
14
14
|
* and the caller (`SessionState`) falls back to its in-process window: when
|
|
15
|
-
* no URL is configured, when the client is not connected (
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
15
|
+
* no URL is configured, when the client is not connected (so an absent
|
|
16
|
+
* Valkey adds no latency), when a call takes longer than
|
|
17
|
+
* `VALKEY_COMMAND_TIMEOUT_MS`, or on any error — the guard every command on
|
|
18
|
+
* the proxy's one Valkey connection goes through (guardedValkey.ts). The
|
|
19
|
+
* proxy behaves exactly as before Wave 5.3 in every one of those cases.
|
|
19
20
|
*
|
|
20
21
|
* @module
|
|
21
22
|
*/
|
|
22
|
-
|
|
23
|
-
export declare const SHARED_WINDOW_TIMEOUT_MS = 200;
|
|
23
|
+
import type { GuardedValkey } from './guardedValkey.js';
|
|
24
24
|
/** Sliding lifetime of the sequence and call-window keys — the Rust `TOOL_SEQUENCE_TTL_SECS`. */
|
|
25
25
|
export declare const SESSION_WINDOW_TTL_SECS = 86400;
|
|
26
26
|
/** Lifetime of a reask allowance, set when the counter is created and never refreshed —
|
|
@@ -44,26 +44,13 @@ export interface SharedSessionStore {
|
|
|
44
44
|
recordCall(scope: string, toolName: string, nowMs: number): Promise<boolean>;
|
|
45
45
|
/** The count including this trip, or `undefined` when unavailable. */
|
|
46
46
|
incrReaskAttempt(scope: string, key: string): Promise<number | undefined>;
|
|
47
|
-
close(): Promise<void>;
|
|
48
|
-
}
|
|
49
|
-
export interface ValkeySessionStoreOptions {
|
|
50
|
-
timeoutMs?: number;
|
|
51
47
|
}
|
|
52
48
|
export declare class ValkeySessionStore implements SharedSessionStore {
|
|
53
|
-
private readonly
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
constructor(url: string, opts?: ValkeySessionStoreOptions);
|
|
49
|
+
private readonly valkey;
|
|
50
|
+
/** The proxy's one Valkey connection, shared with its call budgets; the proxy closes it. */
|
|
51
|
+
constructor(valkey: GuardedValkey);
|
|
57
52
|
readWindow(scope: string, nowMs: number, windowMs: number): Promise<SharedWindowSnapshot | undefined>;
|
|
58
53
|
recordCall(scope: string, toolName: string, nowMs: number): Promise<boolean>;
|
|
59
54
|
incrReaskAttempt(scope: string, key: string): Promise<number | undefined>;
|
|
60
|
-
close(): Promise<void>;
|
|
61
|
-
/**
|
|
62
|
-
* The fail-open wrapper every operation goes through: nothing is attempted
|
|
63
|
-
* unless the client is connected, nothing waits longer than the timeout,
|
|
64
|
-
* and any failure is `undefined`.
|
|
65
|
-
*/
|
|
66
|
-
private guarded;
|
|
67
|
-
private warnOnce;
|
|
68
55
|
}
|
|
69
56
|
//# sourceMappingURL=sessionStore.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionStore.d.ts","sourceRoot":"","sources":["../src/sessionStore.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"sessionStore.d.ts","sourceRoot":"","sources":["../src/sessionStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAGvD,iGAAiG;AACjG,eAAO,MAAM,uBAAuB,QAAS,CAAA;AAC7C;0EAC0E;AAC1E,eAAO,MAAM,iBAAiB,OAAQ,CAAA;AAEtC,eAAO,MAAM,WAAW;4BACP,MAAM;4BACN,MAAM;4BACN,MAAM,OAAO,MAAM;CAC1B,CAAA;AAEV,MAAM,WAAW,oBAAoB;IACnC,+DAA+D;IAC/D,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,6EAA6E;IAC7E,YAAY,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,kBAAkB;IACjC,mEAAmE;IACnE,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC,CAAA;IACrG,sEAAsE;IACtE,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC5E,sEAAsE;IACtE,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAA;CAC1E;AAED,qBAAa,kBAAmB,YAAW,kBAAkB;IAE/C,OAAO,CAAC,QAAQ,CAAC,MAAM;IADnC,4FAA4F;gBAC/D,MAAM,EAAE,aAAa;IAE5C,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,GAAG,SAAS,CAAC;IAcrG,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAoB5E,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;CAQhF"}
|
package/dist/sessionStore.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* sessionStore.ts — the Valkey-backed session window the sibling proxy
|
|
3
|
-
* processes of one harness session share (
|
|
3
|
+
* processes of one harness session share (Wave 5.3).
|
|
4
4
|
*
|
|
5
5
|
* The Rust LLM proxy keeps a session's tool-call history in Valkey
|
|
6
6
|
* (`store/valkey.rs`: a capped LIST for the sequence, a ZSET for the 60 s
|
|
@@ -12,21 +12,16 @@
|
|
|
12
12
|
*
|
|
13
13
|
* Never a hard dependency. Every operation fails open to `undefined`/`false`
|
|
14
14
|
* and the caller (`SessionState`) falls back to its in-process window: when
|
|
15
|
-
* no URL is configured, when the client is not connected (
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
15
|
+
* no URL is configured, when the client is not connected (so an absent
|
|
16
|
+
* Valkey adds no latency), when a call takes longer than
|
|
17
|
+
* `VALKEY_COMMAND_TIMEOUT_MS`, or on any error — the guard every command on
|
|
18
|
+
* the proxy's one Valkey connection goes through (guardedValkey.ts). The
|
|
19
|
+
* proxy behaves exactly as before Wave 5.3 in every one of those cases.
|
|
19
20
|
*
|
|
20
21
|
* @module
|
|
21
22
|
*/
|
|
22
23
|
import * as node_crypto from 'node:crypto';
|
|
23
|
-
import { Redis } from 'ioredis';
|
|
24
|
-
import { createStderrLogger } from './stderrLog.js';
|
|
25
|
-
import { describeConnectionError } from './valkeyErrors.js';
|
|
26
24
|
import { TOOL_SEQUENCE_CAP } from './session.js';
|
|
27
|
-
const log = createStderrLogger('mcp-proxy.sessionStore');
|
|
28
|
-
/** A shared read or write that takes longer than this loses to the local window. */
|
|
29
|
-
export const SHARED_WINDOW_TIMEOUT_MS = 200;
|
|
30
25
|
/** Sliding lifetime of the sequence and call-window keys — the Rust `TOOL_SEQUENCE_TTL_SECS`. */
|
|
31
26
|
export const SESSION_WINDOW_TTL_SECS = 86_400;
|
|
32
27
|
/** Lifetime of a reask allowance, set when the counter is created and never refreshed —
|
|
@@ -38,26 +33,14 @@ export const sessionKeys = {
|
|
|
38
33
|
reask: (scope, key) => `v2:mcpsession:${scope}:reask:${key}`,
|
|
39
34
|
};
|
|
40
35
|
export class ValkeySessionStore {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
this.timeoutMs = opts.timeoutMs ?? SHARED_WINDOW_TIMEOUT_MS;
|
|
46
|
-
this.client = new Redis(url, {
|
|
47
|
-
lazyConnect: true,
|
|
48
|
-
// No offline queue: a command issued before the connection is up must
|
|
49
|
-
// fail now, not wait for a Valkey that may never answer.
|
|
50
|
-
enableOfflineQueue: false,
|
|
51
|
-
maxRetriesPerRequest: 1,
|
|
52
|
-
connectTimeout: 1000,
|
|
53
|
-
retryStrategy: (times) => Math.min(1000 * 2 ** Math.min(times, 5), 30_000),
|
|
54
|
-
});
|
|
55
|
-
this.client.on('error', (err) => this.warnOnce('Valkey session store unreachable', err));
|
|
56
|
-
void this.client.connect().catch((err) => this.warnOnce('Valkey session store connect failed', err));
|
|
36
|
+
valkey;
|
|
37
|
+
/** The proxy's one Valkey connection, shared with its call budgets; the proxy closes it. */
|
|
38
|
+
constructor(valkey) {
|
|
39
|
+
this.valkey = valkey;
|
|
57
40
|
}
|
|
58
41
|
async readWindow(scope, nowMs, windowMs) {
|
|
59
|
-
return this.
|
|
60
|
-
const results = await
|
|
42
|
+
return this.valkey.run(async (client) => {
|
|
43
|
+
const results = await client
|
|
61
44
|
.pipeline()
|
|
62
45
|
.lrange(sessionKeys.tools(scope), 0, -1)
|
|
63
46
|
.zcount(sessionKeys.calls(scope), nowMs - windowMs, '+inf')
|
|
@@ -70,10 +53,10 @@ export class ValkeySessionStore {
|
|
|
70
53
|
});
|
|
71
54
|
}
|
|
72
55
|
async recordCall(scope, toolName, nowMs) {
|
|
73
|
-
const done = await this.
|
|
56
|
+
const done = await this.valkey.run(async (client) => {
|
|
74
57
|
const tools = sessionKeys.tools(scope);
|
|
75
58
|
const calls = sessionKeys.calls(scope);
|
|
76
|
-
await
|
|
59
|
+
await client
|
|
77
60
|
.pipeline()
|
|
78
61
|
.rpush(tools, toolName)
|
|
79
62
|
.ltrim(tools, -TOOL_SEQUENCE_CAP, -1)
|
|
@@ -89,55 +72,13 @@ export class ValkeySessionStore {
|
|
|
89
72
|
return done === true;
|
|
90
73
|
}
|
|
91
74
|
async incrReaskAttempt(scope, key) {
|
|
92
|
-
return this.
|
|
75
|
+
return this.valkey.run(async (client) => {
|
|
93
76
|
const k = sessionKeys.reask(scope, key);
|
|
94
|
-
const n = await
|
|
77
|
+
const n = await client.incr(k);
|
|
95
78
|
if (n === 1)
|
|
96
|
-
await
|
|
79
|
+
await client.expire(k, REASK_WINDOW_SECS);
|
|
97
80
|
return n;
|
|
98
81
|
});
|
|
99
82
|
}
|
|
100
|
-
async close() {
|
|
101
|
-
try {
|
|
102
|
-
await this.client.quit();
|
|
103
|
-
}
|
|
104
|
-
catch {
|
|
105
|
-
this.client.disconnect();
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
/**
|
|
109
|
-
* The fail-open wrapper every operation goes through: nothing is attempted
|
|
110
|
-
* unless the client is connected, nothing waits longer than the timeout,
|
|
111
|
-
* and any failure is `undefined`.
|
|
112
|
-
*/
|
|
113
|
-
async guarded(op) {
|
|
114
|
-
if (this.client.status !== 'ready')
|
|
115
|
-
return undefined;
|
|
116
|
-
let timer;
|
|
117
|
-
const timeout = new Promise((resolve) => {
|
|
118
|
-
timer = setTimeout(() => resolve(undefined), this.timeoutMs);
|
|
119
|
-
timer.unref();
|
|
120
|
-
});
|
|
121
|
-
try {
|
|
122
|
-
return await Promise.race([op(), timeout]);
|
|
123
|
-
}
|
|
124
|
-
catch (err) {
|
|
125
|
-
this.warnOnce('Valkey session store operation failed', err);
|
|
126
|
-
return undefined;
|
|
127
|
-
}
|
|
128
|
-
finally {
|
|
129
|
-
if (timer)
|
|
130
|
-
clearTimeout(timer);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
warnOnce(msg, err) {
|
|
134
|
-
const detail = { err: describeConnectionError(err) };
|
|
135
|
-
if (this.warned) {
|
|
136
|
-
log.debug(detail, msg);
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
this.warned = true;
|
|
140
|
-
log.warn(detail, `${msg} — falling back to the per-process session window`);
|
|
141
|
-
}
|
|
142
83
|
}
|
|
143
84
|
//# sourceMappingURL=sessionStore.js.map
|
package/dist/sessionStore.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sessionStore.js","sourceRoot":"","sources":["../src/sessionStore.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"sessionStore.js","sourceRoot":"","sources":["../src/sessionStore.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* version.ts — this package's own version, read from its package.json.
|
|
3
|
+
*
|
|
4
|
+
* The standalone `intutic` MCP server reports it to clients in its
|
|
5
|
+
* `initialize` response. It was a hard-coded `'0.1.0'` that never moved with
|
|
6
|
+
* a release. `../package.json` resolves from both `src/` (tests) and `dist/`
|
|
7
|
+
* (the published build), and npm always ships package.json.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
export declare const PACKAGE_VERSION: string;
|
|
12
|
+
//# sourceMappingURL=version.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,eAAO,MAAM,eAAe,EAAE,MAA2F,CAAA"}
|
package/dist/version.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* version.ts — this package's own version, read from its package.json.
|
|
3
|
+
*
|
|
4
|
+
* The standalone `intutic` MCP server reports it to clients in its
|
|
5
|
+
* `initialize` response. It was a hard-coded `'0.1.0'` that never moved with
|
|
6
|
+
* a release. `../package.json` resolves from both `src/` (tests) and `dist/`
|
|
7
|
+
* (the published build), and npm always ships package.json.
|
|
8
|
+
*
|
|
9
|
+
* @module
|
|
10
|
+
*/
|
|
11
|
+
import { createRequire } from 'node:module';
|
|
12
|
+
export const PACKAGE_VERSION = createRequire(import.meta.url)('../package.json').version;
|
|
13
|
+
//# sourceMappingURL=version.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,MAAM,CAAC,MAAM,eAAe,GAAY,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,iBAAiB,CAAyB,CAAC,OAAO,CAAA"}
|
package/dist/wasm/context.d.ts
CHANGED
|
@@ -46,6 +46,8 @@ export interface WasmContextInput {
|
|
|
46
46
|
corroboratingDetectors: number;
|
|
47
47
|
/** `undefined` when no `tools/list` response has been TOFU-checked yet this session. */
|
|
48
48
|
toolContractChanged: boolean | undefined;
|
|
49
|
+
/** The MCP server this proxy fronts (`--server-name`); a Rego rule reads it as `input.server`. */
|
|
50
|
+
serverName?: string;
|
|
49
51
|
}
|
|
50
52
|
/**
|
|
51
53
|
* Builds the plain object to `JSON.stringify` and hand to a WASM rule's
|
|
@@ -54,4 +56,12 @@ export interface WasmContextInput {
|
|
|
54
56
|
* not present as keys at all.
|
|
55
57
|
*/
|
|
56
58
|
export declare function buildWasmContext(input: WasmContextInput): Record<string, unknown>;
|
|
59
|
+
/**
|
|
60
|
+
* The `input` document a Rego rule is evaluated against — version 1, the shape
|
|
61
|
+
* `packages/proxy/src/wasm/opa.rs`'s `policy_input` builds for the LLM proxy,
|
|
62
|
+
* less the fields this proxy has no honest value for (`model`, `risk_tier`,
|
|
63
|
+
* the budget), plus `server`. Bounded and serialised by `boundedRegoInput`,
|
|
64
|
+
* which cuts long strings in `args` exactly as the Rust host does.
|
|
65
|
+
*/
|
|
66
|
+
export declare function buildRegoInput(input: WasmContextInput): string;
|
|
57
67
|
//# sourceMappingURL=context.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/wasm/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/wasm/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAEnD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,2EAA2E;IAC3E,KAAK,EAAE,SAAS,cAAc,EAAE,CAAA;IAChC;;;;;;OAMG;IACH,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,aAAa,EAAE,OAAO,CAAA;IACtB,0GAA0G;IAC1G,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;IAC/B,YAAY,EAAE,MAAM,CAAA;IACpB;;;mEAG+D;IAC/D,sBAAsB,EAAE,SAAS,MAAM,EAAE,CAAA;IACzC,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAA;IACpC,gBAAgB,EAAE,SAAS,MAAM,EAAE,CAAA;IACnC,sBAAsB,EAAE,MAAM,CAAA;IAC9B,wFAAwF;IACxF,mBAAmB,EAAE,OAAO,GAAG,SAAS,CAAA;IACxC,kGAAkG;IAClG,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AASD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAyBjF;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,CAkB9D"}
|
package/dist/wasm/context.js
CHANGED
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
*
|
|
18
18
|
* @module
|
|
19
19
|
*/
|
|
20
|
+
import { REGO_INPUT_VERSION, boundedRegoInput } from '@intutic/shared-types';
|
|
20
21
|
/** `(tool, count)` pairs, wire-shaped as 2-element arrays — see context.ts's module doc. */
|
|
21
22
|
function foldToolCallCounts(sequence) {
|
|
22
23
|
const counts = new Map();
|
|
@@ -56,4 +57,30 @@ export function buildWasmContext(input) {
|
|
|
56
57
|
}
|
|
57
58
|
return ctx;
|
|
58
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* The `input` document a Rego rule is evaluated against — version 1, the shape
|
|
62
|
+
* `packages/proxy/src/wasm/opa.rs`'s `policy_input` builds for the LLM proxy,
|
|
63
|
+
* less the fields this proxy has no honest value for (`model`, `risk_tier`,
|
|
64
|
+
* the budget), plus `server`. Bounded and serialised by `boundedRegoInput`,
|
|
65
|
+
* which cuts long strings in `args` exactly as the Rust host does.
|
|
66
|
+
*/
|
|
67
|
+
export function buildRegoInput(input) {
|
|
68
|
+
return boundedRegoInput({
|
|
69
|
+
v: REGO_INPUT_VERSION,
|
|
70
|
+
host: 'mcp',
|
|
71
|
+
tool: input.toolName,
|
|
72
|
+
args: input.toolArguments ?? {},
|
|
73
|
+
...(input.serverName ? { server: input.serverName } : {}),
|
|
74
|
+
session: {
|
|
75
|
+
id: input.sessionId,
|
|
76
|
+
workspace_id: input.workspaceId,
|
|
77
|
+
tool_sequence: [...input.toolSequence],
|
|
78
|
+
calls_last_60s: input.callsLast60s,
|
|
79
|
+
},
|
|
80
|
+
request: {
|
|
81
|
+
dlp_findings: input.dlpFindingDescriptions.map((description) => ({ pattern_name: description })),
|
|
82
|
+
injection_findings: [...input.injectionFindings],
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
}
|
|
59
86
|
//# sourceMappingURL=context.js.map
|
package/dist/wasm/context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/wasm/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/wasm/context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AAmC5E,4FAA4F;AAC5F,SAAS,kBAAkB,CAAC,QAA2B;IACrD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAA;IACxC,KAAK,MAAM,IAAI,IAAI,QAAQ;QAAE,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IAC1E,OAAO,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAA;AACrC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAuB;IACtD,MAAM,GAAG,GAA4B;QACnC,UAAU,EAAE,KAAK,CAAC,SAAS;QAC3B,YAAY,EAAE,KAAK,CAAC,WAAW;QAC/B,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,EAAE,EAAE,CAAC,CAAC;QACnF,UAAU,EAAE,CAAC,EAAE,EAAE,EAAE,KAAK,CAAC,UAAU,EAAE,IAAI,EAAE,KAAK,CAAC,QAAQ,EAAE,SAAS,EAAE,KAAK,CAAC,aAAa,IAAI,EAAE,EAAE,CAAC;QAClG,aAAa,EAAE,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC;QACtC,gBAAgB,EAAE,kBAAkB,CAAC,KAAK,CAAC,YAAY,CAAC;QACxD,cAAc,EAAE,KAAK,CAAC,YAAY;QAClC,kEAAkE;QAClE,uEAAuE;QACvE,sEAAsE;QACtE,2DAA2D;QAC3D,oEAAoE;QACpE,qEAAqE;QACrE,oEAAoE;QACpE,YAAY,EAAE,KAAK,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC,CAAC;QAChG,kBAAkB,EAAE,CAAC,GAAG,KAAK,CAAC,iBAAiB,CAAC;QAChD,iBAAiB,EAAE,CAAC,GAAG,KAAK,CAAC,gBAAgB,CAAC;QAC9C,uBAAuB,EAAE,KAAK,CAAC,sBAAsB;KACtD,CAAA;IACD,IAAI,KAAK,CAAC,mBAAmB,KAAK,SAAS,EAAE,CAAC;QAC5C,GAAG,CAAC,uBAAuB,CAAC,GAAG,KAAK,CAAC,mBAAmB,CAAA;IAC1D,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,KAAuB;IACpD,OAAO,gBAAgB,CAAC;QACtB,CAAC,EAAE,kBAAkB;QACrB,IAAI,EAAE,KAAK;QACX,IAAI,EAAE,KAAK,CAAC,QAAQ;QACpB,IAAI,EAAE,KAAK,CAAC,aAAa,IAAI,EAAE;QAC/B,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACzD,OAAO,EAAE;YACP,EAAE,EAAE,KAAK,CAAC,SAAS;YACnB,YAAY,EAAE,KAAK,CAAC,WAAW;YAC/B,aAAa,EAAE,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC;YACtC,cAAc,EAAE,KAAK,CAAC,YAAY;SACnC;QACD,OAAO,EAAE;YACP,YAAY,EAAE,KAAK,CAAC,sBAAsB,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC,CAAC;YAChG,kBAAkB,EAAE,CAAC,GAAG,KAAK,CAAC,iBAAiB,CAAC;SACjD;KACF,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
* (never `console.log`/stdout — the same stdio-isolation rule every other
|
|
12
12
|
* module in this package follows). `read_referenced_file` resolves against
|
|
13
13
|
* the per-evaluation table the runner pre-reads through `referencedFiles.ts`
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* — the port of `host.rs`'s `read_referenced_file_impl`, code for code: the
|
|
15
|
+
* read budget is charged before argument validation, a refusal is a value
|
|
16
|
+
* the rule can act on, and nothing here traps. With no table (no
|
|
17
17
|
* `INTUTIC_WASM_MANIFEST_ROOT`, or a rule that does not import the function)
|
|
18
18
|
* every call gets `ERR_REFUSED`, which is what the Rust proxy answers with no
|
|
19
19
|
* root configured.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hostImports.d.ts","sourceRoot":"","sources":["../../src/wasm/hostImports.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EACL,eAAe,EAOhB,MAAM,sBAAsB,CAAA;AAI7B,mIAAmI;AACnI,eAAO,MAAM,WAAW,KAAU,CAAA;AAElC,uEAAuE;AACvE,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,KAAK,EAAE,eAAe,CAAA;IACtB,6DAA6D;IAC7D,kBAAkB,EAAE,MAAM,CAAA;CAC3B;AAED,wBAAgB,kBAAkB,CAAC,KAAK,GAAE,eAAyC,GAAG,eAAe,CAEpG;AAoBD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,WAAW,CAAC,MAAM,GAAG,SAAS,EAC/C,KAAK,GAAE,eAAsC,GAC5C,WAAW,CAAC,aAAa,
|
|
1
|
+
{"version":3,"file":"hostImports.d.ts","sourceRoot":"","sources":["../../src/wasm/hostImports.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EACL,eAAe,EAOhB,MAAM,sBAAsB,CAAA;AAI7B,mIAAmI;AACnI,eAAO,MAAM,WAAW,KAAU,CAAA;AAElC,uEAAuE;AACvE,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,KAAK,EAAE,eAAe,CAAA;IACtB,6DAA6D;IAC7D,kBAAkB,EAAE,MAAM,CAAA;CAC3B;AAED,wBAAgB,kBAAkB,CAAC,KAAK,GAAE,eAAyC,GAAG,eAAe,CAEpG;AAoBD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,WAAW,CAAC,MAAM,GAAG,SAAS,EAC/C,KAAK,GAAE,eAAsC,GAC5C,WAAW,CAAC,aAAa,CA2G3B"}
|
package/dist/wasm/hostImports.js
CHANGED
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
* (never `console.log`/stdout — the same stdio-isolation rule every other
|
|
12
12
|
* module in this package follows). `read_referenced_file` resolves against
|
|
13
13
|
* the per-evaluation table the runner pre-reads through `referencedFiles.ts`
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
14
|
+
* — the port of `host.rs`'s `read_referenced_file_impl`, code for code: the
|
|
15
|
+
* read budget is charged before argument validation, a refusal is a value
|
|
16
|
+
* the rule can act on, and nothing here traps. With no table (no
|
|
17
17
|
* `INTUTIC_WASM_MANIFEST_ROOT`, or a rule that does not import the function)
|
|
18
18
|
* every call gets `ERR_REFUSED`, which is what the Rust proxy answers with no
|
|
19
19
|
* root configured.
|
|
@@ -74,7 +74,8 @@ export function createHostImports(getMemory, state = newHostImportState()) {
|
|
|
74
74
|
// Mirrors host.rs's `abort` import: log only, never throw/trap. A guest
|
|
75
75
|
// unhandled-exception calling `abort` must not crash the evaluation —
|
|
76
76
|
// the caller (worker.ts) still wraps the whole `evaluate` call so any
|
|
77
|
-
// resulting trap
|
|
77
|
+
// resulting trap is a rule that reached no verdict, but this import itself
|
|
78
|
+
// is inert.
|
|
78
79
|
abort: (msgPtr, filePtr, line, col) => {
|
|
79
80
|
log.warn({ action: 'wasm_abort', msgPtr, filePtr, line, col }, 'WASM rule called abort (AssemblyScript unhandled exception)');
|
|
80
81
|
},
|
|
@@ -110,9 +111,9 @@ export function createHostImports(getMemory, state = newHostImportState()) {
|
|
|
110
111
|
},
|
|
111
112
|
// Ported from host.rs's `read_referenced_file_impl`. Returns a length or
|
|
112
113
|
// one of the negative codes; never throws — a host trap would unwind the
|
|
113
|
-
// guest
|
|
114
|
-
//
|
|
115
|
-
//
|
|
114
|
+
// guest and leave the whole evaluation without a verdict, so one malformed
|
|
115
|
+
// call would override every OTHER check the rule performs with the fail
|
|
116
|
+
// setting.
|
|
116
117
|
read_referenced_file: (pathPtr, pathLen, outPtr, outCap) => {
|
|
117
118
|
// Charged before anything else, including argument validation, so a
|
|
118
119
|
// guest cannot spin on cheap malformed calls any more than on
|