@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.
Files changed (123) hide show
  1. package/README.md +28 -0
  2. package/dist/anomaly/detectors.d.ts +129 -0
  3. package/dist/anomaly/detectors.d.ts.map +1 -0
  4. package/dist/anomaly/detectors.js +368 -0
  5. package/dist/anomaly/detectors.js.map +1 -0
  6. package/dist/anomaly/index.d.ts +52 -0
  7. package/dist/anomaly/index.d.ts.map +1 -0
  8. package/dist/anomaly/index.js +71 -0
  9. package/dist/anomaly/index.js.map +1 -0
  10. package/dist/config.d.ts +107 -1
  11. package/dist/config.d.ts.map +1 -1
  12. package/dist/config.js +129 -6
  13. package/dist/config.js.map +1 -1
  14. package/dist/daemon/healthMonitor.d.ts.map +1 -1
  15. package/dist/daemon/healthMonitor.js +45 -46
  16. package/dist/daemon/healthMonitor.js.map +1 -1
  17. package/dist/daemon/index.d.ts +15 -1
  18. package/dist/daemon/index.d.ts.map +1 -1
  19. package/dist/daemon/index.js +78 -9
  20. package/dist/daemon/index.js.map +1 -1
  21. package/dist/daemon/instrumentation.d.ts +20 -0
  22. package/dist/daemon/instrumentation.d.ts.map +1 -0
  23. package/dist/daemon/instrumentation.js +61 -0
  24. package/dist/daemon/instrumentation.js.map +1 -0
  25. package/dist/daemon/policyCache.d.ts +83 -0
  26. package/dist/daemon/policyCache.d.ts.map +1 -1
  27. package/dist/daemon/policyCache.js +280 -11
  28. package/dist/daemon/policyCache.js.map +1 -1
  29. package/dist/daemon/statusReporter.d.ts +12 -0
  30. package/dist/daemon/statusReporter.d.ts.map +1 -0
  31. package/dist/daemon/statusReporter.js +130 -0
  32. package/dist/daemon/statusReporter.js.map +1 -0
  33. package/dist/daemon/telemetryBatcher.d.ts +3 -1
  34. package/dist/daemon/telemetryBatcher.d.ts.map +1 -1
  35. package/dist/daemon/telemetryBatcher.js +56 -13
  36. package/dist/daemon/telemetryBatcher.js.map +1 -1
  37. package/dist/daemonClient.d.ts +1 -1
  38. package/dist/daemonClient.d.ts.map +1 -1
  39. package/dist/daemonClient.js +0 -2
  40. package/dist/daemonClient.js.map +1 -1
  41. package/dist/dlp.d.ts +19 -0
  42. package/dist/dlp.d.ts.map +1 -1
  43. package/dist/dlp.js +95 -18
  44. package/dist/dlp.js.map +1 -1
  45. package/dist/emitter.d.ts +40 -2
  46. package/dist/emitter.d.ts.map +1 -1
  47. package/dist/emitter.js +27 -5
  48. package/dist/emitter.js.map +1 -1
  49. package/dist/index.js +13 -2
  50. package/dist/index.js.map +1 -1
  51. package/dist/injection.d.ts +46 -0
  52. package/dist/injection.d.ts.map +1 -0
  53. package/dist/injection.js +147 -0
  54. package/dist/injection.js.map +1 -0
  55. package/dist/interceptor.d.ts +131 -1
  56. package/dist/interceptor.d.ts.map +1 -1
  57. package/dist/interceptor.js +301 -5
  58. package/dist/interceptor.js.map +1 -1
  59. package/dist/policy.d.ts +110 -2
  60. package/dist/policy.d.ts.map +1 -1
  61. package/dist/policy.js +206 -5
  62. package/dist/policy.js.map +1 -1
  63. package/dist/proxy.d.ts +205 -0
  64. package/dist/proxy.d.ts.map +1 -1
  65. package/dist/proxy.js +572 -65
  66. package/dist/proxy.js.map +1 -1
  67. package/dist/remoteBridge.d.ts +51 -0
  68. package/dist/remoteBridge.d.ts.map +1 -0
  69. package/dist/remoteBridge.js +182 -0
  70. package/dist/remoteBridge.js.map +1 -0
  71. package/dist/session.d.ts +158 -0
  72. package/dist/session.d.ts.map +1 -0
  73. package/dist/session.js +206 -0
  74. package/dist/session.js.map +1 -0
  75. package/dist/sessionScope.d.ts +51 -0
  76. package/dist/sessionScope.d.ts.map +1 -0
  77. package/dist/sessionScope.js +94 -0
  78. package/dist/sessionScope.js.map +1 -0
  79. package/dist/sessionStore.d.ts +69 -0
  80. package/dist/sessionStore.d.ts.map +1 -0
  81. package/dist/sessionStore.js +143 -0
  82. package/dist/sessionStore.js.map +1 -0
  83. package/dist/tofu.d.ts +112 -0
  84. package/dist/tofu.d.ts.map +1 -0
  85. package/dist/tofu.js +180 -0
  86. package/dist/tofu.js.map +1 -0
  87. package/dist/toolPoison.d.ts +32 -0
  88. package/dist/toolPoison.d.ts.map +1 -0
  89. package/dist/toolPoison.js +81 -0
  90. package/dist/toolPoison.js.map +1 -0
  91. package/dist/valkeyErrors.d.ts +17 -0
  92. package/dist/valkeyErrors.d.ts.map +1 -0
  93. package/dist/valkeyErrors.js +24 -0
  94. package/dist/valkeyErrors.js.map +1 -0
  95. package/dist/wasm/context.d.ts +57 -0
  96. package/dist/wasm/context.d.ts.map +1 -0
  97. package/dist/wasm/context.js +59 -0
  98. package/dist/wasm/context.js.map +1 -0
  99. package/dist/wasm/hostImports.d.ts +43 -0
  100. package/dist/wasm/hostImports.d.ts.map +1 -0
  101. package/dist/wasm/hostImports.js +158 -0
  102. package/dist/wasm/hostImports.js.map +1 -0
  103. package/dist/wasm/loader.d.ts +95 -0
  104. package/dist/wasm/loader.d.ts.map +1 -0
  105. package/dist/wasm/loader.js +198 -0
  106. package/dist/wasm/loader.js.map +1 -0
  107. package/dist/wasm/referencedFiles.d.ts +115 -0
  108. package/dist/wasm/referencedFiles.d.ts.map +1 -0
  109. package/dist/wasm/referencedFiles.js +366 -0
  110. package/dist/wasm/referencedFiles.js.map +1 -0
  111. package/dist/wasm/runner.d.ts +91 -0
  112. package/dist/wasm/runner.d.ts.map +1 -0
  113. package/dist/wasm/runner.js +308 -0
  114. package/dist/wasm/runner.js.map +1 -0
  115. package/dist/wasm/watch.d.ts +5 -0
  116. package/dist/wasm/watch.d.ts.map +1 -0
  117. package/dist/wasm/watch.js +54 -0
  118. package/dist/wasm/watch.js.map +1 -0
  119. package/dist/wasm/worker.d.ts +39 -0
  120. package/dist/wasm/worker.d.ts.map +1 -0
  121. package/dist/wasm/worker.js +245 -0
  122. package/dist/wasm/worker.js.map +1 -0
  123. 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"}
@@ -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
- constructor(policy: PolicyClient, emitter: GovernanceEmitter, failOpen?: boolean);
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;AAIH,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;gBAFR,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,GAAE,OAAc;IAG3C;;;;;;OAMG;IACG,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC;CAgEtE"}
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"}