@intutic/mcp-governance-proxy 1.10.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +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,366 @@
|
|
|
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
|
+
import { createHash } from 'node:crypto';
|
|
38
|
+
import * as fs from 'node:fs/promises';
|
|
39
|
+
import * as os from 'node:os';
|
|
40
|
+
import * as path from 'node:path';
|
|
41
|
+
import { createStderrLogger as createLogger } from '../stderrLog.js';
|
|
42
|
+
const log = createLogger('mcp-proxy-wasm-referenced-files');
|
|
43
|
+
/** Largest file the host will hand to a rule. `referenced_files.rs`: 256 KiB. */
|
|
44
|
+
export const MAX_REFERENCED_FILE_BYTES = 256 * 1024;
|
|
45
|
+
/** Candidate paths considered per evaluation. */
|
|
46
|
+
export const MAX_REFERENCED_FILES = 8;
|
|
47
|
+
/** Longest path a guest may ask for. */
|
|
48
|
+
export const MAX_GUEST_PATH_BYTES = 4096;
|
|
49
|
+
/** How much of a shell command is scanned for operands. */
|
|
50
|
+
const MAX_COMMAND_SCAN_BYTES = 64 * 1024;
|
|
51
|
+
// Error codes, verbatim from `referenced_files.rs`. Negative so a guest can
|
|
52
|
+
// tell a length from a refusal with one comparison.
|
|
53
|
+
export const ERR_BAD_ARGS = -1;
|
|
54
|
+
export const ERR_REFUSED = -2;
|
|
55
|
+
export const ERR_NOT_FOUND = -3;
|
|
56
|
+
export const ERR_TOO_LARGE = -4;
|
|
57
|
+
export const ERR_BUFFER_TOO_SMALL = -5;
|
|
58
|
+
export const ERR_BUDGET = -6;
|
|
59
|
+
/** Host calls one evaluation may make, charged before argument validation. */
|
|
60
|
+
export const MAX_READS_PER_EVALUATION = 64;
|
|
61
|
+
/** The operator-configured root. Unset means the capability is off. */
|
|
62
|
+
export const MANIFEST_ROOT_ENV = 'INTUTIC_WASM_MANIFEST_ROOT';
|
|
63
|
+
const MANIFEST_EXTENSIONS = new Set(['yaml', 'yml', 'json', 'tf', 'tfvars', 'hcl', 'toml']);
|
|
64
|
+
const PATH_ARG_KEYS = ['file_path', 'filepath', 'path', 'filename', 'target_file', 'notebook_path', 'manifest'];
|
|
65
|
+
const COMMAND_ARG_KEYS = ['command', 'cmd', 'script'];
|
|
66
|
+
/**
|
|
67
|
+
* The pre-read table one evaluation sees. Immutable after construction; the
|
|
68
|
+
* worker rebuilds it from `toTable()` on its side of `postMessage`.
|
|
69
|
+
*/
|
|
70
|
+
export class ReferencedFiles {
|
|
71
|
+
entries;
|
|
72
|
+
constructor(entries) {
|
|
73
|
+
this.entries = entries;
|
|
74
|
+
}
|
|
75
|
+
static empty() {
|
|
76
|
+
return new ReferencedFiles([]);
|
|
77
|
+
}
|
|
78
|
+
static fromTable(table) {
|
|
79
|
+
return new ReferencedFiles(table ? table.map(([t, o]) => [t, o]) : []);
|
|
80
|
+
}
|
|
81
|
+
toTable() {
|
|
82
|
+
return this.entries.map(([t, o]) => [t, o]);
|
|
83
|
+
}
|
|
84
|
+
isEmpty() {
|
|
85
|
+
return this.entries.length === 0;
|
|
86
|
+
}
|
|
87
|
+
readableCount() {
|
|
88
|
+
return this.entries.filter(([, o]) => o.kind === 'content').length;
|
|
89
|
+
}
|
|
90
|
+
/** The bytes for `requested`, or the error code the guest gets. */
|
|
91
|
+
lookup(requested) {
|
|
92
|
+
const hit = this.entries.find(([t]) => t === requested);
|
|
93
|
+
if (!hit)
|
|
94
|
+
return { ok: false, code: ERR_REFUSED };
|
|
95
|
+
const o = hit[1];
|
|
96
|
+
switch (o.kind) {
|
|
97
|
+
case 'content':
|
|
98
|
+
return { ok: true, bytes: o.bytes };
|
|
99
|
+
case 'not_found':
|
|
100
|
+
return { ok: false, code: ERR_NOT_FOUND };
|
|
101
|
+
case 'too_large':
|
|
102
|
+
return { ok: false, code: ERR_TOO_LARGE };
|
|
103
|
+
case 'refused':
|
|
104
|
+
return { ok: false, code: ERR_REFUSED };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/** Operator-facing reason. Never handed to the guest. */
|
|
108
|
+
refusalReason(requested) {
|
|
109
|
+
const hit = this.entries.find(([t]) => t === requested);
|
|
110
|
+
if (!hit)
|
|
111
|
+
return "not referenced by this request's tool calls";
|
|
112
|
+
const o = hit[1];
|
|
113
|
+
switch (o.kind) {
|
|
114
|
+
case 'refused':
|
|
115
|
+
return o.why;
|
|
116
|
+
case 'not_found':
|
|
117
|
+
return 'does not exist';
|
|
118
|
+
case 'too_large':
|
|
119
|
+
return 'exceeds the size cap';
|
|
120
|
+
case 'content':
|
|
121
|
+
return 'readable';
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/** Debug rendering: states, never contents. */
|
|
125
|
+
describe() {
|
|
126
|
+
return this.entries
|
|
127
|
+
.map(([t, o]) => {
|
|
128
|
+
switch (o.kind) {
|
|
129
|
+
case 'content':
|
|
130
|
+
return `${t} => readable(${o.bytes.length} bytes)`;
|
|
131
|
+
case 'refused':
|
|
132
|
+
return `${t} => refused(${o.why})`;
|
|
133
|
+
case 'not_found':
|
|
134
|
+
return `${t} => not_found`;
|
|
135
|
+
case 'too_large':
|
|
136
|
+
return `${t} => too_large(${o.size} bytes)`;
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
.join(', ');
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/** The configured root, `~/` expanded. `undefined` keeps the capability off. */
|
|
143
|
+
export function resolveRoot(env = process.env) {
|
|
144
|
+
const raw = env[MANIFEST_ROOT_ENV];
|
|
145
|
+
if (!raw)
|
|
146
|
+
return undefined;
|
|
147
|
+
if (raw.startsWith('~/'))
|
|
148
|
+
return path.join(os.homedir(), raw.slice(2));
|
|
149
|
+
return raw;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Guard 1 and 2: every manifest-shaped path the tool calls literally name,
|
|
153
|
+
* deduped, capped at `MAX_REFERENCED_FILES`, in first-seen order.
|
|
154
|
+
*/
|
|
155
|
+
export function candidateTokens(toolCalls) {
|
|
156
|
+
const out = [];
|
|
157
|
+
for (const call of toolCalls) {
|
|
158
|
+
const args = call.arguments;
|
|
159
|
+
if (typeof args !== 'object' || args === null || Array.isArray(args))
|
|
160
|
+
continue;
|
|
161
|
+
const map = args;
|
|
162
|
+
for (const key of PATH_ARG_KEYS) {
|
|
163
|
+
const value = map[key];
|
|
164
|
+
if (typeof value === 'string')
|
|
165
|
+
consider(value, out);
|
|
166
|
+
}
|
|
167
|
+
for (const key of COMMAND_ARG_KEYS) {
|
|
168
|
+
const value = map[key];
|
|
169
|
+
if (typeof value === 'string') {
|
|
170
|
+
const scanned = value.length > MAX_COMMAND_SCAN_BYTES ? value.slice(0, MAX_COMMAND_SCAN_BYTES) : value;
|
|
171
|
+
for (const token of shellTokens(scanned))
|
|
172
|
+
consider(token, out);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
if (out.length >= MAX_REFERENCED_FILES)
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
return out;
|
|
179
|
+
}
|
|
180
|
+
function consider(raw, out) {
|
|
181
|
+
if (out.length >= MAX_REFERENCED_FILES)
|
|
182
|
+
return;
|
|
183
|
+
const trimmed = raw.replace(/^["']+|["']+$/g, '');
|
|
184
|
+
// `--values=charts/prod.yaml` is one shell word carrying one path. Only
|
|
185
|
+
// option-shaped words are split, so a filename that legitimately contains
|
|
186
|
+
// `=` is passed through rather than silently rewritten.
|
|
187
|
+
let candidate = trimmed;
|
|
188
|
+
const eq = trimmed.indexOf('=');
|
|
189
|
+
if (eq > 0 && trimmed.startsWith('-'))
|
|
190
|
+
candidate = trimmed.slice(eq + 1);
|
|
191
|
+
if (candidate.length === 0 || Buffer.byteLength(candidate) > MAX_GUEST_PATH_BYTES || !hasManifestExtension(candidate))
|
|
192
|
+
return;
|
|
193
|
+
if (out.includes(candidate))
|
|
194
|
+
return;
|
|
195
|
+
out.push(candidate);
|
|
196
|
+
}
|
|
197
|
+
function hasManifestExtension(token) {
|
|
198
|
+
const ext = path.extname(token);
|
|
199
|
+
if (!ext)
|
|
200
|
+
return false;
|
|
201
|
+
return MANIFEST_EXTENSIONS.has(ext.slice(1).toLowerCase());
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Split a command into shell words. Quotes group; whitespace and the
|
|
205
|
+
* metacharacters that end a word separate. Deliberately does NOT expand
|
|
206
|
+
* globs, variables or command substitution — an unexpanded `*.yaml` simply
|
|
207
|
+
* fails to resolve and the guest is told so.
|
|
208
|
+
*/
|
|
209
|
+
export function shellTokens(command) {
|
|
210
|
+
const out = [];
|
|
211
|
+
let current = '';
|
|
212
|
+
let quote = null;
|
|
213
|
+
const flush = () => {
|
|
214
|
+
if (current.length > 0) {
|
|
215
|
+
out.push(current);
|
|
216
|
+
current = '';
|
|
217
|
+
}
|
|
218
|
+
};
|
|
219
|
+
for (const ch of command) {
|
|
220
|
+
if (quote !== null) {
|
|
221
|
+
if (ch === quote)
|
|
222
|
+
quote = null;
|
|
223
|
+
else
|
|
224
|
+
current += ch;
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
if (ch === "'" || ch === '"') {
|
|
228
|
+
quote = ch;
|
|
229
|
+
}
|
|
230
|
+
else if (';|&<>()`'.includes(ch) || /\s/.test(ch)) {
|
|
231
|
+
flush();
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
current += ch;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
flush();
|
|
238
|
+
return out;
|
|
239
|
+
}
|
|
240
|
+
/** Resolve and read every candidate under `root`. Async, so the runner awaits it once per evaluation. */
|
|
241
|
+
export async function readTokens(tokens, root) {
|
|
242
|
+
if (tokens.length === 0)
|
|
243
|
+
return ReferencedFiles.empty();
|
|
244
|
+
// Canonicalised per batch, not once per process: the root is operator
|
|
245
|
+
// configured and may be created after the proxy starts.
|
|
246
|
+
let canonicalRoot;
|
|
247
|
+
try {
|
|
248
|
+
canonicalRoot = await fs.realpath(root);
|
|
249
|
+
}
|
|
250
|
+
catch (err) {
|
|
251
|
+
log.warn({ action: 'wasm_manifest_root_unresolvable', root, err: err instanceof Error ? err.message : String(err) }, `${MANIFEST_ROOT_ENV} does not resolve — every referenced-file read will be refused`);
|
|
252
|
+
return ReferencedFiles.fromTable(tokens.map((t) => [t, { kind: 'refused', why: 'the configured manifest root does not resolve' }]));
|
|
253
|
+
}
|
|
254
|
+
const table = [];
|
|
255
|
+
for (const token of tokens) {
|
|
256
|
+
const outcome = await readOne(canonicalRoot, token);
|
|
257
|
+
if (outcome.kind === 'content') {
|
|
258
|
+
log.debug({
|
|
259
|
+
action: 'wasm_referenced_file_exposed',
|
|
260
|
+
path: token,
|
|
261
|
+
bytes: outcome.bytes.length,
|
|
262
|
+
// A content hash, not the content: enough to explain why a replay
|
|
263
|
+
// produced a different verdict without copying a manifest into
|
|
264
|
+
// telemetry.
|
|
265
|
+
sha256Prefix: createHash('sha256').update(outcome.bytes).digest('hex').slice(0, 16),
|
|
266
|
+
}, 'referenced file exposed to WASM rules');
|
|
267
|
+
}
|
|
268
|
+
else {
|
|
269
|
+
log.debug({ action: 'wasm_referenced_file_withheld', path: token, reason: describeOutcome(outcome) }, 'referenced file withheld from WASM rules');
|
|
270
|
+
}
|
|
271
|
+
table.push([token, outcome]);
|
|
272
|
+
}
|
|
273
|
+
return ReferencedFiles.fromTable(table);
|
|
274
|
+
}
|
|
275
|
+
function describeOutcome(o) {
|
|
276
|
+
switch (o.kind) {
|
|
277
|
+
case 'refused':
|
|
278
|
+
return o.why;
|
|
279
|
+
case 'not_found':
|
|
280
|
+
return 'does not exist';
|
|
281
|
+
case 'too_large':
|
|
282
|
+
return 'exceeds the size cap';
|
|
283
|
+
case 'content':
|
|
284
|
+
return 'readable';
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
/** Convenience for callers with tool calls in hand. */
|
|
288
|
+
export function prefetch(toolCalls, root) {
|
|
289
|
+
return readTokens(candidateTokens(toolCalls), root);
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Guards 3–6 on one candidate. Ordered so nothing touches the filesystem
|
|
293
|
+
* until the lexical checks pass: a `..` path is refused without a `stat`, so
|
|
294
|
+
* the import cannot probe for files outside the root.
|
|
295
|
+
*/
|
|
296
|
+
async function readOne(canonicalRoot, token) {
|
|
297
|
+
if (token.length === 0 || token.includes('\0'))
|
|
298
|
+
return { kind: 'refused', why: 'is empty or contains a NUL byte' };
|
|
299
|
+
const parts = token.split(/[\\/]+/);
|
|
300
|
+
if (parts.includes('..'))
|
|
301
|
+
return { kind: 'refused', why: 'contains a `..` component' };
|
|
302
|
+
// Windows drive/UNC prefixes. Refused rather than reasoned about; the
|
|
303
|
+
// proxy's deployment target is Unix.
|
|
304
|
+
if (/^[A-Za-z]:/.test(token) || token.startsWith('\\\\'))
|
|
305
|
+
return { kind: 'refused', why: 'carries a platform path prefix' };
|
|
306
|
+
const joined = path.isAbsolute(token) ? token : path.join(canonicalRoot, token);
|
|
307
|
+
let resolved;
|
|
308
|
+
try {
|
|
309
|
+
resolved = await fs.realpath(joined);
|
|
310
|
+
}
|
|
311
|
+
catch (err) {
|
|
312
|
+
if (isNotFound(err))
|
|
313
|
+
return { kind: 'not_found' };
|
|
314
|
+
return { kind: 'refused', why: 'could not be resolved' };
|
|
315
|
+
}
|
|
316
|
+
if (resolved !== canonicalRoot && !resolved.startsWith(canonicalRoot + path.sep)) {
|
|
317
|
+
return { kind: 'refused', why: 'resolves outside the configured manifest root' };
|
|
318
|
+
}
|
|
319
|
+
let meta;
|
|
320
|
+
try {
|
|
321
|
+
meta = await fs.lstat(resolved);
|
|
322
|
+
}
|
|
323
|
+
catch (err) {
|
|
324
|
+
if (isNotFound(err))
|
|
325
|
+
return { kind: 'not_found' };
|
|
326
|
+
return { kind: 'refused', why: 'could not be inspected' };
|
|
327
|
+
}
|
|
328
|
+
if (!meta.isFile())
|
|
329
|
+
return { kind: 'refused', why: 'is not a regular file' };
|
|
330
|
+
if (meta.size > MAX_REFERENCED_FILE_BYTES)
|
|
331
|
+
return { kind: 'too_large', size: meta.size };
|
|
332
|
+
// Bounded independently of the stat: the file may have grown between the
|
|
333
|
+
// two, and an unbounded read is how an endless file becomes an OOM.
|
|
334
|
+
let handle;
|
|
335
|
+
try {
|
|
336
|
+
handle = await fs.open(resolved, 'r');
|
|
337
|
+
}
|
|
338
|
+
catch (err) {
|
|
339
|
+
if (isNotFound(err))
|
|
340
|
+
return { kind: 'not_found' };
|
|
341
|
+
return { kind: 'refused', why: 'could not be opened' };
|
|
342
|
+
}
|
|
343
|
+
try {
|
|
344
|
+
const buf = new Uint8Array(MAX_REFERENCED_FILE_BYTES + 1);
|
|
345
|
+
let total = 0;
|
|
346
|
+
while (total < buf.length) {
|
|
347
|
+
const { bytesRead } = await handle.read(buf, total, buf.length - total, total);
|
|
348
|
+
if (bytesRead === 0)
|
|
349
|
+
break;
|
|
350
|
+
total += bytesRead;
|
|
351
|
+
}
|
|
352
|
+
if (total > MAX_REFERENCED_FILE_BYTES)
|
|
353
|
+
return { kind: 'too_large', size: total };
|
|
354
|
+
return { kind: 'content', bytes: buf.slice(0, total) };
|
|
355
|
+
}
|
|
356
|
+
catch {
|
|
357
|
+
return { kind: 'refused', why: 'could not be read' };
|
|
358
|
+
}
|
|
359
|
+
finally {
|
|
360
|
+
await handle.close();
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
function isNotFound(err) {
|
|
364
|
+
return typeof err === 'object' && err !== null && err.code === 'ENOENT';
|
|
365
|
+
}
|
|
366
|
+
//# sourceMappingURL=referencedFiles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"referencedFiles.js","sourceRoot":"","sources":["../../src/wasm/referencedFiles.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* wasm/runner.ts — WasmRunner: owns the one dedicated `worker_threads`
|
|
3
|
+
* Worker (worker.ts), the local-rules loader (loader.ts), and the
|
|
4
|
+
* evaluate-all-rules union logic ported from
|
|
5
|
+
* `packages/proxy/src/wasm/registry.rs`'s `evaluate_inner` (most-restrictive-
|
|
6
|
+
* wins, short-circuit on a block, carry the first reask through).
|
|
7
|
+
*
|
|
8
|
+
* ## Divergences from the Rust runner (all recorded as TD entries)
|
|
9
|
+
*
|
|
10
|
+
* - **50ms per-rule deadline, not 5ms + fuel metering.** Wasmtime's `Store`
|
|
11
|
+
* can price guest instructions with fuel and enforce a hard wall-clock
|
|
12
|
+
* timeout independently; V8's WebAssembly has no fuel-equivalent
|
|
13
|
+
* instruction metering accessible from `worker_threads`, so a wall-clock
|
|
14
|
+
* race against a `postMessage` round trip (which also pays IPC overhead
|
|
15
|
+
* the in-process Wasmtime call never did) is the only backstop available
|
|
16
|
+
* here. 50ms, not 5ms, to keep that overhead from false-positiving a
|
|
17
|
+
* legitimate rule under normal load.
|
|
18
|
+
* - **Guest memory ceiling is checked, not enforced mid-call.** `runner.rs`
|
|
19
|
+
* sets a 16MB `StoreLimits` cap that stops a `memory.grow` as it happens;
|
|
20
|
+
* V8 exposes no such hook on a module-exported memory, so `worker.ts`
|
|
21
|
+
* refuses a module whose initial memory is over 16MB and discards the
|
|
22
|
+
* verdict of one that grew past it during the call (reported as a
|
|
23
|
+
* failure, fail-open like a trap). The growth itself is bounded only by
|
|
24
|
+
* V8 (TD-440's remainder).
|
|
25
|
+
* - **`read_referenced_file` is served from a pre-read table**
|
|
26
|
+
* (`referencedFiles.ts`, the port of `referenced_files.rs`), prefetched
|
|
27
|
+
* once per `evaluate()` only when a loaded rule imports the function and
|
|
28
|
+
* `INTUTIC_WASM_MANIFEST_ROOT` is set; otherwise every call refuses,
|
|
29
|
+
* exactly as the Rust proxy answers with no root configured.
|
|
30
|
+
*
|
|
31
|
+
* @module
|
|
32
|
+
*/
|
|
33
|
+
import { type CompileBridge, type CompileOutcome } from './loader.js';
|
|
34
|
+
import { type WasmContextInput } from './context.js';
|
|
35
|
+
export type WasmVerdict = {
|
|
36
|
+
code: 'allow';
|
|
37
|
+
} | {
|
|
38
|
+
code: 'block';
|
|
39
|
+
reason: string;
|
|
40
|
+
ruleId: string;
|
|
41
|
+
} | {
|
|
42
|
+
code: 'reask';
|
|
43
|
+
reason: string;
|
|
44
|
+
ruleId: string;
|
|
45
|
+
};
|
|
46
|
+
export declare class WasmRunner implements CompileBridge {
|
|
47
|
+
private readonly loader;
|
|
48
|
+
private worker;
|
|
49
|
+
private nextRequestId;
|
|
50
|
+
private pending;
|
|
51
|
+
private consecutiveTimeouts;
|
|
52
|
+
private disabledRuleIds;
|
|
53
|
+
constructor(dirOverride?: string);
|
|
54
|
+
/** The resolved local rules directory, for logging. */
|
|
55
|
+
getDir(): string;
|
|
56
|
+
/** Currently loaded rule ids (`local:<file name>`), priority order — observability for callers/tests. */
|
|
57
|
+
getLoadedRuleIds(): string[];
|
|
58
|
+
private ensureWorker;
|
|
59
|
+
/** Send one message and wait for its correlated reply, or `null` on timeout. */
|
|
60
|
+
private send;
|
|
61
|
+
private allocId;
|
|
62
|
+
compile(ruleId: string, bytes: Uint8Array): Promise<CompileOutcome>;
|
|
63
|
+
remove(ruleId: string): void;
|
|
64
|
+
/**
|
|
65
|
+
* Rescans `~/.intutic/wasm/` and (re)compiles anything changed. Also
|
|
66
|
+
* clears every rule's disabled-by-timeout status — "disable that rule
|
|
67
|
+
* until the next policy-driven rescan" is this call.
|
|
68
|
+
*/
|
|
69
|
+
rescan(): Promise<void>;
|
|
70
|
+
/** Terminates the worker and respawns a fresh one, resending every currently-loaded rule's bytes so its module cache is rebuilt. */
|
|
71
|
+
private respawnWorker;
|
|
72
|
+
/**
|
|
73
|
+
* Evaluates every currently loaded, non-disabled rule (priority order)
|
|
74
|
+
* against one context, mirroring `registry.rs`'s `evaluate_inner`:
|
|
75
|
+
* short-circuit on the first block, carry the first reask through in case
|
|
76
|
+
* a later, higher-priority rule still blocks, `allow` when nothing fired
|
|
77
|
+
* or every loaded rule was fail-open (timeout/trap/unmapped code).
|
|
78
|
+
*/
|
|
79
|
+
evaluate(input: WasmContextInput): Promise<WasmVerdict>;
|
|
80
|
+
/**
|
|
81
|
+
* The referenced-files table for this evaluation (TD-441). With no
|
|
82
|
+
* `INTUTIC_WASM_MANIFEST_ROOT` the table is empty and every read refuses.
|
|
83
|
+
*/
|
|
84
|
+
private prefetchReferencedFiles;
|
|
85
|
+
/** One rule's evaluation, raced against `EVALUATE_TIMEOUT_MS`. `null` means fail-open (timeout, worker error, or guest trap). */
|
|
86
|
+
private evaluateOne;
|
|
87
|
+
/** Terminates the worker. Safe to call even if one was never spawned. */
|
|
88
|
+
shutdown(): Promise<void>;
|
|
89
|
+
}
|
|
90
|
+
export type { WasmContextInput };
|
|
91
|
+
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/wasm/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAMH,OAAO,EAA8B,KAAK,aAAa,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAA;AACjG,OAAO,EAAoB,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAA;AAkBtE,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAA;AAyCrD,qBAAa,UAAW,YAAW,aAAa;IAC9C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,aAAa,CAAI;IACzB,OAAO,CAAC,OAAO,CAAkC;IACjD,OAAO,CAAC,mBAAmB,CAA4B;IACvD,OAAO,CAAC,eAAe,CAAoB;gBAE/B,WAAW,CAAC,EAAE,MAAM;IAIhC,uDAAuD;IACvD,MAAM,IAAI,MAAM;IAIhB,yGAAyG;IACzG,gBAAgB,IAAI,MAAM,EAAE;IAI5B,OAAO,CAAC,YAAY;IAmBpB,gFAAgF;IAChF,OAAO,CAAC,IAAI;IAYZ,OAAO,CAAC,OAAO;IAQT,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC;IAmBzE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAQ5B;;;;OAIG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAM7B,oIAAoI;YACtH,aAAa;IAqB3B;;;;;;OAMG;IACG,QAAQ,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,WAAW,CAAC;IAuD7D;;;OAGG;YACW,uBAAuB;IAUrC,iIAAiI;YACnH,WAAW;IA8CzB,yEAAyE;IACnE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAUhC;AAWD,YAAY,EAAE,gBAAgB,EAAE,CAAA"}
|