@nekzus/liop 2.2.0 → 2.3.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.
Files changed (66) hide show
  1. package/LICENSE +201 -21
  2. package/NOTICE +5 -0
  3. package/README.md +61 -5
  4. package/dist/bin/agent.js +7 -5
  5. package/dist/bin/agent.js.map +1 -1
  6. package/dist/bridge.d.ts +2 -2
  7. package/dist/bridge.js +2 -1
  8. package/dist/{chunk-UVO7DII3.js → chunk-4LQPDN3W.js} +108 -15
  9. package/dist/chunk-4LQPDN3W.js.map +1 -0
  10. package/dist/{chunk-NJRSFFD7.js → chunk-74CISO2I.js} +60 -22
  11. package/dist/chunk-74CISO2I.js.map +1 -0
  12. package/dist/{chunk-E5QBDD5E.js → chunk-CRZBVFDV.js} +169 -22
  13. package/dist/chunk-CRZBVFDV.js.map +1 -0
  14. package/dist/chunk-GKV6M2PQ.js +208106 -0
  15. package/dist/chunk-GKV6M2PQ.js.map +1 -0
  16. package/dist/chunk-JIJPZFR2.js +51 -0
  17. package/dist/chunk-JIJPZFR2.js.map +1 -0
  18. package/dist/chunk-OIMJZ64E.js +441 -0
  19. package/dist/chunk-OIMJZ64E.js.map +1 -0
  20. package/dist/chunk-PYKRQAER.js +77 -0
  21. package/dist/chunk-PYKRQAER.js.map +1 -0
  22. package/dist/{chunk-J3WPBMJ5.js → chunk-SONUORBT.js} +95 -6
  23. package/dist/chunk-SONUORBT.js.map +1 -0
  24. package/dist/{chunk-2JLG4DET.js → chunk-UBOQZVV5.js} +261 -107
  25. package/dist/chunk-UBOQZVV5.js.map +1 -0
  26. package/dist/chunk-UCJEK75U.js +714 -0
  27. package/dist/chunk-UCJEK75U.js.map +1 -0
  28. package/dist/chunk-WSW6YJNY.js +168 -0
  29. package/dist/chunk-WSW6YJNY.js.map +1 -0
  30. package/dist/client.d.ts +3 -2
  31. package/dist/client.js +4 -3
  32. package/dist/gateway.d.ts +5 -110
  33. package/dist/gateway.js +5 -4
  34. package/dist/hybrid-CF__0YnC.d.ts +170 -0
  35. package/dist/{index-BlGc0iym.d.ts → index-BW95kAL4.d.ts} +63 -2
  36. package/dist/index-cMV0_yD9.d.ts +200 -0
  37. package/dist/index.d.ts +273 -18
  38. package/dist/index.js +266 -13
  39. package/dist/index.js.map +1 -1
  40. package/dist/mesh.d.ts +14 -0
  41. package/dist/mesh.js +1 -1
  42. package/dist/server.d.ts +2 -2
  43. package/dist/server.js +5 -4
  44. package/dist/{types-sKeUxuky.d.ts → types-lJIxBlWF.d.ts} +71 -1
  45. package/dist/types.d.ts +1 -1
  46. package/dist/types.js +1 -1
  47. package/dist/workers/logic-execution.d.ts +1 -0
  48. package/dist/workers/logic-execution.js +17 -1
  49. package/dist/workers/logic-execution.js.map +1 -1
  50. package/package.json +53 -33
  51. package/dist/chunk-2JLG4DET.js.map +0 -1
  52. package/dist/chunk-CT6NHSYP.js +0 -30
  53. package/dist/chunk-CT6NHSYP.js.map +0 -1
  54. package/dist/chunk-E5QBDD5E.js.map +0 -1
  55. package/dist/chunk-HB5DXX3Q.js +0 -1976
  56. package/dist/chunk-HB5DXX3Q.js.map +0 -1
  57. package/dist/chunk-IJHTRIZC.js +0 -56
  58. package/dist/chunk-IJHTRIZC.js.map +0 -1
  59. package/dist/chunk-J3WPBMJ5.js.map +0 -1
  60. package/dist/chunk-NJRSFFD7.js.map +0 -1
  61. package/dist/chunk-PHTWUTY7.js +0 -300
  62. package/dist/chunk-PHTWUTY7.js.map +0 -1
  63. package/dist/chunk-RDWCGZ2A.js +0 -87
  64. package/dist/chunk-RDWCGZ2A.js.map +0 -1
  65. package/dist/chunk-UVO7DII3.js.map +0 -1
  66. package/dist/index-qM8ZH8sC.d.ts +0 -101
@@ -1,10 +1,12 @@
1
- import { LIOP_SCOPES, authorizeRequest } from './chunk-IJHTRIZC.js';
2
- import { liopV1, createServerCredentials } from './chunk-RDWCGZ2A.js';
3
- import { MeshNode } from './chunk-NJRSFFD7.js';
1
+ import { sanitizeOutput } from './chunk-JIJPZFR2.js';
2
+ import { LIOP_SCOPES, Dilithium65Wrapper, authorizeRequest, egressBlocksTotal, toolCallsTotal, fuelConsumed } from './chunk-OIMJZ64E.js';
3
+ import { GRPC_CHANNEL_OPTIONS, liopV1, createServerCredentials } from './chunk-WSW6YJNY.js';
4
+ import { MeshNode } from './chunk-74CISO2I.js';
4
5
  import { log } from './chunk-72MNYFR6.js';
5
6
  import { Buffer } from 'buffer';
6
- import crypto2 from 'crypto';
7
- import * as fs from 'fs';
7
+ import * as crypto3 from 'crypto';
8
+ import crypto3__default from 'crypto';
9
+ import * as fs2 from 'fs';
8
10
  import { createRequire } from 'module';
9
11
  import path from 'path';
10
12
  import { fileURLToPath, pathToFileURL } from 'url';
@@ -17,14 +19,6 @@ import Provider from 'oidc-provider';
17
19
  import * as acorn from 'acorn';
18
20
  import { simple } from 'acorn-walk';
19
21
 
20
- var GRPC_CHANNEL_OPTIONS = {
21
- "grpc.keepalive_time_ms": 3e4,
22
- "grpc.keepalive_timeout_ms": 1e4,
23
- "grpc.keepalive_permit_without_calls": 1,
24
- "grpc.max_send_message_length": -1,
25
- "grpc.max_receive_message_length": -1,
26
- "grpc.enable_retries": 1
27
- };
28
22
  var LiopRpcServer = class {
29
23
  server;
30
24
  constructor() {
@@ -53,15 +47,145 @@ var LiopRpcServer = class {
53
47
  );
54
48
  });
55
49
  }
56
- async stop() {
50
+ async gracefulShutdown(timeoutMs = 5e3) {
57
51
  return new Promise((resolve) => {
52
+ let resolved = false;
53
+ const timer = setTimeout(() => {
54
+ if (!resolved) {
55
+ resolved = true;
56
+ log.warn(
57
+ `[LIOP-RPC] tryShutdown timed out after ${timeoutMs}ms \u2014 forcing shutdown`
58
+ );
59
+ this.server.forceShutdown();
60
+ resolve();
61
+ }
62
+ }, timeoutMs);
58
63
  this.server.tryShutdown(() => {
59
- log.info("[LIOP-RPC] Server shut down");
60
- resolve();
64
+ if (!resolved) {
65
+ resolved = true;
66
+ clearTimeout(timer);
67
+ log.info("[LIOP-RPC] Server gracefully shut down");
68
+ resolve();
69
+ }
61
70
  });
62
71
  });
63
72
  }
73
+ async stop() {
74
+ return this.gracefulShutdown(5e3);
75
+ }
76
+ };
77
+ var GENESIS_HASH = "0".repeat(64);
78
+ function canonicalize(obj) {
79
+ const sortedKeys = Object.keys(obj).sort();
80
+ const canonicalObj = {};
81
+ for (const key of sortedKeys) {
82
+ canonicalObj[key] = obj[key];
83
+ }
84
+ return JSON.stringify(canonicalObj);
85
+ }
86
+ function computeEntryHash(entryWithoutHash) {
87
+ const canonical = canonicalize(
88
+ entryWithoutHash
89
+ );
90
+ return crypto3.createHash("sha256").update(canonical).digest("hex");
91
+ }
92
+ var AuditLogger = class {
93
+ entries = [];
94
+ lastEntryHash = GENESIS_HASH;
95
+ filePath;
96
+ constructor(filePath) {
97
+ this.filePath = filePath;
98
+ if (this.filePath && fs2.existsSync(this.filePath)) {
99
+ this.loadFromFile(this.filePath);
100
+ }
101
+ }
102
+ recordExecution(params) {
103
+ const id = crypto3.randomUUID();
104
+ const timestamp = params.timestamp || (/* @__PURE__ */ new Date()).toISOString();
105
+ const traceId = params.traceId || crypto3.randomBytes(16).toString("hex");
106
+ const datasetHash = params.datasetHash || crypto3.createHash("sha256").update("").digest("hex");
107
+ const outputHash = params.outputHash || crypto3.createHash("sha256").update("").digest("hex");
108
+ const zkReceiptSig = params.zkReceiptSig || "";
109
+ const partialEntry = {
110
+ id,
111
+ timestamp,
112
+ traceId,
113
+ agentDid: params.agentDid,
114
+ peerId: params.peerId,
115
+ toolName: params.toolName,
116
+ datasetHash,
117
+ fuelConsumed: params.fuelConsumed,
118
+ outputHash,
119
+ zkReceiptSig,
120
+ status: params.status,
121
+ prevEntryHash: this.lastEntryHash
122
+ };
123
+ const entryHash = computeEntryHash(partialEntry);
124
+ const fullEntry = {
125
+ ...partialEntry,
126
+ entryHash
127
+ };
128
+ this.entries.push(fullEntry);
129
+ this.lastEntryHash = entryHash;
130
+ if (this.filePath) {
131
+ fs2.appendFileSync(
132
+ this.filePath,
133
+ `${JSON.stringify(fullEntry)}
134
+ `,
135
+ "utf8"
136
+ );
137
+ }
138
+ return fullEntry;
139
+ }
140
+ getEntries() {
141
+ return [...this.entries];
142
+ }
143
+ getEntryCount() {
144
+ return this.entries.length;
145
+ }
146
+ verifyIntegrity() {
147
+ let expectedPrevHash = GENESIS_HASH;
148
+ for (let i = 0; i < this.entries.length; i++) {
149
+ const entry = this.entries[i];
150
+ if (entry.prevEntryHash !== expectedPrevHash) {
151
+ return {
152
+ valid: false,
153
+ totalEntries: this.entries.length,
154
+ brokenIndex: i,
155
+ reason: `Broken hash chain at index ${i}: expected prevHash ${expectedPrevHash}, got ${entry.prevEntryHash}`
156
+ };
157
+ }
158
+ const { entryHash, ...withoutHash } = entry;
159
+ const recalculated = computeEntryHash(withoutHash);
160
+ if (recalculated !== entryHash) {
161
+ return {
162
+ valid: false,
163
+ totalEntries: this.entries.length,
164
+ brokenIndex: i,
165
+ reason: `Tampered entry at index ${i}: hash mismatch (expected ${recalculated}, stored ${entryHash})`
166
+ };
167
+ }
168
+ expectedPrevHash = entryHash;
169
+ }
170
+ return {
171
+ valid: true,
172
+ totalEntries: this.entries.length
173
+ };
174
+ }
175
+ exportJsonl() {
176
+ return this.entries.map((e) => JSON.stringify(e)).join("\n");
177
+ }
178
+ loadFromFile(path2) {
179
+ const content = fs2.readFileSync(path2, "utf8");
180
+ const lines = content.split("\n").filter((l) => l.trim().length > 0);
181
+ for (const line of lines) {
182
+ const entry = JSON.parse(line);
183
+ this.entries.push(entry);
184
+ this.lastEntryHash = entry.entryHash;
185
+ }
186
+ }
64
187
  };
188
+ var globalAuditLogger = new AuditLogger();
65
189
 
66
190
  // src/security/auth-config.ts
67
191
  var AUTH_DEFAULTS = {
@@ -206,10 +330,10 @@ var JwtValidator = class {
206
330
  }
207
331
  };
208
332
  function createOAuthServer(config) {
209
- const { privateKey, publicKey } = crypto2.generateKeyPairSync("ed25519");
333
+ const { privateKey, publicKey } = crypto3__default.generateKeyPairSync("ed25519");
210
334
  const privateJwk = privateKey.export({ format: "jwk" });
211
335
  const publicJwk = publicKey.export({ format: "jwk" });
212
- const kid = crypto2.createHash("sha256").update(publicJwk.x || "").digest("hex").slice(0, 16);
336
+ const kid = crypto3__default.createHash("sha256").update(publicJwk.x || "").digest("hex").slice(0, 16);
213
337
  const privateJwkComplete = {
214
338
  ...privateJwk,
215
339
  kid,
@@ -286,7 +410,7 @@ function createOAuthServer(config) {
286
410
  },
287
411
  // Allow HTTP locally for development/Docker testnets (production MUST use HTTPS in proxy)
288
412
  cookies: {
289
- keys: [crypto2.randomBytes(32).toString("hex")]
413
+ keys: [crypto3__default.randomBytes(32).toString("hex")]
290
414
  },
291
415
  // Map scopes directly into the JWT token claims during client_credentials grant
292
416
  extraTokenClaims: (_ctx, token) => {
@@ -1133,54 +1257,6 @@ var NerScanner = class _NerScanner {
1133
1257
  }
1134
1258
  };
1135
1259
 
1136
- // src/server/output-sanitizer.ts
1137
- var DEFAULT_CONFIG = {
1138
- maxDecimalPlaces: 4,
1139
- clampNonNegative: true
1140
- };
1141
- function sanitizeOutput(output, config) {
1142
- const merged = { ...DEFAULT_CONFIG, ...config };
1143
- const seen = /* @__PURE__ */ new WeakSet();
1144
- function walk(node) {
1145
- if (node === null || node === void 0) {
1146
- return node;
1147
- }
1148
- if (typeof node === "number") {
1149
- if (!Number.isFinite(node)) {
1150
- return node;
1151
- }
1152
- let value = node;
1153
- if (merged.clampNonNegative && value < 0) {
1154
- value = 0;
1155
- }
1156
- const factor = 10 ** merged.maxDecimalPlaces;
1157
- value = Math.round(value * factor) / factor;
1158
- return value;
1159
- }
1160
- if (typeof node === "string" || typeof node === "boolean") {
1161
- return node;
1162
- }
1163
- if (typeof node === "object") {
1164
- if (seen.has(node)) {
1165
- return node;
1166
- }
1167
- seen.add(node);
1168
- if (Array.isArray(node)) {
1169
- return node.map((item) => walk(item));
1170
- }
1171
- const result = {};
1172
- for (const [key, val] of Object.entries(
1173
- node
1174
- )) {
1175
- result[key] = walk(val);
1176
- }
1177
- return result;
1178
- }
1179
- return node;
1180
- }
1181
- return walk(output);
1182
- }
1183
-
1184
1260
  // src/server/pii.ts
1185
1261
  function isLuhnValid(cardNumber) {
1186
1262
  const digits = cardNumber.replace(/\D/g, "");
@@ -1610,6 +1686,7 @@ var LiopServer = class _LiopServer {
1610
1686
  ];
1611
1687
  const sensitiveKeys = this.config?.security?.sensitiveKeys ?? [];
1612
1688
  this.taintAnalyzer = new TaintAnalyzer(forbiddenKeys, sensitiveKeys);
1689
+ this.auditLogger = this.config?.auditLogger || globalAuditLogger;
1613
1690
  const isTS = import.meta.url.endsWith(".ts");
1614
1691
  const workerExt = isTS ? ".ts" : ".js";
1615
1692
  let execArgv = [];
@@ -1635,7 +1712,7 @@ var LiopServer = class _LiopServer {
1635
1712
  path.resolve(__dirname2, `../workers/logic-execution${workerExt}`)
1636
1713
  // Original src/
1637
1714
  ];
1638
- const workerFilename = workerPaths.find((p) => fs.existsSync(p)) || workerPaths[1];
1715
+ const workerFilename = workerPaths.find((p) => fs2.existsSync(p)) || workerPaths[1];
1639
1716
  this.workerPool = new Piscina({
1640
1717
  filename: workerFilename,
1641
1718
  minThreads: this.config?.workerPool?.minThreads ?? (isTest ? 0 : 2),
@@ -1730,10 +1807,16 @@ var LiopServer = class _LiopServer {
1730
1807
  sessions = /* @__PURE__ */ new Map();
1731
1808
  revokedTokenHashes = /* @__PURE__ */ new Set();
1732
1809
  lastRevocationLoadTime = 0;
1810
+ pqcKeyPair = Dilithium65Wrapper.generateKeyPair();
1811
+ auditLogger;
1812
+ getDatasetHash() {
1813
+ return crypto3__default.createHash("sha256").update(JSON.stringify(this.sandboxRecords || [])).digest("hex");
1814
+ }
1733
1815
  // Compact envelope: @LIOP{target,name}\n<code>\n@END
1734
- static LIOP_COMPACT_REGEX = /@LIOP\{(?<target>[^,}]+)(?:,(?<name>[^}]*))?\}\n(?<logic>[\s\S]*?)\n@END/m;
1816
+ static LIOP_COMPACT_REGEX = /@LIOP\{(?<target>[^,}]+)(?:,\s*(?<name>[^}]*))?\}[\r\n]+(?<logic>[\s\S]*?)[\r\n]+@END/m;
1735
1817
  extractLogic(payload) {
1736
- const compact = payload.match(_LiopServer.LIOP_COMPACT_REGEX);
1818
+ if (!payload || typeof payload !== "string") return null;
1819
+ const compact = payload.trim().match(_LiopServer.LIOP_COMPACT_REGEX);
1737
1820
  return compact?.groups?.logic ? compact.groups.logic.trim() : null;
1738
1821
  }
1739
1822
  parseUnknownJson(input) {
@@ -1780,6 +1863,9 @@ var LiopServer = class _LiopServer {
1780
1863
  }
1781
1864
  const extractedFields = this.taintAnalyzer.extractQueriedFields(logic);
1782
1865
  if (extractedFields.length > 0) {
1866
+ if (clientId === "__proto__" || clientId === "constructor" || clientId === "prototype" || _toolName === "__proto__" || _toolName === "constructor" || _toolName === "prototype") {
1867
+ return "Preflight policy rejected: invalid property key names (prototype pollution guard).";
1868
+ }
1783
1869
  const storePath = policy?.budgetStorePath || this.config?.budgetStorePath;
1784
1870
  if (storePath) {
1785
1871
  try {
@@ -2157,7 +2243,7 @@ Data structure: ${schemaDigest}. Full schema: resource liop://schema/global`;
2157
2243
  }
2158
2244
  const payloadValue = args.payload;
2159
2245
  const bypassCache = args.__liop_bypass_ast_cache === true;
2160
- const payloadHash = crypto2.createHash("sha256").update(payloadValue).digest("hex");
2246
+ const payloadHash = crypto3__default.createHash("sha256").update(payloadValue).digest("hex");
2161
2247
  const logic = this.extractLogic(payloadValue);
2162
2248
  const cached = this.logicCache.get(payloadHash);
2163
2249
  if (!bypassCache && cached && now - cached.timestamp < this.CACHE_TTL_MS) {
@@ -2621,7 +2707,7 @@ Data structure: ${schemaDigest}. Full schema: resource ${uri}. Guidelines: resou
2621
2707
  mimeType: r.mimeType,
2622
2708
  text: typeof r.content === "string" ? r.content : r.description
2623
2709
  }));
2624
- return {
2710
+ const unsignedManifest = {
2625
2711
  peerId: meshNodeRef.getPeerId(),
2626
2712
  grpcPort: port,
2627
2713
  tools,
@@ -2635,6 +2721,16 @@ Data structure: ${schemaDigest}. Full schema: resource ${uri}. Guidelines: resou
2635
2721
  executionTypes: this.config.taxonomy.executionTypes || []
2636
2722
  } : void 0
2637
2723
  };
2724
+ const attestation = Dilithium65Wrapper.signManifest(
2725
+ unsignedManifest,
2726
+ this.pqcKeyPair.secretKey,
2727
+ this.pqcKeyPair.publicKey
2728
+ );
2729
+ return {
2730
+ ...unsignedManifest,
2731
+ pqcSignature: attestation.signature,
2732
+ pqcPublicKey: attestation.publicKey
2733
+ };
2638
2734
  });
2639
2735
  for (const tool of this.listTools()) {
2640
2736
  await this.meshNode.announceCapability(tool.name).catch(log.info);
@@ -2657,7 +2753,7 @@ Data structure: ${schemaDigest}. Full schema: resource ${uri}. Guidelines: resou
2657
2753
  return;
2658
2754
  }
2659
2755
  const token = authHeader.startsWith("Bearer ") ? authHeader.slice(7) : authHeader;
2660
- const tokenHash = crypto2.createHash("sha256").update(token).digest("hex").toLowerCase();
2756
+ const tokenHash = crypto3__default.createHash("sha256").update(token).digest("hex").toLowerCase();
2661
2757
  this.loadRevocationList();
2662
2758
  if (this.revokedTokenHashes.has(tokenHash)) {
2663
2759
  callback({
@@ -2676,12 +2772,13 @@ Data structure: ${schemaDigest}. Full schema: resource ${uri}. Guidelines: resou
2676
2772
  import('./kyber-3ULIJSE3.js').then(
2677
2773
  async ({ Kyber768Wrapper }) => {
2678
2774
  const { publicKey, secretKey } = await Kyber768Wrapper.generateKeyPair();
2679
- const sessionToken = crypto2.randomUUID();
2775
+ const sessionToken = crypto3__default.randomUUID();
2680
2776
  this.sessions.set(sessionToken, {
2681
2777
  capability_hash: request.capability_hash,
2682
2778
  kyber_sk: secretKey,
2683
2779
  agent_did: request.agent_did,
2684
- tokenHash
2780
+ tokenHash,
2781
+ createdAt: Date.now()
2685
2782
  });
2686
2783
  callback(null, {
2687
2784
  accepted: true,
@@ -2711,12 +2808,13 @@ Data structure: ${schemaDigest}. Full schema: resource ${uri}. Guidelines: resou
2711
2808
  import('./kyber-3ULIJSE3.js').then(
2712
2809
  async ({ Kyber768Wrapper }) => {
2713
2810
  const { publicKey, secretKey } = await Kyber768Wrapper.generateKeyPair();
2714
- const sessionToken = crypto2.randomUUID();
2811
+ const sessionToken = crypto3__default.randomUUID();
2715
2812
  this.sessions.set(sessionToken, {
2716
2813
  capability_hash: request.capability_hash,
2717
2814
  kyber_sk: secretKey,
2718
2815
  agent_did: request.agent_did,
2719
- tokenHash
2816
+ tokenHash,
2817
+ createdAt: Date.now()
2720
2818
  });
2721
2819
  callback(null, {
2722
2820
  accepted: true,
@@ -2735,11 +2833,12 @@ Data structure: ${schemaDigest}. Full schema: resource ${uri}. Guidelines: resou
2735
2833
  } else {
2736
2834
  import('./kyber-3ULIJSE3.js').then(async ({ Kyber768Wrapper }) => {
2737
2835
  const { publicKey, secretKey } = await Kyber768Wrapper.generateKeyPair();
2738
- const sessionToken = crypto2.randomUUID();
2836
+ const sessionToken = crypto3__default.randomUUID();
2739
2837
  this.sessions.set(sessionToken, {
2740
2838
  capability_hash: request.capability_hash,
2741
2839
  kyber_sk: secretKey,
2742
- agent_did: request.agent_did
2840
+ agent_did: request.agent_did,
2841
+ createdAt: Date.now()
2743
2842
  });
2744
2843
  callback(null, {
2745
2844
  accepted: true,
@@ -2764,6 +2863,18 @@ Data structure: ${schemaDigest}. Full schema: resource ${uri}. Guidelines: resou
2764
2863
  });
2765
2864
  return;
2766
2865
  }
2866
+ const MAX_SESSION_KEY_LIFETIME_MS = 3600 * 1e3;
2867
+ if (session.createdAt) {
2868
+ const sessionAge = Date.now() - session.createdAt;
2869
+ if (sessionAge > MAX_SESSION_KEY_LIFETIME_MS) {
2870
+ this.sessions.delete(request.session_token);
2871
+ call.emit("error", {
2872
+ code: grpc2.status.UNAUTHENTICATED,
2873
+ details: `[LIOP-PQC] Session secret expired: Age (${Math.round(sessionAge / 1e3)}s) exceeds 3600s TTL limit. Re-handshake required.`
2874
+ });
2875
+ return;
2876
+ }
2877
+ }
2767
2878
  if (session.tokenHash) {
2768
2879
  this.loadRevocationList();
2769
2880
  if (this.revokedTokenHashes.has(session.tokenHash)) {
@@ -2787,7 +2898,7 @@ Data structure: ${schemaDigest}. Full schema: resource ${uri}. Guidelines: resou
2787
2898
  const wasmBuffer = Buffer.from(request.wasm_binary);
2788
2899
  const authTag = wasmBuffer.subarray(-16);
2789
2900
  const encryptedData = wasmBuffer.subarray(0, -16);
2790
- const decipher = crypto2.createDecipheriv(
2901
+ const decipher = crypto3__default.createDecipheriv(
2791
2902
  "aes-256-gcm",
2792
2903
  aesKey,
2793
2904
  Buffer.from(request.aes_nonce || new Uint8Array(12))
@@ -2839,6 +2950,7 @@ Data structure: ${schemaDigest}. Full schema: resource ${uri}. Guidelines: resou
2839
2950
  aesNonce: request.aes_nonce,
2840
2951
  records: this.sandboxRecords,
2841
2952
  sessionToken: request.session_token,
2953
+ sessionTimestamp: session.createdAt,
2842
2954
  isEncrypted: true,
2843
2955
  dpConfig
2844
2956
  // Apply DP noise inside worker before ZK-Receipt commitment
@@ -2920,14 +3032,36 @@ Data structure: ${schemaDigest}. Full schema: resource ${uri}. Guidelines: resou
2920
3032
  toolPolicy?.enforceAggregationFirst,
2921
3033
  this.sandboxRecords?.length
2922
3034
  );
2923
- if (violation || aggregationViolation) {
3035
+ const isBlocked = Boolean(violation || aggregationViolation);
3036
+ if (isBlocked) {
2924
3037
  const internalReason = violation || "Aggregation-First Policy Violation";
2925
3038
  log.info(
2926
3039
  `[LIOP-RPC] Secure egress blocked in gRPC stream: ${internalReason}`
2927
3040
  );
2928
3041
  response.semantic_evidence = "[LIOP] Egress Security Violation. Output blocked due to policy enforcement.";
2929
3042
  response.is_error = true;
3043
+ egressBlocksTotal.inc({
3044
+ reason: violation ? "pii_scanner" : "aggregation_policy"
3045
+ });
2930
3046
  }
3047
+ this.auditLogger.recordExecution({
3048
+ agentDid: session.agent_did || "unknown",
3049
+ peerId: session.tokenHash || "unknown",
3050
+ toolName: toolName || "unknown",
3051
+ datasetHash: this.getDatasetHash(),
3052
+ fuelConsumed: workerResponse.fuel_consumed || 0,
3053
+ outputHash: crypto3__default.createHash("sha256").update(response.semantic_evidence).digest("hex"),
3054
+ zkReceiptSig: workerResponse.zk_receipt || "",
3055
+ status: isBlocked ? "BLOCKED_EGRESS" : "SUCCESS"
3056
+ });
3057
+ toolCallsTotal.inc({
3058
+ tool: toolName || "unknown",
3059
+ status: isBlocked ? "blocked_egress" : "success"
3060
+ });
3061
+ fuelConsumed.observe(
3062
+ { tool: toolName || "unknown" },
3063
+ workerResponse.fuel_consumed || 0
3064
+ );
2931
3065
  call.write(response, () => {
2932
3066
  call.end();
2933
3067
  });
@@ -2937,6 +3071,20 @@ Data structure: ${schemaDigest}. Full schema: resource ${uri}. Guidelines: resou
2937
3071
  const detail = e.message || String(error);
2938
3072
  log.error(`[LIOP-RPC] Execution Error: ${detail}`);
2939
3073
  const errorMessage = isDev ? `Execution Error: ${detail}` : "[LIOP] Execution Failed. The injected logic violated runtime constraints or encountered a fatal error.";
3074
+ this.auditLogger.recordExecution({
3075
+ agentDid: session.agent_did || "unknown",
3076
+ peerId: session.tokenHash || "unknown",
3077
+ toolName: toolName || "unknown",
3078
+ datasetHash: this.getDatasetHash(),
3079
+ fuelConsumed: 0,
3080
+ outputHash: crypto3__default.createHash("sha256").update(errorMessage).digest("hex"),
3081
+ zkReceiptSig: "",
3082
+ status: "ERROR"
3083
+ });
3084
+ toolCallsTotal.inc({
3085
+ tool: toolName || "unknown",
3086
+ status: "error"
3087
+ });
2940
3088
  const errorResponse = {
2941
3089
  semantic_evidence: errorMessage,
2942
3090
  cryptographic_proof: Buffer.from(""),
@@ -2962,7 +3110,7 @@ Data structure: ${schemaDigest}. Full schema: resource ${uri}. Guidelines: resou
2962
3110
  return;
2963
3111
  }
2964
3112
  const token = authHeader.startsWith("Bearer ") ? authHeader.slice(7) : authHeader;
2965
- const tokenHash = crypto2.createHash("sha256").update(token).digest("hex").toLowerCase();
3113
+ const tokenHash = crypto3__default.createHash("sha256").update(token).digest("hex").toLowerCase();
2966
3114
  this.loadRevocationList();
2967
3115
  if (this.revokedTokenHashes.has(tokenHash)) {
2968
3116
  call.emit("error", {
@@ -3137,12 +3285,12 @@ Data structure: ${schemaDigest}. Full schema: resource ${uri}. Guidelines: resou
3137
3285
  const rPath = this.config?.auth?.revocationPath;
3138
3286
  if (!rPath) return;
3139
3287
  try {
3140
- if (fs.existsSync(rPath)) {
3141
- const stats = fs.statSync(rPath);
3288
+ if (fs2.existsSync(rPath)) {
3289
+ const stats = fs2.statSync(rPath);
3142
3290
  if (stats.mtimeMs <= this.lastRevocationLoadTime) {
3143
3291
  return;
3144
3292
  }
3145
- const content = fs.readFileSync(rPath, "utf-8");
3293
+ const content = fs2.readFileSync(rPath, "utf-8");
3146
3294
  const list = JSON.parse(content);
3147
3295
  if (Array.isArray(list)) {
3148
3296
  this.revokedTokenHashes.clear();
@@ -3158,10 +3306,10 @@ Data structure: ${schemaDigest}. Full schema: resource ${uri}. Guidelines: resou
3158
3306
  }
3159
3307
  } else {
3160
3308
  const dir = path.dirname(rPath);
3161
- if (!fs.existsSync(dir)) {
3162
- fs.mkdirSync(dir, { recursive: true });
3309
+ if (!fs2.existsSync(dir)) {
3310
+ fs2.mkdirSync(dir, { recursive: true });
3163
3311
  }
3164
- fs.writeFileSync(rPath, JSON.stringify([], null, 2), "utf-8");
3312
+ fs2.writeFileSync(rPath, JSON.stringify([], null, 2), "utf-8");
3165
3313
  this.lastRevocationLoadTime = Date.now();
3166
3314
  log.info(
3167
3315
  `[LiopServer] Created empty local revocation list at ${rPath}`
@@ -3175,7 +3323,7 @@ Data structure: ${schemaDigest}. Full schema: resource ${uri}. Guidelines: resou
3175
3323
  }
3176
3324
  revokeToken(token) {
3177
3325
  if (!token) return;
3178
- const hash = crypto2.createHash("sha256").update(token).digest("hex").toLowerCase();
3326
+ const hash = crypto3__default.createHash("sha256").update(token).digest("hex").toLowerCase();
3179
3327
  this.revokeTokenHash(hash);
3180
3328
  }
3181
3329
  revokeTokenHash(hash) {
@@ -3187,12 +3335,12 @@ Data structure: ${schemaDigest}. Full schema: resource ${uri}. Guidelines: resou
3187
3335
  if (rPath) {
3188
3336
  try {
3189
3337
  const dir = path.dirname(rPath);
3190
- if (!fs.existsSync(dir)) {
3191
- fs.mkdirSync(dir, { recursive: true });
3338
+ if (!fs2.existsSync(dir)) {
3339
+ fs2.mkdirSync(dir, { recursive: true });
3192
3340
  }
3193
3341
  const hashes = Array.from(this.revokedTokenHashes);
3194
- fs.writeFileSync(rPath, JSON.stringify(hashes, null, 2), "utf-8");
3195
- const stats = fs.statSync(rPath);
3342
+ fs2.writeFileSync(rPath, JSON.stringify(hashes, null, 2), "utf-8");
3343
+ const stats = fs2.statSync(rPath);
3196
3344
  this.lastRevocationLoadTime = stats.mtimeMs;
3197
3345
  log.info(
3198
3346
  `[LiopServer] Persisted revocation for hash ${normalizedHash} to ${rPath}`
@@ -3213,6 +3361,12 @@ Data structure: ${schemaDigest}. Full schema: resource ${uri}. Guidelines: resou
3213
3361
  * Uses file-level locking for safe concurrent access.
3214
3362
  */
3215
3363
  resetFieldBudget(clientId, toolName) {
3364
+ if (clientId === "__proto__" || clientId === "constructor" || clientId === "prototype" || toolName && (toolName === "__proto__" || toolName === "constructor" || toolName === "prototype")) {
3365
+ log.warn(
3366
+ `[LiopServer] Blocked resetFieldBudget call due to prototype pollution keys.`
3367
+ );
3368
+ return;
3369
+ }
3216
3370
  if (toolName) {
3217
3371
  const clientBudget = this.fieldQueryBudget.get(clientId);
3218
3372
  if (clientBudget) {
@@ -3246,10 +3400,10 @@ Data structure: ${schemaDigest}. Full schema: resource ${uri}. Guidelines: resou
3246
3400
  }
3247
3401
  getPersistentBudget(storePath) {
3248
3402
  try {
3249
- if (!fs.existsSync(storePath)) {
3403
+ if (!fs2.existsSync(storePath)) {
3250
3404
  return {};
3251
3405
  }
3252
- const content = fs.readFileSync(storePath, "utf-8");
3406
+ const content = fs2.readFileSync(storePath, "utf-8");
3253
3407
  return JSON.parse(content || "{}");
3254
3408
  } catch {
3255
3409
  return {};
@@ -3258,26 +3412,26 @@ Data structure: ${schemaDigest}. Full schema: resource ${uri}. Guidelines: resou
3258
3412
  savePersistentBudget(storePath, budget) {
3259
3413
  const tempPath = `${storePath}.tmp`;
3260
3414
  const dir = path.dirname(storePath);
3261
- if (!fs.existsSync(dir)) {
3262
- fs.mkdirSync(dir, { recursive: true });
3415
+ if (!fs2.existsSync(dir)) {
3416
+ fs2.mkdirSync(dir, { recursive: true });
3263
3417
  }
3264
- fs.writeFileSync(tempPath, JSON.stringify(budget, null, 2), "utf-8");
3265
- fs.renameSync(tempPath, storePath);
3418
+ fs2.writeFileSync(tempPath, JSON.stringify(budget, null, 2), "utf-8");
3419
+ fs2.renameSync(tempPath, storePath);
3266
3420
  }
3267
3421
  executeWithBudgetLock(storePath, action) {
3268
3422
  const lockPath = `${storePath}.lock`;
3269
3423
  const maxRetries = 100;
3270
3424
  let attempts = 0;
3271
3425
  const dir = path.dirname(storePath);
3272
- if (!fs.existsSync(dir)) {
3426
+ if (!fs2.existsSync(dir)) {
3273
3427
  try {
3274
- fs.mkdirSync(dir, { recursive: true });
3428
+ fs2.mkdirSync(dir, { recursive: true });
3275
3429
  } catch {
3276
3430
  }
3277
3431
  }
3278
3432
  while (attempts < maxRetries) {
3279
3433
  try {
3280
- fs.writeFileSync(lockPath, process.pid.toString(), { flag: "wx" });
3434
+ fs2.writeFileSync(lockPath, process.pid.toString(), { flag: "wx" });
3281
3435
  break;
3282
3436
  } catch (e) {
3283
3437
  if (e && typeof e === "object" && "code" in e && e.code === "EEXIST") {
@@ -3301,8 +3455,8 @@ Data structure: ${schemaDigest}. Full schema: resource ${uri}. Guidelines: resou
3301
3455
  return result;
3302
3456
  } finally {
3303
3457
  try {
3304
- if (fs.existsSync(lockPath)) {
3305
- fs.unlinkSync(lockPath);
3458
+ if (fs2.existsSync(lockPath)) {
3459
+ fs2.unlinkSync(lockPath);
3306
3460
  }
3307
3461
  } catch {
3308
3462
  }
@@ -3349,6 +3503,6 @@ Data structure: ${schemaDigest}. Full schema: resource ${uri}. Guidelines: resou
3349
3503
  }
3350
3504
  };
3351
3505
 
3352
- export { AUTH_DEFAULTS, JwtValidator, LiopRpcServer, LiopServer, NerScanner, PII_PATTERNS, PII_PRESETS, PiiScanner, createOAuthServer, sanitizeOutput };
3353
- //# sourceMappingURL=chunk-2JLG4DET.js.map
3354
- //# sourceMappingURL=chunk-2JLG4DET.js.map
3506
+ export { AUTH_DEFAULTS, AuditLogger, GENESIS_HASH, JwtValidator, LiopRpcServer, LiopServer, NerScanner, PII_PATTERNS, PII_PRESETS, PiiScanner, computeEntryHash, createOAuthServer, globalAuditLogger };
3507
+ //# sourceMappingURL=chunk-UBOQZVV5.js.map
3508
+ //# sourceMappingURL=chunk-UBOQZVV5.js.map