@zanii/certify 0.0.0-stage → 0.6.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.
Files changed (141) hide show
  1. package/LICENSE +159 -0
  2. package/README.md +144 -2
  3. package/dist/appliance-execution.d.ts +18 -0
  4. package/dist/appliance-execution.js +12 -0
  5. package/dist/appliance.d.ts +135 -0
  6. package/dist/appliance.js +253 -0
  7. package/dist/assurance-status.d.ts +58 -0
  8. package/dist/assurance-status.js +86 -0
  9. package/dist/audit-renewal.d.ts +39 -0
  10. package/dist/audit-renewal.js +62 -0
  11. package/dist/audit.d.ts +69 -0
  12. package/dist/audit.js +112 -0
  13. package/dist/beacon-client.d.ts +40 -0
  14. package/dist/beacon-client.js +151 -0
  15. package/dist/beacon.d.ts +84 -0
  16. package/dist/beacon.js +106 -0
  17. package/dist/bitstring-status.d.ts +56 -0
  18. package/dist/bitstring-status.js +135 -0
  19. package/dist/board.d.ts +218 -0
  20. package/dist/board.js +428 -0
  21. package/dist/bundle.d.ts +100 -0
  22. package/dist/bundle.js +122 -0
  23. package/dist/certificate.d.ts +161 -0
  24. package/dist/certificate.js +346 -0
  25. package/dist/cli-messages.json +148 -0
  26. package/dist/cli.d.ts +16 -0
  27. package/dist/cli.js +369 -0
  28. package/dist/current-issuer-vc.d.ts +20 -0
  29. package/dist/current-issuer-vc.js +60 -0
  30. package/dist/evidence-share.d.ts +89 -0
  31. package/dist/evidence-share.js +479 -0
  32. package/dist/federation.d.ts +103 -0
  33. package/dist/federation.js +240 -0
  34. package/dist/feed-snapshot.d.ts +97 -0
  35. package/dist/feed-snapshot.js +186 -0
  36. package/dist/fingerprint.d.ts +23 -0
  37. package/dist/fingerprint.js +48 -0
  38. package/dist/formats/status-v2.schema.json +31 -0
  39. package/dist/governance.d.ts +244 -0
  40. package/dist/governance.js +418 -0
  41. package/dist/identity.d.ts +79 -0
  42. package/dist/identity.js +146 -0
  43. package/dist/impartiality.d.ts +47 -0
  44. package/dist/impartiality.js +85 -0
  45. package/dist/index.d.ts +61 -0
  46. package/dist/index.js +63 -0
  47. package/dist/issuer-authorization.d.ts +4 -0
  48. package/dist/issuer-authorization.js +52 -0
  49. package/dist/issuer-resolution.d.ts +25 -0
  50. package/dist/issuer-resolution.js +89 -0
  51. package/dist/licence-owner-entry.d.ts +20 -0
  52. package/dist/licence-owner-entry.js +33 -0
  53. package/dist/licence-owner.d.ts +67 -0
  54. package/dist/licence-owner.js +180 -0
  55. package/dist/licence.d.ts +174 -0
  56. package/dist/licence.js +400 -0
  57. package/dist/live-evidence.d.ts +135 -0
  58. package/dist/live-evidence.js +210 -0
  59. package/dist/nitro-roots.d.ts +3 -0
  60. package/dist/nitro-roots.js +20 -0
  61. package/dist/nitro-x509.d.ts +16 -0
  62. package/dist/nitro-x509.js +141 -0
  63. package/dist/nitro.d.ts +74 -0
  64. package/dist/nitro.js +329 -0
  65. package/dist/normalization.d.ts +8 -0
  66. package/dist/normalization.js +10 -0
  67. package/dist/pq.d.ts +32 -0
  68. package/dist/pq.js +69 -0
  69. package/dist/profile.d.ts +15 -0
  70. package/dist/profile.js +165 -0
  71. package/dist/register.d.ts +79 -0
  72. package/dist/register.js +134 -0
  73. package/dist/rotation.d.ts +49 -0
  74. package/dist/rotation.js +124 -0
  75. package/dist/royalty-reconciliation.d.ts +24 -0
  76. package/dist/royalty-reconciliation.js +88 -0
  77. package/dist/runtime-client.d.ts +40 -0
  78. package/dist/runtime-client.js +190 -0
  79. package/dist/runtime-gateway.d.ts +26 -0
  80. package/dist/runtime-gateway.js +169 -0
  81. package/dist/runtime-knowledge.d.ts +28 -0
  82. package/dist/runtime-knowledge.js +75 -0
  83. package/dist/runtime-nitro.d.ts +30 -0
  84. package/dist/runtime-nitro.js +57 -0
  85. package/dist/runtime.d.ts +226 -0
  86. package/dist/runtime.js +254 -0
  87. package/dist/sandbox-delegation.d.ts +38 -0
  88. package/dist/sandbox-delegation.js +61 -0
  89. package/dist/schema-dialect.d.ts +1 -0
  90. package/dist/schema-dialect.js +97 -0
  91. package/dist/schemas/clause-map.schema.json +52 -0
  92. package/dist/schemas/profile.schema.json +81 -0
  93. package/dist/schemas/scenarios.schema.json +573 -0
  94. package/dist/schemas/suite.schema.json +138 -0
  95. package/dist/schemas/trajectory.schema.json +1396 -0
  96. package/dist/scheme-authority.d.ts +5 -0
  97. package/dist/scheme-authority.js +15 -0
  98. package/dist/scheme-entry.d.ts +25 -0
  99. package/dist/scheme-entry.js +85 -0
  100. package/dist/scheme-history.d.ts +5 -0
  101. package/dist/scheme-history.js +87 -0
  102. package/dist/scheme-log.d.ts +98 -0
  103. package/dist/scheme-log.js +266 -0
  104. package/dist/scheme-merkle.d.ts +2 -0
  105. package/dist/scheme-merkle.js +20 -0
  106. package/dist/scheme-text.d.ts +25 -0
  107. package/dist/scheme-text.js +46 -0
  108. package/dist/scheme-timing.d.ts +16 -0
  109. package/dist/scheme-timing.js +22 -0
  110. package/dist/scheme-transition.d.ts +47 -0
  111. package/dist/scheme-transition.js +101 -0
  112. package/dist/scoring.d.ts +35 -0
  113. package/dist/scoring.js +50 -0
  114. package/dist/shared.d.ts +16 -0
  115. package/dist/shared.js +20 -0
  116. package/dist/signer.d.ts +18 -0
  117. package/dist/signer.js +49 -0
  118. package/dist/signing-identity.d.ts +1 -0
  119. package/dist/signing-identity.js +11 -0
  120. package/dist/status.d.ts +113 -0
  121. package/dist/status.js +204 -0
  122. package/dist/succession.d.ts +21 -0
  123. package/dist/succession.js +67 -0
  124. package/dist/suite.d.ts +261 -0
  125. package/dist/suite.js +458 -0
  126. package/dist/trajectory.d.ts +216 -0
  127. package/dist/trajectory.js +409 -0
  128. package/dist/transcript-provenance.d.ts +25 -0
  129. package/dist/transcript-provenance.js +37 -0
  130. package/dist/transport-key.d.ts +3 -0
  131. package/dist/transport-key.js +16 -0
  132. package/dist/vc.d.ts +29 -0
  133. package/dist/vc.js +96 -0
  134. package/dist/verification-bounds.d.ts +5 -0
  135. package/dist/verification-bounds.js +78 -0
  136. package/dist/verification-policy.d.ts +32 -0
  137. package/dist/verification-policy.js +85 -0
  138. package/dist/witness.d.ts +19 -0
  139. package/dist/witness.js +80 -0
  140. package/package.json +65 -4
  141. package/src/cli.ts +331 -0
@@ -0,0 +1,135 @@
1
+ // W3C Bitstring Status List v1.0, fixed 131072-slot publishing profile. Offline status remains a snapshot.
2
+ import { gzipSync, gunzipSync } from "node:zlib";
3
+ import { publicKeyFromDid } from "@zanii/core";
4
+ import { credentialHash } from "@zanii/credentials";
5
+ import { VC_CONTEXT, verifyVC } from "@zanii/vc";
6
+ import { isInt, isIso, isObj, ms } from "./shared.js";
7
+ import { signerDid } from "./signer.js";
8
+ import { signVcWith } from "./vc.js";
9
+ export const BITSTRING_STATUS_SLOTS = 131_072;
10
+ const BYTES = BITSTRING_STATUS_SLOTS / 8;
11
+ const purpose = (p) => p === "revocation" || p === "suspension";
12
+ const web = (s) => {
13
+ if (typeof s !== "string" || s.length > 2048 || !/^[\x21-\x7e]+$/.test(s))
14
+ return false;
15
+ try {
16
+ const u = new URL(s);
17
+ return u.protocol === "https:" && !u.username && !u.password && !s.includes("#") && s === u.href;
18
+ }
19
+ catch {
20
+ return false;
21
+ }
22
+ };
23
+ const decode = (s) => {
24
+ if (typeof s !== "string" || s.length > 32768 || !/^u[A-Za-z0-9_-]+$/.test(s) || s.trim() !== s)
25
+ return null;
26
+ try {
27
+ const data = Buffer.from(s.slice(1), "base64url");
28
+ if (`u${data.toString("base64url")}` !== s)
29
+ return null;
30
+ const bits = gunzipSync(data, { maxOutputLength: BYTES });
31
+ return bits.length === BYTES ? bits : null;
32
+ }
33
+ catch {
34
+ return null;
35
+ }
36
+ };
37
+ const encode = (bits) => {
38
+ // shortcut: stored GZIP blocks fix bytes across zlib versions; use a canonical compressor if shard bandwidth requires it.
39
+ const gzip = gzipSync(bits, { level: 0 });
40
+ gzip[9] = 255; // Stable RFC1952 OS field across Node/Python; payload is ordinary GZIP.
41
+ return `u${gzip.toString("base64url")}`;
42
+ };
43
+ const entryShape = (s) => isObj(s) && Object.keys(s).length === 5 && s.type === "BitstringStatusListEntry" && purpose(s.statusPurpose)
44
+ && web(s.statusListCredential) && typeof s.statusListIndex === "string" && /^(?:0|[1-9][0-9]{0,5})$/.test(s.statusListIndex) && s.statusListIndex.trim() === s.statusListIndex
45
+ && Number(s.statusListIndex) < BITSTRING_STATUS_SLOTS && s.id === `${s.statusListCredential}#${s.statusListIndex}`;
46
+ export { entryShape as isBitstringStatusEntry };
47
+ const proofShape = (proof) => isObj(proof) && Object.keys(proof).length === 6 && proof.type === "DataIntegrityProof"
48
+ && proof.cryptosuite === "eddsa-jcs-2022" && proof.proofPurpose === "assertionMethod" && isIso(proof.created)
49
+ && typeof proof.verificationMethod === "string" && proof.verificationMethod.length <= 140
50
+ && typeof proof.proofValue === "string" && proof.proofValue.length <= 100;
51
+ export function bitstringStatusEntry(input) {
52
+ if (!isInt(input.index, 0, BITSTRING_STATUS_SLOTS - 1) || !web(input.list) || !purpose(input.purpose))
53
+ throw new Error("invalid bitstring status entry");
54
+ return { id: `${input.list}#${input.index}`, type: "BitstringStatusListEntry", statusPurpose: input.purpose, statusListIndex: String(input.index), statusListCredential: input.list };
55
+ }
56
+ export async function buildBitstringStatusList(input, signer) {
57
+ if (!web(input.id) || !purpose(input.purpose) || !isIso(input.validFrom) || !isIso(input.validUntil) || !isIso(input.created)
58
+ || ms(input.validUntil) <= ms(input.validFrom) || ms(input.validUntil) - ms(input.validFrom) > 86_400_000
59
+ || !Array.isArray(input.entries) || input.entries.length > BITSTRING_STATUS_SLOTS)
60
+ throw new Error("invalid bitstring status list input");
61
+ const bits = new Uint8Array(BYTES), seen = new Set();
62
+ for (const e of input.entries) {
63
+ if (!isObj(e) || Object.keys(e).length !== 2 || !isInt(e.index, 0, BITSTRING_STATUS_SLOTS - 1) || typeof e.value !== "boolean" || seen.has(e.index))
64
+ throw new Error("invalid or duplicate bitstring status index");
65
+ seen.add(e.index);
66
+ if (e.value)
67
+ bits[Math.floor(e.index / 8)] |= 0x80 >> (e.index % 8);
68
+ }
69
+ if (input.previous !== undefined) {
70
+ const prior = input.previous, subject = isObj(prior?.credentialSubject) ? prior.credentialSubject : {};
71
+ const old = verifyBitstringStatusList(prior, { issuers: [signerDid(signer)], now: String(prior?.validFrom) }).bits;
72
+ if (prior?.id !== input.id || subject.statusPurpose !== input.purpose || !old
73
+ || !isIso(prior.validFrom) || ms(prior.validFrom) > ms(input.validFrom))
74
+ throw new Error("invalid previous bitstring status list");
75
+ if (input.purpose === "revocation" && old.some((byte, i) => (byte & bits[i]) !== byte))
76
+ throw new Error("revocation bits cannot be cleared");
77
+ }
78
+ return signVcWith({ "@context": [VC_CONTEXT], id: input.id, type: ["VerifiableCredential", "BitstringStatusListCredential"], issuer: signerDid(signer),
79
+ validFrom: input.validFrom, validUntil: input.validUntil,
80
+ credentialSubject: { id: `${input.id}#list`, type: "BitstringStatusList", statusPurpose: input.purpose, encodedList: encode(bits) } }, signer, input.created);
81
+ }
82
+ export function verifyBitstringStatusList(doc, opts) {
83
+ const denied = (reason) => ({ ok: false, reasons: [reason], bits: null });
84
+ if (!isObj(opts) || !Array.isArray(opts.issuers) || opts.issuers.length < 1 || opts.issuers.length > 64 || !Array.from(opts.issuers).every((d) => typeof d === "string" && d.length <= 69 && publicKeyFromDid(d)) || !isIso(opts.now))
85
+ return denied("explicit trusted bitstring issuers and reference time are required");
86
+ if (!isObj(doc) || Object.keys(doc).length !== 8 || !web(doc.id) || !opts.issuers.includes(String(doc.issuer)) || !isIso(doc.validFrom) || !isIso(doc.validUntil)
87
+ || ms(doc.validFrom) > ms(opts.now) || ms(doc.validUntil) <= ms(opts.now) || ms(doc.validUntil) - ms(doc.validFrom) > 86_400_000
88
+ || !Array.isArray(doc.type) || doc.type.length !== 2 || doc.type[0] !== "VerifiableCredential" || doc.type[1] !== "BitstringStatusListCredential"
89
+ || !Array.isArray(doc["@context"]) || doc["@context"].length !== 1 || doc["@context"][0] !== VC_CONTEXT || !proofShape(doc.proof))
90
+ return denied("invalid, untrusted or stale bitstring status list");
91
+ const subject = doc.credentialSubject;
92
+ if (!isObj(subject) || Object.keys(subject).length !== 4 || subject.id !== `${doc.id}#list` || subject.type !== "BitstringStatusList" || !purpose(subject.statusPurpose))
93
+ return denied("invalid bitstring status subject");
94
+ const bits = decode(subject.encodedList);
95
+ if (!bits)
96
+ return denied("invalid or oversized bitstring encoding");
97
+ const check = verifyVC(doc, { at: opts.now });
98
+ return check.ok ? { ok: true, reasons: [], bits } : { ok: false, reasons: check.reasons, bits: null };
99
+ }
100
+ export function verifyBitstringStatusEntry(entry, doc, opts) {
101
+ if (!entryShape(entry))
102
+ return { ok: false, reasons: ["invalid bitstring status entry"], value: null };
103
+ const checked = verifyBitstringStatusList(doc, opts);
104
+ if (!checked.ok || !checked.bits)
105
+ return { ok: false, reasons: checked.reasons, value: null };
106
+ const list = doc;
107
+ if (list.id !== entry.statusListCredential || list.credentialSubject.statusPurpose !== entry.statusPurpose)
108
+ return { ok: false, reasons: ["bitstring list URL or purpose does not match the entry"], value: null };
109
+ const index = Number(entry.statusListIndex);
110
+ return { ok: true, reasons: [], value: !!(checked.bits[Math.floor(index / 8)] & (0x80 >> (index % 8))) };
111
+ }
112
+ export async function certificateToBitstringVc(cert, signer, opts) {
113
+ if (cert?.v !== 1 || cert.type !== "credential" || cert.issuer !== signerDid(signer) || !isIso(opts.created) || opts.revocationList === opts.suspensionList)
114
+ throw new Error("invalid certificate or bitstring VC signer/options");
115
+ return signVcWith({ "@context": [VC_CONTEXT], type: ["VerifiableCredential", "ZaniiCertifyCertificateV2"], issuer: cert.issuer,
116
+ validFrom: cert.issued_at, validUntil: cert.exp,
117
+ credentialSubject: { id: cert.holder, scope: cert.scope, claim: cert.claim, issuerDomain: cert.issuer_domain, certificate: credentialHash(cert), sig: cert.sig },
118
+ credentialStatus: [bitstringStatusEntry({ index: opts.index, list: opts.revocationList, purpose: "revocation" }), bitstringStatusEntry({ index: opts.index, list: opts.suspensionList, purpose: "suspension" })] }, signer, opts.created);
119
+ }
120
+ export function verifyCertificateBitstringVc(vc, opts = {}) {
121
+ if (!isObj(vc) || !proofShape(vc.proof))
122
+ return { ok: false, reasons: ["not a certificate bitstring VC v2 proof"], certificate: null };
123
+ const checked = verifyVC(vc, opts.at === undefined ? {} : { at: opts.at });
124
+ if (!checked.ok)
125
+ return { ok: false, reasons: checked.reasons, certificate: null };
126
+ const doc = vc, s = doc.credentialSubject;
127
+ if (!doc.type.includes("ZaniiCertifyCertificateV2") || !isObj(s) || !["id", "scope", "claim", "issuerDomain", "sig", "certificate"].every((k) => Object.hasOwn(s, k)))
128
+ return { ok: false, reasons: ["not a complete certificate bitstring VC v2"], certificate: null };
129
+ const cert = { v: 1, type: "credential", issuer: doc.issuer, issuer_domain: s.issuerDomain, holder: s.id, scope: s.scope, claim: s.claim, issued_at: doc.validFrom, exp: doc.validUntil, sig: s.sig };
130
+ const statuses = doc.credentialStatus;
131
+ if (credentialHash(cert) !== s.certificate || !Array.isArray(statuses) || statuses.length !== 2 || !Array.from(statuses).every(entryShape)
132
+ || statuses[0].statusPurpose !== "revocation" || statuses[1].statusPurpose !== "suspension" || statuses[0].statusListIndex !== statuses[1].statusListIndex || statuses[0].statusListCredential === statuses[1].statusListCredential)
133
+ return { ok: false, reasons: ["bitstring VC certificate or status bindings are invalid"], certificate: null };
134
+ return { ok: true, reasons: [], certificate: cert };
135
+ }
@@ -0,0 +1,218 @@
1
+ import { type Signer } from "./signer.ts";
2
+ import type { SchemeLogsInput } from "./scheme-log.ts";
3
+ /** Section 1: one signature over the canonical bytes of a document without `signatures`. */
4
+ export interface BodySignature {
5
+ signer: string;
6
+ sig: string;
7
+ }
8
+ export declare function bodySignature(body: object, signer: Signer): Promise<BodySignature>;
9
+ /** The document with its signatures sorted by signer; one signer signs once. */
10
+ export declare function withSignatures<T extends object>(body: T, sigs: readonly BodySignature[]): T & {
11
+ signatures: BodySignature[];
12
+ };
13
+ /**
14
+ * Section 1: the signers of `doc` whose signature verifies, and whether `signatures` is well formed
15
+ * (1 to 64 `{signer, sig}`, strictly sorted by signer, each verifying, each in `allowed` when given).
16
+ */
17
+ export declare function signersOf(doc: Record<string, unknown>, allowed?: readonly string[]): {
18
+ signers: string[];
19
+ wellFormed: boolean;
20
+ };
21
+ export interface BoardInput {
22
+ owner: string;
23
+ seq: number;
24
+ prev: string | null;
25
+ members: readonly string[];
26
+ threshold: number;
27
+ effectiveFrom: string;
28
+ /** scheme-log.md section 3: the scheme owner's ledger identity, the root of the delegation of its append receipts. */
29
+ ledger?: string;
30
+ }
31
+ export type BoardBody = {
32
+ v: 1;
33
+ type: "certify.board";
34
+ owner: string;
35
+ seq: number;
36
+ prev: string | null;
37
+ members: string[];
38
+ threshold: number;
39
+ effective_from: string;
40
+ ledger?: string;
41
+ };
42
+ export type Board = BoardBody & {
43
+ signatures: BodySignature[];
44
+ };
45
+ export interface BoardCheck {
46
+ ok: boolean;
47
+ reasons: string[];
48
+ }
49
+ declare function boardError(b: Record<string, unknown>): string | null;
50
+ /** The unsigned board (each signer signs it with `bodySignature`). */
51
+ export declare function boardBody(f: BoardInput): BoardBody;
52
+ /** A board signed by `signers`: the owner for the first board, k of the previous board after. */
53
+ export declare function buildBoard(f: BoardInput, signers: readonly Signer[]): Promise<Board>;
54
+ export declare const isBoard: (b: unknown) => b is Record<string, unknown>;
55
+ /**
56
+ * Section 2: the boards form one log: board i at seq i naming board i - 1, one owner, each taking
57
+ * effect after the previous one; board 0 signed by the owner, every later board by at least the
58
+ * previous board's threshold of its members, and no other signature.
59
+ */
60
+ export declare function verifyBoardLog(boards: readonly unknown[], opts?: {
61
+ owner?: string;
62
+ }): BoardCheck;
63
+ export declare const RELEASE_KINDS: readonly ["scheme", "profile"];
64
+ export type ReleaseKind = (typeof RELEASE_KINDS)[number];
65
+ export interface ReleaseSubject {
66
+ kind: ReleaseKind;
67
+ /** `zanii-certify/<major>.<minor>` for a scheme, `<slug>/<version>` for a profile. */
68
+ ref: string;
69
+ }
70
+ export interface ReleaseInput {
71
+ seq: number;
72
+ prev: string | null;
73
+ subject: ReleaseSubject;
74
+ /** The released content: a scheme's published text, file hash; a profile, jcsHash of the profile. */
75
+ sha256: string;
76
+ effectiveFrom: string;
77
+ notes: {
78
+ en: string;
79
+ ar: string;
80
+ };
81
+ /** jcsHash of the board that signs the release (the board in force at effectiveFrom). */
82
+ board: string;
83
+ }
84
+ export type ReleaseBody = {
85
+ v: 1;
86
+ type: "certify.release";
87
+ seq: number;
88
+ prev: string | null;
89
+ subject: ReleaseSubject;
90
+ sha256: string;
91
+ effective_from: string;
92
+ notes: {
93
+ en: string;
94
+ ar: string;
95
+ };
96
+ board: string;
97
+ };
98
+ export type Release = ReleaseBody & {
99
+ signatures: BodySignature[];
100
+ };
101
+ export declare const isText: (t: unknown) => boolean;
102
+ export declare function subjectOk(s: unknown): s is ReleaseSubject;
103
+ declare function releaseError(r: Record<string, unknown>): string | null;
104
+ export declare function releaseBody(f: ReleaseInput): ReleaseBody;
105
+ /** A release signed by `signers` (members of the board it names). */
106
+ export declare function buildRelease(f: ReleaseInput, signers: readonly Signer[]): Promise<Release>;
107
+ export declare const isRelease: (r: unknown) => r is Record<string, unknown>;
108
+ /**
109
+ * A board-signed document (release, withdrawal, body register) against a board log already checked:
110
+ * the board it names is in the log and in force at its effective_from, and k of its members signed it.
111
+ */
112
+ export declare function boardSignedReasons(r: Record<string, unknown>, boards: readonly unknown[], noun: string): string[];
113
+ /** Section 3: one release, with the board log it names (checked with `verifyBoardLog`). */
114
+ export declare function verifyRelease(release: unknown, boards: readonly unknown[], opts?: {
115
+ owner?: string;
116
+ }): BoardCheck;
117
+ export declare const subjectKey: (s: unknown) => string;
118
+ /** Section 4: the release log: every release valid, at seq i naming release i - 1, effective_from never going back, each subject released once. */
119
+ export declare function verifyReleaseLog(releases: readonly unknown[], boards: readonly unknown[], opts?: {
120
+ owner?: string;
121
+ schemeLog?: SchemeLogsInput;
122
+ }): BoardCheck;
123
+ /**
124
+ * Section 5: may a lab use `subject` at `at`? The release log must verify, release the subject, take
125
+ * effect no later than `at` and (with `sha256`) for exactly that content. With `withdrawals`
126
+ * (section 6), a release withdrawn at or before `at` may not be used.
127
+ */
128
+ export declare function requireRelease(releases: readonly unknown[], boards: readonly unknown[], subject: ReleaseSubject, at: string, opts?: {
129
+ owner?: string;
130
+ sha256?: string;
131
+ withdrawals?: readonly unknown[];
132
+ schemeLog?: SchemeLogsInput;
133
+ }): BoardCheck & {
134
+ release: Release | null;
135
+ withdrawal?: ReleaseWithdrawal | null;
136
+ };
137
+ /**
138
+ * Section 4a: may `board` be appended to the board log now? The board log with it verifies, it takes
139
+ * effect after the effective_from of every release already in the release log, and the release log
140
+ * still verifies against the longer board log (a board change never breaks a release).
141
+ */
142
+ export declare function verifyBoardAppend(boards: readonly unknown[], releases: readonly unknown[], board: unknown, opts?: {
143
+ owner?: string;
144
+ }): BoardCheck;
145
+ /**
146
+ * Section 4a: may `release` be appended to the release log now? The release log with it verifies,
147
+ * and it is signed by the newest board of the board log (a board that was replaced signs nothing more).
148
+ */
149
+ export declare function verifyReleaseAppend(releases: readonly unknown[], boards: readonly unknown[], release: unknown, opts?: {
150
+ owner?: string;
151
+ }): BoardCheck;
152
+ export declare const WITHDRAWAL_REASONS: readonly ["DEFECT", "SECURITY", "LEGAL", "OTHER"];
153
+ export type WithdrawalReason = (typeof WITHDRAWAL_REASONS)[number];
154
+ export interface ReleaseWithdrawalInput {
155
+ seq: number;
156
+ prev: string | null;
157
+ subject: ReleaseSubject;
158
+ /** jcsHash of the release withdrawn. */
159
+ release: string;
160
+ reason: WithdrawalReason;
161
+ notes: {
162
+ en: string;
163
+ ar: string;
164
+ };
165
+ effectiveFrom: string;
166
+ /** jcsHash of the board that signs (the newest board when it is appended). */
167
+ board: string;
168
+ }
169
+ export type ReleaseWithdrawalBody = {
170
+ v: 1;
171
+ type: "certify.release-withdrawal";
172
+ seq: number;
173
+ prev: string | null;
174
+ subject: ReleaseSubject;
175
+ release: string;
176
+ reason: WithdrawalReason;
177
+ notes: {
178
+ en: string;
179
+ ar: string;
180
+ };
181
+ effective_from: string;
182
+ board: string;
183
+ };
184
+ export type ReleaseWithdrawal = ReleaseWithdrawalBody & {
185
+ signatures: BodySignature[];
186
+ };
187
+ declare function withdrawalError(w: Record<string, unknown>): string | null;
188
+ export { boardError as boardFieldError, releaseError as releaseFieldError, withdrawalError as withdrawalFieldError };
189
+ export declare function releaseWithdrawalBody(f: ReleaseWithdrawalInput): ReleaseWithdrawalBody;
190
+ /** A release withdrawal signed by `signers` (k members of the board it names). */
191
+ export declare function buildReleaseWithdrawal(f: ReleaseWithdrawalInput, signers: readonly Signer[]): Promise<ReleaseWithdrawal>;
192
+ export declare const isWithdrawal: (w: unknown) => w is Record<string, unknown>;
193
+ /**
194
+ * Section 6: the withdrawal log: the release log verifies, every withdrawal at seq i naming
195
+ * withdrawal i - 1, effective_from never going back, naming a release of the log with its subject,
196
+ * taking effect no earlier than it, each release withdrawn once, signed by k of the board in force.
197
+ */
198
+ export declare function verifyWithdrawalLog(withdrawals: readonly unknown[], releases: readonly unknown[], boards: readonly unknown[], opts?: {
199
+ owner?: string;
200
+ schemeLog?: SchemeLogsInput;
201
+ }): BoardCheck;
202
+ /**
203
+ * Section 6: a certificate issued under a withdrawn scheme or profile version is flagged, never
204
+ * failed. `ok` is whether the withdrawal log verified; `flags` names each withdrawal that touches
205
+ * the certificate's scheme or profile.
206
+ */
207
+ export declare function withdrawalFlags(cert: {
208
+ issued_at?: unknown;
209
+ claim?: unknown;
210
+ }, logs: {
211
+ withdrawals: readonly unknown[];
212
+ releases: readonly unknown[];
213
+ boards: readonly unknown[];
214
+ owner?: string;
215
+ schemeLog?: SchemeLogsInput;
216
+ }): BoardCheck & {
217
+ flags: string[];
218
+ };