@nexart/ai-execution 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -48,8 +48,12 @@ __export(src_exports, {
48
48
  getAttestationReceipt: () => getAttestationReceipt,
49
49
  hasAttestation: () => hasAttestation,
50
50
  hashCanonicalJson: () => hashCanonicalJson,
51
+ hashToolOutput: () => hashToolOutput,
51
52
  hashUtf8: () => hashUtf8,
52
53
  importCer: () => importCer,
54
+ makeToolEvent: () => makeToolEvent,
55
+ mapToAiefReason: () => mapToAiefReason,
56
+ redactBeforeSeal: () => redactBeforeSeal,
53
57
  sanitizeForAttestation: () => sanitizeForAttestation,
54
58
  sanitizeForStamp: () => sanitizeForStamp,
55
59
  sanitizeForStorage: () => sanitizeForStorage,
@@ -57,10 +61,13 @@ __export(src_exports, {
57
61
  selectNodeKey: () => selectNodeKey,
58
62
  sha256Hex: () => sha256Hex,
59
63
  toCanonicalJson: () => toCanonicalJson,
64
+ validateProfile: () => validateProfile,
60
65
  verify: () => verifyCer,
66
+ verifyAief: () => verifyAief,
61
67
  verifyBundleAttestation: () => verifyBundleAttestation,
62
68
  verifyCer: () => verifyCer,
63
69
  verifyNodeReceiptSignature: () => verifyNodeReceiptSignature,
70
+ verifyRunSummary: () => verifyRunSummary,
64
71
  verifySnapshot: () => verifySnapshot,
65
72
  wrapProvider: () => wrapProvider
66
73
  });
@@ -80,7 +87,13 @@ var CerVerifyCode = {
80
87
  ATTESTATION_MISSING: "ATTESTATION_MISSING",
81
88
  ATTESTATION_KEY_NOT_FOUND: "ATTESTATION_KEY_NOT_FOUND",
82
89
  ATTESTATION_INVALID_SIGNATURE: "ATTESTATION_INVALID_SIGNATURE",
83
- ATTESTATION_KEY_FORMAT_UNSUPPORTED: "ATTESTATION_KEY_FORMAT_UNSUPPORTED"
90
+ ATTESTATION_KEY_FORMAT_UNSUPPORTED: "ATTESTATION_KEY_FORMAT_UNSUPPORTED",
91
+ // v0.7.0 — Level 4 + AIEF interop codes
92
+ CHAIN_BREAK_DETECTED: "CHAIN_BREAK_DETECTED",
93
+ INCOMPLETE_ARTIFACT: "INCOMPLETE_ARTIFACT",
94
+ VERIFICATION_MATERIAL_UNAVAILABLE: "VERIFICATION_MATERIAL_UNAVAILABLE",
95
+ TOOL_EVIDENCE_MISSING: "TOOL_EVIDENCE_MISSING",
96
+ TOOL_OUTPUT_HASH_MISMATCH: "TOOL_OUTPUT_HASH_MISMATCH"
84
97
  };
85
98
 
86
99
  // src/errors.ts
@@ -176,7 +189,7 @@ function computeOutputHash(output) {
176
189
  }
177
190
 
178
191
  // src/snapshot.ts
179
- var PACKAGE_VERSION = "0.6.0";
192
+ var PACKAGE_VERSION = "0.7.0";
180
193
  function validateParameters(params) {
181
194
  const errors = [];
182
195
  if (typeof params.temperature !== "number" || !Number.isFinite(params.temperature)) {
@@ -229,6 +242,9 @@ function createSnapshot(params) {
229
242
  if (params.workflowId !== void 0) snapshot.workflowId = params.workflowId ?? null;
230
243
  if (params.conversationId !== void 0) snapshot.conversationId = params.conversationId ?? null;
231
244
  if (params.prevStepHash !== void 0) snapshot.prevStepHash = params.prevStepHash ?? null;
245
+ if (params.toolCalls !== void 0 && params.toolCalls.length > 0) {
246
+ snapshot.toolCalls = params.toolCalls;
247
+ }
232
248
  return snapshot;
233
249
  }
234
250
  function verifySnapshot(snapshot) {
@@ -336,6 +352,9 @@ function sealCer(snapshot, options) {
336
352
  if (options?.meta) {
337
353
  bundle.meta = options.meta;
338
354
  }
355
+ if (options?.declaration) {
356
+ bundle.declaration = options.declaration;
357
+ }
339
358
  return bundle;
340
359
  }
341
360
  function verifyCer(bundle) {
@@ -2150,6 +2169,322 @@ function createClient(defaults = {}) {
2150
2169
  }
2151
2170
  };
2152
2171
  }
2172
+
2173
+ // src/aief.ts
2174
+ var AIEF_REASON_MAP = {
2175
+ [CerVerifyCode.OK]: "ok",
2176
+ [CerVerifyCode.CERTIFICATE_HASH_MISMATCH]: "integrityProofMismatch",
2177
+ [CerVerifyCode.SNAPSHOT_HASH_MISMATCH]: "integrityProofMismatch",
2178
+ [CerVerifyCode.INPUT_HASH_MISMATCH]: "integrityProofMismatch",
2179
+ [CerVerifyCode.OUTPUT_HASH_MISMATCH]: "integrityProofMismatch",
2180
+ [CerVerifyCode.TOOL_OUTPUT_HASH_MISMATCH]: "integrityProofMismatch",
2181
+ [CerVerifyCode.SCHEMA_ERROR]: "unsupportedSchema",
2182
+ [CerVerifyCode.CANONICALIZATION_ERROR]: "malformedArtifact",
2183
+ [CerVerifyCode.INVALID_SHA256_FORMAT]: "malformedArtifact",
2184
+ [CerVerifyCode.UNKNOWN_ERROR]: "malformedArtifact",
2185
+ [CerVerifyCode.INCOMPLETE_ARTIFACT]: "incompleteArtifact",
2186
+ [CerVerifyCode.CHAIN_BREAK_DETECTED]: "chainBreakDetected",
2187
+ [CerVerifyCode.VERIFICATION_MATERIAL_UNAVAILABLE]: "verificationMaterialUnavailable",
2188
+ [CerVerifyCode.TOOL_EVIDENCE_MISSING]: "incompleteArtifact",
2189
+ [CerVerifyCode.ATTESTATION_INVALID_SIGNATURE]: "signatureInvalid",
2190
+ [CerVerifyCode.ATTESTATION_MISSING]: "verificationMaterialUnavailable",
2191
+ [CerVerifyCode.ATTESTATION_KEY_NOT_FOUND]: "verificationMaterialUnavailable",
2192
+ [CerVerifyCode.ATTESTATION_KEY_FORMAT_UNSUPPORTED]: "verificationMaterialUnavailable"
2193
+ };
2194
+ var INTEGRITY_FAILURE_CODES = /* @__PURE__ */ new Set([
2195
+ CerVerifyCode.CERTIFICATE_HASH_MISMATCH,
2196
+ CerVerifyCode.SNAPSHOT_HASH_MISMATCH,
2197
+ CerVerifyCode.INPUT_HASH_MISMATCH,
2198
+ CerVerifyCode.OUTPUT_HASH_MISMATCH,
2199
+ CerVerifyCode.TOOL_OUTPUT_HASH_MISMATCH
2200
+ ]);
2201
+ var SCHEMA_FAILURE_CODES = /* @__PURE__ */ new Set([
2202
+ CerVerifyCode.SCHEMA_ERROR,
2203
+ CerVerifyCode.CANONICALIZATION_ERROR,
2204
+ CerVerifyCode.INVALID_SHA256_FORMAT,
2205
+ CerVerifyCode.UNKNOWN_ERROR,
2206
+ CerVerifyCode.INCOMPLETE_ARTIFACT
2207
+ ]);
2208
+ function mapToAiefReason(code) {
2209
+ return AIEF_REASON_MAP[code] ?? "malformedArtifact";
2210
+ }
2211
+ function verifyAief(bundle) {
2212
+ const inner = verifyCer(bundle);
2213
+ if (inner.ok) {
2214
+ return {
2215
+ result: "PASS",
2216
+ reason: null,
2217
+ checks: {
2218
+ schemaSupported: true,
2219
+ integrityValid: true,
2220
+ protectedSetValid: true,
2221
+ chainValid: true
2222
+ }
2223
+ };
2224
+ }
2225
+ const aiefReason = mapToAiefReason(inner.code);
2226
+ const isIntegrityFailure = INTEGRITY_FAILURE_CODES.has(inner.code);
2227
+ const isSchemaFailure = SCHEMA_FAILURE_CODES.has(inner.code);
2228
+ const isChainFailure = inner.code === CerVerifyCode.CHAIN_BREAK_DETECTED;
2229
+ const result = {
2230
+ result: "FAIL",
2231
+ reason: aiefReason,
2232
+ checks: {
2233
+ schemaSupported: !isSchemaFailure,
2234
+ integrityValid: !isIntegrityFailure,
2235
+ protectedSetValid: !isIntegrityFailure,
2236
+ chainValid: !isChainFailure
2237
+ }
2238
+ };
2239
+ if (inner.details && inner.details.length > 0) {
2240
+ result.notes = inner.details;
2241
+ } else if (inner.errors.length > 0) {
2242
+ result.notes = inner.errors;
2243
+ }
2244
+ return result;
2245
+ }
2246
+
2247
+ // src/tools.ts
2248
+ function hashToolOutput(value) {
2249
+ if (typeof value === "string") {
2250
+ return hashUtf8(value);
2251
+ }
2252
+ return hashCanonicalJson(value);
2253
+ }
2254
+ function makeToolEvent(params) {
2255
+ const at = params.at ?? (/* @__PURE__ */ new Date()).toISOString();
2256
+ const outputHash = hashToolOutput(params.output);
2257
+ const event = {
2258
+ toolId: params.toolId,
2259
+ at,
2260
+ outputHash
2261
+ };
2262
+ if (params.input !== void 0) {
2263
+ event.inputHash = hashToolOutput(params.input);
2264
+ }
2265
+ if (params.evidenceRef !== void 0) {
2266
+ event.evidenceRef = params.evidenceRef;
2267
+ }
2268
+ if (params.error !== void 0) {
2269
+ event.error = params.error;
2270
+ }
2271
+ return event;
2272
+ }
2273
+
2274
+ // src/chain.ts
2275
+ function verifyRunSummary(summary, bundles, opts) {
2276
+ if (bundles.length !== summary.stepCount) {
2277
+ return {
2278
+ ok: false,
2279
+ code: CerVerifyCode.INCOMPLETE_ARTIFACT,
2280
+ errors: [
2281
+ `Step count mismatch: summary declares ${summary.stepCount} step(s), received ${bundles.length}`
2282
+ ],
2283
+ details: ["Possible step deletion or insertion"]
2284
+ };
2285
+ }
2286
+ if (bundles.length === 0) {
2287
+ return { ok: true, code: CerVerifyCode.OK, errors: [] };
2288
+ }
2289
+ let prevHash = null;
2290
+ for (let i = 0; i < bundles.length; i++) {
2291
+ const bundle = bundles[i];
2292
+ const summaryStep = summary.steps[i];
2293
+ if (!summaryStep) {
2294
+ return {
2295
+ ok: false,
2296
+ code: CerVerifyCode.INCOMPLETE_ARTIFACT,
2297
+ errors: [`Missing summary entry for step index ${i}`],
2298
+ breakAt: i
2299
+ };
2300
+ }
2301
+ if (!opts?.skipBundleVerification) {
2302
+ const bundleResult = verifyCer(bundle);
2303
+ if (!bundleResult.ok) {
2304
+ return {
2305
+ ok: false,
2306
+ code: bundleResult.code,
2307
+ errors: [`Step ${i}: individual bundle verification failed: ${bundleResult.errors.join("; ")}`],
2308
+ details: bundleResult.details,
2309
+ breakAt: i
2310
+ };
2311
+ }
2312
+ }
2313
+ const stepIndex = bundle.snapshot?.stepIndex;
2314
+ if (stepIndex !== i) {
2315
+ return {
2316
+ ok: false,
2317
+ code: CerVerifyCode.CHAIN_BREAK_DETECTED,
2318
+ errors: [`Step ${i}: expected stepIndex ${i}, got ${String(stepIndex)}`],
2319
+ details: ["stepIndex mismatch indicates insertion or reordering"],
2320
+ breakAt: i
2321
+ };
2322
+ }
2323
+ const snapshotPrevHash = bundle.snapshot?.prevStepHash ?? null;
2324
+ if (i === 0) {
2325
+ if (snapshotPrevHash !== null) {
2326
+ return {
2327
+ ok: false,
2328
+ code: CerVerifyCode.CHAIN_BREAK_DETECTED,
2329
+ errors: [`Step 0: expected prevStepHash null, got "${snapshotPrevHash}"`],
2330
+ details: ["First step must have prevStepHash null"],
2331
+ breakAt: 0,
2332
+ expectedPrev: "null",
2333
+ observedPrev: snapshotPrevHash
2334
+ };
2335
+ }
2336
+ } else {
2337
+ if (snapshotPrevHash !== prevHash) {
2338
+ return {
2339
+ ok: false,
2340
+ code: CerVerifyCode.CHAIN_BREAK_DETECTED,
2341
+ errors: [`Step ${i}: prevStepHash mismatch \u2014 chain break detected`],
2342
+ details: [
2343
+ `Expected prevStepHash "${prevHash ?? "null"}", got "${snapshotPrevHash ?? "null"}"`
2344
+ ],
2345
+ breakAt: i,
2346
+ expectedPrev: prevHash ?? void 0,
2347
+ observedPrev: snapshotPrevHash ?? void 0
2348
+ };
2349
+ }
2350
+ }
2351
+ if (bundle.certificateHash !== summaryStep.certificateHash) {
2352
+ return {
2353
+ ok: false,
2354
+ code: CerVerifyCode.CHAIN_BREAK_DETECTED,
2355
+ errors: [`Step ${i}: certificateHash does not match summary record`],
2356
+ details: [
2357
+ `Summary has "${summaryStep.certificateHash}", bundle has "${bundle.certificateHash}"`
2358
+ ],
2359
+ breakAt: i
2360
+ };
2361
+ }
2362
+ prevHash = bundle.certificateHash;
2363
+ }
2364
+ const lastBundle = bundles[bundles.length - 1];
2365
+ if (summary.finalStepHash !== lastBundle.certificateHash) {
2366
+ return {
2367
+ ok: false,
2368
+ code: CerVerifyCode.CHAIN_BREAK_DETECTED,
2369
+ errors: ["summary.finalStepHash does not match last step certificateHash"],
2370
+ details: [
2371
+ `Expected "${summary.finalStepHash ?? "null"}", got "${lastBundle.certificateHash}"`
2372
+ ],
2373
+ breakAt: bundles.length - 1,
2374
+ expectedPrev: summary.finalStepHash ?? void 0,
2375
+ observedPrev: lastBundle.certificateHash
2376
+ };
2377
+ }
2378
+ return { ok: true, code: CerVerifyCode.OK, errors: [] };
2379
+ }
2380
+
2381
+ // src/redact.ts
2382
+ function hashValue(value) {
2383
+ if (typeof value === "string") return hashUtf8(value);
2384
+ return hashCanonicalJson(value);
2385
+ }
2386
+ function getNestedValue(obj, path) {
2387
+ const parts = path.split(".");
2388
+ let cursor = obj;
2389
+ for (const part of parts) {
2390
+ if (typeof cursor !== "object" || cursor === null) return void 0;
2391
+ cursor = cursor[part];
2392
+ }
2393
+ return cursor;
2394
+ }
2395
+ function setNestedPath(obj, path, value) {
2396
+ const parts = path.split(".");
2397
+ const clone = { ...obj };
2398
+ let cursor = clone;
2399
+ for (let i = 0; i < parts.length - 1; i++) {
2400
+ const key = parts[i];
2401
+ const child = cursor[key];
2402
+ if (typeof child !== "object" || child === null) return clone;
2403
+ cursor[key] = { ...child };
2404
+ cursor = cursor[key];
2405
+ }
2406
+ const last = parts[parts.length - 1];
2407
+ if (last in cursor) {
2408
+ cursor[last] = value;
2409
+ }
2410
+ return clone;
2411
+ }
2412
+ function redactBeforeSeal(snapshot, policy) {
2413
+ let result = { ...snapshot };
2414
+ for (const path of policy.paths) {
2415
+ const original = getNestedValue(result, path);
2416
+ if (original === void 0) continue;
2417
+ const envelope = {
2418
+ _redacted: true,
2419
+ hash: hashValue(original)
2420
+ };
2421
+ result = setNestedPath(result, path, envelope);
2422
+ if (path === "input") {
2423
+ result["inputHash"] = computeInputHash(envelope);
2424
+ } else if (path === "output") {
2425
+ result["outputHash"] = computeOutputHash(envelope);
2426
+ }
2427
+ }
2428
+ return result;
2429
+ }
2430
+
2431
+ // src/profile.ts
2432
+ var SHA256_PATTERN2 = /^sha256:[0-9a-f]{64}$/;
2433
+ function validateToolEvent(event, index) {
2434
+ const errs = [];
2435
+ if (!event.toolId || typeof event.toolId !== "string") {
2436
+ errs.push(`toolCalls[${index}].toolId must be a non-empty string`);
2437
+ }
2438
+ if (!event.at || typeof event.at !== "string") {
2439
+ errs.push(`toolCalls[${index}].at must be a non-empty ISO 8601 string`);
2440
+ }
2441
+ if (!event.outputHash || !SHA256_PATTERN2.test(event.outputHash)) {
2442
+ errs.push(`toolCalls[${index}].outputHash must be in sha256:<64hex> format, got "${event.outputHash ?? ""}"`);
2443
+ }
2444
+ if (event.inputHash !== void 0 && !SHA256_PATTERN2.test(event.inputHash)) {
2445
+ errs.push(`toolCalls[${index}].inputHash must be in sha256:<64hex> format when present`);
2446
+ }
2447
+ return errs;
2448
+ }
2449
+ function validateL2(snapshot, label) {
2450
+ const errs = [];
2451
+ if (!snapshot.executionId) errs.push(`executionId is required for ${label}`);
2452
+ if (!snapshot.timestamp) errs.push(`timestamp is required for ${label}`);
2453
+ if (!snapshot.provider) errs.push(`provider is required for ${label}`);
2454
+ if (!snapshot.model) errs.push(`model is required for ${label}`);
2455
+ if (snapshot.input === void 0 || snapshot.input === null) errs.push(`input is required for ${label}`);
2456
+ if (snapshot.output === void 0 || snapshot.output === null) errs.push(`output is required for ${label}`);
2457
+ if (!snapshot.inputHash) errs.push(`inputHash is required for ${label}`);
2458
+ if (!snapshot.outputHash) errs.push(`outputHash is required for ${label}`);
2459
+ return errs;
2460
+ }
2461
+ function resolveSnapshot(target) {
2462
+ if ("snapshot" in target && target.snapshot) {
2463
+ return target.snapshot;
2464
+ }
2465
+ return target;
2466
+ }
2467
+ function validateProfile(target, profile) {
2468
+ if (profile === "flexible") {
2469
+ return { ok: true, errors: [] };
2470
+ }
2471
+ const snapshot = resolveSnapshot(target);
2472
+ const errors = [];
2473
+ if (profile === "AIEF_L2" || profile === "AIEF_L3" || profile === "AIEF_L4") {
2474
+ errors.push(...validateL2(snapshot, profile));
2475
+ }
2476
+ if (profile === "AIEF_L4") {
2477
+ if (snapshot.toolCalls && snapshot.toolCalls.length > 0) {
2478
+ for (let i = 0; i < snapshot.toolCalls.length; i++) {
2479
+ errors.push(...validateToolEvent(snapshot.toolCalls[i], i));
2480
+ }
2481
+ }
2482
+ if (snapshot.stepIndex !== null && snapshot.stepIndex !== void 0 && snapshot.stepIndex > 0 && !snapshot.prevStepHash) {
2483
+ errors.push("prevStepHash is required when stepIndex > 0 in AIEF_L4 profile");
2484
+ }
2485
+ }
2486
+ return { ok: errors.length === 0, errors };
2487
+ }
2153
2488
  // Annotate the CommonJS export names for ESM import in node:
2154
2489
  0 && (module.exports = {
2155
2490
  CerAttestationError,
@@ -2170,8 +2505,12 @@ function createClient(defaults = {}) {
2170
2505
  getAttestationReceipt,
2171
2506
  hasAttestation,
2172
2507
  hashCanonicalJson,
2508
+ hashToolOutput,
2173
2509
  hashUtf8,
2174
2510
  importCer,
2511
+ makeToolEvent,
2512
+ mapToAiefReason,
2513
+ redactBeforeSeal,
2175
2514
  sanitizeForAttestation,
2176
2515
  sanitizeForStamp,
2177
2516
  sanitizeForStorage,
@@ -2179,10 +2518,13 @@ function createClient(defaults = {}) {
2179
2518
  selectNodeKey,
2180
2519
  sha256Hex,
2181
2520
  toCanonicalJson,
2521
+ validateProfile,
2182
2522
  verify,
2523
+ verifyAief,
2183
2524
  verifyBundleAttestation,
2184
2525
  verifyCer,
2185
2526
  verifyNodeReceiptSignature,
2527
+ verifyRunSummary,
2186
2528
  verifySnapshot,
2187
2529
  wrapProvider
2188
2530
  });