@colophon-claims/verify 0.1.0 → 0.2.1
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 +23 -9
- package/dist/admission/contracts.d.ts +483 -0
- package/dist/admission/contracts.js +285 -0
- package/dist/admission/index.d.ts +2 -0
- package/dist/admission/index.js +2 -0
- package/dist/admission/prompted-commitment.d.ts +19 -0
- package/dist/admission/prompted-commitment.js +52 -0
- package/dist/admission/prompted-selection.d.ts +24 -0
- package/dist/admission/prompted-selection.js +85 -0
- package/dist/admission/verification.d.ts +17 -3
- package/dist/admission/verification.js +230 -49
- package/dist/assets.d.ts +21 -1
- package/dist/assets.js +60 -3
- package/dist/binding/beacon-binding.d.ts +230 -0
- package/dist/binding/beacon-binding.js +325 -0
- package/dist/binding/report-face.d.ts +45 -0
- package/dist/binding/report-face.js +153 -0
- package/dist/cli.js +74 -12
- package/dist/index.d.ts +14 -3
- package/dist/index.js +16 -3
- package/dist/manifest.d.ts +30 -4
- package/dist/manifest.js +30 -0
- package/dist/materialize.d.ts +7 -0
- package/dist/materialize.js +7 -0
- package/dist/outcome.d.ts +31 -0
- package/dist/outcome.js +45 -0
- package/dist/profile/binary-qualification.js +6 -0
- package/dist/profile/claim-consistency.d.ts +8 -1
- package/dist/profile/claim-consistency.js +4 -4
- package/dist/profile/claim.d.ts +203 -1
- package/dist/profile/claim.js +192 -43
- package/dist/profile/disclosure.d.ts +273 -0
- package/dist/profile/disclosure.js +240 -0
- package/dist/profile/pinning-evidence.d.ts +1 -1
- package/dist/profile/run-results.d.ts +8 -2
- package/dist/profile/run-results.js +9 -3
- package/dist/profile/task-selection.d.ts +69 -0
- package/dist/profile/task-selection.js +140 -0
- package/dist/reader-instructions.d.ts +38 -1
- package/dist/reader-instructions.js +42 -2
- package/dist/schema.d.ts +13 -2
- package/dist/schema.js +39 -8
- package/dist/signers.d.ts +48 -0
- package/dist/signers.js +77 -0
- package/dist/verify.d.ts +20 -6
- package/dist/verify.js +156 -31
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +14 -14
package/dist/verify.js
CHANGED
|
@@ -2,16 +2,17 @@ import { createHash, createPublicKey, verify as verifySignature } from "node:cry
|
|
|
2
2
|
import { verifyReport } from "@jinn-network/benchmarking-aggregate";
|
|
3
3
|
import { verifyEvidenceNativePortableBundle, } from "@jinn-network/benchmarking-evidence";
|
|
4
4
|
import { exportStaticBundle } from "@jinn-network/benchmarking-interop";
|
|
5
|
-
import { cellIdempotencyKey, expectedCellSet, parseBenchmark, parseMatrix, parseReport, parseRun, readRunAnchorIntentExtension, readRunPublicationExtension, } from "@jinn-network/benchmarking-records";
|
|
5
|
+
import { DISCLOSURE_SPECIFICATION_EXTENSION, cellIdempotencyKey, expectedCellSet, parseBenchmark, parseMatrix, parseReport, parseRun, readReportDisclosureExtension, readRunAnchorIntentExtension, readRunPublicationExtension, } from "@jinn-network/benchmarking-records";
|
|
6
6
|
import { verifyMatrix } from "@jinn-network/benchmarking-run";
|
|
7
7
|
import { BINARY_JUDGMENT_INSTRUMENT_REQUIREMENT_KEY, BINARY_JUDGMENT_PROFILE_URI, BinaryJudgmentSnapshotProbeSchema, deriveEvaluationTask, parseBinaryJudgmentAnalysisContext, parseBinaryJudgmentInstrument, parseEvaluationSpec, } from "@jinn-network/task-execution-profiles";
|
|
8
8
|
import { DeliveryRecordSchema, SubmissionRecordSchema, TaskSpecificationSchema } from "@jinn-network/task-execution-protocol";
|
|
9
9
|
import { canonicalJsonBytes, dssePreAuthEncoding, parseExactDsseEnvelope } from "@jinn-network/trust-core";
|
|
10
10
|
import { refuse } from "./profile/errors.js";
|
|
11
|
-
import { ClaimPackageSchema } from "./profile/claim.js";
|
|
11
|
+
import { BINARY_QUALIFICATION_CLAIM_PACKAGE_SCHEMA_ID, ClaimPackageSchema, DISCLOSED_CLAIM_PACKAGE_SCHEMA_ID, } from "./profile/claim.js";
|
|
12
12
|
import { buildMethodPortsFromResolver } from "./profile/ports.js";
|
|
13
13
|
import { didKeyFromEd25519PublicKey } from "./profile/signing.js";
|
|
14
14
|
import { buildPublicReportTrustDeps } from "./profile/trust.js";
|
|
15
|
+
import { evidenceNativeBundleSigners, legacyBundleSigners } from "./signers.js";
|
|
15
16
|
import { buildAssemblyPortsFromFacts } from "./profile/assembly-ports.js";
|
|
16
17
|
import { parseRunPinningEvidenceArtifact, pinningEvidenceFacts, } from "./profile/pinning-evidence.js";
|
|
17
18
|
import { parsePredictionSnapshotAdmissionReceipt, } from "./profile/admission-receipts.js";
|
|
@@ -23,11 +24,13 @@ import { InspectSelectionManifestSchema, isInspectMultiScorerSelection, } from "
|
|
|
23
24
|
import { describeInspectRuntimeMethod, } from "./profile/inspect-disclosure.js";
|
|
24
25
|
import { deriveInspectEvaluationStrategy, INSPECT_SEPARATE_ASSURANCE_LIMITATIONS, inspectLogVerifierMethod, } from "./profile/inspect-assurance.js";
|
|
25
26
|
import { assertClaimConsistency } from "./profile/claim-consistency.js";
|
|
27
|
+
import { assertTaskSelectionConsistency } from "./profile/task-selection.js";
|
|
26
28
|
import { buildPublicAssets } from "./assets.js";
|
|
27
29
|
import { derivePublicComparison } from "./comparison.js";
|
|
28
30
|
import { verifyBundleSnapshot, } from "./manifest.js";
|
|
29
31
|
import { PUBLIC_BUNDLE_FILES, PUBLIC_BUNDLE_V4_FILES } from "./materialize.js";
|
|
30
|
-
import { BUNDLE_V4_FORMAT, BUNDLE_V5_FORMAT, BUNDLE_V6_FORMAT } from "./manifest.js";
|
|
32
|
+
import { BUNDLE_V4_FORMAT, BUNDLE_V5_FORMAT, BUNDLE_V6_FORMAT, BUNDLE_V7_FORMAT, BUNDLE_V8_FORMAT } from "./manifest.js";
|
|
33
|
+
import { DISCLOSURE_SPECIFICATION_BUNDLE_ROLE, DisclosureProjectionError, assertDisclosureSpecification, deriveDisclosureSpecification, } from "./profile/disclosure.js";
|
|
31
34
|
import { evaluateIntegrityAnchors, } from "./anchor/check.js";
|
|
32
35
|
import { ClaimAnchorProjectionError, deriveClaimAnchors } from "./profile/anchor-claims.js";
|
|
33
36
|
import { verifyBinaryJudgmentAdmissionClosure, } from "./admission/verification.js";
|
|
@@ -214,13 +217,54 @@ export function checkItemBankSourceClosure(itemRows, sourceRows) {
|
|
|
214
217
|
* public keys. No pathname is reopened after manifest authentication. */
|
|
215
218
|
export async function verifyPublicBundleSnapshot(bundleDir, deps = {}) {
|
|
216
219
|
const checked = verifyBundleSnapshot(bundleDir, deps);
|
|
220
|
+
// ── G0, the closure-INDEPENDENT extension guard (disclosure design §7 preamble, issue #2839) ──
|
|
221
|
+
//
|
|
222
|
+
// A Report carrying `DISCLOSURE_SPECIFICATION_EXTENSION` on any format other than `/8` refuses,
|
|
223
|
+
// here, before the format branch — so this holds for `/2`, `/4`, `/5`, `/6`, and `/7` alike, the
|
|
224
|
+
// evidence-native path included.
|
|
225
|
+
//
|
|
226
|
+
// Without it there is a real hole: a `/7` bundle could carry both the extension and the record,
|
|
227
|
+
// have the record's role derived by the extension edge, satisfy the evidence-closure reachability
|
|
228
|
+
// guard, and never be looked at by any check — because the named check runs only on `/8`. G0
|
|
229
|
+
// closes that direction; the evidence closure's own size and per-digest guards close the
|
|
230
|
+
// complementary one (role present, extension absent). The two together are what make the
|
|
231
|
+
// extension and the closure inseparable.
|
|
232
|
+
//
|
|
233
|
+
// Read deliberately at the JSON level rather than through `parseReport`: this must fire on a
|
|
234
|
+
// format whose `report.json` this function never otherwise parses, and it must fire on the
|
|
235
|
+
// extension's PRESENCE, not on its well-formedness.
|
|
236
|
+
if (checked.manifest.format !== BUNDLE_V8_FORMAT) {
|
|
237
|
+
const carriedReport = checked.fileBytes.get("report.json");
|
|
238
|
+
if (carriedReport !== undefined) {
|
|
239
|
+
let parsedReportJson;
|
|
240
|
+
try {
|
|
241
|
+
parsedReportJson = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(carriedReport));
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
parsedReportJson = undefined;
|
|
245
|
+
}
|
|
246
|
+
if (typeof parsedReportJson === "object" && parsedReportJson !== null && !Array.isArray(parsedReportJson)
|
|
247
|
+
&& parsedReportJson[DISCLOSURE_SPECIFICATION_EXTENSION] !== undefined) {
|
|
248
|
+
refuse("record-integrity", "report.json", `a Report carrying ${DISCLOSURE_SPECIFICATION_EXTENSION} is publishable only on`
|
|
249
|
+
+ ` ${BUNDLE_V8_FORMAT}, whose disclosure-specification check reads it; this bundle`
|
|
250
|
+
+ ` declares ${checked.manifest.format}`);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
217
254
|
if (checked.manifest.format === BUNDLE_V5_FORMAT) {
|
|
218
255
|
try {
|
|
256
|
+
const claimPackageBytes = checked.fileBytes.get("claim-package.json");
|
|
257
|
+
if (claimPackageBytes === undefined)
|
|
258
|
+
throw new TypeError("portable bundle is missing claim-package.json");
|
|
259
|
+
const verification = await verifyEvidenceNativePortableBundle({
|
|
260
|
+
files: checked.fileBytes,
|
|
261
|
+
verifySignature: verifyEvidenceNativeSignature,
|
|
262
|
+
});
|
|
219
263
|
return {
|
|
220
|
-
verification:
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
}
|
|
264
|
+
verification: {
|
|
265
|
+
...verification,
|
|
266
|
+
signers: evidenceNativeBundleSigners(claimPackageBytes, verification.verifiedSignerKeyIds),
|
|
267
|
+
},
|
|
224
268
|
snapshot: checked,
|
|
225
269
|
};
|
|
226
270
|
}
|
|
@@ -236,17 +280,25 @@ export async function verifyPublicBundleSnapshot(bundleDir, deps = {}) {
|
|
|
236
280
|
};
|
|
237
281
|
const checks = ["manifest"];
|
|
238
282
|
const manifestPaths = new Set(checked.manifest.files.map((file) => file.path));
|
|
239
|
-
|
|
240
|
-
//
|
|
241
|
-
//
|
|
242
|
-
|
|
243
|
-
|
|
283
|
+
// Three independent axes, five formats. The qualification axis decides the mandatory member list,
|
|
284
|
+
// the evidence-catalog grammar, and the trust grammar; the anchor axis decides the `anchors/`
|
|
285
|
+
// allowlist and the `integrity-anchors` check; the disclosure axis decides the Report-extension
|
|
286
|
+
// edge and the `disclosure-specification` check. v6 is v2 plus anchors, v7 is v4 plus anchors
|
|
287
|
+
// (issue #3205), v8 is v7 plus disclosure (issue #2839) — no axis reinterprets another.
|
|
288
|
+
const carriesQualification = checked.manifest.format === BUNDLE_V4_FORMAT
|
|
289
|
+
|| checked.manifest.format === BUNDLE_V7_FORMAT
|
|
290
|
+
|| checked.manifest.format === BUNDLE_V8_FORMAT;
|
|
291
|
+
const carriesAnchors = checked.manifest.format === BUNDLE_V6_FORMAT
|
|
292
|
+
|| checked.manifest.format === BUNDLE_V7_FORMAT
|
|
293
|
+
|| checked.manifest.format === BUNDLE_V8_FORMAT;
|
|
294
|
+
const carriesDisclosure = checked.manifest.format === BUNDLE_V8_FORMAT;
|
|
295
|
+
const mandatoryFiles = carriesQualification ? PUBLIC_BUNDLE_V4_FILES : PUBLIC_BUNDLE_FILES;
|
|
244
296
|
for (const path of mandatoryFiles) {
|
|
245
297
|
if (!manifestPaths.has(path))
|
|
246
298
|
refuse("record-integrity", path, `mandatory public bundle file "${path}" is missing`);
|
|
247
299
|
}
|
|
248
300
|
const evidenceBytes = read("evidence.json");
|
|
249
|
-
const evidence =
|
|
301
|
+
const evidence = carriesQualification
|
|
250
302
|
? parseJson(evidenceBytes, BundleV4EvidenceCatalogSchema, "evidence.json")
|
|
251
303
|
: parseJson(evidenceBytes, BundleEvidenceCatalogSchema, "evidence.json");
|
|
252
304
|
requireCanonical(evidenceBytes, evidence, "evidence.json");
|
|
@@ -263,10 +315,10 @@ export async function verifyPublicBundleSnapshot(bundleDir, deps = {}) {
|
|
|
263
315
|
if (/^native\/inspect\/[a-f0-9]{64}\.eval$/u.test(path))
|
|
264
316
|
expectedPaths.add(path);
|
|
265
317
|
}
|
|
266
|
-
// `anchors/<sha256>.bin` is allowlisted only by the closure
|
|
267
|
-
// member in a v2 or v4 bundle is a non-allowlisted file, exactly as it was before
|
|
318
|
+
// `anchors/<sha256>.bin` is allowlisted only by the closure versions that define it: an anchor
|
|
319
|
+
// member in a v2 or v4 bundle is a non-allowlisted file, exactly as it was before these formats.
|
|
268
320
|
const anchorPaths = [];
|
|
269
|
-
if (
|
|
321
|
+
if (carriesAnchors) {
|
|
270
322
|
for (const path of manifestPaths) {
|
|
271
323
|
if (/^anchors\/[a-f0-9]{64}\.bin$/u.test(path)) {
|
|
272
324
|
expectedPaths.add(path);
|
|
@@ -290,7 +342,7 @@ export async function verifyPublicBundleSnapshot(bundleDir, deps = {}) {
|
|
|
290
342
|
declaredRoles.set(record.sha256, new Set(record.roles));
|
|
291
343
|
}
|
|
292
344
|
const trustBytes = read("trust/public-keys.json");
|
|
293
|
-
const trust =
|
|
345
|
+
const trust = carriesQualification
|
|
294
346
|
? parseJson(trustBytes, BundleV4TrustSchema, "trust/public-keys.json")
|
|
295
347
|
: parseJson(trustBytes, BundleTrustSchema, "trust/public-keys.json");
|
|
296
348
|
requireCanonical(trustBytes, trust, "trust/public-keys.json");
|
|
@@ -300,7 +352,7 @@ export async function verifyPublicBundleSnapshot(bundleDir, deps = {}) {
|
|
|
300
352
|
{ keyId: entry.keyId, publicKey: publicKey(entry.spkiDerBase64, `trust.evaluators.${entry.evaluator}`) },
|
|
301
353
|
]));
|
|
302
354
|
let qualification;
|
|
303
|
-
if (
|
|
355
|
+
if (carriesQualification) {
|
|
304
356
|
const qualificationBytes = read("qualification.json");
|
|
305
357
|
qualification = parseJson(qualificationBytes, BundleQualificationSchema, "qualification.json");
|
|
306
358
|
requireCanonical(qualificationBytes, qualification, "qualification.json");
|
|
@@ -348,7 +400,7 @@ export async function verifyPublicBundleSnapshot(bundleDir, deps = {}) {
|
|
|
348
400
|
// empty section and an omitted one are different claims, and §7.3's declared-but-absent bundle
|
|
349
401
|
// carries the first.
|
|
350
402
|
let claimAnchors;
|
|
351
|
-
if (
|
|
403
|
+
if (carriesAnchors) {
|
|
352
404
|
const anchorRecords = anchorPaths
|
|
353
405
|
.map((path) => {
|
|
354
406
|
const bytes = read(path);
|
|
@@ -384,6 +436,33 @@ export async function verifyPublicBundleSnapshot(bundleDir, deps = {}) {
|
|
|
384
436
|
throw cause;
|
|
385
437
|
}
|
|
386
438
|
}
|
|
439
|
+
// ── The disclosed closure's Report-extension edge and claim projection (issue #2839) ────────
|
|
440
|
+
//
|
|
441
|
+
// Read here, beside the anchors, and for the same two reasons: the evidence-closure walk below
|
|
442
|
+
// needs the edge to derive the record's role, and `assertClaimConsistency` needs the projection to
|
|
443
|
+
// rebuild the claim from the RECORD'S OWN BYTES rather than from the claim under test.
|
|
444
|
+
let disclosureExtensionDigest;
|
|
445
|
+
let claimDisclosure;
|
|
446
|
+
if (carriesDisclosure) {
|
|
447
|
+
const descriptor = readReportDisclosureExtension(report);
|
|
448
|
+
if (descriptor === undefined) {
|
|
449
|
+
refuse("record-integrity", "disclosure-specification", `a ${BUNDLE_V8_FORMAT} bundle must carry ${DISCLOSURE_SPECIFICATION_EXTENSION} on its Report`);
|
|
450
|
+
}
|
|
451
|
+
disclosureExtensionDigest = descriptor.digest.sha256;
|
|
452
|
+
const disclosureBytes = records.get(disclosureExtensionDigest);
|
|
453
|
+
if (disclosureBytes === undefined) {
|
|
454
|
+
refuse("record-integrity", `records/${disclosureExtensionDigest}.bin`, "the bundle does not carry the disclosure-specification record its Report names");
|
|
455
|
+
}
|
|
456
|
+
try {
|
|
457
|
+
claimDisclosure = deriveDisclosureSpecification(disclosureBytes);
|
|
458
|
+
}
|
|
459
|
+
catch (cause) {
|
|
460
|
+
if (cause instanceof DisclosureProjectionError) {
|
|
461
|
+
refuse("record-integrity", `records/${disclosureExtensionDigest}.bin`, cause.message);
|
|
462
|
+
}
|
|
463
|
+
throw cause;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
387
466
|
const assembly = parseAssembly(read("verification/assembly.jsonl"));
|
|
388
467
|
const expectedNativePaths = new Set(assembly.header.graph.solveDeliveries.flatMap((delivery) => delivery.outputs
|
|
389
468
|
.filter((output) => output.name === "inspect-log")
|
|
@@ -415,6 +494,18 @@ export async function verifyPublicBundleSnapshot(bundleDir, deps = {}) {
|
|
|
415
494
|
const cellsByKey = new Map(assembly.cells.map((cell) => [cell.cellKey, cell]));
|
|
416
495
|
const coordinatesByKey = new Map(expectedCoordinates.map((coord) => [coord.cellKey, coord]));
|
|
417
496
|
const expectedRoles = new Map();
|
|
497
|
+
// ── The disclosed closure's one graph edge (issue #2839, design §6.2 / §10.2) ───────────────
|
|
498
|
+
//
|
|
499
|
+
// The Report extension IS the edge: it is the only thing that derives the
|
|
500
|
+
// `disclosure-specification` role for any record. Adding it here — and only on `/8` — is what
|
|
501
|
+
// makes the two refusals in §6.5.2 fire on every other format without a bespoke guard. A
|
|
502
|
+
// standalone disclosure record on a `/7` bundle makes `declaredRoles` exceed `expectedRoles` and
|
|
503
|
+
// trips the size compare; the role appended to an existing graph record's array leaves the sizes
|
|
504
|
+
// equal and trips the per-digest compare instead. Both refusals already existed and cannot be
|
|
505
|
+
// forgotten.
|
|
506
|
+
if (disclosureExtensionDigest !== undefined) {
|
|
507
|
+
addRole(expectedRoles, disclosureExtensionDigest, DISCLOSURE_SPECIFICATION_BUNDLE_ROLE);
|
|
508
|
+
}
|
|
418
509
|
const evaluationSpecs = new Map();
|
|
419
510
|
const taskSpecs = new Map();
|
|
420
511
|
const inspectSelections = new Map();
|
|
@@ -1476,6 +1567,11 @@ export async function verifyPublicBundleSnapshot(bundleDir, deps = {}) {
|
|
|
1476
1567
|
if (!equalBytes(canonicalJsonBytes(verifiedReport.record), reportBytes))
|
|
1477
1568
|
refuse("record-integrity", "report-verification", "verified Report payload does not match report.json");
|
|
1478
1569
|
checks.push("report-verification");
|
|
1570
|
+
// Task-selection provenance (#2980). Runs under the `claim-consistency` check because that is
|
|
1571
|
+
// exactly the question it answers -- does the claim's declared selection survive contact with
|
|
1572
|
+
// the records? -- and because the claim pins the check list byte-for-byte, so a new named check
|
|
1573
|
+
// would be a bundle-format bump rather than an addition.
|
|
1574
|
+
assertTaskSelectionConsistency({ benchmarkRecord: benchmark, runRecord: run });
|
|
1479
1575
|
assertClaimConsistency({
|
|
1480
1576
|
claim,
|
|
1481
1577
|
identities,
|
|
@@ -1490,12 +1586,41 @@ export async function verifyPublicBundleSnapshot(bundleDir, deps = {}) {
|
|
|
1490
1586
|
: {}),
|
|
1491
1587
|
...(assembly.header.rehearsal === undefined ? {} : { rehearsal: assembly.header.rehearsal }),
|
|
1492
1588
|
...(claimAnchors === undefined ? {} : { anchors: claimAnchors }),
|
|
1589
|
+
...(claimDisclosure === undefined ? {} : { disclosure: claimDisclosure }),
|
|
1493
1590
|
});
|
|
1494
1591
|
checks.push("claim-consistency");
|
|
1495
|
-
// Always present for
|
|
1496
|
-
// whose anchors were stripped is a closure failure above, not a shorter check list here.
|
|
1497
|
-
if (
|
|
1592
|
+
// Always present for the anchored closure versions, and never for any earlier one: an anchored
|
|
1593
|
+
// bundle whose anchors were stripped is a closure failure above, not a shorter check list here.
|
|
1594
|
+
if (carriesAnchors)
|
|
1498
1595
|
checks.push("integrity-anchors");
|
|
1596
|
+
// ── disclosure-specification (issue #2839, design §7 steps 1-9) ────────────────────────────
|
|
1597
|
+
//
|
|
1598
|
+
// Runs after `claim-consistency` because step 10 — projection equality — is delivered BY that
|
|
1599
|
+
// check's existing whole-claim byte-compare rather than by a second comparison here. What is left
|
|
1600
|
+
// for this block is authenticating the record itself and pairing the two claim identifiers.
|
|
1601
|
+
let disclosureReport;
|
|
1602
|
+
if (carriesDisclosure) {
|
|
1603
|
+
// Step 9: claim-id pairing. `qualification.json`'s `claimSchema` names WHICH PROJECTION SHAPE
|
|
1604
|
+
// the qualification graph was built for, and that shape is claim-package/2's on every binary
|
|
1605
|
+
// allocation — so the frozen literal does not move, while `claim-package.json` declares the
|
|
1606
|
+
// closure. Either field carrying the other's value refuses, so the two cannot drift together.
|
|
1607
|
+
if (claim.claimSchema !== DISCLOSED_CLAIM_PACKAGE_SCHEMA_ID) {
|
|
1608
|
+
refuse("record-integrity", "claim-package.json", `a ${BUNDLE_V8_FORMAT} bundle's claim must declare ${DISCLOSED_CLAIM_PACKAGE_SCHEMA_ID}`);
|
|
1609
|
+
}
|
|
1610
|
+
if (qualification?.claimSchema !== BINARY_QUALIFICATION_CLAIM_PACKAGE_SCHEMA_ID) {
|
|
1611
|
+
refuse("record-integrity", "qualification.json", `a ${BUNDLE_V8_FORMAT} bundle's qualification document must keep its frozen`
|
|
1612
|
+
+ ` ${BINARY_QUALIFICATION_CLAIM_PACKAGE_SCHEMA_ID} projection literal`);
|
|
1613
|
+
}
|
|
1614
|
+
disclosureReport = assertDisclosureSpecification({
|
|
1615
|
+
extensionDigestSha256: disclosureExtensionDigest,
|
|
1616
|
+
catalogRoles: declaredRoles,
|
|
1617
|
+
recordBytes: records,
|
|
1618
|
+
matrixSha256: identities.matrixSha256,
|
|
1619
|
+
reportAuthor: verifiedReport.record.author,
|
|
1620
|
+
refuse: (path, message) => refuse("record-integrity", path, message),
|
|
1621
|
+
});
|
|
1622
|
+
checks.push("disclosure-specification");
|
|
1623
|
+
}
|
|
1499
1624
|
const dissentCellKeys = assembly.cells
|
|
1500
1625
|
.filter((cell) => new Set(cell.verdicts.map((verdict) => verdict.verdict)).size > 1)
|
|
1501
1626
|
.map((cell) => cell.cellKey)
|
|
@@ -1520,17 +1645,15 @@ export async function verifyPublicBundleSnapshot(bundleDir, deps = {}) {
|
|
|
1520
1645
|
}),
|
|
1521
1646
|
dissentCellKeys,
|
|
1522
1647
|
};
|
|
1523
|
-
//
|
|
1524
|
-
//
|
|
1525
|
-
//
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1648
|
+
// The closure selects the presentation profile and the bundle must byte-match that one
|
|
1649
|
+
// profile completely — assets cannot be mixed, and there is no second profile to fall back
|
|
1650
|
+
// to (issue #2984). A qualification-projecting bundle (`/4`, `/7`) renders the
|
|
1651
|
+
// instrument-qualification graph; every other one renders the human comparison, which
|
|
1652
|
+
// `derivePublicComparison` above always produces. The comparison-absent rendering a
|
|
1653
|
+
// pre-comparison producer would have written is therefore no bundle's profile.
|
|
1529
1654
|
const expectedAssets = qualification !== undefined
|
|
1530
1655
|
? buildPublicAssets({ ...assetFacts, binaryQualification: binaryAssetQualification })
|
|
1531
|
-
:
|
|
1532
|
-
? legacyAssets
|
|
1533
|
-
: buildPublicAssets({ ...assetFacts, comparison });
|
|
1656
|
+
: buildPublicAssets({ ...assetFacts, comparison });
|
|
1534
1657
|
for (const [path, bytes] of Object.entries(expectedAssets)) {
|
|
1535
1658
|
if (!equalBytes(read(path), bytes))
|
|
1536
1659
|
refuse("record-integrity", path, `${path} is not the exact projection of verified public facts`);
|
|
@@ -1547,9 +1670,11 @@ export async function verifyPublicBundleSnapshot(bundleDir, deps = {}) {
|
|
|
1547
1670
|
format: checked.manifest.format,
|
|
1548
1671
|
identity: checked.identity,
|
|
1549
1672
|
checks,
|
|
1673
|
+
signers: legacyBundleSigners(trust, new Set(verdictCatalog.verdicts.map((verdict) => verdict.evaluator))),
|
|
1550
1674
|
...identities,
|
|
1551
1675
|
...(runtimeMethod === undefined ? {} : { runtimeMethod }),
|
|
1552
1676
|
...(anchorReport === undefined ? {} : { anchors: anchorReport }),
|
|
1677
|
+
...(disclosureReport === undefined ? {} : { disclosure: disclosureReport }),
|
|
1553
1678
|
...(qualification === undefined ? {} : {
|
|
1554
1679
|
qualification: {
|
|
1555
1680
|
publicationGrade: qualification.publicationGrade,
|
package/dist/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Public verifier release line. Kept in one module for output and bundle instructions. */
|
|
2
|
-
export declare const VERIFIER_VERSION: "0.1
|
|
2
|
+
export declare const VERIFIER_VERSION: "0.2.1";
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Public verifier release line. Kept in one module for output and bundle instructions. */
|
|
2
|
-
export const VERIFIER_VERSION = "0.1
|
|
2
|
+
export const VERIFIER_VERSION = "0.2.1";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@colophon-claims/verify",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Standalone public-bundle verifier for Colophon claims.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -47,28 +47,28 @@
|
|
|
47
47
|
"@fontsource-variable/newsreader": "5.3.0",
|
|
48
48
|
"@fontsource-variable/public-sans": "5.3.0",
|
|
49
49
|
"@fontsource/ibm-plex-mono": "5.3.0",
|
|
50
|
-
"@jinn-network/benchmarking-aggregate": "0.1.0-canary.sha.
|
|
51
|
-
"@jinn-network/benchmarking-evidence": "0.1.0-canary.sha.
|
|
52
|
-
"@jinn-network/benchmarking-interop": "0.1.0-canary.sha.
|
|
53
|
-
"@jinn-network/benchmarking-local": "0.1.0-canary.sha.
|
|
54
|
-
"@jinn-network/benchmarking-protocol": "0.1.0-canary.sha.
|
|
55
|
-
"@jinn-network/benchmarking-records": "0.1.0-canary.sha.
|
|
56
|
-
"@jinn-network/benchmarking-run": "0.1.0-canary.sha.
|
|
57
|
-
"@jinn-network/task-admission": "0.1.0-canary.sha.
|
|
58
|
-
"@jinn-network/task-execution-profiles": "0.1.0-canary.sha.
|
|
59
|
-
"@jinn-network/task-execution-protocol": "0.1.0-canary.sha.
|
|
60
|
-
"@jinn-network/trust-core": "0.1.0-canary.sha.
|
|
50
|
+
"@jinn-network/benchmarking-aggregate": "0.1.0-canary.sha.0533a224cf99f06d7facf0c23455f2781a5b9e62",
|
|
51
|
+
"@jinn-network/benchmarking-evidence": "0.1.0-canary.sha.0533a224cf99f06d7facf0c23455f2781a5b9e62",
|
|
52
|
+
"@jinn-network/benchmarking-interop": "0.1.0-canary.sha.0533a224cf99f06d7facf0c23455f2781a5b9e62",
|
|
53
|
+
"@jinn-network/benchmarking-local": "0.1.0-canary.sha.0533a224cf99f06d7facf0c23455f2781a5b9e62",
|
|
54
|
+
"@jinn-network/benchmarking-protocol": "0.1.0-canary.sha.0533a224cf99f06d7facf0c23455f2781a5b9e62",
|
|
55
|
+
"@jinn-network/benchmarking-records": "0.1.0-canary.sha.0533a224cf99f06d7facf0c23455f2781a5b9e62",
|
|
56
|
+
"@jinn-network/benchmarking-run": "0.1.0-canary.sha.0533a224cf99f06d7facf0c23455f2781a5b9e62",
|
|
57
|
+
"@jinn-network/task-admission": "0.1.0-canary.sha.0533a224cf99f06d7facf0c23455f2781a5b9e62",
|
|
58
|
+
"@jinn-network/task-execution-profiles": "0.1.0-canary.sha.0533a224cf99f06d7facf0c23455f2781a5b9e62",
|
|
59
|
+
"@jinn-network/task-execution-protocol": "0.1.0-canary.sha.0533a224cf99f06d7facf0c23455f2781a5b9e62",
|
|
60
|
+
"@jinn-network/trust-core": "0.1.0-canary.sha.0533a224cf99f06d7facf0c23455f2781a5b9e62",
|
|
61
61
|
"zod": "4.4.3"
|
|
62
62
|
},
|
|
63
63
|
"resolutions": {
|
|
64
64
|
"@noble/hashes": "2.2.0"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
|
-
"@jinn-network/trust-testing": "0.1.0-canary.sha.
|
|
67
|
+
"@jinn-network/trust-testing": "0.1.0-canary.sha.0533a224cf99f06d7facf0c23455f2781a5b9e62",
|
|
68
68
|
"@types/node": "^22.0.0",
|
|
69
69
|
"ajv": "8.17.1",
|
|
70
70
|
"typescript": "^5.9.3",
|
|
71
71
|
"vitest": "^4.1.8"
|
|
72
72
|
},
|
|
73
|
-
"gitHead": "
|
|
73
|
+
"gitHead": "56d36e4167d395ee496b5b4baa72d3527970060f"
|
|
74
74
|
}
|