@mondaydotcomorg/atp-provenance 0.19.7 → 0.19.8

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/dist/index.js CHANGED
@@ -1,12 +1,1910 @@
1
- export * from './types.js';
2
- export { createProvenanceProxy, getProvenance, hasProvenance, getAllProvenance, canRead, getProvenanceForPrimitive, markPrimitiveTainted, isPrimitiveTainted, setProvenanceExecutionId, clearProvenanceExecutionId, registerProvenanceMetadata, cleanupProvenanceForExecution, captureProvenanceState, restoreProvenanceState, captureProvenanceSnapshot, restoreProvenanceSnapshot, setGlobalProvenanceStore, hydrateProvenance, hydrateExecutionProvenance, } from './registry.js';
3
- export { issueProvenanceToken, verifyProvenanceToken, verifyProvenanceHints, computeDigest, stableStringify, getClientSecret, } from './tokens.js';
4
- export { SecurityPolicyEngine } from './policies/engine.js';
5
- export { preventDataExfiltration, preventDataExfiltrationWithApproval, requireUserOrigin, requireUserOriginWithApproval, blockLLMRecipients, blockLLMRecipientsWithApproval, auditSensitiveAccess, getBuiltInPolicies, getBuiltInPoliciesWithApproval, createCustomPolicy, } from './policies/engine.js';
6
- export { createDeclarativePolicy, loadDeclarativePolicies, } from './policies/declarative.js';
7
- export { DeclarativePolicyConfigSchema, PolicyConfigurationSchema, PolicyRuleSchema, ConditionSchema, OperatorSchema, PolicyActionSchema, } from './policies/schema.js';
8
- export { PolicyBuilder, RuleBuilder } from './policies/builder.js';
9
- export { DynamicPolicyRegistry } from './policies/dynamic.js';
10
- export { instrumentCode, createTrackingRuntime } from './ast/instrumentor.js';
11
- export { InMemoryProvenanceStore } from './store.js';
1
+ import { nanoid } from 'nanoid';
2
+ import { log } from '@mondaydotcomorg/atp-runtime';
3
+ import crypto from 'crypto';
4
+ import { z } from 'zod';
5
+ import * as acorn from 'acorn';
6
+ import * as walk from 'acorn-walk';
7
+ import * as escodegen from 'escodegen';
8
+
9
+ var __defProp = Object.defineProperty;
10
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
11
+
12
+ // src/types.ts
13
+ var ProvenanceMode;
14
+ (function(ProvenanceMode2) {
15
+ ProvenanceMode2["NONE"] = "none";
16
+ ProvenanceMode2["PROXY"] = "proxy";
17
+ ProvenanceMode2["AST"] = "ast";
18
+ })(ProvenanceMode || (ProvenanceMode = {}));
19
+ var ProvenanceSource;
20
+ (function(ProvenanceSource2) {
21
+ ProvenanceSource2["USER"] = "user";
22
+ ProvenanceSource2["LLM"] = "llm";
23
+ ProvenanceSource2["TOOL"] = "tool";
24
+ ProvenanceSource2["SYSTEM"] = "system";
25
+ })(ProvenanceSource || (ProvenanceSource = {}));
26
+ var ProvenanceSecurityError = class extends Error {
27
+ static {
28
+ __name(this, "ProvenanceSecurityError");
29
+ }
30
+ policy;
31
+ toolName;
32
+ details;
33
+ constructor(message, policy, toolName, details) {
34
+ super(message);
35
+ this.policy = policy;
36
+ this.toolName = toolName;
37
+ this.details = details;
38
+ this.name = "ProvenanceSecurityError";
39
+ }
40
+ };
41
+ var MAX_VALUE_SIZE = 1024 * 1024;
42
+ function stableStringify(value) {
43
+ try {
44
+ if (value === null || value === void 0) {
45
+ return String(value);
46
+ }
47
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
48
+ return JSON.stringify(value);
49
+ }
50
+ if (typeof value === "function" || typeof value === "symbol") {
51
+ return null;
52
+ }
53
+ const seen = /* @__PURE__ */ new WeakSet();
54
+ const replacer = /* @__PURE__ */ __name((_key, val) => {
55
+ if (val !== null && typeof val === "object") {
56
+ if (seen.has(val)) {
57
+ return "[Circular]";
58
+ }
59
+ seen.add(val);
60
+ if (!Array.isArray(val)) {
61
+ const sorted = {};
62
+ const keys = Object.keys(val).sort();
63
+ for (const k of keys) {
64
+ sorted[k] = val[k];
65
+ }
66
+ return sorted;
67
+ }
68
+ }
69
+ return val;
70
+ }, "replacer");
71
+ const result = JSON.stringify(value, replacer);
72
+ if (result.length > MAX_VALUE_SIZE) {
73
+ return null;
74
+ }
75
+ return result;
76
+ } catch (error) {
77
+ return null;
78
+ }
79
+ }
80
+ __name(stableStringify, "stableStringify");
81
+ function computeDigest(value) {
82
+ const serialized = stableStringify(value);
83
+ if (!serialized) {
84
+ return null;
85
+ }
86
+ return crypto.createHash("sha256").update(serialized).digest("base64url");
87
+ }
88
+ __name(computeDigest, "computeDigest");
89
+ function getClientSecret(clientId) {
90
+ const secret = process.env.PROVENANCE_SECRET;
91
+ if (!secret) {
92
+ throw new Error("PROVENANCE_SECRET environment variable is required for provenance tracking. Generate a strong secret with: openssl rand -base64 32");
93
+ }
94
+ const secretBytes = Buffer.from(secret, "utf-8").length;
95
+ if (secretBytes < 32) {
96
+ throw new Error(`PROVENANCE_SECRET must be at least 32 bytes (currently ${secretBytes} bytes). Generate a strong secret with: openssl rand -base64 32`);
97
+ }
98
+ return secret;
99
+ }
100
+ __name(getClientSecret, "getClientSecret");
101
+ function hmacSign(data, secret) {
102
+ return crypto.createHmac("sha256", secret).update(data).digest("base64url");
103
+ }
104
+ __name(hmacSign, "hmacSign");
105
+ async function issueProvenanceToken(metadata, value, clientId, executionId, cacheProvider, ttl = 3600) {
106
+ const valueDigest = computeDigest(value);
107
+ if (!valueDigest) {
108
+ return null;
109
+ }
110
+ const metaId = nanoid();
111
+ const cacheKey = `prov:meta:${clientId}:${metaId}`;
112
+ try {
113
+ await cacheProvider.set(cacheKey, JSON.stringify(metadata), ttl);
114
+ if (typeof value === "string" || typeof value === "number") {
115
+ const valueKey = `prov:value:${clientId}:${valueDigest}`;
116
+ await cacheProvider.set(valueKey, JSON.stringify({
117
+ value: String(value),
118
+ metaId
119
+ }), ttl);
120
+ }
121
+ } catch (error) {
122
+ log.error("Failed to store provenance metadata in cache", {
123
+ error
124
+ });
125
+ return null;
126
+ }
127
+ const payload = {
128
+ v: 1,
129
+ clientId,
130
+ executionId,
131
+ createdAt: Date.now(),
132
+ expiresAt: Date.now() + ttl * 1e3,
133
+ valueDigest,
134
+ metaId
135
+ };
136
+ const payloadStr = JSON.stringify(payload);
137
+ const payloadB64 = Buffer.from(payloadStr).toString("base64url");
138
+ const secret = getClientSecret();
139
+ const signature = hmacSign(payloadB64, secret);
140
+ return `${payloadB64}.${signature}`;
141
+ }
142
+ __name(issueProvenanceToken, "issueProvenanceToken");
143
+ async function verifyProvenanceToken(token, value, clientId, executionId, cacheProvider) {
144
+ try {
145
+ const parts = token.split(".");
146
+ if (parts.length !== 2) {
147
+ return null;
148
+ }
149
+ const [payloadB64, signature] = parts;
150
+ if (!payloadB64 || !signature) {
151
+ return null;
152
+ }
153
+ const secret = getClientSecret(clientId);
154
+ const expectedSig = hmacSign(payloadB64, secret);
155
+ try {
156
+ const sigBuf = Buffer.from(signature, "base64url");
157
+ const expectedBuf = Buffer.from(expectedSig, "base64url");
158
+ if (sigBuf.length !== expectedBuf.length || !crypto.timingSafeEqual(sigBuf, expectedBuf)) {
159
+ log.error("Token signature verification failed");
160
+ return null;
161
+ }
162
+ } catch (error) {
163
+ log.error("Token signature comparison error", {
164
+ error
165
+ });
166
+ return null;
167
+ }
168
+ const payloadStr = Buffer.from(payloadB64, "base64url").toString();
169
+ const payload = JSON.parse(payloadStr);
170
+ if (payload.v !== 1) {
171
+ log.error("Unsupported token version", {
172
+ version: payload.v
173
+ });
174
+ return null;
175
+ }
176
+ if (payload.clientId !== clientId) {
177
+ log.error("Token clientId mismatch", {
178
+ tokenClientId: payload.clientId,
179
+ expectedClientId: clientId
180
+ });
181
+ return null;
182
+ }
183
+ if (payload.executionId !== executionId) {
184
+ log.error("Token executionId mismatch", {
185
+ tokenExecutionId: payload.executionId,
186
+ expectedExecutionId: executionId
187
+ });
188
+ return null;
189
+ }
190
+ if (Date.now() > payload.expiresAt) {
191
+ log.warn("Token expired");
192
+ return null;
193
+ }
194
+ const valueDigest = computeDigest(value);
195
+ if (!valueDigest || valueDigest !== payload.valueDigest) {
196
+ log.warn("Token value digest mismatch (value may have been modified)");
197
+ return null;
198
+ }
199
+ const cacheKey = `prov:meta:${payload.clientId}:${payload.metaId}`;
200
+ const metaStr = await cacheProvider.get(cacheKey);
201
+ if (!metaStr || typeof metaStr !== "string") {
202
+ log.warn("Token metadata not found in cache (expired or evicted)");
203
+ return null;
204
+ }
205
+ const metadata = JSON.parse(metaStr);
206
+ return metadata;
207
+ } catch (error) {
208
+ log.error("Token verification error", {
209
+ error
210
+ });
211
+ return null;
212
+ }
213
+ }
214
+ __name(verifyProvenanceToken, "verifyProvenanceToken");
215
+ async function verifyProvenanceHints(hints, clientId, executionId, cacheProvider, maxHints = 1e3) {
216
+ const map = /* @__PURE__ */ new Map();
217
+ const hintsToProcess = hints.slice(0, maxHints);
218
+ if (hints.length > maxHints) {
219
+ log.warn(`Capped provenance hints from ${hints.length} to ${maxHints}`);
220
+ }
221
+ const timeout = 100;
222
+ const promises = hintsToProcess.map(async (token) => {
223
+ try {
224
+ const parts = token.split(".");
225
+ if (parts.length !== 2) return;
226
+ const [payloadB64] = parts;
227
+ if (!payloadB64) return;
228
+ const payloadStr = Buffer.from(payloadB64, "base64url").toString();
229
+ const payload = JSON.parse(payloadStr);
230
+ const cacheKey = `prov:meta:${payload.clientId}:${payload.metaId}`;
231
+ const fetchPromise = cacheProvider.get(cacheKey);
232
+ const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve(null), timeout));
233
+ const metaStr = await Promise.race([
234
+ fetchPromise,
235
+ timeoutPromise
236
+ ]);
237
+ if (metaStr && typeof metaStr === "string") {
238
+ const metadata = JSON.parse(metaStr);
239
+ map.set(payload.valueDigest, metadata);
240
+ const valueKey = `prov:value:${payload.clientId}:${payload.valueDigest}`;
241
+ const valueStr = await Promise.race([
242
+ cacheProvider.get(valueKey),
243
+ new Promise((resolve) => setTimeout(() => resolve(null), timeout))
244
+ ]);
245
+ if (valueStr && typeof valueStr === "string") {
246
+ try {
247
+ const { value } = JSON.parse(valueStr);
248
+ map.__valueMap = map.__valueMap || /* @__PURE__ */ new Map();
249
+ map.__valueMap.set(value, metadata);
250
+ } catch (e) {
251
+ }
252
+ }
253
+ }
254
+ } catch (error) {
255
+ }
256
+ });
257
+ await Promise.all(promises);
258
+ return map;
259
+ }
260
+ __name(verifyProvenanceHints, "verifyProvenanceHints");
261
+
262
+ // src/store.ts
263
+ var InMemoryProvenanceStore = class {
264
+ static {
265
+ __name(this, "InMemoryProvenanceStore");
266
+ }
267
+ registry = /* @__PURE__ */ new Map();
268
+ primitives = /* @__PURE__ */ new Map();
269
+ executionIds = /* @__PURE__ */ new Map();
270
+ executionPrimitives = /* @__PURE__ */ new Map();
271
+ async get(id) {
272
+ return this.registry.get(id) || null;
273
+ }
274
+ async getBatch(ids) {
275
+ const result = /* @__PURE__ */ new Map();
276
+ for (const id of ids) {
277
+ const meta = this.registry.get(id);
278
+ if (meta) {
279
+ result.set(id, meta);
280
+ }
281
+ }
282
+ return result;
283
+ }
284
+ async set(id, metadata, executionId) {
285
+ this.registry.set(id, metadata);
286
+ if (executionId) {
287
+ let ids = this.executionIds.get(executionId);
288
+ if (!ids) {
289
+ ids = /* @__PURE__ */ new Set();
290
+ this.executionIds.set(executionId, ids);
291
+ }
292
+ ids.add(id);
293
+ }
294
+ }
295
+ async getPrimitive(key) {
296
+ return this.primitives.get(key) || null;
297
+ }
298
+ async setPrimitive(key, metadata, executionId) {
299
+ this.primitives.set(key, metadata);
300
+ if (executionId) {
301
+ let keys = this.executionPrimitives.get(executionId);
302
+ if (!keys) {
303
+ keys = /* @__PURE__ */ new Set();
304
+ this.executionPrimitives.set(executionId, keys);
305
+ }
306
+ keys.add(key);
307
+ }
308
+ }
309
+ async cleanupExecution(executionId) {
310
+ const ids = this.executionIds.get(executionId);
311
+ if (ids) {
312
+ for (const id of ids) {
313
+ this.registry.delete(id);
314
+ }
315
+ this.executionIds.delete(executionId);
316
+ }
317
+ const primKeys = this.executionPrimitives.get(executionId);
318
+ if (primKeys) {
319
+ for (const key of primKeys) {
320
+ this.primitives.delete(key);
321
+ }
322
+ this.executionPrimitives.delete(executionId);
323
+ }
324
+ }
325
+ async getExecution(executionId) {
326
+ const result = /* @__PURE__ */ new Map();
327
+ const ids = this.executionIds.get(executionId);
328
+ if (ids) {
329
+ for (const id of ids) {
330
+ const meta = this.registry.get(id);
331
+ if (meta) {
332
+ result.set(id, meta);
333
+ }
334
+ }
335
+ }
336
+ return result;
337
+ }
338
+ };
339
+
340
+ // src/registry.ts
341
+ var PROVENANCE_KEY = "__provenance__";
342
+ var PROVENANCE_ID_KEY = "__prov_id__";
343
+ var provenanceStore = /* @__PURE__ */ new WeakMap();
344
+ var provenanceRegistry = /* @__PURE__ */ new Map();
345
+ var executionProvenanceIds = /* @__PURE__ */ new Map();
346
+ var currentExecutionId = null;
347
+ var primitiveProvenanceMap = /* @__PURE__ */ new Map();
348
+ var executionTaintedPrimitives = /* @__PURE__ */ new Map();
349
+ var globalStore = new InMemoryProvenanceStore();
350
+ function setGlobalProvenanceStore(store) {
351
+ globalStore = store;
352
+ }
353
+ __name(setGlobalProvenanceStore, "setGlobalProvenanceStore");
354
+ function markPrimitiveTainted(value, sourceMetadata) {
355
+ if (typeof value !== "string" && typeof value !== "number") {
356
+ return;
357
+ }
358
+ if (currentExecutionId) {
359
+ const tainted = executionTaintedPrimitives.get(currentExecutionId);
360
+ if (tainted) {
361
+ tainted.add(value);
362
+ }
363
+ }
364
+ const key = `tainted:${String(value)}`;
365
+ primitiveProvenanceMap.set(key, sourceMetadata);
366
+ globalStore.setPrimitive(key, sourceMetadata, currentExecutionId || void 0).catch((err) => {
367
+ log.warn("Failed to save primitive taint to provenance store", {
368
+ error: err
369
+ });
370
+ });
371
+ }
372
+ __name(markPrimitiveTainted, "markPrimitiveTainted");
373
+ function isPrimitiveTainted(value) {
374
+ if (typeof value !== "string" && typeof value !== "number") {
375
+ return false;
376
+ }
377
+ if (currentExecutionId) {
378
+ const tainted = executionTaintedPrimitives.get(currentExecutionId);
379
+ if (tainted && tainted.has(value)) {
380
+ return true;
381
+ }
382
+ }
383
+ return false;
384
+ }
385
+ __name(isPrimitiveTainted, "isPrimitiveTainted");
386
+ function setProvenanceExecutionId(executionId) {
387
+ currentExecutionId = executionId;
388
+ if (!executionProvenanceIds.has(executionId)) {
389
+ executionProvenanceIds.set(executionId, /* @__PURE__ */ new Set());
390
+ }
391
+ if (!executionTaintedPrimitives.has(executionId)) {
392
+ executionTaintedPrimitives.set(executionId, /* @__PURE__ */ new Set());
393
+ }
394
+ }
395
+ __name(setProvenanceExecutionId, "setProvenanceExecutionId");
396
+ function clearProvenanceExecutionId() {
397
+ currentExecutionId = null;
398
+ }
399
+ __name(clearProvenanceExecutionId, "clearProvenanceExecutionId");
400
+ async function hydrateProvenance(ids) {
401
+ const batch = await globalStore.getBatch(ids);
402
+ for (const [id, metadata] of batch.entries()) {
403
+ provenanceRegistry.set(id, metadata);
404
+ if (currentExecutionId) {
405
+ let execIds = executionProvenanceIds.get(currentExecutionId);
406
+ if (!execIds) {
407
+ execIds = /* @__PURE__ */ new Set();
408
+ executionProvenanceIds.set(currentExecutionId, execIds);
409
+ }
410
+ execIds.add(id);
411
+ }
412
+ }
413
+ }
414
+ __name(hydrateProvenance, "hydrateProvenance");
415
+ async function hydrateExecutionProvenance(executionId) {
416
+ const batch = await globalStore.getExecution(executionId);
417
+ for (const [id, metadata] of batch.entries()) {
418
+ provenanceRegistry.set(id, metadata);
419
+ if (currentExecutionId === executionId) {
420
+ let executionSet = executionProvenanceIds.get(executionId);
421
+ if (!executionSet) {
422
+ executionSet = /* @__PURE__ */ new Set();
423
+ executionProvenanceIds.set(executionId, executionSet);
424
+ }
425
+ executionSet.add(id);
426
+ }
427
+ }
428
+ }
429
+ __name(hydrateExecutionProvenance, "hydrateExecutionProvenance");
430
+ function registerProvenanceMetadata(id, metadata, executionId) {
431
+ if (id.startsWith("tainted:") || id.includes(":")) {
432
+ primitiveProvenanceMap.set(id, metadata);
433
+ globalStore.setPrimitive(id, metadata, executionId).catch((err) => {
434
+ log.warn("Failed to save primitive provenance to store", {
435
+ error: err
436
+ });
437
+ });
438
+ if (id.startsWith("tainted:")) {
439
+ const value = id.slice("tainted:".length);
440
+ if (executionId) {
441
+ let tainted = executionTaintedPrimitives.get(executionId);
442
+ if (!tainted) {
443
+ tainted = /* @__PURE__ */ new Set();
444
+ executionTaintedPrimitives.set(executionId, tainted);
445
+ }
446
+ tainted.add(value);
447
+ }
448
+ }
449
+ } else {
450
+ provenanceRegistry.set(id, metadata);
451
+ globalStore.set(id, metadata, executionId).catch((err) => {
452
+ log.warn("Failed to save provenance to store", {
453
+ error: err
454
+ });
455
+ });
456
+ }
457
+ if (executionId) {
458
+ let ids = executionProvenanceIds.get(executionId);
459
+ if (!ids) {
460
+ ids = /* @__PURE__ */ new Set();
461
+ executionProvenanceIds.set(executionId, ids);
462
+ }
463
+ ids.add(id);
464
+ }
465
+ }
466
+ __name(registerProvenanceMetadata, "registerProvenanceMetadata");
467
+ function cleanupProvenanceForExecution(executionId) {
468
+ const ids = executionProvenanceIds.get(executionId);
469
+ if (ids) {
470
+ for (const id of ids) {
471
+ provenanceRegistry.delete(id);
472
+ const keysToDelete = [];
473
+ for (const key of primitiveProvenanceMap.keys()) {
474
+ if (key.startsWith(`${id}:`) || key.startsWith("tainted:")) {
475
+ keysToDelete.push(key);
476
+ }
477
+ }
478
+ for (const key of keysToDelete) {
479
+ primitiveProvenanceMap.delete(key);
480
+ }
481
+ }
482
+ executionProvenanceIds.delete(executionId);
483
+ }
484
+ executionTaintedPrimitives.delete(executionId);
485
+ globalStore.cleanupExecution(executionId).catch((err) => {
486
+ log.warn("Failed to cleanup provenance store", {
487
+ error: err
488
+ });
489
+ });
490
+ }
491
+ __name(cleanupProvenanceForExecution, "cleanupProvenanceForExecution");
492
+ function getProvenanceForPrimitive(value) {
493
+ if (typeof value !== "string" && typeof value !== "number") {
494
+ return null;
495
+ }
496
+ const valueStr = String(value);
497
+ if (isPrimitiveTainted(value)) {
498
+ const taintedKey2 = `tainted:${valueStr}`;
499
+ const metadata = primitiveProvenanceMap.get(taintedKey2);
500
+ if (metadata) {
501
+ return metadata;
502
+ }
503
+ }
504
+ const taintedKey = `tainted:${valueStr}`;
505
+ const taintedMetadata = primitiveProvenanceMap.get(taintedKey);
506
+ if (taintedMetadata) {
507
+ return taintedMetadata;
508
+ }
509
+ for (const [key, metadata] of primitiveProvenanceMap.entries()) {
510
+ const parts = key.split(":");
511
+ if (parts.length >= 3 && !key.startsWith("tainted:")) {
512
+ const primitiveValue = parts.slice(2).join(":");
513
+ if (primitiveValue === valueStr) {
514
+ return metadata;
515
+ }
516
+ }
517
+ }
518
+ const digest = computeDigest(value);
519
+ if (digest) {
520
+ const digestMetadata = provenanceRegistry.get(digest);
521
+ if (digestMetadata) {
522
+ return digestMetadata;
523
+ }
524
+ }
525
+ return null;
526
+ }
527
+ __name(getProvenanceForPrimitive, "getProvenanceForPrimitive");
528
+ function captureProvenanceState(executionId) {
529
+ const state = /* @__PURE__ */ new Map();
530
+ const ids = executionProvenanceIds.get(executionId);
531
+ if (ids) {
532
+ for (const id of ids) {
533
+ const metadata = provenanceRegistry.get(id);
534
+ if (metadata) {
535
+ state.set(id, metadata);
536
+ }
537
+ }
538
+ }
539
+ return state;
540
+ }
541
+ __name(captureProvenanceState, "captureProvenanceState");
542
+ function captureProvenanceSnapshot(executionId) {
543
+ const registryMap = captureProvenanceState(executionId);
544
+ const registry = Array.from(registryMap.entries());
545
+ const primitives = [];
546
+ const ids = executionProvenanceIds.get(executionId) || /* @__PURE__ */ new Set();
547
+ const tainted = executionTaintedPrimitives.get(executionId);
548
+ if (tainted) {
549
+ for (const value of tainted) {
550
+ const key = `tainted:${String(value)}`;
551
+ const meta = primitiveProvenanceMap.get(key);
552
+ if (meta) {
553
+ primitives.push([
554
+ key,
555
+ meta
556
+ ]);
557
+ }
558
+ }
559
+ }
560
+ for (const [key, meta] of primitiveProvenanceMap.entries()) {
561
+ if (key.startsWith("tainted:")) {
562
+ continue;
563
+ }
564
+ const [first] = key.split(":");
565
+ if (first && ids.has(first)) {
566
+ primitives.push([
567
+ key,
568
+ meta
569
+ ]);
570
+ }
571
+ }
572
+ return {
573
+ registry,
574
+ primitives
575
+ };
576
+ }
577
+ __name(captureProvenanceSnapshot, "captureProvenanceSnapshot");
578
+ function restoreProvenanceState(executionId, state) {
579
+ setProvenanceExecutionId(executionId);
580
+ const ids = executionProvenanceIds.get(executionId);
581
+ for (const [id, metadata] of state) {
582
+ provenanceRegistry.set(id, metadata);
583
+ ids.add(id);
584
+ globalStore.set(id, metadata, executionId).catch((err) => {
585
+ log.error("Failed to save provenance to store", {
586
+ error: err
587
+ });
588
+ });
589
+ }
590
+ }
591
+ __name(restoreProvenanceState, "restoreProvenanceState");
592
+ function restoreProvenanceSnapshot(executionId, snapshot) {
593
+ const registryMap = new Map(snapshot.registry);
594
+ restoreProvenanceState(executionId, registryMap);
595
+ for (const [key, meta] of snapshot.primitives) {
596
+ primitiveProvenanceMap.set(key, meta);
597
+ globalStore.setPrimitive(key, meta, executionId).catch((err) => {
598
+ log.error("Failed to save primitive provenance to store", {
599
+ error: err
600
+ });
601
+ });
602
+ if (key.startsWith("tainted:")) {
603
+ const value = key.slice("tainted:".length);
604
+ let set = executionTaintedPrimitives.get(executionId);
605
+ if (!set) {
606
+ set = /* @__PURE__ */ new Set();
607
+ executionTaintedPrimitives.set(executionId, set);
608
+ }
609
+ set.add(value);
610
+ }
611
+ }
612
+ }
613
+ __name(restoreProvenanceSnapshot, "restoreProvenanceSnapshot");
614
+ function createProvenanceProxy(value, source, readers = {
615
+ type: "public"
616
+ }, dependencies = []) {
617
+ if (value === null || value === void 0) {
618
+ return value;
619
+ }
620
+ if (typeof value !== "object" && typeof value !== "function") {
621
+ return value;
622
+ }
623
+ const id = nanoid();
624
+ const metadata = {
625
+ id,
626
+ source,
627
+ readers,
628
+ dependencies,
629
+ context: {}
630
+ };
631
+ provenanceRegistry.set(id, metadata);
632
+ if (currentExecutionId) {
633
+ const ids = executionProvenanceIds.get(currentExecutionId);
634
+ if (ids) {
635
+ ids.add(id);
636
+ }
637
+ }
638
+ globalStore.set(id, metadata, currentExecutionId || void 0).catch((err) => {
639
+ log.warn("Failed to persist provenance to store", {
640
+ error: err
641
+ });
642
+ });
643
+ try {
644
+ Object.defineProperty(value, PROVENANCE_ID_KEY, {
645
+ value: id,
646
+ writable: false,
647
+ enumerable: true,
648
+ configurable: true,
649
+ // @ts-ignore
650
+ __proto__: null
651
+ });
652
+ } catch (e) {
653
+ provenanceStore.set(value, metadata);
654
+ }
655
+ if (Array.isArray(value)) {
656
+ for (const item of value) {
657
+ if (typeof item === "object" && item !== null && !hasProvenance(item)) {
658
+ createProvenanceProxy(item, source, readers, [
659
+ id,
660
+ ...dependencies
661
+ ]);
662
+ }
663
+ }
664
+ } else if (typeof value === "object") {
665
+ for (const key in value) {
666
+ if (Object.prototype.hasOwnProperty.call(value, key) && key !== PROVENANCE_ID_KEY) {
667
+ const nestedValue = value[key];
668
+ if (typeof nestedValue === "object" && nestedValue !== null && !hasProvenance(nestedValue)) {
669
+ createProvenanceProxy(nestedValue, source, readers, [
670
+ id,
671
+ ...dependencies
672
+ ]);
673
+ } else if (typeof nestedValue === "string" || typeof nestedValue === "number") {
674
+ const primitiveKey = `${id}:${key}:${String(nestedValue)}`;
675
+ primitiveProvenanceMap.set(primitiveKey, metadata);
676
+ globalStore.setPrimitive(primitiveKey, metadata, currentExecutionId || void 0).catch((err) => {
677
+ log.error("Failed to save primitive provenance to store", {
678
+ error: err
679
+ });
680
+ });
681
+ }
682
+ }
683
+ }
684
+ }
685
+ return value;
686
+ }
687
+ __name(createProvenanceProxy, "createProvenanceProxy");
688
+ function getProvenance(value) {
689
+ if (value === null || value === void 0) {
690
+ return null;
691
+ }
692
+ if (typeof value === "string" || typeof value === "number") {
693
+ const primitiveProvenance = getProvenanceForPrimitive(value);
694
+ if (primitiveProvenance) {
695
+ return primitiveProvenance;
696
+ }
697
+ }
698
+ if (typeof value === "object") {
699
+ const id = value[PROVENANCE_ID_KEY];
700
+ if (id && typeof id === "string") {
701
+ const metadata = provenanceRegistry.get(id);
702
+ if (metadata) {
703
+ return metadata;
704
+ }
705
+ }
706
+ if (PROVENANCE_KEY in value) {
707
+ return value[PROVENANCE_KEY];
708
+ }
709
+ const stored = provenanceStore.get(value);
710
+ if (stored) {
711
+ return stored;
712
+ }
713
+ }
714
+ return null;
715
+ }
716
+ __name(getProvenance, "getProvenance");
717
+ function hasProvenance(value) {
718
+ return getProvenance(value) !== null;
719
+ }
720
+ __name(hasProvenance, "hasProvenance");
721
+ function getAllProvenance(value, visited = /* @__PURE__ */ new Set()) {
722
+ if (value === null || value === void 0 || typeof value !== "object") {
723
+ return [];
724
+ }
725
+ if (visited.has(value)) {
726
+ return [];
727
+ }
728
+ visited.add(value);
729
+ const results = [];
730
+ const metadata = getProvenance(value);
731
+ if (metadata) {
732
+ results.push(metadata);
733
+ }
734
+ if (Array.isArray(value)) {
735
+ for (const item of value) {
736
+ results.push(...getAllProvenance(item, visited));
737
+ }
738
+ } else if (typeof value === "object") {
739
+ for (const key in value) {
740
+ if (key !== PROVENANCE_KEY && key !== PROVENANCE_ID_KEY && Object.prototype.hasOwnProperty.call(value, key)) {
741
+ results.push(...getAllProvenance(value[key], visited));
742
+ }
743
+ }
744
+ }
745
+ return results;
746
+ }
747
+ __name(getAllProvenance, "getAllProvenance");
748
+ function canRead(reader, permissions) {
749
+ if (permissions.type === "public") {
750
+ return true;
751
+ }
752
+ return permissions.readers.includes(reader);
753
+ }
754
+ __name(canRead, "canRead");
755
+
756
+ // src/policies/engine.ts
757
+ var SecurityPolicyEngine = class {
758
+ static {
759
+ __name(this, "SecurityPolicyEngine");
760
+ }
761
+ policies;
762
+ logger;
763
+ approvalCallback;
764
+ customGetProvenance;
765
+ constructor(policies, logger, customGetProvenance) {
766
+ this.policies = policies;
767
+ this.logger = logger;
768
+ this.customGetProvenance = customGetProvenance;
769
+ }
770
+ /**
771
+ * Set a custom getProvenance function (e.g., for AST mode)
772
+ */
773
+ setGetProvenance(fn) {
774
+ this.customGetProvenance = fn;
775
+ }
776
+ /**
777
+ * Set approval callback for policies that return action='approve'
778
+ */
779
+ setApprovalCallback(callback) {
780
+ this.approvalCallback = callback;
781
+ }
782
+ async checkTool(toolName, apiGroup, args) {
783
+ this.logger.debug("Checking security policies", {
784
+ toolName,
785
+ apiGroup,
786
+ policyCount: this.policies.length
787
+ });
788
+ const getProvenanceFn = this.customGetProvenance || getProvenance;
789
+ for (const policy of this.policies) {
790
+ const result = await policy.check(toolName, args, getProvenanceFn);
791
+ const action = this.normalizeAction(result);
792
+ if (action === "block") {
793
+ this.logger.warn("Security policy blocked tool execution", {
794
+ toolName,
795
+ apiGroup,
796
+ policy: policy.name,
797
+ reason: result.reason
798
+ });
799
+ throw new ProvenanceSecurityError(result.reason || `Policy ${policy.name} denied execution`, policy.name, toolName, {
800
+ apiGroup,
801
+ args: this.sanitizeArgs(args),
802
+ context: result.context
803
+ });
804
+ }
805
+ if (action === "approve") {
806
+ this.logger.info("Security policy requires approval", {
807
+ toolName,
808
+ apiGroup,
809
+ policy: policy.name,
810
+ reason: result.reason
811
+ });
812
+ const approved = await this.requestApproval(toolName, apiGroup, policy.name, result);
813
+ if (!approved) {
814
+ this.logger.warn("Security policy approval denied", {
815
+ toolName,
816
+ apiGroup,
817
+ policy: policy.name
818
+ });
819
+ throw new ProvenanceSecurityError(`Approval denied: ${result.reason || "Operation requires approval"}`, policy.name, toolName, {
820
+ apiGroup,
821
+ args: this.sanitizeArgs(args),
822
+ approvalDenied: true
823
+ });
824
+ }
825
+ this.logger.info("Security policy approval granted", {
826
+ toolName,
827
+ apiGroup,
828
+ policy: policy.name
829
+ });
830
+ }
831
+ if (action === "log") {
832
+ this.logger.warn("Security policy audit event", {
833
+ toolName,
834
+ apiGroup,
835
+ policy: policy.name,
836
+ reason: result.reason,
837
+ context: result.context,
838
+ args: this.sanitizeArgs(args)
839
+ });
840
+ }
841
+ }
842
+ this.logger.debug("All security policies passed", {
843
+ toolName,
844
+ apiGroup
845
+ });
846
+ }
847
+ normalizeAction(result) {
848
+ if (result.action) {
849
+ return result.action;
850
+ }
851
+ if (result.allowed !== void 0) {
852
+ return result.allowed ? "log" : "block";
853
+ }
854
+ return "log";
855
+ }
856
+ async requestApproval(toolName, apiGroup, policyName, result) {
857
+ if (!this.approvalCallback) {
858
+ this.logger.error("Approval required but no callback configured", {
859
+ toolName,
860
+ policy: policyName
861
+ });
862
+ throw new ProvenanceSecurityError("Approval required but approval handler not configured", policyName, toolName, {
863
+ requiresApproval: true
864
+ });
865
+ }
866
+ const message = result.reason || `Policy ${policyName} requires approval for ${toolName}`;
867
+ const context = {
868
+ toolName,
869
+ apiGroup,
870
+ policy: policyName,
871
+ ...result.context || {}
872
+ };
873
+ try {
874
+ return await this.approvalCallback(message, context);
875
+ } catch (error) {
876
+ this.logger.error("Approval request failed", {
877
+ error,
878
+ toolName,
879
+ policy: policyName
880
+ });
881
+ return false;
882
+ }
883
+ }
884
+ sanitizeArgs(args) {
885
+ const sanitized = {};
886
+ for (const [key, value] of Object.entries(args)) {
887
+ if (typeof value === "string" && value.length > 100) {
888
+ sanitized[key] = value.substring(0, 100) + "...";
889
+ } else if (typeof value === "object") {
890
+ sanitized[key] = "[object]";
891
+ } else {
892
+ sanitized[key] = value;
893
+ }
894
+ }
895
+ return sanitized;
896
+ }
897
+ };
898
+ function getAllProvenanceFromArgs(args, getProvenance2) {
899
+ const allProvenance = [];
900
+ const visited = /* @__PURE__ */ new Set();
901
+ function scan(value) {
902
+ if (value === null || value === void 0) return;
903
+ if (typeof value === "string" || typeof value === "number") {
904
+ try {
905
+ const primitiveProv = getProvenance2(value);
906
+ if (primitiveProv) {
907
+ allProvenance.push(primitiveProv);
908
+ }
909
+ } catch (error) {
910
+ }
911
+ return;
912
+ }
913
+ if (typeof value !== "object") return;
914
+ if (visited.has(value)) return;
915
+ visited.add(value);
916
+ const provenance = getProvenance2(value);
917
+ if (provenance) {
918
+ allProvenance.push(provenance);
919
+ }
920
+ if (Array.isArray(value)) {
921
+ for (const item of value) {
922
+ scan(item);
923
+ }
924
+ } else {
925
+ for (const key in value) {
926
+ if (Object.prototype.hasOwnProperty.call(value, key)) {
927
+ scan(value[key]);
928
+ }
929
+ }
930
+ }
931
+ }
932
+ __name(scan, "scan");
933
+ for (const key in args) {
934
+ if (Object.prototype.hasOwnProperty.call(args, key)) {
935
+ scan(args[key]);
936
+ }
937
+ }
938
+ return allProvenance;
939
+ }
940
+ __name(getAllProvenanceFromArgs, "getAllProvenanceFromArgs");
941
+ var preventDataExfiltration = {
942
+ name: "prevent-data-exfiltration",
943
+ description: "Prevents sending data to recipients who cannot read it",
944
+ check: /* @__PURE__ */ __name((toolName, args, getProvenance2) => {
945
+ const recipientKeys = [
946
+ "to",
947
+ "recipient",
948
+ "recipients",
949
+ "email",
950
+ "address"
951
+ ];
952
+ let recipient = null;
953
+ for (const key of recipientKeys) {
954
+ if (args[key] && typeof args[key] === "string") {
955
+ recipient = args[key];
956
+ break;
957
+ }
958
+ }
959
+ if (!recipient) {
960
+ return {
961
+ action: "log"
962
+ };
963
+ }
964
+ const allProvenance = getAllProvenanceFromArgs(args, getProvenance2);
965
+ for (const metadata of allProvenance) {
966
+ if (metadata.source.type === ProvenanceSource.TOOL) {
967
+ if (metadata.readers.type === "restricted") {
968
+ if (!canRead(recipient, metadata.readers)) {
969
+ return {
970
+ action: "block",
971
+ reason: `Recipient "${recipient}" cannot read data from ${metadata.source.toolName}. Authorized readers: ${metadata.readers.readers.join(", ")}`,
972
+ policy: "prevent-data-exfiltration",
973
+ context: {
974
+ recipient,
975
+ toolSource: metadata.source.toolName,
976
+ authorizedReaders: metadata.readers.readers
977
+ }
978
+ };
979
+ }
980
+ }
981
+ }
982
+ }
983
+ return {
984
+ action: "log"
985
+ };
986
+ }, "check")
987
+ };
988
+ var preventDataExfiltrationWithApproval = {
989
+ name: "prevent-data-exfiltration-approval",
990
+ description: "Requires approval for sending data to recipients who cannot read it",
991
+ check: /* @__PURE__ */ __name((toolName, args, getProvenance2) => {
992
+ const recipientKeys = [
993
+ "to",
994
+ "recipient",
995
+ "recipients",
996
+ "email",
997
+ "address"
998
+ ];
999
+ let recipient = null;
1000
+ for (const key of recipientKeys) {
1001
+ if (args[key] && typeof args[key] === "string") {
1002
+ recipient = args[key];
1003
+ break;
1004
+ }
1005
+ }
1006
+ if (!recipient) {
1007
+ return {
1008
+ action: "log"
1009
+ };
1010
+ }
1011
+ const allProvenance = getAllProvenanceFromArgs(args, getProvenance2);
1012
+ for (const metadata of allProvenance) {
1013
+ if (metadata.source.type === ProvenanceSource.TOOL) {
1014
+ if (metadata.readers.type === "restricted") {
1015
+ if (!canRead(recipient, metadata.readers)) {
1016
+ return {
1017
+ action: "approve",
1018
+ reason: `Sending data from ${metadata.source.toolName} to "${recipient}" (not in authorized readers)`,
1019
+ policy: "prevent-data-exfiltration-approval",
1020
+ context: {
1021
+ recipient,
1022
+ toolSource: metadata.source.toolName,
1023
+ authorizedReaders: metadata.readers.readers,
1024
+ sensitiveFields: Object.keys(args).filter((k) => args[k] !== null)
1025
+ }
1026
+ };
1027
+ }
1028
+ }
1029
+ }
1030
+ }
1031
+ return {
1032
+ action: "log"
1033
+ };
1034
+ }, "check")
1035
+ };
1036
+ var requireUserOrigin = {
1037
+ name: "require-user-origin",
1038
+ description: "Requires critical parameters to come directly from user input",
1039
+ check: /* @__PURE__ */ __name((toolName, args, getProvenance2) => {
1040
+ const criticalTools = [
1041
+ "deleteDatabase",
1042
+ "dropTable",
1043
+ "executeSQL",
1044
+ "sendMoney",
1045
+ "transfer"
1046
+ ];
1047
+ if (!criticalTools.some((t) => toolName.toLowerCase().includes(t.toLowerCase()))) {
1048
+ return {
1049
+ action: "log"
1050
+ };
1051
+ }
1052
+ for (const [key, value] of Object.entries(args)) {
1053
+ const allProvenance = getAllProvenance(value);
1054
+ for (const metadata of allProvenance) {
1055
+ if (metadata.source.type !== ProvenanceSource.USER && metadata.source.type !== ProvenanceSource.SYSTEM) {
1056
+ return {
1057
+ action: "block",
1058
+ reason: `Critical tool "${toolName}" parameter "${key}" must come from user input, but came from ${metadata.source.type}`,
1059
+ policy: "require-user-origin",
1060
+ context: {
1061
+ toolName,
1062
+ parameterKey: key,
1063
+ actualSource: metadata.source.type
1064
+ }
1065
+ };
1066
+ }
1067
+ }
1068
+ }
1069
+ return {
1070
+ action: "log"
1071
+ };
1072
+ }, "check")
1073
+ };
1074
+ var requireUserOriginWithApproval = {
1075
+ name: "require-user-origin-approval",
1076
+ description: "Requires approval for critical operations with non-user data",
1077
+ check: /* @__PURE__ */ __name((toolName, args, getProvenance2) => {
1078
+ const criticalTools = [
1079
+ "deleteDatabase",
1080
+ "dropTable",
1081
+ "executeSQL",
1082
+ "sendMoney",
1083
+ "transfer"
1084
+ ];
1085
+ if (!criticalTools.some((t) => toolName.toLowerCase().includes(t.toLowerCase()))) {
1086
+ return {
1087
+ action: "log"
1088
+ };
1089
+ }
1090
+ for (const [key, value] of Object.entries(args)) {
1091
+ const allProvenance = getAllProvenance(value);
1092
+ for (const metadata of allProvenance) {
1093
+ if (metadata.source.type !== ProvenanceSource.USER && metadata.source.type !== ProvenanceSource.SYSTEM) {
1094
+ return {
1095
+ action: "approve",
1096
+ reason: `Critical operation "${toolName}" with parameter "${key}" from ${metadata.source.type} source`,
1097
+ policy: "require-user-origin-approval",
1098
+ context: {
1099
+ toolName,
1100
+ parameterKey: key,
1101
+ actualSource: metadata.source.type,
1102
+ value: String(value).substring(0, 100)
1103
+ }
1104
+ };
1105
+ }
1106
+ }
1107
+ }
1108
+ return {
1109
+ action: "log"
1110
+ };
1111
+ }, "check")
1112
+ };
1113
+ var blockLLMRecipients = {
1114
+ name: "block-llm-recipients",
1115
+ description: "Blocks sending data to LLM-extracted email addresses",
1116
+ check: /* @__PURE__ */ __name((toolName, args, getProvenance2) => {
1117
+ const recipientKeys = [
1118
+ "to",
1119
+ "recipient",
1120
+ "recipients",
1121
+ "email"
1122
+ ];
1123
+ for (const key of recipientKeys) {
1124
+ if (!args[key]) continue;
1125
+ const metadata = getProvenance2(args[key]);
1126
+ if (metadata && metadata.source.type === ProvenanceSource.LLM) {
1127
+ return {
1128
+ action: "block",
1129
+ reason: `Cannot send to LLM-extracted recipient in parameter "${key}". Recipients must come from user input or trusted sources.`,
1130
+ policy: "block-llm-recipients",
1131
+ context: {
1132
+ parameterKey: key,
1133
+ recipientValue: String(args[key]).substring(0, 50)
1134
+ }
1135
+ };
1136
+ }
1137
+ }
1138
+ return {
1139
+ action: "log"
1140
+ };
1141
+ }, "check")
1142
+ };
1143
+ var blockLLMRecipientsWithApproval = {
1144
+ name: "block-llm-recipients-approval",
1145
+ description: "Requires approval for sending to LLM-extracted email addresses",
1146
+ check: /* @__PURE__ */ __name((toolName, args, getProvenance2) => {
1147
+ const recipientKeys = [
1148
+ "to",
1149
+ "recipient",
1150
+ "recipients",
1151
+ "email"
1152
+ ];
1153
+ for (const key of recipientKeys) {
1154
+ if (!args[key]) continue;
1155
+ const metadata = getProvenance2(args[key]);
1156
+ if (metadata && metadata.source.type === ProvenanceSource.LLM) {
1157
+ return {
1158
+ action: "approve",
1159
+ reason: `Sending to LLM-extracted recipient "${args[key]}" in parameter "${key}"`,
1160
+ policy: "block-llm-recipients-approval",
1161
+ context: {
1162
+ parameterKey: key,
1163
+ recipientValue: String(args[key]),
1164
+ llmOperation: metadata.source.operation
1165
+ }
1166
+ };
1167
+ }
1168
+ }
1169
+ return {
1170
+ action: "log"
1171
+ };
1172
+ }, "check")
1173
+ };
1174
+ var auditSensitiveAccess = {
1175
+ name: "audit-sensitive-access",
1176
+ description: "Logs access to sensitive data (does not block)",
1177
+ check: /* @__PURE__ */ __name((toolName, args, getProvenance2) => {
1178
+ const sensitiveTools = [
1179
+ "getPassword",
1180
+ "getCreditCard",
1181
+ "getSSN",
1182
+ "getBankAccount"
1183
+ ];
1184
+ if (sensitiveTools.some((t) => toolName.toLowerCase().includes(t.toLowerCase()))) {
1185
+ const allProvenance = getAllProvenance(args);
1186
+ return {
1187
+ action: "log",
1188
+ reason: `Sensitive data accessed via ${toolName}`,
1189
+ policy: "audit-sensitive-access",
1190
+ context: {
1191
+ toolName,
1192
+ provenanceChain: allProvenance.map((p) => ({
1193
+ source: p.source,
1194
+ id: p.id
1195
+ }))
1196
+ }
1197
+ };
1198
+ }
1199
+ return {
1200
+ action: "log"
1201
+ };
1202
+ }, "check")
1203
+ };
1204
+ function createCustomPolicy(name, description, checkFn) {
1205
+ return {
1206
+ name,
1207
+ description,
1208
+ check: checkFn
1209
+ };
1210
+ }
1211
+ __name(createCustomPolicy, "createCustomPolicy");
1212
+ function getBuiltInPolicies() {
1213
+ return [
1214
+ preventDataExfiltration,
1215
+ requireUserOrigin,
1216
+ blockLLMRecipients,
1217
+ auditSensitiveAccess
1218
+ ];
1219
+ }
1220
+ __name(getBuiltInPolicies, "getBuiltInPolicies");
1221
+ function getBuiltInPoliciesWithApproval() {
1222
+ return [
1223
+ preventDataExfiltrationWithApproval,
1224
+ requireUserOriginWithApproval,
1225
+ blockLLMRecipientsWithApproval,
1226
+ auditSensitiveAccess
1227
+ ];
1228
+ }
1229
+ __name(getBuiltInPoliciesWithApproval, "getBuiltInPoliciesWithApproval");
1230
+
1231
+ // src/policies/declarative.ts
1232
+ function resolveValue(path, args, getProvenance2) {
1233
+ const parts = path.split(".");
1234
+ const root = parts.shift();
1235
+ if (root === "args") {
1236
+ let current = args;
1237
+ for (const part of parts) {
1238
+ if (current === null || current === void 0) {
1239
+ return void 0;
1240
+ }
1241
+ current = current[part];
1242
+ }
1243
+ return current;
1244
+ }
1245
+ if (root === "provenance" && parts[0] === "args") {
1246
+ parts.shift();
1247
+ const argName = parts.shift();
1248
+ if (!argName) return void 0;
1249
+ const argValue = args[argName];
1250
+ let remainingParts = [
1251
+ ...parts
1252
+ ];
1253
+ const metadataKeys = [
1254
+ "source",
1255
+ "readers",
1256
+ "dependencies",
1257
+ "id",
1258
+ "context"
1259
+ ];
1260
+ let splitIndex = -1;
1261
+ for (let i = 0; i < remainingParts.length; i++) {
1262
+ if (metadataKeys.includes(remainingParts[i])) {
1263
+ splitIndex = i;
1264
+ break;
1265
+ }
1266
+ }
1267
+ if (splitIndex === -1) {
1268
+ return void 0;
1269
+ }
1270
+ let valuePath = remainingParts.slice(0, splitIndex);
1271
+ let metaPath = remainingParts.slice(splitIndex);
1272
+ let currentVal = argValue;
1273
+ for (const part of valuePath) {
1274
+ if (currentVal === null || currentVal === void 0) return void 0;
1275
+ currentVal = currentVal[part];
1276
+ }
1277
+ const metadata = getProvenance2(currentVal);
1278
+ if (!metadata) return void 0;
1279
+ let currentMeta = metadata;
1280
+ for (const part of metaPath) {
1281
+ if (currentMeta === null || currentMeta === void 0) return void 0;
1282
+ currentMeta = currentMeta[part];
1283
+ }
1284
+ return currentMeta;
1285
+ }
1286
+ return void 0;
1287
+ }
1288
+ __name(resolveValue, "resolveValue");
1289
+ function evaluateCondition(actual, operator, expected) {
1290
+ switch (operator) {
1291
+ case "equals":
1292
+ return actual === expected;
1293
+ case "notEquals":
1294
+ return actual !== expected;
1295
+ case "contains":
1296
+ return Array.isArray(actual) || typeof actual === "string" ? actual.includes(expected) : false;
1297
+ case "notContains":
1298
+ return Array.isArray(actual) || typeof actual === "string" ? !actual.includes(expected) : true;
1299
+ case "startsWith":
1300
+ return typeof actual === "string" ? actual.startsWith(expected) : false;
1301
+ case "notStartsWith":
1302
+ return typeof actual === "string" ? !actual.startsWith(expected) : true;
1303
+ case "endsWith":
1304
+ return typeof actual === "string" ? actual.endsWith(expected) : false;
1305
+ case "notEndsWith":
1306
+ return typeof actual === "string" ? !actual.endsWith(expected) : true;
1307
+ case "matches":
1308
+ if (typeof actual === "string") {
1309
+ return new RegExp(expected).test(actual);
1310
+ }
1311
+ if (typeof actual === "number" && typeof expected === "string") {
1312
+ const match = expected.match(/^([<>]=?|==|!=)(\d+(?:\.\d+)?)$/);
1313
+ if (match) {
1314
+ const [, op, value] = match;
1315
+ const numValue = parseFloat(value);
1316
+ switch (op) {
1317
+ case ">":
1318
+ return actual > numValue;
1319
+ case ">=":
1320
+ return actual >= numValue;
1321
+ case "<":
1322
+ return actual < numValue;
1323
+ case "<=":
1324
+ return actual <= numValue;
1325
+ case "==":
1326
+ return actual === numValue;
1327
+ case "!=":
1328
+ return actual !== numValue;
1329
+ }
1330
+ }
1331
+ }
1332
+ return false;
1333
+ case "in":
1334
+ return Array.isArray(expected) ? expected.includes(actual) : false;
1335
+ case "notIn":
1336
+ return Array.isArray(expected) ? !expected.includes(actual) : true;
1337
+ default:
1338
+ return false;
1339
+ }
1340
+ }
1341
+ __name(evaluateCondition, "evaluateCondition");
1342
+ function createDeclarativePolicy(config) {
1343
+ return {
1344
+ name: config.id,
1345
+ description: config.description,
1346
+ check: /* @__PURE__ */ __name(async (toolName, args, getProvenance2) => {
1347
+ if (config.scope.toolName) {
1348
+ const toolRegex = new RegExp(`^${config.scope.toolName}$`);
1349
+ if (!toolRegex.test(toolName)) {
1350
+ return {
1351
+ action: "log"
1352
+ };
1353
+ }
1354
+ }
1355
+ if (config.scope.apiGroup) {
1356
+ const extractedGroup = toolName.split(".")[0] || "";
1357
+ const groupRegex = new RegExp(`^${config.scope.apiGroup}$`);
1358
+ if (!groupRegex.test(extractedGroup)) {
1359
+ return {
1360
+ action: "log"
1361
+ };
1362
+ }
1363
+ }
1364
+ for (const rule of config.rules) {
1365
+ const allMatch = rule.conditions.every((condition) => {
1366
+ const actualValue = resolveValue(condition.field, args, getProvenance2);
1367
+ return evaluateCondition(actualValue, condition.operator, condition.value);
1368
+ });
1369
+ if (allMatch) {
1370
+ return {
1371
+ action: rule.action,
1372
+ reason: rule.reason || `Matched rule ${rule.id || "unknown"} in policy ${config.id}`,
1373
+ policy: config.id,
1374
+ context: {
1375
+ ruleId: rule.id,
1376
+ conditions: rule.conditions
1377
+ }
1378
+ };
1379
+ }
1380
+ }
1381
+ return {
1382
+ action: "log"
1383
+ };
1384
+ }, "check")
1385
+ };
1386
+ }
1387
+ __name(createDeclarativePolicy, "createDeclarativePolicy");
1388
+ function loadDeclarativePolicies(config) {
1389
+ if (Array.isArray(config)) {
1390
+ return config.map(createDeclarativePolicy);
1391
+ }
1392
+ return config.policies.map(createDeclarativePolicy);
1393
+ }
1394
+ __name(loadDeclarativePolicies, "loadDeclarativePolicies");
1395
+ var OperatorSchema = z.enum([
1396
+ "equals",
1397
+ "notEquals",
1398
+ "contains",
1399
+ "notContains",
1400
+ "startsWith",
1401
+ "notStartsWith",
1402
+ "endsWith",
1403
+ "notEndsWith",
1404
+ "matches",
1405
+ "in",
1406
+ "notIn"
1407
+ ]);
1408
+ var ConditionSchema = z.object({
1409
+ field: z.string().describe("Field to check (e.g. args.paramName, provenance.args.param.source.type)"),
1410
+ operator: OperatorSchema,
1411
+ value: z.any().describe("Value to compare against")
1412
+ });
1413
+ var PolicyActionSchema = z.enum([
1414
+ "log",
1415
+ "approve",
1416
+ "block"
1417
+ ]);
1418
+ var PolicyRuleSchema = z.object({
1419
+ id: z.string().optional(),
1420
+ action: PolicyActionSchema,
1421
+ conditions: z.array(ConditionSchema).describe("All conditions must match (implicit AND)"),
1422
+ reason: z.string().optional()
1423
+ });
1424
+ var DeclarativePolicyConfigSchema = z.object({
1425
+ id: z.string(),
1426
+ description: z.string().optional(),
1427
+ scope: z.object({
1428
+ toolName: z.string().optional().describe("Regex pattern or exact match for tool name"),
1429
+ apiGroup: z.string().optional().describe("Regex pattern or exact match for API group")
1430
+ }),
1431
+ rules: z.array(PolicyRuleSchema).describe("Rules are evaluated in order. First match wins.")
1432
+ });
1433
+ var PolicyConfigurationSchema = z.object({
1434
+ version: z.string(),
1435
+ policies: z.array(DeclarativePolicyConfigSchema)
1436
+ });
1437
+
1438
+ // src/policies/builder.ts
1439
+ var RuleBuilder = class {
1440
+ static {
1441
+ __name(this, "RuleBuilder");
1442
+ }
1443
+ rule = {
1444
+ action: "log",
1445
+ conditions: []
1446
+ };
1447
+ constructor(action = "log") {
1448
+ this.rule.action = action;
1449
+ }
1450
+ action(action) {
1451
+ this.rule.action = action;
1452
+ return this;
1453
+ }
1454
+ id(id) {
1455
+ this.rule.id = id;
1456
+ return this;
1457
+ }
1458
+ reason(reason) {
1459
+ this.rule.reason = reason;
1460
+ return this;
1461
+ }
1462
+ condition(field, operator, value) {
1463
+ this.rule.conditions.push({
1464
+ field,
1465
+ operator,
1466
+ value
1467
+ });
1468
+ return this;
1469
+ }
1470
+ build() {
1471
+ return this.rule;
1472
+ }
1473
+ };
1474
+ var PolicyBuilder = class {
1475
+ static {
1476
+ __name(this, "PolicyBuilder");
1477
+ }
1478
+ config;
1479
+ constructor(id) {
1480
+ this.config = {
1481
+ id,
1482
+ scope: {},
1483
+ rules: []
1484
+ };
1485
+ }
1486
+ description(desc) {
1487
+ this.config.description = desc;
1488
+ return this;
1489
+ }
1490
+ scopeTool(toolNamePattern) {
1491
+ this.config.scope.toolName = toolNamePattern;
1492
+ return this;
1493
+ }
1494
+ scopeApiGroup(apiGroupPattern) {
1495
+ this.config.scope.apiGroup = apiGroupPattern;
1496
+ return this;
1497
+ }
1498
+ /**
1499
+ * Add a rule using a builder callback
1500
+ * @example
1501
+ * .addRule(r => r.action('block').condition('args.amount', 'matches', '>1000'))
1502
+ */
1503
+ addRule(buildFn) {
1504
+ const builder = new RuleBuilder();
1505
+ this.config.rules.push(buildFn(builder).build());
1506
+ return this;
1507
+ }
1508
+ /**
1509
+ * Add a fully formed rule object
1510
+ */
1511
+ addRuleObject(rule) {
1512
+ this.config.rules.push(rule);
1513
+ return this;
1514
+ }
1515
+ build() {
1516
+ return this.config;
1517
+ }
1518
+ };
1519
+
1520
+ // src/policies/dynamic.ts
1521
+ var DynamicPolicyRegistry = class {
1522
+ static {
1523
+ __name(this, "DynamicPolicyRegistry");
1524
+ }
1525
+ name = "dynamic-policy-registry";
1526
+ description = "Container for dynamically managed security policies";
1527
+ policies = /* @__PURE__ */ new Map();
1528
+ constructor(initialPolicies = []) {
1529
+ for (const policy of initialPolicies) {
1530
+ this.policies.set(policy.name, policy);
1531
+ }
1532
+ }
1533
+ /**
1534
+ * Add or update a policy
1535
+ */
1536
+ addPolicy(policy) {
1537
+ this.policies.set(policy.name, policy);
1538
+ }
1539
+ /**
1540
+ * Remove a policy by name
1541
+ */
1542
+ removePolicy(name) {
1543
+ this.policies.delete(name);
1544
+ }
1545
+ /**
1546
+ * clear all policies
1547
+ */
1548
+ clear() {
1549
+ this.policies.clear();
1550
+ }
1551
+ /**
1552
+ * Load policies from declarative configurations (JSON)
1553
+ * This is useful for loading policies saved from a UI
1554
+ */
1555
+ loadFromConfigs(configs, replace = false) {
1556
+ if (replace) {
1557
+ this.policies.clear();
1558
+ }
1559
+ for (const config of configs) {
1560
+ const policy = createDeclarativePolicy(config);
1561
+ this.policies.set(policy.name, policy);
1562
+ }
1563
+ }
1564
+ /**
1565
+ * Get all registered policies
1566
+ */
1567
+ getPolicies() {
1568
+ return Array.from(this.policies.values());
1569
+ }
1570
+ /**
1571
+ * Implementation of the SecurityPolicy check interface.
1572
+ * Delegates to all registered policies.
1573
+ */
1574
+ async check(toolName, args, getProvenance2) {
1575
+ let requiresApproval = null;
1576
+ for (const policy of this.policies.values()) {
1577
+ const result = await policy.check(toolName, args, getProvenance2);
1578
+ if (result.action === "block") {
1579
+ return result;
1580
+ }
1581
+ if (result.action === "approve") {
1582
+ if (!requiresApproval) {
1583
+ requiresApproval = result;
1584
+ }
1585
+ }
1586
+ }
1587
+ if (requiresApproval) {
1588
+ return requiresApproval;
1589
+ }
1590
+ return {
1591
+ action: "log"
1592
+ };
1593
+ }
1594
+ };
1595
+ function instrumentCode(code) {
1596
+ const wrappedCode = `(async function() {
1597
+ ${code}
1598
+ })`;
1599
+ const ast = acorn.parse(wrappedCode, {
1600
+ ecmaVersion: 2022,
1601
+ sourceType: "script"
1602
+ });
1603
+ const context = {
1604
+ trackingCalls: 0
1605
+ };
1606
+ walk.simple(ast, {
1607
+ BinaryExpression(node) {
1608
+ wrapBinaryExpression(node, context);
1609
+ },
1610
+ AssignmentExpression(node) {
1611
+ wrapAssignment(node, context);
1612
+ },
1613
+ CallExpression(node) {
1614
+ if (node.callee.type === "MemberExpression") {
1615
+ wrapMethodCall(node, context);
1616
+ }
1617
+ },
1618
+ TemplateLiteral(node) {
1619
+ wrapTemplateLiteral(node, context);
1620
+ }
1621
+ });
1622
+ let instrumentedCode = escodegen.generate(ast);
1623
+ if (instrumentedCode.endsWith(");")) {
1624
+ instrumentedCode = instrumentedCode.slice(0, -1);
1625
+ }
1626
+ return {
1627
+ code: instrumentedCode,
1628
+ metadata: {
1629
+ trackingCalls: context.trackingCalls
1630
+ }
1631
+ };
1632
+ }
1633
+ __name(instrumentCode, "instrumentCode");
1634
+ function wrapBinaryExpression(node, context) {
1635
+ context.trackingCalls++;
1636
+ const originalNode = {
1637
+ ...node
1638
+ };
1639
+ node.type = "CallExpression";
1640
+ node.callee = {
1641
+ type: "Identifier",
1642
+ name: "__track_binary"
1643
+ };
1644
+ node.arguments = [
1645
+ originalNode.left,
1646
+ originalNode.right,
1647
+ {
1648
+ type: "Literal",
1649
+ value: originalNode.operator
1650
+ }
1651
+ ];
1652
+ }
1653
+ __name(wrapBinaryExpression, "wrapBinaryExpression");
1654
+ function wrapAssignment(node, context) {
1655
+ context.trackingCalls++;
1656
+ const originalRight = node.right;
1657
+ node.right = {
1658
+ type: "CallExpression",
1659
+ callee: {
1660
+ type: "Identifier",
1661
+ name: "__track_assign"
1662
+ },
1663
+ arguments: [
1664
+ {
1665
+ type: "Literal",
1666
+ value: node.left.type === "Identifier" ? node.left.name : "unknown"
1667
+ },
1668
+ originalRight
1669
+ ]
1670
+ };
1671
+ }
1672
+ __name(wrapAssignment, "wrapAssignment");
1673
+ function wrapMethodCall(node, context) {
1674
+ const obj = node.callee.object;
1675
+ const isAPICall = obj.type === "Identifier" && (obj.name === "api" || obj.name === "atp") || obj.type === "MemberExpression" && isAPIObject(obj);
1676
+ if (!isAPICall) {
1677
+ return;
1678
+ }
1679
+ context.trackingCalls++;
1680
+ const originalNode = {
1681
+ ...node
1682
+ };
1683
+ node.type = "CallExpression";
1684
+ node.callee = {
1685
+ type: "Identifier",
1686
+ name: "__track_method"
1687
+ };
1688
+ node.arguments = [
1689
+ originalNode.callee.object,
1690
+ {
1691
+ type: "Literal",
1692
+ value: originalNode.callee.property.name || originalNode.callee.property.value
1693
+ },
1694
+ {
1695
+ type: "ArrayExpression",
1696
+ elements: originalNode.arguments
1697
+ }
1698
+ ];
1699
+ }
1700
+ __name(wrapMethodCall, "wrapMethodCall");
1701
+ function isAPIObject(node) {
1702
+ if (node.type === "Identifier") {
1703
+ return node.name === "api" || node.name === "atp";
1704
+ }
1705
+ if (node.type === "MemberExpression") {
1706
+ return isAPIObject(node.object);
1707
+ }
1708
+ return false;
1709
+ }
1710
+ __name(isAPIObject, "isAPIObject");
1711
+ function wrapTemplateLiteral(node, context) {
1712
+ context.trackingCalls++;
1713
+ const originalNode = {
1714
+ ...node
1715
+ };
1716
+ node.type = "CallExpression";
1717
+ node.callee = {
1718
+ type: "Identifier",
1719
+ name: "__track_template"
1720
+ };
1721
+ node.arguments = [
1722
+ {
1723
+ type: "ArrayExpression",
1724
+ elements: originalNode.expressions || []
1725
+ },
1726
+ {
1727
+ type: "ArrayExpression",
1728
+ elements: (originalNode.quasis || []).map((quasi) => ({
1729
+ type: "Literal",
1730
+ value: quasi.value.cooked || quasi.value.raw
1731
+ }))
1732
+ }
1733
+ ];
1734
+ }
1735
+ __name(wrapTemplateLiteral, "wrapTemplateLiteral");
1736
+ var ASTProvenanceTracker = class {
1737
+ static {
1738
+ __name(this, "ASTProvenanceTracker");
1739
+ }
1740
+ metadata = /* @__PURE__ */ new Map();
1741
+ valueToId = /* @__PURE__ */ new WeakMap();
1742
+ nextId = 0;
1743
+ getId(value) {
1744
+ if (typeof value === "object" && value !== null) {
1745
+ const existing = this.valueToId.get(value);
1746
+ if (existing) return existing;
1747
+ const id = `tracked_${this.nextId++}`;
1748
+ this.valueToId.set(value, id);
1749
+ return id;
1750
+ }
1751
+ return `primitive_${nanoid()}`;
1752
+ }
1753
+ track(value, source, dependencies = []) {
1754
+ if (value === null || value === void 0) {
1755
+ return value;
1756
+ }
1757
+ const id = this.getId(value);
1758
+ if (!this.metadata.has(id)) {
1759
+ this.metadata.set(id, {
1760
+ id,
1761
+ source,
1762
+ readers: {
1763
+ type: "public"
1764
+ },
1765
+ dependencies
1766
+ });
1767
+ }
1768
+ return value;
1769
+ }
1770
+ trackBinary(left, right, operator) {
1771
+ const leftId = this.getId(left);
1772
+ const rightId = this.getId(right);
1773
+ const leftProv = getProvenance(left) || getProvenanceForPrimitive(left);
1774
+ const rightProv = getProvenance(right) || getProvenanceForPrimitive(right);
1775
+ const toolMetadata = leftProv?.source.type === ProvenanceSource.TOOL ? leftProv : rightProv?.source.type === ProvenanceSource.TOOL ? rightProv : null;
1776
+ let result;
1777
+ switch (operator) {
1778
+ case "+":
1779
+ result = left + right;
1780
+ if (typeof result === "string" && toolMetadata) {
1781
+ markPrimitiveTainted(result, toolMetadata);
1782
+ }
1783
+ break;
1784
+ case "-":
1785
+ result = left - right;
1786
+ break;
1787
+ case "*":
1788
+ result = left * right;
1789
+ break;
1790
+ case "/":
1791
+ result = left / right;
1792
+ break;
1793
+ case "%":
1794
+ result = left % right;
1795
+ break;
1796
+ case "===":
1797
+ case "==":
1798
+ result = left === right;
1799
+ break;
1800
+ case "!==":
1801
+ case "!=":
1802
+ result = left !== right;
1803
+ break;
1804
+ case "<":
1805
+ result = left < right;
1806
+ break;
1807
+ case ">":
1808
+ result = left > right;
1809
+ break;
1810
+ case "<=":
1811
+ result = left <= right;
1812
+ break;
1813
+ case ">=":
1814
+ result = left >= right;
1815
+ break;
1816
+ case "&&":
1817
+ result = left && right;
1818
+ break;
1819
+ case "||":
1820
+ result = left || right;
1821
+ break;
1822
+ default:
1823
+ result = void 0;
1824
+ }
1825
+ return this.track(result, {
1826
+ type: "system",
1827
+ operation: `binary_${operator}`,
1828
+ timestamp: Date.now()
1829
+ }, [
1830
+ leftId,
1831
+ rightId
1832
+ ]);
1833
+ }
1834
+ trackAssign(name, value) {
1835
+ return this.track(value, {
1836
+ type: "system",
1837
+ operation: "assignment",
1838
+ timestamp: Date.now()
1839
+ }, [
1840
+ this.getId(value)
1841
+ ]);
1842
+ }
1843
+ trackMethod(object, method, args) {
1844
+ if (typeof object === "object" && object !== null && method in object) {
1845
+ const result = object[method](...args);
1846
+ return this.track(result, {
1847
+ type: "system",
1848
+ operation: `method_${method}`,
1849
+ timestamp: Date.now()
1850
+ }, [
1851
+ this.getId(object),
1852
+ ...args.map((a) => this.getId(a))
1853
+ ]);
1854
+ }
1855
+ return void 0;
1856
+ }
1857
+ trackTemplate(expressions, quasis) {
1858
+ let result = "";
1859
+ let toolMetadata = null;
1860
+ for (let i = 0; i < quasis.length; i++) {
1861
+ result += quasis[i] || "";
1862
+ if (i < expressions.length) {
1863
+ const expr = expressions[i];
1864
+ result += String(expr);
1865
+ const prov = getProvenance(expr) || getProvenanceForPrimitive(expr);
1866
+ if (prov && prov.source.type === ProvenanceSource.TOOL && !toolMetadata) {
1867
+ toolMetadata = prov;
1868
+ }
1869
+ }
1870
+ }
1871
+ if (toolMetadata) {
1872
+ markPrimitiveTainted(result, toolMetadata);
1873
+ }
1874
+ return result;
1875
+ }
1876
+ getMetadata(value) {
1877
+ if (typeof value === "object" && value !== null) {
1878
+ const id = this.valueToId.get(value);
1879
+ if (id) {
1880
+ return this.metadata.get(id) || null;
1881
+ }
1882
+ }
1883
+ return null;
1884
+ }
1885
+ getAllMetadata() {
1886
+ return new Map(this.metadata);
1887
+ }
1888
+ restoreMetadata(metadata) {
1889
+ this.metadata = new Map(metadata);
1890
+ }
1891
+ };
1892
+ function createTrackingRuntime() {
1893
+ const tracker = new ASTProvenanceTracker();
1894
+ return {
1895
+ tracker,
1896
+ runtime: {
1897
+ __track: /* @__PURE__ */ __name((value, source, deps) => tracker.track(value, source, deps), "__track"),
1898
+ __track_binary: /* @__PURE__ */ __name((left, right, operator) => tracker.trackBinary(left, right, operator), "__track_binary"),
1899
+ __track_assign: /* @__PURE__ */ __name((name, value) => tracker.trackAssign(name, value), "__track_assign"),
1900
+ __track_method: /* @__PURE__ */ __name((object, method, args) => tracker.trackMethod(object, method, args), "__track_method"),
1901
+ __track_template: /* @__PURE__ */ __name((expressions, quasis) => tracker.trackTemplate(expressions, quasis), "__track_template"),
1902
+ __get_provenance: /* @__PURE__ */ __name((value) => tracker.getMetadata(value), "__get_provenance")
1903
+ }
1904
+ };
1905
+ }
1906
+ __name(createTrackingRuntime, "createTrackingRuntime");
1907
+
1908
+ export { ConditionSchema, DeclarativePolicyConfigSchema, DynamicPolicyRegistry, InMemoryProvenanceStore, OperatorSchema, PolicyActionSchema, PolicyBuilder, PolicyConfigurationSchema, PolicyRuleSchema, ProvenanceMode, ProvenanceSecurityError, ProvenanceSource, RuleBuilder, SecurityPolicyEngine, auditSensitiveAccess, blockLLMRecipients, blockLLMRecipientsWithApproval, canRead, captureProvenanceSnapshot, captureProvenanceState, cleanupProvenanceForExecution, clearProvenanceExecutionId, computeDigest, createCustomPolicy, createDeclarativePolicy, createProvenanceProxy, createTrackingRuntime, getAllProvenance, getBuiltInPolicies, getBuiltInPoliciesWithApproval, getClientSecret, getProvenance, getProvenanceForPrimitive, hasProvenance, hydrateExecutionProvenance, hydrateProvenance, instrumentCode, isPrimitiveTainted, issueProvenanceToken, loadDeclarativePolicies, markPrimitiveTainted, preventDataExfiltration, preventDataExfiltrationWithApproval, registerProvenanceMetadata, requireUserOrigin, requireUserOriginWithApproval, restoreProvenanceSnapshot, restoreProvenanceState, setGlobalProvenanceStore, setProvenanceExecutionId, stableStringify, verifyProvenanceHints, verifyProvenanceToken };
1909
+ //# sourceMappingURL=index.js.map
12
1910
  //# sourceMappingURL=index.js.map