@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 @@
1
+ {"version":3,"file":"hostImports.d.ts","sourceRoot":"","sources":["../../src/wasm/hostImports.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EACL,eAAe,EAOhB,MAAM,sBAAsB,CAAA;AAI7B,mIAAmI;AACnI,eAAO,MAAM,WAAW,KAAU,CAAA;AAElC,uEAAuE;AACvE,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,KAAK,EAAE,eAAe,CAAA;IACtB,6DAA6D;IAC7D,kBAAkB,EAAE,MAAM,CAAA;CAC3B;AAED,wBAAgB,kBAAkB,CAAC,KAAK,GAAE,eAAyC,GAAG,eAAe,CAEpG;AAoBD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,WAAW,CAAC,MAAM,GAAG,SAAS,EAC/C,KAAK,GAAE,eAAsC,GAC5C,WAAW,CAAC,aAAa,CA0G3B"}
@@ -0,0 +1,158 @@
1
+ /**
2
+ * wasm/hostImports.ts — The 4 frozen host imports (`WASM_HOST_IMPORTS` from
3
+ * `@intutic/shared-types`), implemented for this proxy's `worker_threads`
4
+ * sandbox.
5
+ *
6
+ * Built from `packages/proxy/src/wasm/host.rs` (the Rust behavior each
7
+ * import must match) and from `packages/wasm-sdk/__tests__/generatedRules.test.ts`'s
8
+ * `HOST_IMPL` (the reference Node-side implementation the task named as the
9
+ * base to build from). `log_info`/`abort`/`trace` mirror `host.rs`'s
10
+ * tracing-log behavior, routed through this package's own `createStderrLogger`
11
+ * (never `console.log`/stdout — the same stdio-isolation rule every other
12
+ * module in this package follows). `read_referenced_file` resolves against
13
+ * the per-evaluation table the runner pre-reads through `referencedFiles.ts`
14
+ * (TD-441) — the port of `host.rs`'s `read_referenced_file_impl`, code for
15
+ * code: the read budget is charged before argument validation, a refusal is
16
+ * a value the rule can act on, and nothing here traps. With no table (no
17
+ * `INTUTIC_WASM_MANIFEST_ROOT`, or a rule that does not import the function)
18
+ * every call gets `ERR_REFUSED`, which is what the Rust proxy answers with no
19
+ * root configured.
20
+ *
21
+ * @module
22
+ */
23
+ import { createStderrLogger as createLogger } from '../stderrLog.js';
24
+ import { ReferencedFiles, ERR_BAD_ARGS, ERR_BUDGET, ERR_BUFFER_TOO_SMALL, ERR_REFUSED as REFUSED, MAX_GUEST_PATH_BYTES, MAX_READS_PER_EVALUATION, } from './referencedFiles.js';
25
+ const log = createLogger('mcp-proxy-wasm-host');
26
+ /** `referenced_files.rs`'s `ERR_REFUSED` (-2), kept exported here for the callers that imported it before the resolver existed. */
27
+ export const ERR_REFUSED = REFUSED;
28
+ export function newHostImportState(files = ReferencedFiles.empty()) {
29
+ return { files, fileReadsRemaining: MAX_READS_PER_EVALUATION };
30
+ }
31
+ /**
32
+ * Decode a UTF-8 string out of a WASM instance's linear memory. Returns `''`
33
+ * on any bounds/decode failure — mirrors `host.rs`'s own posture of logging
34
+ * a warning and returning without acting, never trapping the guest over a
35
+ * malformed log call.
36
+ */
37
+ function readUtf8(memory, ptr, len) {
38
+ if (ptr < 0 || len < 0)
39
+ return null;
40
+ const bytes = new Uint8Array(memory.buffer);
41
+ const end = ptr + len;
42
+ if (end > bytes.length)
43
+ return null;
44
+ try {
45
+ return new TextDecoder('utf-8', { fatal: true }).decode(bytes.subarray(ptr, end));
46
+ }
47
+ catch {
48
+ return null;
49
+ }
50
+ }
51
+ /**
52
+ * Builds the `env.*` import object for one WASM instance. `getMemory` is a
53
+ * thunk rather than a captured value because the memory export does not
54
+ * exist until AFTER `WebAssembly.instantiate` returns, while the import
55
+ * object has to be supplied BEFORE it — the same ordering `host.rs` avoids
56
+ * entirely by reading `caller.get_export("memory")` inside each call; this
57
+ * is the Node-side equivalent of that lazy lookup.
58
+ */
59
+ export function createHostImports(getMemory, state = newHostImportState()) {
60
+ return {
61
+ log_info: (ptr, len) => {
62
+ const memory = getMemory();
63
+ if (!memory) {
64
+ log.warn({ action: 'wasm_host_no_memory', call: 'log_info' }, 'WASM rule called log_info with no memory export');
65
+ return;
66
+ }
67
+ const msg = readUtf8(memory, ptr, len);
68
+ if (msg === null) {
69
+ log.warn({ action: 'wasm_log_info_bad_args' }, 'WASM rule log_info payload out of bounds or not valid UTF-8');
70
+ return;
71
+ }
72
+ log.info({ action: 'wasm_rule_log' }, msg);
73
+ },
74
+ // Mirrors host.rs's `abort` import: log only, never throw/trap. A guest
75
+ // unhandled-exception calling `abort` must not crash the evaluation —
76
+ // the caller (worker.ts) still wraps the whole `evaluate` call so any
77
+ // resulting trap fails open, but this import itself is inert.
78
+ abort: (msgPtr, filePtr, line, col) => {
79
+ log.warn({ action: 'wasm_abort', msgPtr, filePtr, line, col }, 'WASM rule called abort (AssemblyScript unhandled exception)');
80
+ },
81
+ // Best-effort decode of AssemblyScript's `String#trace` layout — a
82
+ // length-prefixed UTF-16LE string with the 4-byte length immediately
83
+ // before `ptr`. Falls back to logging the raw pointer/length, same as
84
+ // host.rs's own fallback branch, rather than treating a decode failure
85
+ // as fatal.
86
+ trace: (ptr, n) => {
87
+ const memory = getMemory();
88
+ if (!memory)
89
+ return;
90
+ if (ptr >= 4) {
91
+ const bytes = new Uint8Array(memory.buffer);
92
+ if (ptr <= bytes.length) {
93
+ const lenBytes = bytes.subarray(ptr - 4, ptr);
94
+ const len = new DataView(lenBytes.buffer, lenBytes.byteOffset, 4).getUint32(0, true);
95
+ const end = ptr + len;
96
+ if (end <= bytes.length) {
97
+ try {
98
+ const utf16 = new Uint16Array(bytes.buffer, bytes.byteOffset + ptr, len / 2);
99
+ const msg = String.fromCharCode(...utf16);
100
+ log.info({ action: 'wasm_trace', n }, msg);
101
+ return;
102
+ }
103
+ catch {
104
+ // fall through to the raw fallback below
105
+ }
106
+ }
107
+ }
108
+ }
109
+ log.info({ action: 'wasm_trace_raw', ptr, n }, 'WASM trace (undecoded)');
110
+ },
111
+ // Ported from host.rs's `read_referenced_file_impl`. Returns a length or
112
+ // one of the negative codes; never throws — a host trap would unwind the
113
+ // guest, fail the whole evaluation and land in the runner's fail-open
114
+ // arm, so one malformed call would silently switch off every OTHER
115
+ // check the rule performs.
116
+ read_referenced_file: (pathPtr, pathLen, outPtr, outCap) => {
117
+ // Charged before anything else, including argument validation, so a
118
+ // guest cannot spin on cheap malformed calls any more than on
119
+ // expensive good ones.
120
+ if (state.fileReadsRemaining <= 0) {
121
+ log.warn({ action: 'wasm_file_read_budget_exhausted', budget: MAX_READS_PER_EVALUATION }, 'WASM rule exhausted its referenced-file reads in one evaluation');
122
+ return ERR_BUDGET;
123
+ }
124
+ state.fileReadsRemaining -= 1;
125
+ const memory = getMemory();
126
+ if (!memory) {
127
+ log.warn({ action: 'wasm_host_no_memory', call: 'read_referenced_file' }, 'WASM rule called read_referenced_file with no memory export');
128
+ return ERR_BAD_ARGS;
129
+ }
130
+ if (pathPtr < 0 || pathLen <= 0 || pathLen > MAX_GUEST_PATH_BYTES || outCap < 0)
131
+ return ERR_BAD_ARGS;
132
+ const requested = readUtf8(memory, pathPtr, pathLen);
133
+ if (requested === null)
134
+ return ERR_BAD_ARGS;
135
+ const hit = state.files.lookup(requested);
136
+ if (!hit.ok) {
137
+ // The reason is operator-facing only. The guest gets the code and is
138
+ // told nothing it did not already supply.
139
+ log.debug({ action: 'wasm_referenced_file_refused', path: requested, code: hit.code, reason: state.files.refusalReason(requested) }, "refused a WASM rule's referenced-file read");
140
+ return hit.code;
141
+ }
142
+ const len = hit.bytes.length; // capped at MAX_REFERENCED_FILE_BYTES on the way in
143
+ if (outCap === 0)
144
+ return len;
145
+ if (outCap < len)
146
+ return ERR_BUFFER_TOO_SMALL;
147
+ const view = new Uint8Array(memory.buffer);
148
+ if (outPtr < 0 || outPtr + len > view.length) {
149
+ // Out of bounds: a refusal, not a trap, same as host.rs.
150
+ log.warn({ action: 'wasm_referenced_file_out_ptr_oob', outPtr, len }, 'WASM rule passed an out-of-bounds output buffer');
151
+ return ERR_BAD_ARGS;
152
+ }
153
+ view.set(hit.bytes, outPtr);
154
+ return len;
155
+ },
156
+ };
157
+ }
158
+ //# sourceMappingURL=hostImports.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hostImports.js","sourceRoot":"","sources":["../../src/wasm/hostImports.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,95 @@
1
+ /**
2
+ * wasm/loader.ts — `~/.intutic/wasm/` directory loader.
3
+ *
4
+ * Direct TypeScript port of `packages/proxy/src/wasm/local_loader.rs`'s
5
+ * directory-resolution order, `NN_name.wasm` priority parsing, the 10MB
6
+ * per-file size cap, and mtime+size-based change detection — confirmed by
7
+ * reading that file, not guessed. Compilation and import validation
8
+ * themselves happen in the worker (`worker.ts`); this module owns file
9
+ * discovery, diffing, and the fail-open-per-file bookkeeping (a corrupt or
10
+ * oversized file is skipped and logged; if a previous good rule was loaded
11
+ * from that same file, it is retained rather than dropped).
12
+ *
13
+ * @module
14
+ */
15
+ /** Ported from `local_loader.rs`'s `MAX_RULE_FILE_BYTES`. */
16
+ export declare const MAX_RULE_FILE_BYTES: number;
17
+ /** Ported from `local_loader.rs`'s `DEFAULT_PRIORITY`. */
18
+ export declare const DEFAULT_PRIORITY = 100;
19
+ /**
20
+ * Resolve the local rules directory: `INTUTIC_WASM_DIR` env var, then the
21
+ * caller-supplied config override, then `~/.intutic/wasm` — same precedence
22
+ * order as `local_loader.rs`'s `resolve_local_dir` (confirmed by its own
23
+ * `resolve_dir_precedence` test: env wins over config, config wins over the
24
+ * home default).
25
+ */
26
+ export declare function resolveWasmDir(configOverride?: string): string;
27
+ /**
28
+ * Parse `NN_name.wasm` into `{ priority, name }`. Ported from
29
+ * `local_loader.rs`'s `parse_priority`, including its edge cases:
30
+ * `10_block-prod-db.wasm` -> `{10, "block-prod-db"}`; `my-rule.wasm` ->
31
+ * `{100, "my-rule"}`; a non-numeric or empty prefix (`block_prod.wasm`,
32
+ * `_hidden.wasm`) also defaults to priority 100 with the whole stem as the name.
33
+ */
34
+ export declare function parsePriority(fileName: string): {
35
+ priority: number;
36
+ name: string;
37
+ };
38
+ export interface FileSignature {
39
+ mtimeMs: number;
40
+ size: number;
41
+ }
42
+ /**
43
+ * `(mtime, size)` signature of every `*.wasm` file in `dir`, keyed by full
44
+ * path. A missing directory returns an empty map (first-run UX, ported from
45
+ * `scan_signatures`'s own `NotFound` handling) — any other I/O error
46
+ * propagates so the caller can retain the previously loaded rules instead of
47
+ * mistaking a transient EACCES/EIO for "every rule was deleted."
48
+ */
49
+ export declare function scanSignatures(dir: string): Promise<Map<string, FileSignature>>;
50
+ export interface LoadedRuleMeta {
51
+ /** `local:<file name>` — same convention `local_loader.rs` uses. */
52
+ ruleId: string;
53
+ fileName: string;
54
+ name: string;
55
+ priority: number;
56
+ readsReferencedFiles: boolean;
57
+ /** Cached raw bytes, so a worker respawn (wasm/runner.ts) can resend every
58
+ * currently-loaded rule without re-reading the directory from disk. */
59
+ bytes: Uint8Array;
60
+ }
61
+ export type CompileOutcome = {
62
+ ok: true;
63
+ readsReferencedFiles: boolean;
64
+ } | {
65
+ ok: false;
66
+ error: string;
67
+ unsupportedImports?: string[];
68
+ };
69
+ /** What `WasmLoader` needs from the worker to load/unload a rule — implemented by `WasmRunner`. */
70
+ export interface CompileBridge {
71
+ compile(ruleId: string, bytes: Uint8Array): Promise<CompileOutcome>;
72
+ remove(ruleId: string): void;
73
+ }
74
+ /**
75
+ * Tracks the local rules directory's current state: which files exist, their
76
+ * change signatures, and the rule metadata successfully compiled from each.
77
+ * Fail-open per file — see this module's doc comment.
78
+ */
79
+ export declare class WasmLoader {
80
+ private readonly dir;
81
+ private signatures;
82
+ private loaded;
83
+ constructor(dir: string);
84
+ getDir(): string;
85
+ /** Currently loaded rules, priority order (lower runs first), ties in file-scan order. */
86
+ getRules(): LoadedRuleMeta[];
87
+ /**
88
+ * Rescans the directory and (re)compiles anything changed via `bridge`.
89
+ * `force` reloads every current file unconditionally (used by the
90
+ * policy-tick hook after a worker respawn, where the worker's own module
91
+ * cache was lost and must be rebuilt even though nothing on disk moved).
92
+ */
93
+ rescan(bridge: CompileBridge, force?: boolean): Promise<void>;
94
+ }
95
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/wasm/loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AASH,6DAA6D;AAC7D,eAAO,MAAM,mBAAmB,QAAmB,CAAA;AAEnD,0DAA0D;AAC1D,eAAO,MAAM,gBAAgB,MAAM,CAAA;AAEnC;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAK9D;AAOD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAWlF;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,CAsBrF;AAWD,MAAM,WAAW,cAAc;IAC7B,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,oBAAoB,EAAE,OAAO,CAAA;IAC7B;4EACwE;IACxE,KAAK,EAAE,UAAU,CAAA;CAClB;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,oBAAoB,EAAE,OAAO,CAAA;CAAE,GAC3C;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAA;CAAE,CAAA;AAE/D,mGAAmG;AACnG,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,CAAA;IACnE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B;AAED;;;;GAIG;AACH,qBAAa,UAAU;IAIT,OAAO,CAAC,QAAQ,CAAC,GAAG;IAHhC,OAAO,CAAC,UAAU,CAAmC;IACrD,OAAO,CAAC,MAAM,CAAoC;gBAErB,GAAG,EAAE,MAAM;IAExC,MAAM,IAAI,MAAM;IAIhB,0FAA0F;IAC1F,QAAQ,IAAI,cAAc,EAAE;IAI5B;;;;;OAKG;IACG,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,UAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;CA+ElE"}
@@ -0,0 +1,198 @@
1
+ /**
2
+ * wasm/loader.ts — `~/.intutic/wasm/` directory loader.
3
+ *
4
+ * Direct TypeScript port of `packages/proxy/src/wasm/local_loader.rs`'s
5
+ * directory-resolution order, `NN_name.wasm` priority parsing, the 10MB
6
+ * per-file size cap, and mtime+size-based change detection — confirmed by
7
+ * reading that file, not guessed. Compilation and import validation
8
+ * themselves happen in the worker (`worker.ts`); this module owns file
9
+ * discovery, diffing, and the fail-open-per-file bookkeeping (a corrupt or
10
+ * oversized file is skipped and logged; if a previous good rule was loaded
11
+ * from that same file, it is retained rather than dropped).
12
+ *
13
+ * @module
14
+ */
15
+ import * as node_fs from 'node:fs/promises';
16
+ import * as node_os from 'node:os';
17
+ import * as node_path from 'node:path';
18
+ import { createStderrLogger as createLogger } from '../stderrLog.js';
19
+ const log = createLogger('mcp-proxy-wasm-loader');
20
+ /** Ported from `local_loader.rs`'s `MAX_RULE_FILE_BYTES`. */
21
+ export const MAX_RULE_FILE_BYTES = 10 * 1024 * 1024;
22
+ /** Ported from `local_loader.rs`'s `DEFAULT_PRIORITY`. */
23
+ export const DEFAULT_PRIORITY = 100;
24
+ /**
25
+ * Resolve the local rules directory: `INTUTIC_WASM_DIR` env var, then the
26
+ * caller-supplied config override, then `~/.intutic/wasm` — same precedence
27
+ * order as `local_loader.rs`'s `resolve_local_dir` (confirmed by its own
28
+ * `resolve_dir_precedence` test: env wins over config, config wins over the
29
+ * home default).
30
+ */
31
+ export function resolveWasmDir(configOverride) {
32
+ const envDir = process.env['INTUTIC_WASM_DIR'];
33
+ if (envDir)
34
+ return expandHome(envDir);
35
+ if (configOverride)
36
+ return expandHome(configOverride);
37
+ return node_path.join(node_os.homedir(), '.intutic', 'wasm');
38
+ }
39
+ function expandHome(raw) {
40
+ if (raw.startsWith('~/'))
41
+ return node_path.join(node_os.homedir(), raw.slice(2));
42
+ return raw;
43
+ }
44
+ /**
45
+ * Parse `NN_name.wasm` into `{ priority, name }`. Ported from
46
+ * `local_loader.rs`'s `parse_priority`, including its edge cases:
47
+ * `10_block-prod-db.wasm` -> `{10, "block-prod-db"}`; `my-rule.wasm` ->
48
+ * `{100, "my-rule"}`; a non-numeric or empty prefix (`block_prod.wasm`,
49
+ * `_hidden.wasm`) also defaults to priority 100 with the whole stem as the name.
50
+ */
51
+ export function parsePriority(fileName) {
52
+ const stem = fileName.endsWith('.wasm') ? fileName.slice(0, -'.wasm'.length) : fileName;
53
+ const idx = stem.indexOf('_');
54
+ if (idx > 0 && idx < stem.length - 1) {
55
+ const prefix = stem.slice(0, idx);
56
+ const rest = stem.slice(idx + 1);
57
+ if (/^\d+$/.test(prefix)) {
58
+ return { priority: Number.parseInt(prefix, 10), name: rest };
59
+ }
60
+ }
61
+ return { priority: DEFAULT_PRIORITY, name: stem };
62
+ }
63
+ /**
64
+ * `(mtime, size)` signature of every `*.wasm` file in `dir`, keyed by full
65
+ * path. A missing directory returns an empty map (first-run UX, ported from
66
+ * `scan_signatures`'s own `NotFound` handling) — any other I/O error
67
+ * propagates so the caller can retain the previously loaded rules instead of
68
+ * mistaking a transient EACCES/EIO for "every rule was deleted."
69
+ */
70
+ export async function scanSignatures(dir) {
71
+ const signatures = new Map();
72
+ let entries;
73
+ try {
74
+ entries = await node_fs.readdir(dir, { withFileTypes: true });
75
+ }
76
+ catch (err) {
77
+ if (err.code === 'ENOENT')
78
+ return signatures;
79
+ throw err;
80
+ }
81
+ for (const entry of entries) {
82
+ if (!entry.isFile() || !entry.name.endsWith('.wasm'))
83
+ continue;
84
+ const full = node_path.join(dir, entry.name);
85
+ try {
86
+ const stat = await node_fs.stat(full);
87
+ signatures.set(full, { mtimeMs: stat.mtimeMs, size: stat.size });
88
+ }
89
+ catch {
90
+ // Vanished between readdir and stat (race with a concurrent
91
+ // write/delete) — skip it this pass; the next rescan sees whatever
92
+ // state settles.
93
+ }
94
+ }
95
+ return signatures;
96
+ }
97
+ function signaturesEqual(a, b) {
98
+ if (a.size !== b.size)
99
+ return false;
100
+ for (const [key, sig] of a) {
101
+ const other = b.get(key);
102
+ if (!other || other.mtimeMs !== sig.mtimeMs || other.size !== sig.size)
103
+ return false;
104
+ }
105
+ return true;
106
+ }
107
+ /**
108
+ * Tracks the local rules directory's current state: which files exist, their
109
+ * change signatures, and the rule metadata successfully compiled from each.
110
+ * Fail-open per file — see this module's doc comment.
111
+ */
112
+ export class WasmLoader {
113
+ dir;
114
+ signatures = new Map();
115
+ loaded = new Map(); // keyed by file path
116
+ constructor(dir) {
117
+ this.dir = dir;
118
+ }
119
+ getDir() {
120
+ return this.dir;
121
+ }
122
+ /** Currently loaded rules, priority order (lower runs first), ties in file-scan order. */
123
+ getRules() {
124
+ return [...this.loaded.values()].sort((a, b) => a.priority - b.priority);
125
+ }
126
+ /**
127
+ * Rescans the directory and (re)compiles anything changed via `bridge`.
128
+ * `force` reloads every current file unconditionally (used by the
129
+ * policy-tick hook after a worker respawn, where the worker's own module
130
+ * cache was lost and must be rebuilt even though nothing on disk moved).
131
+ */
132
+ async rescan(bridge, force = false) {
133
+ let newSignatures;
134
+ try {
135
+ newSignatures = await scanSignatures(this.dir);
136
+ }
137
+ catch (err) {
138
+ log.warn({ action: 'wasm_scan_error', dir: this.dir, err: err.message }, 'local WASM rule directory scan failed — keeping previously loaded rules');
139
+ return;
140
+ }
141
+ if (!force && signaturesEqual(newSignatures, this.signatures))
142
+ return;
143
+ // Removed files.
144
+ for (const filePath of [...this.loaded.keys()]) {
145
+ if (!newSignatures.has(filePath)) {
146
+ const meta = this.loaded.get(filePath);
147
+ if (meta)
148
+ bridge.remove(meta.ruleId);
149
+ this.loaded.delete(filePath);
150
+ }
151
+ }
152
+ // New or changed files.
153
+ for (const [filePath, sig] of newSignatures) {
154
+ const previousSig = this.signatures.get(filePath);
155
+ const changed = force || !previousSig || previousSig.mtimeMs !== sig.mtimeMs || previousSig.size !== sig.size;
156
+ if (!changed)
157
+ continue;
158
+ const fileName = node_path.basename(filePath);
159
+ const ruleId = `local:${fileName}`;
160
+ if (sig.size > MAX_RULE_FILE_BYTES) {
161
+ log.warn({ action: 'wasm_rule_too_large', file: filePath, sizeBytes: sig.size, capBytes: MAX_RULE_FILE_BYTES }, 'local WASM rule exceeds size cap — skipped');
162
+ continue; // fail-open-per-file: whatever was in `this.loaded` for this path (if anything) stays
163
+ }
164
+ let bytes;
165
+ try {
166
+ bytes = await node_fs.readFile(filePath);
167
+ }
168
+ catch (err) {
169
+ log.warn({ action: 'wasm_rule_read_error', file: filePath, err: err.message }, 'local WASM rule failed to read — retaining previous version if any');
170
+ continue;
171
+ }
172
+ const result = await bridge.compile(ruleId, bytes);
173
+ if (result.ok) {
174
+ const { priority, name } = parsePriority(fileName);
175
+ this.loaded.set(filePath, {
176
+ ruleId,
177
+ fileName,
178
+ name,
179
+ priority,
180
+ readsReferencedFiles: result.readsReferencedFiles,
181
+ bytes,
182
+ });
183
+ }
184
+ else {
185
+ log.warn({
186
+ action: 'wasm_rule_load_error',
187
+ file: filePath,
188
+ error: result.error,
189
+ unsupportedImports: result.unsupportedImports,
190
+ }, 'local WASM rule failed to load — retaining previous version if any');
191
+ // Fail-open-per-file: do NOT touch `this.loaded.get(filePath)` — a
192
+ // previously good module (if any) for this exact path stays active.
193
+ }
194
+ }
195
+ this.signatures = newSignatures;
196
+ }
197
+ }
198
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/wasm/loader.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * wasm/referencedFiles.ts — The MCP-side resolver behind the
3
+ * `read_referenced_file` host import (TD-441). A 1:1 port of
4
+ * `packages/proxy/src/wasm/referenced_files.rs`: same constants, same error
5
+ * codes, same candidate-token rules, same six guards, same realpath
6
+ * confinement. Where the two differ it is stated at the site.
7
+ *
8
+ * ## The design, in one paragraph
9
+ *
10
+ * A rule never names a file. The proxy derives the candidate paths from the
11
+ * CURRENT tool call's arguments (structured path keys and the shell words of
12
+ * a command), keeps the manifest-shaped ones, resolves each under the
13
+ * operator-configured root with every symlink followed, and reads the ones
14
+ * that survive — all BEFORE the sandbox exists. The guest then passes a path
15
+ * as a lookup key into that fixed table. There is no code path from a guest
16
+ * string to `open(2)`.
17
+ *
18
+ * ## Guards (numbered as in the Rust module)
19
+ *
20
+ * 1. Only paths the tool call literally named (no glob expansion).
21
+ * 2. Only manifest extensions.
22
+ * 3. No `..` component; no platform prefix.
23
+ * 4. Realpath must stay under the realpath'd root (symlink escape covered).
24
+ * 5. Regular files only.
25
+ * 6. Size-capped, checked on the stat AND on the read.
26
+ *
27
+ * ## Divergence from the Rust module
28
+ *
29
+ * Reads are `fs/promises` (async) rather than a blocking pool — the runner
30
+ * awaits them once per evaluation, before any rule runs, so the per-rule
31
+ * deadline still covers only guest execution. The residual TOCTOU between
32
+ * `realpath` and `open` is the same one `referenced_files.rs` documents;
33
+ * closing it needs `openat2(RESOLVE_BENEATH)`, which Node does not expose.
34
+ *
35
+ * @module
36
+ */
37
+ /** Largest file the host will hand to a rule. `referenced_files.rs`: 256 KiB. */
38
+ export declare const MAX_REFERENCED_FILE_BYTES: number;
39
+ /** Candidate paths considered per evaluation. */
40
+ export declare const MAX_REFERENCED_FILES = 8;
41
+ /** Longest path a guest may ask for. */
42
+ export declare const MAX_GUEST_PATH_BYTES = 4096;
43
+ export declare const ERR_BAD_ARGS = -1;
44
+ export declare const ERR_REFUSED = -2;
45
+ export declare const ERR_NOT_FOUND = -3;
46
+ export declare const ERR_TOO_LARGE = -4;
47
+ export declare const ERR_BUFFER_TOO_SMALL = -5;
48
+ export declare const ERR_BUDGET = -6;
49
+ /** Host calls one evaluation may make, charged before argument validation. */
50
+ export declare const MAX_READS_PER_EVALUATION = 64;
51
+ /** The operator-configured root. Unset means the capability is off. */
52
+ export declare const MANIFEST_ROOT_ENV = "INTUTIC_WASM_MANIFEST_ROOT";
53
+ /** One candidate's fate. `content` carries bytes; everything else a code. */
54
+ export type Outcome = {
55
+ kind: 'content';
56
+ bytes: Uint8Array;
57
+ } | {
58
+ kind: 'refused';
59
+ why: string;
60
+ } | {
61
+ kind: 'not_found';
62
+ } | {
63
+ kind: 'too_large';
64
+ size: number;
65
+ };
66
+ /** The structured-clone-safe wire form the runner posts to the worker. */
67
+ export type ReferencedFilesTable = Array<[string, Outcome]>;
68
+ export interface ToolCallLike {
69
+ name: string;
70
+ arguments: unknown;
71
+ }
72
+ /**
73
+ * The pre-read table one evaluation sees. Immutable after construction; the
74
+ * worker rebuilds it from `toTable()` on its side of `postMessage`.
75
+ */
76
+ export declare class ReferencedFiles {
77
+ private readonly entries;
78
+ private constructor();
79
+ static empty(): ReferencedFiles;
80
+ static fromTable(table: ReferencedFilesTable | undefined): ReferencedFiles;
81
+ toTable(): ReferencedFilesTable;
82
+ isEmpty(): boolean;
83
+ readableCount(): number;
84
+ /** The bytes for `requested`, or the error code the guest gets. */
85
+ lookup(requested: string): {
86
+ ok: true;
87
+ bytes: Uint8Array;
88
+ } | {
89
+ ok: false;
90
+ code: number;
91
+ };
92
+ /** Operator-facing reason. Never handed to the guest. */
93
+ refusalReason(requested: string): string;
94
+ /** Debug rendering: states, never contents. */
95
+ describe(): string;
96
+ }
97
+ /** The configured root, `~/` expanded. `undefined` keeps the capability off. */
98
+ export declare function resolveRoot(env?: NodeJS.ProcessEnv): string | undefined;
99
+ /**
100
+ * Guard 1 and 2: every manifest-shaped path the tool calls literally name,
101
+ * deduped, capped at `MAX_REFERENCED_FILES`, in first-seen order.
102
+ */
103
+ export declare function candidateTokens(toolCalls: readonly ToolCallLike[]): string[];
104
+ /**
105
+ * Split a command into shell words. Quotes group; whitespace and the
106
+ * metacharacters that end a word separate. Deliberately does NOT expand
107
+ * globs, variables or command substitution — an unexpanded `*.yaml` simply
108
+ * fails to resolve and the guest is told so.
109
+ */
110
+ export declare function shellTokens(command: string): string[];
111
+ /** Resolve and read every candidate under `root`. Async, so the runner awaits it once per evaluation. */
112
+ export declare function readTokens(tokens: readonly string[], root: string): Promise<ReferencedFiles>;
113
+ /** Convenience for callers with tool calls in hand. */
114
+ export declare function prefetch(toolCalls: readonly ToolCallLike[], root: string): Promise<ReferencedFiles>;
115
+ //# sourceMappingURL=referencedFiles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"referencedFiles.d.ts","sourceRoot":"","sources":["../../src/wasm/referencedFiles.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAUH,iFAAiF;AACjF,eAAO,MAAM,yBAAyB,QAAa,CAAA;AACnD,iDAAiD;AACjD,eAAO,MAAM,oBAAoB,IAAI,CAAA;AACrC,wCAAwC;AACxC,eAAO,MAAM,oBAAoB,OAAO,CAAA;AAMxC,eAAO,MAAM,YAAY,KAAK,CAAA;AAC9B,eAAO,MAAM,WAAW,KAAK,CAAA;AAC7B,eAAO,MAAM,aAAa,KAAK,CAAA;AAC/B,eAAO,MAAM,aAAa,KAAK,CAAA;AAC/B,eAAO,MAAM,oBAAoB,KAAK,CAAA;AACtC,eAAO,MAAM,UAAU,KAAK,CAAA;AAE5B,8EAA8E;AAC9E,eAAO,MAAM,wBAAwB,KAAK,CAAA;AAE1C,uEAAuE;AACvE,eAAO,MAAM,iBAAiB,+BAA+B,CAAA;AAO7D,6EAA6E;AAC7E,MAAM,MAAM,OAAO,GACf;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,WAAW,CAAA;CAAE,GACrB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAEvC,0EAA0E;AAC1E,MAAM,MAAM,oBAAoB,GAAG,KAAK,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;AAE3D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,OAAO,CAAA;CACnB;AAED;;;GAGG;AACH,qBAAa,eAAe;IACN,OAAO,CAAC,QAAQ,CAAC,OAAO;IAA5C,OAAO;IAEP,MAAM,CAAC,KAAK,IAAI,eAAe;IAI/B,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,oBAAoB,GAAG,SAAS,GAAG,eAAe;IAI1E,OAAO,IAAI,oBAAoB;IAI/B,OAAO,IAAI,OAAO;IAIlB,aAAa,IAAI,MAAM;IAIvB,mEAAmE;IACnE,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG;QAAE,EAAE,EAAE,IAAI,CAAC;QAAC,KAAK,EAAE,UAAU,CAAA;KAAE,GAAG;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;IAgBxF,yDAAyD;IACzD,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAgBxC,+CAA+C;IAC/C,QAAQ,IAAI,MAAM;CAgBnB;AAED,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CAKpF;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,SAAS,YAAY,EAAE,GAAG,MAAM,EAAE,CAoB5E;AAsBD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CA0BrD;AAED,yGAAyG;AACzG,wBAAsB,UAAU,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CA2ClG;AAeD,uDAAuD;AACvD,wBAAgB,QAAQ,CAAC,SAAS,EAAE,SAAS,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAEnG"}