@sanning/proof 0.12.0 → 0.14.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 +25 -12
- 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 +353 -0
- package/dist/case.d.ts +217 -26
- package/dist/case.js +535 -124
- package/dist/cli.d.ts +64 -8
- package/dist/cli.js +799 -219
- package/dist/compose.js +6 -1
- 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 +38 -0
- package/dist/evidence.js +238 -22
- package/dist/exit-codes.d.ts +17 -0
- package/dist/exit-codes.js +50 -0
- package/dist/file-match.d.ts +105 -0
- package/dist/file-match.js +374 -0
- package/dist/grading.d.ts +28 -13
- package/dist/grading.js +90 -31
- package/dist/index.d.ts +14 -7
- package/dist/index.js +20 -6
- package/dist/message-parts.d.ts +18 -10
- package/dist/message-parts.js +25 -15
- package/dist/types.d.ts +1 -0
- package/dist/verifier.d.ts +63 -4
- package/dist/verifier.js +223 -15
- package/dist/witness-cache.d.ts +85 -0
- package/dist/witness-cache.js +264 -0
- 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 +422 -0
- package/src/case.ts +671 -131
- package/src/cli.ts +932 -217
- package/src/compose.ts +8 -1
- package/src/crypto.ts +5 -1
- package/src/declaration.ts +248 -52
- package/src/evidence.ts +257 -23
- package/src/exit-codes.ts +54 -0
- package/src/file-match.ts +461 -0
- package/src/grading.ts +109 -52
- package/src/index.ts +101 -2
- package/src/message-parts.ts +25 -15
- package/src/types.ts +5 -0
- package/src/verifier.ts +225 -16
- package/src/witness-cache.ts +306 -0
- package/src/zip-reader.ts +229 -0
- package/vectors/README.md +66 -8
- package/vectors/case-file-index.json +668 -0
- package/vectors/case-split.json +218 -9
- package/vectors/file-match.json +1808 -0
- package/vectors/jcs-reader.json +82 -3
- package/vectors/pack-grading.json +68 -4
- package/vectors/stamp-on-chain.json +20 -5
- package/vectors/witness-cache.json +1304 -0
package/src/grading.ts
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
|
|
@@ -86,15 +86,17 @@ import { jcsParse } from "./verifier.js";
|
|
|
86
86
|
// A superset of `EvidenceStatus`: the four the kernel can return, plus the
|
|
87
87
|
// pack-level `incomplete`, plus `pending` from the shared §3 vocabulary so a
|
|
88
88
|
// kernel headline this module does not downgrade can pass through unchanged.
|
|
89
|
-
export
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
89
|
+
export const PACK_VERDICTS = [
|
|
90
|
+
"verified",
|
|
91
|
+
"partial",
|
|
92
|
+
"pending",
|
|
93
|
+
"not_found",
|
|
94
|
+
"mixed",
|
|
95
|
+
"failed",
|
|
96
|
+
"malformed",
|
|
97
|
+
"incomplete",
|
|
98
|
+
] as const;
|
|
99
|
+
export type PackVerdict = (typeof PACK_VERDICTS)[number];
|
|
98
100
|
|
|
99
101
|
// ---- Inputs ------------------------------------------------------------------
|
|
100
102
|
|
|
@@ -109,7 +111,17 @@ export type PackVerdict =
|
|
|
109
111
|
*/
|
|
110
112
|
export interface GradeInput {
|
|
111
113
|
status: string | null | undefined;
|
|
112
|
-
|
|
114
|
+
/**
|
|
115
|
+
* `eventId` and `payloadBindingOk` are read by rule version 6 alone (A22):
|
|
116
|
+
* an input that does not carry both is never withheld by its declaration,
|
|
117
|
+
* so an adapter written for rule version 5 keeps the stricter reading.
|
|
118
|
+
*/
|
|
119
|
+
events: {
|
|
120
|
+
ok: boolean;
|
|
121
|
+
contentOk: boolean | null;
|
|
122
|
+
eventId?: string;
|
|
123
|
+
payloadBindingOk?: boolean | null;
|
|
124
|
+
}[];
|
|
113
125
|
}
|
|
114
126
|
|
|
115
127
|
/**
|
|
@@ -144,21 +156,23 @@ export type CompletenessNote =
|
|
|
144
156
|
|
|
145
157
|
// ---- Output ------------------------------------------------------------------
|
|
146
158
|
|
|
147
|
-
export
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
159
|
+
export const PACK_GRADE_CAUSE_KINDS = [
|
|
160
|
+
"records_omitted",
|
|
161
|
+
"records_surplus",
|
|
162
|
+
"leaf_count_unreadable",
|
|
163
|
+
"no_disclosure",
|
|
164
|
+
"missing_disclosure",
|
|
165
|
+
"unreadable_disclosure",
|
|
166
|
+
"unaccounted_disclosure",
|
|
167
|
+
"declaration_deviation",
|
|
156
168
|
/**
|
|
157
169
|
* The pack and the UNSIGNED content handed in beside it do not line up
|
|
158
170
|
* (proof#147). A cause, so the pack cannot read clean over it and a reader
|
|
159
171
|
* is told which record; NOT a deviation, so it never reaches `failed`.
|
|
160
172
|
*/
|
|
161
|
-
|
|
173
|
+
"declaration_content_dependent",
|
|
174
|
+
] as const;
|
|
175
|
+
export type PackGradeCauseKind = (typeof PACK_GRADE_CAUSE_KINDS)[number];
|
|
162
176
|
|
|
163
177
|
/**
|
|
164
178
|
* One reason a pack is not `verified`, as data.
|
|
@@ -186,8 +200,8 @@ export interface PackGradeCause {
|
|
|
186
200
|
reason?: string;
|
|
187
201
|
/**
|
|
188
202
|
* Which deviation from the pack's own declaration, for
|
|
189
|
-
* `
|
|
190
|
-
* `
|
|
203
|
+
* `declaration_deviation`, or which content-dependent finding, for
|
|
204
|
+
* `declaration_content_dependent`.
|
|
191
205
|
*/
|
|
192
206
|
deviation?: DeclarationDeviationKind | DeclarationContentKind;
|
|
193
207
|
}
|
|
@@ -205,6 +219,17 @@ export interface PackGrade {
|
|
|
205
219
|
* check was passed, which is the pre-§5.4 call.
|
|
206
220
|
*/
|
|
207
221
|
declaration?: DeclarationVerdict;
|
|
222
|
+
/**
|
|
223
|
+
* Records WITHHELD BY THEIR DECLARATION (rule version 6, evidence-bundle
|
|
224
|
+
* 5.4.5 v1.20, A22): a readable declaration lists them in
|
|
225
|
+
* `declaredWithheld`, their `ok` is true, their `contentOk` is `null` and
|
|
226
|
+
* their `payloadBindingOk` is true. Never counted in `recordsVerified`: no
|
|
227
|
+
* byte of their content was hashed, and a surface MUST NOT print them as
|
|
228
|
+
* verified records.
|
|
229
|
+
*/
|
|
230
|
+
recordsWithheld: number;
|
|
231
|
+
/** Their `event_id`s, in bundle order. */
|
|
232
|
+
withheldEventIds: string[];
|
|
208
233
|
}
|
|
209
234
|
|
|
210
235
|
// ---- Reading a bundle --------------------------------------------------------
|
|
@@ -522,7 +547,20 @@ export function gradeCauses(
|
|
|
522
547
|
account: DisclosureAccount,
|
|
523
548
|
notes: readonly CompletenessNote[],
|
|
524
549
|
declaration?: DeclarationCheck | null,
|
|
550
|
+
withheld: readonly string[] = [],
|
|
525
551
|
): PackGradeCause[] {
|
|
552
|
+
// The `event_id`s WITHHELD BY THEIR DECLARATION (rule version 6) are taken
|
|
553
|
+
// out of `expected` and `missing` before the disclosure causes are computed,
|
|
554
|
+
// so a pack whose every record its declaration withholds earns neither
|
|
555
|
+
// `no_disclosure` nor `missing_disclosure`.
|
|
556
|
+
if (withheld.length > 0) {
|
|
557
|
+
const gone = new Set(withheld);
|
|
558
|
+
account = {
|
|
559
|
+
...account,
|
|
560
|
+
expected: account.expected.filter((e) => !gone.has(e)),
|
|
561
|
+
missing: account.missing.filter((e) => !gone.has(e)),
|
|
562
|
+
};
|
|
563
|
+
}
|
|
526
564
|
const causes: PackGradeCause[] = [];
|
|
527
565
|
|
|
528
566
|
// What the pack CLAIMED to hold comes first, because it frames everything
|
|
@@ -532,7 +570,7 @@ export function gradeCauses(
|
|
|
532
570
|
// four ways can never be reported as one vague shortfall.
|
|
533
571
|
for (const deviation of declaration?.deviations ?? []) {
|
|
534
572
|
causes.push({
|
|
535
|
-
kind: "
|
|
573
|
+
kind: "declaration_deviation",
|
|
536
574
|
deviation: deviation.kind,
|
|
537
575
|
...(deviation.eventId === undefined ? {} : { firstEventId: deviation.eventId }),
|
|
538
576
|
reason: renderDeviation(deviation),
|
|
@@ -544,7 +582,7 @@ export function gradeCauses(
|
|
|
544
582
|
// deviation, so it never reaches `failed`.
|
|
545
583
|
for (const finding of declaration?.contentFindings ?? []) {
|
|
546
584
|
causes.push({
|
|
547
|
-
kind: "
|
|
585
|
+
kind: "declaration_content_dependent",
|
|
548
586
|
deviation: finding.kind,
|
|
549
587
|
...(finding.eventId === undefined ? {} : { firstEventId: finding.eventId }),
|
|
550
588
|
reason: renderContentFinding(finding),
|
|
@@ -554,7 +592,7 @@ export function gradeCauses(
|
|
|
554
592
|
for (const note of notes) {
|
|
555
593
|
if (note.kind === "omitted") {
|
|
556
594
|
causes.push({
|
|
557
|
-
kind: "
|
|
595
|
+
kind: "records_omitted",
|
|
558
596
|
checkpointRef: note.checkpointRef,
|
|
559
597
|
signed: note.signed,
|
|
560
598
|
presented: note.presented,
|
|
@@ -562,14 +600,14 @@ export function gradeCauses(
|
|
|
562
600
|
});
|
|
563
601
|
} else if (note.kind === "surplus") {
|
|
564
602
|
causes.push({
|
|
565
|
-
kind: "
|
|
603
|
+
kind: "records_surplus",
|
|
566
604
|
checkpointRef: note.checkpointRef,
|
|
567
605
|
signed: note.signed,
|
|
568
606
|
presented: note.presented,
|
|
569
607
|
count: note.presented - note.signed,
|
|
570
608
|
});
|
|
571
609
|
} else {
|
|
572
|
-
causes.push({ kind: "
|
|
610
|
+
causes.push({ kind: "leaf_count_unreadable", checkpointRef: note.checkpointRef });
|
|
573
611
|
}
|
|
574
612
|
}
|
|
575
613
|
|
|
@@ -578,10 +616,10 @@ export function gradeCauses(
|
|
|
578
616
|
// reader deserves to be told the pack disclosed nothing rather than counting
|
|
579
617
|
// N absences.
|
|
580
618
|
if (account.expected.length > 0 && account.present.length === 0 && account.unreadable.length === 0) {
|
|
581
|
-
causes.push({ kind: "
|
|
619
|
+
causes.push({ kind: "no_disclosure", count: account.expected.length, of: account.expected.length });
|
|
582
620
|
} else if (account.missing.length > 0) {
|
|
583
621
|
causes.push({
|
|
584
|
-
kind: "
|
|
622
|
+
kind: "missing_disclosure",
|
|
585
623
|
count: account.missing.length,
|
|
586
624
|
of: account.expected.length,
|
|
587
625
|
...(account.missing[0] === undefined ? {} : { firstEventId: account.missing[0] }),
|
|
@@ -589,12 +627,12 @@ export function gradeCauses(
|
|
|
589
627
|
}
|
|
590
628
|
|
|
591
629
|
for (const u of account.unreadable) {
|
|
592
|
-
causes.push({ kind: "
|
|
630
|
+
causes.push({ kind: "unreadable_disclosure", firstEventId: u.eventId, reason: u.reason });
|
|
593
631
|
}
|
|
594
632
|
|
|
595
633
|
if (account.extra.length > 0) {
|
|
596
634
|
causes.push({
|
|
597
|
-
kind: "
|
|
635
|
+
kind: "unaccounted_disclosure",
|
|
598
636
|
count: account.extra.length,
|
|
599
637
|
...(account.extra[0] === undefined ? {} : { firstEventId: account.extra[0] }),
|
|
600
638
|
});
|
|
@@ -614,7 +652,8 @@ export function gradeCauses(
|
|
|
614
652
|
* the type and renders the verdict verbatim would then print the one word
|
|
615
653
|
* `evidence-bundle.md` §6 forbids, over a pack this rule never graded.
|
|
616
654
|
*
|
|
617
|
-
* So: the
|
|
655
|
+
* So: the five words of the §3 vocabulary that a bundle status can pass up to
|
|
656
|
+
* a pack pass through, and ANYTHING ELSE is
|
|
618
657
|
* `incomplete`. A verdict we cannot interpret is a check we could not run, and
|
|
619
658
|
* the answer to that is UNKNOWN — never a pass, and never an accusation.
|
|
620
659
|
* (`failed` and `malformed` are handled before this is reached.)
|
|
@@ -637,8 +676,9 @@ function passThrough(status: string | null | undefined): PackVerdict {
|
|
|
637
676
|
* The verdict a surface may print, and the counts it may print beside it.
|
|
638
677
|
*
|
|
639
678
|
* The invariant, stated so a mutation test can kill it: `verified` is reachable
|
|
640
|
-
* ONLY when every record's supplied bytes bound to its own commitment
|
|
641
|
-
*
|
|
679
|
+
* ONLY when every record's supplied bytes bound to its own commitment, or
|
|
680
|
+
* (rule version 6) the record is withheld by its declaration, and nothing is
|
|
681
|
+
* missing, unreadable, surplus or omitted.
|
|
642
682
|
*
|
|
643
683
|
* Precedence: malformed > failed > incomplete > the kernel's own headline.
|
|
644
684
|
* A hard verdict wins — "the bytes are absent" is never reported as failure
|
|
@@ -696,8 +736,23 @@ export function gradePack(
|
|
|
696
736
|
const events = Array.isArray(result?.events) ? result.events : [];
|
|
697
737
|
const recordsVerified = events.filter((e) => e.ok && e.contentOk === true).length;
|
|
698
738
|
const recordsFailed = events.filter((e) => e.ok === false || e.contentOk === false).length;
|
|
699
|
-
|
|
700
|
-
|
|
739
|
+
// WITHHELD BY ITS DECLARATION (rule version 6, 5.4.5 v1.20, A22, D5). All
|
|
740
|
+
// four conditions, each on its own. `declaredWithheld` is empty for an
|
|
741
|
+
// absent, unreadable or malformed declaration.
|
|
742
|
+
const declaredWithheld = new Set(declaration?.declaredWithheld ?? []);
|
|
743
|
+
const withheldEventIds = events
|
|
744
|
+
.filter(
|
|
745
|
+
(e) =>
|
|
746
|
+
typeof e.eventId === "string" &&
|
|
747
|
+
declaredWithheld.has(e.eventId) &&
|
|
748
|
+
e.ok === true &&
|
|
749
|
+
e.contentOk === null &&
|
|
750
|
+
e.payloadBindingOk === true,
|
|
751
|
+
)
|
|
752
|
+
.map((e) => e.eventId as string);
|
|
753
|
+
const recordsWithheld = withheldEventIds.length;
|
|
754
|
+
const recordsUndetermined = events.length - recordsVerified - recordsFailed - recordsWithheld;
|
|
755
|
+
const causes = gradeCauses(account, notes, declaration, withheldEventIds);
|
|
701
756
|
|
|
702
757
|
let verdict: PackVerdict;
|
|
703
758
|
if (result?.status === "malformed") verdict = "malformed";
|
|
@@ -714,6 +769,8 @@ export function gradePack(
|
|
|
714
769
|
recordsFailed,
|
|
715
770
|
recordsUndetermined,
|
|
716
771
|
causes,
|
|
772
|
+
recordsWithheld,
|
|
773
|
+
withheldEventIds,
|
|
717
774
|
};
|
|
718
775
|
if (declaration != null) grade.declaration = declaration.verdict;
|
|
719
776
|
return grade;
|
|
@@ -733,31 +790,31 @@ export function gradePack(
|
|
|
733
790
|
*/
|
|
734
791
|
export function renderCause(cause: PackGradeCause, subject = "this pack"): string {
|
|
735
792
|
switch (cause.kind) {
|
|
736
|
-
case "
|
|
793
|
+
case "records_omitted":
|
|
737
794
|
return (
|
|
738
795
|
`checkpoint ${cause.checkpointRef} commits to ${cause.signed} record(s); ${subject} presents ` +
|
|
739
796
|
`${cause.presented} — ${cause.count} record(s) OMITTED`
|
|
740
797
|
);
|
|
741
|
-
case "
|
|
798
|
+
case "records_surplus":
|
|
742
799
|
return (
|
|
743
800
|
`checkpoint ${cause.checkpointRef} commits to ${cause.signed} record(s); ${subject} presents ` +
|
|
744
801
|
`${cause.presented} — more records than the signed tree accounts for`
|
|
745
802
|
);
|
|
746
|
-
case "
|
|
803
|
+
case "leaf_count_unreadable":
|
|
747
804
|
return `checkpoint ${cause.checkpointRef} has no readable signed leaf_count — completeness is UNKNOWN`;
|
|
748
|
-
case "
|
|
805
|
+
case "no_disclosure":
|
|
749
806
|
return (
|
|
750
807
|
`no event bytes were disclosed — content binding is UNKNOWN for all ${cause.count} ` +
|
|
751
808
|
`record(s), not verified`
|
|
752
809
|
);
|
|
753
|
-
case "
|
|
810
|
+
case "missing_disclosure":
|
|
754
811
|
return (
|
|
755
812
|
`${cause.count} of ${cause.of} record(s) disclose no bytes (first: ${cause.firstEventId}) — ` +
|
|
756
813
|
`content binding is UNKNOWN, not verified`
|
|
757
814
|
);
|
|
758
|
-
case "
|
|
815
|
+
case "unreadable_disclosure":
|
|
759
816
|
return `the disclosure for ${cause.firstEventId} is unreadable: ${cause.reason}`;
|
|
760
|
-
case "
|
|
817
|
+
case "unaccounted_disclosure":
|
|
761
818
|
return (
|
|
762
819
|
`${cause.count} disclosed file(s) are not accounted for by any record in this bundle ` +
|
|
763
820
|
`(first: ${cause.firstEventId})`
|
|
@@ -766,9 +823,9 @@ export function renderCause(cause: PackGradeCause, subject = "this pack"): strin
|
|
|
766
823
|
// here on `reason`. Re-deriving the sentence from the cause fields would
|
|
767
824
|
// put the declaration's wording in two places, and one of the two would be
|
|
768
825
|
// edited alone.
|
|
769
|
-
case "
|
|
826
|
+
case "declaration_deviation":
|
|
770
827
|
return `this pack deviates from its own declaration: ${cause.reason}`;
|
|
771
|
-
case "
|
|
828
|
+
case "declaration_content_dependent":
|
|
772
829
|
// Named as what the reader could not establish, never as what the
|
|
773
830
|
// holder did: the bytes it turns on are unsigned and whoever assembled
|
|
774
831
|
// the case chose them (proof#147).
|
package/src/index.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
// gateway/transport concerns are consumer-layer logic composed above it.
|
|
13
13
|
|
|
14
14
|
// ACCEPTED_SPEC_MAJORS is exported for parity with the sibling kernels'
|
|
15
|
-
// registries (Python
|
|
15
|
+
// registries (Python ACCEPTED_SPEC_MAJORS, Go SupportedSpecMajor): a consumer
|
|
16
16
|
// can see which profiles this build admits without inferring it from probe
|
|
17
17
|
// calls. It is frozen at its definition (`Object.freeze`, typed
|
|
18
18
|
// `readonly string[]`) because the verifier reads that same array — an exported
|
|
@@ -60,11 +60,14 @@ export type { ContentRole, Envelope, Subject, VerificationResult, VerifyOptions
|
|
|
60
60
|
// bytes, and only for events whose verification bound them to the committed
|
|
61
61
|
// content_hash. Additive; verifyEvidenceBundle's behavior is unchanged.
|
|
62
62
|
export {
|
|
63
|
+
ACCEPTED_EVIDENCE_MAJORS,
|
|
63
64
|
ANCHOR_TRACE_BODY_TYPE,
|
|
65
|
+
CO_SIGNATURES_NOTE,
|
|
64
66
|
EXPORT_BODY_TYPE,
|
|
65
67
|
STAMP_BODY_VERSION,
|
|
66
68
|
STAMP_TRACE_BODY_TYPE,
|
|
67
69
|
STAMP_EVIDENCE_BODY_TYPE,
|
|
70
|
+
coSignaturesPresent,
|
|
68
71
|
disclosedContent,
|
|
69
72
|
recomputeExportVerdict,
|
|
70
73
|
verifyEvidenceBundle,
|
|
@@ -128,6 +131,8 @@ export type {
|
|
|
128
131
|
// derivation to it, and diff its copy against ours. Additive — no existing
|
|
129
132
|
// export changes.
|
|
130
133
|
export {
|
|
134
|
+
PACK_GRADE_CAUSE_KINDS,
|
|
135
|
+
PACK_VERDICTS,
|
|
131
136
|
accountDisclosure,
|
|
132
137
|
completenessNotes,
|
|
133
138
|
gradeCauses,
|
|
@@ -162,7 +167,14 @@ export type {
|
|
|
162
167
|
// optional fourth argument, so a surface gets one verdict; omitting it is the
|
|
163
168
|
// pre-§5.4 behavior, unchanged. Additive: no existing export changes.
|
|
164
169
|
export {
|
|
170
|
+
DECLARATION_CONTENT_KINDS,
|
|
171
|
+
DECLARATION_DEVIATION_KINDS,
|
|
172
|
+
DECLARATION_NOTE_KINDS,
|
|
173
|
+
DECLARATION_ROLES,
|
|
174
|
+
DECLARATION_VERDICTS,
|
|
165
175
|
DECLARATION_VERSION,
|
|
176
|
+
DECLARATION_VERSION_V2,
|
|
177
|
+
DECLARATION_VERSIONS,
|
|
166
178
|
checkDeclaration,
|
|
167
179
|
declarationClaims,
|
|
168
180
|
packRecords,
|
|
@@ -180,6 +192,7 @@ export type {
|
|
|
180
192
|
DeclarationDeviationKind,
|
|
181
193
|
DeclarationNote,
|
|
182
194
|
DeclarationNoteKind,
|
|
195
|
+
DeclarationRole,
|
|
183
196
|
DeclarationVerdict,
|
|
184
197
|
PackRecord,
|
|
185
198
|
} from "./declaration.js";
|
|
@@ -206,20 +219,94 @@ export {
|
|
|
206
219
|
CASE_EXCEPTION_KINDS,
|
|
207
220
|
CASE_QUARANTINED_PROFILES,
|
|
208
221
|
CASE_RECORD_PROFILES,
|
|
222
|
+
CASE_NOTE_KINDS,
|
|
223
|
+
CASE_RELIANCE,
|
|
224
|
+
CASE_RELIANCE_HANDOFF_CLAUSE,
|
|
209
225
|
CASE_VERDICTS,
|
|
226
|
+
CONTENT_WITHHELD_BY_DECLARATION,
|
|
227
|
+
CO_SIGNATURES_PRESENT,
|
|
228
|
+
VERDICT_DISPLAY_TITLES,
|
|
229
|
+
WITNESS_NOT_LOOKED_UP,
|
|
230
|
+
WITNESS_STATES,
|
|
231
|
+
WITNESS_TIME_CACHED,
|
|
232
|
+
WITNESS_TIME_RECORDED,
|
|
233
|
+
caseReliance,
|
|
210
234
|
readCase,
|
|
235
|
+
renderCaseNote,
|
|
211
236
|
renderCaseSummary,
|
|
212
237
|
renderException,
|
|
238
|
+
renderWitnessLine,
|
|
213
239
|
} from "./case.js";
|
|
240
|
+
// The witnessed-time cache (evidence-bundle 5.6.6, v1.25, A30): read it, look it
|
|
241
|
+
// up, print it. Never an input to a verdict.
|
|
242
|
+
export {
|
|
243
|
+
MAX_BLOCK_TIME,
|
|
244
|
+
MAX_WITNESS_CACHE_DEPTH,
|
|
245
|
+
WITNESS_CACHE_NAME,
|
|
246
|
+
WITNESS_CACHE_VERSION,
|
|
247
|
+
checkWitnessCache,
|
|
248
|
+
formatBlockTime,
|
|
249
|
+
readWitnessCache,
|
|
250
|
+
renderWitnessTime,
|
|
251
|
+
witnessTimeQuery,
|
|
252
|
+
} from "./witness-cache.js";
|
|
253
|
+
export type { CachedWitnessTime, WitnessTimeAnswer, WitnessTimeCheck } from "./witness-cache.js";
|
|
214
254
|
export type {
|
|
215
255
|
CaseException,
|
|
216
256
|
CaseExceptionKind,
|
|
257
|
+
CaseNote,
|
|
258
|
+
CaseNoteKind,
|
|
217
259
|
CasePack,
|
|
260
|
+
CasePackReading,
|
|
218
261
|
CaseReading,
|
|
219
262
|
CaseRecordReading,
|
|
220
263
|
CaseVerdict,
|
|
264
|
+
WitnessLine,
|
|
265
|
+
WitnessState,
|
|
221
266
|
} from "./case.js";
|
|
222
267
|
|
|
268
|
+
// The case file's index (src/case-file.ts, evidence-bundle.md §5.6, A25):
|
|
269
|
+
// compared with the drop it describes, with NO verdict contribution. The index
|
|
270
|
+
// is never an input to `readCase`. Pure: bytes and a file list in.
|
|
271
|
+
export {
|
|
272
|
+
CASE_FILE_FINDING_KINDS,
|
|
273
|
+
CASE_FILE_INDEX_NAME,
|
|
274
|
+
CASE_FILE_VERSION,
|
|
275
|
+
HOW_TO_VERIFY_NAME,
|
|
276
|
+
REPORT_README_FIRST_LINE,
|
|
277
|
+
howToVerifyText,
|
|
278
|
+
isPackRef,
|
|
279
|
+
readCaseFileIndex,
|
|
280
|
+
renderCaseFileFinding,
|
|
281
|
+
} from "./case-file.js";
|
|
282
|
+
export type {
|
|
283
|
+
CaseFileFinding,
|
|
284
|
+
CaseFileFindingKind,
|
|
285
|
+
CaseFileIndexReading,
|
|
286
|
+
} from "./case-file.js";
|
|
287
|
+
|
|
288
|
+
// Files handed in beside a pack (src/file-match.ts, evidence-bundle.md §5.7,
|
|
289
|
+
// A29, proof#92): each file's SHA-256 matched against the commitments the
|
|
290
|
+
// pack's SIGNED records make, by hash alone. Never moves a verdict.
|
|
291
|
+
export {
|
|
292
|
+
FILE_MATCH_SCOPE,
|
|
293
|
+
NOT_READ_REASONS,
|
|
294
|
+
fileMatchToJson,
|
|
295
|
+
matchCaseFiles,
|
|
296
|
+
matchFiles,
|
|
297
|
+
renderFileMatch,
|
|
298
|
+
} from "./file-match.js";
|
|
299
|
+
export type {
|
|
300
|
+
FileCommitment,
|
|
301
|
+
FileMatchPack,
|
|
302
|
+
FileMatchReading,
|
|
303
|
+
MatchedFile,
|
|
304
|
+
NotRead,
|
|
305
|
+
NotReadReason,
|
|
306
|
+
OfferedFile,
|
|
307
|
+
UnmatchedFile,
|
|
308
|
+
} from "./file-match.js";
|
|
309
|
+
|
|
223
310
|
// Chain reading (src/chain.ts): following the pointer every sanning.events/v2
|
|
224
311
|
// record carries to the record before it, over the records ONE bundle presents.
|
|
225
312
|
//
|
|
@@ -258,13 +345,25 @@ export type {
|
|
|
258
345
|
// signed, offline-verifiable sanning.evidence.export/v2 artifact from a source
|
|
259
346
|
// anchor-trace bundle + operator attestations + an exporter Ed25519 key. The
|
|
260
347
|
// inverse of verifyEvidenceBundle's verifyExportBody dispatch.
|
|
348
|
+
// One exit-code table for every verb (0.13.0): the verdict word to the exit
|
|
349
|
+
// code, and the help text every verb prints. Additive.
|
|
350
|
+
export {
|
|
351
|
+
EXIT_CODES,
|
|
352
|
+
EXIT_CODES_HELP,
|
|
353
|
+
EXIT_FAILED,
|
|
354
|
+
EXIT_MALFORMED,
|
|
355
|
+
EXIT_MIXED,
|
|
356
|
+
EXIT_UNDETERMINED,
|
|
357
|
+
EXIT_VERIFIED,
|
|
358
|
+
exitCodeFor,
|
|
359
|
+
} from "./exit-codes.js";
|
|
261
360
|
export { attestationSignatureToHex, composeExport } from "./compose.js";
|
|
262
361
|
export type { ComposeExportOptions, ComposeExportResult, ExporterKey } from "./compose.js";
|
|
263
362
|
|
|
264
363
|
// Agent inclusion-proof bundle verification: the
|
|
265
364
|
// sanning.agent.proof/v1 bundle. The CLI sniffs spec_version and routes here so
|
|
266
365
|
// one verifier covers both agent and anchor bundles.
|
|
267
|
-
export {
|
|
366
|
+
export { AGENT_PROOF_SPEC_VERSION, isAgentProofSpec, verifyAgentProof } from "./agent-proof.js";
|
|
268
367
|
export type {
|
|
269
368
|
AgentProofBundle,
|
|
270
369
|
AgentProofResult,
|
package/src/message-parts.ts
CHANGED
|
@@ -278,23 +278,33 @@ const HELD_UNCHECKED_RESULTS: readonly string[] = [
|
|
|
278
278
|
|
|
279
279
|
/**
|
|
280
280
|
* The keys that make a part carry its content INLINE, in the order they are
|
|
281
|
-
* read.
|
|
282
|
-
*
|
|
283
|
-
*
|
|
284
|
-
*
|
|
281
|
+
* read. Settled at `bytes` alone (envelope-spec §4.1, A31, proof#163): that
|
|
282
|
+
* is A2A's spelling, the one the wedge actually emits, and it is the only
|
|
283
|
+
* inline spelling either reference kernel has read from a real producer.
|
|
284
|
+
* `content` and `data` were added on inference rather than on an observed
|
|
285
|
+
* wire shape, and sanning-io/anchor's `filePart()` and `file_part()` SDK
|
|
286
|
+
* helpers, the only producer this plane ships, confirm the inference was
|
|
287
|
+
* wrong: both emit a descriptor part, `kind: "file"` plus `content_hash` and
|
|
288
|
+
* `content_length`, and neither ever writes a `content` or `data` wire key
|
|
289
|
+
* for inline bytes. None is A2A 1.0.0's either: its `Part` has no `kind` and
|
|
290
|
+
* carries a file as `raw` or `url`, so a literal A2A part reads
|
|
291
|
+
* `part_not_a_file` (envelope-spec §4.1, A19). The one key present with a
|
|
292
|
+
* value that is not `null` is the inline content.
|
|
285
293
|
*
|
|
286
294
|
* A key present with `null` is an ABSENT inline value, on A14's ruling that an
|
|
287
|
-
* absent value and one written as `null` name one thing. That matters:
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
* (proof#156 gate).
|
|
291
|
-
*
|
|
292
|
-
*/
|
|
293
|
-
//
|
|
294
|
-
//
|
|
295
|
-
//
|
|
296
|
-
//
|
|
297
|
-
|
|
295
|
+
* absent value and one written as `null` name one thing. That matters: a
|
|
296
|
+
* proto3 JSON encoder can write an unset field as `"bytes": null`, and reading
|
|
297
|
+
* that as inline made a conformant DESCRIPTOR part uncheckable
|
|
298
|
+
* (proof#156 gate). Such a part falls through to the descriptor rule, which is
|
|
299
|
+
* what it is.
|
|
300
|
+
*/
|
|
301
|
+
// Before A31 this list also carried `content` and `data`, and a conformant
|
|
302
|
+
// DESCRIPTOR part that happened to carry either key meaning something else (a
|
|
303
|
+
// filename, a caption) was silently reclassified as inline and never checked
|
|
304
|
+
// against supplied bytes: the swapped-bytes check A18 exists to run
|
|
305
|
+
// (proof#145) never ran on it. proof#163 is resolved by narrowing to `bytes`
|
|
306
|
+
// alone, closing that gap.
|
|
307
|
+
export const INLINE_BYTES_KEYS = ["bytes"] as const;
|
|
298
308
|
|
|
299
309
|
const HEX64 = /^[0-9a-fA-F]{64}$/;
|
|
300
310
|
const HEX_CHARSET = /^[0-9a-fA-F]+$/;
|
package/src/types.ts
CHANGED
|
@@ -48,6 +48,11 @@ export interface VerifyOptions {
|
|
|
48
48
|
// Content bind: the caller's own hash of an artifact (e.g. the in-browser
|
|
49
49
|
// hash of a user's file) to match against the hashes the envelope commits to.
|
|
50
50
|
expectedContentHash?: string;
|
|
51
|
+
// NARROWS the accept-set for this call and never widens it: the set used is
|
|
52
|
+
// `ACCEPTED_SPEC_MAJORS` intersected with this list, so a caller cannot
|
|
53
|
+
// admit a profile this kernel does not. The Python twin is
|
|
54
|
+
// `accepted_spec_majors` (P-10, 0.13.0).
|
|
55
|
+
acceptedSpecMajors?: readonly string[];
|
|
51
56
|
}
|
|
52
57
|
|
|
53
58
|
export interface VerificationResult {
|