agent-passport-system 7.1.0 → 7.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/dist/src/core/tool-integrity.d.ts +13 -0
  2. package/dist/src/core/tool-integrity.d.ts.map +1 -1
  3. package/dist/src/core/tool-integrity.js +1 -1
  4. package/dist/src/core/tool-integrity.js.map +1 -1
  5. package/dist/src/index.d.ts +28 -0
  6. package/dist/src/index.d.ts.map +1 -1
  7. package/dist/src/index.js +242 -0
  8. package/dist/src/index.js.map +1 -1
  9. package/dist/src/v2/activation/canonical.d.ts +40 -0
  10. package/dist/src/v2/activation/canonical.d.ts.map +1 -0
  11. package/dist/src/v2/activation/canonical.js +64 -0
  12. package/dist/src/v2/activation/canonical.js.map +1 -0
  13. package/dist/src/v2/activation/index.d.ts +4 -0
  14. package/dist/src/v2/activation/index.d.ts.map +1 -0
  15. package/dist/src/v2/activation/index.js +11 -0
  16. package/dist/src/v2/activation/index.js.map +1 -0
  17. package/dist/src/v2/activation/types.d.ts +268 -0
  18. package/dist/src/v2/activation/types.d.ts.map +1 -0
  19. package/dist/src/v2/activation/types.js +198 -0
  20. package/dist/src/v2/activation/types.js.map +1 -0
  21. package/dist/src/v2/activation/verify.d.ts +132 -0
  22. package/dist/src/v2/activation/verify.d.ts.map +1 -0
  23. package/dist/src/v2/activation/verify.js +406 -0
  24. package/dist/src/v2/activation/verify.js.map +1 -0
  25. package/dist/src/v2/authority-state/fencing.d.ts +49 -0
  26. package/dist/src/v2/authority-state/fencing.d.ts.map +1 -0
  27. package/dist/src/v2/authority-state/fencing.js +92 -0
  28. package/dist/src/v2/authority-state/fencing.js.map +1 -0
  29. package/dist/src/v2/authority-state/index.d.ts +7 -0
  30. package/dist/src/v2/authority-state/index.d.ts.map +1 -0
  31. package/dist/src/v2/authority-state/index.js +14 -0
  32. package/dist/src/v2/authority-state/index.js.map +1 -0
  33. package/dist/src/v2/authority-state/marker.d.ts +70 -0
  34. package/dist/src/v2/authority-state/marker.d.ts.map +1 -0
  35. package/dist/src/v2/authority-state/marker.js +122 -0
  36. package/dist/src/v2/authority-state/marker.js.map +1 -0
  37. package/dist/src/v2/authority-state/report.d.ts +55 -0
  38. package/dist/src/v2/authority-state/report.d.ts.map +1 -0
  39. package/dist/src/v2/authority-state/report.js +51 -0
  40. package/dist/src/v2/authority-state/report.js.map +1 -0
  41. package/dist/src/v2/authority-state/retained.d.ts +82 -0
  42. package/dist/src/v2/authority-state/retained.d.ts.map +1 -0
  43. package/dist/src/v2/authority-state/retained.js +93 -0
  44. package/dist/src/v2/authority-state/retained.js.map +1 -0
  45. package/dist/src/v2/authority-state/types.d.ts +198 -0
  46. package/dist/src/v2/authority-state/types.d.ts.map +1 -0
  47. package/dist/src/v2/authority-state/types.js +103 -0
  48. package/dist/src/v2/authority-state/types.js.map +1 -0
  49. package/dist/src/v2/authority-state/withdrawal.d.ts +80 -0
  50. package/dist/src/v2/authority-state/withdrawal.d.ts.map +1 -0
  51. package/dist/src/v2/authority-state/withdrawal.js +199 -0
  52. package/dist/src/v2/authority-state/withdrawal.js.map +1 -0
  53. package/dist/src/v2/bounds/canonical.d.ts +30 -0
  54. package/dist/src/v2/bounds/canonical.d.ts.map +1 -0
  55. package/dist/src/v2/bounds/canonical.js +69 -0
  56. package/dist/src/v2/bounds/canonical.js.map +1 -0
  57. package/dist/src/v2/bounds/evaluate.d.ts +107 -0
  58. package/dist/src/v2/bounds/evaluate.d.ts.map +1 -0
  59. package/dist/src/v2/bounds/evaluate.js +315 -0
  60. package/dist/src/v2/bounds/evaluate.js.map +1 -0
  61. package/dist/src/v2/bounds/index.d.ts +6 -0
  62. package/dist/src/v2/bounds/index.d.ts.map +1 -0
  63. package/dist/src/v2/bounds/index.js +13 -0
  64. package/dist/src/v2/bounds/index.js.map +1 -0
  65. package/dist/src/v2/bounds/purpose.d.ts +2 -0
  66. package/dist/src/v2/bounds/purpose.d.ts.map +1 -0
  67. package/dist/src/v2/bounds/purpose.js +23 -0
  68. package/dist/src/v2/bounds/purpose.js.map +1 -0
  69. package/dist/src/v2/bounds/record.d.ts +78 -0
  70. package/dist/src/v2/bounds/record.d.ts.map +1 -0
  71. package/dist/src/v2/bounds/record.js +170 -0
  72. package/dist/src/v2/bounds/record.js.map +1 -0
  73. package/dist/src/v2/bounds/types.d.ts +275 -0
  74. package/dist/src/v2/bounds/types.d.ts.map +1 -0
  75. package/dist/src/v2/bounds/types.js +124 -0
  76. package/dist/src/v2/bounds/types.js.map +1 -0
  77. package/dist/src/v2/capability-binding/binding.d.ts +67 -0
  78. package/dist/src/v2/capability-binding/binding.d.ts.map +1 -0
  79. package/dist/src/v2/capability-binding/binding.js +267 -0
  80. package/dist/src/v2/capability-binding/binding.js.map +1 -0
  81. package/dist/src/v2/capability-binding/digest.d.ts +33 -0
  82. package/dist/src/v2/capability-binding/digest.d.ts.map +1 -0
  83. package/dist/src/v2/capability-binding/digest.js +55 -0
  84. package/dist/src/v2/capability-binding/digest.js.map +1 -0
  85. package/dist/src/v2/capability-binding/identifier.d.ts +103 -0
  86. package/dist/src/v2/capability-binding/identifier.d.ts.map +1 -0
  87. package/dist/src/v2/capability-binding/identifier.js +281 -0
  88. package/dist/src/v2/capability-binding/identifier.js.map +1 -0
  89. package/dist/src/v2/capability-binding/index.d.ts +6 -0
  90. package/dist/src/v2/capability-binding/index.d.ts.map +1 -0
  91. package/dist/src/v2/capability-binding/index.js +13 -0
  92. package/dist/src/v2/capability-binding/index.js.map +1 -0
  93. package/dist/src/v2/capability-binding/pins.d.ts +30 -0
  94. package/dist/src/v2/capability-binding/pins.d.ts.map +1 -0
  95. package/dist/src/v2/capability-binding/pins.js +109 -0
  96. package/dist/src/v2/capability-binding/pins.js.map +1 -0
  97. package/dist/src/v2/capability-binding/types.d.ts +213 -0
  98. package/dist/src/v2/capability-binding/types.d.ts.map +1 -0
  99. package/dist/src/v2/capability-binding/types.js +150 -0
  100. package/dist/src/v2/capability-binding/types.js.map +1 -0
  101. package/dist/src/v2/chain-selection/index.d.ts +4 -0
  102. package/dist/src/v2/chain-selection/index.d.ts.map +1 -0
  103. package/dist/src/v2/chain-selection/index.js +11 -0
  104. package/dist/src/v2/chain-selection/index.js.map +1 -0
  105. package/dist/src/v2/chain-selection/select.d.ts +62 -0
  106. package/dist/src/v2/chain-selection/select.d.ts.map +1 -0
  107. package/dist/src/v2/chain-selection/select.js +390 -0
  108. package/dist/src/v2/chain-selection/select.js.map +1 -0
  109. package/dist/src/v2/chain-selection/types.d.ts +189 -0
  110. package/dist/src/v2/chain-selection/types.d.ts.map +1 -0
  111. package/dist/src/v2/chain-selection/types.js +81 -0
  112. package/dist/src/v2/chain-selection/types.js.map +1 -0
  113. package/dist/src/v2/lifecycle-state/index.d.ts +4 -0
  114. package/dist/src/v2/lifecycle-state/index.d.ts.map +1 -0
  115. package/dist/src/v2/lifecycle-state/index.js +10 -0
  116. package/dist/src/v2/lifecycle-state/index.js.map +1 -0
  117. package/dist/src/v2/lifecycle-state/map.d.ts +52 -0
  118. package/dist/src/v2/lifecycle-state/map.d.ts.map +1 -0
  119. package/dist/src/v2/lifecycle-state/map.js +122 -0
  120. package/dist/src/v2/lifecycle-state/map.js.map +1 -0
  121. package/dist/src/v2/lifecycle-state/state.d.ts +60 -0
  122. package/dist/src/v2/lifecycle-state/state.d.ts.map +1 -0
  123. package/dist/src/v2/lifecycle-state/state.js +157 -0
  124. package/dist/src/v2/lifecycle-state/state.js.map +1 -0
  125. package/dist/src/v2/lifecycle-state/types.d.ts +163 -0
  126. package/dist/src/v2/lifecycle-state/types.d.ts.map +1 -0
  127. package/dist/src/v2/lifecycle-state/types.js +121 -0
  128. package/dist/src/v2/lifecycle-state/types.js.map +1 -0
  129. package/dist/src/v2/status-coverage/decide.d.ts +52 -0
  130. package/dist/src/v2/status-coverage/decide.d.ts.map +1 -0
  131. package/dist/src/v2/status-coverage/decide.js +398 -0
  132. package/dist/src/v2/status-coverage/decide.js.map +1 -0
  133. package/dist/src/v2/status-coverage/index.d.ts +3 -0
  134. package/dist/src/v2/status-coverage/index.d.ts.map +1 -0
  135. package/dist/src/v2/status-coverage/index.js +10 -0
  136. package/dist/src/v2/status-coverage/index.js.map +1 -0
  137. package/dist/src/v2/status-coverage/types.d.ts +258 -0
  138. package/dist/src/v2/status-coverage/types.d.ts.map +1 -0
  139. package/dist/src/v2/status-coverage/types.js +127 -0
  140. package/dist/src/v2/status-coverage/types.js.map +1 -0
  141. package/dist/src/v2/suspension/evaluate.d.ts +88 -0
  142. package/dist/src/v2/suspension/evaluate.d.ts.map +1 -0
  143. package/dist/src/v2/suspension/evaluate.js +404 -0
  144. package/dist/src/v2/suspension/evaluate.js.map +1 -0
  145. package/dist/src/v2/suspension/index.d.ts +3 -0
  146. package/dist/src/v2/suspension/index.d.ts.map +1 -0
  147. package/dist/src/v2/suspension/index.js +10 -0
  148. package/dist/src/v2/suspension/index.js.map +1 -0
  149. package/dist/src/v2/suspension/types.d.ts +243 -0
  150. package/dist/src/v2/suspension/types.d.ts.map +1 -0
  151. package/dist/src/v2/suspension/types.js +135 -0
  152. package/dist/src/v2/suspension/types.js.map +1 -0
  153. package/package.json +3 -3
@@ -0,0 +1,78 @@
1
+ import { type AuthorityBoundFulfilment, type AuthorityExhaustion, type BoundEvaluation } from './types.js';
2
+ export interface IssueFulfilmentInput {
3
+ readonly bound_id: string;
4
+ readonly delegation_id: string;
5
+ readonly attestor: string;
6
+ readonly verification_method: string;
7
+ /** Canonical UTC-millisecond time, supplied by the caller. Issuance never reads a clock,
8
+ * so the same inputs produce the same bytes on every run, which is what makes the
9
+ * signature reproducible in a test and in a conformance vector. */
10
+ readonly attested_at: string;
11
+ readonly outcome: 'fulfilled' | 'not_fulfilled';
12
+ readonly reason_code: string;
13
+ /** Omitted from the record entirely when not supplied, never written as null. */
14
+ readonly detail?: string;
15
+ }
16
+ /**
17
+ * Mint a signed fulfilment attestation.
18
+ *
19
+ * What this function does NOT establish: that the holder of `privateKey` is in fact
20
+ * `attestor`, that `verification_method` is one of that party's keys, or that the attestor
21
+ * holds any fulfilment-attestor role. All three are a resolver's answer, not a local one.
22
+ * `assessFulfilment` makes those checks, and it asks about standing BEFORE it asks about the
23
+ * signature, because a record can be perfectly authentic and still come from somebody with
24
+ * no standing to make the statement.
25
+ *
26
+ * Proposed. Concept source: aeoess/agent-authority-lifecycle.
27
+ */
28
+ export declare function issueAuthorityBoundFulfilment(input: IssueFulfilmentInput, privateKeyHex: string): AuthorityBoundFulfilment;
29
+ export interface IssueExhaustionInput {
30
+ readonly boundary: string;
31
+ readonly verification_method: string;
32
+ /** Canonical UTC-millisecond time the finding was made. Never read from a clock. */
33
+ readonly found_at: string;
34
+ readonly detail?: string;
35
+ }
36
+ /**
37
+ * Mint the OPTIONAL signed exhaustion record for a `BoundEvaluation` that reached
38
+ * `exhausted`.
39
+ *
40
+ * REFUSES on any other state, and the refusal is the design. A record that says "I found
41
+ * this bound exhausted" when the evaluation said `not_established` would be a boundary
42
+ * asserting a finding it did not make, which is precisely what CAND-01 forbids. There is no
43
+ * flag to override it.
44
+ *
45
+ * `evidence` is derived from the evaluation's own accepted fulfilment records, and it is
46
+ * EMPTY for a `use_count` or `budget` bound. That emptiness is honest rather than
47
+ * incomplete: the basis for those two is the boundary's own ledger, which is the one thing
48
+ * an outside verifier cannot check, and a placeholder there would hide the gap. The same
49
+ * limit applies to the whole record, and ./types.ts states it: the record attests the
50
+ * boundary's finding, not the state of the world, on the model draft-03 section 5.3.3 uses
51
+ * for an action result.
52
+ *
53
+ * Proposed. Concept source: aeoess/agent-authority-lifecycle, invariant L10.
54
+ */
55
+ export declare function issueAuthorityExhaustion(evaluation: BoundEvaluation, delegationId: string, input: IssueExhaustionInput, privateKeyHex: string): AuthorityExhaustion;
56
+ export type AuthorityExhaustionFailureCode = 'SCHEMA_INVALID' | 'UNSUPPORTED_RECORD_TYPE' | 'ID_MISMATCH' | 'KEY_UNRESOLVED' | 'SIGNATURE_INVALID';
57
+ export interface AuthorityExhaustionVerification {
58
+ /** `valid` or `invalid` only. This function answers a question about ONE record's bytes
59
+ * and its signer, which is genuinely two sided, so it does not borrow the lifecycle
60
+ * vocabulary. What the record means for a grant's state is `evaluateBound`'s question,
61
+ * and a verified record is evidence toward it, never a substitute for it. */
62
+ readonly status: 'valid' | 'invalid';
63
+ readonly failures: readonly AuthorityExhaustionFailureCode[];
64
+ }
65
+ /**
66
+ * Verify an exhaustion record's bytes, identifier and signature.
67
+ *
68
+ * A `valid` answer here means: the record recomputes its own identifier, and the key
69
+ * resolved for its `boundary` at its `found_at` signed it. It does NOT mean the bound is
70
+ * exhausted. It means the named boundary said so, at that time, over those bytes. Treating
71
+ * the two as the same thing is the substitution draft-03's own security considerations warn
72
+ * about for receipts generally, verbatim: "Verifiers MUST treat receipts as evidence of what
73
+ * was attested, not as proof of what is true."
74
+ *
75
+ * Proposed.
76
+ */
77
+ export declare function verifyAuthorityExhaustion(record: AuthorityExhaustion, resolveVerificationKey: (boundary: string, verificationMethod: string, foundAt: string) => string | null): AuthorityExhaustionVerification;
78
+ //# sourceMappingURL=record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../../../src/v2/bounds/record.ts"],"names":[],"mappings":"AAgBA,OAAO,EAIL,KAAK,wBAAwB,EAE7B,KAAK,mBAAmB,EAExB,KAAK,eAAe,EAErB,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAA;IACpC;;wEAEoE;IACpE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,OAAO,EAAE,WAAW,GAAG,eAAe,CAAA;IAC/C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,iFAAiF;IACjF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,oBAAoB,EAC3B,aAAa,EAAE,MAAM,GACpB,wBAAwB,CAsC1B;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAA;IACpC,oFAAoF;IACpF,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,wBAAwB,CACtC,UAAU,EAAE,eAAe,EAC3B,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,oBAAoB,EAC3B,aAAa,EAAE,MAAM,GACpB,mBAAmB,CAiDrB;AAED,MAAM,MAAM,8BAA8B,GACtC,gBAAgB,GAChB,yBAAyB,GACzB,aAAa,GACb,gBAAgB,GAChB,mBAAmB,CAAA;AAEvB,MAAM,WAAW,+BAA+B;IAC9C;;;kFAG8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,CAAA;IACpC,QAAQ,CAAC,QAAQ,EAAE,SAAS,8BAA8B,EAAE,CAAA;CAC7D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,mBAAmB,EAC3B,sBAAsB,EAAE,CACtB,QAAQ,EAAE,MAAM,EAChB,kBAAkB,EAAE,MAAM,EAC1B,OAAO,EAAE,MAAM,KACZ,MAAM,GAAG,IAAI,GACjB,+BAA+B,CAqDjC"}
@@ -0,0 +1,170 @@
1
+ // Copyright (c) 2026 Tymofii Pidlisnyi
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ //
4
+ // PROPOSED, OPT-IN. Issuing and verifying the two records this module declares.
5
+ //
6
+ // Neither record is required by draft-pidlisnyi-aps-03 and neither is an `aps:` record type.
7
+ // See ./types.ts for what each one attests and, more importantly, what it does not.
8
+ import { computeAuthorityExhaustionIdForWrite, computeAuthorityExhaustionId, signAuthorityBoundFulfilment, signAuthorityExhaustion, verifyAuthorityExhaustionSignature, } from './canonical.js';
9
+ import { AuthorityBoundError } from './evaluate.js';
10
+ import { AUTHORITY_BOUND_FULFILMENT_TYPE, AUTHORITY_EXHAUSTION_TYPE, BOUND_KINDS, } from './types.js';
11
+ /**
12
+ * Mint a signed fulfilment attestation.
13
+ *
14
+ * What this function does NOT establish: that the holder of `privateKey` is in fact
15
+ * `attestor`, that `verification_method` is one of that party's keys, or that the attestor
16
+ * holds any fulfilment-attestor role. All three are a resolver's answer, not a local one.
17
+ * `assessFulfilment` makes those checks, and it asks about standing BEFORE it asks about the
18
+ * signature, because a record can be perfectly authentic and still come from somebody with
19
+ * no standing to make the statement.
20
+ *
21
+ * Proposed. Concept source: aeoess/agent-authority-lifecycle.
22
+ */
23
+ export function issueAuthorityBoundFulfilment(input, privateKeyHex) {
24
+ for (const field of [
25
+ 'bound_id',
26
+ 'delegation_id',
27
+ 'attestor',
28
+ 'verification_method',
29
+ 'attested_at',
30
+ 'reason_code',
31
+ ]) {
32
+ const value = input[field];
33
+ if (typeof value !== 'string' || value.length === 0) {
34
+ throw new AuthorityBoundError('FULFILMENT_ISSUE_MALFORMED', `${field} must be a non-empty string`);
35
+ }
36
+ }
37
+ if (input.outcome !== 'fulfilled' && input.outcome !== 'not_fulfilled') {
38
+ throw new AuthorityBoundError('FULFILMENT_ISSUE_MALFORMED', 'outcome must be fulfilled or not_fulfilled');
39
+ }
40
+ const body = Object.freeze({
41
+ record_type: AUTHORITY_BOUND_FULFILMENT_TYPE,
42
+ bound_id: input.bound_id,
43
+ delegation_id: input.delegation_id,
44
+ attestor: input.attestor,
45
+ verification_method: input.verification_method,
46
+ attested_at: input.attested_at,
47
+ outcome: input.outcome,
48
+ reason_code: input.reason_code,
49
+ ...(input.detail !== undefined ? { detail: input.detail } : {}),
50
+ });
51
+ return Object.freeze({
52
+ ...body,
53
+ signature: signAuthorityBoundFulfilment(body, privateKeyHex),
54
+ });
55
+ }
56
+ /**
57
+ * Mint the OPTIONAL signed exhaustion record for a `BoundEvaluation` that reached
58
+ * `exhausted`.
59
+ *
60
+ * REFUSES on any other state, and the refusal is the design. A record that says "I found
61
+ * this bound exhausted" when the evaluation said `not_established` would be a boundary
62
+ * asserting a finding it did not make, which is precisely what CAND-01 forbids. There is no
63
+ * flag to override it.
64
+ *
65
+ * `evidence` is derived from the evaluation's own accepted fulfilment records, and it is
66
+ * EMPTY for a `use_count` or `budget` bound. That emptiness is honest rather than
67
+ * incomplete: the basis for those two is the boundary's own ledger, which is the one thing
68
+ * an outside verifier cannot check, and a placeholder there would hide the gap. The same
69
+ * limit applies to the whole record, and ./types.ts states it: the record attests the
70
+ * boundary's finding, not the state of the world, on the model draft-03 section 5.3.3 uses
71
+ * for an action result.
72
+ *
73
+ * Proposed. Concept source: aeoess/agent-authority-lifecycle, invariant L10.
74
+ */
75
+ export function issueAuthorityExhaustion(evaluation, delegationId, input, privateKeyHex) {
76
+ if (evaluation === null || typeof evaluation !== 'object') {
77
+ throw new AuthorityBoundError('EXHAUSTION_ISSUE_MALFORMED', 'evaluation is not an object');
78
+ }
79
+ if (evaluation.bound_state !== 'exhausted') {
80
+ throw new AuthorityBoundError('EXHAUSTION_STATE_NOT_EXHAUSTED', `an exhaustion record can only be minted for bound_state exhausted, not ${String(evaluation.bound_state)}`);
81
+ }
82
+ for (const field of ['boundary', 'verification_method', 'found_at']) {
83
+ const value = input[field];
84
+ if (typeof value !== 'string' || value.length === 0) {
85
+ throw new AuthorityBoundError('EXHAUSTION_ISSUE_MALFORMED', `${field} must be a non-empty string`);
86
+ }
87
+ }
88
+ if (!BOUND_KINDS.includes(evaluation.kind)) {
89
+ throw new AuthorityBoundError('EXHAUSTION_ISSUE_MALFORMED', `kind must be one of ${BOUND_KINDS.join(', ')}`);
90
+ }
91
+ const body = Object.freeze({
92
+ record_type: AUTHORITY_EXHAUSTION_TYPE,
93
+ bound_id: evaluation.bound_id,
94
+ delegation_id: delegationId,
95
+ kind: evaluation.kind,
96
+ boundary: input.boundary,
97
+ verification_method: input.verification_method,
98
+ found_at: input.found_at,
99
+ reason_code: evaluation.reason_code,
100
+ evidence: Object.freeze(evaluation.fulfilments
101
+ .filter(a => a.accepted)
102
+ .map(a => Object.freeze({ attestor: a.attestor, attested_at: a.attested_at }))),
103
+ ...(input.detail !== undefined ? { detail: input.detail } : {}),
104
+ });
105
+ const exhaustionId = computeAuthorityExhaustionIdForWrite(body);
106
+ const unsigned = Object.freeze({ ...body, exhaustion_id: exhaustionId });
107
+ return Object.freeze({
108
+ ...unsigned,
109
+ signature: signAuthorityExhaustion(unsigned, privateKeyHex),
110
+ });
111
+ }
112
+ /**
113
+ * Verify an exhaustion record's bytes, identifier and signature.
114
+ *
115
+ * A `valid` answer here means: the record recomputes its own identifier, and the key
116
+ * resolved for its `boundary` at its `found_at` signed it. It does NOT mean the bound is
117
+ * exhausted. It means the named boundary said so, at that time, over those bytes. Treating
118
+ * the two as the same thing is the substitution draft-03's own security considerations warn
119
+ * about for receipts generally, verbatim: "Verifiers MUST treat receipts as evidence of what
120
+ * was attested, not as proof of what is true."
121
+ *
122
+ * Proposed.
123
+ */
124
+ export function verifyAuthorityExhaustion(record, resolveVerificationKey) {
125
+ const failures = [];
126
+ const invalid = () => Object.freeze({ status: 'invalid', failures: Object.freeze([...failures]) });
127
+ if (record === null || typeof record !== 'object') {
128
+ failures.push('SCHEMA_INVALID');
129
+ return invalid();
130
+ }
131
+ if (record.record_type !== AUTHORITY_EXHAUSTION_TYPE) {
132
+ failures.push('UNSUPPORTED_RECORD_TYPE');
133
+ return invalid();
134
+ }
135
+ for (const field of [
136
+ 'bound_id',
137
+ 'delegation_id',
138
+ 'boundary',
139
+ 'verification_method',
140
+ 'found_at',
141
+ 'reason_code',
142
+ 'exhaustion_id',
143
+ 'signature',
144
+ ]) {
145
+ if (typeof record[field] !== 'string' || record[field].length === 0) {
146
+ failures.push('SCHEMA_INVALID');
147
+ return invalid();
148
+ }
149
+ }
150
+ if (!Array.isArray(record.evidence) || !BOUND_KINDS.includes(record.kind)) {
151
+ failures.push('SCHEMA_INVALID');
152
+ return invalid();
153
+ }
154
+ const { exhaustion_id: claimedId, signature: _signature, ...body } = record;
155
+ if (computeAuthorityExhaustionId(body) !== claimedId) {
156
+ failures.push('ID_MISMATCH');
157
+ return invalid();
158
+ }
159
+ const publicKey = resolveVerificationKey(record.boundary, record.verification_method, record.found_at);
160
+ if (typeof publicKey !== 'string' || publicKey.length === 0) {
161
+ failures.push('KEY_UNRESOLVED');
162
+ return invalid();
163
+ }
164
+ if (!verifyAuthorityExhaustionSignature(record, publicKey)) {
165
+ failures.push('SIGNATURE_INVALID');
166
+ return invalid();
167
+ }
168
+ return Object.freeze({ status: 'valid', failures: Object.freeze([]) });
169
+ }
170
+ //# sourceMappingURL=record.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record.js","sourceRoot":"","sources":["../../../../src/v2/bounds/record.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,275 @@
1
+ import type { EstablishmentGap, LifecycleStateResult } from '../lifecycle-state/types.js';
2
+ /** Record type of the bound declaration. The `proposed:` prefix is load-bearing: this is
3
+ * not an `aps:` record type, because no published specification defines it. */
4
+ export declare const AUTHORITY_BOUND_TYPE: 'proposed:aps:authority-bound:v0';
5
+ /** Record type of a fulfilment attestation against a bound. */
6
+ export declare const AUTHORITY_BOUND_FULFILMENT_TYPE: 'proposed:aps:authority-bound-fulfilment:v0';
7
+ /** Record type of the optional exhaustion record. See ./record.ts for what it does and
8
+ * does not attest. */
9
+ export declare const AUTHORITY_EXHAUSTION_TYPE: 'proposed:aps:authority-exhaustion:v0';
10
+ /** The three bound kinds the case corpus produces.
11
+ *
12
+ * - `purpose` the grant states a reason. It is reached when a fulfilment record from a
13
+ * party with standing establishes the reason was met. Exercising the grant
14
+ * does NOT by itself reach it.
15
+ * - `use_count` the grant allows a fixed number of admissions. The admission itself
16
+ * reaches it. No fulfilment record is involved.
17
+ * - `budget` a cumulative spend ceiling. Listed for completeness and delegated to,
18
+ * never reimplemented: `InMemoryAuthorityBudgetLedger` already answers it,
19
+ * and draft-03 section 3.4 already states the rule, verbatim: "Signatures
20
+ * establish static limits; they do not establish the current cumulative
21
+ * total."
22
+ *
23
+ * Three bases for one state, kept apart on purpose. Proposed. */
24
+ export declare const BOUND_KINDS: readonly ['purpose', 'use_count', 'budget'];
25
+ export type BoundKind = (typeof BOUND_KINDS)[number];
26
+ /** The state of one grant's declared bound, as a verifier can establish it at an instant.
27
+ *
28
+ * - `not_reached` established: the bound has not been reached.
29
+ * - `exhausted` established: it has. Neither revocation nor expiry. L10.
30
+ * - `not_established` the verifier cannot say. A fulfilment claim arrived that could not
31
+ * be authenticated, or could not be attributed to a party with
32
+ * standing. That establishes neither that the bound was reached nor
33
+ * that it was not, and it is never the negation of either. CAND-01.
34
+ *
35
+ * Proposed. */
36
+ export declare const BOUND_STATES: readonly ['not_reached', 'exhausted', 'not_established'];
37
+ export type BoundState = (typeof BOUND_STATES)[number];
38
+ /** Which ending a bound evaluation reports, in L10's vocabulary.
39
+ *
40
+ * `exhaustion` and nothing else. This module never reports `expiry` and never reports
41
+ * `revocation`: both of those are chain-verification answers, they arrive as
42
+ * `EXPIRED` and `REVOKED` failure codes on an `AuthorityValidationResult`, and a bound
43
+ * evaluation has no standing to restate them. A grant can be expired AND exhausted at the
44
+ * same instant, which is why the two are reported side by side and neither overwrites the
45
+ * other.
46
+ *
47
+ * Concept source: invariant L10. Proposed. */
48
+ export type BoundEnding = 'exhaustion' | null;
49
+ /** A bound declared on one delegation.
50
+ *
51
+ * This module does NOT authenticate the bound declaration itself. A bound is an input the
52
+ * caller has already established, by whatever means its authority model provides: a
53
+ * principal signature over this body, an entry in a registry the verifier accepts, or a
54
+ * term of a contract outside the wire format. Saying so plainly matters, because
55
+ * draft-03's closed facet set means there is no way to put the bound inside the signed
56
+ * delegation, and a module that silently treated an unauthenticated bound as established
57
+ * would be inventing the very thing CAND-01 forbids inventing.
58
+ *
59
+ * What this module DOES authenticate is the fulfilment record, which is the external event
60
+ * CAND-01 is about. */
61
+ export interface AuthorityBound {
62
+ readonly record_type: typeof AUTHORITY_BOUND_TYPE;
63
+ /** Caller-chosen stable identifier for this bound. Non-empty. */
64
+ readonly bound_id: string;
65
+ /** Content address of the bounded delegation: `sha256:<64 lowercase hex>`. */
66
+ readonly delegation_id: string;
67
+ readonly kind: BoundKind;
68
+ /** kind `purpose`: a hierarchical colon-separated purpose, the same grammar
69
+ * `isPurposePermitted` reads for a scope grant.
70
+ * kind `use_count`: a canonical unsigned decimal integer, no leading zero unless the
71
+ * value is exactly "0".
72
+ * kind `budget`: a canonical unsigned decimal integer in the unit's minor units. */
73
+ readonly value: string;
74
+ /** Who may attest that this bound was reached. ROLES, not principals, for the reason a
75
+ * role registry exists at all: the party with standing to say a compressor was installed
76
+ * is whoever currently holds the maintenance-attestor role, not whoever held it when the
77
+ * grant was signed. An empty array means nobody but the delegation's issuer, and a
78
+ * resolver is still what decides whether a given attestor holds the role.
79
+ *
80
+ * Ignored for kind `use_count` and kind `budget`, where no attestation is involved. */
81
+ readonly fulfilment_attestor_roles: readonly string[];
82
+ }
83
+ /** The signed content of a fulfilment attestation: the record with `signature` absent.
84
+ *
85
+ * Modelled on what draft-03 section 3.5.1 requires of a revocation record, which is the
86
+ * nearest published shape for "a party with standing recorded that an authority artifact's
87
+ * state changed", verbatim: "A revocation MUST produce a signed revocation record
88
+ * carrying, at minimum: the revoked delegation's identity; the revocation time, inside the
89
+ * signed content; a reference to the revoking authority; and a machine-readable reason
90
+ * code, with optional free-text detail." Each of those four has a member below. Nothing in
91
+ * draft-03 requires this record to exist. */
92
+ export interface AuthorityBoundFulfilmentBody {
93
+ readonly record_type: typeof AUTHORITY_BOUND_FULFILMENT_TYPE;
94
+ /** The bound this attestation is about. Compared to `AuthorityBound.bound_id`. */
95
+ readonly bound_id: string;
96
+ /** The bounded delegation's identity. Compared to `AuthorityBound.delegation_id`. */
97
+ readonly delegation_id: string;
98
+ /** The attesting party. A valid signature establishes WHO signed. It does not establish
99
+ * that the signer was allowed to make this statement, which is what the role resolver
100
+ * is for. */
101
+ readonly attestor: string;
102
+ /** Which key signed. No local rule relates it to `attestor`: an identifier-to-key
103
+ * binding is a resolver's answer. */
104
+ readonly verification_method: string;
105
+ /** Canonical UTC-millisecond time, inside the signed content, supplied by the caller and
106
+ * never read from a clock. */
107
+ readonly attested_at: string;
108
+ /** Machine-readable outcome. `fulfilled` is the only value that can reach a bound. A
109
+ * record that says `not_fulfilled` is a statement about the world, and it is why "a
110
+ * fulfilment record exists" and "it says the purpose was met" stay two facts. */
111
+ readonly outcome: 'fulfilled' | 'not_fulfilled';
112
+ /** Machine-readable reason code. Non-empty, and no grammar is fixed. */
113
+ readonly reason_code: string;
114
+ /** OPTIONAL free-text detail. An absent detail is absent, never serialized as null: JCS
115
+ * has no canonical form for undefined. */
116
+ readonly detail?: string;
117
+ }
118
+ export interface AuthorityBoundFulfilment extends AuthorityBoundFulfilmentBody {
119
+ /** Raw 64-byte Ed25519 signature as 128 lowercase hexadecimal characters. */
120
+ readonly signature: string;
121
+ }
122
+ /** What a resolver says about one attestor's standing at one instant.
123
+ *
124
+ * Three values, and the third is the point. `unknown` is not `other`: a resolver that
125
+ * cannot answer has not told the verifier that the attestor lacks the role, and collapsing
126
+ * the two would turn an unanswered question into a finding. Mirrors the three-value shape
127
+ * the activation-condition surface uses for the same reason. */
128
+ export declare const ATTESTOR_ROLE_ANSWERS: readonly ['holds_role', 'does_not_hold_role', 'unknown'];
129
+ export type AttestorRoleAnswer = (typeof ATTESTOR_ROLE_ANSWERS)[number];
130
+ /** Resolve whether `attestor` held any of `roles` at `atInstant`.
131
+ *
132
+ * Roles, not principals: see `AuthorityBound.fulfilment_attestor_roles`. The resolver is
133
+ * the caller's, because who holds a role is not a local fact. */
134
+ export type AttestorRoleResolver = (attestor: string, roles: readonly string[], atInstant: string) => AttestorRoleAnswer;
135
+ /** Resolve the verification key for one attestor's method as of one instant. `null` means
136
+ * no key was resolved, which is a `source` gap and never a signature failure. The
137
+ * instant-taking shape matches the historical key resolution invariant L9 describes: a
138
+ * verifier selects the key version authorized at the record's own timestamp. */
139
+ export type BoundVerificationKeyResolver = (attestor: string, verificationMethod: string, attestedAt: string) => string | null;
140
+ /** The reason codes this module emits. Stable, module-local, SCREAMING_SNAKE_CASE. */
141
+ export declare const BOUND_REASON_CODES: readonly [
142
+ /** not_reached: the bound is declared and no accepted evidence reaches it. */
143
+ 'BOUND_NOT_REACHED',
144
+ /** exhausted: an accepted fulfilment record established the purpose was met. */
145
+ 'PURPOSE_EXHAUSTED',
146
+ /** exhausted: admissions counted against the bound reached its limit. */
147
+ 'USE_COUNT_EXHAUSTED',
148
+ /** exhausted: committed plus reserved spend reached the cumulative ceiling. */
149
+ 'BUDGET_EXHAUSTED',
150
+ /** not_established: at least one fulfilment claim could not be established, and none
151
+ * was accepted. The per-record code says which limb failed on which record. */
152
+ 'BOUND_STATE_NOT_ESTABLISHED'];
153
+ export type BoundReasonCode = (typeof BOUND_REASON_CODES)[number];
154
+ /** Per-record codes an assessment carries. A rejected record always says which of the
155
+ * three failure classes it fell into, because "we did not accept it" is not an answer. */
156
+ export declare const FULFILMENT_REASON_CODES: readonly [
157
+ /** Accepted: structurally sound, signature verified, attestor holds a named role. */
158
+ 'FULFILMENT_ACCEPTED',
159
+ /** The record does not have the shape this module reads. */
160
+ 'FULFILMENT_SCHEMA_INVALID',
161
+ /** The record names a different bound or a different delegation. */
162
+ 'FULFILMENT_NOT_BOUND_TO_BOUND',
163
+ /** The record says the bound was not met. Established, and negative. */
164
+ 'FULFILMENT_OUTCOME_NOT_FULFILLED',
165
+ /** `attested_at` is later than the instant being evaluated. A verifier asked about
166
+ * Tuesday does not get to read Wednesday's records. */
167
+ 'FULFILMENT_NOT_YET_ATTESTED',
168
+ /** No key resolved for the attestor's method. A source gap, not a signature failure. */
169
+ 'FULFILMENT_KEY_UNRESOLVED',
170
+ /** A key resolved and the signature did not verify over the canonical preimage. */
171
+ 'FULFILMENT_SIGNATURE_INVALID',
172
+ /** The signature verified and the resolver says the attestor does not hold a named role.
173
+ * Authenticated, and by someone without standing. A different failure from the one
174
+ * above, and this module will not collapse them. */
175
+ 'FULFILMENT_ATTESTOR_WITHOUT_STANDING',
176
+ /** The resolver could not say whether the attestor holds a role. Not the same as
177
+ * `WITHOUT_STANDING`: nobody has told the verifier anything. */
178
+ 'FULFILMENT_ATTESTOR_ROLE_UNKNOWN',
179
+ /** The bound's kind takes no fulfilment record. A `use_count` bound is reached by the
180
+ * admission and a `budget` bound by the ledger. */
181
+ 'FULFILMENT_NOT_APPLICABLE_TO_KIND'];
182
+ export type FulfilmentReasonCode = (typeof FULFILMENT_REASON_CODES)[number];
183
+ /** What this module concluded about ONE fulfilment record. */
184
+ export interface FulfilmentAssessment {
185
+ /** `bound_id` plus `attested_at` plus `attestor`, as supplied. Never computed from the
186
+ * record's own claims about itself. */
187
+ readonly attestor: string;
188
+ readonly attested_at: string;
189
+ readonly accepted: boolean;
190
+ readonly reason_code: FulfilmentReasonCode;
191
+ /** The resolver's answer, when one was asked for. */
192
+ readonly role_answer?: AttestorRoleAnswer;
193
+ /** Which establishment limb this rejection leaves missing, when the rejection is an
194
+ * evidential one rather than an established negative. Absent on an accepted record and
195
+ * on `FULFILMENT_OUTCOME_NOT_FULFILLED`, which is a conclusion, not a gap. */
196
+ readonly missing?: readonly EstablishmentGap[];
197
+ }
198
+ /** What `evaluateBound` concludes. */
199
+ export interface BoundEvaluation {
200
+ readonly bound_id: string;
201
+ readonly kind: BoundKind;
202
+ readonly bound_state: BoundState;
203
+ readonly reason_code: BoundReasonCode;
204
+ /** L10's ending vocabulary. `exhaustion` exactly when `bound_state` is `exhausted`, and
205
+ * `null` otherwise. Never `expiry` and never `revocation`: see `BoundEnding`. */
206
+ readonly ending: BoundEnding;
207
+ /** The same conclusion in the `../lifecycle-state/` vocabulary, for reporting alongside
208
+ * a chain result. `not_reached` is `valid`, `exhausted` is `invalid` (the vocabulary
209
+ * has no seventh verdict and exhaustion is one of the findings that lands there,
210
+ * separated by reason code), `not_established` is `not_established` with its limbs. */
211
+ readonly lifecycle: LifecycleStateResult;
212
+ /** Every fulfilment record that was looked at, in the order supplied, with what happened
213
+ * to it. Never a count and never a boolean. */
214
+ readonly fulfilments: readonly FulfilmentAssessment[];
215
+ /** kind `use_count` only: admissions still allowed, as a canonical decimal string.
216
+ * "0" when exhausted. Absent for the other kinds. */
217
+ readonly remaining?: string;
218
+ }
219
+ /** The signed content of the OPTIONAL exhaustion record: the record with `exhaustion_id`
220
+ * and `signature` absent.
221
+ *
222
+ * WHAT THIS RECORD ATTESTS, stated once and stated plainly. It attests that the
223
+ * enforcement boundary named in `boundary` found, from the evidence it names, that the
224
+ * bound had been reached. It does NOT attest that the purpose was met in the world. That
225
+ * distinction is not an invention of this module: draft-03 section 5.3.3 draws the same
226
+ * one for an action result, verbatim: "An action-result record attests to what the
227
+ * enforcement boundary observed after dispatch. External occurrence or settlement
228
+ * requires separately resolved evidence." A verifier with no access to the boundary's
229
+ * ledgers cannot reach an exhaustion verdict from signed records alone, and this record
230
+ * does not pretend otherwise.
231
+ *
232
+ * WHY IT EXISTS ANYWAY. draft-03 section 3.5.1 gives revocation a signed record, verbatim:
233
+ * "A revocation MUST produce a signed revocation record carrying, at minimum: the revoked
234
+ * delegation's identity; the revocation time, inside the signed content; a reference to the
235
+ * revoking authority; and a machine-readable reason code, with optional free-text detail."
236
+ * Exhaustion has no published counterpart. Invariant L10 says the difference between the
237
+ * two endings "matters for evidence and for whether a replacement is expected", and an
238
+ * ending with no record at all cannot carry that difference anywhere. This record is shaped
239
+ * deliberately like the section 3.5.1 one so the two endings are comparable evidence and
240
+ * still never the same record type.
241
+ *
242
+ * Concept source: invariant L10 and invariant candidate CAND-01. Proposed. */
243
+ export interface AuthorityExhaustionBody {
244
+ readonly record_type: typeof AUTHORITY_EXHAUSTION_TYPE;
245
+ /** The bound that was reached. */
246
+ readonly bound_id: string;
247
+ /** The bounded delegation's identity. */
248
+ readonly delegation_id: string;
249
+ readonly kind: BoundKind;
250
+ /** The enforcement boundary making the finding. Its own identity, not the principal's:
251
+ * this is the boundary's statement about what it observed. */
252
+ readonly boundary: string;
253
+ readonly verification_method: string;
254
+ /** Canonical UTC-millisecond time the finding was made, inside the signed content. */
255
+ readonly found_at: string;
256
+ /** One of `BOUND_REASON_CODES`, and the reason the module reached `exhausted`. */
257
+ readonly reason_code: string;
258
+ /** The evidence the finding rests on. For a purpose bound, the `attestor` and
259
+ * `attested_at` of every accepted fulfilment record. For a use-count or budget bound,
260
+ * an empty array: the basis is the boundary's own ledger, which is exactly the thing an
261
+ * outside verifier cannot check, and writing a placeholder here would hide that. */
262
+ readonly evidence: readonly {
263
+ readonly attestor: string;
264
+ readonly attested_at: string;
265
+ }[];
266
+ /** OPTIONAL free-text detail. Absent means absent, never null. */
267
+ readonly detail?: string;
268
+ }
269
+ export interface AuthorityExhaustion extends AuthorityExhaustionBody {
270
+ /** `sha256:<64 lowercase hex>` over the ID domain tag and JCS of the body. */
271
+ readonly exhaustion_id: string;
272
+ /** Raw 64-byte Ed25519 signature as 128 lowercase hexadecimal characters. */
273
+ readonly signature: string;
274
+ }
275
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/v2/bounds/types.ts"],"names":[],"mappings":"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"}