@intutic/mcp-governance-proxy 1.9.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
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* injection.ts — Prompt-injection pattern scanning over MCP tool-call traffic.
|
|
3
|
+
*
|
|
4
|
+
* Direct TypeScript port of `packages/proxy/src/injection.rs`'s five named
|
|
5
|
+
* regex patterns. Rust's `regex` crate and JS `RegExp` agree on everything
|
|
6
|
+
* these patterns use (case-insensitive alternation, `\b`, `\s+`, no
|
|
7
|
+
* backreferences or lookaround), so the pattern SOURCE TEXT is unchanged —
|
|
8
|
+
* only the syntax wrapper (Rust raw string → JS regex literal) differs.
|
|
9
|
+
*
|
|
10
|
+
* This is deliberately not a classifier — see injection.rs's module doc for
|
|
11
|
+
* the full argument. Pattern matching only, priced at a handful of regex
|
|
12
|
+
* tests, catching the well-known phrasings and nothing else. False positives
|
|
13
|
+
* are the real cost (people legitimately tell an agent to "ignore my last
|
|
14
|
+
* message"), which is why the patterns stay narrow and a single match steers
|
|
15
|
+
* rather than kills.
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Replace the dynamic pattern set. Cheap to call on every scan: a source
|
|
21
|
+
* list identical to the last one is a no-op, so callers can hand it the
|
|
22
|
+
* policy's current list without tracking changes themselves. Returns how
|
|
23
|
+
* many sources did not compile.
|
|
24
|
+
*/
|
|
25
|
+
export declare function setDynamicInjectionPatterns(sources: readonly string[]): number;
|
|
26
|
+
/**
|
|
27
|
+
* Names of the injection patterns present in `text`, deduplicated. Empty
|
|
28
|
+
* when nothing matched (the overwhelmingly common case).
|
|
29
|
+
*/
|
|
30
|
+
export declare function scanText(text: string): string[];
|
|
31
|
+
/** Where a piece of scanned MCP traffic came from. */
|
|
32
|
+
export type InjectionSource = 'tool_result' | 'tool_description' | 'tool_input';
|
|
33
|
+
export type InjectionSeverity = 'low' | 'high';
|
|
34
|
+
/**
|
|
35
|
+
* Mirrors `PromptInjectionDetector::detect`'s escalation rule (detectors.rs):
|
|
36
|
+
* severity escalates to `high` when findings reach the kill threshold (≥2
|
|
37
|
+
* distinct techniques) OR the source is untrusted content — otherwise `low`.
|
|
38
|
+
* Note this is an EVENT-severity mirror only; it does not by itself decide
|
|
39
|
+
* `allow`/`block` — see `mcpInjectionAction` (interceptor.ts / proxy.ts) for
|
|
40
|
+
* the actual disposition, which follows this package's own warn/block
|
|
41
|
+
* config rather than the Rust detector's reask/steer ladder (MCP's headless
|
|
42
|
+
* proxy has no reask loop of its own at the injection layer — Phase 2's
|
|
43
|
+
* anomaly reask ladder is the analogue for that).
|
|
44
|
+
*/
|
|
45
|
+
export declare function injectionSeverity(findings: readonly string[], source: InjectionSource): InjectionSeverity;
|
|
46
|
+
//# sourceMappingURL=injection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injection.d.ts","sourceRoot":"","sources":["../src/injection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAsEH;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAe9E;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAW/C;AAED,sDAAsD;AACtD,MAAM,MAAM,eAAe,GAAG,aAAa,GAAG,kBAAkB,GAAG,YAAY,CAAA;AAE/E,MAAM,MAAM,iBAAiB,GAAG,KAAK,GAAG,MAAM,CAAA;AAc9C;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,EAAE,MAAM,EAAE,eAAe,GAAG,iBAAiB,CAGzG"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* injection.ts — Prompt-injection pattern scanning over MCP tool-call traffic.
|
|
3
|
+
*
|
|
4
|
+
* Direct TypeScript port of `packages/proxy/src/injection.rs`'s five named
|
|
5
|
+
* regex patterns. Rust's `regex` crate and JS `RegExp` agree on everything
|
|
6
|
+
* these patterns use (case-insensitive alternation, `\b`, `\s+`, no
|
|
7
|
+
* backreferences or lookaround), so the pattern SOURCE TEXT is unchanged —
|
|
8
|
+
* only the syntax wrapper (Rust raw string → JS regex literal) differs.
|
|
9
|
+
*
|
|
10
|
+
* This is deliberately not a classifier — see injection.rs's module doc for
|
|
11
|
+
* the full argument. Pattern matching only, priced at a handful of regex
|
|
12
|
+
* tests, catching the well-known phrasings and nothing else. False positives
|
|
13
|
+
* are the real cost (people legitimately tell an agent to "ignore my last
|
|
14
|
+
* message"), which is why the patterns stay narrow and a single match steers
|
|
15
|
+
* rather than kills.
|
|
16
|
+
*
|
|
17
|
+
* @module
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Ported verbatim from `packages/proxy/src/injection.rs`'s `PATTERNS` const
|
|
21
|
+
* (confirmed by reading that file directly — names and pattern text below
|
|
22
|
+
* are not inferred). None of these patterns has the wide bounded-repetition
|
|
23
|
+
* shape (`{20,300}`, etc.) that caused the unrelated `RegexSet` performance
|
|
24
|
+
* regression documented in `dlp.rs` — the widest quantifier here is `\s+`
|
|
25
|
+
* and a handful of short alternations — so a plain sequential scan (no
|
|
26
|
+
* RegexSet-equivalent needed) is both correct and linear-time on untrusted
|
|
27
|
+
* input.
|
|
28
|
+
*/
|
|
29
|
+
const PATTERNS = [
|
|
30
|
+
{
|
|
31
|
+
name: 'override-instructions',
|
|
32
|
+
regex: /\b(ignore|disregard|forget)\s+(all\s+|any\s+)?(previous|prior|earlier|above|preceding)\s+(instruction|direction|prompt|rule|command)s?\b/i,
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
name: 'reveal-system-prompt',
|
|
36
|
+
regex: /\b(reveal|repeat|print|show|output|display)\s+(me\s+)?(your|the)\s+(system\s+prompt|initial\s+instructions|original\s+instructions)\b/i,
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'role-reassignment',
|
|
40
|
+
regex: /\byou\s+are\s+now\s+(a|an|in)\b|\bfrom\s+now\s+on,?\s+you\s+(are|will|must)\b/i,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'guardrail-bypass',
|
|
44
|
+
regex: /\b(developer|debug|god)\s+mode\b|\bDAN\s+mode\b|\bwithout\s+any\s+(restrictions|filters|guardrails)\b/i,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
name: 'instruction-boundary-forgery',
|
|
48
|
+
// Rust's `(^|\n)` with no `(?m)` flag matches only the start of the WHOLE
|
|
49
|
+
// haystack or a literal newline character — never "start of any line" the
|
|
50
|
+
// way `^` would under a multiline flag. JS `^` without the `m` flag has
|
|
51
|
+
// the identical "start of whole string" semantics, and the pattern
|
|
52
|
+
// already spells out `(^|\n)` explicitly, so no `m` flag is added here —
|
|
53
|
+
// adding one would change behavior (every line start would match) rather
|
|
54
|
+
// than preserve it.
|
|
55
|
+
regex: /(^|\n)\s*(\[\/?(INST|SYSTEM)\]|<\|?(im_start|system)\|?>|###\s*system\b)/i,
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
/**
|
|
59
|
+
* Ported from `detectors.rs`'s `INJECTION_KILL_THRESHOLD` (confirmed: `const
|
|
60
|
+
* INJECTION_KILL_THRESHOLD: usize = 2;`) — the Rust `PromptInjectionDetector`
|
|
61
|
+
* escalates to `reask` once findings reach this count, OR immediately on any
|
|
62
|
+
* untrusted-content source. `scanText`/`injectionSeverity` below reuse the
|
|
63
|
+
* same threshold for MCP's `injection_detected` event severity, mirroring
|
|
64
|
+
* that escalation rule rather than reimplementing a new one.
|
|
65
|
+
*/
|
|
66
|
+
const KILL_THRESHOLD = 2;
|
|
67
|
+
/**
|
|
68
|
+
* Workspace-supplied patterns, compiled (TD-436). Same contract as
|
|
69
|
+
* `dlp.ts`'s `setDynamicPatterns`: sources come from the control plane's
|
|
70
|
+
* `mcpInjectionPatterns`, an invalid one is dropped and counted, and the
|
|
71
|
+
* hardcoded floor above applies regardless — an unreachable control plane
|
|
72
|
+
* degrades to the floor, never to no scanning. Named `workspace:<n>` so a
|
|
73
|
+
* finding says which layer matched.
|
|
74
|
+
*/
|
|
75
|
+
let dynamicPatterns = [];
|
|
76
|
+
let dynamicKey = '';
|
|
77
|
+
/**
|
|
78
|
+
* Replace the dynamic pattern set. Cheap to call on every scan: a source
|
|
79
|
+
* list identical to the last one is a no-op, so callers can hand it the
|
|
80
|
+
* policy's current list without tracking changes themselves. Returns how
|
|
81
|
+
* many sources did not compile.
|
|
82
|
+
*/
|
|
83
|
+
export function setDynamicInjectionPatterns(sources) {
|
|
84
|
+
const key = sources.join('\u0000');
|
|
85
|
+
if (key === dynamicKey)
|
|
86
|
+
return 0;
|
|
87
|
+
const compiled = [];
|
|
88
|
+
let dropped = 0;
|
|
89
|
+
sources.forEach((src, i) => {
|
|
90
|
+
try {
|
|
91
|
+
compiled.push({ name: `workspace:${i + 1}`, regex: new RegExp(src, 'i') });
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
dropped += 1;
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
dynamicPatterns = compiled;
|
|
98
|
+
dynamicKey = key;
|
|
99
|
+
return dropped;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Names of the injection patterns present in `text`, deduplicated. Empty
|
|
103
|
+
* when nothing matched (the overwhelmingly common case).
|
|
104
|
+
*/
|
|
105
|
+
export function scanText(text) {
|
|
106
|
+
if (!text)
|
|
107
|
+
return [];
|
|
108
|
+
const found = [];
|
|
109
|
+
for (const { name, regex } of PATTERNS) {
|
|
110
|
+
if (regex.test(text))
|
|
111
|
+
found.push(name);
|
|
112
|
+
}
|
|
113
|
+
for (const { name, regex } of dynamicPatterns) {
|
|
114
|
+
regex.lastIndex = 0;
|
|
115
|
+
if (regex.test(text))
|
|
116
|
+
found.push(name);
|
|
117
|
+
}
|
|
118
|
+
return found;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Sources this proxy treats as untrusted content the agent fetched or was
|
|
122
|
+
* handed, rather than the calling agent's own request — the same
|
|
123
|
+
* distinction `detectors.rs`'s `from_untrusted_content` draws between
|
|
124
|
+
* `tool_result`/`tool_description` and `user_prompt`. MCP has no
|
|
125
|
+
* `user_prompt`/`system_prompt` concept of its own; `tool_input` (the
|
|
126
|
+
* request direction, the calling agent's own tool arguments) is this
|
|
127
|
+
* proxy's closest analogue to the Rust detector's trusted `user_prompt`
|
|
128
|
+
* source, so it is deliberately excluded here.
|
|
129
|
+
*/
|
|
130
|
+
const UNTRUSTED_SOURCES = new Set(['tool_result', 'tool_description']);
|
|
131
|
+
/**
|
|
132
|
+
* Mirrors `PromptInjectionDetector::detect`'s escalation rule (detectors.rs):
|
|
133
|
+
* severity escalates to `high` when findings reach the kill threshold (≥2
|
|
134
|
+
* distinct techniques) OR the source is untrusted content — otherwise `low`.
|
|
135
|
+
* Note this is an EVENT-severity mirror only; it does not by itself decide
|
|
136
|
+
* `allow`/`block` — see `mcpInjectionAction` (interceptor.ts / proxy.ts) for
|
|
137
|
+
* the actual disposition, which follows this package's own warn/block
|
|
138
|
+
* config rather than the Rust detector's reask/steer ladder (MCP's headless
|
|
139
|
+
* proxy has no reask loop of its own at the injection layer — Phase 2's
|
|
140
|
+
* anomaly reask ladder is the analogue for that).
|
|
141
|
+
*/
|
|
142
|
+
export function injectionSeverity(findings, source) {
|
|
143
|
+
if (findings.length >= KILL_THRESHOLD || UNTRUSTED_SOURCES.has(source))
|
|
144
|
+
return 'high';
|
|
145
|
+
return 'low';
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=injection.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"injection.js","sourceRoot":"","sources":["../src/injection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAOH;;;;;;;;;GASG;AACH,MAAM,QAAQ,GAAgC;IAC5C;QACE,IAAI,EAAE,uBAAuB;QAC7B,KAAK,EACH,2IAA2I;KAC9I;IACD;QACE,IAAI,EAAE,sBAAsB;QAC5B,KAAK,EACH,wIAAwI;KAC3I;IACD;QACE,IAAI,EAAE,mBAAmB;QACzB,KAAK,EAAE,gFAAgF;KACxF;IACD;QACE,IAAI,EAAE,kBAAkB;QACxB,KAAK,EAAE,wGAAwG;KAChH;IACD;QACE,IAAI,EAAE,8BAA8B;QACpC,0EAA0E;QAC1E,0EAA0E;QAC1E,wEAAwE;QACxE,mEAAmE;QACnE,yEAAyE;QACzE,yEAAyE;QACzE,oBAAoB;QACpB,KAAK,EAAE,2EAA2E;KACnF;CACF,CAAA;AAED;;;;;;;GAOG;AACH,MAAM,cAAc,GAAG,CAAC,CAAA;AAExB;;;;;;;GAOG;AACH,IAAI,eAAe,GAAgC,EAAE,CAAA;AACrD,IAAI,UAAU,GAAG,EAAE,CAAA;AAEnB;;;;;GAKG;AACH,MAAM,UAAU,2BAA2B,CAAC,OAA0B;IACpE,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAClC,IAAI,GAAG,KAAK,UAAU;QAAE,OAAO,CAAC,CAAA;IAChC,MAAM,QAAQ,GAAuB,EAAE,CAAA;IACvC,IAAI,OAAO,GAAG,CAAC,CAAA;IACf,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;QACzB,IAAI,CAAC;YACH,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,CAAA;QAC5E,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC,CAAA;QACd,CAAC;IACH,CAAC,CAAC,CAAA;IACF,eAAe,GAAG,QAAQ,CAAA;IAC1B,UAAU,GAAG,GAAG,CAAA;IAChB,OAAO,OAAO,CAAA;AAChB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAY;IACnC,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAA;IACpB,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,KAAK,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,QAAQ,EAAE,CAAC;QACvC,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACxC,CAAC;IACD,KAAK,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,eAAe,EAAE,CAAC;QAC9C,KAAK,CAAC,SAAS,GAAG,CAAC,CAAA;QACnB,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;IACxC,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAOD;;;;;;;;;GASG;AACH,MAAM,iBAAiB,GAAiC,IAAI,GAAG,CAAC,CAAC,aAAa,EAAE,kBAAkB,CAAC,CAAC,CAAA;AAEpG;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAA2B,EAAE,MAAuB;IACpF,IAAI,QAAQ,CAAC,MAAM,IAAI,cAAc,IAAI,iBAAiB,CAAC,GAAG,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAA;IACrF,OAAO,KAAK,CAAA;AACd,CAAC"}
|
package/dist/interceptor.d.ts
CHANGED
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
*
|
|
10
10
|
* @module
|
|
11
11
|
*/
|
|
12
|
+
import type { AnomalyMode, Disposition } from './anomaly/index.js';
|
|
13
|
+
import { SessionState } from './session.js';
|
|
14
|
+
import type { WasmRunner } from './wasm/runner.js';
|
|
12
15
|
import type { PolicyClient } from './policy.js';
|
|
13
16
|
import type { GovernanceEmitter } from './emitter.js';
|
|
14
17
|
export type Decision = {
|
|
@@ -25,7 +28,134 @@ export declare class ToolCallInterceptor {
|
|
|
25
28
|
private readonly policy;
|
|
26
29
|
private readonly emitter;
|
|
27
30
|
private readonly failOpen;
|
|
28
|
-
|
|
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
|
+
private readonly serverName;
|
|
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
|
+
private readonly injectionActionDefault;
|
|
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
|
+
private readonly session;
|
|
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
|
+
private readonly anomalyModeDefault;
|
|
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
|
+
private readonly 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
|
+
private readonly wasmRunner;
|
|
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
|
+
private readonly workspaceId;
|
|
90
|
+
constructor(policy: PolicyClient, emitter: GovernanceEmitter, failOpen?: boolean,
|
|
91
|
+
/**
|
|
92
|
+
* The real MCP server this proxy process fronts, from `--server-name`
|
|
93
|
+
* (config.ts, threaded since Phase D's `wrapWithProxy` but unconsumed
|
|
94
|
+
* until now). `'unknown'` when unset, matching config.ts's own default —
|
|
95
|
+
* see the server-scoping check below for why an allowlist naming
|
|
96
|
+
* anything else then refuses every call from this process.
|
|
97
|
+
*/
|
|
98
|
+
serverName?: string,
|
|
99
|
+
/**
|
|
100
|
+
* Env-derived default prompt-injection disposition (`config.ts`'s
|
|
101
|
+
* `mcpInjectionAction`), used whenever `policy.getInjectionAction()`
|
|
102
|
+
* reports no control-plane override. Defaults to `'warn'` here too, so
|
|
103
|
+
* every existing construction site/test that doesn't pass this
|
|
104
|
+
* parameter keeps the same steer-not-kill posture the Rust detector this
|
|
105
|
+
* was ported from uses by default.
|
|
106
|
+
*/
|
|
107
|
+
injectionActionDefault?: 'warn' | 'block',
|
|
108
|
+
/**
|
|
109
|
+
* Shared per-process session state (Phase 2) — the SAME instance
|
|
110
|
+
* `McpGovernanceProxy` (proxy.ts) owns and hands to `handleHarnessLine`
|
|
111
|
+
* for post-decision recording, so the sequence this method reads for
|
|
112
|
+
* detection and the sequence `handleHarnessLine` appends to after an
|
|
113
|
+
* `allow` are never two different objects that could drift. Defaults to
|
|
114
|
+
* a fresh instance so every existing construction site/test that
|
|
115
|
+
* predates Phase 2 keeps working unchanged.
|
|
116
|
+
*/
|
|
117
|
+
session?: SessionState,
|
|
118
|
+
/**
|
|
119
|
+
* Env-derived default anomaly mode (`config.ts`'s `mcpAnomalyMode`),
|
|
120
|
+
* used whenever `policy.getAnomalyMode()` reports no control-plane
|
|
121
|
+
* override. Defaults to `'enforce'` — see `config.ts`'s doc comment on
|
|
122
|
+
* why "enforce" here does not mean "block on suspicion": every
|
|
123
|
+
* detector's own Rust-declared disposition ceiling still applies via
|
|
124
|
+
* `resolveEffectiveDisposition`.
|
|
125
|
+
*/
|
|
126
|
+
anomalyModeDefault?: AnomalyMode,
|
|
127
|
+
/**
|
|
128
|
+
* Env-derived default per-detector override map (`config.ts`'s
|
|
129
|
+
* `mcpAnomalyOverrides`). Merged with `policy.getAnomalyOverrides()` per
|
|
130
|
+
* key, control-plane value winning — the same "policy overrides the
|
|
131
|
+
* env-derived default, per field" shape `injectionActionDefault` uses,
|
|
132
|
+
* just applied per-map-entry instead of to one scalar.
|
|
133
|
+
*/
|
|
134
|
+
anomalyOverridesDefault?: Readonly<Record<string, Disposition | 'off'>>,
|
|
135
|
+
/**
|
|
136
|
+
* Phase 3's WASM custom-rule runner, or `undefined` to skip WASM
|
|
137
|
+
* evaluation entirely (every construction site/test that predates Phase
|
|
138
|
+
* 3, and any deployment with no `~/.intutic/wasm/` rules). Owned by
|
|
139
|
+
* `McpGovernanceProxy` (proxy.ts), same sharing pattern as `session`.
|
|
140
|
+
*/
|
|
141
|
+
wasmRunner?: WasmRunner | undefined,
|
|
142
|
+
/**
|
|
143
|
+
* This proxy's workspace id, from `config.ts` — needed for Phase 3's
|
|
144
|
+
* `RequestContext.workspace_id` field. Stored separately from `policy`
|
|
145
|
+
* (which has no getter for it) and from `serverName` (a different
|
|
146
|
+
* identity: the MCP SERVER this process fronts, not the WORKSPACE it
|
|
147
|
+
* belongs to).
|
|
148
|
+
*/
|
|
149
|
+
workspaceId?: string);
|
|
150
|
+
/**
|
|
151
|
+
* Applies the shared reask ladder (Phase 2 anomaly detectors AND Phase 3
|
|
152
|
+
* WASM rules both use this): a session-lifetime attempt counter keyed by
|
|
153
|
+
* `key`, `REASK_MAX_ATTEMPTS` (3) tries before hardening into an
|
|
154
|
+
* unconditional block. Always emits `tool_blocked` — a reask blocks the
|
|
155
|
+
* CURRENT attempt, so existing consumers keyed on `tool_blocked` must see
|
|
156
|
+
* it, exactly like every other new block reason in this package.
|
|
157
|
+
*/
|
|
158
|
+
private applyReaskLadder;
|
|
29
159
|
/**
|
|
30
160
|
* Evaluate a tools/call request and return a governance decision.
|
|
31
161
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interceptor.d.ts","sourceRoot":"","sources":["../src/interceptor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;
|
|
1
|
+
{"version":3,"file":"interceptor.d.ts","sourceRoot":"","sources":["../src/interceptor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAClE,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAC3C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAIrD,MAAM,MAAM,QAAQ,GAChB;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GACnB;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,aAAa,EAAE,OAAO,CAAA;CAAE,CAAA;AAEhE,qBAAa,mBAAmB;IAE5B,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,CAAC,sBAAsB;IACvC;;;;;;;;OAQG;IACH,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IACnC;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAC,uBAAuB;IACxC;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B;;;;;;OAMG;IACH,OAAO,CAAC,QAAQ,CAAC,WAAW;gBA7DX,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,GAAE,OAAc;IACzC;;;;;;OAMG;IACc,UAAU,GAAE,MAAkB;IAC/C;;;;;;;OAOG;IACc,sBAAsB,GAAE,MAAM,GAAG,OAAgB;IAClE;;;;;;;;OAQG;IACc,OAAO,GAAE,YAAiC;IAC3D;;;;;;;OAOG;IACc,kBAAkB,GAAE,WAAuB;IAC5D;;;;;;OAMG;IACc,uBAAuB,GAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK,CAAC,CAAM;IAC5F;;;;;OAKG;IACc,UAAU,GAAE,UAAU,GAAG,SAAqB;IAC/D;;;;;;OAMG;IACc,WAAW,GAAE,MAAkB;IAGlD;;;;;;;OAOG;YACW,gBAAgB;IAmB9B;;;;;;OAMG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;CAiRtE"}
|