@ziffer-io/types 0.1.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/LICENSE +120 -0
- package/README.md +58 -0
- package/THIRD-PARTY-NOTICES +18 -0
- package/dist/generated.d.ts +1696 -0
- package/dist/generated.d.ts.map +1 -0
- package/dist/generated.js +193 -0
- package/dist/generated.js.map +1 -0
- package/dist/generated_wire.d.ts +4466 -0
- package/dist/generated_wire.d.ts.map +1 -0
- package/dist/generated_wire.js +20 -0
- package/dist/generated_wire.js.map +1 -0
- package/dist/index.d.ts +58 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +61 -0
- package/dist/index.js.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1,1696 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AS0 software key · AS1 multi-factor-protected key · AS2 hardware-bound
|
|
3
|
+
* key. Ordered: AS0 < AS1 < AS2, and AT-10 compares an entry's level against
|
|
4
|
+
* the registry floor with >=, so the ordering is load-bearing — a chain like
|
|
5
|
+
* §4's custody tiers and floors' resource tiers, NOT like suites, whose
|
|
6
|
+
* floor is containment (CR-4) precisely because suites do not rank.
|
|
7
|
+
* Correspondence, stated so the M-A annex can cite it and a buyer can map
|
|
8
|
+
* it: AS1 is the arrangement NIST SP 800-63B calls AAL2 (multi-factor,
|
|
9
|
+
* software permitted), AS2 is AAL3's (hardware authenticator). The names are
|
|
10
|
+
* this specification's own because an external framework's labels move on
|
|
11
|
+
* that framework's schedule.
|
|
12
|
+
* Generated from attesters.schema.json#/$defs/assurance.
|
|
13
|
+
*/
|
|
14
|
+
export type Assurance = 'AS0' | 'AS1' | 'AS2';
|
|
15
|
+
/**
|
|
16
|
+
* Assurance low to high, from the schema's declared order.
|
|
17
|
+
*
|
|
18
|
+
* TypeScript has no derived ordering, so the ladder is a value and the
|
|
19
|
+
* comparison is a function. §8.4 composes with max, so `max` is what
|
|
20
|
+
* callers need and index arithmetic is what they must not write.
|
|
21
|
+
*/
|
|
22
|
+
export declare const ASSURANCE_ORDER: readonly Assurance[];
|
|
23
|
+
export declare function maxAssurance(a: Assurance, b: Assurance): Assurance;
|
|
24
|
+
/**
|
|
25
|
+
* Which of the two acknowledgement duties an enrolled identity may
|
|
26
|
+
* discharge.
|
|
27
|
+
*
|
|
28
|
+
* Hoisted into `$defs` for the same reason `reversibility` was: an inline
|
|
29
|
+
* enum has no name, and a generator inventing one invents a name that
|
|
30
|
+
* drifts.
|
|
31
|
+
*
|
|
32
|
+
* DELIBERATELY NOT ORDERED. A confirmer does not outrank an approver; they
|
|
33
|
+
* are different duties, and DR-9's separation is enforced per action against
|
|
34
|
+
* the proposer rather than by comparing roles.
|
|
35
|
+
* Generated from attesters.schema.json#/$defs/attester_role.
|
|
36
|
+
*/
|
|
37
|
+
export type AttesterRole = 'approver' | 'confirmer';
|
|
38
|
+
/**
|
|
39
|
+
* The credential's public key as a COSE_Key (RFC 9052) map, canonical CBOR,
|
|
40
|
+
* base64, holding EXACTLY the labels kty, crv, x and (for EC2) y and nothing
|
|
41
|
+
* else. Every real authenticator also returns label 3 (alg); the enrolling
|
|
42
|
+
* service strips it before the entry is written, because a key that admits
|
|
43
|
+
* two encodings is two `public_key` strings for one credential, and PB-7's
|
|
44
|
+
* distinctness over `public_key` would then see one holder as two. The
|
|
45
|
+
* verifier refuses label 3 at load as Malformed rather than tolerating it,
|
|
46
|
+
* so the one encoding is the one the registry can hold. Not re-encoded to a
|
|
47
|
+
* raw point either, for AB-1's reason: a re-encoding is a second definition
|
|
48
|
+
* of the key. The verifier decodes it (kty EC2 / P-256 for `webauthn-es256`;
|
|
49
|
+
* kty OKP / Ed25519 for `webauthn-ed25519`) and refuses at load a key whose
|
|
50
|
+
* kty/crv/alg do not match the entry's `alg`, a P-256 point not on the
|
|
51
|
+
* curve, or an Ed25519 point of small order (HM-5, PB-9).
|
|
52
|
+
* Generated from attesters.schema.json#/$defs/cose_key.
|
|
53
|
+
*
|
|
54
|
+
* The schema constrains this to `^[A-Za-z0-9+/]{40,}={0,2}$`, which is NOT enforced here.
|
|
55
|
+
*/
|
|
56
|
+
export type CoseKey = string;
|
|
57
|
+
/**
|
|
58
|
+
* The authenticator's credential id from registration, base64 (the
|
|
59
|
+
* registry's encoding, as `ed25519_pub` and `mldsa65_pub` are). Not a secret
|
|
60
|
+
* and not a key: it names the credential, and the Consumption Ledger keys
|
|
61
|
+
* the signature counter on it (HM-4 (f)).
|
|
62
|
+
* Generated from attesters.schema.json#/$defs/credential_id.
|
|
63
|
+
*
|
|
64
|
+
* The schema constrains this to `^[A-Za-z0-9+/]{20,}={0,2}$`, which is NOT enforced here.
|
|
65
|
+
*/
|
|
66
|
+
export type CredentialId = string;
|
|
67
|
+
/**
|
|
68
|
+
* Ed25519 verification key (RFC 8032), base64. 32 bytes raw; the decoded
|
|
69
|
+
* length is asserted in code, because a base64 string of the wrong length is
|
|
70
|
+
* well-formed JSON and a schema pattern alone would let a truncated key
|
|
71
|
+
* through.
|
|
72
|
+
* Generated from attesters.schema.json#/$defs/ed25519_pub.
|
|
73
|
+
*
|
|
74
|
+
* The schema constrains this to `^[A-Za-z0-9+/]{43}=$`, which is NOT enforced here.
|
|
75
|
+
*/
|
|
76
|
+
export type Ed25519PublicKey = string;
|
|
77
|
+
/**
|
|
78
|
+
* F-HIGH: no free text reaches the Proposal; every field is a bounded
|
|
79
|
+
* scalar, constrained string, enum or fixed-shape nested model, so
|
|
80
|
+
* instruction injection into the Proposal is grammatically impossible.
|
|
81
|
+
* F-LOW: a translator model produced the Proposal from free text, injection
|
|
82
|
+
* into the TRANSLATION STEP is possible by construction, and containment
|
|
83
|
+
* rests on capability limits, confirmation and receipts -- never on ingress
|
|
84
|
+
* hygiene (FC-1, FC-3). Exactly one class per adapter.
|
|
85
|
+
*
|
|
86
|
+
* DELIBERATELY UNORDERED. There is no `x-acp-ordered` here and there must
|
|
87
|
+
* not be. The two classes are not ranked: FC-2 conditions on the class and
|
|
88
|
+
* requires confirmation for F-LOW at effective tier >= T2, which is a case
|
|
89
|
+
* distinction, not a comparison. An ordering invented for convenience would
|
|
90
|
+
* invite `>=` against a value that has no scale, which is the
|
|
91
|
+
* tier-versus-risk conflation this repository has already published a
|
|
92
|
+
* correction for -- and the names point the wrong way for a ladder, since
|
|
93
|
+
* here HIGH is the safer class.
|
|
94
|
+
*
|
|
95
|
+
* THIS IS ALSO THE WIRE ROOT'S `FidelityClass` (ACP-73). It was declared in
|
|
96
|
+
* `spec/schemas/wire/proposal.schema.json` until this table existed, and
|
|
97
|
+
* `proposal`, `decision_receipt` and `audit_record` now `$ref` this
|
|
98
|
+
* declaration across roots rather than restating it, for the reason
|
|
99
|
+
* `SuiteId` is homed in `signature.schema.json`: TR-8 compares the receipt's
|
|
100
|
+
* transmitted `fidelity` against the class registered HERE, and two enums
|
|
101
|
+
* that merely look alike is that comparison passing on a vocabulary nobody
|
|
102
|
+
* checked. The signed side owns the vocabulary; the wire carries it.
|
|
103
|
+
* Generated from adapters.schema.json#/$defs/fidelity_class.
|
|
104
|
+
*/
|
|
105
|
+
export type FidelityClass = 'F-HIGH' | 'F-LOW';
|
|
106
|
+
/**
|
|
107
|
+
* ML-DSA-65 verification key (FIPS 204), base64. 1952 bytes raw. Its size is
|
|
108
|
+
* why hybrid receipts run 13.2 kB against 256 B classical-only — a 53x wire
|
|
109
|
+
* increase that is algorithm-bound and does not improve with a faster
|
|
110
|
+
* library.
|
|
111
|
+
* Generated from attesters.schema.json#/$defs/mldsa65_pub.
|
|
112
|
+
*
|
|
113
|
+
* The schema constrains this to `^[A-Za-z0-9+/]{2603}=$`, which is NOT enforced here.
|
|
114
|
+
*/
|
|
115
|
+
export type MlDsa65PublicKey = string;
|
|
116
|
+
/**
|
|
117
|
+
* A primitive NAME as it appears on the wire.
|
|
118
|
+
*
|
|
119
|
+
* `pq-slh` is declared and NOT implemented. It keeps its own name and fails
|
|
120
|
+
* closed — aliasing it to `pq` would let a verifier report success for a
|
|
121
|
+
* primitive it cannot compute, which is the one thing an unimplemented
|
|
122
|
+
* primitive must never do.
|
|
123
|
+
* Generated from signature.schema.json#/$defs/primitive.
|
|
124
|
+
*/
|
|
125
|
+
export type PrimitiveName = 'classical' | 'pq' | 'pq-slh';
|
|
126
|
+
/**
|
|
127
|
+
* Whether an action class can be undone.
|
|
128
|
+
*
|
|
129
|
+
* Hoisted out of `additionalProperties` into `$defs` so that it has a NAME.
|
|
130
|
+
* An inline enum is a type the generator has to invent a name for, and an
|
|
131
|
+
* invented name is a name that drifts — `floors.schema.json` already
|
|
132
|
+
* declared its values under `$defs.tier` and this file did not, which is a
|
|
133
|
+
* difference with no reason behind it.
|
|
134
|
+
*
|
|
135
|
+
* DELIBERATELY NOT ORDERED. REVERSIBLE and IRREVERSIBLE are two cases, not a
|
|
136
|
+
* scale; a generated `Ord` would invite `max` composition that means nothing
|
|
137
|
+
* here.
|
|
138
|
+
* Generated from reversibility.schema.json#/$defs/reversibility.
|
|
139
|
+
*/
|
|
140
|
+
export type Reversibility = 'REVERSIBLE' | 'IRREVERSIBLE';
|
|
141
|
+
/**
|
|
142
|
+
* Ordered LOW < MEDIUM < HIGH. §8.4 composes with max.
|
|
143
|
+
*
|
|
144
|
+
* A RISK LEVEL IS NOT A RESOURCE TIER. This is a different ladder from
|
|
145
|
+
* `floors.schema.json`'s T0..T3, over a different subject, and §8.4 composes
|
|
146
|
+
* both with max — which is exactly why one type served for both until
|
|
147
|
+
* someone looked. The Rust and TypeScript definitions carried a single
|
|
148
|
+
* `RiskTier` enum whose doc comment cited RK-1's absent-⇒-T3 rule and whose
|
|
149
|
+
* values were LOW/MEDIUM/HIGH, so the fail-safe default was stated in the
|
|
150
|
+
* wrong domain in both. Generated separately, and named separately, for that
|
|
151
|
+
* reason.
|
|
152
|
+
* Generated from risk_functions.schema.json#/$defs/risk.
|
|
153
|
+
*/
|
|
154
|
+
export type Risk = 'LOW' | 'MEDIUM' | 'HIGH';
|
|
155
|
+
/**
|
|
156
|
+
* Risk low to high, from the schema's declared order.
|
|
157
|
+
*
|
|
158
|
+
* TypeScript has no derived ordering, so the ladder is a value and the
|
|
159
|
+
* comparison is a function. §8.4 composes with max, so `max` is what
|
|
160
|
+
* callers need and index arithmetic is what they must not write.
|
|
161
|
+
*/
|
|
162
|
+
export declare const RISK_ORDER: readonly Risk[];
|
|
163
|
+
export declare function maxRisk(a: Risk, b: Risk): Risk;
|
|
164
|
+
/**
|
|
165
|
+
* The WebAuthn relying-party identifier the credential was created for: the
|
|
166
|
+
* approval page's host, lower-case, no scheme, no port, no path (e.g.
|
|
167
|
+
* `approve.example.com`). Stored PER ENTRY because that is what the
|
|
168
|
+
* credential itself is bound to; HM-4 (c) requires the assertion's origin to
|
|
169
|
+
* be exactly `https://` + this, and (d) requires `rpIdHash` = SHA-256 of it.
|
|
170
|
+
* Signed policy: an assertion for any other origin is an assertion made on
|
|
171
|
+
* another site, which is the phishing case this field refuses.
|
|
172
|
+
* Generated from attesters.schema.json#/$defs/rp_id.
|
|
173
|
+
*
|
|
174
|
+
* The schema constrains this to `^[a-z0-9]([a-z0-9-]{0,62}[a-z0-9])?(\.[a-z0-9]([a-z0-9-]{0,62}[a-z0-9])?)+$`, which is NOT enforced here.
|
|
175
|
+
*/
|
|
176
|
+
export type RpId = string;
|
|
177
|
+
/**
|
|
178
|
+
* A suite NAME as it appears on the wire.
|
|
179
|
+
*
|
|
180
|
+
* DELIBERATELY NOT ORDERED. There is no `x-acp-ordered` here and there must
|
|
181
|
+
* not be one: CR-4's floor is satisfied by CONTAINMENT of primitives, not by
|
|
182
|
+
* rank. A generated `Ord` would make `declared >= floor` compile, and that
|
|
183
|
+
* comparison is the downgrade — `ed25519` and `slhdsa128s` are incomparable,
|
|
184
|
+
* not adjacent. The behavioural type is `acp_crypto::Suite`, which carries
|
|
185
|
+
* `satisfies_floor` and `primitives()`; this is the wire name and nothing
|
|
186
|
+
* more.
|
|
187
|
+
*
|
|
188
|
+
* NOT `const`. Listing only the hybrid suite would make a bundle signed
|
|
189
|
+
* under `ed25519` fail SHAPE validation, when the required outcome is a CR-4
|
|
190
|
+
* refusal naming the floor. Unknown names outside this list are refused
|
|
191
|
+
* under CR-1 by the loader, never defaulted to a known suite. THIS IS ALSO
|
|
192
|
+
* THE WIRE ROOT'S `SuiteId` (ACP-78 M1): the Decision Receipt's `alg`
|
|
193
|
+
* `$ref`s this declaration across roots. CR-4 compares a receipt's suite
|
|
194
|
+
* against the floor registered here, so the two artifacts must draw from ONE
|
|
195
|
+
* set -- two enums that merely look alike is the comparison passing on a
|
|
196
|
+
* vocabulary nobody checked.
|
|
197
|
+
* Generated from signature.schema.json#/$defs/suite_id.
|
|
198
|
+
*/
|
|
199
|
+
export type SuiteId = 'ed25519' | 'hybrid-ed25519-mldsa65' | 'slhdsa128s';
|
|
200
|
+
/**
|
|
201
|
+
* One tenant, named once, in signed policy. Declared here and CARRIED by
|
|
202
|
+
* every wire message that names a tenant -- the receipt, the ledger claim,
|
|
203
|
+
* the pending-release record, the audit record and the anchor all `$ref`
|
|
204
|
+
* this definition -- because the bundle is what says which tenant a decision
|
|
205
|
+
* belongs to (RAD-5) and a message can only repeat it. Same direction as
|
|
206
|
+
* `SuiteId` and `Tier`: policy defines, messages carry. Through ACP-78 M1
|
|
207
|
+
* this was the wire root's one `TenantId`, homed on the ledger claim; it
|
|
208
|
+
* moved here with RAD-5 (v1.3.23) when the bundle gained the field, so that
|
|
209
|
+
* the manifest's copy and the messages' copies cannot be two types.
|
|
210
|
+
*
|
|
211
|
+
* IN A MESSAGE IT NAMES A NAMESPACE AND DOES NOT AUTHORISE ONE (RES-8). CL-5
|
|
212
|
+
* permits both topologies -- one ledger per tenant, or one ledger keyed by
|
|
213
|
+
* tenant -- and under the first this value is redundant with the instance
|
|
214
|
+
* the Executor is connected to. It is carried under both so that one claim
|
|
215
|
+
* has one encoding rather than two, which is the Z4 rule applied to a
|
|
216
|
+
* deployment choice. A ledger that RESOLVES which tenant's namespace to use
|
|
217
|
+
* from this field, rather than from the authenticated connection, has let
|
|
218
|
+
* the claimant pick its own scope; EX-1 scopes the Executor's credentials
|
|
219
|
+
* per tenant precisely so the connection is the thing that answers.
|
|
220
|
+
*
|
|
221
|
+
* THE MAXIMUM IS L-04's AND ITS SCOPE IS CONTESTED. This declaration is the
|
|
222
|
+
* wire root's one `TenantId`, and it was five declarations with three bounds
|
|
223
|
+
* before ACP-78 M1: unbounded here, 2,048 in the audit record and the
|
|
224
|
+
* anchor, 128 in the receipt and the pending-release record. Two lengths for
|
|
225
|
+
* one value means a tenant nameable in one artifact and unnameable in the
|
|
226
|
+
* artifact that produced it, so one bound was kept -- the only one any
|
|
227
|
+
* clause states. L-04 reads `max string field length 2,048 chars. No
|
|
228
|
+
* exceptions` with `Schema` as its enforcement point. It is applied here and
|
|
229
|
+
* the reading is disclosed rather than assumed: L-04's neighbours L-03,
|
|
230
|
+
* L-05, L-06 and L-07 are all about TENANT-REGISTERED schemas, so `Schema`
|
|
231
|
+
* may well scope it there, and read literally across every wire string it
|
|
232
|
+
* makes CR-6's hybrid floor unsatisfiable -- an ML-DSA-65 signature is 4,412
|
|
233
|
+
* base64 characters. AB-6's rationale separately treats `tenant_id` length
|
|
234
|
+
* as deployment-variable in as many words. Whichever way the document
|
|
235
|
+
* settles that, this file states one length rather than three.
|
|
236
|
+
* Generated from manifest.schema.json#/$defs/tenant_id.
|
|
237
|
+
*/
|
|
238
|
+
export type TenantId = string;
|
|
239
|
+
/**
|
|
240
|
+
* T0 public/sandbox · T1 internal · T2 production · T3 privileged. Ordered:
|
|
241
|
+
* T0 < T1 < T2 < T3, and §8.4 composes tiers with max, so the ordering is
|
|
242
|
+
* load-bearing rather than cosmetic. THIS IS ALSO THE WIRE ROOT'S `Tier`
|
|
243
|
+
* (ACP-78 M1): `spec/schemas/wire/context_read.schema.json` `$ref`s this
|
|
244
|
+
* declaration across roots rather than restating it, because TR-3 composes
|
|
245
|
+
* the FLOOR from this table with the RAISE from the Context read using
|
|
246
|
+
* `max`, and a value nameable in one and not the other leaves that `max`
|
|
247
|
+
* undefined. It was declared in both roots until M1, character for
|
|
248
|
+
* character, each copy carrying a note saying the two must move together.
|
|
249
|
+
* Generated from floors.schema.json#/$defs/tier.
|
|
250
|
+
*/
|
|
251
|
+
export type Tier = 'T0' | 'T1' | 'T2' | 'T3';
|
|
252
|
+
/**
|
|
253
|
+
* Tier low to high, from the schema's declared order.
|
|
254
|
+
*
|
|
255
|
+
* TypeScript has no derived ordering, so the ladder is a value and the
|
|
256
|
+
* comparison is a function. §8.4 composes with max, so `max` is what
|
|
257
|
+
* callers need and index arithmetic is what they must not write.
|
|
258
|
+
*/
|
|
259
|
+
export declare const TIER_ORDER: readonly Tier[];
|
|
260
|
+
export declare function maxTier(a: Tier, b: Tier): Tier;
|
|
261
|
+
/**
|
|
262
|
+
* Which key type HM-4 (e) verifies under: ES256 (ECDSA P-256 with SHA-256,
|
|
263
|
+
* DER-encoded, COSE alg -7 -- what every authenticator supports) or Ed25519
|
|
264
|
+
* (COSE alg -8, RFC 8032 under ACP-106's strict rule). An attestation-entry
|
|
265
|
+
* suite only: CR-8 forbids either as a bundle, receipt or door suite, and
|
|
266
|
+
* neither is compared against `min_suite` -- a human leg is outside the
|
|
267
|
+
* floor by construction, and HM-6 states the cost.
|
|
268
|
+
* Generated from attesters.schema.json#/$defs/webauthn_alg.
|
|
269
|
+
*/
|
|
270
|
+
export type WebauthnAlg = 'webauthn-es256' | 'webauthn-ed25519';
|
|
271
|
+
/**
|
|
272
|
+
* Maps each registered `schema_id` to the fidelity class of the ingress
|
|
273
|
+
* adapter that produces Proposals under it. This is the "bundle-registered
|
|
274
|
+
* adapter binding" §9.3 step 7 tells the Executor to verify `fidelity`
|
|
275
|
+
* against, and it is the last bundle table on the decision path to get a
|
|
276
|
+
* schema (ACP-73).
|
|
277
|
+
*
|
|
278
|
+
* A CONTROL INPUT, NOT METADATA. The value looked up here is bound into the
|
|
279
|
+
* EL-1 environment as `fidelity` (`acp_executor.py`, `recompute_risk`), so
|
|
280
|
+
* any `raise_to` clause can read it and it can raise or fail to raise a
|
|
281
|
+
* grade; FC-2 keys the confirmation requirement on it; and §9.3 step 7a
|
|
282
|
+
* makes disagreement between this table and the receipt's transmitted
|
|
283
|
+
* `fidelity` a CRITICAL ALERT (T-18), which the reference raises at
|
|
284
|
+
* `acp_executor.py`'s `execute` under TR-8. It is inside the bundle hash
|
|
285
|
+
* (`Bundle.hash`), so it is signed policy, and PB-4 makes it read-only to
|
|
286
|
+
* the runtime by cryptography.
|
|
287
|
+
*
|
|
288
|
+
* ABSENCE IS REFUSED, NEVER DEFAULTED, AND JSON SCHEMA CANNOT SAY SO. The
|
|
289
|
+
* reference is `Bundle.recompute_fidelity`: a `schema_id` with no entry here
|
|
290
|
+
* raises `FailClosed("TR-8", "schema_id not bound to a registered
|
|
291
|
+
* adapter")`, and the simulation's Policy Engine turns the same refusal into
|
|
292
|
+
* a DENY at §8.4 step 2 (`sim/policy.py`). The rule is carried by the
|
|
293
|
+
* `x-acp-absent` annotation below and GENERATED into the accessor in both
|
|
294
|
+
* languages, the `RiskFunctions` / `NoticeTargets` shape rather than the
|
|
295
|
+
* `Floors` / `Reversibility` default-value shape, because there is no
|
|
296
|
+
* fail-safe class to fall back to: defaulting to F-HIGH suppresses FC-2's
|
|
297
|
+
* confirmation exactly as a forged stamp would (X1), and defaulting to F-LOW
|
|
298
|
+
* looks conservative but is a policy value the implementation invented for
|
|
299
|
+
* an adapter nobody registered. P-4: unknown is refused. The WHOLE table is
|
|
300
|
+
* likewise required, not optional -- the reference `Bundle` dataclass gives
|
|
301
|
+
* `adapters` no default, so a bundle without it fails to construct rather
|
|
302
|
+
* than acquiring an empty registry that refuses every Proposal for a reason
|
|
303
|
+
* nobody wrote down.
|
|
304
|
+
*
|
|
305
|
+
* WHY A MAP AND NOT A ROW ARRAY. FC-1 says every adapter declares EXACTLY
|
|
306
|
+
* ONE fidelity class. A map keyed by `schema_id` cannot carry two classes
|
|
307
|
+
* for one id, so the schema enforces FC-1 by shape; an array of `{schema_id,
|
|
308
|
+
* fidelity}` rows would need the loader's duplicate-key refusal that
|
|
309
|
+
* `risk_functions.json` needs for `applies_to`.
|
|
310
|
+
*
|
|
311
|
+
* WHAT THIS SCHEMA FOUND. Until it existed the TR-8 refusal was a
|
|
312
|
+
* hand-written `if` in the Python reference and a hand-written `let ...
|
|
313
|
+
* else` in `crates/acp-decision` (ACP-45 slice 3, disclosed there rather
|
|
314
|
+
* than typed), and `tools/codegen.sh` emitted no type and no accessor for
|
|
315
|
+
* the one table whose miss suppresses a confirmation. It also found that
|
|
316
|
+
* §8.2's bundle tree names NO FILE for this binding: `floors.json`,
|
|
317
|
+
* `reversibility.json`, `notice_targets.json` and `risk_functions.json` are
|
|
318
|
+
* listed and `adapters.json` is not, although §9.3 step 7 and FC-1 both
|
|
319
|
+
* require the binding to be bundle-registered. The file name here follows
|
|
320
|
+
* its four siblings; the §8.2 listing is reported as a normative gap, not
|
|
321
|
+
* silently closed by this file. And the fidelity vocabulary had been
|
|
322
|
+
* declared in the WIRE root (`proposal.schema.json`) with no signed table to
|
|
323
|
+
* draw from -- the value the Executor compares a receipt against lived only
|
|
324
|
+
* on the side being verified. It is declared once, below, and the wire root
|
|
325
|
+
* now `$ref`s it, exactly as `Tier` and `SuiteId` are homed in
|
|
326
|
+
* `floors.schema.json` and `signature.schema.json` (ACP-78 M1).
|
|
327
|
+
*
|
|
328
|
+
* A-7 applies here as it does to floors and reversibility: that an adapter's
|
|
329
|
+
* declared class is HONEST is conceded unprovable. An F-LOW adapter
|
|
330
|
+
* registered as F-HIGH defeats FC-2 with zero attack, and no verifier can
|
|
331
|
+
* tell from this file. Registration is the governance task; this file is
|
|
332
|
+
* where that risk concentrates.
|
|
333
|
+
* Generated from adapters.schema.json.
|
|
334
|
+
*/
|
|
335
|
+
export interface Adapters {
|
|
336
|
+
readonly schemaVersion: '1';
|
|
337
|
+
/**
|
|
338
|
+
* schema_id -> fidelity class. Open map (schemas are deployment-specific),
|
|
339
|
+
* closed values. The key space is the Proposal's `schema_id` (SR-1's
|
|
340
|
+
* identifier half) and is `$ref`d rather than restated so the two spellings
|
|
341
|
+
* cannot drift; note that `tools/codegen.sh` resolves the `$ref` under
|
|
342
|
+
* `propertyNames` (it halts on one it cannot resolve, ACP-128) and carries
|
|
343
|
+
* its description into both languages' doc comments, but still emits map
|
|
344
|
+
* keys as plain strings, so the key constraint is documentary until a
|
|
345
|
+
* validator reads it (ACP-52).
|
|
346
|
+
*
|
|
347
|
+
* Map keys: A registered `schema_id`, the same identifier a Proposal carries
|
|
348
|
+
* and the Executor looks this table up by (§9.3 step 7).
|
|
349
|
+
*/
|
|
350
|
+
readonly adapters: Readonly<Record<string, FidelityClass>>;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Look up one entry in Adapters.adapters.
|
|
354
|
+
*
|
|
355
|
+
* TR-8: a schema_id bound to no registered adapter is REFUSED, never
|
|
356
|
+
* defaulted. `fidelity` is readable by any raise_to clause and FC-2 keys
|
|
357
|
+
* confirmation on it, so there is no fail-safe class to fall back to: F-HIGH
|
|
358
|
+
* suppresses the confirmation requirement exactly as a forged stamp would
|
|
359
|
+
* (X1, T-18), and F-LOW is a policy value the implementation invented for an
|
|
360
|
+
* adapter nobody registered. A lookup returning `Option` here would let a
|
|
361
|
+
* caller write `unwrap_or_default()` and grade a Proposal from an
|
|
362
|
+
* unregistered ingress on a class nobody signed.
|
|
363
|
+
*
|
|
364
|
+
* Generated from the schema's `x-acp-absent` rule. It is not restated here.
|
|
365
|
+
*/
|
|
366
|
+
export type AdaptersLookup = {
|
|
367
|
+
readonly present: true;
|
|
368
|
+
readonly value: FidelityClass;
|
|
369
|
+
} | {
|
|
370
|
+
readonly present: false;
|
|
371
|
+
readonly clause: string;
|
|
372
|
+
readonly why: string;
|
|
373
|
+
};
|
|
374
|
+
export declare function adaptersLookup(table: Adapters, key: string): AdaptersLookup;
|
|
375
|
+
/**
|
|
376
|
+
* The lenient projection of Adapters: every field optional, every enum
|
|
377
|
+
* degraded to `string`. What a verifier parses. Never make a decision on
|
|
378
|
+
* one — the fail-safe lookups live on the strict type only.
|
|
379
|
+
*/
|
|
380
|
+
export interface RawAdapters {
|
|
381
|
+
readonly schemaVersion?: string;
|
|
382
|
+
readonly adapters?: Readonly<Record<string, string>>;
|
|
383
|
+
}
|
|
384
|
+
/**
|
|
385
|
+
* Maps each class of critical alert to the parties woken when one is raised.
|
|
386
|
+
* PB-10 (v1.3.23).
|
|
387
|
+
*
|
|
388
|
+
* WHY THIS FILE EXISTS. Twenty-odd sentences in ZIFFER-SPEC-001 end in 'with
|
|
389
|
+
* a critical alert' and, through v1.3.22, none said to whom. Every
|
|
390
|
+
* implementation therefore chose its own audience -- the notifier's
|
|
391
|
+
* configuration, the KMS's, the deployment's -- and a service that selects
|
|
392
|
+
* its own alert audience is certifying its own coverage: RES-8, and the
|
|
393
|
+
* exact shape of the still-open finding T-32 one component over. It surfaced
|
|
394
|
+
* while the KMS was built as a service, where every 'critical alert'
|
|
395
|
+
* sentence landed on a seam whose only implementation was a no-op (ACP-134).
|
|
396
|
+
*
|
|
397
|
+
* WHY THE MECHANISM IS notice_targets' AND NOT A NEW ONE. DR-13(2) already
|
|
398
|
+
* solved this problem for the fast-path notice: the recipient set is read
|
|
399
|
+
* from the signed bundle, keyed by class, inside policy_bundle_hash, and a
|
|
400
|
+
* class naming nobody fails closed because a notice with no addressee is not
|
|
401
|
+
* a detection channel. It is mutation-proven. Alerts take the identical
|
|
402
|
+
* mechanism -- two mechanisms for one problem is the two-definitions defect
|
|
403
|
+
* this repository has published corrections for three times -- and this file
|
|
404
|
+
* is notice_targets.schema.json with the key set changed.
|
|
405
|
+
*
|
|
406
|
+
* COMPLETENESS FAILS CLOSED AT LOAD, AND JSON SCHEMA CANNOT SAY SO. PB-10
|
|
407
|
+
* enumerates the alert classes and requires every one of them to name at
|
|
408
|
+
* least one recipient; a bundle missing any is invalid and MUST be refused
|
|
409
|
+
* at load by every consumer, on PB-1's footing. The list of classes is owned
|
|
410
|
+
* by the clause, not by this file -- a `required` list here would be a
|
|
411
|
+
* second definition of it -- so the enforcement point is the loader, as with
|
|
412
|
+
* PB-7 in attesters.schema.json. A normative rule with no enforcement point
|
|
413
|
+
* is a comment. Why load-time and not raise-time: a notice's 'fail closed'
|
|
414
|
+
* has an action to withhold, but an alert is raised on a path that has
|
|
415
|
+
* already failed, so refusing at raise time would withhold nothing. What can
|
|
416
|
+
* be withheld is the bundle: a deployment either names who is woken for each
|
|
417
|
+
* class, or it does not run.
|
|
418
|
+
*
|
|
419
|
+
* WHAT IS NOT DECIDED HERE: the transport of an alert (pager, queue,
|
|
420
|
+
* webhook) and what acknowledgement closes it. Those are deployment
|
|
421
|
+
* obligations in DR-12's shape -- silence as measurable debt -- and belong
|
|
422
|
+
* in ZIFFER-DEPLOY-001. Identities, not addresses, for notice_targets'
|
|
423
|
+
* reason: an address is a routing detail that changes without a policy
|
|
424
|
+
* review, and putting one under an offline signing key makes routine
|
|
425
|
+
* operations require RK-5.
|
|
426
|
+
* Generated from alert_targets.schema.json.
|
|
427
|
+
*/
|
|
428
|
+
export interface AlertTargets {
|
|
429
|
+
readonly schemaVersion: '1';
|
|
430
|
+
/**
|
|
431
|
+
* alert class -> recipient identities. Keys are the classes PB-10 enumerates
|
|
432
|
+
* (BUNDLE_INVALID, SIGNING_SUBSTRATE, RECEIPT_INVALID,
|
|
433
|
+
* RECOMPUTATION_MISMATCH, ATTESTATION_INVALID, LEDGER_REPLAY,
|
|
434
|
+
* SUITE_BELOW_FLOOR, DEFERRED_RELEASE, AUDIT_INTEGRITY,
|
|
435
|
+
* ATTESTATION_QUEUE_DEPTH, CONTEXT_STORE); the map is open here so that the
|
|
436
|
+
* clause, not this file, owns the list, and the loader refuses a bundle in
|
|
437
|
+
* which any of them is missing. Every value is a non-empty set: an empty
|
|
438
|
+
* array is REFUSED rather than read as 'wake nobody', because the two are
|
|
439
|
+
* indistinguishable at run time from an entry never written, and the
|
|
440
|
+
* fail-safe reading of both is refusal.
|
|
441
|
+
*
|
|
442
|
+
* Schema constraints, carried as documentation and NOT enforced by this
|
|
443
|
+
* type: values minItems 1, uniqueItems; values items minLength 1, maxLength
|
|
444
|
+
* 128.
|
|
445
|
+
*/
|
|
446
|
+
readonly alertTargets: Readonly<Record<string, readonly string[]>>;
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Look up one entry in AlertTargets.alert_targets.
|
|
450
|
+
*
|
|
451
|
+
* PB-10: an alert with no addressee is not a detection channel. PB-10
|
|
452
|
+
* requires every class to be present at load, so a miss here means a loader
|
|
453
|
+
* skipped PB-10 -- and the generated accessor refuses rather than returning
|
|
454
|
+
* an Option a caller could unwrap_or_default() into silence. Same rule as
|
|
455
|
+
* notice_targets, and deliberately not a value default: there is no
|
|
456
|
+
* fail-safe recipient.
|
|
457
|
+
*
|
|
458
|
+
* Generated from the schema's `x-acp-absent` rule. It is not restated here.
|
|
459
|
+
*/
|
|
460
|
+
export type AlertTargetsLookup = {
|
|
461
|
+
readonly present: true;
|
|
462
|
+
readonly value: readonly string[];
|
|
463
|
+
} | {
|
|
464
|
+
readonly present: false;
|
|
465
|
+
readonly clause: string;
|
|
466
|
+
readonly why: string;
|
|
467
|
+
};
|
|
468
|
+
export declare function alertTargetsLookup(table: AlertTargets, key: string): AlertTargetsLookup;
|
|
469
|
+
/**
|
|
470
|
+
* The lenient projection of AlertTargets: every field optional, every enum
|
|
471
|
+
* degraded to `string`. What a verifier parses. Never make a decision on
|
|
472
|
+
* one — the fail-safe lookups live on the strict type only.
|
|
473
|
+
*/
|
|
474
|
+
export interface RawAlertTargets {
|
|
475
|
+
readonly schemaVersion?: string;
|
|
476
|
+
readonly alertTargets?: Readonly<Record<string, readonly string[]>>;
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* The approver and confirmer verification keys, and the quorum k.
|
|
480
|
+
*
|
|
481
|
+
* PUBLIC KEYS ONLY. This is not a stylistic constraint — it is the v1.3.14
|
|
482
|
+
* custody fix, and it closed a real hole. Through v1.3.13 the primitives
|
|
483
|
+
* were HMAC-SHA256, so verifying a signature required holding the key that
|
|
484
|
+
* made it: the Executor held every attester key and could therefore MINT ITS
|
|
485
|
+
* OWN QUORUM. INV-1-HIGH did not hold against the very adversary it names,
|
|
486
|
+
* and no protocol test could have found it, because the defect was key
|
|
487
|
+
* CUSTODY rather than control flow. Never reintroduce a symmetric primitive
|
|
488
|
+
* here, not even for tests.
|
|
489
|
+
*
|
|
490
|
+
* PB-KEY: this registry is INSIDE the bundle hash. A `policy_bundle_hash`
|
|
491
|
+
* that does not cover it lets two Executors trusting DIFFERENT attesters
|
|
492
|
+
* agree that they hold the same bundle — which is the encoding-split defect
|
|
493
|
+
* wearing a key registry as a hat.
|
|
494
|
+
*
|
|
495
|
+
* ACK-4 (reference-level, see reference/src/acp_ack.py — not a spec clause):
|
|
496
|
+
* an attester's identity is the one the SIGNATURE covers, never a
|
|
497
|
+
* transmitted `attester_id` field. This registry maps identity to key so
|
|
498
|
+
* that the signature can establish which of these entries signed. It does
|
|
499
|
+
* not authorise anyone to name themselves.
|
|
500
|
+
* Generated from attesters.schema.json.
|
|
501
|
+
*/
|
|
502
|
+
export interface AttesterRegistry {
|
|
503
|
+
readonly schemaVersion: '1';
|
|
504
|
+
/**
|
|
505
|
+
* How many DISTINCT attesters must sign the same canonical hash for a
|
|
506
|
+
* floor-HIGH action. INV-1-HIGH. k=1 is permitted by the schema and is a
|
|
507
|
+
* deployment choice, not a conformance failure — but it collapses the
|
|
508
|
+
* invariant to single-compromise, so a deployment choosing it should say so
|
|
509
|
+
* in its residual risk statement rather than discover it later.
|
|
510
|
+
*
|
|
511
|
+
* DR-9 is enforced separately and is not expressible here: whoever proposed
|
|
512
|
+
* the action can never be among the k.
|
|
513
|
+
*
|
|
514
|
+
* Schema constraints, carried as documentation and NOT enforced by this
|
|
515
|
+
* type: minimum 1.
|
|
516
|
+
*/
|
|
517
|
+
readonly quorumK: number;
|
|
518
|
+
/**
|
|
519
|
+
* attester identity -> a machine's hybrid public key or a human's WebAuthn
|
|
520
|
+
* credential (`kind` tells which, HM-1, v1.3.30). Open map (people are
|
|
521
|
+
* deployment-specific), closed entries.
|
|
522
|
+
*
|
|
523
|
+
* PB-DISTINCT (NORMATIVE, and NOT EXPRESSIBLE HERE): no two identities may
|
|
524
|
+
* carry the same public key. `quorum_k` counts DISTINCT KEY HOLDERS; a
|
|
525
|
+
* registry mapping two names onto one key lets the holder of that one
|
|
526
|
+
* private key sign two objects with different nonces, label them with the
|
|
527
|
+
* two names, and satisfy a k=2 quorum alone. INV-1-HIGH broken by a single
|
|
528
|
+
* compromise, reached through the registry rather than through the
|
|
529
|
+
* threshold.
|
|
530
|
+
*
|
|
531
|
+
* JSON Schema cannot state this: `uniqueItems` applies to arrays, and there
|
|
532
|
+
* is no keyword for uniqueness across the VALUES of a map. The rule is
|
|
533
|
+
* therefore enforced by the LOADER, and a loader that does not enforce it is
|
|
534
|
+
* non-conformant however cleanly it validates. Reference implementation:
|
|
535
|
+
* `Bundle.__post_init__` in reference/src/acp_executor.py, which refuses at
|
|
536
|
+
* construction — a bundle whose registry cannot support its own quorum is
|
|
537
|
+
* malformed everywhere it is used, not only on the quorum path. Compare over
|
|
538
|
+
* the full hybrid identity, not the classical half alone; two identities
|
|
539
|
+
* sharing only an ML-DSA key is CR-3 undone at the registry.
|
|
540
|
+
*/
|
|
541
|
+
readonly attesters: Readonly<Record<string, Attester>>;
|
|
542
|
+
/**
|
|
543
|
+
* AT-10: the minimum authenticator assurance every attestation counted
|
|
544
|
+
* toward a quorum must clear. OPTIONAL, and absent means AS0 — the
|
|
545
|
+
* permissive reading, taken deliberately and disclosed in the same breath,
|
|
546
|
+
* exactly as `quorum_k: 1` is permitted and must be disclosed (PB-6): a
|
|
547
|
+
* floor nobody chose must not silently invalidate every registry written
|
|
548
|
+
* before the field existed, and AS0 is what those registries were already
|
|
549
|
+
* getting. A deployment claiming any Door A property stronger than key
|
|
550
|
+
* possession raises this floor; the EU AI Act Art. 14(5) reading of 'two
|
|
551
|
+
* natural persons' is not supported at AS0 and a deployment at AS0 should
|
|
552
|
+
* say so in its residual risk statement.
|
|
553
|
+
*/
|
|
554
|
+
readonly minAttesterAssurance?: Assurance;
|
|
555
|
+
/**
|
|
556
|
+
* AT-10: attester identity -> the assurance level that identity's key was
|
|
557
|
+
* ENROLLED at, over $defs/assurance. A SEPARATE map beside `attesters`
|
|
558
|
+
* rather than a field inside each entry, deliberately: every implementation
|
|
559
|
+
* carries it this way on the wire (the reference Bundle's dict, the
|
|
560
|
+
* differential bridge, the Rust QuorumPolicy), and the map shape is what
|
|
561
|
+
* gives the generated fail-safe accessor an absent rule to answer with -- an
|
|
562
|
+
* identity missing from this map reads AS0, a claim's safe default, inverted
|
|
563
|
+
* from RK-1's floors: an entry claiming less than it has can only cause a
|
|
564
|
+
* refusal, one defaulting to more than it has is the attack. What no field
|
|
565
|
+
* here can carry is honesty: whether a key is REALLY hardware-bound is
|
|
566
|
+
* established at enrolment by humans, and a wrong label is A-7's conceded
|
|
567
|
+
* shape, stated at AT-10.
|
|
568
|
+
*/
|
|
569
|
+
readonly assurance?: Readonly<Record<string, Assurance>>;
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* Look up one entry in AttesterRegistry.attesters.
|
|
573
|
+
*
|
|
574
|
+
* AT-9, PB-6: an identity absent from the signed registry is not an
|
|
575
|
+
* attester. Its signature verifies against no key here and counts toward no
|
|
576
|
+
* quorum, and resolving it to a default would let a name nobody enrolled
|
|
577
|
+
* satisfy INV-1-HIGH. ACK-4: identity is what the SIGNATURE covers, never a
|
|
578
|
+
* transmitted `attester_id` — this map is how a signature is resolved to an
|
|
579
|
+
* enrolled key, not how a name authorises itself.
|
|
580
|
+
*
|
|
581
|
+
* Generated from the schema's `x-acp-absent` rule. It is not restated here.
|
|
582
|
+
*/
|
|
583
|
+
export type AttesterRegistryLookup = {
|
|
584
|
+
readonly present: true;
|
|
585
|
+
readonly value: Attester;
|
|
586
|
+
} | {
|
|
587
|
+
readonly present: false;
|
|
588
|
+
readonly clause: string;
|
|
589
|
+
readonly why: string;
|
|
590
|
+
};
|
|
591
|
+
export declare function attesterRegistryAttestersLookup(table: AttesterRegistry, key: string): AttesterRegistryLookup;
|
|
592
|
+
/**
|
|
593
|
+
* Look up one entry in AttesterRegistry.assurance.
|
|
594
|
+
*
|
|
595
|
+
* AT-10: an identity with no recorded level is read as AS0 -- for a CLAIM
|
|
596
|
+
* the low default is the fail-safe one. Resolving it upward would let an
|
|
597
|
+
* unlabelled key satisfy a floor nobody vouched it for.
|
|
598
|
+
*
|
|
599
|
+
* Generated from the schema's `x-acp-absent` rule. It is not restated here.
|
|
600
|
+
*/
|
|
601
|
+
export declare function attesterRegistryAssuranceLookup(table: AttesterRegistry, key: string): Assurance;
|
|
602
|
+
/**
|
|
603
|
+
* `AttesterRegistry.min_attester_assurance`, with the schema's absent rule
|
|
604
|
+
* applied.
|
|
605
|
+
*
|
|
606
|
+
* AT-10: the floor is POLICY, and its permissive default is taken openly and
|
|
607
|
+
* disclosed on PB-6's terms (quorum_k = 1): a floor nobody chose must not
|
|
608
|
+
* silently invalidate every registry written before the field existed. A
|
|
609
|
+
* deployment claiming any Door A property stronger than key possession
|
|
610
|
+
* raises it.
|
|
611
|
+
*
|
|
612
|
+
* Generated from the schema's `x-acp-absent` rule. It is not restated here.
|
|
613
|
+
*/
|
|
614
|
+
export declare function attesterRegistryMinAttesterAssurance(doc: AttesterRegistry): Assurance;
|
|
615
|
+
/**
|
|
616
|
+
* The lenient projection of AttesterRegistry: every field optional, every enum
|
|
617
|
+
* degraded to `string`. What a verifier parses. Never make a decision on
|
|
618
|
+
* one — the fail-safe lookups live on the strict type only.
|
|
619
|
+
*/
|
|
620
|
+
export interface RawAttesterRegistry {
|
|
621
|
+
readonly schemaVersion?: string;
|
|
622
|
+
readonly quorumK?: number;
|
|
623
|
+
readonly attesters?: Readonly<Record<string, string>>;
|
|
624
|
+
readonly minAttesterAssurance?: string;
|
|
625
|
+
readonly assurance?: Readonly<Record<string, string>>;
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* How the bundle signing key is held.
|
|
629
|
+
*
|
|
630
|
+
* CLASSIFIED **T** (trusted as transmitted) AND NOT A CONTROL INPUT. A
|
|
631
|
+
* verifier MUST NOT weight any decision on this object. A bundle asserting
|
|
632
|
+
* its own custody strength is the recurring defect RES-8/RES-9/RES-10 names:
|
|
633
|
+
* a verifier must never accept a derived security value from the party it is
|
|
634
|
+
* verifying. A compromised signer writes this object freely.
|
|
635
|
+
*
|
|
636
|
+
* It is recorded for humans — auditors, operators, and the reviewer named
|
|
637
|
+
* above — and for no other purpose. The real binding is that the verifier is
|
|
638
|
+
* configured out of band with the expected public key.
|
|
639
|
+
* Generated from manifest.schema.json#/$defs/custody.
|
|
640
|
+
*/
|
|
641
|
+
export interface Custody {
|
|
642
|
+
/**
|
|
643
|
+
* T0 development only; T1 encrypted key on an air-gapped host; T2
|
|
644
|
+
* non-exportable cloud KMS; T3 PKCS#11 HSM. Split custody reports the WEAKER
|
|
645
|
+
* of its two legs, because a claim should never round in the flattering
|
|
646
|
+
* direction.
|
|
647
|
+
*
|
|
648
|
+
* The SAME four values as a resource floor, drawn from `floors.schema.json`
|
|
649
|
+
* so there is one definition of the tier ladder. Note that the two uses are
|
|
650
|
+
* unrelated in meaning: a resource floor says how sensitive a thing is, a
|
|
651
|
+
* custody tier says how a key is held. They share a scale, not a subject.
|
|
652
|
+
*/
|
|
653
|
+
readonly tier: Tier;
|
|
654
|
+
readonly classical: CustodyLeg;
|
|
655
|
+
readonly pq: CustodyLeg;
|
|
656
|
+
}
|
|
657
|
+
/**
|
|
658
|
+
* The lenient projection of Custody: every field optional, every enum
|
|
659
|
+
* degraded to `string`. What a verifier parses. Never make a decision on
|
|
660
|
+
* one — the fail-safe lookups live on the strict type only.
|
|
661
|
+
*/
|
|
662
|
+
export interface RawCustody {
|
|
663
|
+
readonly tier?: string;
|
|
664
|
+
readonly classical?: RawCustodyLeg;
|
|
665
|
+
readonly pq?: RawCustodyLeg;
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* Custody of one primitive. The two legs may differ, and differing is not a
|
|
669
|
+
* weakness: verification is conjunctive (CR-3), so forging requires BOTH
|
|
670
|
+
* signatures and therefore BOTH keys. An attacker must defeat both
|
|
671
|
+
* mechanisms.
|
|
672
|
+
* Generated from manifest.schema.json#/$defs/custody_leg.
|
|
673
|
+
*/
|
|
674
|
+
export interface CustodyLeg {
|
|
675
|
+
readonly tier: Tier;
|
|
676
|
+
/**
|
|
677
|
+
* Free text naming the concrete mechanism, e.g. "YubiHSM2 slot 3" or
|
|
678
|
+
* "age-encrypted file, offline laptop". Human-readable only.
|
|
679
|
+
*
|
|
680
|
+
* Schema constraints, carried as documentation and NOT enforced by this
|
|
681
|
+
* type: minLength 1, maxLength 256.
|
|
682
|
+
*/
|
|
683
|
+
readonly mechanism: string;
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* The lenient projection of CustodyLeg: every field optional, every enum
|
|
687
|
+
* degraded to `string`. What a verifier parses. Never make a decision on
|
|
688
|
+
* one — the fail-safe lookups live on the strict type only.
|
|
689
|
+
*/
|
|
690
|
+
export interface RawCustodyLeg {
|
|
691
|
+
readonly tier?: string;
|
|
692
|
+
readonly mechanism?: string;
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Names the two services whose summaries the Executor consumes during a
|
|
696
|
+
* deferred-release hold, each with the verification keys its Rendered
|
|
697
|
+
* Summary objects (DR-14; notification.schema.json `$defs/rendered_summary`)
|
|
698
|
+
* are signed under. PB-11 (v1.3.25).
|
|
699
|
+
*
|
|
700
|
+
* WHY THIS FILE EXISTS. From v1.3.6 to v1.3.24 the Executor established
|
|
701
|
+
* DR-2's independence -- the notification path shares no rendering code with
|
|
702
|
+
* the approval path -- by comparing two labels the notification service
|
|
703
|
+
* chose (`source_path`) and reading a boolean it set (`from_canonical`).
|
|
704
|
+
* Both were classified T in ACP-CLASS-001 (rows 24-25, finding T-32):
|
|
705
|
+
* evidence about a service, produced by that service. A compromised notifier
|
|
706
|
+
* that rendered through the approval path, labelled itself otherwise and
|
|
707
|
+
* reported full delivery passed every check, and
|
|
708
|
+
* `reference/suites/class_findings.py` demonstrated it for thirteen
|
|
709
|
+
* revisions. The structural reason was recorded in notification.schema.json:
|
|
710
|
+
* the notification was not a signed structure, so there were no bytes to
|
|
711
|
+
* verify. This file supplies the keys those bytes are now verified under.
|
|
712
|
+
*
|
|
713
|
+
* WHY THE MECHANISM IS THE ATTESTER REGISTRY'S AND NOT A NEW ONE. Who may
|
|
714
|
+
* speak for a door is the same kind of value as who may attest (PB-6, PB-7),
|
|
715
|
+
* who is told (DR-13) and who is woken (PB-10): a service that names its own
|
|
716
|
+
* identity is certifying its own independence, RES-8. So the identities sit
|
|
717
|
+
* in signed policy under RK-5 two-person control, in the attester registry's
|
|
718
|
+
* key shape -- one Ed25519 and one ML-DSA-65 verification key, the same
|
|
719
|
+
* named scalars -- and the loader applies PB-7's distinctness rule across
|
|
720
|
+
* the two: compared over the COMPLETE suite, because two identities sharing
|
|
721
|
+
* a post-quantum key are not distinct, and treating them as such is CR-3's
|
|
722
|
+
* conjunctive guarantee undone at the registry instead of at the verifier.
|
|
723
|
+
*
|
|
724
|
+
* DISTINCTNESS FAILS CLOSED AT LOAD, AND JSON SCHEMA CANNOT SAY SO.
|
|
725
|
+
* `presentation` and `notification` are both required here, so an absent one
|
|
726
|
+
* is a schema violation as well as a PB-11 refusal; but 'the two share no
|
|
727
|
+
* key' is a relation across two values, and there is no keyword for it. As
|
|
728
|
+
* with PB-7 in attesters.schema.json the enforcement point is the loader: a
|
|
729
|
+
* bundle in which either key of one door equals the corresponding key of the
|
|
730
|
+
* other is refused at load by every consumer, on PB-1's footing. A normative
|
|
731
|
+
* rule with no enforcement point is a comment.
|
|
732
|
+
*
|
|
733
|
+
* WHAT A KEY HERE DOES NOT PROVE. A Rendered Summary that verifies under the
|
|
734
|
+
* `notification` key was produced by the holder of that key, for the
|
|
735
|
+
* proposal hash it names. That the prose is faithful to those bytes is
|
|
736
|
+
* DR-2's STRUCTURAL requirement -- no shared rendering path, demonstrated at
|
|
737
|
+
* build time under conformance suite 3 -- and no signature supplies it. A
|
|
738
|
+
* signature over a lie is a signed lie; what it can no longer be is a lie
|
|
739
|
+
* told by the other door.
|
|
740
|
+
*
|
|
741
|
+
* WHAT IS DELIBERATELY NOT HERE. Addresses, endpoints, channels: identities
|
|
742
|
+
* rather than routing, for notice_targets' and alert_targets' reason -- a
|
|
743
|
+
* routing detail changes without a policy review, and putting one under an
|
|
744
|
+
* offline signing key makes routine operations require RK-5. And no third
|
|
745
|
+
* role: the fast-path notice (DR-13) is committed by the Executor to its own
|
|
746
|
+
* state and involves no service, so it needs no identity.
|
|
747
|
+
* Generated from door_identities.schema.json.
|
|
748
|
+
*/
|
|
749
|
+
export interface DoorIdentities {
|
|
750
|
+
readonly schemaVersion: '1';
|
|
751
|
+
/**
|
|
752
|
+
* The Attestation Presentation Service: the approval path, the door the
|
|
753
|
+
* attesters were shown the action through. Its key signs the approval
|
|
754
|
+
* summary the Executor compares against the notification at DR-14.
|
|
755
|
+
*/
|
|
756
|
+
readonly presentation: DoorIdentity;
|
|
757
|
+
/**
|
|
758
|
+
* The notification service: DR-2's independent path, the door the
|
|
759
|
+
* out-of-band summary reaches the attesters and the operator through. Its
|
|
760
|
+
* key signs the Notification (DR-3 leg). A summary that verifies under this
|
|
761
|
+
* key was not produced by the presentation service -- which is the whole of
|
|
762
|
+
* what deferred release needs the second door for.
|
|
763
|
+
*/
|
|
764
|
+
readonly notification: DoorIdentity;
|
|
765
|
+
}
|
|
766
|
+
/**
|
|
767
|
+
* The lenient projection of DoorIdentities: every field optional, every enum
|
|
768
|
+
* degraded to `string`. What a verifier parses. Never make a decision on
|
|
769
|
+
* one — the fail-safe lookups live on the strict type only.
|
|
770
|
+
*/
|
|
771
|
+
export interface RawDoorIdentities {
|
|
772
|
+
readonly schemaVersion?: string;
|
|
773
|
+
readonly presentation?: RawDoorIdentity;
|
|
774
|
+
readonly notification?: RawDoorIdentity;
|
|
775
|
+
}
|
|
776
|
+
/**
|
|
777
|
+
* `DoorIdentity`.
|
|
778
|
+
* Generated from door_identities.schema.json#/$defs/door.
|
|
779
|
+
*/
|
|
780
|
+
export interface DoorIdentity {
|
|
781
|
+
/**
|
|
782
|
+
* The identity's name, for the audit record and the alert. NOT what the
|
|
783
|
+
* Executor resolves a signature by -- ACK-4's rule applies here too:
|
|
784
|
+
* identity is what the signature verifies under, and this name is a label
|
|
785
|
+
* for the key beside it, never a way for a name to authorise itself.
|
|
786
|
+
*
|
|
787
|
+
* Schema constraints, carried as documentation and NOT enforced by this
|
|
788
|
+
* type: minLength 1, maxLength 128.
|
|
789
|
+
*/
|
|
790
|
+
readonly name: string;
|
|
791
|
+
/**
|
|
792
|
+
* The door's Ed25519 verification key. The attester registry's named scalar,
|
|
793
|
+
* referenced rather than re-declared: one definition of a key encoding.
|
|
794
|
+
*/
|
|
795
|
+
readonly classical: Ed25519PublicKey;
|
|
796
|
+
/**
|
|
797
|
+
* The door's ML-DSA-65 verification key. Both legs are required because CR-3
|
|
798
|
+
* is conjunctive and the bundle's suite names both; a door registered with
|
|
799
|
+
* one leg would be a door whose summaries can never verify.
|
|
800
|
+
*/
|
|
801
|
+
readonly pq: MlDsa65PublicKey;
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* The lenient projection of DoorIdentity: every field optional, every enum
|
|
805
|
+
* degraded to `string`. What a verifier parses. Never make a decision on
|
|
806
|
+
* one — the fail-safe lookups live on the strict type only.
|
|
807
|
+
*/
|
|
808
|
+
export interface RawDoorIdentity {
|
|
809
|
+
readonly name?: string;
|
|
810
|
+
readonly classical?: string;
|
|
811
|
+
readonly pq?: string;
|
|
812
|
+
}
|
|
813
|
+
/**
|
|
814
|
+
* Maps each governable resource to its floor tier.
|
|
815
|
+
*
|
|
816
|
+
* RK-1: a resource ABSENT from this file MUST be treated as T3. That rule
|
|
817
|
+
* cannot be expressed in JSON Schema — a schema constrains what is present,
|
|
818
|
+
* never what is missing — so it is carried instead by the `x-acp-absent`
|
|
819
|
+
* annotation on `floors` below, which `tools/codegen.sh` reads to GENERATE
|
|
820
|
+
* the fail-safe direction into `Tier::for_unclassified()` (crates/acp-core)
|
|
821
|
+
* and its TypeScript equivalent. The Python reference spells the same
|
|
822
|
+
* default at `acp_executor.py`. A conformance case asserts it, because a
|
|
823
|
+
* fail-safe default that only exists in a comment is not a control — and
|
|
824
|
+
* stating it only in this prose is what let the Rust and TypeScript versions
|
|
825
|
+
* return HIGH, a RISK LEVEL, where a TIER was required.
|
|
826
|
+
*
|
|
827
|
+
* RES-1 (A-7): the architecture guarantees no runtime component evaluates a
|
|
828
|
+
* resource BELOW its signed floor. It cannot know whether the floor was set
|
|
829
|
+
* correctly. A production database labelled T0 defeats the design with zero
|
|
830
|
+
* attack. Floor maintenance is the highest-leverage governance task in the
|
|
831
|
+
* system and is structurally unprovable — this file is where that risk
|
|
832
|
+
* concentrates.
|
|
833
|
+
* Generated from floors.schema.json.
|
|
834
|
+
*/
|
|
835
|
+
export interface Floors {
|
|
836
|
+
readonly schemaVersion: '1';
|
|
837
|
+
/**
|
|
838
|
+
* resource identifier -> floor tier. Deliberately an open map: resources are
|
|
839
|
+
* deployment-specific. The VALUES are closed.
|
|
840
|
+
*/
|
|
841
|
+
readonly floors: Readonly<Record<string, Tier>>;
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Look up one entry in Floors.floors.
|
|
845
|
+
*
|
|
846
|
+
* RK-1: absent means unknown, and unknown is the HIGHEST tier, not the
|
|
847
|
+
* lowest (P-4). Returning T0 or T1 here is the whole class of defect this
|
|
848
|
+
* specification exists to prevent, and it is the direction a lookup
|
|
849
|
+
* returning `Option` invites.
|
|
850
|
+
*
|
|
851
|
+
* Generated from the schema's `x-acp-absent` rule. It is not restated here.
|
|
852
|
+
*/
|
|
853
|
+
export declare function floorsLookup(table: Floors, key: string): Tier;
|
|
854
|
+
/**
|
|
855
|
+
* The lenient projection of Floors: every field optional, every enum
|
|
856
|
+
* degraded to `string`. What a verifier parses. Never make a decision on
|
|
857
|
+
* one — the fail-safe lookups live on the strict type only.
|
|
858
|
+
*/
|
|
859
|
+
export interface RawFloors {
|
|
860
|
+
readonly schemaVersion?: string;
|
|
861
|
+
readonly floors?: Readonly<Record<string, string>>;
|
|
862
|
+
}
|
|
863
|
+
/**
|
|
864
|
+
* A human attester (HM-1, v1.3.30): a person who enrolled a WebAuthn
|
|
865
|
+
* credential -- a passkey on their phone or laptop, or a hardware security
|
|
866
|
+
* key -- through a registration ceremony with user verification required and
|
|
867
|
+
* attestation requested. Their signature is a WebAuthn assertion over the
|
|
868
|
+
* same bytes a machine signs (HM-2), verified under HM-4; it is classical,
|
|
869
|
+
* and HM-6 says what that costs. The level recorded for this identity in
|
|
870
|
+
* `assurance` is DERIVED from the authenticator (platform + UV = AS1,
|
|
871
|
+
* roaming hardware = AS2) and an entry at AS0 or with no level is an invalid
|
|
872
|
+
* bundle.
|
|
873
|
+
* Generated from attesters.schema.json#/$defs/human_attester.
|
|
874
|
+
*/
|
|
875
|
+
export interface HumanAttester {
|
|
876
|
+
/**
|
|
877
|
+
* The discriminator. `webauthn`: this identity is a person holding an
|
|
878
|
+
* authenticator; the entry's signature is an assertion, never a hybrid pair.
|
|
879
|
+
*/
|
|
880
|
+
readonly kind: 'webauthn';
|
|
881
|
+
/**
|
|
882
|
+
* approver signs for authorisation; confirmer provides the non-operator
|
|
883
|
+
* positive acknowledgement DR-9 requires for irreversible actions. One
|
|
884
|
+
* person MAY hold both roles in the registry — DR-9 is enforced per action
|
|
885
|
+
* against the proposer, not by role exclusion here.
|
|
886
|
+
*/
|
|
887
|
+
readonly role: AttesterRole;
|
|
888
|
+
readonly rpId: RpId;
|
|
889
|
+
readonly credentialId: CredentialId;
|
|
890
|
+
readonly publicKey: CoseKey;
|
|
891
|
+
readonly alg: WebauthnAlg;
|
|
892
|
+
}
|
|
893
|
+
/**
|
|
894
|
+
* The lenient projection of HumanAttester: every field optional, every enum
|
|
895
|
+
* degraded to `string`. What a verifier parses. Never make a decision on
|
|
896
|
+
* one — the fail-safe lookups live on the strict type only.
|
|
897
|
+
*/
|
|
898
|
+
export interface RawHumanAttester {
|
|
899
|
+
readonly kind?: string;
|
|
900
|
+
readonly role?: string;
|
|
901
|
+
readonly rpId?: string;
|
|
902
|
+
readonly credentialId?: string;
|
|
903
|
+
readonly publicKey?: string;
|
|
904
|
+
readonly alg?: string;
|
|
905
|
+
}
|
|
906
|
+
/**
|
|
907
|
+
* `Identity`.
|
|
908
|
+
* Generated from manifest.schema.json#/$defs/identity.
|
|
909
|
+
*/
|
|
910
|
+
export interface Identity {
|
|
911
|
+
/**
|
|
912
|
+
* Stable identifier. Compared byte-for-byte for PB-2; display_name is never
|
|
913
|
+
* used for the comparison because two people can share a display name.
|
|
914
|
+
*
|
|
915
|
+
* Schema constraints, carried as documentation and NOT enforced by this
|
|
916
|
+
* type: minLength 1, maxLength 128.
|
|
917
|
+
*/
|
|
918
|
+
readonly id: string;
|
|
919
|
+
/**
|
|
920
|
+
* Schema constraints, carried as documentation and NOT enforced by this
|
|
921
|
+
* type: minLength 1, maxLength 256.
|
|
922
|
+
*/
|
|
923
|
+
readonly displayName: string;
|
|
924
|
+
}
|
|
925
|
+
/**
|
|
926
|
+
* The lenient projection of Identity: every field optional, every enum
|
|
927
|
+
* degraded to `string`. What a verifier parses. Never make a decision on
|
|
928
|
+
* one — the fail-safe lookups live on the strict type only.
|
|
929
|
+
*/
|
|
930
|
+
export interface RawIdentity {
|
|
931
|
+
readonly id?: string;
|
|
932
|
+
readonly displayName?: string;
|
|
933
|
+
}
|
|
934
|
+
/**
|
|
935
|
+
* The three numbers this document calls policy and no member carried: how
|
|
936
|
+
* long a human has to approve (L-15), how long a floor-HIGH action is held
|
|
937
|
+
* before release (DR-1, L-28), and what fraction of reversible releases
|
|
938
|
+
* draws a mandatory confirmation (DR-10, L-29). Signed, inside the tree
|
|
939
|
+
* hash, read by the issuer of each: the Policy Engine sets an Attestation
|
|
940
|
+
* Object's `expires_at` from `attestation_window_seconds`; the Executor
|
|
941
|
+
* builds its deferred door from the other two.
|
|
942
|
+
*
|
|
943
|
+
* WHY THIS MEMBER EXISTS (ACP-287, v1.3.30). DR-1 and DR-10 said
|
|
944
|
+
* `bundle-configured` since v1.3.7 and no schema had a field for either, so
|
|
945
|
+
* every implementation read the hold window and the sampling rate from its
|
|
946
|
+
* own environment -- a number this document calls signed policy, set per
|
|
947
|
+
* process by whoever runs it. L-15 gave the attestation window a ceiling and
|
|
948
|
+
* no home at all, so the one engine that issues attestations used the
|
|
949
|
+
* ceiling as the window and said so in its module note: shortening it would
|
|
950
|
+
* be that binary choosing how long a human has to approve. It was right. The
|
|
951
|
+
* place the number lives is here.
|
|
952
|
+
*
|
|
953
|
+
* EVERY FIELD IS OPTIONAL, AND ABSENT MEANS THE DOCUMENT'S OWN DEFAULT --
|
|
954
|
+
* the AT-10 precedent (`min_attester_assurance`, absent ⇒ AS0): a permissive
|
|
955
|
+
* reading taken openly, so that no bundle written before this member existed
|
|
956
|
+
* is invalidated by it, and a bundle that omits the file altogether reads as
|
|
957
|
+
* every field at its default. The defaults are this document's numbers and
|
|
958
|
+
* not an implementation's: 3600 s is L-15's ceiling and what every
|
|
959
|
+
* deployment had; 60 s and 10 % are the values DR-1 and DR-10 state. A
|
|
960
|
+
* deployment that wants the document's defaults may say nothing; one that
|
|
961
|
+
* wants anything else must sign it here.
|
|
962
|
+
*
|
|
963
|
+
* BOUNDS ARE REFUSALS, NOT CLAMPS. A value outside its declared range is an
|
|
964
|
+
* invalid bundle under PB-1 (`LimitOutOfBounds`), refused at load by every
|
|
965
|
+
* consumer and never rounded to the nearest legal value -- a clamped limit
|
|
966
|
+
* is a limit nobody chose. The bounds are the document's: L-15's ceiling,
|
|
967
|
+
* L-28's floor and DR-6's ceiling (a hold at or above L-14's 120 s receipt
|
|
968
|
+
* validity is an unsatisfiable configuration), and a percentage. A present
|
|
969
|
+
* file that is not an object, or a field of the wrong type, is `Malformed`.
|
|
970
|
+
*
|
|
971
|
+
* INTEGERS ONLY. A float in a signed policy file is a canonicalisation
|
|
972
|
+
* question -- AT-8a forbids one in a canonical structure for the reason
|
|
973
|
+
* `canon()` cannot encode it deterministically -- and DR-10's own unit is a
|
|
974
|
+
* percentage, so the fraction is carried as an integer percent. One-percent
|
|
975
|
+
* resolution is deliberate and disclosed: DR-10 exists to keep the detection
|
|
976
|
+
* channel live, not to meter it.
|
|
977
|
+
*
|
|
978
|
+
* WHAT IS NOT HERE, AND WHY. L-25 (DS-6e, the re-drive maximum,
|
|
979
|
+
* `bundle-configured, default 3`) and L-23 (AQ-3, queue depth per attester)
|
|
980
|
+
* are also called bundle-configured and have no reader in any
|
|
981
|
+
* implementation; a field nothing reads is documentation shaped like a
|
|
982
|
+
* control (the RV-1 lesson, v1.3.15), so each joins this member with its
|
|
983
|
+
* first reader and not before. The Executor cannot VERIFY the attestation
|
|
984
|
+
* window either: AT-1's object carries `expires_at` and no issue instant, so
|
|
985
|
+
* only the issuer knows the length. The declared value governs the issuer,
|
|
986
|
+
* and the bundle is signed.
|
|
987
|
+
* Generated from limits.schema.json.
|
|
988
|
+
*/
|
|
989
|
+
export interface Limits {
|
|
990
|
+
readonly schemaVersion: '1';
|
|
991
|
+
/**
|
|
992
|
+
* AT-1 / L-15: the Attestation Object's `expires_at` is its issue instant
|
|
993
|
+
* plus this many seconds. At most 3600, L-15's ceiling. Absent ⇒ 3600, which
|
|
994
|
+
* is what every deployment had before this field existed and the only number
|
|
995
|
+
* the document stated.
|
|
996
|
+
*
|
|
997
|
+
* Schema constraints, carried as documentation and NOT enforced by this
|
|
998
|
+
* type: minimum 1, maximum 3600.
|
|
999
|
+
*/
|
|
1000
|
+
readonly attestationWindowSeconds?: number;
|
|
1001
|
+
/**
|
|
1002
|
+
* DR-1 / L-28: how long a floor-HIGH action is held in `pending_release`
|
|
1003
|
+
* before it may release. At least 30 (L-28's floor: a hold too short for a
|
|
1004
|
+
* human to read the summary is not a detection channel), and below 120
|
|
1005
|
+
* (DR-6: L-14 caps receipt validity at 120 s, and a hold that can outlive
|
|
1006
|
+
* its receipt is an unsatisfiable configuration, refused rather than
|
|
1007
|
+
* silently never releasing). Absent ⇒ 60, DR-1's default.
|
|
1008
|
+
*
|
|
1009
|
+
* Schema constraints, carried as documentation and NOT enforced by this
|
|
1010
|
+
* type: minimum 30, maximum 119.
|
|
1011
|
+
*/
|
|
1012
|
+
readonly holdWindowSeconds?: number;
|
|
1013
|
+
/**
|
|
1014
|
+
* DR-10 / L-29: the percentage of REVERSIBLE floor-HIGH actions selected for
|
|
1015
|
+
* mandatory acknowledgement under the DR-9 rule, drawn by the Executor from
|
|
1016
|
+
* a CSPRNG (DR-11). 0 is permitted by the schema and is a deployment choice
|
|
1017
|
+
* that switches the sampled channel off; a deployment choosing it should say
|
|
1018
|
+
* so in its residual risk statement. Absent ⇒ 10, DR-10's default.
|
|
1019
|
+
*
|
|
1020
|
+
* Schema constraints, carried as documentation and NOT enforced by this
|
|
1021
|
+
* type: minimum 0, maximum 100.
|
|
1022
|
+
*/
|
|
1023
|
+
readonly samplePercent?: number;
|
|
1024
|
+
}
|
|
1025
|
+
/**
|
|
1026
|
+
* `Limits.attestation_window_seconds`, with the schema's absent rule
|
|
1027
|
+
* applied.
|
|
1028
|
+
*
|
|
1029
|
+
* L-15: the ceiling is the document's own number and the behaviour every
|
|
1030
|
+
* deployment had; a shorter window is a deployment's choice and must be
|
|
1031
|
+
* signed here to take effect.
|
|
1032
|
+
*
|
|
1033
|
+
* Generated from the schema's `x-acp-absent` rule. It is not restated here.
|
|
1034
|
+
*/
|
|
1035
|
+
export declare function limitsAttestationWindowSeconds(doc: Limits): number;
|
|
1036
|
+
/**
|
|
1037
|
+
* `Limits.hold_window_seconds`, with the schema's absent rule applied.
|
|
1038
|
+
*
|
|
1039
|
+
* DR-1: DR-1 states the default; a bundle that says nothing gets the
|
|
1040
|
+
* document's number and not a process's environment.
|
|
1041
|
+
*
|
|
1042
|
+
* Generated from the schema's `x-acp-absent` rule. It is not restated here.
|
|
1043
|
+
*/
|
|
1044
|
+
export declare function limitsHoldWindowSeconds(doc: Limits): number;
|
|
1045
|
+
/**
|
|
1046
|
+
* `Limits.sample_percent`, with the schema's absent rule applied.
|
|
1047
|
+
*
|
|
1048
|
+
* DR-10: DR-10 states the default; a bundle that says nothing gets the
|
|
1049
|
+
* document's number.
|
|
1050
|
+
*
|
|
1051
|
+
* Generated from the schema's `x-acp-absent` rule. It is not restated here.
|
|
1052
|
+
*/
|
|
1053
|
+
export declare function limitsSamplePercent(doc: Limits): number;
|
|
1054
|
+
/**
|
|
1055
|
+
* The lenient projection of Limits: every field optional, every enum
|
|
1056
|
+
* degraded to `string`. What a verifier parses. Never make a decision on
|
|
1057
|
+
* one — the fail-safe lookups live on the strict type only.
|
|
1058
|
+
*/
|
|
1059
|
+
export interface RawLimits {
|
|
1060
|
+
readonly schemaVersion?: string;
|
|
1061
|
+
readonly attestationWindowSeconds?: number;
|
|
1062
|
+
readonly holdWindowSeconds?: number;
|
|
1063
|
+
readonly samplePercent?: number;
|
|
1064
|
+
}
|
|
1065
|
+
/**
|
|
1066
|
+
* A machine attester: a service that signs with a hybrid key pair -- the
|
|
1067
|
+
* sandbox robot, a confirmer that is a system. The shape every registry
|
|
1068
|
+
* entry had before v1.3.30, plus `kind`, which every entry now carries so
|
|
1069
|
+
* that a human and a machine are told apart by a signed tag and never by
|
|
1070
|
+
* which fields happen to be present (HM-1).
|
|
1071
|
+
* Generated from attesters.schema.json#/$defs/machine_attester.
|
|
1072
|
+
*/
|
|
1073
|
+
export interface MachineAttester {
|
|
1074
|
+
/**
|
|
1075
|
+
* The discriminator. `hybrid`: this identity signs with the two-primitive
|
|
1076
|
+
* pair below and is held to CR-3/CR-4.
|
|
1077
|
+
*/
|
|
1078
|
+
readonly kind: 'hybrid';
|
|
1079
|
+
/**
|
|
1080
|
+
* approver signs for authorisation; confirmer provides the non-operator
|
|
1081
|
+
* positive acknowledgement DR-9 requires for irreversible actions. One
|
|
1082
|
+
* person MAY hold both roles in the registry — DR-9 is enforced per action
|
|
1083
|
+
* against the proposer, not by role exclusion here.
|
|
1084
|
+
*/
|
|
1085
|
+
readonly role: AttesterRole;
|
|
1086
|
+
readonly classical: Ed25519PublicKey;
|
|
1087
|
+
readonly pq: MlDsa65PublicKey;
|
|
1088
|
+
}
|
|
1089
|
+
/**
|
|
1090
|
+
* The lenient projection of MachineAttester: every field optional, every enum
|
|
1091
|
+
* degraded to `string`. What a verifier parses. Never make a decision on
|
|
1092
|
+
* one — the fail-safe lookups live on the strict type only.
|
|
1093
|
+
*/
|
|
1094
|
+
export interface RawMachineAttester {
|
|
1095
|
+
readonly kind?: string;
|
|
1096
|
+
readonly role?: string;
|
|
1097
|
+
readonly classical?: string;
|
|
1098
|
+
readonly pq?: string;
|
|
1099
|
+
}
|
|
1100
|
+
/**
|
|
1101
|
+
* Identity and provenance of one signed policy bundle. PB-5: bundle_epoch is
|
|
1102
|
+
* strictly increasing and never reused or decreased. PB-2: author and
|
|
1103
|
+
* reviewer identities MUST differ — asserted by the signer, because a schema
|
|
1104
|
+
* cannot express a comparison between two of its own fields.
|
|
1105
|
+
* Generated from manifest.schema.json.
|
|
1106
|
+
*/
|
|
1107
|
+
export interface Manifest {
|
|
1108
|
+
/**
|
|
1109
|
+
* Version of this manifest schema. Present so a decoder can refuse a bundle
|
|
1110
|
+
* it does not fully understand rather than ignoring fields it does not
|
|
1111
|
+
* recognise.
|
|
1112
|
+
*/
|
|
1113
|
+
readonly schemaVersion: '1';
|
|
1114
|
+
/**
|
|
1115
|
+
* RAD-5 (v1.3.23). The tenant this bundle governs, inside the tree hash
|
|
1116
|
+
* because every member is. This is the value the KMS binds a signing request
|
|
1117
|
+
* to (§9.1.1 step 5a) and the Executor binds a receipt to (§9.3 step 8): a
|
|
1118
|
+
* request or a receipt naming any other tenant is refused. Through v1.3.22
|
|
1119
|
+
* no bundle named its tenant, so the KMS chose which tenant's receipt key
|
|
1120
|
+
* signs from `tenant_id` in the request body -- a value the Policy Engine
|
|
1121
|
+
* wrote, i.e. the party under verification, classified T -- and the only
|
|
1122
|
+
* thing between tenant A's bundle and tenant B's key was a repository
|
|
1123
|
+
* partition a verifier cannot inspect (ACP-139). This is PB-6's move:
|
|
1124
|
+
* `quorum_k` went into signed policy as the only authoritative source, and
|
|
1125
|
+
* the tenant goes in for the same reason.
|
|
1126
|
+
*
|
|
1127
|
+
* REQUIRED, AND ABSENCE IS REFUSAL. A manifest naming no tenant is an
|
|
1128
|
+
* invalid bundle under PB-1 and is refused at load by every consumer -- the
|
|
1129
|
+
* KMS under RAD-4, the Policy Engine under PB-1, the Executor at §9.3 step
|
|
1130
|
+
* 4. There is no default tenant to fall back to, for the reason there is no
|
|
1131
|
+
* default notice recipient (DR-13): the fail-safe reading of 'no tenant' is
|
|
1132
|
+
* 'no bundle', never 'any tenant'. Not derived from the transport either:
|
|
1133
|
+
* the control plane is multi-tenant, so the Policy Engine's mTLS identity is
|
|
1134
|
+
* not the tenant's.
|
|
1135
|
+
*/
|
|
1136
|
+
readonly tenantId: TenantId;
|
|
1137
|
+
/**
|
|
1138
|
+
* PB-5. Strictly increasing integer. Never reused, never decreased. The
|
|
1139
|
+
* Executor keeps a high-water mark indefinitely (CL-4) — an expiring epoch
|
|
1140
|
+
* mark would reopen rollback.
|
|
1141
|
+
*
|
|
1142
|
+
* Schema constraints, carried as documentation and NOT enforced by this
|
|
1143
|
+
* type: minimum 0.
|
|
1144
|
+
*/
|
|
1145
|
+
readonly bundleEpoch: number;
|
|
1146
|
+
/**
|
|
1147
|
+
* RFC 3339 UTC. Informational: freshness is enforced by expires_at and by
|
|
1148
|
+
* the epoch, never by comparing this to a local clock.
|
|
1149
|
+
*
|
|
1150
|
+
* Schema constraints, carried as documentation and NOT enforced by this
|
|
1151
|
+
* type: format `date-time`.
|
|
1152
|
+
*/
|
|
1153
|
+
readonly createdAt: string;
|
|
1154
|
+
/**
|
|
1155
|
+
* Who wrote this bundle. PB-2: MUST differ from reviewer.
|
|
1156
|
+
*/
|
|
1157
|
+
readonly author: Identity;
|
|
1158
|
+
/**
|
|
1159
|
+
* Who reviewed it. PB-2: MUST differ from author. Two-person integrity on
|
|
1160
|
+
* the highest-leverage governance artifact in the system — RES-1 names floor
|
|
1161
|
+
* maintenance as exactly that.
|
|
1162
|
+
*/
|
|
1163
|
+
readonly reviewer: Identity;
|
|
1164
|
+
/**
|
|
1165
|
+
* RFC 3339 UTC. PB-1: the engine MUST refuse to serve an expired bundle. A
|
|
1166
|
+
* deployment MAY configure a grace window during which all Decisions are
|
|
1167
|
+
* capped at ATTEST — it may not configure one that serves the bundle
|
|
1168
|
+
* normally.
|
|
1169
|
+
*
|
|
1170
|
+
* Schema constraints, carried as documentation and NOT enforced by this
|
|
1171
|
+
* type: format `date-time`.
|
|
1172
|
+
*/
|
|
1173
|
+
readonly expiresAt: string;
|
|
1174
|
+
/**
|
|
1175
|
+
* CR-4. The signed floor on signature suites. A receipt or attestation
|
|
1176
|
+
* declaring a weaker suite is refused. This is in the signed bundle
|
|
1177
|
+
* precisely so a downgrade cannot be negotiated at runtime.
|
|
1178
|
+
*
|
|
1179
|
+
* It is NOT this bundle's own floor. It floors the suites of downstream
|
|
1180
|
+
* receipts and attestations; the floor THIS bundle must clear is configured
|
|
1181
|
+
* out of band in the verifier, because a floor a bundle can lower is not a
|
|
1182
|
+
* floor (RES-8). Wiring this field in as the bundle's own floor looks like
|
|
1183
|
+
* an improvement and is the recurring defect.
|
|
1184
|
+
*
|
|
1185
|
+
* Drawn from `signature.schema.json` rather than restated, so that one edit
|
|
1186
|
+
* to the suite list cannot leave the two spellings disagreeing.
|
|
1187
|
+
*/
|
|
1188
|
+
readonly minSuite: SuiteId;
|
|
1189
|
+
readonly custody: Custody;
|
|
1190
|
+
}
|
|
1191
|
+
/**
|
|
1192
|
+
* The lenient projection of Manifest: every field optional, every enum
|
|
1193
|
+
* degraded to `string`. What a verifier parses. Never make a decision on
|
|
1194
|
+
* one — the fail-safe lookups live on the strict type only.
|
|
1195
|
+
*/
|
|
1196
|
+
export interface RawManifest {
|
|
1197
|
+
readonly schemaVersion?: string;
|
|
1198
|
+
readonly tenantId?: string;
|
|
1199
|
+
readonly bundleEpoch?: number;
|
|
1200
|
+
readonly createdAt?: string;
|
|
1201
|
+
readonly author?: RawIdentity;
|
|
1202
|
+
readonly reviewer?: RawIdentity;
|
|
1203
|
+
readonly expiresAt?: string;
|
|
1204
|
+
readonly minSuite?: string;
|
|
1205
|
+
readonly custody?: RawCustody;
|
|
1206
|
+
}
|
|
1207
|
+
/**
|
|
1208
|
+
* Maps each action class to the parties told when an IRREVERSIBLE action of
|
|
1209
|
+
* that class executes BELOW floor-HIGH.
|
|
1210
|
+
*
|
|
1211
|
+
* WHY THIS FILE EXISTS. Risk is recomputed from the target resource's tier
|
|
1212
|
+
* floor; reversibility is a property of the action class. They are
|
|
1213
|
+
* orthogonal, so an action can be IRREVERSIBLE and LOW at the same time —
|
|
1214
|
+
* and every clause governing irreversible actions lived behind DR-1, which
|
|
1215
|
+
* scopes the deferred-release gate to floor-HIGH. Below HIGH the Executor
|
|
1216
|
+
* computed the reversibility class and discarded it: the action executed
|
|
1217
|
+
* with no notification, no acknowledgement, and no record that a human
|
|
1218
|
+
* existed. RV-1's fail-safe default set a value nothing on that path read.
|
|
1219
|
+
* Mail exfiltration is exactly this shape — floor an inbox at T1, which is
|
|
1220
|
+
* the natural choice because reading mail is routine, and an injected
|
|
1221
|
+
* send_email goes out unseen.
|
|
1222
|
+
*
|
|
1223
|
+
* WHY THE RECIPIENTS ARE HERE AND NOT IN THE NOTIFIER'S CONFIGURATION. A
|
|
1224
|
+
* notification service that selects its own audience is certifying its own
|
|
1225
|
+
* coverage. That is RES-8 — a verifier must never accept a derived security
|
|
1226
|
+
* value from the party it is verifying — and it is the exact shape of the
|
|
1227
|
+
* still-open finding T-32, where note.source_path, note.from_canonical and
|
|
1228
|
+
* delivered are all classified T. Naming recipients in the signed bundle
|
|
1229
|
+
* puts the audience under RK-5 two-person offline control alongside the
|
|
1230
|
+
* floors it complements, and makes "who would have found out" a property an
|
|
1231
|
+
* auditor reads off signed policy rather than asks the notifier about.
|
|
1232
|
+
*
|
|
1233
|
+
* ABSENCE FAILS CLOSED, AND JSON SCHEMA CANNOT SAY SO. An action class that
|
|
1234
|
+
* is IRREVERSIBLE, graded below HIGH, and absent from this file MUST cause
|
|
1235
|
+
* the Executor to refuse the action: a notice with no addressee is not a
|
|
1236
|
+
* detection channel, and DR-8's rule — executing while the detection channel
|
|
1237
|
+
* is absent is executing unwatched — does not become false because the risk
|
|
1238
|
+
* grade is lower. The condition spans three files (this one,
|
|
1239
|
+
* reversibility.json, and the risk grading over floors.json), so no schema
|
|
1240
|
+
* keyword can express it. The rule is normative in §9.6 DR-13 and its
|
|
1241
|
+
* enforcement point is the Executor, as with PB-7 in attesters.schema.json.
|
|
1242
|
+
* A normative rule with no enforcement point is a comment.
|
|
1243
|
+
*
|
|
1244
|
+
* WHAT IS NOT REQUIRED: acknowledgement. DR-9's friction is affordable at
|
|
1245
|
+
* floor-HIGH because a human quorum has already been paid for. Below HIGH
|
|
1246
|
+
* there is no quorum and the traffic is the bulk of a deployment, so
|
|
1247
|
+
* demanding acknowledgement would page a human for routine work at volume —
|
|
1248
|
+
* T-26 habituation and AT-7 rubber-stamping, and W2 already recorded that
|
|
1249
|
+
* saturating approvers produces assent rather than refusal. DR-13 buys
|
|
1250
|
+
* detection, not prevention, and is stated as the weaker guarantee it is.
|
|
1251
|
+
*
|
|
1252
|
+
* DELIVERY IS NOT A PRECONDITION OF EXECUTION. EO-2 budgets 25 ms p99
|
|
1253
|
+
* end-to-end for LOW and MEDIUM decisions and a synchronous confirmed
|
|
1254
|
+
* delivery does not fit inside it — two normative requirements that cannot
|
|
1255
|
+
* both hold, which is the DR-6 defect class. What DR-13 requires before
|
|
1256
|
+
* execution is the durable local commit of the notice. A notice committed
|
|
1257
|
+
* and never delivered leaves an audit record and no human; that residual is
|
|
1258
|
+
* disclosed as RES-P6, and reconciling committed notices against delivery
|
|
1259
|
+
* outcomes is a deployment obligation.
|
|
1260
|
+
*
|
|
1261
|
+
* A-7 applies here as it does to floors and to reversibility: that a
|
|
1262
|
+
* deployment named the RIGHT recipients is conceded unprovable. Deployments
|
|
1263
|
+
* SHOULD floor action classes that are both irreversible and externally
|
|
1264
|
+
* visible at T2 or above, which moves them onto the deferred path under
|
|
1265
|
+
* DR-9; this file is what holds when they have not.
|
|
1266
|
+
* Generated from notice_targets.schema.json.
|
|
1267
|
+
*/
|
|
1268
|
+
export interface NoticeTargets {
|
|
1269
|
+
readonly schemaVersion: '1';
|
|
1270
|
+
/**
|
|
1271
|
+
* action class -> recipient identities. Open map (actions are
|
|
1272
|
+
* deployment-specific), and every value is a non-empty set. An empty array
|
|
1273
|
+
* is REFUSED rather than treated as 'notify nobody': the two are
|
|
1274
|
+
* indistinguishable at run time from an entry that was never written, and
|
|
1275
|
+
* the fail-safe reading of both is refusal. Making the empty case invalid
|
|
1276
|
+
* here means a deployment that wants no notice channel for a class must say
|
|
1277
|
+
* so by floor policy — raise the class to T2+ and let DR-9 govern it —
|
|
1278
|
+
* rather than by writing a control that looks configured and does nothing.
|
|
1279
|
+
*
|
|
1280
|
+
* Schema constraints, carried as documentation and NOT enforced by this
|
|
1281
|
+
* type: values minItems 1, uniqueItems; values items minLength 1, maxLength
|
|
1282
|
+
* 128.
|
|
1283
|
+
*/
|
|
1284
|
+
readonly noticeTargets: Readonly<Record<string, readonly string[]>>;
|
|
1285
|
+
}
|
|
1286
|
+
/**
|
|
1287
|
+
* Look up one entry in NoticeTargets.notice_targets.
|
|
1288
|
+
*
|
|
1289
|
+
* DR-13: a notice with no addressee is not a detection channel, and DR-8's
|
|
1290
|
+
* rule — executing while the detection channel is absent is executing
|
|
1291
|
+
* unwatched — does not become false because the risk grade is lower. This is
|
|
1292
|
+
* the one absent-rule of the three that is NOT a default value: there is no
|
|
1293
|
+
* fail-safe recipient to fall back to, so the fail-safe outcome is that the
|
|
1294
|
+
* action does not run. A lookup returning `Option` here would let a caller
|
|
1295
|
+
* write `unwrap_or_default()` and execute unwatched with an empty audience.
|
|
1296
|
+
*
|
|
1297
|
+
* Generated from the schema's `x-acp-absent` rule. It is not restated here.
|
|
1298
|
+
*/
|
|
1299
|
+
export type NoticeTargetsLookup = {
|
|
1300
|
+
readonly present: true;
|
|
1301
|
+
readonly value: readonly string[];
|
|
1302
|
+
} | {
|
|
1303
|
+
readonly present: false;
|
|
1304
|
+
readonly clause: string;
|
|
1305
|
+
readonly why: string;
|
|
1306
|
+
};
|
|
1307
|
+
export declare function noticeTargetsLookup(table: NoticeTargets, key: string): NoticeTargetsLookup;
|
|
1308
|
+
/**
|
|
1309
|
+
* The lenient projection of NoticeTargets: every field optional, every enum
|
|
1310
|
+
* degraded to `string`. What a verifier parses. Never make a decision on
|
|
1311
|
+
* one — the fail-safe lookups live on the strict type only.
|
|
1312
|
+
*/
|
|
1313
|
+
export interface RawNoticeTargets {
|
|
1314
|
+
readonly schemaVersion?: string;
|
|
1315
|
+
readonly noticeTargets?: Readonly<Record<string, readonly string[]>>;
|
|
1316
|
+
}
|
|
1317
|
+
/**
|
|
1318
|
+
* `RaiseClause`.
|
|
1319
|
+
* Generated from risk_functions.schema.json#/$defs/raise_clause.
|
|
1320
|
+
*/
|
|
1321
|
+
export interface RaiseClause {
|
|
1322
|
+
/**
|
|
1323
|
+
* An EL-1 expression. EL-1 is deliberately minimal, TOTAL (no expression can
|
|
1324
|
+
* fail to evaluate, so there is no error path to fall open through) and
|
|
1325
|
+
* monotone.
|
|
1326
|
+
*
|
|
1327
|
+
* PRECEDENCE IS NORMATIVE: `&&` binds tighter than `||`. That sentence
|
|
1328
|
+
* exists because its absence WAS a defect — Z1, found by building two
|
|
1329
|
+
* evaluators from the prose alone and running 10,000 differential cases
|
|
1330
|
+
* until they disagreed. An implementation that leaves precedence to its host
|
|
1331
|
+
* language reproduces the ambiguity.
|
|
1332
|
+
*
|
|
1333
|
+
* Schema constraints, carried as documentation and NOT enforced by this
|
|
1334
|
+
* type: minLength 1, maxLength 1024.
|
|
1335
|
+
*/
|
|
1336
|
+
readonly if: string;
|
|
1337
|
+
readonly then: Risk;
|
|
1338
|
+
}
|
|
1339
|
+
/**
|
|
1340
|
+
* The lenient projection of RaiseClause: every field optional, every enum
|
|
1341
|
+
* degraded to `string`. What a verifier parses. Never make a decision on
|
|
1342
|
+
* one — the fail-safe lookups live on the strict type only.
|
|
1343
|
+
*/
|
|
1344
|
+
export interface RawRaiseClause {
|
|
1345
|
+
readonly if?: string;
|
|
1346
|
+
readonly then?: string;
|
|
1347
|
+
}
|
|
1348
|
+
/**
|
|
1349
|
+
* The tenant's receipt verification keys -- the public half of the
|
|
1350
|
+
* `receipt_signing_key` the KMS holds (§4, EX-4) -- one per primitive of the
|
|
1351
|
+
* bundle's suite, named by the signed bundle. PB-12 (v1.3.27).
|
|
1352
|
+
*
|
|
1353
|
+
* WHY THIS FILE EXISTS. §9.3 step 1 has read, since v1.3.0, `Signature valid
|
|
1354
|
+
* under the current receipt_signing_key (public key from the signed
|
|
1355
|
+
* bundle)`, and §8.2's tree named no member that could carry it. Every
|
|
1356
|
+
* implementation therefore took the key from somewhere else: the Python
|
|
1357
|
+
* reference held it as a field of its modelled bundle (and hashed it there,
|
|
1358
|
+
* so `policy_bundle_hash` covered a value the on-disk tree did not), the
|
|
1359
|
+
* Rust differential passed it in beside the bundle, and the first Executor
|
|
1360
|
+
* process (M7) would have read it from its own configuration -- a verifier
|
|
1361
|
+
* trusting its deployment's description of the party it verifies, which is
|
|
1362
|
+
* the T-32 shape one level below the bundle. This file is the member step
|
|
1363
|
+
* 1's words had always assumed, and the on-disk tree now covers what the
|
|
1364
|
+
* reference's hash already did.
|
|
1365
|
+
*
|
|
1366
|
+
* WHY THE MECHANISM IS THE DOORS' AND THE REGISTRY'S. Who signs receipts is
|
|
1367
|
+
* the same kind of value as who may attest (PB-6, PB-7) and who speaks for a
|
|
1368
|
+
* door (PB-11): an identity a runtime component supplied about itself would
|
|
1369
|
+
* be RES-8. So it sits in signed policy under RK-5 two-person control, in
|
|
1370
|
+
* the attester registry's key shape -- one Ed25519 and one ML-DSA-65
|
|
1371
|
+
* verification key, the same named scalars -- and both legs are REQUIRED
|
|
1372
|
+
* because CR-3 is conjunctive: a receipt key registered with one leg is a
|
|
1373
|
+
* key under which no receipt can ever verify.
|
|
1374
|
+
*
|
|
1375
|
+
* WHAT THE LOADER CHECKS, AND WHAT IT DELIBERATELY DOES NOT. Present, both
|
|
1376
|
+
* legs at their declared lengths, and the classical leg not a small-order
|
|
1377
|
+
* point (PB-9's rule, the same predicate the registry and the doors are held
|
|
1378
|
+
* to) -- else the bundle is refused at load by every consumer, on PB-1's
|
|
1379
|
+
* footing, under one name (`ReceiptIdentityAbsent` for a member that is
|
|
1380
|
+
* missing, one leg short or not a key). NO distinctness bar against the
|
|
1381
|
+
* attester registry or the two doors, and that is a decision rather than an
|
|
1382
|
+
* omission: at any k >= 2 a KMS that also held one attester key still needs
|
|
1383
|
+
* a second approver, so INV-1-HIGH is not broken by that component alone and
|
|
1384
|
+
* the bar would remove no compromise while dressing an arbitrary rule as a
|
|
1385
|
+
* control -- the reference has recorded that reasoning beside its door check
|
|
1386
|
+
* since PB-11 landed, and it applies unchanged here. EX-4's rule that no
|
|
1387
|
+
* component HOLDS private keys from more than one class is custody, enforced
|
|
1388
|
+
* at the KMS and not by comparing public keys in a file.
|
|
1389
|
+
*
|
|
1390
|
+
* WHAT THE KMS DOES WITH IT. §9.1.1 step 4: the KMS compares the identity it
|
|
1391
|
+
* holds for the tenant against this member of the bundle it independently
|
|
1392
|
+
* verified, and answers `SIGNING_DENIED` on a mismatch -- RAD-5's shape (the
|
|
1393
|
+
* bundle and the signer agree, and the bundle is the byte the ceremony
|
|
1394
|
+
* covered) applied to the key rather than to the tenant. A bundle that names
|
|
1395
|
+
* a key the KMS does not hold is a bundle under which nothing will ever be
|
|
1396
|
+
* signed, and refusing at the signer says so where an operator can read it
|
|
1397
|
+
* instead of at the Executor's step 1 at 03:00.
|
|
1398
|
+
*
|
|
1399
|
+
* WHAT IS DELIBERATELY NOT HERE. Custody metadata: the tier the key is held
|
|
1400
|
+
* at is the manifest's `custody` (§4) and belongs beside the epoch, not
|
|
1401
|
+
* beside the key. Rotation: a new receipt identity is a new bundle epoch
|
|
1402
|
+
* (PB-5), which is what makes the old key's receipts refuse at step 4 before
|
|
1403
|
+
* they can fail at step 1.
|
|
1404
|
+
* Generated from receipt_identity.schema.json.
|
|
1405
|
+
*/
|
|
1406
|
+
export interface ReceiptIdentity {
|
|
1407
|
+
readonly schemaVersion: '1';
|
|
1408
|
+
/**
|
|
1409
|
+
* The identity's name, for the audit record and the alert -- a label for the
|
|
1410
|
+
* keys beside it, never what the Executor resolves a signature by (ACK-4's
|
|
1411
|
+
* rule, as for the doors).
|
|
1412
|
+
*
|
|
1413
|
+
* Schema constraints, carried as documentation and NOT enforced by this
|
|
1414
|
+
* type: minLength 1, maxLength 128.
|
|
1415
|
+
*/
|
|
1416
|
+
readonly name: string;
|
|
1417
|
+
/**
|
|
1418
|
+
* The Ed25519 verification key. The attester registry's named scalar,
|
|
1419
|
+
* referenced rather than re-declared: one definition of a key encoding. Held
|
|
1420
|
+
* to PB-9 at load: a small-order point here is a key under which one
|
|
1421
|
+
* signature verifies every message.
|
|
1422
|
+
*/
|
|
1423
|
+
readonly classical: Ed25519PublicKey;
|
|
1424
|
+
/**
|
|
1425
|
+
* The ML-DSA-65 verification key. Required because CR-3 is conjunctive and
|
|
1426
|
+
* the bundle's suite names both primitives; a receipt verifies only when
|
|
1427
|
+
* every leg does.
|
|
1428
|
+
*/
|
|
1429
|
+
readonly pq: MlDsa65PublicKey;
|
|
1430
|
+
}
|
|
1431
|
+
/**
|
|
1432
|
+
* The lenient projection of ReceiptIdentity: every field optional, every enum
|
|
1433
|
+
* degraded to `string`. What a verifier parses. Never make a decision on
|
|
1434
|
+
* one — the fail-safe lookups live on the strict type only.
|
|
1435
|
+
*/
|
|
1436
|
+
export interface RawReceiptIdentity {
|
|
1437
|
+
readonly schemaVersion?: string;
|
|
1438
|
+
readonly name?: string;
|
|
1439
|
+
readonly classical?: string;
|
|
1440
|
+
readonly pq?: string;
|
|
1441
|
+
}
|
|
1442
|
+
/**
|
|
1443
|
+
* Maps each action class to whether it can be undone.
|
|
1444
|
+
*
|
|
1445
|
+
* RV-1: an action ABSENT from this file MUST be treated as IRREVERSIBLE. As
|
|
1446
|
+
* with floors, JSON Schema cannot express absence, so the rule is carried by
|
|
1447
|
+
* the `x-acp-absent` annotation below and GENERATED into the type: `impl
|
|
1448
|
+
* Default for Reversibility` returns `Irreversible` in crates/acp-core, and
|
|
1449
|
+
* the lookup on the table returns it directly, so a struct update, a
|
|
1450
|
+
* deserialisation gap, or an `Option` a caller unwraps cannot silently
|
|
1451
|
+
* produce the permissive value.
|
|
1452
|
+
*
|
|
1453
|
+
* Why this matters more than it looks: reversibility selects the
|
|
1454
|
+
* acknowledgement regime. IRREVERSIBLE at floor-HIGH demands positive
|
|
1455
|
+
* acknowledgement from a non-operator (DR-9) — silence is not consent.
|
|
1456
|
+
* Getting this entry wrong in the permissive direction converts a held
|
|
1457
|
+
* action into a released one.
|
|
1458
|
+
*
|
|
1459
|
+
* RV-3 is the reason the value is recomputed here and never read from a
|
|
1460
|
+
* receipt: a compromised issuer claiming REVERSIBLE otherwise obtains Silent
|
|
1461
|
+
* mode. Proven in reference/proofs/binding.dfy as
|
|
1462
|
+
* `RV3_TrustedModeAcceptsDowngrade`.
|
|
1463
|
+
*
|
|
1464
|
+
* A-7 applies here exactly as it does to floors: that a classification is
|
|
1465
|
+
* HONEST is conceded unprovable.
|
|
1466
|
+
* Generated from reversibility.schema.json.
|
|
1467
|
+
*/
|
|
1468
|
+
export interface ReversibilityTable {
|
|
1469
|
+
readonly schemaVersion: '1';
|
|
1470
|
+
/**
|
|
1471
|
+
* action class -> reversibility. Open map (actions are deployment-specific),
|
|
1472
|
+
* closed values.
|
|
1473
|
+
*/
|
|
1474
|
+
readonly reversibility: Readonly<Record<string, Reversibility>>;
|
|
1475
|
+
}
|
|
1476
|
+
/**
|
|
1477
|
+
* Look up one entry in ReversibilityTable.reversibility.
|
|
1478
|
+
*
|
|
1479
|
+
* RV-1: reversibility selects the acknowledgement regime, so the permissive
|
|
1480
|
+
* default converts a held action into a released one. An action nobody
|
|
1481
|
+
* classified is one nobody thought about, and the fail-safe reading of that
|
|
1482
|
+
* is that it cannot be undone.
|
|
1483
|
+
*
|
|
1484
|
+
* Generated from the schema's `x-acp-absent` rule. It is not restated here.
|
|
1485
|
+
*/
|
|
1486
|
+
export declare function reversibilityTableLookup(table: ReversibilityTable, key: string): Reversibility;
|
|
1487
|
+
/**
|
|
1488
|
+
* The lenient projection of ReversibilityTable: every field optional, every enum
|
|
1489
|
+
* degraded to `string`. What a verifier parses. Never make a decision on
|
|
1490
|
+
* one — the fail-safe lookups live on the strict type only.
|
|
1491
|
+
*/
|
|
1492
|
+
export interface RawReversibilityTable {
|
|
1493
|
+
readonly schemaVersion?: string;
|
|
1494
|
+
readonly reversibility?: Readonly<Record<string, string>>;
|
|
1495
|
+
}
|
|
1496
|
+
/**
|
|
1497
|
+
* `RiskFunction`.
|
|
1498
|
+
* Generated from risk_functions.schema.json#/$defs/risk_function.
|
|
1499
|
+
*/
|
|
1500
|
+
export interface RiskFunction {
|
|
1501
|
+
/**
|
|
1502
|
+
* Action class this function grades. At most one function per action class —
|
|
1503
|
+
* two functions for one class is an ambiguity, not a merge, and the loader
|
|
1504
|
+
* refuses it.
|
|
1505
|
+
*
|
|
1506
|
+
* Schema constraints, carried as documentation and NOT enforced by this
|
|
1507
|
+
* type: minLength 1, maxLength 128.
|
|
1508
|
+
*/
|
|
1509
|
+
readonly appliesTo: string;
|
|
1510
|
+
readonly base: Risk;
|
|
1511
|
+
/**
|
|
1512
|
+
* Clauses evaluated in order. MONOTONE BY CONSTRUCTION: a clause can only
|
|
1513
|
+
* raise the level, never lower it, which is why the field is `raise_to` and
|
|
1514
|
+
* there is no `lower_to`. Monotonicity is what makes the Dafny proof that
|
|
1515
|
+
* floors dominate raises tractable — a lowering clause would let a crafted
|
|
1516
|
+
* parameter walk a HIGH action down to LOW.
|
|
1517
|
+
*/
|
|
1518
|
+
readonly raiseTo: readonly RaiseClause[];
|
|
1519
|
+
}
|
|
1520
|
+
/**
|
|
1521
|
+
* The lenient projection of RiskFunction: every field optional, every enum
|
|
1522
|
+
* degraded to `string`. What a verifier parses. Never make a decision on
|
|
1523
|
+
* one — the fail-safe lookups live on the strict type only.
|
|
1524
|
+
*/
|
|
1525
|
+
export interface RawRiskFunction {
|
|
1526
|
+
readonly appliesTo?: string;
|
|
1527
|
+
readonly base?: string;
|
|
1528
|
+
readonly raiseTo?: readonly RawRaiseClause[];
|
|
1529
|
+
}
|
|
1530
|
+
/**
|
|
1531
|
+
* Deterministic functions from a Proposal's parameters and its targets'
|
|
1532
|
+
* effective tiers to a risk level.
|
|
1533
|
+
*
|
|
1534
|
+
* RK-2 exists because static per-action risk is insufficient:
|
|
1535
|
+
* `modify_firewall_rule = HIGH` says nothing useful, since risk is a
|
|
1536
|
+
* function of PARAMETERS and TARGETS, not action names.
|
|
1537
|
+
*
|
|
1538
|
+
* THE ABSENT CASE DIFFERS FROM floors AND reversibility. An action with no
|
|
1539
|
+
* risk function is REFUSED at §8.4 step 3 — it is NOT graded HIGH. Refusing
|
|
1540
|
+
* and grading-HIGH are different behaviours: grading HIGH would route an
|
|
1541
|
+
* unknown action into the human quorum, which looks conservative but
|
|
1542
|
+
* silently teaches approvers to rubber-stamp things the policy author never
|
|
1543
|
+
* considered. P-4: unknown is never LOW, and here it is not HIGH either — it
|
|
1544
|
+
* is a refusal.
|
|
1545
|
+
*
|
|
1546
|
+
* TR-8: these functions are evaluated by the Executor over the INDEPENDENTLY
|
|
1547
|
+
* RECEIVED canonical Proposal and the trusted bundle, ignoring every
|
|
1548
|
+
* Context-Store raise and ignoring any risk value asserted in the receipt.
|
|
1549
|
+
* The recomputed value is what all subsequent attestation requirements key
|
|
1550
|
+
* on.
|
|
1551
|
+
* Generated from risk_functions.schema.json.
|
|
1552
|
+
*/
|
|
1553
|
+
export interface RiskFunctions {
|
|
1554
|
+
readonly schemaVersion: '1';
|
|
1555
|
+
readonly riskFunctions: readonly RiskFunction[];
|
|
1556
|
+
}
|
|
1557
|
+
/**
|
|
1558
|
+
* Look up one entry in RiskFunctions.risk_functions.
|
|
1559
|
+
*
|
|
1560
|
+
* 8.4-3: THE ABSENT CASE HERE IS NOT THE ABSENT CASE IN floors OR
|
|
1561
|
+
* reversibility. An action with no risk function is REFUSED, not graded
|
|
1562
|
+
* HIGH. Grading HIGH would route an unknown action into the human quorum,
|
|
1563
|
+
* which looks conservative and is worse: it teaches approvers to
|
|
1564
|
+
* rubber-stamp things the policy author never considered (T-26 habituation,
|
|
1565
|
+
* AT-7). P-4 says unknown is never LOW; here it is not HIGH either. A lookup
|
|
1566
|
+
* returning `Option` would let a caller reach for HIGH as the obvious safe
|
|
1567
|
+
* default and get this exactly wrong.
|
|
1568
|
+
*
|
|
1569
|
+
* Generated from the schema's `x-acp-absent` rule. It is not restated here.
|
|
1570
|
+
*/
|
|
1571
|
+
export type RiskFunctionsLookup = {
|
|
1572
|
+
readonly present: true;
|
|
1573
|
+
readonly value: RiskFunction;
|
|
1574
|
+
} | {
|
|
1575
|
+
readonly present: false;
|
|
1576
|
+
readonly clause: string;
|
|
1577
|
+
readonly why: string;
|
|
1578
|
+
};
|
|
1579
|
+
export declare function riskFunctionsLookup(table: RiskFunctions, key: string): RiskFunctionsLookup;
|
|
1580
|
+
/**
|
|
1581
|
+
* The lenient projection of RiskFunctions: every field optional, every enum
|
|
1582
|
+
* degraded to `string`. What a verifier parses. Never make a decision on
|
|
1583
|
+
* one — the fail-safe lookups live on the strict type only.
|
|
1584
|
+
*/
|
|
1585
|
+
export interface RawRiskFunctions {
|
|
1586
|
+
readonly schemaVersion?: string;
|
|
1587
|
+
readonly riskFunctions?: readonly RawRiskFunction[];
|
|
1588
|
+
}
|
|
1589
|
+
/**
|
|
1590
|
+
* The `SIGNATURE` file at the bundle root: the declared suite, and one
|
|
1591
|
+
* signature value per primitive that suite requires, over SHA-256 of the
|
|
1592
|
+
* canonical bundle tree.
|
|
1593
|
+
*
|
|
1594
|
+
* A CORRECTION IS RECORDED HERE. Until this revision this file was named
|
|
1595
|
+
* `bundle.schema.json` and described a *tree index* — `schema_version`, a
|
|
1596
|
+
* `members` array of path+digest pairs, and a `signature` object carrying
|
|
1597
|
+
* two fixed base64 fields named `classical` and `pq`. None of that artifact
|
|
1598
|
+
* exists. §8.2's file listing contains no index file; the covered set is
|
|
1599
|
+
* established by the CANONICAL WALK (`walk_bundle`, in both
|
|
1600
|
+
* implementations), which is what makes "the tree" a fact rather than a
|
|
1601
|
+
* convention. And PB-8, added in v1.3.15 when the offline signer turned the
|
|
1602
|
+
* format from a diagram into bytes, specifies the file as a suite plus ONE
|
|
1603
|
+
* VALUE PER PRIMITIVE — a map keyed by primitive name, hex-encoded — which
|
|
1604
|
+
* is not the fixed pair the old schema declared.
|
|
1605
|
+
*
|
|
1606
|
+
* So the normative source held two descriptions of one object, and they
|
|
1607
|
+
* disagreed: the encoding-split defect arriving inside the document that
|
|
1608
|
+
* exists to prevent it. It survived because NOTHING READ THE SCHEMAS. They
|
|
1609
|
+
* were normative and unexecuted, and the first consumer — `tools/codegen.sh`
|
|
1610
|
+
* — found this on its first run. That is the same shape as `sim/bundle.py`
|
|
1611
|
+
* silently dropping three fields from a hash for several releases: a
|
|
1612
|
+
* load-bearing artifact with no gate line.
|
|
1613
|
+
*
|
|
1614
|
+
* WHY THE MEMBERS INDEX IS NOT COMING BACK. The old rationale was real —
|
|
1615
|
+
* without an explicit list, a verifier that skipped a file and a signer that
|
|
1616
|
+
* included it compute different hashes and neither can tell which is wrong.
|
|
1617
|
+
* The adopted answer is to make the WALK normative rather than to ship a
|
|
1618
|
+
* list: it refuses symlinks, refuses unrecognised file types, and orders
|
|
1619
|
+
* byte-wise, so two conformant implementations enumerate the same set. A
|
|
1620
|
+
* committed index would be a second statement of the same fact, and this
|
|
1621
|
+
* file exists because of what happens to the second statement.
|
|
1622
|
+
* Generated from signature.schema.json.
|
|
1623
|
+
*/
|
|
1624
|
+
export interface SignatureEnvelope {
|
|
1625
|
+
/**
|
|
1626
|
+
* The suite this signature was produced under. PB-8: it MUST be inside the
|
|
1627
|
+
* tree hash. Outside it, an attacker relabels a hybrid bundle as classical,
|
|
1628
|
+
* the verifier obligingly requires one primitive, and the CR-3 downgrade
|
|
1629
|
+
* costs nothing.
|
|
1630
|
+
*/
|
|
1631
|
+
readonly suite: SuiteId;
|
|
1632
|
+
/**
|
|
1633
|
+
* primitive name -> signature value, lowercase hex.
|
|
1634
|
+
*
|
|
1635
|
+
* CR-3, CONJUNCTIVE: the values present MUST be exactly those the declared
|
|
1636
|
+
* suite requires, and every one of them MUST verify. Not "at least": a value
|
|
1637
|
+
* for a primitive the suite does not declare is as much a refusal as a
|
|
1638
|
+
* missing one, because an `any`-shaped check lets an attacker strip the
|
|
1639
|
+
* post-quantum leg, present a genuine classical signature, and be accepted.
|
|
1640
|
+
*
|
|
1641
|
+
* Hex rather than base64, matching what both implementations write.
|
|
1642
|
+
* Per-primitive lengths (Ed25519 64 bytes, ML-DSA-65 3309) are asserted in
|
|
1643
|
+
* code and not here: `parts` is keyed by primitive, so no single value
|
|
1644
|
+
* pattern can express a length that depends on its own key.
|
|
1645
|
+
*
|
|
1646
|
+
* Schema constraints, carried as documentation and NOT enforced by this
|
|
1647
|
+
* type: values pattern `^[0-9a-f]+$`.
|
|
1648
|
+
*/
|
|
1649
|
+
readonly parts: Readonly<Record<string, string>>;
|
|
1650
|
+
}
|
|
1651
|
+
/**
|
|
1652
|
+
* Look up one entry in SignatureEnvelope.parts.
|
|
1653
|
+
*
|
|
1654
|
+
* CR-3, PB-8: a primitive the declared suite requires and this file does not
|
|
1655
|
+
* carry is a stripped leg, and a stripped leg is the downgrade the hybrid
|
|
1656
|
+
* suite exists to prevent. Absent is refused, never treated as 'not
|
|
1657
|
+
* applicable'.
|
|
1658
|
+
*
|
|
1659
|
+
* Generated from the schema's `x-acp-absent` rule. It is not restated here.
|
|
1660
|
+
*/
|
|
1661
|
+
export type SignatureEnvelopeLookup = {
|
|
1662
|
+
readonly present: true;
|
|
1663
|
+
readonly value: string;
|
|
1664
|
+
} | {
|
|
1665
|
+
readonly present: false;
|
|
1666
|
+
readonly clause: string;
|
|
1667
|
+
readonly why: string;
|
|
1668
|
+
};
|
|
1669
|
+
export declare function signatureEnvelopeLookup(table: SignatureEnvelope, key: string): SignatureEnvelopeLookup;
|
|
1670
|
+
/**
|
|
1671
|
+
* The lenient projection of SignatureEnvelope: every field optional, every enum
|
|
1672
|
+
* degraded to `string`. What a verifier parses. Never make a decision on
|
|
1673
|
+
* one — the fail-safe lookups live on the strict type only.
|
|
1674
|
+
*/
|
|
1675
|
+
export interface RawSignatureEnvelope {
|
|
1676
|
+
readonly suite?: string;
|
|
1677
|
+
readonly parts?: Readonly<Record<string, string>>;
|
|
1678
|
+
}
|
|
1679
|
+
/**
|
|
1680
|
+
* One registry entry: a machine (`kind: hybrid`) or a human (`kind:
|
|
1681
|
+
* webauthn`). A TAGGED union, deliberately: the generator refuses an
|
|
1682
|
+
* untagged `oneOf` because 'first branch that parses' is how a document
|
|
1683
|
+
* meant as one thing is read as another, and a key kind guessed from which
|
|
1684
|
+
* fields are present is exactly that guess. Every entry carries `kind`; one
|
|
1685
|
+
* without it is `Malformed` at load (HM-1).
|
|
1686
|
+
* Generated from attesters.schema.json#/$defs/attester.
|
|
1687
|
+
*
|
|
1688
|
+
* A DISCRIMINATED union over `kind`, which every branch pins to a literal.
|
|
1689
|
+
* Narrow it by switching on that field; a `default` arm that accepts an
|
|
1690
|
+
* unrecognised value is a branch this union does not have, and the fail-safe
|
|
1691
|
+
* answer there is to refuse. There is no `Raw` union: with every field
|
|
1692
|
+
* optional each branch would accept every other document and the tag would
|
|
1693
|
+
* decide nothing.
|
|
1694
|
+
*/
|
|
1695
|
+
export type Attester = MachineAttester | HumanAttester;
|
|
1696
|
+
//# sourceMappingURL=generated.d.ts.map
|