@sanning/proof 0.11.1 → 0.13.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 +43 -8
- package/dist/agent-proof.d.ts +2 -2
- package/dist/agent-proof.js +4 -4
- package/dist/case-file.d.ts +126 -0
- package/dist/case-file.js +349 -0
- package/dist/case.d.ts +199 -43
- package/dist/case.js +522 -146
- package/dist/cli.d.ts +132 -1
- package/dist/cli.js +1140 -96
- package/dist/crypto.d.ts +1 -1
- package/dist/crypto.js +5 -1
- package/dist/declaration.d.ts +58 -52
- package/dist/declaration.js +256 -33
- package/dist/evidence.d.ts +2 -0
- package/dist/evidence.js +134 -19
- package/dist/exit-codes.d.ts +17 -0
- package/dist/exit-codes.js +50 -0
- package/dist/grading.d.ts +28 -13
- package/dist/grading.js +90 -31
- package/dist/handoff.d.ts +16 -1
- package/dist/handoff.js +91 -16
- package/dist/index.d.ts +10 -7
- package/dist/index.js +15 -7
- package/dist/message-parts.d.ts +11 -9
- package/dist/message-parts.js +11 -9
- package/dist/types.d.ts +1 -0
- package/dist/verifier.d.ts +9 -2
- package/dist/verifier.js +28 -12
- package/dist/zip-reader.d.ts +50 -0
- package/dist/zip-reader.js +220 -0
- package/package.json +2 -2
- package/src/agent-proof.ts +4 -4
- package/src/case-file.ts +419 -0
- package/src/case.ts +651 -156
- package/src/cli.ts +1325 -100
- package/src/crypto.ts +5 -1
- package/src/declaration.ts +248 -52
- package/src/evidence.ts +142 -21
- package/src/exit-codes.ts +54 -0
- package/src/grading.ts +109 -52
- package/src/handoff.ts +108 -17
- package/src/index.ts +60 -3
- package/src/message-parts.ts +11 -9
- package/src/types.ts +5 -0
- package/src/verifier.ts +35 -13
- package/src/zip-reader.ts +229 -0
- package/vectors/README.md +56 -3
- package/vectors/case-file-index.json +668 -0
- package/vectors/case-split.json +1102 -0
- package/vectors/pack-grading.json +68 -4
- package/vectors/stamp-on-chain.json +3 -3
package/dist/grading.js
CHANGED
|
@@ -41,13 +41,13 @@
|
|
|
41
41
|
// presents a different number of records than a checkpoint
|
|
42
42
|
// signed for — UNKNOWN
|
|
43
43
|
//
|
|
44
|
-
// `incomplete` is
|
|
45
|
-
//
|
|
46
|
-
// bundle; this
|
|
47
|
-
// whatever bytes travelled beside it. A pack can be incomplete
|
|
48
|
-
// it carries is impeccable, which is exactly the case that
|
|
49
|
-
// over zero hashed bytes.
|
|
50
|
-
//
|
|
44
|
+
// `incomplete` is one of the eight words of `evidence-bundle.md` §3 (v1.17,
|
|
45
|
+
// A18), and it is a PACK verdict, never a bundle status. The bundle status
|
|
46
|
+
// grades a signed bundle; this grades a PACK — a strictly larger object, the
|
|
47
|
+
// bundle plus whatever bytes travelled beside it. A pack can be incomplete
|
|
48
|
+
// while the bundle it carries is impeccable, which is exactly the case that
|
|
49
|
+
// used to render green over zero hashed bytes. One vocabulary, two layers,
|
|
50
|
+
// each issuing the subset it can reach.
|
|
51
51
|
//
|
|
52
52
|
// `recordsVerified` counts CONTENT-BOUND records only. The kernel's own
|
|
53
53
|
// `event.ok` tolerates undisclosed content by design — a bundle may legitimately
|
|
@@ -73,6 +73,37 @@ import { hasSideContent, sideContentKeys } from "./side-content.js";
|
|
|
73
73
|
// byte-order mark, no non-finite literal. `jcs_loads` in
|
|
74
74
|
// `src/sanning_proof/canonicalize.py` is the twin (proof#140 gate 5).
|
|
75
75
|
import { jcsParse } from "./verifier.js";
|
|
76
|
+
// ---- The verdict a surface may print ----------------------------------------
|
|
77
|
+
// A superset of `EvidenceStatus`: the four the kernel can return, plus the
|
|
78
|
+
// pack-level `incomplete`, plus `pending` from the shared §3 vocabulary so a
|
|
79
|
+
// kernel headline this module does not downgrade can pass through unchanged.
|
|
80
|
+
export const PACK_VERDICTS = [
|
|
81
|
+
"verified",
|
|
82
|
+
"partial",
|
|
83
|
+
"pending",
|
|
84
|
+
"not_found",
|
|
85
|
+
"mixed",
|
|
86
|
+
"failed",
|
|
87
|
+
"malformed",
|
|
88
|
+
"incomplete",
|
|
89
|
+
];
|
|
90
|
+
// ---- Output ------------------------------------------------------------------
|
|
91
|
+
export const PACK_GRADE_CAUSE_KINDS = [
|
|
92
|
+
"records_omitted",
|
|
93
|
+
"records_surplus",
|
|
94
|
+
"leaf_count_unreadable",
|
|
95
|
+
"no_disclosure",
|
|
96
|
+
"missing_disclosure",
|
|
97
|
+
"unreadable_disclosure",
|
|
98
|
+
"unaccounted_disclosure",
|
|
99
|
+
"declaration_deviation",
|
|
100
|
+
/**
|
|
101
|
+
* The pack and the UNSIGNED content handed in beside it do not line up
|
|
102
|
+
* (proof#147). A cause, so the pack cannot read clean over it and a reader
|
|
103
|
+
* is told which record; NOT a deviation, so it never reaches `failed`.
|
|
104
|
+
*/
|
|
105
|
+
"declaration_content_dependent",
|
|
106
|
+
];
|
|
76
107
|
/**
|
|
77
108
|
* The checkpoint's join key, in whichever vocabulary the bundle speaks.
|
|
78
109
|
*
|
|
@@ -358,7 +389,19 @@ export function completenessNotes(bundle) {
|
|
|
358
389
|
* Every reason this pack is not `verified`, in the order a reader should hear
|
|
359
390
|
* them: what is missing from the whole, then what is missing from the parts.
|
|
360
391
|
*/
|
|
361
|
-
export function gradeCauses(account, notes, declaration) {
|
|
392
|
+
export function gradeCauses(account, notes, declaration, withheld = []) {
|
|
393
|
+
// The `event_id`s WITHHELD BY THEIR DECLARATION (rule version 6) are taken
|
|
394
|
+
// out of `expected` and `missing` before the disclosure causes are computed,
|
|
395
|
+
// so a pack whose every record its declaration withholds earns neither
|
|
396
|
+
// `no_disclosure` nor `missing_disclosure`.
|
|
397
|
+
if (withheld.length > 0) {
|
|
398
|
+
const gone = new Set(withheld);
|
|
399
|
+
account = {
|
|
400
|
+
...account,
|
|
401
|
+
expected: account.expected.filter((e) => !gone.has(e)),
|
|
402
|
+
missing: account.missing.filter((e) => !gone.has(e)),
|
|
403
|
+
};
|
|
404
|
+
}
|
|
362
405
|
const causes = [];
|
|
363
406
|
// What the pack CLAIMED to hold comes first, because it frames everything
|
|
364
407
|
// below it: a reader told "four records are missing from what this pack says
|
|
@@ -367,7 +410,7 @@ export function gradeCauses(account, notes, declaration) {
|
|
|
367
410
|
// four ways can never be reported as one vague shortfall.
|
|
368
411
|
for (const deviation of declaration?.deviations ?? []) {
|
|
369
412
|
causes.push({
|
|
370
|
-
kind: "
|
|
413
|
+
kind: "declaration_deviation",
|
|
371
414
|
deviation: deviation.kind,
|
|
372
415
|
...(deviation.eventId === undefined ? {} : { firstEventId: deviation.eventId }),
|
|
373
416
|
reason: renderDeviation(deviation),
|
|
@@ -378,7 +421,7 @@ export function gradeCauses(account, notes, declaration) {
|
|
|
378
421
|
// deviation, so it never reaches `failed`.
|
|
379
422
|
for (const finding of declaration?.contentFindings ?? []) {
|
|
380
423
|
causes.push({
|
|
381
|
-
kind: "
|
|
424
|
+
kind: "declaration_content_dependent",
|
|
382
425
|
deviation: finding.kind,
|
|
383
426
|
...(finding.eventId === undefined ? {} : { firstEventId: finding.eventId }),
|
|
384
427
|
reason: renderContentFinding(finding),
|
|
@@ -387,7 +430,7 @@ export function gradeCauses(account, notes, declaration) {
|
|
|
387
430
|
for (const note of notes) {
|
|
388
431
|
if (note.kind === "omitted") {
|
|
389
432
|
causes.push({
|
|
390
|
-
kind: "
|
|
433
|
+
kind: "records_omitted",
|
|
391
434
|
checkpointRef: note.checkpointRef,
|
|
392
435
|
signed: note.signed,
|
|
393
436
|
presented: note.presented,
|
|
@@ -396,7 +439,7 @@ export function gradeCauses(account, notes, declaration) {
|
|
|
396
439
|
}
|
|
397
440
|
else if (note.kind === "surplus") {
|
|
398
441
|
causes.push({
|
|
399
|
-
kind: "
|
|
442
|
+
kind: "records_surplus",
|
|
400
443
|
checkpointRef: note.checkpointRef,
|
|
401
444
|
signed: note.signed,
|
|
402
445
|
presented: note.presented,
|
|
@@ -404,7 +447,7 @@ export function gradeCauses(account, notes, declaration) {
|
|
|
404
447
|
});
|
|
405
448
|
}
|
|
406
449
|
else {
|
|
407
|
-
causes.push({ kind: "
|
|
450
|
+
causes.push({ kind: "leaf_count_unreadable", checkpointRef: note.checkpointRef });
|
|
408
451
|
}
|
|
409
452
|
}
|
|
410
453
|
// "Nothing at all was disclosed" is reported once, as itself. It is the
|
|
@@ -412,22 +455,22 @@ export function gradeCauses(account, notes, declaration) {
|
|
|
412
455
|
// reader deserves to be told the pack disclosed nothing rather than counting
|
|
413
456
|
// N absences.
|
|
414
457
|
if (account.expected.length > 0 && account.present.length === 0 && account.unreadable.length === 0) {
|
|
415
|
-
causes.push({ kind: "
|
|
458
|
+
causes.push({ kind: "no_disclosure", count: account.expected.length, of: account.expected.length });
|
|
416
459
|
}
|
|
417
460
|
else if (account.missing.length > 0) {
|
|
418
461
|
causes.push({
|
|
419
|
-
kind: "
|
|
462
|
+
kind: "missing_disclosure",
|
|
420
463
|
count: account.missing.length,
|
|
421
464
|
of: account.expected.length,
|
|
422
465
|
...(account.missing[0] === undefined ? {} : { firstEventId: account.missing[0] }),
|
|
423
466
|
});
|
|
424
467
|
}
|
|
425
468
|
for (const u of account.unreadable) {
|
|
426
|
-
causes.push({ kind: "
|
|
469
|
+
causes.push({ kind: "unreadable_disclosure", firstEventId: u.eventId, reason: u.reason });
|
|
427
470
|
}
|
|
428
471
|
if (account.extra.length > 0) {
|
|
429
472
|
causes.push({
|
|
430
|
-
kind: "
|
|
473
|
+
kind: "unaccounted_disclosure",
|
|
431
474
|
count: account.extra.length,
|
|
432
475
|
...(account.extra[0] === undefined ? {} : { firstEventId: account.extra[0] }),
|
|
433
476
|
});
|
|
@@ -445,7 +488,8 @@ export function gradeCauses(account, notes, declaration) {
|
|
|
445
488
|
* the type and renders the verdict verbatim would then print the one word
|
|
446
489
|
* `evidence-bundle.md` §6 forbids, over a pack this rule never graded.
|
|
447
490
|
*
|
|
448
|
-
* So: the
|
|
491
|
+
* So: the five words of the §3 vocabulary that a bundle status can pass up to
|
|
492
|
+
* a pack pass through, and ANYTHING ELSE is
|
|
449
493
|
* `incomplete`. A verdict we cannot interpret is a check we could not run, and
|
|
450
494
|
* the answer to that is UNKNOWN — never a pass, and never an accusation.
|
|
451
495
|
* (`failed` and `malformed` are handled before this is reached.)
|
|
@@ -466,8 +510,9 @@ function passThrough(status) {
|
|
|
466
510
|
* The verdict a surface may print, and the counts it may print beside it.
|
|
467
511
|
*
|
|
468
512
|
* The invariant, stated so a mutation test can kill it: `verified` is reachable
|
|
469
|
-
* ONLY when every record's supplied bytes bound to its own commitment
|
|
470
|
-
*
|
|
513
|
+
* ONLY when every record's supplied bytes bound to its own commitment, or
|
|
514
|
+
* (rule version 6) the record is withheld by its declaration, and nothing is
|
|
515
|
+
* missing, unreadable, surplus or omitted.
|
|
471
516
|
*
|
|
472
517
|
* Precedence: malformed > failed > incomplete > the kernel's own headline.
|
|
473
518
|
* A hard verdict wins — "the bytes are absent" is never reported as failure
|
|
@@ -520,8 +565,20 @@ export function gradePack(result, account, notes, declaration) {
|
|
|
520
565
|
const events = Array.isArray(result?.events) ? result.events : [];
|
|
521
566
|
const recordsVerified = events.filter((e) => e.ok && e.contentOk === true).length;
|
|
522
567
|
const recordsFailed = events.filter((e) => e.ok === false || e.contentOk === false).length;
|
|
523
|
-
|
|
524
|
-
|
|
568
|
+
// WITHHELD BY ITS DECLARATION (rule version 6, 5.4.5 v1.20, A22, D5). All
|
|
569
|
+
// four conditions, each on its own. `declaredWithheld` is empty for an
|
|
570
|
+
// absent, unreadable or malformed declaration.
|
|
571
|
+
const declaredWithheld = new Set(declaration?.declaredWithheld ?? []);
|
|
572
|
+
const withheldEventIds = events
|
|
573
|
+
.filter((e) => typeof e.eventId === "string" &&
|
|
574
|
+
declaredWithheld.has(e.eventId) &&
|
|
575
|
+
e.ok === true &&
|
|
576
|
+
e.contentOk === null &&
|
|
577
|
+
e.payloadBindingOk === true)
|
|
578
|
+
.map((e) => e.eventId);
|
|
579
|
+
const recordsWithheld = withheldEventIds.length;
|
|
580
|
+
const recordsUndetermined = events.length - recordsVerified - recordsFailed - recordsWithheld;
|
|
581
|
+
const causes = gradeCauses(account, notes, declaration, withheldEventIds);
|
|
525
582
|
let verdict;
|
|
526
583
|
if (result?.status === "malformed")
|
|
527
584
|
verdict = "malformed";
|
|
@@ -541,6 +598,8 @@ export function gradePack(result, account, notes, declaration) {
|
|
|
541
598
|
recordsFailed,
|
|
542
599
|
recordsUndetermined,
|
|
543
600
|
causes,
|
|
601
|
+
recordsWithheld,
|
|
602
|
+
withheldEventIds,
|
|
544
603
|
};
|
|
545
604
|
if (declaration != null)
|
|
546
605
|
grade.declaration = declaration.verdict;
|
|
@@ -559,32 +618,32 @@ export function gradePack(result, account, notes, declaration) {
|
|
|
559
618
|
*/
|
|
560
619
|
export function renderCause(cause, subject = "this pack") {
|
|
561
620
|
switch (cause.kind) {
|
|
562
|
-
case "
|
|
621
|
+
case "records_omitted":
|
|
563
622
|
return (`checkpoint ${cause.checkpointRef} commits to ${cause.signed} record(s); ${subject} presents ` +
|
|
564
623
|
`${cause.presented} — ${cause.count} record(s) OMITTED`);
|
|
565
|
-
case "
|
|
624
|
+
case "records_surplus":
|
|
566
625
|
return (`checkpoint ${cause.checkpointRef} commits to ${cause.signed} record(s); ${subject} presents ` +
|
|
567
626
|
`${cause.presented} — more records than the signed tree accounts for`);
|
|
568
|
-
case "
|
|
627
|
+
case "leaf_count_unreadable":
|
|
569
628
|
return `checkpoint ${cause.checkpointRef} has no readable signed leaf_count — completeness is UNKNOWN`;
|
|
570
|
-
case "
|
|
629
|
+
case "no_disclosure":
|
|
571
630
|
return (`no event bytes were disclosed — content binding is UNKNOWN for all ${cause.count} ` +
|
|
572
631
|
`record(s), not verified`);
|
|
573
|
-
case "
|
|
632
|
+
case "missing_disclosure":
|
|
574
633
|
return (`${cause.count} of ${cause.of} record(s) disclose no bytes (first: ${cause.firstEventId}) — ` +
|
|
575
634
|
`content binding is UNKNOWN, not verified`);
|
|
576
|
-
case "
|
|
635
|
+
case "unreadable_disclosure":
|
|
577
636
|
return `the disclosure for ${cause.firstEventId} is unreadable: ${cause.reason}`;
|
|
578
|
-
case "
|
|
637
|
+
case "unaccounted_disclosure":
|
|
579
638
|
return (`${cause.count} disclosed file(s) are not accounted for by any record in this bundle ` +
|
|
580
639
|
`(first: ${cause.firstEventId})`);
|
|
581
640
|
// Rendered once, by `renderDeviation` in `./declaration.ts`, and carried
|
|
582
641
|
// here on `reason`. Re-deriving the sentence from the cause fields would
|
|
583
642
|
// put the declaration's wording in two places, and one of the two would be
|
|
584
643
|
// edited alone.
|
|
585
|
-
case "
|
|
644
|
+
case "declaration_deviation":
|
|
586
645
|
return `this pack deviates from its own declaration: ${cause.reason}`;
|
|
587
|
-
case "
|
|
646
|
+
case "declaration_content_dependent":
|
|
588
647
|
// Named as what the reader could not establish, never as what the
|
|
589
648
|
// holder did: the bytes it turns on are unsigned and whoever assembled
|
|
590
649
|
// the case chose them (proof#147).
|
package/dist/handoff.d.ts
CHANGED
|
@@ -126,6 +126,16 @@ export interface CandidateReading {
|
|
|
126
126
|
ref: string;
|
|
127
127
|
verdict: HandoffVerdict;
|
|
128
128
|
failedChecks: string[];
|
|
129
|
+
/**
|
|
130
|
+
* The ref of the record that ACCOUNTS FOR this candidate, or `null` (4.1
|
|
131
|
+
* v1.17, A20). Set only on a candidate that graded `failed` and that the
|
|
132
|
+
* reader holds a verified pair for elsewhere; such a candidate is still
|
|
133
|
+
* reported here and takes no part in the subject's verdict, failed checks or
|
|
134
|
+
* ambiguity. Every reading this kernel returns carries it. It is optional in
|
|
135
|
+
* the type only so that code which builds a `CandidateReading` itself keeps
|
|
136
|
+
* compiling: the field is an addition.
|
|
137
|
+
*/
|
|
138
|
+
accountedFor?: string | null;
|
|
129
139
|
}
|
|
130
140
|
export interface HandoffReading {
|
|
131
141
|
ref: string;
|
|
@@ -135,7 +145,12 @@ export interface HandoffReading {
|
|
|
135
145
|
findings: string[];
|
|
136
146
|
/** Ordered, never filtered. */
|
|
137
147
|
candidates: string[];
|
|
138
|
-
/**
|
|
148
|
+
/**
|
|
149
|
+
* One entry per candidate, in the same order, and nothing left out of it. A
|
|
150
|
+
* candidate another record accounts for is here with `accountedFor` set, and
|
|
151
|
+
* where every candidate is accounted for the reading is `counterpart_absent`
|
|
152
|
+
* with the candidates still listed.
|
|
153
|
+
*/
|
|
139
154
|
candidateReadings: CandidateReading[];
|
|
140
155
|
}
|
|
141
156
|
/**
|
package/dist/handoff.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// The hand-off pairing rule of specs/envelope-spec.md §4.1 (v1.
|
|
1
|
+
// The hand-off pairing rule of specs/envelope-spec.md §4.1 (v1.17).
|
|
2
2
|
//
|
|
3
3
|
// Two agents exchange a message and each side records what it held. This module
|
|
4
4
|
// is the TypeScript half of the reference reading of those two records: which
|
|
@@ -119,14 +119,23 @@
|
|
|
119
119
|
// `not_a_handoff_record` are findings reported beside a verdict rather than
|
|
120
120
|
// verdicts.
|
|
121
121
|
//
|
|
122
|
-
// THE COST OF GRADING EVERY CANDIDATE,
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
//
|
|
126
|
-
// than one message
|
|
127
|
-
//
|
|
128
|
-
//
|
|
129
|
-
//
|
|
122
|
+
// THE COST OF GRADING EVERY CANDIDATE, AND THE ACCOUNTED-FOR RULE THAT PAYS
|
|
123
|
+
// MOST OF IT (envelope-spec.md 4.1 v1.17, amendment A20). Grading every
|
|
124
|
+
// candidate means the records of a party's OTHER exchanges are candidates too,
|
|
125
|
+
// and they fail. Up to v1.16 that put `verified` out of reach for any two agents
|
|
126
|
+
// that exchanged more than one message in one direction, and the declaration
|
|
127
|
+
// named as the belt cannot be one: evidence-bundle.md 5.5 forbids the reading
|
|
128
|
+
// to consult `handoffs[]` to pair anything. So a candidate that grades `failed`
|
|
129
|
+
// is SET ASIDE from the subject's verdict, failed checks and ambiguity when,
|
|
130
|
+
// and only when, the reader holds another record `o` that accounts for it
|
|
131
|
+
// (`accountedFor` below): `o` is signed by the subject's own key and is the
|
|
132
|
+
// subject's type; `o` names the candidate's signer and the candidate names the
|
|
133
|
+
// subject's key back; `o`'s sequence differs from the subject's; and the
|
|
134
|
+
// candidate grades `verified` against `o`. The candidate stays in `candidates`
|
|
135
|
+
// and `candidateReadings`, with `accountedFor` set. Setting one aside needs a
|
|
136
|
+
// verified pair with a record the OTHER side signed, so a tampered record
|
|
137
|
+
// stays live. Fan-in, fan-out, and one pair in two cases at one sequence still
|
|
138
|
+
// read `failed`: the Python half's module docstring says why.
|
|
130
139
|
export const CANDIDATE_NAMESPACE = "handoff.";
|
|
131
140
|
export const DEFINED_EVENT_TYPES = ["handoff.sent", "handoff.received"];
|
|
132
141
|
/**
|
|
@@ -546,21 +555,39 @@ export function readHandoff(subject, held) {
|
|
|
546
555
|
// and took none of them out of this list.
|
|
547
556
|
const graded = candidates.map((candidate) => {
|
|
548
557
|
const { verdict, checks } = gradePair(subject, candidate);
|
|
549
|
-
|
|
558
|
+
const by = verdict === "failed" ? accountedFor(subject, candidate, held) : null;
|
|
559
|
+
return { ref: candidate.ref, verdict, failedChecks: checks, accountedFor: by };
|
|
550
560
|
});
|
|
551
|
-
|
|
561
|
+
// The verdict, the failed checks and the ambiguity are taken over the
|
|
562
|
+
// candidates nothing accounts for. The others stay in the report.
|
|
563
|
+
const live = graded.filter((g) => g.accountedFor === null);
|
|
564
|
+
if (live.length === 0) {
|
|
565
|
+
// Every candidate is another exchange's record, each proven so by a
|
|
566
|
+
// verified pair with a record the subject's own key signed: an absence,
|
|
567
|
+
// reported with the candidates it looked at.
|
|
568
|
+
return {
|
|
569
|
+
ref: subject.ref,
|
|
570
|
+
verdict: null,
|
|
571
|
+
failedChecks: [],
|
|
572
|
+
findings: ["counterpart_absent"],
|
|
573
|
+
candidates: candidates.map((c) => c.ref),
|
|
574
|
+
candidateReadings: graded,
|
|
575
|
+
};
|
|
576
|
+
}
|
|
577
|
+
const worst = Math.max(...live.map((g) => VERDICT_RANK[g.verdict]));
|
|
552
578
|
const verdict = Object.keys(VERDICT_RANK).find((name) => VERDICT_RANK[name] === worst);
|
|
553
|
-
// Over every candidate, not only the ones at the winning verdict:
|
|
554
|
-
// outranks `failed`, so a single junk record would otherwise
|
|
555
|
-
// `message_hash` failure out of the report (proof#133
|
|
579
|
+
// Over every live candidate, not only the ones at the winning verdict:
|
|
580
|
+
// `malformed` outranks `failed`, so a single junk record would otherwise
|
|
581
|
+
// strip the named `message_hash` failure out of the report (proof#133
|
|
582
|
+
// review, ruling 6).
|
|
556
583
|
const failed = new Set();
|
|
557
|
-
for (const g of
|
|
584
|
+
for (const g of live)
|
|
558
585
|
for (const check of g.failedChecks)
|
|
559
586
|
failed.add(check);
|
|
560
587
|
const findings = [];
|
|
561
588
|
// Never a free choice: a reader permitted to take one match can be handed an
|
|
562
589
|
// honest decoy beside a tampered record.
|
|
563
|
-
if (
|
|
590
|
+
if (live.length > 1)
|
|
564
591
|
findings.push("counterpart_ambiguous");
|
|
565
592
|
if (verdict === "malformed")
|
|
566
593
|
findings.push("malformed_record");
|
|
@@ -573,6 +600,54 @@ export function readHandoff(subject, held) {
|
|
|
573
600
|
candidateReadings: graded,
|
|
574
601
|
};
|
|
575
602
|
}
|
|
603
|
+
/**
|
|
604
|
+
* The ref of the record that accounts for a FAILED candidate, or `null` (4.1
|
|
605
|
+
* v1.17, A20). The candidate is another exchange's record, and not a deviation
|
|
606
|
+
* on this one, only where the reader holds a record `o`, other than the
|
|
607
|
+
* subject, for which all four hold:
|
|
608
|
+
*
|
|
609
|
+
* 1. `o` is signed by the SUBJECT's own key, and is the subject's type;
|
|
610
|
+
* 2. `o` names the candidate's signer, and the candidate names the subject's
|
|
611
|
+
* key back;
|
|
612
|
+
* 3. `o`'s `sequence` differs from the subject's;
|
|
613
|
+
* 4. the candidate grades `verified` against `o`.
|
|
614
|
+
*
|
|
615
|
+
* Condition 1 is what the audited party cannot supply: a verified pair needs
|
|
616
|
+
* the OTHER side's signature over the digest and the number. Condition 3 is
|
|
617
|
+
* the position guard (proof#129): a second record at the subject's own number
|
|
618
|
+
* is a second claim about the subject's message. The first `o` in the order
|
|
619
|
+
* the records are held is reported, so two kernels name one record. The
|
|
620
|
+
* Python half, `_accounted_for`, carries the full reasoning.
|
|
621
|
+
*/
|
|
622
|
+
function accountedFor(subject, candidate, held) {
|
|
623
|
+
const own = normalizedSigningKey(subject.publicKey);
|
|
624
|
+
const theirs = normalizedSigningKey(candidate.publicKey);
|
|
625
|
+
// Condition 2: the candidate names the subject's key back.
|
|
626
|
+
if (normalizedSigningKey(section(candidate.record, "event").counterparty_public_key) !== own) {
|
|
627
|
+
return null;
|
|
628
|
+
}
|
|
629
|
+
const subjectSequence = section(subject.record, "event").sequence;
|
|
630
|
+
for (const other of held) {
|
|
631
|
+
if (other === subject)
|
|
632
|
+
continue;
|
|
633
|
+
// Condition 1: signed by the subject's own key, of the subject's own type.
|
|
634
|
+
if (normalizedSigningKey(other.publicKey) !== own)
|
|
635
|
+
continue;
|
|
636
|
+
if (eventType(other) !== eventType(subject))
|
|
637
|
+
continue;
|
|
638
|
+
// Condition 2: o names the candidate's signer.
|
|
639
|
+
if (normalizedSigningKey(section(other.record, "event").counterparty_public_key) !== theirs) {
|
|
640
|
+
continue;
|
|
641
|
+
}
|
|
642
|
+
// Condition 3: another position than the subject's.
|
|
643
|
+
if (sameNumber(section(other.record, "event").sequence, subjectSequence))
|
|
644
|
+
continue;
|
|
645
|
+
// Condition 4: a verified pair.
|
|
646
|
+
if (gradePair(other, candidate).verdict === "verified")
|
|
647
|
+
return other.ref;
|
|
648
|
+
}
|
|
649
|
+
return null;
|
|
650
|
+
}
|
|
576
651
|
/**
|
|
577
652
|
* EVERY record the reader holds gets a reading, in the order given.
|
|
578
653
|
*
|
package/dist/index.d.ts
CHANGED
|
@@ -2,19 +2,22 @@ export { ACCEPTED_SPEC_MAJORS, contentHashes, jcs, specVersionSupported, verifyE
|
|
|
2
2
|
export { bytesToHex, deriveOperatorAddress, ed25519Verify, hexToBytes, sha256Bytes, sha256Hex, utf8, verifyRsaPssSha256, } from "./crypto.js";
|
|
3
3
|
export { EMPTY_TREE_ROOT_HEX, auditPath, leafHash, merkleRoot, nodeHash, verifyInclusion, } from "./merkle.js";
|
|
4
4
|
export type { ContentRole, Envelope, Subject, VerificationResult, VerifyOptions } from "./types.js";
|
|
5
|
-
export { ANCHOR_TRACE_BODY_TYPE, EXPORT_BODY_TYPE, STAMP_BODY_VERSION, STAMP_TRACE_BODY_TYPE, STAMP_EVIDENCE_BODY_TYPE, disclosedContent, recomputeExportVerdict, verifyEvidenceBundle, } from "./evidence.js";
|
|
5
|
+
export { ACCEPTED_EVIDENCE_MAJORS, ANCHOR_TRACE_BODY_TYPE, EXPORT_BODY_TYPE, STAMP_BODY_VERSION, STAMP_TRACE_BODY_TYPE, STAMP_EVIDENCE_BODY_TYPE, disclosedContent, recomputeExportVerdict, verifyEvidenceBundle, } from "./evidence.js";
|
|
6
6
|
export type { AnchorTraceBody, AttestationPayload, AttestationRecord, AttestationResult, CheckpointResult, ComposeVerdictResult, DisclosedContentResult, DisclosedEventContent, DisclosureStatus, EvidenceBundle, EvidenceBundleResult, EvidenceIssuer, EvidenceStatus, EvidenceVerdict, EventResult, ExportBody, ExportResult, OnChainOutcome, OnChainResult, PerGatewayOutcome, AnchorRef, StampBody, StampEntry, StampResult, StampSubtree, StampSubtreeResult, StampTraceBody, StampEvidenceBody, StampEvidenceEvent, StampEvidenceInclusion, TraceCheckpoint, TraceEvent, TraceInclusion, VerdictAttestation, VerdictCheckpoint, VerdictEvent, VerdictObject, VerdictOnChain, VerdictOnChainGateway, VerifyEvidenceOptions, } from "./evidence.js";
|
|
7
|
-
export { accountDisclosure, completenessNotes, gradeCauses, gradePack, renderCause, signedLeafCount, } from "./grading.js";
|
|
7
|
+
export { PACK_GRADE_CAUSE_KINDS, PACK_VERDICTS, accountDisclosure, completenessNotes, gradeCauses, gradePack, renderCause, signedLeafCount, } from "./grading.js";
|
|
8
8
|
export type { CompletenessNote, DisclosureAccount, GradeInput, PackGrade, PackGradeCause, PackGradeCauseKind, PackVerdict, } from "./grading.js";
|
|
9
|
-
export { DECLARATION_VERSION, checkDeclaration, declarationClaims, packRecords, renderContentFinding, renderDeclarationSummary, renderDeviation, renderNote, } from "./declaration.js";
|
|
10
|
-
export type { DeclarationCheck, DeclarationClaims, DeclarationContentFinding, DeclarationContentKind, DeclarationDeviation, DeclarationDeviationKind, DeclarationNote, DeclarationNoteKind, DeclarationVerdict, PackRecord, } from "./declaration.js";
|
|
11
|
-
export { CASE_BODY_TYPES, CASE_EXCEPTION_KINDS, CASE_QUARANTINED_PROFILES, CASE_RECORD_PROFILES, CASE_VERDICTS, readCase, renderCaseSummary, renderException, } from "./case.js";
|
|
12
|
-
export type { CaseException, CaseExceptionKind, CasePack, CaseReading, CaseRecordReading, CaseVerdict, } from "./case.js";
|
|
9
|
+
export { DECLARATION_CONTENT_KINDS, DECLARATION_DEVIATION_KINDS, DECLARATION_NOTE_KINDS, DECLARATION_ROLES, DECLARATION_VERDICTS, DECLARATION_VERSION, DECLARATION_VERSION_V2, DECLARATION_VERSIONS, checkDeclaration, declarationClaims, packRecords, renderContentFinding, renderDeclarationSummary, renderDeviation, renderNote, } from "./declaration.js";
|
|
10
|
+
export type { DeclarationCheck, DeclarationClaims, DeclarationContentFinding, DeclarationContentKind, DeclarationDeviation, DeclarationDeviationKind, DeclarationNote, DeclarationNoteKind, DeclarationRole, DeclarationVerdict, PackRecord, } from "./declaration.js";
|
|
11
|
+
export { CASE_BODY_TYPES, CASE_EXCEPTION_KINDS, CASE_QUARANTINED_PROFILES, CASE_RECORD_PROFILES, CASE_NOTE_KINDS, CASE_RELIANCE, CASE_VERDICTS, CONTENT_WITHHELD_BY_DECLARATION, VERDICT_DISPLAY_TITLES, WITNESS_NOT_LOOKED_UP, WITNESS_STATES, readCase, renderCaseNote, renderCaseSummary, renderException, renderWitnessLine, } from "./case.js";
|
|
12
|
+
export type { CaseException, CaseExceptionKind, CaseNote, CaseNoteKind, CasePack, CasePackReading, CaseReading, CaseRecordReading, CaseVerdict, WitnessLine, WitnessState, } from "./case.js";
|
|
13
|
+
export { CASE_FILE_FINDING_KINDS, CASE_FILE_INDEX_NAME, CASE_FILE_VERSION, HOW_TO_VERIFY_NAME, REPORT_README_FIRST_LINE, howToVerifyText, isPackRef, readCaseFileIndex, renderCaseFileFinding, } from "./case-file.js";
|
|
14
|
+
export type { CaseFileFinding, CaseFileFindingKind, CaseFileIndexReading, } from "./case-file.js";
|
|
13
15
|
export { ADAPTER_CHAIN_NAMESPACES, CHAIN_READING_SCOPE, readChains, renderChainFinding, } from "./chain.js";
|
|
14
16
|
export type { ChainFinding, ChainFindingKind, ChainReading, ChainSource, ChainSummary, } from "./chain.js";
|
|
17
|
+
export { EXIT_CODES, EXIT_CODES_HELP, EXIT_FAILED, EXIT_MALFORMED, EXIT_MIXED, EXIT_UNDETERMINED, EXIT_VERIFIED, exitCodeFor, } from "./exit-codes.js";
|
|
15
18
|
export { attestationSignatureToHex, composeExport } from "./compose.js";
|
|
16
19
|
export type { ComposeExportOptions, ComposeExportResult, ExporterKey } from "./compose.js";
|
|
17
|
-
export {
|
|
20
|
+
export { AGENT_PROOF_SPEC_VERSION, isAgentProofSpec, verifyAgentProof } from "./agent-proof.js";
|
|
18
21
|
export type { AgentProofBundle, AgentProofResult, VerifyAgentProofOptions, } from "./agent-proof.js";
|
|
19
22
|
export { CANDIDATE_NAMESPACE, DEFINED_EVENT_TYPES, NOT_A_HANDOFF_FINDING, isConformantHandoffRecord, readHandoff, readHandoffs, recordIsMalformed, } from "./handoff.js";
|
|
20
23
|
export type { CandidateReading, HandoffReading, HandoffRecord, HandoffVerdict, HeldRecord, } from "./handoff.js";
|
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// envelope. Chain walking (previous_hash), checkpoint reconciliation, and
|
|
12
12
|
// gateway/transport concerns are consumer-layer logic composed above it.
|
|
13
13
|
// ACCEPTED_SPEC_MAJORS is exported for parity with the sibling kernels'
|
|
14
|
-
// registries (Python
|
|
14
|
+
// registries (Python ACCEPTED_SPEC_MAJORS, Go SupportedSpecMajor): a consumer
|
|
15
15
|
// can see which profiles this build admits without inferring it from probe
|
|
16
16
|
// calls. It is frozen at its definition (`Object.freeze`, typed
|
|
17
17
|
// `readonly string[]`) because the verifier reads that same array — an exported
|
|
@@ -34,7 +34,7 @@ export { EMPTY_TREE_ROOT_HEX, auditPath, leafHash, merkleRoot, nodeHash, verifyI
|
|
|
34
34
|
// files that failed verification on genuine evidence. This hands back DECODED
|
|
35
35
|
// bytes, and only for events whose verification bound them to the committed
|
|
36
36
|
// content_hash. Additive; verifyEvidenceBundle's behavior is unchanged.
|
|
37
|
-
export { ANCHOR_TRACE_BODY_TYPE, EXPORT_BODY_TYPE, STAMP_BODY_VERSION, STAMP_TRACE_BODY_TYPE, STAMP_EVIDENCE_BODY_TYPE, disclosedContent, recomputeExportVerdict, verifyEvidenceBundle, } from "./evidence.js";
|
|
37
|
+
export { ACCEPTED_EVIDENCE_MAJORS, ANCHOR_TRACE_BODY_TYPE, EXPORT_BODY_TYPE, STAMP_BODY_VERSION, STAMP_TRACE_BODY_TYPE, STAMP_EVIDENCE_BODY_TYPE, disclosedContent, recomputeExportVerdict, verifyEvidenceBundle, } from "./evidence.js";
|
|
38
38
|
// Pack grading (src/grading.ts): what a verification SURFACE may claim about a
|
|
39
39
|
// pack — the signed bundle PLUS whatever disclosed bytes travelled beside it.
|
|
40
40
|
//
|
|
@@ -50,7 +50,7 @@ export { ANCHOR_TRACE_BODY_TYPE, EXPORT_BODY_TYPE, STAMP_BODY_VERSION, STAMP_TRA
|
|
|
50
50
|
// consumer that cannot yet import `gradePack` can vendor the table, hold its own
|
|
51
51
|
// derivation to it, and diff its copy against ours. Additive — no existing
|
|
52
52
|
// export changes.
|
|
53
|
-
export { accountDisclosure, completenessNotes, gradeCauses, gradePack, renderCause, signedLeafCount, } from "./grading.js";
|
|
53
|
+
export { PACK_GRADE_CAUSE_KINDS, PACK_VERDICTS, accountDisclosure, completenessNotes, gradeCauses, gradePack, renderCause, signedLeafCount, } from "./grading.js";
|
|
54
54
|
// The declaration (src/declaration.ts): what a pack SAYS it holds, checked
|
|
55
55
|
// against what it does (evidence-bundle.md §5.4).
|
|
56
56
|
//
|
|
@@ -67,7 +67,7 @@ export { accountDisclosure, completenessNotes, gradeCauses, gradePack, renderCau
|
|
|
67
67
|
// Pure: data in, data out, no I/O. `gradePack` takes the result as an
|
|
68
68
|
// optional fourth argument, so a surface gets one verdict; omitting it is the
|
|
69
69
|
// pre-§5.4 behavior, unchanged. Additive: no existing export changes.
|
|
70
|
-
export { DECLARATION_VERSION, checkDeclaration, declarationClaims, packRecords, renderContentFinding, renderDeclarationSummary, renderDeviation, renderNote, } from "./declaration.js";
|
|
70
|
+
export { DECLARATION_CONTENT_KINDS, DECLARATION_DEVIATION_KINDS, DECLARATION_NOTE_KINDS, DECLARATION_ROLES, DECLARATION_VERDICTS, DECLARATION_VERSION, DECLARATION_VERSION_V2, DECLARATION_VERSIONS, checkDeclaration, declarationClaims, packRecords, renderContentFinding, renderDeclarationSummary, renderDeviation, renderNote, } from "./declaration.js";
|
|
71
71
|
// The case (src/case.ts): one verdict over SEVERAL packs, across organizations
|
|
72
72
|
// (anchor#198). The layer above the declaration, and the closure for what a
|
|
73
73
|
// declaration cannot reach.
|
|
@@ -77,14 +77,19 @@ export { DECLARATION_VERSION, checkDeclaration, declarationClaims, packRecords,
|
|
|
77
77
|
// because the omission happens before any reader runs. Reading several parties'
|
|
78
78
|
// packs at once is what closes it: a `handoff.sent` with no counterpart is
|
|
79
79
|
// always named, and where a pack signed by the key it names is in the case, the
|
|
80
|
-
// reading says that pack holds no counterpart
|
|
80
|
+
// reading says that pack holds no counterpart (unless every candidate was
|
|
81
|
+
// accounted for under A20, which reads as no counterpart and names no pack). Whether a party that presented
|
|
81
82
|
// no such pack recorded anything is not established (proof#143). `readCase`
|
|
82
83
|
// verifies every pack itself, offline, so it is async. Matching is on keys and hashes alone and NEVER on tenancy, so a pair from two
|
|
83
84
|
// organizations verifies (DL-60).
|
|
84
85
|
//
|
|
85
86
|
// Pure: data in, data out, no I/O. Additive: a new module, no existing export
|
|
86
87
|
// changes, and no new verdict word anywhere.
|
|
87
|
-
export { CASE_BODY_TYPES, CASE_EXCEPTION_KINDS, CASE_QUARANTINED_PROFILES, CASE_RECORD_PROFILES, CASE_VERDICTS, readCase, renderCaseSummary, renderException, } from "./case.js";
|
|
88
|
+
export { CASE_BODY_TYPES, CASE_EXCEPTION_KINDS, CASE_QUARANTINED_PROFILES, CASE_RECORD_PROFILES, CASE_NOTE_KINDS, CASE_RELIANCE, CASE_VERDICTS, CONTENT_WITHHELD_BY_DECLARATION, VERDICT_DISPLAY_TITLES, WITNESS_NOT_LOOKED_UP, WITNESS_STATES, readCase, renderCaseNote, renderCaseSummary, renderException, renderWitnessLine, } from "./case.js";
|
|
89
|
+
// The case file's index (src/case-file.ts, evidence-bundle.md §5.6, A25):
|
|
90
|
+
// compared with the drop it describes, with NO verdict contribution. The index
|
|
91
|
+
// is never an input to `readCase`. Pure: bytes and a file list in.
|
|
92
|
+
export { CASE_FILE_FINDING_KINDS, CASE_FILE_INDEX_NAME, CASE_FILE_VERSION, HOW_TO_VERIFY_NAME, REPORT_README_FIRST_LINE, howToVerifyText, isPackRef, readCaseFileIndex, renderCaseFileFinding, } from "./case-file.js";
|
|
88
93
|
// Chain reading (src/chain.ts): following the pointer every sanning.events/v2
|
|
89
94
|
// record carries to the record before it, over the records ONE bundle presents.
|
|
90
95
|
//
|
|
@@ -110,11 +115,14 @@ export { ADAPTER_CHAIN_NAMESPACES, CHAIN_READING_SCOPE, readChains, renderChainF
|
|
|
110
115
|
// signed, offline-verifiable sanning.evidence.export/v2 artifact from a source
|
|
111
116
|
// anchor-trace bundle + operator attestations + an exporter Ed25519 key. The
|
|
112
117
|
// inverse of verifyEvidenceBundle's verifyExportBody dispatch.
|
|
118
|
+
// One exit-code table for every verb (0.13.0): the verdict word to the exit
|
|
119
|
+
// code, and the help text every verb prints. Additive.
|
|
120
|
+
export { EXIT_CODES, EXIT_CODES_HELP, EXIT_FAILED, EXIT_MALFORMED, EXIT_MIXED, EXIT_UNDETERMINED, EXIT_VERIFIED, exitCodeFor, } from "./exit-codes.js";
|
|
113
121
|
export { attestationSignatureToHex, composeExport } from "./compose.js";
|
|
114
122
|
// Agent inclusion-proof bundle verification: the
|
|
115
123
|
// sanning.agent.proof/v1 bundle. The CLI sniffs spec_version and routes here so
|
|
116
124
|
// one verifier covers both agent and anchor bundles.
|
|
117
|
-
export {
|
|
125
|
+
export { AGENT_PROOF_SPEC_VERSION, isAgentProofSpec, verifyAgentProof } from "./agent-proof.js";
|
|
118
126
|
// The hand-off pairing rule (src/handoff.ts): which records are candidates to
|
|
119
127
|
// be the counterpart of a hand-off record, how a candidate set of more than one
|
|
120
128
|
// is ordered, and what a formed pair grades to (specs/envelope-spec.md §4.1
|
package/dist/message-parts.d.ts
CHANGED
|
@@ -118,17 +118,19 @@ export declare const REFUSAL_ORDER: readonly ["bytes_for_unknown_part", "conflic
|
|
|
118
118
|
export declare const MESSAGE_RESULT_ORDER: readonly ["parts_not_an_array"];
|
|
119
119
|
/**
|
|
120
120
|
* The keys that make a part carry its content INLINE, in the order they are
|
|
121
|
-
* read. Named rather than inferred: `bytes`
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
121
|
+
* read. Named rather than inferred: `bytes`, `data` and `content` are the
|
|
122
|
+
* spellings in the wild. None is A2A 1.0.0's: its `Part` has no `kind` and
|
|
123
|
+
* carries a file as `raw` or `url`, so a literal A2A part reads
|
|
124
|
+
* `part_not_a_file` (envelope-spec §4.1, A19). The FIRST of them present with
|
|
125
|
+
* a value that is not `null` is the inline content, so a part spelling it
|
|
126
|
+
* twice reads one way in both kernels.
|
|
125
127
|
*
|
|
126
128
|
* A key present with `null` is an ABSENT inline value, on A14's ruling that an
|
|
127
|
-
* absent value and one written as `null` name one thing. That matters:
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
* (proof#156 gate).
|
|
131
|
-
*
|
|
129
|
+
* absent value and one written as `null` name one thing. That matters: a
|
|
130
|
+
* proto3 JSON encoder can write an unset field as `"bytes": null`, and reading
|
|
131
|
+
* that as inline made a conformant DESCRIPTOR part uncheckable
|
|
132
|
+
* (proof#156 gate). Such a part falls through to the descriptor rule, which is
|
|
133
|
+
* what it is.
|
|
132
134
|
*/
|
|
133
135
|
export declare const INLINE_BYTES_KEYS: readonly ["bytes", "content", "data"];
|
|
134
136
|
/**
|
package/dist/message-parts.js
CHANGED
|
@@ -262,17 +262,19 @@ const HELD_UNCHECKED_RESULTS = [
|
|
|
262
262
|
];
|
|
263
263
|
/**
|
|
264
264
|
* The keys that make a part carry its content INLINE, in the order they are
|
|
265
|
-
* read. Named rather than inferred: `bytes`
|
|
266
|
-
*
|
|
267
|
-
*
|
|
268
|
-
*
|
|
265
|
+
* read. Named rather than inferred: `bytes`, `data` and `content` are the
|
|
266
|
+
* spellings in the wild. None is A2A 1.0.0's: its `Part` has no `kind` and
|
|
267
|
+
* carries a file as `raw` or `url`, so a literal A2A part reads
|
|
268
|
+
* `part_not_a_file` (envelope-spec §4.1, A19). The FIRST of them present with
|
|
269
|
+
* a value that is not `null` is the inline content, so a part spelling it
|
|
270
|
+
* twice reads one way in both kernels.
|
|
269
271
|
*
|
|
270
272
|
* A key present with `null` is an ABSENT inline value, on A14's ruling that an
|
|
271
|
-
* absent value and one written as `null` name one thing. That matters:
|
|
272
|
-
*
|
|
273
|
-
*
|
|
274
|
-
* (proof#156 gate).
|
|
275
|
-
*
|
|
273
|
+
* absent value and one written as `null` name one thing. That matters: a
|
|
274
|
+
* proto3 JSON encoder can write an unset field as `"bytes": null`, and reading
|
|
275
|
+
* that as inline made a conformant DESCRIPTOR part uncheckable
|
|
276
|
+
* (proof#156 gate). Such a part falls through to the descriptor rule, which is
|
|
277
|
+
* what it is.
|
|
276
278
|
*/
|
|
277
279
|
// A conformant DESCRIPTOR part that also carries a `content` or `data` key
|
|
278
280
|
// meaning something else (a filename, a metadata blob) is reclassified by this
|
package/dist/types.d.ts
CHANGED
|
@@ -22,6 +22,7 @@ export type ContentRole = "asset" | "baseline" | "observed";
|
|
|
22
22
|
export interface VerifyOptions {
|
|
23
23
|
payloadBytes?: Uint8Array;
|
|
24
24
|
expectedContentHash?: string;
|
|
25
|
+
acceptedSpecMajors?: readonly string[];
|
|
25
26
|
}
|
|
26
27
|
export interface VerificationResult {
|
|
27
28
|
ok: boolean;
|
package/dist/verifier.d.ts
CHANGED
|
@@ -38,11 +38,18 @@ export declare function jcs(value: unknown): string;
|
|
|
38
38
|
* Throws for anything that is not conformant; every call site treats a throw as
|
|
39
39
|
* "this reader cannot read these bytes" and names the check that failed.
|
|
40
40
|
*/
|
|
41
|
+
/**
|
|
42
|
+
* Bytes as strict UTF-8, a leading byte-order mark KEPT as a character.
|
|
43
|
+
* `utf8_strict` in the Python twin's `canonicalize.py` is the same rule, and
|
|
44
|
+
* `jcsParse` below performs the identical decode. Throws on bytes that are not
|
|
45
|
+
* UTF-8.
|
|
46
|
+
*/
|
|
47
|
+
export declare function utf8Strict(bytes: Uint8Array): string;
|
|
41
48
|
export declare function jcsParse(bytes: Uint8Array): unknown;
|
|
42
|
-
export declare function specVersionSupported(specVersion: string): boolean;
|
|
49
|
+
export declare function specVersionSupported(specVersion: string, accepted?: readonly string[]): boolean;
|
|
43
50
|
export declare function isRfc3339UtcInstant(value: unknown): boolean;
|
|
44
51
|
export declare function contentHashes(env: Envelope): {
|
|
45
52
|
role: ContentRole;
|
|
46
53
|
hash: string;
|
|
47
54
|
}[];
|
|
48
|
-
export declare function verifyEnvelope(env: Envelope,
|
|
55
|
+
export declare function verifyEnvelope(env: Envelope, options?: VerifyOptions): Promise<VerificationResult>;
|