@intutic/mcp-governance-proxy 1.10.0 → 1.10.1
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 +28 -0
- package/dist/anomaly/detectors.d.ts +129 -0
- package/dist/anomaly/detectors.d.ts.map +1 -0
- package/dist/anomaly/detectors.js +368 -0
- package/dist/anomaly/detectors.js.map +1 -0
- package/dist/anomaly/index.d.ts +52 -0
- package/dist/anomaly/index.d.ts.map +1 -0
- package/dist/anomaly/index.js +71 -0
- package/dist/anomaly/index.js.map +1 -0
- package/dist/config.d.ts +107 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +129 -6
- package/dist/config.js.map +1 -1
- package/dist/daemon/healthMonitor.d.ts.map +1 -1
- package/dist/daemon/healthMonitor.js +45 -46
- package/dist/daemon/healthMonitor.js.map +1 -1
- package/dist/daemon/index.d.ts +15 -1
- package/dist/daemon/index.d.ts.map +1 -1
- package/dist/daemon/index.js +78 -9
- package/dist/daemon/index.js.map +1 -1
- package/dist/daemon/instrumentation.d.ts +20 -0
- package/dist/daemon/instrumentation.d.ts.map +1 -0
- package/dist/daemon/instrumentation.js +61 -0
- package/dist/daemon/instrumentation.js.map +1 -0
- package/dist/daemon/policyCache.d.ts +83 -0
- package/dist/daemon/policyCache.d.ts.map +1 -1
- package/dist/daemon/policyCache.js +280 -11
- package/dist/daemon/policyCache.js.map +1 -1
- package/dist/daemon/statusReporter.d.ts +12 -0
- package/dist/daemon/statusReporter.d.ts.map +1 -0
- package/dist/daemon/statusReporter.js +130 -0
- package/dist/daemon/statusReporter.js.map +1 -0
- package/dist/daemon/telemetryBatcher.d.ts +3 -1
- package/dist/daemon/telemetryBatcher.d.ts.map +1 -1
- package/dist/daemon/telemetryBatcher.js +56 -13
- package/dist/daemon/telemetryBatcher.js.map +1 -1
- package/dist/daemonClient.d.ts +1 -1
- package/dist/daemonClient.d.ts.map +1 -1
- package/dist/daemonClient.js +0 -2
- package/dist/daemonClient.js.map +1 -1
- package/dist/dlp.d.ts +19 -0
- package/dist/dlp.d.ts.map +1 -1
- package/dist/dlp.js +95 -18
- package/dist/dlp.js.map +1 -1
- package/dist/emitter.d.ts +40 -2
- package/dist/emitter.d.ts.map +1 -1
- package/dist/emitter.js +27 -5
- package/dist/emitter.js.map +1 -1
- package/dist/index.js +13 -2
- package/dist/index.js.map +1 -1
- package/dist/injection.d.ts +46 -0
- package/dist/injection.d.ts.map +1 -0
- package/dist/injection.js +147 -0
- package/dist/injection.js.map +1 -0
- package/dist/interceptor.d.ts +131 -1
- package/dist/interceptor.d.ts.map +1 -1
- package/dist/interceptor.js +301 -5
- package/dist/interceptor.js.map +1 -1
- package/dist/policy.d.ts +110 -2
- package/dist/policy.d.ts.map +1 -1
- package/dist/policy.js +206 -5
- package/dist/policy.js.map +1 -1
- package/dist/proxy.d.ts +205 -0
- package/dist/proxy.d.ts.map +1 -1
- package/dist/proxy.js +572 -65
- package/dist/proxy.js.map +1 -1
- package/dist/remoteBridge.d.ts +51 -0
- package/dist/remoteBridge.d.ts.map +1 -0
- package/dist/remoteBridge.js +182 -0
- package/dist/remoteBridge.js.map +1 -0
- package/dist/session.d.ts +158 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +206 -0
- package/dist/session.js.map +1 -0
- package/dist/sessionScope.d.ts +51 -0
- package/dist/sessionScope.d.ts.map +1 -0
- package/dist/sessionScope.js +94 -0
- package/dist/sessionScope.js.map +1 -0
- package/dist/sessionStore.d.ts +69 -0
- package/dist/sessionStore.d.ts.map +1 -0
- package/dist/sessionStore.js +143 -0
- package/dist/sessionStore.js.map +1 -0
- package/dist/tofu.d.ts +112 -0
- package/dist/tofu.d.ts.map +1 -0
- package/dist/tofu.js +180 -0
- package/dist/tofu.js.map +1 -0
- package/dist/toolPoison.d.ts +32 -0
- package/dist/toolPoison.d.ts.map +1 -0
- package/dist/toolPoison.js +81 -0
- package/dist/toolPoison.js.map +1 -0
- package/dist/valkeyErrors.d.ts +17 -0
- package/dist/valkeyErrors.d.ts.map +1 -0
- package/dist/valkeyErrors.js +24 -0
- package/dist/valkeyErrors.js.map +1 -0
- package/dist/wasm/context.d.ts +57 -0
- package/dist/wasm/context.d.ts.map +1 -0
- package/dist/wasm/context.js +59 -0
- package/dist/wasm/context.js.map +1 -0
- package/dist/wasm/hostImports.d.ts +43 -0
- package/dist/wasm/hostImports.d.ts.map +1 -0
- package/dist/wasm/hostImports.js +158 -0
- package/dist/wasm/hostImports.js.map +1 -0
- package/dist/wasm/loader.d.ts +95 -0
- package/dist/wasm/loader.d.ts.map +1 -0
- package/dist/wasm/loader.js +198 -0
- package/dist/wasm/loader.js.map +1 -0
- package/dist/wasm/referencedFiles.d.ts +115 -0
- package/dist/wasm/referencedFiles.d.ts.map +1 -0
- package/dist/wasm/referencedFiles.js +366 -0
- package/dist/wasm/referencedFiles.js.map +1 -0
- package/dist/wasm/runner.d.ts +91 -0
- package/dist/wasm/runner.d.ts.map +1 -0
- package/dist/wasm/runner.js +308 -0
- package/dist/wasm/runner.js.map +1 -0
- package/dist/wasm/watch.d.ts +5 -0
- package/dist/wasm/watch.d.ts.map +1 -0
- package/dist/wasm/watch.js +54 -0
- package/dist/wasm/watch.js.map +1 -0
- package/dist/wasm/worker.d.ts +39 -0
- package/dist/wasm/worker.d.ts.map +1 -0
- package/dist/wasm/worker.js +245 -0
- package/dist/wasm/worker.js.map +1 -0
- package/package.json +14 -4
package/dist/interceptor.js
CHANGED
|
@@ -9,17 +9,118 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @module
|
|
11
11
|
*/
|
|
12
|
+
import * as node_crypto from 'node:crypto';
|
|
12
13
|
import { createStderrLogger as createLogger } from './stderrLog.js';
|
|
13
|
-
import { scanToolInput, formatDlpBlockReason } from './dlp.js';
|
|
14
|
+
import { scanToolInput, formatDlpBlockReason, setDynamicPatterns } from './dlp.js';
|
|
15
|
+
import { scanText, injectionSeverity, setDynamicInjectionPatterns } from './injection.js';
|
|
16
|
+
import { evaluateSequenceDetectors, resolveEffectiveDisposition, REASK_MAX_ATTEMPTS } from './anomaly/index.js';
|
|
17
|
+
import { SessionState } from './session.js';
|
|
14
18
|
const log = createLogger('mcp-proxy-interceptor');
|
|
15
19
|
export class ToolCallInterceptor {
|
|
16
20
|
policy;
|
|
17
21
|
emitter;
|
|
18
22
|
failOpen;
|
|
19
|
-
|
|
23
|
+
serverName;
|
|
24
|
+
injectionActionDefault;
|
|
25
|
+
session;
|
|
26
|
+
anomalyModeDefault;
|
|
27
|
+
anomalyOverridesDefault;
|
|
28
|
+
wasmRunner;
|
|
29
|
+
workspaceId;
|
|
30
|
+
constructor(policy, emitter, failOpen = true,
|
|
31
|
+
/**
|
|
32
|
+
* The real MCP server this proxy process fronts, from `--server-name`
|
|
33
|
+
* (config.ts, threaded since Phase D's `wrapWithProxy` but unconsumed
|
|
34
|
+
* until now). `'unknown'` when unset, matching config.ts's own default —
|
|
35
|
+
* see the server-scoping check below for why an allowlist naming
|
|
36
|
+
* anything else then refuses every call from this process.
|
|
37
|
+
*/
|
|
38
|
+
serverName = 'unknown',
|
|
39
|
+
/**
|
|
40
|
+
* Env-derived default prompt-injection disposition (`config.ts`'s
|
|
41
|
+
* `mcpInjectionAction`), used whenever `policy.getInjectionAction()`
|
|
42
|
+
* reports no control-plane override. Defaults to `'warn'` here too, so
|
|
43
|
+
* every existing construction site/test that doesn't pass this
|
|
44
|
+
* parameter keeps the same steer-not-kill posture the Rust detector this
|
|
45
|
+
* was ported from uses by default.
|
|
46
|
+
*/
|
|
47
|
+
injectionActionDefault = 'warn',
|
|
48
|
+
/**
|
|
49
|
+
* Shared per-process session state (Phase 2) — the SAME instance
|
|
50
|
+
* `McpGovernanceProxy` (proxy.ts) owns and hands to `handleHarnessLine`
|
|
51
|
+
* for post-decision recording, so the sequence this method reads for
|
|
52
|
+
* detection and the sequence `handleHarnessLine` appends to after an
|
|
53
|
+
* `allow` are never two different objects that could drift. Defaults to
|
|
54
|
+
* a fresh instance so every existing construction site/test that
|
|
55
|
+
* predates Phase 2 keeps working unchanged.
|
|
56
|
+
*/
|
|
57
|
+
session = new SessionState(),
|
|
58
|
+
/**
|
|
59
|
+
* Env-derived default anomaly mode (`config.ts`'s `mcpAnomalyMode`),
|
|
60
|
+
* used whenever `policy.getAnomalyMode()` reports no control-plane
|
|
61
|
+
* override. Defaults to `'enforce'` — see `config.ts`'s doc comment on
|
|
62
|
+
* why "enforce" here does not mean "block on suspicion": every
|
|
63
|
+
* detector's own Rust-declared disposition ceiling still applies via
|
|
64
|
+
* `resolveEffectiveDisposition`.
|
|
65
|
+
*/
|
|
66
|
+
anomalyModeDefault = 'enforce',
|
|
67
|
+
/**
|
|
68
|
+
* Env-derived default per-detector override map (`config.ts`'s
|
|
69
|
+
* `mcpAnomalyOverrides`). Merged with `policy.getAnomalyOverrides()` per
|
|
70
|
+
* key, control-plane value winning — the same "policy overrides the
|
|
71
|
+
* env-derived default, per field" shape `injectionActionDefault` uses,
|
|
72
|
+
* just applied per-map-entry instead of to one scalar.
|
|
73
|
+
*/
|
|
74
|
+
anomalyOverridesDefault = {},
|
|
75
|
+
/**
|
|
76
|
+
* Phase 3's WASM custom-rule runner, or `undefined` to skip WASM
|
|
77
|
+
* evaluation entirely (every construction site/test that predates Phase
|
|
78
|
+
* 3, and any deployment with no `~/.intutic/wasm/` rules). Owned by
|
|
79
|
+
* `McpGovernanceProxy` (proxy.ts), same sharing pattern as `session`.
|
|
80
|
+
*/
|
|
81
|
+
wasmRunner = undefined,
|
|
82
|
+
/**
|
|
83
|
+
* This proxy's workspace id, from `config.ts` — needed for Phase 3's
|
|
84
|
+
* `RequestContext.workspace_id` field. Stored separately from `policy`
|
|
85
|
+
* (which has no getter for it) and from `serverName` (a different
|
|
86
|
+
* identity: the MCP SERVER this process fronts, not the WORKSPACE it
|
|
87
|
+
* belongs to).
|
|
88
|
+
*/
|
|
89
|
+
workspaceId = 'unknown') {
|
|
20
90
|
this.policy = policy;
|
|
21
91
|
this.emitter = emitter;
|
|
22
92
|
this.failOpen = failOpen;
|
|
93
|
+
this.serverName = serverName;
|
|
94
|
+
this.injectionActionDefault = injectionActionDefault;
|
|
95
|
+
this.session = session;
|
|
96
|
+
this.anomalyModeDefault = anomalyModeDefault;
|
|
97
|
+
this.anomalyOverridesDefault = anomalyOverridesDefault;
|
|
98
|
+
this.wasmRunner = wasmRunner;
|
|
99
|
+
this.workspaceId = workspaceId;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Applies the shared reask ladder (Phase 2 anomaly detectors AND Phase 3
|
|
103
|
+
* WASM rules both use this): a session-lifetime attempt counter keyed by
|
|
104
|
+
* `key`, `REASK_MAX_ATTEMPTS` (3) tries before hardening into an
|
|
105
|
+
* unconditional block. Always emits `tool_blocked` — a reask blocks the
|
|
106
|
+
* CURRENT attempt, so existing consumers keyed on `tool_blocked` must see
|
|
107
|
+
* it, exactly like every other new block reason in this package.
|
|
108
|
+
*/
|
|
109
|
+
async applyReaskLadder(key, baseReason, toolName, toolInput) {
|
|
110
|
+
// Shared across the session's sibling proxy processes when a session
|
|
111
|
+
// store is configured (Wave 5.3); the per-process counter otherwise.
|
|
112
|
+
const attempts = await this.session.incrReaskAttemptShared(key);
|
|
113
|
+
if (attempts > REASK_MAX_ATTEMPTS) {
|
|
114
|
+
const hardenedReason = `${baseReason} — hardened to an unconditional block after ${REASK_MAX_ATTEMPTS} reask ` +
|
|
115
|
+
`attempts with no correction.`;
|
|
116
|
+
log.warn({ action: 'reask_hardened', toolName, key, attempts }, 'Reask attempts exhausted — hardening to a hard block');
|
|
117
|
+
this.emitter.emit('tool_blocked', toolName, toolInput, hardenedReason);
|
|
118
|
+
return { action: 'block', reason: hardenedReason };
|
|
119
|
+
}
|
|
120
|
+
const reaskReason = `${baseReason} (attempt ${attempts}/${REASK_MAX_ATTEMPTS} — will become an unconditional ` +
|
|
121
|
+
`block if this keeps tripping)`;
|
|
122
|
+
this.emitter.emit('tool_blocked', toolName, toolInput, reaskReason);
|
|
123
|
+
return { action: 'block', reason: reaskReason };
|
|
23
124
|
}
|
|
24
125
|
/**
|
|
25
126
|
* Evaluate a tools/call request and return a governance decision.
|
|
@@ -30,9 +131,65 @@ export class ToolCallInterceptor {
|
|
|
30
131
|
*/
|
|
31
132
|
async decide(toolName, toolInput) {
|
|
32
133
|
log.debug({ action: 'interceptor_decide', toolName }, 'Evaluating tool call');
|
|
33
|
-
//
|
|
134
|
+
// Captured across pipeline steps for Phase 3's WASM context (built only
|
|
135
|
+
// if this call reaches step 5) — each stays honestly empty/undefined
|
|
136
|
+
// when its step never ran or found nothing, never fabricated.
|
|
137
|
+
let dlpFindingsForContext = [];
|
|
138
|
+
let injectionFindingsForContext = [];
|
|
139
|
+
let injectionSourcesForContext = [];
|
|
140
|
+
let corroboratingDetectorsForContext = 0;
|
|
141
|
+
// -1. Additive SERVER scoping. When the workspace declares a server
|
|
142
|
+
// allowlist (mcpAllowedServers), ONLY calls proxied to those servers may
|
|
143
|
+
// proceed — checked ahead of the per-tool allowlist below since a
|
|
144
|
+
// disallowed server should never even reach tool-name evaluation. Same
|
|
145
|
+
// empty-means-unrestricted convention as every allowlist in this file,
|
|
146
|
+
// and — deliberately, like the tool-scoping check right below it — NOT
|
|
147
|
+
// gated on `failOpen`: an explicit, non-empty allowlist that excludes
|
|
148
|
+
// this server is a definite policy decision the proxy already has the
|
|
149
|
+
// data to make, not a "control plane unreachable" failure mode. A
|
|
150
|
+
// control-plane outage naturally fails open here too, for the same
|
|
151
|
+
// reason it does for tool scoping: an unreachable policy fetch leaves
|
|
152
|
+
// `allowedServers` empty, which reads as unrestricted rather than as a
|
|
153
|
+
// block.
|
|
154
|
+
const allowedServers = this.policy.getAllowedServers();
|
|
155
|
+
if (allowedServers.length > 0 && !allowedServers.includes(this.serverName)) {
|
|
156
|
+
const reason = `MCP server "${this.serverName}" is not in this workspace's MCP server allowlist ` +
|
|
157
|
+
`(${allowedServers.length} server(s) permitted). An operator can widen the ` +
|
|
158
|
+
`allowlist in workspace settings (mcpAllowedServers).`;
|
|
159
|
+
log.warn({ action: 'server_allowlist_block', serverName: this.serverName, toolName }, reason);
|
|
160
|
+
this.emitter.emit('tool_blocked', toolName, toolInput, reason);
|
|
161
|
+
return { action: 'block', reason };
|
|
162
|
+
}
|
|
163
|
+
// 0. Additive tool scoping. When the workspace declares an allowlist,
|
|
164
|
+
// ONLY those tools may be called — the inverse of every other rule here,
|
|
165
|
+
// which names what is forbidden. An EMPTY allowlist means unrestricted,
|
|
166
|
+
// never "permit nothing": read the other way it would block every
|
|
167
|
+
// workspace that never declared one, which is the exact inversion the
|
|
168
|
+
// starter rules' harness-allowlist near-miss exists to catch.
|
|
169
|
+
const allowedTools = this.policy.getAllowedTools();
|
|
170
|
+
if (allowedTools.length > 0 && !allowedTools.includes(toolName)) {
|
|
171
|
+
const reason = `Tool "${toolName}" is not in this workspace's MCP tool allowlist ` +
|
|
172
|
+
`(${allowedTools.length} tool(s) permitted). An operator can widen the ` +
|
|
173
|
+
`allowlist in workspace settings (mcpAllowedTools).`;
|
|
174
|
+
log.warn({ action: 'allowlist_block', toolName }, reason);
|
|
175
|
+
this.emitter.emit('tool_blocked', toolName, toolInput, reason);
|
|
176
|
+
return { action: 'block', reason };
|
|
177
|
+
}
|
|
178
|
+
// 1. DLP scan — with the workspace's own patterns loaded first, so a
|
|
179
|
+
// control-plane-defined pattern reaches the same scanner as the floor.
|
|
180
|
+
try {
|
|
181
|
+
setDynamicPatterns(this.policy.getDlpPatterns());
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// Pattern delivery must never take the scanner down; the floor stands.
|
|
185
|
+
}
|
|
34
186
|
try {
|
|
35
187
|
const dlp = scanToolInput(toolInput);
|
|
188
|
+
// Captured regardless of outcome — by pipeline position, a non-empty
|
|
189
|
+
// result here always blocks below, so `dlpFindingsForContext` is
|
|
190
|
+
// honestly almost always `[]` by the time Phase 3 reads it (a
|
|
191
|
+
// property of the pipeline order, not a bug in this capture).
|
|
192
|
+
dlpFindingsForContext = dlp.findings;
|
|
36
193
|
if (dlp.hasFinding) {
|
|
37
194
|
const reason = formatDlpBlockReason(dlp.findings);
|
|
38
195
|
log.warn({ action: 'dlp_block', toolName, findings: dlp.findings }, 'DLP block');
|
|
@@ -63,7 +220,10 @@ export class ToolCallInterceptor {
|
|
|
63
220
|
}
|
|
64
221
|
if (rule.action === 'warn') {
|
|
65
222
|
log.warn({ action: 'policy_warn', toolName, ruleId: rule.id, reason: rule.reason }, 'Policy warning (allowing)');
|
|
66
|
-
// Fall through to allow
|
|
223
|
+
// Fall through to allow. Reported as `tool_flagged` with the rule id
|
|
224
|
+
// in the reason — the same shape the harness gates use — so a
|
|
225
|
+
// SHADOW guardrail's evidence (LLD #71) counts this proxy's traffic.
|
|
226
|
+
this.emitter.emit('tool_flagged', toolName, toolInput, `${rule.reason} [${rule.id}]`);
|
|
67
227
|
}
|
|
68
228
|
// 'require_approval' treated as block in headless proxy (no interactive UI)
|
|
69
229
|
if (rule.action === 'require_approval') {
|
|
@@ -85,7 +245,143 @@ export class ToolCallInterceptor {
|
|
|
85
245
|
};
|
|
86
246
|
}
|
|
87
247
|
}
|
|
88
|
-
// 3.
|
|
248
|
+
// 3. Prompt-injection scan (request direction) — the `toolInput` a
|
|
249
|
+
// MISBEHAVING or COMPROMISED calling agent sends, e.g. an agent that
|
|
250
|
+
// itself already ingested injected content from an earlier step and is
|
|
251
|
+
// now echoing instructions into its own tool call. Pipeline position
|
|
252
|
+
// mirrors the Rust proxy's own ordering: after DLP/SOP, before anomaly
|
|
253
|
+
// detection and WASM rules (neither exists yet in this package — Phase
|
|
254
|
+
// 2/3 land after this).
|
|
255
|
+
try {
|
|
256
|
+
const toolInputText = JSON.stringify(toolInput ?? {});
|
|
257
|
+
setDynamicInjectionPatterns(this.policy.getInjectionPatterns());
|
|
258
|
+
const findings = scanText(toolInputText);
|
|
259
|
+
if (findings.length > 0) {
|
|
260
|
+
injectionFindingsForContext = findings;
|
|
261
|
+
injectionSourcesForContext = ['tool_input'];
|
|
262
|
+
const severity = injectionSeverity(findings, 'tool_input');
|
|
263
|
+
const reason = `Prompt-injection pattern(s) detected in tool input: ${findings.join(', ')}`;
|
|
264
|
+
log.warn({ action: 'injection_detected', toolName, patterns: findings, source: 'tool_input', severity }, 'Prompt-injection pattern matched in tool call input');
|
|
265
|
+
const injectionAction = this.policy.getInjectionAction() ?? this.injectionActionDefault;
|
|
266
|
+
this.emitter.emit('injection_detected', toolName, toolInput, reason, severity);
|
|
267
|
+
if (injectionAction === 'block') {
|
|
268
|
+
this.emitter.emit('tool_blocked', toolName, toolInput, reason);
|
|
269
|
+
return { action: 'block', reason };
|
|
270
|
+
}
|
|
271
|
+
// 'warn' (default): report only, fall through to allow.
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
catch (err) {
|
|
275
|
+
// Never let a scanner failure take the proxy down — same posture as
|
|
276
|
+
// the DLP/SOP try/catches above, and unconditionally non-fatal (unlike
|
|
277
|
+
// those) because injection scanning's own default disposition is
|
|
278
|
+
// report-only, so a scanner error degrading to "scan skipped" is no
|
|
279
|
+
// more permissive than the feature's own warn default.
|
|
280
|
+
log.error({ action: 'injection_scan_error', err: err.message }, 'Injection scan error — skipping');
|
|
281
|
+
}
|
|
282
|
+
// 4. Anomaly detection (Phase 2) — the 7 detectors ported from
|
|
283
|
+
// `packages/proxy/src/plugins/anomaly/detectors.rs`; see
|
|
284
|
+
// `anomaly/detectors.ts`. Five (consecutive_repeat, ping_pong_cycle,
|
|
285
|
+
// landmark_cycle, tool_diversity_collapse, code_as_action) are
|
|
286
|
+
// sequence/current-call detectors evaluated here, on every request; the
|
|
287
|
+
// other two (tool_poisoning, dlp_escalation) read data this pipeline
|
|
288
|
+
// stage does not have (a cached tools/list, response-direction DLP
|
|
289
|
+
// findings) and run from `proxy.ts`'s response-direction handling
|
|
290
|
+
// instead. Position: after injection, before WASM (Phase 3, not yet
|
|
291
|
+
// built) and allow.
|
|
292
|
+
const anomalyMode = this.policy.getAnomalyMode() ?? this.anomalyModeDefault;
|
|
293
|
+
// The session window — the shared one across this session's sibling
|
|
294
|
+
// proxy processes when a store is configured (Wave 5.3, TD-437), the
|
|
295
|
+
// per-process one otherwise. One round trip at most per tools/call, and
|
|
296
|
+
// none when nothing below would read it.
|
|
297
|
+
const window = anomalyMode !== 'off' || this.wasmRunner ? await this.session.loadWindow(toolName) : undefined;
|
|
298
|
+
if (anomalyMode !== 'off' && window) {
|
|
299
|
+
try {
|
|
300
|
+
const prospective = window.prospective;
|
|
301
|
+
const findings = evaluateSequenceDetectors(prospective, toolName, toolInput);
|
|
302
|
+
corroboratingDetectorsForContext = findings.length;
|
|
303
|
+
const overrides = { ...this.anomalyOverridesDefault, ...this.policy.getAnomalyOverrides() };
|
|
304
|
+
for (const finding of findings) {
|
|
305
|
+
const effective = resolveEffectiveDisposition(finding, anomalyMode, overrides);
|
|
306
|
+
if (effective === 'off')
|
|
307
|
+
continue; // demoted below reporting entirely — skip silently
|
|
308
|
+
const severity = effective === 'kill' ? 'high' : effective === 'reask' ? 'medium' : 'low';
|
|
309
|
+
log.warn({
|
|
310
|
+
action: 'anomaly_detected',
|
|
311
|
+
toolName,
|
|
312
|
+
detectorId: finding.detectorId,
|
|
313
|
+
kind: finding.kind,
|
|
314
|
+
disposition: effective,
|
|
315
|
+
confidence: finding.confidence,
|
|
316
|
+
}, 'Anomaly detector fired');
|
|
317
|
+
this.emitter.emit('anomaly_detected', toolName, toolInput, finding.reason, severity);
|
|
318
|
+
if (effective === 'kill') {
|
|
319
|
+
this.emitter.emit('tool_blocked', toolName, toolInput, finding.reason);
|
|
320
|
+
return { action: 'block', reason: finding.reason };
|
|
321
|
+
}
|
|
322
|
+
if (effective === 'reask') {
|
|
323
|
+
// Keyed per-detector-id, independent of every other detector's
|
|
324
|
+
// (and every WASM rule's — see applyReaskLadder) own counter.
|
|
325
|
+
return await this.applyReaskLadder(finding.detectorId, finding.reason, toolName, toolInput);
|
|
326
|
+
}
|
|
327
|
+
// 'steer': report only. Findings are sorted most-severe-first
|
|
328
|
+
// (evaluateSequenceDetectors), so once we reach a 'steer' finding
|
|
329
|
+
// every remaining one is 'steer' too — keep logging/emitting them,
|
|
330
|
+
// then fall through to allow.
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
catch (err) {
|
|
334
|
+
// Same non-fatal posture as the injection scanner above: an anomaly
|
|
335
|
+
// detector is a pure function of in-memory state, but a defensive
|
|
336
|
+
// catch here means a bug in one detector degrades to "this call's
|
|
337
|
+
// anomaly check was skipped," never "the proxy crashed."
|
|
338
|
+
log.error({ action: 'anomaly_detection_error', err: err.message }, 'Anomaly detection error — skipping');
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
// 5. WASM custom rules (Phase 3) — operator-authored, compiled
|
|
342
|
+
// AssemblyScript rules dropped into `~/.intutic/wasm/`. Position: after
|
|
343
|
+
// every built-in check, immediately before allow — this is deliberately
|
|
344
|
+
// the LAST gate, so a WASM rule's `RequestContext` carries
|
|
345
|
+
// `injection_findings`/`corroborating_detectors`/etc. already populated
|
|
346
|
+
// by the steps above it (see `wasm/context.ts`'s module doc).
|
|
347
|
+
if (this.wasmRunner) {
|
|
348
|
+
try {
|
|
349
|
+
const verdict = await this.wasmRunner.evaluate({
|
|
350
|
+
sessionId: this.session.sessionId,
|
|
351
|
+
workspaceId: this.workspaceId,
|
|
352
|
+
tools: this.session.getToolsList(),
|
|
353
|
+
toolCallId: node_crypto.randomUUID(),
|
|
354
|
+
toolName,
|
|
355
|
+
toolArguments: toolInput,
|
|
356
|
+
toolSequence: window?.prospective ?? this.session.prospectiveSequence(toolName),
|
|
357
|
+
callsLast60s: window?.callsLast60s ?? this.session.callsInLastMs(),
|
|
358
|
+
dlpFindingDescriptions: dlpFindingsForContext.map((f) => f.description),
|
|
359
|
+
injectionFindings: injectionFindingsForContext,
|
|
360
|
+
injectionSources: injectionSourcesForContext,
|
|
361
|
+
corroboratingDetectors: corroboratingDetectorsForContext,
|
|
362
|
+
toolContractChanged: this.session.getToolContractChanged(),
|
|
363
|
+
});
|
|
364
|
+
if (verdict.code === 'block') {
|
|
365
|
+
log.warn({ action: 'wasm_block', toolName, ruleId: verdict.ruleId }, 'Tool call blocked by WASM governance rule');
|
|
366
|
+
this.emitter.emit('tool_blocked', toolName, toolInput, verdict.reason);
|
|
367
|
+
return { action: 'block', reason: verdict.reason };
|
|
368
|
+
}
|
|
369
|
+
if (verdict.code === 'reask') {
|
|
370
|
+
// Keyed per-rule-id, independent of every anomaly detector's own
|
|
371
|
+
// counter — see applyReaskLadder's doc comment.
|
|
372
|
+
return await this.applyReaskLadder(`wasm:${verdict.ruleId}`, verdict.reason, toolName, toolInput);
|
|
373
|
+
}
|
|
374
|
+
// 'allow': fall through.
|
|
375
|
+
}
|
|
376
|
+
catch (err) {
|
|
377
|
+
// Fail-open, matching every other governance-check catch in this
|
|
378
|
+
// method — a WASM runner failure (not to be confused with a single
|
|
379
|
+
// rule's own timeout/trap, which `WasmRunner.evaluate` already
|
|
380
|
+
// absorbs internally) must not take the whole proxy down.
|
|
381
|
+
log.error({ action: 'wasm_evaluate_error', err: err.message }, 'WASM rule evaluation error — skipping');
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
// 6. Allow — emit telemetry event
|
|
89
385
|
this.emitter.emit('tool_allowed', toolName, toolInput);
|
|
90
386
|
return { action: 'allow' };
|
|
91
387
|
}
|
package/dist/interceptor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interceptor.js","sourceRoot":"","sources":["../src/interceptor.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"interceptor.js","sourceRoot":"","sources":["../src/interceptor.ts"],"names":[],"mappings":"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"}
|
package/dist/policy.d.ts
CHANGED
|
@@ -17,6 +17,28 @@ export interface SopRule {
|
|
|
17
17
|
/** Human-readable reason reported back to harness */
|
|
18
18
|
reason: string;
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Is this unvalidated object actually a policy rule?
|
|
22
|
+
*
|
|
23
|
+
* The daemon caches `sopRules` as `Record<string, unknown>[]` — it filters the
|
|
24
|
+
* control plane's response to plain objects and validates nothing further. The
|
|
25
|
+
* client then used `as SopRule[]`, behind a `Promise<any>` that hid the
|
|
26
|
+
* mismatch entirely.
|
|
27
|
+
*
|
|
28
|
+
* That matters because these drive blocking decisions: a rule missing
|
|
29
|
+
* `toolPattern` reaches `new RegExp(undefined)` and matches everything, and a
|
|
30
|
+
* rule with an unrecognised `action` falls through every branch and enforces
|
|
31
|
+
* nothing. Neither is a shape the control plane intends to send — which is the
|
|
32
|
+
* argument for dropping the malformed ones loudly rather than trusting a cast.
|
|
33
|
+
*/
|
|
34
|
+
/**
|
|
35
|
+
* Exported because it is the contract between this package and whatever
|
|
36
|
+
* produces rules for it, not merely an internal helper. `policyCache`'s snapshot
|
|
37
|
+
* seed has to satisfy it, and a test that asserted against a *copy* of this
|
|
38
|
+
* predicate would prove nothing about the real one — which is precisely the
|
|
39
|
+
* two-copies-of-one-rule failure the harness gates were just rebuilt to remove.
|
|
40
|
+
*/
|
|
41
|
+
export declare function isSopRule(value: unknown): value is SopRule;
|
|
20
42
|
export declare class PolicyClient {
|
|
21
43
|
private readonly controlPlaneUrl;
|
|
22
44
|
private readonly apiKey;
|
|
@@ -24,15 +46,101 @@ export declare class PolicyClient {
|
|
|
24
46
|
private readonly ttlMs;
|
|
25
47
|
private readonly mcpProxyMode;
|
|
26
48
|
private rules;
|
|
49
|
+
/**
|
|
50
|
+
* Workspace DLP regex sources, delivered to the scanner on every refresh.
|
|
51
|
+
* The daemon has cached these since the policy cache existed; this client
|
|
52
|
+
* received and dropped them — a workspace's custom patterns were a setting
|
|
53
|
+
* wired to nothing.
|
|
54
|
+
*/
|
|
55
|
+
private dlpPatterns;
|
|
56
|
+
/** Workspace injection-pattern sources (`mcpInjectionPatterns`, TD-436); empty = floor only. */
|
|
57
|
+
private injectionPatterns;
|
|
58
|
+
/**
|
|
59
|
+
* Additive tool scoping: when non-empty, ONLY these tools may be called
|
|
60
|
+
* through this proxy. Empty means unrestricted — the same convention as
|
|
61
|
+
* `allow_harnesses` and the starter rules' allowlist inversion warnings:
|
|
62
|
+
* an empty allowlist read as "permit nothing" would block every workspace
|
|
63
|
+
* that never declared one.
|
|
64
|
+
*/
|
|
65
|
+
private allowedTools;
|
|
66
|
+
/** Operator-curated tool descriptions, applied to tools/list responses. */
|
|
67
|
+
private toolDescriptionOverrides;
|
|
68
|
+
/**
|
|
69
|
+
* Additive SERVER scoping: when non-empty, ONLY these MCP server names may
|
|
70
|
+
* be proxied by this process. Empty means unrestricted — same convention
|
|
71
|
+
* and same source as `allowedTools` above (mirrors `mcpAllowedTools` /
|
|
72
|
+
* `mcpAllowedServers` in workspace settings, delivered via the same
|
|
73
|
+
* `GET /api/v1/sop/rules` response this class already polls).
|
|
74
|
+
*/
|
|
75
|
+
private allowedServers;
|
|
76
|
+
/**
|
|
77
|
+
* Control-plane-delivered prompt-injection disposition override. `undefined`
|
|
78
|
+
* (never `'warn'`/`'block'` by default) means "the control plane did not
|
|
79
|
+
* send this field" — distinct from the field being explicitly set to
|
|
80
|
+
* `'warn'` — so the caller (interceptor.ts) knows to fall back to
|
|
81
|
+
* `config.ts`'s `mcpInjectionAction` env-derived default rather than
|
|
82
|
+
* silently treating an unset policy as an explicit warn.
|
|
83
|
+
*/
|
|
84
|
+
private injectionAction;
|
|
85
|
+
/**
|
|
86
|
+
* Control-plane-delivered anomaly-detection mode override (Phase 2).
|
|
87
|
+
* `undefined` when absent — same "absent means no override, fall back to
|
|
88
|
+
* config.ts's env-derived default" convention as `injectionAction` above.
|
|
89
|
+
*/
|
|
90
|
+
private anomalyMode;
|
|
91
|
+
/**
|
|
92
|
+
* Control-plane-delivered per-detector disposition overrides. Always an
|
|
93
|
+
* object (never `undefined`) — an absent policy field reads as "no
|
|
94
|
+
* overrides," which `resolveEffectiveDisposition` (anomaly/index.ts)
|
|
95
|
+
* already treats as a no-op via `overrides[detectorId] === undefined`, the
|
|
96
|
+
* same empty-object-means-unrestricted convention `toolDescriptionOverrides`
|
|
97
|
+
* above uses.
|
|
98
|
+
*/
|
|
99
|
+
private anomalyOverrides;
|
|
27
100
|
private lastFetchAt;
|
|
28
101
|
private refreshTimer;
|
|
29
102
|
constructor(controlPlaneUrl: string, apiKey: string, workspaceId: string, ttlMs?: number, mcpProxyMode?: string);
|
|
30
|
-
/**
|
|
31
|
-
|
|
103
|
+
/**
|
|
104
|
+
* Start background refresh timer.
|
|
105
|
+
*
|
|
106
|
+
* @param onTick - Optional callback invoked on the SAME interval as the
|
|
107
|
+
* policy refresh (including the initial kick below) — Phase 3's
|
|
108
|
+
* `~/.intutic/wasm/` rescan (`WasmRunner.rescan`, wired from proxy.ts)
|
|
109
|
+
* hooks this rather than starting a second timer, per the task's own
|
|
110
|
+
* "don't add a second timer" instruction. Errors are swallowed the same
|
|
111
|
+
* way `refresh()`'s own are — a rescan failure must not take down the
|
|
112
|
+
* policy refresh it rides alongside.
|
|
113
|
+
*/
|
|
114
|
+
start(onTick?: () => void | Promise<void>): void;
|
|
32
115
|
/** Stop the background refresh timer. */
|
|
33
116
|
stop(): void;
|
|
34
117
|
/** Return the current cached rule set. */
|
|
35
118
|
getRules(): readonly SopRule[];
|
|
119
|
+
/** Workspace DLP regex sources from the last successful refresh. */
|
|
120
|
+
/** Workspace-supplied prompt-injection regex sources; empty means the hardcoded floor alone. */
|
|
121
|
+
getInjectionPatterns(): readonly string[];
|
|
122
|
+
getDlpPatterns(): readonly string[];
|
|
123
|
+
/** The additive tool allowlist; empty means unrestricted. */
|
|
124
|
+
getAllowedTools(): readonly string[];
|
|
125
|
+
/** The additive MCP server allowlist; empty means unrestricted. */
|
|
126
|
+
getAllowedServers(): readonly string[];
|
|
127
|
+
/** Operator description overrides for tools/list curation. */
|
|
128
|
+
getToolDescriptionOverrides(): Readonly<Record<string, string>>;
|
|
129
|
+
/**
|
|
130
|
+
* The control-plane-delivered prompt-injection disposition, or `undefined`
|
|
131
|
+
* when the policy source never sent `mcpInjectionAction` — absent means
|
|
132
|
+
* "no override", not "warn". Callers (interceptor.ts) fall back to
|
|
133
|
+
* `config.ts`'s env-derived default in that case, the same "absent means
|
|
134
|
+
* default" convention every other optional policy field in this class
|
|
135
|
+
* follows.
|
|
136
|
+
*/
|
|
137
|
+
getInjectionAction(): 'warn' | 'block' | undefined;
|
|
138
|
+
/** The control-plane-delivered anomaly mode, or `undefined` if unset (see field doc). */
|
|
139
|
+
getAnomalyMode(): 'enforce' | 'warn' | 'off' | undefined;
|
|
140
|
+
/** Per-detector disposition overrides; always an object, empty means none. */
|
|
141
|
+
getAnomalyOverrides(): Readonly<Record<string, 'steer' | 'reask' | 'kill' | 'off'>>;
|
|
142
|
+
/** Parse the optional curation fields shared by both refresh paths. */
|
|
143
|
+
private absorbCuration;
|
|
36
144
|
/** Find the first matching rule for a given tool name + serialized args. */
|
|
37
145
|
matchRule(toolName: string, toolInputJson: string): SopRule | null;
|
|
38
146
|
/** Fetch fresh rules from the control plane. */
|
package/dist/policy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"policy.d.ts","sourceRoot":"","sources":["../src/policy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAUH,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,iFAAiF;IACjF,WAAW,EAAE,MAAM,CAAA;IACnB,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,2CAA2C;IAC3C,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,kBAAkB,CAAA;IAC7C,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAA;CACf;AAED;;;;;;;;;;;;;GAaG;AACH;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,OAAO,CAU1D;AAMD,qBAAa,YAAY;IAyDrB,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,YAAY;IA5D/B,OAAO,CAAC,KAAK,CAAgB;IAC7B;;;;;OAKG;IACH,OAAO,CAAC,WAAW,CAAe;IAClC,gGAAgG;IAChG,OAAO,CAAC,iBAAiB,CAAe;IACxC;;;;;;OAMG;IACH,OAAO,CAAC,YAAY,CAAe;IACnC,2EAA2E;IAC3E,OAAO,CAAC,wBAAwB,CAA6B;IAC7D;;;;;;OAMG;IACH,OAAO,CAAC,cAAc,CAAe;IACrC;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe,CAA8B;IACrD;;;;OAIG;IACH,OAAO,CAAC,WAAW,CAAwC;IAC3D;;;;;;;OAOG;IACH,OAAO,CAAC,gBAAgB,CAAyD;IACjF,OAAO,CAAC,WAAW,CAAI;IACvB,OAAO,CAAC,YAAY,CAA8B;gBAG/B,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,KAAK,GAAE,MAAe,EACtB,YAAY,GAAE,MAAsB;IAGvD;;;;;;;;;;OAUG;IACH,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAehD,yCAAyC;IACzC,IAAI,IAAI,IAAI;IAOZ,0CAA0C;IAC1C,QAAQ,IAAI,SAAS,OAAO,EAAE;IAI9B,oEAAoE;IACpE,gGAAgG;IAChG,oBAAoB,IAAI,SAAS,MAAM,EAAE;IAIzC,cAAc,IAAI,SAAS,MAAM,EAAE;IAInC,6DAA6D;IAC7D,eAAe,IAAI,SAAS,MAAM,EAAE;IAIpC,mEAAmE;IACnE,iBAAiB,IAAI,SAAS,MAAM,EAAE;IAItC,8DAA8D;IAC9D,2BAA2B,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAI/D;;;;;;;OAOG;IACH,kBAAkB,IAAI,MAAM,GAAG,OAAO,GAAG,SAAS;IAIlD,yFAAyF;IACzF,cAAc,IAAI,SAAS,GAAG,MAAM,GAAG,KAAK,GAAG,SAAS;IAIxD,8EAA8E;IAC9E,mBAAmB,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC,CAAC;IAInF,uEAAuE;IACvE,OAAO,CAAC,cAAc;IAmCtB,4EAA4E;IAC5E,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI;IAiBlE,gDAAgD;IAC1C,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CA6D/B"}
|