@nexart/ai-execution 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -7
- package/dist/index.cjs +143 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +215 -3
- package/dist/index.d.ts +215 -3
- package/dist/index.mjs +139 -2
- package/dist/index.mjs.map +1 -1
- package/dist/providers/anthropic.cjs +1 -1
- package/dist/providers/anthropic.cjs.map +1 -1
- package/dist/providers/anthropic.d.cts +1 -1
- package/dist/providers/anthropic.d.ts +1 -1
- package/dist/providers/anthropic.mjs +1 -1
- package/dist/providers/anthropic.mjs.map +1 -1
- package/dist/providers/openai.cjs +1 -1
- package/dist/providers/openai.cjs.map +1 -1
- package/dist/providers/openai.d.cts +1 -1
- package/dist/providers/openai.d.ts +1 -1
- package/dist/providers/openai.mjs +1 -1
- package/dist/providers/openai.mjs.map +1 -1
- package/dist/providers/wrap.cjs +1 -1
- package/dist/providers/wrap.cjs.map +1 -1
- package/dist/providers/wrap.d.cts +1 -1
- package/dist/providers/wrap.d.ts +1 -1
- package/dist/providers/wrap.mjs +1 -1
- package/dist/providers/wrap.mjs.map +1 -1
- package/dist/{types-CcqCDPrD.d.cts → types-C5t12OK8.d.cts} +2 -0
- package/dist/{types-CcqCDPrD.d.ts → types-C5t12OK8.d.ts} +2 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @nexart/ai-execution v0.
|
|
1
|
+
# @nexart/ai-execution v0.8.0
|
|
2
2
|
|
|
3
3
|
Tamper-evident records and Certified Execution Records (CER) for AI operations.
|
|
4
4
|
|
|
@@ -7,7 +7,7 @@ Tamper-evident records and Certified Execution Records (CER) for AI operations.
|
|
|
7
7
|
| Component | Version |
|
|
8
8
|
|---|---|
|
|
9
9
|
| Service | — |
|
|
10
|
-
| SDK | 0.
|
|
10
|
+
| SDK | 0.8.0 |
|
|
11
11
|
| Protocol | 1.2.0 |
|
|
12
12
|
|
|
13
13
|
## Why Not Just Store Logs?
|
|
@@ -147,7 +147,7 @@ const restored = importCer(json); // parse + verify (throws on tamper)
|
|
|
147
147
|
| `modelVersion` | Optional | `string \| null` | Defaults to `null` |
|
|
148
148
|
| `parameters.topP` | Optional | `number \| null` | Defaults to `null` |
|
|
149
149
|
| `parameters.seed` | Optional | `number \| null` | Defaults to `null` |
|
|
150
|
-
| `sdkVersion` | Optional | `string \| null` | Defaults to `"0.
|
|
150
|
+
| `sdkVersion` | Optional | `string \| null` | Defaults to `"0.8.0"` |
|
|
151
151
|
| `appId` | Optional | `string \| null` | Defaults to `null` |
|
|
152
152
|
| `runId` | Optional | `string \| null` | Workflow run ID |
|
|
153
153
|
| `stepId` | Optional | `string \| null` | Step identifier within a run |
|
|
@@ -442,6 +442,49 @@ const result = validateProfile(bundle, 'AIEF_L4');
|
|
|
442
442
|
// { ok: boolean, errors: string[] }
|
|
443
443
|
```
|
|
444
444
|
|
|
445
|
+
## Opinionated Run Helper
|
|
446
|
+
|
|
447
|
+
`certifyAndAttestRun(steps, options?)` combines RunBuilder step creation, optional per-step attestation, and finalization into a single call. It does not change `RunBuilder` semantics — it creates an internal RunBuilder and returns all artifacts together.
|
|
448
|
+
|
|
449
|
+
```typescript
|
|
450
|
+
import { certifyAndAttestRun, verifyRunSummary, attest } from '@nexart/ai-execution';
|
|
451
|
+
|
|
452
|
+
const { runSummary, stepBundles, receipts, finalStepHash } =
|
|
453
|
+
await certifyAndAttestRun(
|
|
454
|
+
[step0Params, step1Params, step2Params],
|
|
455
|
+
{
|
|
456
|
+
runId: 'analysis-run',
|
|
457
|
+
workflowId: 'data-pipeline',
|
|
458
|
+
// Optional: attest each step immediately after sealing
|
|
459
|
+
attestStep: (bundle) => attest(bundle, { nodeUrl, apiKey }),
|
|
460
|
+
},
|
|
461
|
+
);
|
|
462
|
+
|
|
463
|
+
verifyRunSummary(runSummary, stepBundles); // { ok: true }
|
|
464
|
+
```
|
|
465
|
+
|
|
466
|
+
**Return shape:**
|
|
467
|
+
|
|
468
|
+
| Field | Type | Description |
|
|
469
|
+
|---|---|---|
|
|
470
|
+
| `runSummary` | `RunSummary` | From `RunBuilder.finalize()` — stepCount, steps, finalStepHash |
|
|
471
|
+
| `stepBundles` | `CerAiExecutionBundle[]` | Sealed bundles in step order (index 0 = step 0) |
|
|
472
|
+
| `receipts` | `(AttestationReceipt \| null)[]` | Attestation receipts in step order; `null` if `attestStep` was not provided |
|
|
473
|
+
| `finalStepHash` | `string \| null` | Alias for `runSummary.finalStepHash` |
|
|
474
|
+
|
|
475
|
+
**Testing without network:** inject a mock `attestStep` to test the full flow without hitting a node:
|
|
476
|
+
|
|
477
|
+
```typescript
|
|
478
|
+
const { runSummary, stepBundles, receipts } = await certifyAndAttestRun(steps, {
|
|
479
|
+
attestStep: async (bundle) => ({
|
|
480
|
+
attestationId: 'mock-' + bundle.certificateHash.slice(7, 15),
|
|
481
|
+
certificateHash: bundle.certificateHash,
|
|
482
|
+
nodeRuntimeHash: 'sha256:' + 'a'.repeat(64),
|
|
483
|
+
protocolVersion: '1.2.0',
|
|
484
|
+
}),
|
|
485
|
+
});
|
|
486
|
+
```
|
|
487
|
+
|
|
445
488
|
## Redaction Semantics (v0.7.0+)
|
|
446
489
|
|
|
447
490
|
### Pre-seal verifiable redaction
|
|
@@ -467,11 +510,43 @@ Each redacted field becomes `{ _redacted: true, hash: "sha256:..." }` where `has
|
|
|
467
510
|
| `toolCalls[n].output` *(via `ToolEvent.outputHash`)* | **Yes** | The `outputHash` already stores only the hash — the raw tool output need not be in the bundle at all |
|
|
468
511
|
| `prompt` and other schema-validated strings | **No** | `verifySnapshot` validates these as non-empty strings. Replacing with an object envelope causes `verifyCer()` to return `SCHEMA_ERROR`. |
|
|
469
512
|
|
|
470
|
-
###
|
|
513
|
+
### Verifiable redacted export (post-seal, new bundle)
|
|
471
514
|
|
|
472
|
-
`
|
|
515
|
+
`exportVerifiableRedacted(bundle, policy, options?)` is the right choice when you already have a sealed bundle and want to share a sanitized version that is still independently verifiable. It:
|
|
516
|
+
|
|
517
|
+
1. Applies `redactBeforeSeal()` to the original snapshot
|
|
518
|
+
2. Re-seals the redacted snapshot into a **new** bundle with a **new** `certificateHash`
|
|
519
|
+
3. Stores the original `certificateHash` in `meta.provenance.originalCertificateHash` as an informational cross-reference
|
|
520
|
+
|
|
521
|
+
```typescript
|
|
522
|
+
import { certifyDecision, exportVerifiableRedacted, verify } from '@nexart/ai-execution';
|
|
523
|
+
|
|
524
|
+
const original = certifyDecision({ ... });
|
|
525
|
+
|
|
526
|
+
const { bundle, originalCertificateHash } = exportVerifiableRedacted(
|
|
527
|
+
original,
|
|
528
|
+
{ paths: ['input', 'output'] },
|
|
529
|
+
);
|
|
530
|
+
|
|
531
|
+
verify(bundle).ok; // true — new bundle verifies
|
|
532
|
+
bundle.certificateHash !== original.certificateHash; // true — different hash
|
|
533
|
+
bundle.meta.provenance.originalCertificateHash; // 'sha256:...' — reference only
|
|
534
|
+
bundle.snapshot.input; // { _redacted: true, hash: 'sha256:...' }
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
**Provenance semantics:** `meta.provenance.originalCertificateHash` is reference metadata only. It is not part of the new `certificateHash` computation. Recipients of the new bundle cannot verify the original bundle's integrity from it — they can only confirm what hash the original had. If you need to prove the original's integrity, keep the original bundle available alongside the redacted one.
|
|
538
|
+
|
|
539
|
+
**Rule of thumb for choosing a redaction approach:**
|
|
540
|
+
|
|
541
|
+
| Approach | `verify()` passes | Original hash preserved | Notes |
|
|
542
|
+
|---|---|---|---|
|
|
543
|
+
| `redactBeforeSeal(snapshot, policy)` + `sealCer()` | ✅ | N/A — no original exists yet | Use when building a redacted bundle from scratch |
|
|
544
|
+
| `exportVerifiableRedacted(bundle, policy)` | ✅ | Reference only in `meta.provenance` | Use when you have a sealed bundle and need a shareable sanitized copy |
|
|
545
|
+
| `sanitizeForStorage(bundle, options)` | ❌ | N/A — hash broken by design | Use only for storage; do not pass result to `verify()` |
|
|
546
|
+
|
|
547
|
+
### Post-hoc redaction breaks integrity — by design
|
|
473
548
|
|
|
474
|
-
|
|
549
|
+
`sanitizeForStorage(bundle, options)` can replace arbitrary paths with a string placeholder, but it does **not** recompute any content hashes. This means `verifyCer()` will return `CERTIFICATE_HASH_MISMATCH` on the result. This is intentional: post-hoc redaction is a lossy, storage-only operation. If you need a verifiable record after storage-side redaction, use `exportVerifiableRedacted` instead.
|
|
475
550
|
|
|
476
551
|
## Canonical JSON Constraints
|
|
477
552
|
|
|
@@ -515,6 +590,7 @@ Fixtures at `fixtures/vectors/` and `fixtures/golden/`. Cross-language implement
|
|
|
515
590
|
|---|---|
|
|
516
591
|
| `RunBuilder` | Multi-step workflow builder with prevStepHash chaining |
|
|
517
592
|
| `verifyRunSummary(summary, bundles, opts?)` | Verify that a RunSummary + step bundles form an unbroken cryptographic chain (v0.7.0+) |
|
|
593
|
+
| `certifyAndAttestRun(steps, options?)` | One-call: create RunBuilder internally, certify all steps, optionally attest each bundle, return `{ runSummary, stepBundles, receipts, finalStepHash }`. Injectable `attestStep` for mocking. |
|
|
518
594
|
|
|
519
595
|
### AIEF Interop (v0.7.0+)
|
|
520
596
|
|
|
@@ -525,6 +601,7 @@ Fixtures at `fixtures/vectors/` and `fixtures/golden/`. Cross-language implement
|
|
|
525
601
|
| `hashToolOutput(value)` | Hash a tool output value: string → UTF-8 SHA-256; other → canonical JSON SHA-256 |
|
|
526
602
|
| `makeToolEvent(params)` | Build a `ToolEvent` record for inclusion in `snapshot.toolCalls` |
|
|
527
603
|
| `redactBeforeSeal(snapshot, policy)` | Pre-seal redaction: replace `input`/`output` with verifiable envelopes before sealing |
|
|
604
|
+
| `exportVerifiableRedacted(bundle, policy, options?)` | Post-seal: produce a new sealed bundle with redacted snapshot + `meta.provenance.originalCertificateHash`. `verify()` passes on the new bundle. Original is unchanged. |
|
|
528
605
|
| `validateProfile(target, profile)` | Validate a snapshot or bundle against an AIEF strictness profile (does not affect hashing) |
|
|
529
606
|
|
|
530
607
|
### Attestation & Archive
|
|
@@ -607,7 +684,8 @@ Priority when multiple failures exist: `CANONICALIZATION_ERROR` > `SCHEMA_ERROR`
|
|
|
607
684
|
| v0.4.2 | `AttestationReceipt`, `getAttestationReceipt`, `certifyAndAttestDecision`, `attestIfNeeded` |
|
|
608
685
|
| v0.5.0 | Ed25519 signed receipt verification: `verifyNodeReceiptSignature`, `verifyBundleAttestation`, `fetchNodeKeys`, `selectNodeKey`; new attestation `CerVerifyCode` entries; `SPEC.md`; `NodeKeysDocument`, `SignedAttestationReceipt`, `NodeReceiptVerifyResult` types |
|
|
609
686
|
| v0.6.0 | Frictionless integration: `certifyDecisionFromProviderCall` (OpenAI/Anthropic/Gemini/Mistral/Bedrock drop-in); `sanitizeForStorage` + `sanitizeForStamp` redaction helpers; `createClient(defaults)` factory; regression fixture suite; all backward-compatible, no hash changes |
|
|
610
|
-
|
|
|
687
|
+
| v0.7.0 | AIEF alignment: `verifyAief()` (AIEF §9.1 adapter); `verifyRunSummary()` chain verifier; `makeToolEvent()` + `hashToolOutput()` + `snapshot.toolCalls` (AIEF-06); `BundleDeclaration` block (`stabilitySchemeId`, `protectedSetId`, `protectedFields`) excluded from `certificateHash`; `redactBeforeSeal()` pre-seal verifiable redaction; `validateProfile()` (flexible/AIEF_L2/L3/L4); 5 new `CerVerifyCode` entries; backward-compatible, no hash changes |
|
|
688
|
+
| **v0.8.0** | Helper APIs: `exportVerifiableRedacted()` (post-seal re-seal with redacted snapshot + provenance metadata); `certifyAndAttestRun()` (one-call multi-step certify + optional per-step attestation with injectable mock); test determinism fix (no time-dependent first-run failures); all v0.1–v0.7 bundles verify identically, no hashing or canonicalization changes |
|
|
611
689
|
| v1.0.0 | Planned: API stabilization, freeze public API surface |
|
|
612
690
|
|
|
613
691
|
## Releasing
|
package/dist/index.cjs
CHANGED
|
@@ -33,10 +33,12 @@ __export(src_exports, {
|
|
|
33
33
|
CerAttestationError: () => CerAttestationError,
|
|
34
34
|
CerVerificationError: () => CerVerificationError,
|
|
35
35
|
CerVerifyCode: () => CerVerifyCode,
|
|
36
|
+
ReasonCode: () => ReasonCode,
|
|
36
37
|
RunBuilder: () => RunBuilder,
|
|
37
38
|
attest: () => attest,
|
|
38
39
|
attestIfNeeded: () => attestIfNeeded,
|
|
39
40
|
certifyAndAttestDecision: () => certifyAndAttestDecision,
|
|
41
|
+
certifyAndAttestRun: () => certifyAndAttestRun,
|
|
40
42
|
certifyDecision: () => certifyDecision,
|
|
41
43
|
certifyDecisionFromProviderCall: () => certifyDecisionFromProviderCall,
|
|
42
44
|
computeInputHash: () => computeInputHash,
|
|
@@ -44,6 +46,7 @@ __export(src_exports, {
|
|
|
44
46
|
createClient: () => createClient,
|
|
45
47
|
createSnapshot: () => createSnapshot,
|
|
46
48
|
exportCer: () => exportCer,
|
|
49
|
+
exportVerifiableRedacted: () => exportVerifiableRedacted,
|
|
47
50
|
fetchNodeKeys: () => fetchNodeKeys,
|
|
48
51
|
getAttestationReceipt: () => getAttestationReceipt,
|
|
49
52
|
hasAttestation: () => hasAttestation,
|
|
@@ -63,6 +66,7 @@ __export(src_exports, {
|
|
|
63
66
|
toCanonicalJson: () => toCanonicalJson,
|
|
64
67
|
validateProfile: () => validateProfile,
|
|
65
68
|
verify: () => verifyCer,
|
|
69
|
+
verifyAiCerBundleDetailed: () => verifyAiCerBundleDetailed,
|
|
66
70
|
verifyAief: () => verifyAief,
|
|
67
71
|
verifyBundleAttestation: () => verifyBundleAttestation,
|
|
68
72
|
verifyCer: () => verifyCer,
|
|
@@ -189,7 +193,7 @@ function computeOutputHash(output) {
|
|
|
189
193
|
}
|
|
190
194
|
|
|
191
195
|
// src/snapshot.ts
|
|
192
|
-
var PACKAGE_VERSION = "0.
|
|
196
|
+
var PACKAGE_VERSION = "0.8.0";
|
|
193
197
|
function validateParameters(params) {
|
|
194
198
|
const errors = [];
|
|
195
199
|
if (typeof params.temperature !== "number" || !Number.isFinite(params.temperature)) {
|
|
@@ -457,7 +461,7 @@ function certifyDecision(params) {
|
|
|
457
461
|
conversationId: params.conversationId,
|
|
458
462
|
prevStepHash: params.prevStepHash
|
|
459
463
|
});
|
|
460
|
-
return sealCer(snapshot, { meta: params.meta });
|
|
464
|
+
return sealCer(snapshot, { createdAt: params.createdAt, meta: params.meta });
|
|
461
465
|
}
|
|
462
466
|
|
|
463
467
|
// src/run.ts
|
|
@@ -2485,15 +2489,150 @@ function validateProfile(target, profile) {
|
|
|
2485
2489
|
}
|
|
2486
2490
|
return { ok: errors.length === 0, errors };
|
|
2487
2491
|
}
|
|
2492
|
+
|
|
2493
|
+
// src/exportRedacted.ts
|
|
2494
|
+
function exportVerifiableRedacted(bundle, policy, options) {
|
|
2495
|
+
const createdAt = options?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString();
|
|
2496
|
+
const redactedSnapshot = redactBeforeSeal(bundle.snapshot, policy);
|
|
2497
|
+
const provenance = {
|
|
2498
|
+
originalCertificateHash: bundle.certificateHash,
|
|
2499
|
+
redactionPolicy: { paths: [...policy.paths] },
|
|
2500
|
+
redactedAt: createdAt
|
|
2501
|
+
};
|
|
2502
|
+
const mergedMeta = {
|
|
2503
|
+
...bundle.meta,
|
|
2504
|
+
provenance
|
|
2505
|
+
};
|
|
2506
|
+
const newBundle = sealCer(redactedSnapshot, {
|
|
2507
|
+
createdAt,
|
|
2508
|
+
meta: mergedMeta,
|
|
2509
|
+
declaration: bundle.declaration
|
|
2510
|
+
});
|
|
2511
|
+
return {
|
|
2512
|
+
bundle: newBundle,
|
|
2513
|
+
originalCertificateHash: bundle.certificateHash
|
|
2514
|
+
};
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2517
|
+
// src/runHelper.ts
|
|
2518
|
+
async function certifyAndAttestRun(steps, options) {
|
|
2519
|
+
const run = new RunBuilder({
|
|
2520
|
+
runId: options?.runId,
|
|
2521
|
+
workflowId: options?.workflowId,
|
|
2522
|
+
conversationId: options?.conversationId,
|
|
2523
|
+
appId: options?.appId
|
|
2524
|
+
});
|
|
2525
|
+
const stepBundles = [];
|
|
2526
|
+
const receipts = [];
|
|
2527
|
+
for (const stepParams of steps) {
|
|
2528
|
+
const bundle = run.step(stepParams);
|
|
2529
|
+
stepBundles.push(bundle);
|
|
2530
|
+
if (options?.attestStep) {
|
|
2531
|
+
const receipt = await options.attestStep(bundle);
|
|
2532
|
+
receipts.push(receipt);
|
|
2533
|
+
} else {
|
|
2534
|
+
receipts.push(null);
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2537
|
+
const runSummary = run.finalize();
|
|
2538
|
+
return {
|
|
2539
|
+
runSummary,
|
|
2540
|
+
stepBundles,
|
|
2541
|
+
receipts,
|
|
2542
|
+
finalStepHash: runSummary.finalStepHash
|
|
2543
|
+
};
|
|
2544
|
+
}
|
|
2545
|
+
|
|
2546
|
+
// src/cerProtocol.ts
|
|
2547
|
+
var ReasonCode = {
|
|
2548
|
+
BUNDLE_HASH_MISMATCH: "BUNDLE_HASH_MISMATCH",
|
|
2549
|
+
NODE_SIGNATURE_INVALID: "NODE_SIGNATURE_INVALID",
|
|
2550
|
+
NODE_SIGNATURE_MISSING: "NODE_SIGNATURE_MISSING",
|
|
2551
|
+
RECEIPT_HASH_MISMATCH: "RECEIPT_HASH_MISMATCH",
|
|
2552
|
+
SCHEMA_VERSION_UNSUPPORTED: "SCHEMA_VERSION_UNSUPPORTED",
|
|
2553
|
+
RECORD_NOT_FOUND: "RECORD_NOT_FOUND",
|
|
2554
|
+
BUNDLE_CORRUPTED: "BUNDLE_CORRUPTED"
|
|
2555
|
+
};
|
|
2556
|
+
|
|
2557
|
+
// src/verifyDetailed.ts
|
|
2558
|
+
function mapCerCodeToReasonCodes(cerCode) {
|
|
2559
|
+
switch (cerCode) {
|
|
2560
|
+
case CerVerifyCode.CERTIFICATE_HASH_MISMATCH:
|
|
2561
|
+
case CerVerifyCode.SNAPSHOT_HASH_MISMATCH:
|
|
2562
|
+
case CerVerifyCode.INPUT_HASH_MISMATCH:
|
|
2563
|
+
case CerVerifyCode.OUTPUT_HASH_MISMATCH:
|
|
2564
|
+
return [ReasonCode.BUNDLE_HASH_MISMATCH];
|
|
2565
|
+
case CerVerifyCode.SCHEMA_ERROR:
|
|
2566
|
+
return [ReasonCode.SCHEMA_VERSION_UNSUPPORTED];
|
|
2567
|
+
case CerVerifyCode.CANONICALIZATION_ERROR:
|
|
2568
|
+
case CerVerifyCode.UNKNOWN_ERROR:
|
|
2569
|
+
case CerVerifyCode.INVALID_SHA256_FORMAT:
|
|
2570
|
+
return [ReasonCode.BUNDLE_CORRUPTED];
|
|
2571
|
+
case CerVerifyCode.ATTESTATION_INVALID_SIGNATURE:
|
|
2572
|
+
case CerVerifyCode.ATTESTATION_KEY_FORMAT_UNSUPPORTED:
|
|
2573
|
+
case CerVerifyCode.ATTESTATION_KEY_NOT_FOUND:
|
|
2574
|
+
return [ReasonCode.NODE_SIGNATURE_INVALID];
|
|
2575
|
+
case CerVerifyCode.ATTESTATION_MISSING:
|
|
2576
|
+
return [ReasonCode.NODE_SIGNATURE_MISSING];
|
|
2577
|
+
default:
|
|
2578
|
+
return [];
|
|
2579
|
+
}
|
|
2580
|
+
}
|
|
2581
|
+
function verifyAiCerBundleDetailed(bundle) {
|
|
2582
|
+
const verifiedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2583
|
+
const verifier = "@nexart/ai-execution";
|
|
2584
|
+
if (!bundle || typeof bundle !== "object" || Array.isArray(bundle)) {
|
|
2585
|
+
return {
|
|
2586
|
+
status: "FAILED",
|
|
2587
|
+
checks: { bundleIntegrity: "FAIL", nodeSignature: "SKIPPED", receiptConsistency: "SKIPPED" },
|
|
2588
|
+
reasonCodes: [ReasonCode.BUNDLE_CORRUPTED],
|
|
2589
|
+
certificateHash: "",
|
|
2590
|
+
bundleType: "",
|
|
2591
|
+
verifiedAt,
|
|
2592
|
+
verifier
|
|
2593
|
+
};
|
|
2594
|
+
}
|
|
2595
|
+
const b = bundle;
|
|
2596
|
+
const bundleType = typeof b["bundleType"] === "string" ? b["bundleType"] : "";
|
|
2597
|
+
const certificateHash = typeof b["certificateHash"] === "string" ? b["certificateHash"] : "";
|
|
2598
|
+
if (bundleType !== "cer.ai.execution.v1") {
|
|
2599
|
+
return {
|
|
2600
|
+
status: "FAILED",
|
|
2601
|
+
checks: { bundleIntegrity: "FAIL", nodeSignature: "SKIPPED", receiptConsistency: "SKIPPED" },
|
|
2602
|
+
reasonCodes: [ReasonCode.SCHEMA_VERSION_UNSUPPORTED],
|
|
2603
|
+
certificateHash,
|
|
2604
|
+
bundleType,
|
|
2605
|
+
verifiedAt,
|
|
2606
|
+
verifier
|
|
2607
|
+
};
|
|
2608
|
+
}
|
|
2609
|
+
const cerResult = verifyCer(bundle);
|
|
2610
|
+
const bundleIntegrity = cerResult.ok ? "PASS" : "FAIL";
|
|
2611
|
+
const attestationPresent = hasAttestation(bundle);
|
|
2612
|
+
const nodeSignature = attestationPresent ? "PASS" : "SKIPPED";
|
|
2613
|
+
const receiptConsistency = attestationPresent ? "PASS" : "SKIPPED";
|
|
2614
|
+
const reasonCodes = cerResult.ok ? [] : mapCerCodeToReasonCodes(cerResult.code);
|
|
2615
|
+
return {
|
|
2616
|
+
status: cerResult.ok ? "VERIFIED" : "FAILED",
|
|
2617
|
+
checks: { bundleIntegrity, nodeSignature, receiptConsistency },
|
|
2618
|
+
reasonCodes,
|
|
2619
|
+
certificateHash,
|
|
2620
|
+
bundleType,
|
|
2621
|
+
verifiedAt,
|
|
2622
|
+
verifier
|
|
2623
|
+
};
|
|
2624
|
+
}
|
|
2488
2625
|
// Annotate the CommonJS export names for ESM import in node:
|
|
2489
2626
|
0 && (module.exports = {
|
|
2490
2627
|
CerAttestationError,
|
|
2491
2628
|
CerVerificationError,
|
|
2492
2629
|
CerVerifyCode,
|
|
2630
|
+
ReasonCode,
|
|
2493
2631
|
RunBuilder,
|
|
2494
2632
|
attest,
|
|
2495
2633
|
attestIfNeeded,
|
|
2496
2634
|
certifyAndAttestDecision,
|
|
2635
|
+
certifyAndAttestRun,
|
|
2497
2636
|
certifyDecision,
|
|
2498
2637
|
certifyDecisionFromProviderCall,
|
|
2499
2638
|
computeInputHash,
|
|
@@ -2501,6 +2640,7 @@ function validateProfile(target, profile) {
|
|
|
2501
2640
|
createClient,
|
|
2502
2641
|
createSnapshot,
|
|
2503
2642
|
exportCer,
|
|
2643
|
+
exportVerifiableRedacted,
|
|
2504
2644
|
fetchNodeKeys,
|
|
2505
2645
|
getAttestationReceipt,
|
|
2506
2646
|
hasAttestation,
|
|
@@ -2520,6 +2660,7 @@ function validateProfile(target, profile) {
|
|
|
2520
2660
|
toCanonicalJson,
|
|
2521
2661
|
validateProfile,
|
|
2522
2662
|
verify,
|
|
2663
|
+
verifyAiCerBundleDetailed,
|
|
2523
2664
|
verifyAief,
|
|
2524
2665
|
verifyBundleAttestation,
|
|
2525
2666
|
verifyCer,
|