@sanning/proof 0.19.0 → 0.20.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 +30 -29
- package/dist/agent-record.d.ts +62 -0
- package/dist/agent-record.js +527 -0
- package/dist/agent-schemas.generated.d.ts +15 -0
- package/dist/agent-schemas.generated.js +5759 -0
- package/dist/case-file.d.ts +32 -89
- package/dist/case-file.js +41 -93
- package/dist/case.d.ts +343 -810
- package/dist/case.js +693 -1151
- package/dist/chain.d.ts +19 -47
- package/dist/chain.js +78 -205
- package/dist/claims.d.ts +211 -0
- package/dist/claims.js +1081 -0
- package/dist/cli.d.ts +45 -68
- package/dist/cli.js +618 -1022
- package/dist/compose.js +23 -65
- package/dist/crypto.d.ts +7 -8
- package/dist/crypto.js +60 -147
- package/dist/declaration.d.ts +68 -194
- package/dist/declaration.js +175 -518
- package/dist/environment.d.ts +9 -30
- package/dist/environment.js +17 -66
- package/dist/evidence.d.ts +119 -160
- package/dist/evidence.js +744 -1103
- package/dist/exit-codes.d.ts +11 -27
- package/dist/exit-codes.js +24 -59
- package/dist/file-match.d.ts +33 -79
- package/dist/file-match.js +33 -69
- package/dist/grading.d.ts +98 -135
- package/dist/grading.js +224 -380
- package/dist/handoff.d.ts +62 -160
- package/dist/handoff.js +153 -393
- package/dist/index.d.ts +14 -10
- package/dist/index.js +60 -167
- package/dist/json-schema.d.ts +29 -0
- package/dist/json-schema.js +298 -0
- package/dist/merkle.js +16 -28
- package/dist/message-parts.d.ts +56 -212
- package/dist/message-parts.js +142 -502
- package/dist/side-content.d.ts +11 -22
- package/dist/side-content.js +22 -65
- package/dist/types.d.ts +17 -0
- package/dist/types.js +19 -5
- package/dist/verifier.d.ts +40 -114
- package/dist/verifier.js +196 -535
- package/dist/witness-cache.d.ts +24 -45
- package/dist/witness-cache.js +38 -81
- package/dist/witness-lookup.d.ts +36 -57
- package/dist/witness-lookup.js +89 -139
- package/dist/zip-reader.d.ts +18 -33
- package/dist/zip-reader.js +19 -34
- package/package.json +11 -3
- package/src/agent-record.ts +608 -0
- package/src/agent-schemas.generated.ts +5764 -0
- package/src/case-file.ts +45 -109
- package/src/case.ts +848 -1322
- package/src/chain.ts +85 -224
- package/src/claims.ts +1253 -0
- package/src/cli.ts +714 -1176
- package/src/compose.ts +33 -79
- package/src/crypto.ts +60 -147
- package/src/declaration.ts +219 -656
- package/src/environment.ts +17 -65
- package/src/evidence.ts +958 -1381
- package/src/exit-codes.ts +24 -63
- package/src/file-match.ts +40 -89
- package/src/grading.ts +287 -421
- package/src/handoff.ts +175 -427
- package/src/index.ts +132 -177
- package/src/json-schema.ts +295 -0
- package/src/merkle.ts +16 -28
- package/src/message-parts.ts +155 -533
- package/src/side-content.ts +25 -68
- package/src/types.ts +55 -36
- package/src/verifier.ts +202 -526
- package/src/witness-cache.ts +45 -94
- package/src/witness-lookup.ts +107 -177
- package/src/zip-reader.ts +20 -38
- package/vectors/README.md +52 -34
- package/vectors/agent-record.json +2175 -0
- package/vectors/case-file-index.json +1 -1
- package/vectors/case-split.json +2 -2
- package/vectors/chain-reading.json +3 -3
- package/vectors/file-match.json +285 -148
- package/vectors/jcs-reader.json +6 -6
- package/vectors/pack-grading.json +102 -25
- package/vectors/sandbox-evidence.json +597 -580
- package/vectors/stamp-on-chain.json +18 -18
- package/vectors/witness-cache.json +49 -49
- package/dist/agent-proof.d.ts +0 -28
- package/dist/agent-proof.js +0 -226
- package/dist/run-adapters.d.ts +0 -10
- package/dist/run-adapters.js +0 -35
- package/dist/run.d.ts +0 -209
- package/dist/run.js +0 -1405
- package/src/agent-proof.ts +0 -264
- package/src/run-adapters.ts +0 -44
- package/src/run.ts +0 -1598
package/dist/index.d.ts
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
|
-
export { ACCEPTED_SPEC_MAJORS, contentHashes, jcs, specVersionSupported, verifyEnvelope, } from "./verifier.js";
|
|
1
|
+
export { ACCEPTED_SPEC_MAJORS, contentHashes, jcs, specVersionSupported, verifyEnvelope, envelopeFault, envelopeFaults, } from "./verifier.js";
|
|
2
|
+
export { ENVELOPE_FAULTS } from "./types.js";
|
|
3
|
+
export type { EnvelopeFault } from "./types.js";
|
|
2
4
|
export { jcsParse } from "./verifier.js";
|
|
3
|
-
export { exceedsTextDepth, hasNonFiniteNumber, jcsParseWithinLimits, MAX_READ_DEPTH } from "./verifier.js";
|
|
4
5
|
export { bytesToHex, deriveOperatorAddress, ed25519Refusal, ed25519Verify, hexToBytes, sha256Bytes, sha256Hex, utf8, verifyRsaPssSha256, } from "./crypto.js";
|
|
5
6
|
export { EMPTY_TREE_ROOT_HEX, auditPath, leafHash, merkleRoot, nodeHash, verifyInclusion, } from "./merkle.js";
|
|
6
7
|
export type { ContentRole, Envelope, Subject, VerificationResult, VerifyOptions } from "./types.js";
|
|
7
8
|
export { ACCEPTED_EVIDENCE_MAJORS, ANCHOR_TRACE_BODY_TYPE, CO_SIGNATURES_NOTE, EXPORT_BODY_TYPE, STAMP_BODY_VERSION, STAMP_TRACE_BODY_TYPE, STAMP_EVIDENCE_BODY_TYPE, coSignaturesPresent, disclosedContent, recomputeExportVerdict, verifyEvidenceBundle, } from "./evidence.js";
|
|
8
|
-
export type { AnchorTraceBody, AttestationPayload, AttestationRecord, AttestationResult, CheckpointResult, ComposeVerdictResult, DisclosedContentResult, DisclosedEventContent, DisclosureStatus, EvidenceBundle, EvidenceBundleResult, EvidenceIssuer, EvidenceStatus,
|
|
9
|
+
export type { AnchorTraceBody, AttestationPayload, AttestationRecord, AttestationResult, CheckpointResult, ComposeVerdictResult, DisclosedContentResult, DisclosedEventContent, DisclosureStatus, EvidenceBundle, EvidenceBundleResult, EvidenceIssuer, EvidenceStatus, 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";
|
|
9
10
|
export { PACK_GRADE_CAUSE_KINDS, PACK_VERDICTS, accountDisclosure, completenessNotes, gradeCauses, gradePack, renderCause, signedLeafCount, } from "./grading.js";
|
|
10
11
|
export type { CompletenessNote, DisclosureAccount, GradeInput, PackGrade, PackGradeCause, PackGradeCauseKind, PackVerdict, } from "./grading.js";
|
|
11
12
|
export { DECLARATION_CONTENT_KINDS, DECLARATION_DEVIATION_KINDS, DECLARATION_NOTE_KINDS, DECLARATION_ROLES, DECLARATION_VERDICTS, DECLARATION_VERSION, DECLARATION_VERSION_V2, DECLARATION_VERSION_V3, DECLARATION_VERSIONS, checkDeclaration, declarationClaims, packRecords, renderContentFinding, renderDeclarationSummary, renderDeviation, renderNote, } from "./declaration.js";
|
|
12
13
|
export type { DeclarationCheck, DeclarationClaims, DeclarationContentFinding, DeclarationContentKind, DeclarationDeviation, DeclarationDeviationKind, DeclarationNote, DeclarationNoteKind, DeclarationRole, DeclarationVerdict, PackRecord, } from "./declaration.js";
|
|
13
|
-
export { CASE_BODY_TYPES, CASE_EXCEPTION_KINDS, CASE_QUARANTINED_PROFILES, CASE_RECORD_PROFILES, CASE_RECORD_STATUSES, CASE_NOTE_KINDS, CASE_RELIANCE, CASE_RELIANCE_HANDOFF_CLAUSE, CASE_VERDICTS, CONTENT_WITHHELD_BY_DECLARATION, CO_SIGNATURES_PRESENT, VERDICT_DISPLAY_TITLES, WITNESS_NOT_LOOKED_UP, WITNESS_STATES, WITNESS_TIME_CACHED, WITNESS_TIME_RECORDED, caseReliance, readCase, renderCaseNote, renderCaseSummary, renderException, renderWitnessLine, } from "./case.js";
|
|
14
|
+
export { CASE_BODY_TYPES, CASE_EXCEPTION_KINDS, CASE_QUARANTINED_PROFILES, CASE_RECORD_PROFILES, CASE_RECORD_STATUSES, CASE_NOTE_KINDS, CASE_RELIANCE, CASE_RELIANCE_HANDOFF_CLAUSE, CASE_RELIANCE_SANDBOX, CASE_VERDICTS, CONTENT_WITHHELD_BY_DECLARATION, CO_SIGNATURES_PRESENT, VERDICT_DISPLAY_TITLES, WITNESS_NOT_LOOKED_UP, WITNESS_STATES, WITNESS_TIME_CACHED, WITNESS_TIME_RECORDED, caseProblems, caseReliance, readCase, renderCaseNote, renderCaseSummary, renderException, renderWitnessLine, } from "./case.js";
|
|
14
15
|
export { MAX_BLOCK_TIME, MAX_WITNESS_CACHE_DEPTH, WITNESS_CACHE_NAME, WITNESS_CACHE_VERSION, checkWitnessCache, formatBlockTime, readWitnessCache, renderWitnessTime, witnessTimeQuery, } from "./witness-cache.js";
|
|
15
16
|
export type { CachedWitnessTime, WitnessTimeAnswer, WitnessTimeCheck } from "./witness-cache.js";
|
|
16
|
-
export { lookupPublicRecord, onChainHalf, witnessLine } from "./witness-lookup.js";
|
|
17
|
+
export { lookupPublicRecord, onChainHalf, onChainOutcome, onChainRow, witnessLine, } from "./witness-lookup.js";
|
|
18
|
+
export { CLAIMS, CLAIM_LABELS, CLAIM_QUESTIONS, CLAIM_STATES, ENVELOPE_FAULT_KINDS, KIND_CLAIMS, NOTE_FINDINGS, NOTE_ORDER, NOT_IN_SCOPE_REASONS, NOT_PROVEN_REASONS, PERSON_TITLES, PERSON_TITLE_PARTS, REASON_KINDS, RECORD_REASON_CLAIMS, RECORD_REASON_LINES, SANDBOX_PERSON_LINE, VERDICTS, VERDICT_COLOURS, VERDICT_TITLES, bundleProblems, claimsOf, downgraded, note, orderedNotes, restOnSigned, personText, problem, problemToJson, renderFindingNote, renderPerson, verdictOf, withItems, } from "./claims.js";
|
|
19
|
+
export type { Claim, ClaimEntry, ClaimItem, ClaimState, Labels, LinePart, NoteEntry, NotInScopeReason, NotProvenReason, Person, Problem, ProblemItem, ProblemJson, ProblemValues, ReasonKind, Verdict, VerdictJson, } from "./claims.js";
|
|
17
20
|
export type { OnChainHalf, OnChainRow, PublicRecordPack, PublicRecordResult, PublicRecordState, WitnessLookupOptions, WitnessTimeRow, } from "./witness-lookup.js";
|
|
18
21
|
export type { CaseException, CaseExceptionKind, CaseNote, CaseNoteKind, CasePack, CasePackReading, CaseReading, CaseRecordReading, CaseRecordStatus, CaseVerdict, WitnessLine, WitnessState, } from "./case.js";
|
|
19
22
|
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";
|
|
@@ -22,14 +25,15 @@ export { FILE_MATCH_SCOPE, NOT_READ_REASONS, SKIPPED_REASONS, fileMatchToJson, m
|
|
|
22
25
|
export type { FileCommitment, FileMatchPack, FileMatchReading, MatchedFile, NotRead, NotReadReason, OfferedFile, SkippedFile, SkippedReason, UnmatchedFile, } from "./file-match.js";
|
|
23
26
|
export { ADAPTER_CHAIN_NAMESPACES, CHAIN_READING_SCOPE, readChainLinks, readChains, renderChainFinding, } from "./chain.js";
|
|
24
27
|
export type { ChainFinding, ChainFindingKind, ChainLink, ChainReading, ChainSource, ChainSummary, } from "./chain.js";
|
|
25
|
-
export { EXIT_CODES, EXIT_CODES_HELP,
|
|
26
|
-
export {
|
|
28
|
+
export { EXIT_CODES, EXIT_CODES_HELP, EXIT_COULD_NOT_RUN, EXIT_FAILED, EXIT_INCOMPLETE, EXIT_SANDBOX, EXIT_VERIFIED, exitCodeFor, } from "./exit-codes.js";
|
|
29
|
+
export { environmentMarker, packEnvelopes, } from "./environment.js";
|
|
27
30
|
export type { EnvironmentMarker } from "./environment.js";
|
|
28
31
|
export { attestationSignatureToHex, composeExport } from "./compose.js";
|
|
29
32
|
export type { ComposeExportOptions, ComposeExportResult, ExporterKey } from "./compose.js";
|
|
30
|
-
export {
|
|
31
|
-
export type { AgentProofBundle, AgentProofResult, VerifyAgentProofOptions, } from "./agent-proof.js";
|
|
32
|
-
export { CANDIDATE_NAMESPACE, DEFINED_EVENT_TYPES, NOT_A_HANDOFF_FINDING, isConformantHandoffRecord, readHandoff, readHandoffs, recordIsMalformed, } from "./handoff.js";
|
|
33
|
+
export { CANDIDATE_NAMESPACE, DEFINED_EVENT_TYPES, NOT_A_HANDOFF_FINDING, isConformantHandoffRecord, readHandoff, readHandoffs, recordDefect, recordIsMalformed, recordIsNonconforming, } from "./handoff.js";
|
|
33
34
|
export type { CandidateReading, HandoffReading, HandoffRecord, HandoffVerdict, HeldRecord, } from "./handoff.js";
|
|
34
35
|
export { BYTES_FOR_UNKNOWN_PART, CONFLICTING_PART_BYTES, INLINE_BYTES_KEYS, MESSAGE_RESULT_ORDER, PARTS_NOT_AN_ARRAY, PART_ENCODING_MISMATCH, PART_INLINE_BYTES, PART_INLINE_MISMATCHED, PART_MALFORMED_DESCRIPTOR, PART_MATCHED, PART_MISMATCHED, PART_NOT_A_FILE, PART_SUPPLIED_TWICE, PART_UNCHECKED, REFUSAL_ORDER, commitHeldMessage, isFilePart, uncheckedHeldParts, } from "./message-parts.js";
|
|
35
36
|
export type { HeldMessage, Note, PartReading, Refusal, SuppliedPart } from "./message-parts.js";
|
|
37
|
+
export { AGENT_EVENT_TYPES, RECORD_TYPES_OUTSIDE_AGENT, readAgentRecord, readAgentRecordWithHeld, readAgentRecords, renderAgentReading, } from "./agent-record.js";
|
|
38
|
+
export type { AgentHeldRecord, AgentReason, AgentRecordReading, AgentVerdict } from "./agent-record.js";
|
|
39
|
+
export { AGENT_SCHEMA_PIN, AGENT_SCHEMA_VERSIONS } from "./agent-schemas.generated.js";
|
package/dist/index.js
CHANGED
|
@@ -1,179 +1,72 @@
|
|
|
1
|
-
// @sanning/proof
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
//
|
|
10
|
-
// Scope boundary (envelope-spec §10 #13): this package verifies a SINGLE
|
|
11
|
-
// envelope. Chain walking (previous_hash), checkpoint reconciliation, and
|
|
12
|
-
// gateway/transport concerns are consumer-layer logic composed above it.
|
|
13
|
-
// ACCEPTED_SPEC_MAJORS is exported for parity with the sibling kernels'
|
|
14
|
-
// registries (Python ACCEPTED_SPEC_MAJORS, Go SupportedSpecMajor): a consumer
|
|
15
|
-
// can see which profiles this build admits without inferring it from probe
|
|
16
|
-
// calls. It is frozen at its definition (`Object.freeze`, typed
|
|
17
|
-
// `readonly string[]`) because the verifier reads that same array — an exported
|
|
18
|
-
// mutable accept-set would be a runtime-widenable kernel. Additive — no
|
|
19
|
-
// existing export changes.
|
|
20
|
-
export { ACCEPTED_SPEC_MAJORS, contentHashes, jcs, specVersionSupported, verifyEnvelope, } from "./verifier.js";
|
|
21
|
-
// The strict reader of bytes that claim to be JCS, the twin of Python's public
|
|
22
|
-
// `canonicalize.jcs_loads`. The enclave attestation adapters read a token's
|
|
23
|
-
// JSON through it, so they refuse what the kernel refuses. Additive.
|
|
1
|
+
// @sanning/proof: the TypeScript verification kernel for the Verifiable Event
|
|
2
|
+
// Envelope family (specs/envelope-spec.md): RFC 8785 (JCS), SHA-256, Ed25519
|
|
3
|
+
// envelope verification, and the bundle, pack and case readings built on them.
|
|
4
|
+
// Conformance is byte-for-byte against the shared `test-vectors/` corpus.
|
|
5
|
+
// The accept-set this build admits. Frozen at its definition, because the
|
|
6
|
+
// verifier reads the same array.
|
|
7
|
+
export { ACCEPTED_SPEC_MAJORS, contentHashes, jcs, specVersionSupported, verifyEnvelope, envelopeFault, envelopeFaults, } from "./verifier.js";
|
|
8
|
+
export { ENVELOPE_FAULTS } from "./types.js";
|
|
9
|
+
// The strict reader of bytes that claim to be JCS (Python's `jcs_loads`).
|
|
24
10
|
export { jcsParse } from "./verifier.js";
|
|
25
|
-
// The same reader within the enclave readers' limits (enclave-attestation
|
|
26
|
-
// section 2.1): depth checked on the bytes first, every number finite. The
|
|
27
|
-
// adapters read a token's header and claims and the manifest through it.
|
|
28
|
-
// Additive.
|
|
29
|
-
export { exceedsTextDepth, hasNonFiniteNumber, jcsParseWithinLimits, MAX_READ_DEPTH } from "./verifier.js";
|
|
30
11
|
export { bytesToHex, deriveOperatorAddress, ed25519Refusal, ed25519Verify, hexToBytes, sha256Bytes, sha256Hex, utf8, verifyRsaPssSha256, } from "./crypto.js";
|
|
31
12
|
export { EMPTY_TREE_ROOT_HEX, auditPath, leafHash, merkleRoot, nodeHash, verifyInclusion, } from "./merkle.js";
|
|
32
|
-
// Evidence-bundle verification (specs/evidence-bundle.md)
|
|
33
|
-
// sanning.evidence/
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
// verifyExportBody (embedded RSA-PSS operator attestations + a recomputed §4
|
|
37
|
-
// verdict object with per-gateway on-chain outcomes).
|
|
38
|
-
//
|
|
39
|
-
// `disclosedContent` is the INGEST half of the same path (evidence-bundle
|
|
40
|
-
// §5.1). A received bundle carries its disclosed raw bytes as lowercase hex, so
|
|
41
|
-
// materializing them was, until now, every consumer re-implementing the
|
|
42
|
-
// encoding convention — and a consumer that copied the field VERBATIM wrote
|
|
43
|
-
// files that failed verification on genuine evidence. This hands back DECODED
|
|
44
|
-
// bytes, and only for events whose verification bound them to the committed
|
|
45
|
-
// content_hash. Additive; verifyEvidenceBundle's behavior is unchanged.
|
|
13
|
+
// Evidence-bundle verification (specs/evidence-bundle.md), including the
|
|
14
|
+
// sanning.evidence.export/v2 body (specs/evidence-export.md).
|
|
15
|
+
// `disclosedContent` returns decoded disclosed bytes, only for events whose
|
|
16
|
+
// verification bound them to the committed content_hash.
|
|
46
17
|
export { ACCEPTED_EVIDENCE_MAJORS, ANCHOR_TRACE_BODY_TYPE, CO_SIGNATURES_NOTE, EXPORT_BODY_TYPE, STAMP_BODY_VERSION, STAMP_TRACE_BODY_TYPE, STAMP_EVIDENCE_BODY_TYPE, coSignaturesPresent, disclosedContent, recomputeExportVerdict, verifyEvidenceBundle, } from "./evidence.js";
|
|
47
|
-
// Pack grading
|
|
48
|
-
//
|
|
49
|
-
//
|
|
50
|
-
// The rule is already normative in evidence-bundle.md §5.1 (absent disclosure is
|
|
51
|
-
// undetermined, not failed) and §6 (no status ever means "safe"); what the
|
|
52
|
-
// surfaces added on top was a sharper word for undetermined and an account of
|
|
53
|
-
// what the pack failed to disclose. It lived twice, in two repos and two
|
|
54
|
-
// languages, and the two derivations had already diverged once. It lives here.
|
|
55
|
-
//
|
|
56
|
-
// Pure — data in, data out, no I/O, so the kernel's scope boundary
|
|
57
|
-
// (specs/architecture.md §3) is unchanged. `vectors/pack-grading.json` is the
|
|
58
|
-
// conformance statement of the rule and ships in the published tarball, so a
|
|
59
|
-
// consumer that cannot yet import `gradePack` can vendor the table, hold its own
|
|
60
|
-
// derivation to it, and diff its copy against ours. Additive — no existing
|
|
61
|
-
// export changes.
|
|
18
|
+
// Pack grading: what a verification surface may claim about a pack and the
|
|
19
|
+
// disclosed bytes beside it (evidence-bundle.md §5.1, §6). Pure.
|
|
20
|
+
// `vectors/pack-grading.json` states the rule for consumers to test against.
|
|
62
21
|
export { PACK_GRADE_CAUSE_KINDS, PACK_VERDICTS, accountDisclosure, completenessNotes, gradeCauses, gradePack, renderCause, signedLeafCount, } from "./grading.js";
|
|
63
|
-
// The declaration
|
|
64
|
-
//
|
|
65
|
-
//
|
|
66
|
-
// Every other check in this kernel checks a record that is PRESENT, so a pack
|
|
67
|
-
// with half its records dropped verifies perfectly and an auditor cannot tell
|
|
68
|
-
// a full hand-over from a trimmed one. The declaration is the pack's own
|
|
69
|
-
// statement of what it was meant to contain, inside `body` and therefore under
|
|
70
|
-
// the bundle's signature. Any deviation FAILS and every deviation is NAMED; a
|
|
71
|
-
// pack that carries no declaration is `partial`, never `verified`; and a
|
|
72
|
-
// reading that rests on the UNSIGNED content handed in beside the pack is
|
|
73
|
-
// named on its own and carries the weaker word, because whoever assembles a
|
|
74
|
-
// case chose those bytes (proof#147).
|
|
75
|
-
//
|
|
76
|
-
// Pure: data in, data out, no I/O. `gradePack` takes the result as an
|
|
77
|
-
// optional fourth argument, so a surface gets one verdict; omitting it is the
|
|
78
|
-
// pre-§5.4 behavior, unchanged. Additive: no existing export changes.
|
|
22
|
+
// The declaration: what a pack says it holds, checked against what it does
|
|
23
|
+
// (evidence-bundle.md §5.4). Pure. `gradePack` takes the result as an optional
|
|
24
|
+
// fourth argument.
|
|
79
25
|
export { DECLARATION_CONTENT_KINDS, DECLARATION_DEVIATION_KINDS, DECLARATION_NOTE_KINDS, DECLARATION_ROLES, DECLARATION_VERDICTS, DECLARATION_VERSION, DECLARATION_VERSION_V2, DECLARATION_VERSION_V3, DECLARATION_VERSIONS, checkDeclaration, declarationClaims, packRecords, renderContentFinding, renderDeclarationSummary, renderDeviation, renderNote, } from "./declaration.js";
|
|
80
|
-
// The case
|
|
81
|
-
//
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
//
|
|
86
|
-
//
|
|
87
|
-
// packs at once is what closes it: a `handoff.sent` with no counterpart is
|
|
88
|
-
// always named, and where a pack signed by the key it names is in the case, the
|
|
89
|
-
// reading says that pack holds no counterpart (unless every candidate was
|
|
90
|
-
// accounted for under A20, which reads as no counterpart and names no pack). Whether a party that presented
|
|
91
|
-
// no such pack recorded anything is not established (proof#143). `readCase`
|
|
92
|
-
// 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
|
|
93
|
-
// organizations verifies (DL-60).
|
|
94
|
-
//
|
|
95
|
-
// Pure: data in, data out, no I/O. Additive: a new module, no existing export
|
|
96
|
-
// changes, and no new verdict word anywhere.
|
|
97
|
-
export { CASE_BODY_TYPES, CASE_EXCEPTION_KINDS, CASE_QUARANTINED_PROFILES, CASE_RECORD_PROFILES, CASE_RECORD_STATUSES, CASE_NOTE_KINDS, CASE_RELIANCE, CASE_RELIANCE_HANDOFF_CLAUSE, CASE_VERDICTS, CONTENT_WITHHELD_BY_DECLARATION, CO_SIGNATURES_PRESENT, VERDICT_DISPLAY_TITLES, WITNESS_NOT_LOOKED_UP, WITNESS_STATES, WITNESS_TIME_CACHED, WITNESS_TIME_RECORDED, caseReliance, readCase, renderCaseNote, renderCaseSummary, renderException, renderWitnessLine, } from "./case.js";
|
|
98
|
-
// The witnessed-time cache (evidence-bundle 5.6.6, v1.25, A30): read it, look it
|
|
99
|
-
// up, print it. Never an input to a verdict.
|
|
26
|
+
// The case: one verdict over several parties' packs, closing what a single
|
|
27
|
+
// pack cannot prove about its own omissions (evidence-bundle.md §5.5).
|
|
28
|
+
// Matching is on keys and hashes alone, never tenancy, so a pair across two
|
|
29
|
+
// organizations verifies. `readCase` verifies every pack itself, offline.
|
|
30
|
+
export { CASE_BODY_TYPES, CASE_EXCEPTION_KINDS, CASE_QUARANTINED_PROFILES, CASE_RECORD_PROFILES, CASE_RECORD_STATUSES, CASE_NOTE_KINDS, CASE_RELIANCE, CASE_RELIANCE_HANDOFF_CLAUSE, CASE_RELIANCE_SANDBOX, CASE_VERDICTS, CONTENT_WITHHELD_BY_DECLARATION, CO_SIGNATURES_PRESENT, VERDICT_DISPLAY_TITLES, WITNESS_NOT_LOOKED_UP, WITNESS_STATES, WITNESS_TIME_CACHED, WITNESS_TIME_RECORDED, caseProblems, caseReliance, readCase, renderCaseNote, renderCaseSummary, renderException, renderWitnessLine, } from "./case.js";
|
|
31
|
+
// The witnessed-time cache (evidence-bundle.md §5.6.6). Never an input to a
|
|
32
|
+
// verdict.
|
|
100
33
|
export { MAX_BLOCK_TIME, MAX_WITNESS_CACHE_DEPTH, WITNESS_CACHE_NAME, WITNESS_CACHE_VERSION, checkWitnessCache, formatBlockTime, readWitnessCache, renderWitnessTime, witnessTimeQuery, } from "./witness-cache.js";
|
|
101
|
-
// The public-record
|
|
102
|
-
//
|
|
103
|
-
//
|
|
104
|
-
//
|
|
105
|
-
|
|
106
|
-
//
|
|
107
|
-
//
|
|
108
|
-
|
|
109
|
-
//
|
|
110
|
-
//
|
|
111
|
-
// point a page wants, additive over both. `confirmed` from
|
|
112
|
-
// `lookupPublicRecord` is a claim about the BYTES only, never about whether
|
|
113
|
-
// the pack itself verifies, and a caller must never show it apart from the
|
|
114
|
-
// pack's own verdict.
|
|
115
|
-
export { lookupPublicRecord, onChainHalf, witnessLine } from "./witness-lookup.js";
|
|
116
|
-
// The case file's index (src/case-file.ts, evidence-bundle.md §5.6, A25):
|
|
117
|
-
// compared with the drop it describes, with NO verdict contribution. The index
|
|
118
|
-
// is never an input to `readCase`. Pure: bytes and a file list in.
|
|
34
|
+
// The public-record lookup behind `--gateways`. The only network call runs when
|
|
35
|
+
// a caller hands in a gateway, through `options.fetchImpl` or the global
|
|
36
|
+
// `fetch`, so it runs in a browser. `confirmed` is a claim about the bytes
|
|
37
|
+
// only: never show it apart from the pack's own verdict.
|
|
38
|
+
export { lookupPublicRecord, onChainHalf, onChainOutcome, onChainRow, witnessLine, } from "./witness-lookup.js";
|
|
39
|
+
// Six claims, three verdicts, and the person layer (evidence-bundle.md section 3): every
|
|
40
|
+
// detailed kind maps to one claim and one state, and the verdict is read off the claims.
|
|
41
|
+
export { CLAIMS, CLAIM_LABELS, CLAIM_QUESTIONS, CLAIM_STATES, ENVELOPE_FAULT_KINDS, KIND_CLAIMS, NOTE_FINDINGS, NOTE_ORDER, NOT_IN_SCOPE_REASONS, NOT_PROVEN_REASONS, PERSON_TITLES, PERSON_TITLE_PARTS, REASON_KINDS, RECORD_REASON_CLAIMS, RECORD_REASON_LINES, SANDBOX_PERSON_LINE, VERDICTS, VERDICT_COLOURS, VERDICT_TITLES, bundleProblems, claimsOf, downgraded, note, orderedNotes, restOnSigned, personText, problem, problemToJson, renderFindingNote, renderPerson, verdictOf, withItems, } from "./claims.js";
|
|
42
|
+
// The case file's index (evidence-bundle.md §5.6), compared with the drop it
|
|
43
|
+
// describes. Never an input to `readCase` or any verdict.
|
|
119
44
|
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";
|
|
120
|
-
// Files handed in beside a pack (
|
|
121
|
-
//
|
|
122
|
-
// pack's SIGNED records make, by hash alone. Never moves a verdict.
|
|
45
|
+
// Files handed in beside a pack (evidence-bundle.md §5.7), matched by SHA-256
|
|
46
|
+
// against the pack's signed commitments. Never moves a verdict.
|
|
123
47
|
export { FILE_MATCH_SCOPE, NOT_READ_REASONS, SKIPPED_REASONS, fileMatchToJson, matchCaseFiles, matchFiles, notAccountedFor, renderFileMatch, } from "./file-match.js";
|
|
124
|
-
// Chain reading
|
|
125
|
-
//
|
|
126
|
-
//
|
|
127
|
-
//
|
|
128
|
-
//
|
|
129
|
-
// chain that restarted after a crash and now asserts two beginnings — passed
|
|
130
|
-
// every check we had (proof#43). The verifier was right not to do this: it
|
|
131
|
-
// verifies a single envelope and says so. Nothing above it did it either.
|
|
132
|
-
//
|
|
133
|
-
// Pure — data in, data out, no I/O — so the kernel's scope boundary
|
|
134
|
-
// (specs/architecture.md §3) is unchanged, and the rule ships as
|
|
135
|
-
// `vectors/chain-reading.json` beside the pack-grading table for the same
|
|
136
|
-
// reason: a rule consumers must agree with needs a statement they can fetch.
|
|
137
|
-
//
|
|
138
|
-
// It returns FINDINGS, never a verdict, and it feeds no status on its own: a
|
|
139
|
-
// pack's signed v3 declaration can claim a chain complete and in order, and
|
|
140
|
-
// `checkDeclaration` holds that claim to the links `readChainLinks` reads
|
|
141
|
-
// (evidence-bundle.md 5.4.2 rule 11). Chain links are
|
|
142
|
-
// deletion/reorder-evidence for the events present and NOT a completeness proof
|
|
143
|
-
// (`anchor/docs/profile-sanning.events-v2.md` §5), drop the last N events of a
|
|
144
|
-
// chain and nothing dangles. `CHAIN_READING_SCOPE` is that sentence, exported so
|
|
145
|
-
// every surface prints the same limit rather than paraphrasing it into a claim.
|
|
146
|
-
// Additive — no existing export changes.
|
|
48
|
+
// Chain reading: findings over the `previous_hash` links one bundle presents,
|
|
49
|
+
// never a verdict and never a completeness proof. `CHAIN_READING_SCOPE` is the
|
|
50
|
+
// sentence every surface prints beside them. `vectors/chain-reading.json`
|
|
51
|
+
// states the rule; a v3 declaration's chain claim is checked against
|
|
52
|
+
// `readChainLinks` (evidence-bundle.md §5.4.2 rule 11).
|
|
147
53
|
export { ADAPTER_CHAIN_NAMESPACES, CHAIN_READING_SCOPE, readChainLinks, readChains, renderChainFinding, } from "./chain.js";
|
|
148
|
-
// The `proof export` composer (specs/evidence-export.md §5
|
|
149
|
-
//
|
|
150
|
-
//
|
|
151
|
-
|
|
152
|
-
//
|
|
153
|
-
//
|
|
154
|
-
export {
|
|
155
|
-
// Sandbox evidence: the environment marker over the envelopes a pack or case
|
|
156
|
-
// holds (envelope-spec §2, the `environment_marker` MAY), and the headline and
|
|
157
|
-
// line both commands print for it. Additive.
|
|
158
|
-
export { SANDBOX_HEADLINE, SANDBOX_LINE, SANDBOX_TITLE, environmentMarker, onlySimulatedUnsettled, packEnvelopes, } from "./environment.js";
|
|
54
|
+
// The `proof export` composer (specs/evidence-export.md §5): a signed,
|
|
55
|
+
// offline-verifiable sanning.evidence.export/v2 artifact. Also the one
|
|
56
|
+
// exit-code table and help text every verb uses.
|
|
57
|
+
export { EXIT_CODES, EXIT_CODES_HELP, EXIT_COULD_NOT_RUN, EXIT_FAILED, EXIT_INCOMPLETE, EXIT_SANDBOX, EXIT_VERIFIED, exitCodeFor, } from "./exit-codes.js";
|
|
58
|
+
// Sandbox evidence: the environment marker over a pack's or case's envelopes
|
|
59
|
+
// (envelope-spec section 2).
|
|
60
|
+
export { environmentMarker, packEnvelopes, } from "./environment.js";
|
|
159
61
|
export { attestationSignatureToHex, composeExport } from "./compose.js";
|
|
160
|
-
//
|
|
161
|
-
//
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
//
|
|
165
|
-
//
|
|
166
|
-
// is ordered, and what a formed pair grades to (specs/envelope-spec.md §4.1
|
|
167
|
-
// v1.9, proof#132 and proof#136). The Python half is src/sanning_proof/handoff.py and the two
|
|
168
|
-
// answer identically on identical bytes. Additive: a new module, and no
|
|
169
|
-
// existing export changes.
|
|
170
|
-
export { CANDIDATE_NAMESPACE, DEFINED_EVENT_TYPES, NOT_A_HANDOFF_FINDING, isConformantHandoffRecord, readHandoff, readHandoffs, recordIsMalformed, } from "./handoff.js";
|
|
171
|
-
// A file part's BYTES (src/message-parts.ts): what a file part is, and what a
|
|
172
|
-
// receiver that HOLDS a part's bytes commits to (envelope-spec.md section 4.1
|
|
173
|
-
// v1.13, A18, proof#145). A receiver that holds the bytes hashes them and, on a
|
|
174
|
-
// mismatch, commits to the message AS IT HELD IT, so the pair fails on
|
|
175
|
-
// `message_hash` rather than verifying over bytes nobody checked. The Python
|
|
176
|
-
// half is src/sanning_proof/message_parts.py and the two are held together by
|
|
177
|
-
// cross-kernel/run_parts.sh. Pure: it neither canonicalizes nor hashes the
|
|
178
|
-
// message.
|
|
62
|
+
// The hand-off pairing rule (envelope-spec.md §4.1). The Python half answers
|
|
63
|
+
// identically on identical bytes.
|
|
64
|
+
export { CANDIDATE_NAMESPACE, DEFINED_EVENT_TYPES, NOT_A_HANDOFF_FINDING, isConformantHandoffRecord, readHandoff, readHandoffs, recordDefect, recordIsMalformed, recordIsNonconforming, } from "./handoff.js";
|
|
65
|
+
// File parts (envelope-spec.md §4.1): a receiver holding a part's bytes
|
|
66
|
+
// commits to the message as it held it, so a mismatch fails on `message_hash`
|
|
67
|
+
// rather than verifying over unchecked bytes.
|
|
179
68
|
export { BYTES_FOR_UNKNOWN_PART, CONFLICTING_PART_BYTES, INLINE_BYTES_KEYS, MESSAGE_RESULT_ORDER, PARTS_NOT_AN_ARRAY, PART_ENCODING_MISMATCH, PART_INLINE_BYTES, PART_INLINE_MISMATCHED, PART_MALFORMED_DESCRIPTOR, PART_MATCHED, PART_MISMATCHED, PART_NOT_A_FILE, PART_SUPPLIED_TWICE, PART_UNCHECKED, REFUSAL_ORDER, commitHeldMessage, isFilePart, uncheckedHeldParts, } from "./message-parts.js";
|
|
69
|
+
// Reading a sanning.agent record (vendor/specs/agent-events.md §10) against
|
|
70
|
+
// the schemas bundled from the pinned specs release: no file read, no fetch.
|
|
71
|
+
export { AGENT_EVENT_TYPES, RECORD_TYPES_OUTSIDE_AGENT, readAgentRecord, readAgentRecordWithHeld, readAgentRecords, renderAgentReading, } from "./agent-record.js";
|
|
72
|
+
export { AGENT_SCHEMA_PIN, AGENT_SCHEMA_VERSIONS } from "./agent-schemas.generated.js";
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type JsonSchema = boolean | {
|
|
2
|
+
readonly [keyword: string]: unknown;
|
|
3
|
+
};
|
|
4
|
+
export type SchemaReason = "unknown_field" | "missing_field" | "bad_value";
|
|
5
|
+
export interface SchemaError {
|
|
6
|
+
readonly reason: SchemaReason;
|
|
7
|
+
readonly at: string;
|
|
8
|
+
}
|
|
9
|
+
/** Validate against schemas that reference each other by `$id`. */
|
|
10
|
+
export declare class SchemaSet {
|
|
11
|
+
private readonly documents;
|
|
12
|
+
private readonly patterns;
|
|
13
|
+
constructor(documents: readonly JsonSchema[]);
|
|
14
|
+
/** Every error `value` has against the document whose `$id` is `id`; empty when it validates. */
|
|
15
|
+
validate(id: string, value: unknown): SchemaError[];
|
|
16
|
+
private check;
|
|
17
|
+
private passes;
|
|
18
|
+
private resolve;
|
|
19
|
+
private pattern;
|
|
20
|
+
}
|
|
21
|
+
/** JSON equality, without recursion so a deeply nested value cannot overflow the stack. */
|
|
22
|
+
export declare function deepEqual(a: unknown, b: unknown): boolean;
|
|
23
|
+
export declare function isObject(v: unknown): v is Record<string, unknown>;
|
|
24
|
+
export declare function has(obj: object, key: string): boolean;
|
|
25
|
+
/** One JSON Pointer reference token (RFC 6901). */
|
|
26
|
+
export declare function escapeToken(t: string): string;
|
|
27
|
+
export declare function unescapeToken(t: string): string;
|
|
28
|
+
/** Freeze `value` and every object and array inside it. */
|
|
29
|
+
export declare function deepFreeze<T>(value: T): T;
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
// A JSON Schema (draft 2020-12) validator for the keywords the pinned
|
|
2
|
+
// sanning.agent schemas use, and no others. It reads schemas handed to it as
|
|
3
|
+
// data, resolves `$ref` among them by `$id`, and never fetches anything. A
|
|
4
|
+
// keyword outside the supported set throws rather than being skipped: a later
|
|
5
|
+
// pin that adds one must fail loudly, never validate less than it says.
|
|
6
|
+
//
|
|
7
|
+
// Errors are collected in all-errors mode and returned as the reasons of
|
|
8
|
+
// agent-events.md §10 step 4 and §10.1: `unknown_field` (additionalProperties), `missing_field`
|
|
9
|
+
// (required) and `bad_value` (anything else), each at a JSON Pointer.
|
|
10
|
+
// Keywords that carry no assertion.
|
|
11
|
+
const ANNOTATIONS = new Set(["$schema", "$id", "$defs", "title", "description"]);
|
|
12
|
+
const ASSERTIONS = new Set([
|
|
13
|
+
"$ref",
|
|
14
|
+
"type",
|
|
15
|
+
"const",
|
|
16
|
+
"enum",
|
|
17
|
+
"not",
|
|
18
|
+
"anyOf",
|
|
19
|
+
"properties",
|
|
20
|
+
"additionalProperties",
|
|
21
|
+
"required",
|
|
22
|
+
"minProperties",
|
|
23
|
+
"items",
|
|
24
|
+
"minItems",
|
|
25
|
+
"maxItems",
|
|
26
|
+
"uniqueItems",
|
|
27
|
+
"pattern",
|
|
28
|
+
"minLength",
|
|
29
|
+
"maxLength",
|
|
30
|
+
"minimum",
|
|
31
|
+
"maximum",
|
|
32
|
+
]);
|
|
33
|
+
/** Validate against schemas that reference each other by `$id`. */
|
|
34
|
+
export class SchemaSet {
|
|
35
|
+
documents = new Map();
|
|
36
|
+
patterns = new Map();
|
|
37
|
+
constructor(documents) {
|
|
38
|
+
for (const d of documents) {
|
|
39
|
+
if (typeof d !== "object" || typeof d.$id !== "string") {
|
|
40
|
+
throw new Error("json-schema: every document needs an $id");
|
|
41
|
+
}
|
|
42
|
+
supportedOnly(d);
|
|
43
|
+
this.documents.set(stripFragment(d.$id), d);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** Every error `value` has against the document whose `$id` is `id`; empty when it validates. */
|
|
47
|
+
validate(id, value) {
|
|
48
|
+
const doc = this.documents.get(id);
|
|
49
|
+
if (doc === undefined)
|
|
50
|
+
throw new Error(`json-schema: no document ${id}`);
|
|
51
|
+
const errors = [];
|
|
52
|
+
this.check(doc, id, value, "", errors);
|
|
53
|
+
return errors;
|
|
54
|
+
}
|
|
55
|
+
check(schema, base, value, at, errors) {
|
|
56
|
+
if (schema === true)
|
|
57
|
+
return;
|
|
58
|
+
if (schema === false) {
|
|
59
|
+
errors.push({ reason: "bad_value", at });
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const s = schema;
|
|
63
|
+
const bad = () => {
|
|
64
|
+
errors.push({ reason: "bad_value", at });
|
|
65
|
+
};
|
|
66
|
+
if (s.$ref !== undefined) {
|
|
67
|
+
const [doc, target] = this.resolve(String(s.$ref), base);
|
|
68
|
+
this.check(target, doc, value, at, errors);
|
|
69
|
+
}
|
|
70
|
+
if (s.type !== undefined) {
|
|
71
|
+
const types = Array.isArray(s.type) ? s.type : [s.type];
|
|
72
|
+
if (!types.some((t) => hasType(value, t)))
|
|
73
|
+
bad();
|
|
74
|
+
}
|
|
75
|
+
if (has(s, "const") && !deepEqual(value, s.const))
|
|
76
|
+
bad();
|
|
77
|
+
if (s.enum !== undefined && !s.enum.some((e) => deepEqual(value, e)))
|
|
78
|
+
bad();
|
|
79
|
+
if (s.not !== undefined && this.passes(s.not, base, value))
|
|
80
|
+
bad();
|
|
81
|
+
if (s.anyOf !== undefined) {
|
|
82
|
+
const branchErrors = [];
|
|
83
|
+
let passed = false;
|
|
84
|
+
for (const branch of s.anyOf) {
|
|
85
|
+
const e = [];
|
|
86
|
+
this.check(branch, base, value, at, e);
|
|
87
|
+
if (e.length === 0) {
|
|
88
|
+
passed = true;
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
branchErrors.push(...e);
|
|
92
|
+
}
|
|
93
|
+
if (!passed) {
|
|
94
|
+
errors.push(...branchErrors);
|
|
95
|
+
bad();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (typeof value === "string") {
|
|
99
|
+
if (s.pattern !== undefined && !this.pattern(String(s.pattern)).test(value))
|
|
100
|
+
bad();
|
|
101
|
+
if (s.minLength !== undefined && codePoints(value) < s.minLength)
|
|
102
|
+
bad();
|
|
103
|
+
if (s.maxLength !== undefined && codePoints(value) > s.maxLength)
|
|
104
|
+
bad();
|
|
105
|
+
}
|
|
106
|
+
if (typeof value === "number") {
|
|
107
|
+
if (s.minimum !== undefined && value < s.minimum)
|
|
108
|
+
bad();
|
|
109
|
+
if (s.maximum !== undefined && value > s.maximum)
|
|
110
|
+
bad();
|
|
111
|
+
}
|
|
112
|
+
if (Array.isArray(value)) {
|
|
113
|
+
if (s.minItems !== undefined && value.length < s.minItems)
|
|
114
|
+
bad();
|
|
115
|
+
if (s.maxItems !== undefined && value.length > s.maxItems)
|
|
116
|
+
bad();
|
|
117
|
+
if (s.uniqueItems === true && !allUnique(value))
|
|
118
|
+
bad();
|
|
119
|
+
if (s.items !== undefined) {
|
|
120
|
+
value.forEach((item, i) => this.check(s.items, base, item, `${at}/${i}`, errors));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (isObject(value)) {
|
|
124
|
+
const props = (s.properties ?? {});
|
|
125
|
+
if (s.required !== undefined) {
|
|
126
|
+
for (const name of s.required) {
|
|
127
|
+
if (!has(value, name))
|
|
128
|
+
errors.push({ reason: "missing_field", at: `${at}/${escapeToken(name)}` });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (s.minProperties !== undefined && Object.keys(value).length < s.minProperties)
|
|
132
|
+
bad();
|
|
133
|
+
for (const key of Object.keys(value)) {
|
|
134
|
+
const child = `${at}/${escapeToken(key)}`;
|
|
135
|
+
if (has(props, key)) {
|
|
136
|
+
this.check(props[key], base, value[key], child, errors);
|
|
137
|
+
}
|
|
138
|
+
else if (s.additionalProperties === false) {
|
|
139
|
+
errors.push({ reason: "unknown_field", at: child });
|
|
140
|
+
}
|
|
141
|
+
else if (s.additionalProperties !== undefined) {
|
|
142
|
+
this.check(s.additionalProperties, base, value[key], child, errors);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
passes(schema, base, value) {
|
|
148
|
+
const e = [];
|
|
149
|
+
this.check(schema, base, value, "", e);
|
|
150
|
+
return e.length === 0;
|
|
151
|
+
}
|
|
152
|
+
resolve(ref, base) {
|
|
153
|
+
const url = new URL(ref, base);
|
|
154
|
+
const doc = stripFragment(url.href);
|
|
155
|
+
let target = this.documents.get(doc);
|
|
156
|
+
if (target === undefined)
|
|
157
|
+
throw new Error(`json-schema: no document for $ref ${ref}`);
|
|
158
|
+
const fragment = decodeURIComponent(url.hash.slice(1));
|
|
159
|
+
if (fragment !== "") {
|
|
160
|
+
if (!fragment.startsWith("/"))
|
|
161
|
+
throw new Error(`json-schema: unsupported $ref ${ref}`);
|
|
162
|
+
for (const token of fragment.slice(1).split("/")) {
|
|
163
|
+
const t = unescapeToken(token);
|
|
164
|
+
if (!isObject(target) || !has(target, t))
|
|
165
|
+
throw new Error(`json-schema: unresolved $ref ${ref}`);
|
|
166
|
+
target = target[t];
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return [doc, target];
|
|
170
|
+
}
|
|
171
|
+
pattern(source) {
|
|
172
|
+
let re = this.patterns.get(source);
|
|
173
|
+
if (re === undefined) {
|
|
174
|
+
// ECMA-262 with the `u` flag, as JSON Schema reads `pattern`: `$` is the
|
|
175
|
+
// end of the string, with no exception for a final newline.
|
|
176
|
+
re = new RegExp(source, "u");
|
|
177
|
+
this.patterns.set(source, re);
|
|
178
|
+
}
|
|
179
|
+
return re;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/** Throw on a keyword this validator does not implement, anywhere in `schema`. */
|
|
183
|
+
function supportedOnly(schema) {
|
|
184
|
+
const stack = [schema];
|
|
185
|
+
while (stack.length > 0) {
|
|
186
|
+
const s = stack.pop();
|
|
187
|
+
if (typeof s === "boolean")
|
|
188
|
+
continue;
|
|
189
|
+
if (!isObject(s))
|
|
190
|
+
throw new Error("json-schema: a schema is an object or a boolean");
|
|
191
|
+
for (const [k, v] of Object.entries(s)) {
|
|
192
|
+
if (!ANNOTATIONS.has(k) && !ASSERTIONS.has(k))
|
|
193
|
+
throw new Error(`json-schema: unsupported keyword ${k}`);
|
|
194
|
+
if (k === "properties" || k === "$defs")
|
|
195
|
+
stack.push(...Object.values(v));
|
|
196
|
+
else if (k === "anyOf")
|
|
197
|
+
stack.push(...v);
|
|
198
|
+
else if (k === "items" || k === "not" || k === "additionalProperties")
|
|
199
|
+
stack.push(v);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
function stripFragment(id) {
|
|
204
|
+
const i = id.indexOf("#");
|
|
205
|
+
return i === -1 ? id : id.slice(0, i);
|
|
206
|
+
}
|
|
207
|
+
function hasType(value, type) {
|
|
208
|
+
switch (type) {
|
|
209
|
+
case "null":
|
|
210
|
+
return value === null;
|
|
211
|
+
case "boolean":
|
|
212
|
+
return typeof value === "boolean";
|
|
213
|
+
case "string":
|
|
214
|
+
return typeof value === "string";
|
|
215
|
+
case "number":
|
|
216
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
217
|
+
case "integer":
|
|
218
|
+
return Number.isInteger(value);
|
|
219
|
+
case "array":
|
|
220
|
+
return Array.isArray(value);
|
|
221
|
+
case "object":
|
|
222
|
+
return isObject(value);
|
|
223
|
+
default:
|
|
224
|
+
throw new Error(`json-schema: unsupported type ${type}`);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
/** String length as JSON Schema counts it: in code points, not UTF-16 code units. */
|
|
228
|
+
function codePoints(s) {
|
|
229
|
+
let n = 0;
|
|
230
|
+
for (const _ of s)
|
|
231
|
+
n++;
|
|
232
|
+
return n;
|
|
233
|
+
}
|
|
234
|
+
function allUnique(items) {
|
|
235
|
+
for (let i = 0; i < items.length; i++) {
|
|
236
|
+
for (let j = i + 1; j < items.length; j++) {
|
|
237
|
+
if (deepEqual(items[i], items[j]))
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
/** JSON equality, without recursion so a deeply nested value cannot overflow the stack. */
|
|
244
|
+
export function deepEqual(a, b) {
|
|
245
|
+
const stack = [[a, b]];
|
|
246
|
+
while (stack.length > 0) {
|
|
247
|
+
const [x, y] = stack.pop();
|
|
248
|
+
if (x === y)
|
|
249
|
+
continue;
|
|
250
|
+
if (Array.isArray(x)) {
|
|
251
|
+
if (!Array.isArray(y) || x.length !== y.length)
|
|
252
|
+
return false;
|
|
253
|
+
for (let i = 0; i < x.length; i++)
|
|
254
|
+
stack.push([x[i], y[i]]);
|
|
255
|
+
continue;
|
|
256
|
+
}
|
|
257
|
+
if (isObject(x)) {
|
|
258
|
+
if (!isObject(y))
|
|
259
|
+
return false;
|
|
260
|
+
const kx = Object.keys(x);
|
|
261
|
+
if (kx.length !== Object.keys(y).length)
|
|
262
|
+
return false;
|
|
263
|
+
for (const k of kx) {
|
|
264
|
+
if (!has(y, k))
|
|
265
|
+
return false;
|
|
266
|
+
stack.push([x[k], y[k]]);
|
|
267
|
+
}
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
return true;
|
|
273
|
+
}
|
|
274
|
+
export function isObject(v) {
|
|
275
|
+
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
276
|
+
}
|
|
277
|
+
export function has(obj, key) {
|
|
278
|
+
return Object.prototype.hasOwnProperty.call(obj, key);
|
|
279
|
+
}
|
|
280
|
+
/** One JSON Pointer reference token (RFC 6901). */
|
|
281
|
+
export function escapeToken(t) {
|
|
282
|
+
return t.replaceAll("~", "~0").replaceAll("/", "~1");
|
|
283
|
+
}
|
|
284
|
+
export function unescapeToken(t) {
|
|
285
|
+
return t.replaceAll("~1", "/").replaceAll("~0", "~");
|
|
286
|
+
}
|
|
287
|
+
/** Freeze `value` and every object and array inside it. */
|
|
288
|
+
export function deepFreeze(value) {
|
|
289
|
+
const stack = [value];
|
|
290
|
+
while (stack.length > 0) {
|
|
291
|
+
const v = stack.pop();
|
|
292
|
+
if (v !== null && typeof v === "object" && !Object.isFrozen(v)) {
|
|
293
|
+
Object.freeze(v);
|
|
294
|
+
stack.push(...Object.values(v));
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return value;
|
|
298
|
+
}
|