agent-passport-system 7.1.0 → 7.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -5
- package/SECURITY.md +2 -2
- package/dist/src/core/tool-integrity.d.ts +13 -0
- package/dist/src/core/tool-integrity.d.ts.map +1 -1
- package/dist/src/core/tool-integrity.js +1 -1
- package/dist/src/core/tool-integrity.js.map +1 -1
- package/dist/src/index.d.ts +28 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +242 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/v2/activation/canonical.d.ts +40 -0
- package/dist/src/v2/activation/canonical.d.ts.map +1 -0
- package/dist/src/v2/activation/canonical.js +64 -0
- package/dist/src/v2/activation/canonical.js.map +1 -0
- package/dist/src/v2/activation/index.d.ts +4 -0
- package/dist/src/v2/activation/index.d.ts.map +1 -0
- package/dist/src/v2/activation/index.js +11 -0
- package/dist/src/v2/activation/index.js.map +1 -0
- package/dist/src/v2/activation/types.d.ts +268 -0
- package/dist/src/v2/activation/types.d.ts.map +1 -0
- package/dist/src/v2/activation/types.js +198 -0
- package/dist/src/v2/activation/types.js.map +1 -0
- package/dist/src/v2/activation/verify.d.ts +132 -0
- package/dist/src/v2/activation/verify.d.ts.map +1 -0
- package/dist/src/v2/activation/verify.js +406 -0
- package/dist/src/v2/activation/verify.js.map +1 -0
- package/dist/src/v2/authority-state/fencing.d.ts +49 -0
- package/dist/src/v2/authority-state/fencing.d.ts.map +1 -0
- package/dist/src/v2/authority-state/fencing.js +92 -0
- package/dist/src/v2/authority-state/fencing.js.map +1 -0
- package/dist/src/v2/authority-state/index.d.ts +7 -0
- package/dist/src/v2/authority-state/index.d.ts.map +1 -0
- package/dist/src/v2/authority-state/index.js +14 -0
- package/dist/src/v2/authority-state/index.js.map +1 -0
- package/dist/src/v2/authority-state/marker.d.ts +70 -0
- package/dist/src/v2/authority-state/marker.d.ts.map +1 -0
- package/dist/src/v2/authority-state/marker.js +122 -0
- package/dist/src/v2/authority-state/marker.js.map +1 -0
- package/dist/src/v2/authority-state/report.d.ts +55 -0
- package/dist/src/v2/authority-state/report.d.ts.map +1 -0
- package/dist/src/v2/authority-state/report.js +51 -0
- package/dist/src/v2/authority-state/report.js.map +1 -0
- package/dist/src/v2/authority-state/retained.d.ts +82 -0
- package/dist/src/v2/authority-state/retained.d.ts.map +1 -0
- package/dist/src/v2/authority-state/retained.js +93 -0
- package/dist/src/v2/authority-state/retained.js.map +1 -0
- package/dist/src/v2/authority-state/types.d.ts +198 -0
- package/dist/src/v2/authority-state/types.d.ts.map +1 -0
- package/dist/src/v2/authority-state/types.js +103 -0
- package/dist/src/v2/authority-state/types.js.map +1 -0
- package/dist/src/v2/authority-state/withdrawal.d.ts +80 -0
- package/dist/src/v2/authority-state/withdrawal.d.ts.map +1 -0
- package/dist/src/v2/authority-state/withdrawal.js +199 -0
- package/dist/src/v2/authority-state/withdrawal.js.map +1 -0
- package/dist/src/v2/bounds/canonical.d.ts +30 -0
- package/dist/src/v2/bounds/canonical.d.ts.map +1 -0
- package/dist/src/v2/bounds/canonical.js +69 -0
- package/dist/src/v2/bounds/canonical.js.map +1 -0
- package/dist/src/v2/bounds/evaluate.d.ts +107 -0
- package/dist/src/v2/bounds/evaluate.d.ts.map +1 -0
- package/dist/src/v2/bounds/evaluate.js +315 -0
- package/dist/src/v2/bounds/evaluate.js.map +1 -0
- package/dist/src/v2/bounds/index.d.ts +6 -0
- package/dist/src/v2/bounds/index.d.ts.map +1 -0
- package/dist/src/v2/bounds/index.js +13 -0
- package/dist/src/v2/bounds/index.js.map +1 -0
- package/dist/src/v2/bounds/purpose.d.ts +2 -0
- package/dist/src/v2/bounds/purpose.d.ts.map +1 -0
- package/dist/src/v2/bounds/purpose.js +23 -0
- package/dist/src/v2/bounds/purpose.js.map +1 -0
- package/dist/src/v2/bounds/record.d.ts +78 -0
- package/dist/src/v2/bounds/record.d.ts.map +1 -0
- package/dist/src/v2/bounds/record.js +170 -0
- package/dist/src/v2/bounds/record.js.map +1 -0
- package/dist/src/v2/bounds/types.d.ts +275 -0
- package/dist/src/v2/bounds/types.d.ts.map +1 -0
- package/dist/src/v2/bounds/types.js +124 -0
- package/dist/src/v2/bounds/types.js.map +1 -0
- package/dist/src/v2/capability-binding/binding.d.ts +67 -0
- package/dist/src/v2/capability-binding/binding.d.ts.map +1 -0
- package/dist/src/v2/capability-binding/binding.js +267 -0
- package/dist/src/v2/capability-binding/binding.js.map +1 -0
- package/dist/src/v2/capability-binding/digest.d.ts +33 -0
- package/dist/src/v2/capability-binding/digest.d.ts.map +1 -0
- package/dist/src/v2/capability-binding/digest.js +55 -0
- package/dist/src/v2/capability-binding/digest.js.map +1 -0
- package/dist/src/v2/capability-binding/identifier.d.ts +103 -0
- package/dist/src/v2/capability-binding/identifier.d.ts.map +1 -0
- package/dist/src/v2/capability-binding/identifier.js +281 -0
- package/dist/src/v2/capability-binding/identifier.js.map +1 -0
- package/dist/src/v2/capability-binding/index.d.ts +6 -0
- package/dist/src/v2/capability-binding/index.d.ts.map +1 -0
- package/dist/src/v2/capability-binding/index.js +13 -0
- package/dist/src/v2/capability-binding/index.js.map +1 -0
- package/dist/src/v2/capability-binding/pins.d.ts +30 -0
- package/dist/src/v2/capability-binding/pins.d.ts.map +1 -0
- package/dist/src/v2/capability-binding/pins.js +109 -0
- package/dist/src/v2/capability-binding/pins.js.map +1 -0
- package/dist/src/v2/capability-binding/types.d.ts +213 -0
- package/dist/src/v2/capability-binding/types.d.ts.map +1 -0
- package/dist/src/v2/capability-binding/types.js +150 -0
- package/dist/src/v2/capability-binding/types.js.map +1 -0
- package/dist/src/v2/chain-selection/index.d.ts +4 -0
- package/dist/src/v2/chain-selection/index.d.ts.map +1 -0
- package/dist/src/v2/chain-selection/index.js +11 -0
- package/dist/src/v2/chain-selection/index.js.map +1 -0
- package/dist/src/v2/chain-selection/select.d.ts +62 -0
- package/dist/src/v2/chain-selection/select.d.ts.map +1 -0
- package/dist/src/v2/chain-selection/select.js +390 -0
- package/dist/src/v2/chain-selection/select.js.map +1 -0
- package/dist/src/v2/chain-selection/types.d.ts +189 -0
- package/dist/src/v2/chain-selection/types.d.ts.map +1 -0
- package/dist/src/v2/chain-selection/types.js +81 -0
- package/dist/src/v2/chain-selection/types.js.map +1 -0
- package/dist/src/v2/lifecycle-state/index.d.ts +4 -0
- package/dist/src/v2/lifecycle-state/index.d.ts.map +1 -0
- package/dist/src/v2/lifecycle-state/index.js +10 -0
- package/dist/src/v2/lifecycle-state/index.js.map +1 -0
- package/dist/src/v2/lifecycle-state/map.d.ts +52 -0
- package/dist/src/v2/lifecycle-state/map.d.ts.map +1 -0
- package/dist/src/v2/lifecycle-state/map.js +122 -0
- package/dist/src/v2/lifecycle-state/map.js.map +1 -0
- package/dist/src/v2/lifecycle-state/state.d.ts +60 -0
- package/dist/src/v2/lifecycle-state/state.d.ts.map +1 -0
- package/dist/src/v2/lifecycle-state/state.js +157 -0
- package/dist/src/v2/lifecycle-state/state.js.map +1 -0
- package/dist/src/v2/lifecycle-state/types.d.ts +163 -0
- package/dist/src/v2/lifecycle-state/types.d.ts.map +1 -0
- package/dist/src/v2/lifecycle-state/types.js +121 -0
- package/dist/src/v2/lifecycle-state/types.js.map +1 -0
- package/dist/src/v2/status-coverage/decide.d.ts +52 -0
- package/dist/src/v2/status-coverage/decide.d.ts.map +1 -0
- package/dist/src/v2/status-coverage/decide.js +398 -0
- package/dist/src/v2/status-coverage/decide.js.map +1 -0
- package/dist/src/v2/status-coverage/index.d.ts +3 -0
- package/dist/src/v2/status-coverage/index.d.ts.map +1 -0
- package/dist/src/v2/status-coverage/index.js +10 -0
- package/dist/src/v2/status-coverage/index.js.map +1 -0
- package/dist/src/v2/status-coverage/types.d.ts +258 -0
- package/dist/src/v2/status-coverage/types.d.ts.map +1 -0
- package/dist/src/v2/status-coverage/types.js +127 -0
- package/dist/src/v2/status-coverage/types.js.map +1 -0
- package/dist/src/v2/suspension/evaluate.d.ts +88 -0
- package/dist/src/v2/suspension/evaluate.d.ts.map +1 -0
- package/dist/src/v2/suspension/evaluate.js +404 -0
- package/dist/src/v2/suspension/evaluate.js.map +1 -0
- package/dist/src/v2/suspension/index.d.ts +3 -0
- package/dist/src/v2/suspension/index.d.ts.map +1 -0
- package/dist/src/v2/suspension/index.js +10 -0
- package/dist/src/v2/suspension/index.js.map +1 -0
- package/dist/src/v2/suspension/types.d.ts +243 -0
- package/dist/src/v2/suspension/types.d.ts.map +1 -0
- package/dist/src/v2/suspension/types.js +135 -0
- package/dist/src/v2/suspension/types.js.map +1 -0
- package/package.json +8 -8
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical.d.ts","sourceRoot":"","sources":["../../../../src/v2/bounds/canonical.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,wBAAwB,EACxB,4BAA4B,EAC5B,mBAAmB,EACnB,uBAAuB,EACxB,MAAM,YAAY,CAAA;AAEnB;;;;;kEAKkE;AAClE,eAAO,MAAM,2CAA2C,2DACE,CAAA;AAC1D,eAAO,MAAM,8BAA8B,8CAA8C,CAAA;AACzF,eAAO,MAAM,qCAAqC,qDACE,CAAA;AAWpD;0CAC0C;AAC1C,wBAAgB,sCAAsC,CACpD,IAAI,EAAE,4BAA4B,GACjC,MAAM,CAER;AAED;kFACkF;AAClF,wBAAgB,8CAA8C,CAC5D,IAAI,EAAE,4BAA4B,GACjC,MAAM,CAER;AAED,wBAAgB,4BAA4B,CAC1C,IAAI,EAAE,4BAA4B,EAClC,aAAa,EAAE,MAAM,GACpB,MAAM,CAER;AAED,wBAAgB,uCAAuC,CACrD,MAAM,EAAE,wBAAwB,EAChC,YAAY,EAAE,MAAM,GACnB,OAAO,CAQT;AAED,kFAAkF;AAClF,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,uBAAuB,GAAG,MAAM,CAEhF;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,uBAAuB,GAAG,MAAM,CAElF;AAED,wBAAgB,oCAAoC,CAAC,IAAI,EAAE,uBAAuB,GAAG,MAAM,CAI1F;AAED;;4FAE4F;AAC5F,wBAAgB,iCAAiC,CAC/C,MAAM,EAAE,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,GAC7C,MAAM,CAER;AAED,wBAAgB,yCAAyC,CACvD,MAAM,EAAE,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,GAC7C,MAAM,CAER;AAED,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,IAAI,CAAC,mBAAmB,EAAE,WAAW,CAAC,EAC9C,aAAa,EAAE,MAAM,GACpB,MAAM,CAER;AAED,wBAAgB,kCAAkC,CAChD,MAAM,EAAE,mBAAmB,EAC3B,YAAY,EAAE,MAAM,GACnB,OAAO,CAQT"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Copyright (c) 2026 Tymofii Pidlisnyi
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
//
|
|
4
|
+
// PROPOSED, OPT-IN. Content addressing and Ed25519 signing for the two records this module
|
|
5
|
+
// declares. Nothing here reimplements JCS, SHA-256 or Ed25519: each comes from the helper
|
|
6
|
+
// the rest of this package already uses.
|
|
7
|
+
//
|
|
8
|
+
// Not required by draft-pidlisnyi-aps-03. See ./types.ts for the specification position.
|
|
9
|
+
import { createHash } from 'node:crypto';
|
|
10
|
+
import { canonicalizeJCS, canonicalizeJCSForWrite } from '../../core/canonical-jcs.js';
|
|
11
|
+
import { sign, verify } from '../../crypto/keys.js';
|
|
12
|
+
/** Domain tags. Each is a distinct tag followed by one zero byte, the same discipline
|
|
13
|
+
* `AuthorityDelegationV1` and `AuthorityRevocationV1` follow, so bytes minted for one
|
|
14
|
+
* construction can never be read as bytes minted for another. The `PROPOSED-` prefix is
|
|
15
|
+
* part of the tag: if any of this is ever specified, the specified construction will use a
|
|
16
|
+
* different tag and records minted under this one will not verify under it. That is the
|
|
17
|
+
* intended behaviour, not a migration problem to solve later. */
|
|
18
|
+
export const AUTHORITY_BOUND_FULFILMENT_SIGNATURE_DOMAIN = 'PROPOSED-APS-AUTHORITY-BOUND-FULFILMENT-SIGNATURE-V0\0';
|
|
19
|
+
export const AUTHORITY_EXHAUSTION_ID_DOMAIN = 'PROPOSED-APS-AUTHORITY-EXHAUSTION-ID-V0\0';
|
|
20
|
+
export const AUTHORITY_EXHAUSTION_SIGNATURE_DOMAIN = 'PROPOSED-APS-AUTHORITY-EXHAUSTION-SIGNATURE-V0\0';
|
|
21
|
+
function sha256Hex(value) {
|
|
22
|
+
return createHash('sha256').update(value, 'utf8').digest('hex');
|
|
23
|
+
}
|
|
24
|
+
function withoutSignature(record) {
|
|
25
|
+
const { signature: _signature, ...body } = record;
|
|
26
|
+
return body;
|
|
27
|
+
}
|
|
28
|
+
/** Exact Ed25519 preimage for a fulfilment attestation: the domain tag plus RFC 8785 JCS of
|
|
29
|
+
* the record with `signature` absent. */
|
|
30
|
+
export function authorityBoundFulfilmentSignatureInput(body) {
|
|
31
|
+
return AUTHORITY_BOUND_FULFILMENT_SIGNATURE_DOMAIN + canonicalizeJCS(body);
|
|
32
|
+
}
|
|
33
|
+
/** Write-boundary twin. Use when ISSUING. The verification path keeps calling the
|
|
34
|
+
* unrestricted form, so a record minted before the write rule still verifies. */
|
|
35
|
+
export function authorityBoundFulfilmentSignatureInputForWrite(body) {
|
|
36
|
+
return AUTHORITY_BOUND_FULFILMENT_SIGNATURE_DOMAIN + canonicalizeJCSForWrite(body);
|
|
37
|
+
}
|
|
38
|
+
export function signAuthorityBoundFulfilment(body, privateKeyHex) {
|
|
39
|
+
return sign(authorityBoundFulfilmentSignatureInputForWrite(body), privateKeyHex);
|
|
40
|
+
}
|
|
41
|
+
export function verifyAuthorityBoundFulfilmentSignature(record, publicKeyHex) {
|
|
42
|
+
return verify(authorityBoundFulfilmentSignatureInput(withoutSignature(record)), record.signature, publicKeyHex);
|
|
43
|
+
}
|
|
44
|
+
/** Exact preimage for `exhaustion_id`: the ID domain tag plus JCS of the body. */
|
|
45
|
+
export function authorityExhaustionIdInput(body) {
|
|
46
|
+
return AUTHORITY_EXHAUSTION_ID_DOMAIN + canonicalizeJCS(body);
|
|
47
|
+
}
|
|
48
|
+
export function computeAuthorityExhaustionId(body) {
|
|
49
|
+
return `sha256:${sha256Hex(authorityExhaustionIdInput(body))}`;
|
|
50
|
+
}
|
|
51
|
+
export function computeAuthorityExhaustionIdForWrite(body) {
|
|
52
|
+
return `sha256:${sha256Hex(AUTHORITY_EXHAUSTION_ID_DOMAIN + canonicalizeJCSForWrite(body))}`;
|
|
53
|
+
}
|
|
54
|
+
/** Exact Ed25519 preimage for the exhaustion record: the signature domain tag plus JCS of
|
|
55
|
+
* the record with `signature` absent. `exhaustion_id` IS inside this preimage, so the
|
|
56
|
+
* identifier is signed rather than being an unauthenticated label beside the signature. */
|
|
57
|
+
export function authorityExhaustionSignatureInput(record) {
|
|
58
|
+
return AUTHORITY_EXHAUSTION_SIGNATURE_DOMAIN + canonicalizeJCS(record);
|
|
59
|
+
}
|
|
60
|
+
export function authorityExhaustionSignatureInputForWrite(record) {
|
|
61
|
+
return AUTHORITY_EXHAUSTION_SIGNATURE_DOMAIN + canonicalizeJCSForWrite(record);
|
|
62
|
+
}
|
|
63
|
+
export function signAuthorityExhaustion(record, privateKeyHex) {
|
|
64
|
+
return sign(authorityExhaustionSignatureInputForWrite(record), privateKeyHex);
|
|
65
|
+
}
|
|
66
|
+
export function verifyAuthorityExhaustionSignature(record, publicKeyHex) {
|
|
67
|
+
return verify(authorityExhaustionSignatureInput(withoutSignature(record)), record.signature, publicKeyHex);
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=canonical.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical.js","sourceRoot":"","sources":["../../../../src/v2/bounds/canonical.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,sCAAsC;AACtC,EAAE;AACF,2FAA2F;AAC3F,0FAA0F;AAC1F,yCAAyC;AACzC,EAAE;AACF,yFAAyF;AAEzF,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,6BAA6B,CAAA;AACtF,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAQnD;;;;;kEAKkE;AAClE,MAAM,CAAC,MAAM,2CAA2C,GACtD,wDAAwD,CAAA;AAC1D,MAAM,CAAC,MAAM,8BAA8B,GAAG,2CAA2C,CAAA;AACzF,MAAM,CAAC,MAAM,qCAAqC,GAChD,kDAAkD,CAAA;AAEpD,SAAS,SAAS,CAAC,KAAa;IAC9B,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;AACjE,CAAC;AAED,SAAS,gBAAgB,CAAkC,MAAS;IAClE,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,GAAG,MAAM,CAAA;IACjD,OAAO,IAAI,CAAA;AACb,CAAC;AAED;0CAC0C;AAC1C,MAAM,UAAU,sCAAsC,CACpD,IAAkC;IAElC,OAAO,2CAA2C,GAAG,eAAe,CAAC,IAAI,CAAC,CAAA;AAC5E,CAAC;AAED;kFACkF;AAClF,MAAM,UAAU,8CAA8C,CAC5D,IAAkC;IAElC,OAAO,2CAA2C,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAA;AACpF,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,IAAkC,EAClC,aAAqB;IAErB,OAAO,IAAI,CAAC,8CAA8C,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,CAAA;AAClF,CAAC;AAED,MAAM,UAAU,uCAAuC,CACrD,MAAgC,EAChC,YAAoB;IAEpB,OAAO,MAAM,CACX,sCAAsC,CACpC,gBAAgB,CAAC,MAAM,CAAiC,CACzD,EACD,MAAM,CAAC,SAAS,EAChB,YAAY,CACb,CAAA;AACH,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,0BAA0B,CAAC,IAA6B;IACtE,OAAO,8BAA8B,GAAG,eAAe,CAAC,IAAI,CAAC,CAAA;AAC/D,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,IAA6B;IACxE,OAAO,UAAU,SAAS,CAAC,0BAA0B,CAAC,IAAI,CAAC,CAAC,EAAE,CAAA;AAChE,CAAC;AAED,MAAM,UAAU,oCAAoC,CAAC,IAA6B;IAChF,OAAO,UAAU,SAAS,CACxB,8BAA8B,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAC/D,EAAE,CAAA;AACL,CAAC;AAED;;4FAE4F;AAC5F,MAAM,UAAU,iCAAiC,CAC/C,MAA8C;IAE9C,OAAO,qCAAqC,GAAG,eAAe,CAAC,MAAM,CAAC,CAAA;AACxE,CAAC;AAED,MAAM,UAAU,yCAAyC,CACvD,MAA8C;IAE9C,OAAO,qCAAqC,GAAG,uBAAuB,CAAC,MAAM,CAAC,CAAA;AAChF,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,MAA8C,EAC9C,aAAqB;IAErB,OAAO,IAAI,CAAC,yCAAyC,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC,CAAA;AAC/E,CAAC;AAED,MAAM,UAAU,kCAAkC,CAChD,MAA2B,EAC3B,YAAoB;IAEpB,OAAO,MAAM,CACX,iCAAiC,CAC/B,gBAAgB,CAAC,MAAM,CAA2C,CACnE,EACD,MAAM,CAAC,SAAS,EAChB,YAAY,CACb,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { type AttestorRoleAnswer, type AttestorRoleResolver, type AuthorityBound, type AuthorityBoundFulfilment, type BoundEvaluation, type BoundKind, type BoundVerificationKeyResolver, type FulfilmentAssessment } from './types.js';
|
|
2
|
+
/** Thrown when an input this module cannot read at all is passed. A malformed BOUND is a
|
|
3
|
+
* programming error, not a verdict: the module was asked a question about nothing. A
|
|
4
|
+
* malformed FULFILMENT RECORD is different and never throws, because a record somebody
|
|
5
|
+
* else wrote is data, and the right answer about it is a rejection with a reason code. */
|
|
6
|
+
export declare class AuthorityBoundError extends Error {
|
|
7
|
+
readonly code: string;
|
|
8
|
+
constructor(code: string, message: string);
|
|
9
|
+
}
|
|
10
|
+
export declare function isBoundKind(value: unknown): value is BoundKind;
|
|
11
|
+
export declare function isAttestorRoleAnswer(value: unknown): value is AttestorRoleAnswer;
|
|
12
|
+
/** Shape check for a bound declaration. Throws, for the reason `AuthorityBoundError`
|
|
13
|
+
* documents. */
|
|
14
|
+
export declare function assertAuthorityBound(bound: AuthorityBound): void;
|
|
15
|
+
export interface AssessFulfilmentInput {
|
|
16
|
+
readonly bound: AuthorityBound;
|
|
17
|
+
readonly record: AuthorityBoundFulfilment;
|
|
18
|
+
/** The instant the question is asked at. A record attested later than this is not read:
|
|
19
|
+
* a verifier asked about Tuesday does not get to use Wednesday's evidence. */
|
|
20
|
+
readonly atInstant: string;
|
|
21
|
+
readonly resolveAttestorRole: AttestorRoleResolver;
|
|
22
|
+
readonly resolveVerificationKey: BoundVerificationKeyResolver;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Assess ONE fulfilment record against one bound.
|
|
26
|
+
*
|
|
27
|
+
* The order of the checks is the substance of this function, not an implementation detail.
|
|
28
|
+
* Standing is asked FIRST and authenticity SECOND, and each produces its own code, because
|
|
29
|
+
* "authenticated by somebody who may not say this" and "not authenticated at all" are
|
|
30
|
+
* different failures and collapsing them loses the distinction CAND-01 turns on. A valid
|
|
31
|
+
* signature establishes who signed. It does not establish that the signer was allowed to
|
|
32
|
+
* make this statement.
|
|
33
|
+
*
|
|
34
|
+
* `FULFILMENT_OUTCOME_NOT_FULFILLED` carries no `missing` limbs, and that is deliberate: a
|
|
35
|
+
* record from a party with standing saying the purpose was NOT met is a conclusion the
|
|
36
|
+
* verifier reached, not a gap in its evidence. Every other rejection names a limb.
|
|
37
|
+
*
|
|
38
|
+
* Concept source: aeoess/agent-authority-lifecycle, invariant candidate CAND-01 and
|
|
39
|
+
* invariant candidate BROAD-L7. Proposed.
|
|
40
|
+
*/
|
|
41
|
+
export declare function assessFulfilment(input: AssessFulfilmentInput): FulfilmentAssessment;
|
|
42
|
+
export interface EvaluateBoundInput {
|
|
43
|
+
readonly bound: AuthorityBound;
|
|
44
|
+
/** Every fulfilment claim the caller holds for this bound. Order is preserved in the
|
|
45
|
+
* result and does not change the verdict: see the resolution rule below. Empty for a
|
|
46
|
+
* `use_count` or `budget` bound, where no attestation is involved. */
|
|
47
|
+
readonly fulfilments?: readonly AuthorityBoundFulfilment[];
|
|
48
|
+
readonly atInstant: string;
|
|
49
|
+
readonly resolveAttestorRole?: AttestorRoleResolver;
|
|
50
|
+
readonly resolveVerificationKey?: BoundVerificationKeyResolver;
|
|
51
|
+
/** kind `use_count` only: admissions already counted against this bound, as a canonical
|
|
52
|
+
* unsigned decimal integer string. The caller's ledger owns this number. This module
|
|
53
|
+
* does not count admissions, because counting them means holding state across events and
|
|
54
|
+
* a pure function has none. */
|
|
55
|
+
readonly consumed?: string;
|
|
56
|
+
/** kind `budget` only: the committed and reserved totals, exactly as
|
|
57
|
+
* `InMemoryAuthorityBudgetLedger.counter(delegationId)` returns them. The budget kind
|
|
58
|
+
* delegates to that ledger and never reimplements it: draft-03 section 3.4 already
|
|
59
|
+
* states the rule, and the ledger already enforces it. */
|
|
60
|
+
readonly budgetCounter?: {
|
|
61
|
+
readonly committed: string;
|
|
62
|
+
readonly reserved: string;
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Evaluate one bound's state at one instant.
|
|
67
|
+
*
|
|
68
|
+
* THE RESOLUTION RULE, and why it is this way round. For a purpose bound:
|
|
69
|
+
*
|
|
70
|
+
* 1. If any fulfilment record was ACCEPTED, the state is `exhausted`.
|
|
71
|
+
* 2. Otherwise, if any record was rejected on an EVIDENTIAL ground (signature, standing,
|
|
72
|
+
* unresolved role, unresolved key, unreadable shape), the state is `not_established`.
|
|
73
|
+
* 3. Otherwise the state is `not_reached`.
|
|
74
|
+
*
|
|
75
|
+
* Step 1 comes before step 2 on purpose, and it is invariant CAND-02's rule made
|
|
76
|
+
* executable: an exhaustion that WAS established is never downgraded by a later claim
|
|
77
|
+
* nobody could authenticate. A later finding is a new record about an earlier one, never a
|
|
78
|
+
* rewrite of it. Because the rule is a fold over the whole set rather than a running
|
|
79
|
+
* mutation, the verdict is the same whatever order the records arrive in, which is what
|
|
80
|
+
* makes it safe for a caller to keep them in an unordered store.
|
|
81
|
+
*
|
|
82
|
+
* Step 3 reads `not_reached` from an empty record set, and that is the one reading here
|
|
83
|
+
* worth arguing with. It is a positive claim: the bound is declared, no evidence reaches
|
|
84
|
+
* it, and under the applicable authority model a purpose that nobody has recorded as met is
|
|
85
|
+
* a purpose that is not met. A model whose default runs the other way (absence of a
|
|
86
|
+
* periodic fulfilment report is itself the trigger) is a model this function cannot
|
|
87
|
+
* express, and a caller in that position should report `not_established` with a `source`
|
|
88
|
+
* limb rather than passing an empty set and reading the answer as a finding. CAND-01's
|
|
89
|
+
* carve-out for a declared default on absence is the reason the disclaimer is here and not
|
|
90
|
+
* a silent assumption.
|
|
91
|
+
*
|
|
92
|
+
* A `use_count` bound needs no records at all: the ADMISSION reaches it, so `consumed`
|
|
93
|
+
* against `value` is the whole computation. A `budget` bound is answered by the ledger's
|
|
94
|
+
* counter, per draft-03 section 3.4, verbatim: "Signatures establish static limits; they do
|
|
95
|
+
* not establish the current cumulative total."
|
|
96
|
+
*
|
|
97
|
+
* Reported ALONGSIDE a chain result, never merged into it, and never in place of it. A
|
|
98
|
+
* grant can be exhausted while its chain still verifies `valid`, which is the whole point:
|
|
99
|
+
* exhaustion is invisible to chain verification. A grant can also be expired AND exhausted,
|
|
100
|
+
* and then the chain result says `EXPIRED` and this says `exhaustion` and neither
|
|
101
|
+
* overwrites the other. Invariant L10.
|
|
102
|
+
*
|
|
103
|
+
* Concept source: aeoess/agent-authority-lifecycle, invariant L10 and invariant candidates
|
|
104
|
+
* CAND-01 and CAND-02. All proposed.
|
|
105
|
+
*/
|
|
106
|
+
export declare function evaluateBound(input: EvaluateBoundInput): BoundEvaluation;
|
|
107
|
+
//# sourceMappingURL=evaluate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluate.d.ts","sourceRoot":"","sources":["../../../../src/v2/bounds/evaluate.ts"],"names":[],"mappings":"AAYA,OAAO,EAKL,KAAK,kBAAkB,EACvB,KAAK,oBAAoB,EACzB,KAAK,cAAc,EACnB,KAAK,wBAAwB,EAE7B,KAAK,eAAe,EACpB,KAAK,SAAS,EAGd,KAAK,4BAA4B,EACjC,KAAK,oBAAoB,EAC1B,MAAM,YAAY,CAAA;AAEnB;;;2FAG2F;AAC3F,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IAErB,YAAY,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAIxC;CACF;AAMD,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAE9D;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,kBAAkB,CAIhF;AAED;iBACiB;AACjB,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,CAgDhE;AA+CD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAA;IAC9B,QAAQ,CAAC,MAAM,EAAE,wBAAwB,CAAA;IACzC;mFAC+E;IAC/E,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,mBAAmB,EAAE,oBAAoB,CAAA;IAClD,QAAQ,CAAC,sBAAsB,EAAE,4BAA4B,CAAA;CAC9D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,GAAG,oBAAoB,CAiFnF;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAA;IAC9B;;2EAEuE;IACvE,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,wBAAwB,EAAE,CAAA;IAC1D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,mBAAmB,CAAC,EAAE,oBAAoB,CAAA;IACnD,QAAQ,CAAC,sBAAsB,CAAC,EAAE,4BAA4B,CAAA;IAC9D;;;oCAGgC;IAChC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B;;;+DAG2D;IAC3D,QAAQ,CAAC,aAAa,CAAC,EAAE;QAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAA;CACnF;AAyBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,eAAe,CA6FxE"}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
// Copyright (c) 2026 Tymofii Pidlisnyi
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
//
|
|
4
|
+
// PROPOSED, OPT-IN. Assessing fulfilment records and evaluating a bound's state.
|
|
5
|
+
//
|
|
6
|
+
// Pure. No clock, no I/O, no network. Every instant compared here is supplied by the
|
|
7
|
+
// caller, and every resolver is the caller's. Not required by draft-pidlisnyi-aps-03; see
|
|
8
|
+
// ./types.ts for the specification position.
|
|
9
|
+
import { lifecycleState, notEstablished } from '../lifecycle-state/state.js';
|
|
10
|
+
import { verifyAuthorityBoundFulfilmentSignature } from './canonical.js';
|
|
11
|
+
import { AUTHORITY_BOUND_FULFILMENT_TYPE, AUTHORITY_BOUND_TYPE, ATTESTOR_ROLE_ANSWERS, BOUND_KINDS, } from './types.js';
|
|
12
|
+
/** Thrown when an input this module cannot read at all is passed. A malformed BOUND is a
|
|
13
|
+
* programming error, not a verdict: the module was asked a question about nothing. A
|
|
14
|
+
* malformed FULFILMENT RECORD is different and never throws, because a record somebody
|
|
15
|
+
* else wrote is data, and the right answer about it is a rejection with a reason code. */
|
|
16
|
+
export class AuthorityBoundError extends Error {
|
|
17
|
+
code;
|
|
18
|
+
constructor(code, message) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.name = 'AuthorityBoundError';
|
|
21
|
+
this.code = code;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const CANONICAL_UNSIGNED_INTEGER = /^(0|[1-9][0-9]*)$/;
|
|
25
|
+
const DELEGATION_ID = /^sha256:[0-9a-f]{64}$/;
|
|
26
|
+
const SIGNATURE_HEX = /^[0-9a-f]{128}$/;
|
|
27
|
+
export function isBoundKind(value) {
|
|
28
|
+
return typeof value === 'string' && BOUND_KINDS.includes(value);
|
|
29
|
+
}
|
|
30
|
+
export function isAttestorRoleAnswer(value) {
|
|
31
|
+
return (typeof value === 'string' && ATTESTOR_ROLE_ANSWERS.includes(value));
|
|
32
|
+
}
|
|
33
|
+
/** Shape check for a bound declaration. Throws, for the reason `AuthorityBoundError`
|
|
34
|
+
* documents. */
|
|
35
|
+
export function assertAuthorityBound(bound) {
|
|
36
|
+
if (bound === null || typeof bound !== 'object') {
|
|
37
|
+
throw new AuthorityBoundError('BOUND_MALFORMED', 'bound is not an object');
|
|
38
|
+
}
|
|
39
|
+
if (bound.record_type !== AUTHORITY_BOUND_TYPE) {
|
|
40
|
+
throw new AuthorityBoundError('BOUND_RECORD_TYPE_UNSUPPORTED', `record_type must be ${AUTHORITY_BOUND_TYPE}`);
|
|
41
|
+
}
|
|
42
|
+
if (typeof bound.bound_id !== 'string' || bound.bound_id.length === 0) {
|
|
43
|
+
throw new AuthorityBoundError('BOUND_MALFORMED', 'bound_id must be a non-empty string');
|
|
44
|
+
}
|
|
45
|
+
if (typeof bound.delegation_id !== 'string' || !DELEGATION_ID.test(bound.delegation_id)) {
|
|
46
|
+
throw new AuthorityBoundError('BOUND_MALFORMED', 'delegation_id must be sha256:<64 lowercase hex>');
|
|
47
|
+
}
|
|
48
|
+
if (!isBoundKind(bound.kind)) {
|
|
49
|
+
throw new AuthorityBoundError('BOUND_KIND_UNSUPPORTED', `kind must be one of ${BOUND_KINDS.join(', ')}`);
|
|
50
|
+
}
|
|
51
|
+
if (typeof bound.value !== 'string' || bound.value.length === 0) {
|
|
52
|
+
throw new AuthorityBoundError('BOUND_MALFORMED', 'value must be a non-empty string');
|
|
53
|
+
}
|
|
54
|
+
if (bound.kind !== 'purpose' && !CANONICAL_UNSIGNED_INTEGER.test(bound.value)) {
|
|
55
|
+
throw new AuthorityBoundError('BOUND_VALUE_NONCANONICAL', `a ${bound.kind} bound's value must be a canonical unsigned decimal integer`);
|
|
56
|
+
}
|
|
57
|
+
if (!Array.isArray(bound.fulfilment_attestor_roles)) {
|
|
58
|
+
throw new AuthorityBoundError('BOUND_MALFORMED', 'fulfilment_attestor_roles must be an array, empty if nobody but the issuer may attest');
|
|
59
|
+
}
|
|
60
|
+
for (const role of bound.fulfilment_attestor_roles) {
|
|
61
|
+
if (typeof role !== 'string' || role.length === 0) {
|
|
62
|
+
throw new AuthorityBoundError('BOUND_MALFORMED', 'fulfilment_attestor_roles must contain only non-empty strings');
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/** True only for a record this module can read far enough to assess. A record that fails
|
|
67
|
+
* here is rejected with `FULFILMENT_SCHEMA_INVALID`, never thrown on. */
|
|
68
|
+
function readableFulfilment(record) {
|
|
69
|
+
return (record !== null &&
|
|
70
|
+
typeof record === 'object' &&
|
|
71
|
+
record.record_type === AUTHORITY_BOUND_FULFILMENT_TYPE &&
|
|
72
|
+
typeof record.bound_id === 'string' &&
|
|
73
|
+
record.bound_id.length > 0 &&
|
|
74
|
+
typeof record.delegation_id === 'string' &&
|
|
75
|
+
DELEGATION_ID.test(record.delegation_id) &&
|
|
76
|
+
typeof record.attestor === 'string' &&
|
|
77
|
+
record.attestor.length > 0 &&
|
|
78
|
+
typeof record.verification_method === 'string' &&
|
|
79
|
+
record.verification_method.length > 0 &&
|
|
80
|
+
typeof record.attested_at === 'string' &&
|
|
81
|
+
record.attested_at.length > 0 &&
|
|
82
|
+
(record.outcome === 'fulfilled' || record.outcome === 'not_fulfilled') &&
|
|
83
|
+
typeof record.reason_code === 'string' &&
|
|
84
|
+
record.reason_code.length > 0 &&
|
|
85
|
+
typeof record.signature === 'string' &&
|
|
86
|
+
SIGNATURE_HEX.test(record.signature));
|
|
87
|
+
}
|
|
88
|
+
function assessment(attestor, attestedAt, accepted, reasonCode, extra = {}) {
|
|
89
|
+
const out = { attestor, attested_at: attestedAt, accepted, reason_code: reasonCode };
|
|
90
|
+
if (extra.role_answer !== undefined)
|
|
91
|
+
out.role_answer = extra.role_answer;
|
|
92
|
+
if (extra.missing !== undefined)
|
|
93
|
+
out.missing = Object.freeze([...extra.missing]);
|
|
94
|
+
return Object.freeze(out);
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Assess ONE fulfilment record against one bound.
|
|
98
|
+
*
|
|
99
|
+
* The order of the checks is the substance of this function, not an implementation detail.
|
|
100
|
+
* Standing is asked FIRST and authenticity SECOND, and each produces its own code, because
|
|
101
|
+
* "authenticated by somebody who may not say this" and "not authenticated at all" are
|
|
102
|
+
* different failures and collapsing them loses the distinction CAND-01 turns on. A valid
|
|
103
|
+
* signature establishes who signed. It does not establish that the signer was allowed to
|
|
104
|
+
* make this statement.
|
|
105
|
+
*
|
|
106
|
+
* `FULFILMENT_OUTCOME_NOT_FULFILLED` carries no `missing` limbs, and that is deliberate: a
|
|
107
|
+
* record from a party with standing saying the purpose was NOT met is a conclusion the
|
|
108
|
+
* verifier reached, not a gap in its evidence. Every other rejection names a limb.
|
|
109
|
+
*
|
|
110
|
+
* Concept source: aeoess/agent-authority-lifecycle, invariant candidate CAND-01 and
|
|
111
|
+
* invariant candidate BROAD-L7. Proposed.
|
|
112
|
+
*/
|
|
113
|
+
export function assessFulfilment(input) {
|
|
114
|
+
assertAuthorityBound(input.bound);
|
|
115
|
+
const { bound, record, atInstant } = input;
|
|
116
|
+
if (bound.kind !== 'purpose') {
|
|
117
|
+
return assessment('', '', false, 'FULFILMENT_NOT_APPLICABLE_TO_KIND', {
|
|
118
|
+
missing: ['coverage'],
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
if (!readableFulfilment(record)) {
|
|
122
|
+
return assessment('', '', false, 'FULFILMENT_SCHEMA_INVALID', { missing: ['source'] });
|
|
123
|
+
}
|
|
124
|
+
const attestor = record.attestor;
|
|
125
|
+
const attestedAt = record.attested_at;
|
|
126
|
+
// The record has to be about THIS bound on THIS delegation. A coverage gap: the claim does
|
|
127
|
+
// not state that it covers what the verdict needed.
|
|
128
|
+
if (record.bound_id !== bound.bound_id || record.delegation_id !== bound.delegation_id) {
|
|
129
|
+
return assessment(attestor, attestedAt, false, 'FULFILMENT_NOT_BOUND_TO_BOUND', {
|
|
130
|
+
missing: ['coverage'],
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
if (attestedAt > atInstant) {
|
|
134
|
+
return assessment(attestor, attestedAt, false, 'FULFILMENT_NOT_YET_ATTESTED', {
|
|
135
|
+
missing: ['coverage'],
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
const roleAnswer = input.resolveAttestorRole(attestor, bound.fulfilment_attestor_roles, atInstant);
|
|
139
|
+
if (!isAttestorRoleAnswer(roleAnswer)) {
|
|
140
|
+
return assessment(attestor, attestedAt, false, 'FULFILMENT_ATTESTOR_ROLE_UNKNOWN', {
|
|
141
|
+
missing: ['source'],
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
if (roleAnswer === 'unknown') {
|
|
145
|
+
return assessment(attestor, attestedAt, false, 'FULFILMENT_ATTESTOR_ROLE_UNKNOWN', {
|
|
146
|
+
role_answer: roleAnswer,
|
|
147
|
+
missing: ['source'],
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
if (roleAnswer === 'does_not_hold_role') {
|
|
151
|
+
return assessment(attestor, attestedAt, false, 'FULFILMENT_ATTESTOR_WITHOUT_STANDING', {
|
|
152
|
+
role_answer: roleAnswer,
|
|
153
|
+
missing: ['source'],
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
const publicKey = input.resolveVerificationKey(attestor, record.verification_method, attestedAt);
|
|
157
|
+
if (typeof publicKey !== 'string' || publicKey.length === 0) {
|
|
158
|
+
return assessment(attestor, attestedAt, false, 'FULFILMENT_KEY_UNRESOLVED', {
|
|
159
|
+
role_answer: roleAnswer,
|
|
160
|
+
missing: ['source'],
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
if (!verifyAuthorityBoundFulfilmentSignature(record, publicKey)) {
|
|
164
|
+
return assessment(attestor, attestedAt, false, 'FULFILMENT_SIGNATURE_INVALID', {
|
|
165
|
+
role_answer: roleAnswer,
|
|
166
|
+
missing: ['source'],
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
if (record.outcome !== 'fulfilled') {
|
|
170
|
+
return assessment(attestor, attestedAt, false, 'FULFILMENT_OUTCOME_NOT_FULFILLED', {
|
|
171
|
+
role_answer: roleAnswer,
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
return assessment(attestor, attestedAt, true, 'FULFILMENT_ACCEPTED', {
|
|
175
|
+
role_answer: roleAnswer,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
function decimal(value, fallback) {
|
|
179
|
+
const raw = value ?? fallback;
|
|
180
|
+
if (!CANONICAL_UNSIGNED_INTEGER.test(raw)) {
|
|
181
|
+
throw new AuthorityBoundError('COUNTER_NONCANONICAL', `expected a canonical unsigned decimal integer, got ${JSON.stringify(raw)}`);
|
|
182
|
+
}
|
|
183
|
+
return BigInt(raw);
|
|
184
|
+
}
|
|
185
|
+
function lifecycleFor(state, reasonCode, missing) {
|
|
186
|
+
if (state === 'not_established')
|
|
187
|
+
return notEstablished(missing, reasonCode);
|
|
188
|
+
return lifecycleState({
|
|
189
|
+
verdict: state === 'exhausted' ? 'invalid' : 'valid',
|
|
190
|
+
reason_code: reasonCode,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Evaluate one bound's state at one instant.
|
|
195
|
+
*
|
|
196
|
+
* THE RESOLUTION RULE, and why it is this way round. For a purpose bound:
|
|
197
|
+
*
|
|
198
|
+
* 1. If any fulfilment record was ACCEPTED, the state is `exhausted`.
|
|
199
|
+
* 2. Otherwise, if any record was rejected on an EVIDENTIAL ground (signature, standing,
|
|
200
|
+
* unresolved role, unresolved key, unreadable shape), the state is `not_established`.
|
|
201
|
+
* 3. Otherwise the state is `not_reached`.
|
|
202
|
+
*
|
|
203
|
+
* Step 1 comes before step 2 on purpose, and it is invariant CAND-02's rule made
|
|
204
|
+
* executable: an exhaustion that WAS established is never downgraded by a later claim
|
|
205
|
+
* nobody could authenticate. A later finding is a new record about an earlier one, never a
|
|
206
|
+
* rewrite of it. Because the rule is a fold over the whole set rather than a running
|
|
207
|
+
* mutation, the verdict is the same whatever order the records arrive in, which is what
|
|
208
|
+
* makes it safe for a caller to keep them in an unordered store.
|
|
209
|
+
*
|
|
210
|
+
* Step 3 reads `not_reached` from an empty record set, and that is the one reading here
|
|
211
|
+
* worth arguing with. It is a positive claim: the bound is declared, no evidence reaches
|
|
212
|
+
* it, and under the applicable authority model a purpose that nobody has recorded as met is
|
|
213
|
+
* a purpose that is not met. A model whose default runs the other way (absence of a
|
|
214
|
+
* periodic fulfilment report is itself the trigger) is a model this function cannot
|
|
215
|
+
* express, and a caller in that position should report `not_established` with a `source`
|
|
216
|
+
* limb rather than passing an empty set and reading the answer as a finding. CAND-01's
|
|
217
|
+
* carve-out for a declared default on absence is the reason the disclaimer is here and not
|
|
218
|
+
* a silent assumption.
|
|
219
|
+
*
|
|
220
|
+
* A `use_count` bound needs no records at all: the ADMISSION reaches it, so `consumed`
|
|
221
|
+
* against `value` is the whole computation. A `budget` bound is answered by the ledger's
|
|
222
|
+
* counter, per draft-03 section 3.4, verbatim: "Signatures establish static limits; they do
|
|
223
|
+
* not establish the current cumulative total."
|
|
224
|
+
*
|
|
225
|
+
* Reported ALONGSIDE a chain result, never merged into it, and never in place of it. A
|
|
226
|
+
* grant can be exhausted while its chain still verifies `valid`, which is the whole point:
|
|
227
|
+
* exhaustion is invisible to chain verification. A grant can also be expired AND exhausted,
|
|
228
|
+
* and then the chain result says `EXPIRED` and this says `exhaustion` and neither
|
|
229
|
+
* overwrites the other. Invariant L10.
|
|
230
|
+
*
|
|
231
|
+
* Concept source: aeoess/agent-authority-lifecycle, invariant L10 and invariant candidates
|
|
232
|
+
* CAND-01 and CAND-02. All proposed.
|
|
233
|
+
*/
|
|
234
|
+
export function evaluateBound(input) {
|
|
235
|
+
assertAuthorityBound(input.bound);
|
|
236
|
+
const { bound } = input;
|
|
237
|
+
if (typeof input.atInstant !== 'string' || input.atInstant.length === 0) {
|
|
238
|
+
throw new AuthorityBoundError('INSTANT_MISSING', 'atInstant must be a non-empty string');
|
|
239
|
+
}
|
|
240
|
+
const assessments = [];
|
|
241
|
+
let state;
|
|
242
|
+
let reasonCode;
|
|
243
|
+
let remaining;
|
|
244
|
+
const missing = [];
|
|
245
|
+
if (bound.kind === 'purpose') {
|
|
246
|
+
const records = input.fulfilments ?? [];
|
|
247
|
+
if (records.length > 0) {
|
|
248
|
+
if (typeof input.resolveAttestorRole !== 'function') {
|
|
249
|
+
throw new AuthorityBoundError('ROLE_RESOLVER_MISSING', 'a purpose bound with fulfilment records needs resolveAttestorRole');
|
|
250
|
+
}
|
|
251
|
+
if (typeof input.resolveVerificationKey !== 'function') {
|
|
252
|
+
throw new AuthorityBoundError('KEY_RESOLVER_MISSING', 'a purpose bound with fulfilment records needs resolveVerificationKey');
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
const resolveAttestorRole = input.resolveAttestorRole ?? (() => 'unknown');
|
|
256
|
+
const resolveVerificationKey = input.resolveVerificationKey ?? (() => null);
|
|
257
|
+
for (const record of records) {
|
|
258
|
+
assessments.push(assessFulfilment({
|
|
259
|
+
bound,
|
|
260
|
+
record,
|
|
261
|
+
atInstant: input.atInstant,
|
|
262
|
+
resolveAttestorRole,
|
|
263
|
+
resolveVerificationKey,
|
|
264
|
+
}));
|
|
265
|
+
}
|
|
266
|
+
const accepted = assessments.some(a => a.accepted);
|
|
267
|
+
const unestablished = assessments.filter(a => !a.accepted && a.missing !== undefined);
|
|
268
|
+
if (accepted) {
|
|
269
|
+
state = 'exhausted';
|
|
270
|
+
reasonCode = 'PURPOSE_EXHAUSTED';
|
|
271
|
+
}
|
|
272
|
+
else if (unestablished.length > 0) {
|
|
273
|
+
state = 'not_established';
|
|
274
|
+
reasonCode = 'BOUND_STATE_NOT_ESTABLISHED';
|
|
275
|
+
for (const a of unestablished) {
|
|
276
|
+
for (const gap of a.missing ?? [])
|
|
277
|
+
if (!missing.includes(gap))
|
|
278
|
+
missing.push(gap);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
else {
|
|
282
|
+
state = 'not_reached';
|
|
283
|
+
reasonCode = 'BOUND_NOT_REACHED';
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
else if (bound.kind === 'use_count') {
|
|
287
|
+
const limit = decimal(bound.value, '0');
|
|
288
|
+
const consumed = decimal(input.consumed, '0');
|
|
289
|
+
const left = consumed >= limit ? 0n : limit - consumed;
|
|
290
|
+
remaining = left.toString(10);
|
|
291
|
+
state = consumed >= limit ? 'exhausted' : 'not_reached';
|
|
292
|
+
reasonCode = state === 'exhausted' ? 'USE_COUNT_EXHAUSTED' : 'BOUND_NOT_REACHED';
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
const ceiling = decimal(bound.value, '0');
|
|
296
|
+
const committed = decimal(input.budgetCounter?.committed, '0');
|
|
297
|
+
const reserved = decimal(input.budgetCounter?.reserved, '0');
|
|
298
|
+
state = committed + reserved >= ceiling ? 'exhausted' : 'not_reached';
|
|
299
|
+
reasonCode = state === 'exhausted' ? 'BUDGET_EXHAUSTED' : 'BOUND_NOT_REACHED';
|
|
300
|
+
}
|
|
301
|
+
const ending = state === 'exhausted' ? 'exhaustion' : null;
|
|
302
|
+
const result = {
|
|
303
|
+
bound_id: bound.bound_id,
|
|
304
|
+
kind: bound.kind,
|
|
305
|
+
bound_state: state,
|
|
306
|
+
reason_code: reasonCode,
|
|
307
|
+
ending,
|
|
308
|
+
lifecycle: lifecycleFor(state, reasonCode, missing.length > 0 ? missing : ['source']),
|
|
309
|
+
fulfilments: Object.freeze([...assessments]),
|
|
310
|
+
};
|
|
311
|
+
if (remaining !== undefined)
|
|
312
|
+
result.remaining = remaining;
|
|
313
|
+
return Object.freeze(result);
|
|
314
|
+
}
|
|
315
|
+
//# sourceMappingURL=evaluate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluate.js","sourceRoot":"","sources":["../../../../src/v2/bounds/evaluate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/v2/bounds/index.ts"],"names":[],"mappings":"AAQA,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,eAAe,CAAA;AAC7B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Copyright (c) 2026 Tymofii Pidlisnyi
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
//
|
|
4
|
+
// PROPOSED, OPT-IN. Non-time bounds on a grant: purpose, use count and budget.
|
|
5
|
+
// Nothing here is required by draft-pidlisnyi-aps-03 and nothing here changes any existing
|
|
6
|
+
// exported behaviour. Concept source: aeoess/agent-authority-lifecycle, invariant L10 and
|
|
7
|
+
// invariant candidates CAND-01 and CAND-02. See ./types.ts.
|
|
8
|
+
export * from './types.js';
|
|
9
|
+
export * from './canonical.js';
|
|
10
|
+
export * from './evaluate.js';
|
|
11
|
+
export * from './record.js';
|
|
12
|
+
export * from './purpose.js';
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/v2/bounds/index.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,sCAAsC;AACtC,EAAE;AACF,+EAA+E;AAC/E,2FAA2F;AAC3F,0FAA0F;AAC1F,4DAA4D;AAE5D,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,eAAe,CAAA;AAC7B,cAAc,aAAa,CAAA;AAC3B,cAAc,cAAc,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"purpose.d.ts","sourceRoot":"","sources":["../../../../src/v2/bounds/purpose.ts"],"names":[],"mappings":"AAsBA,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
// Copyright (c) 2026 Tymofii Pidlisnyi
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
//
|
|
4
|
+
// PROPOSED module, but these two functions are NOT new and NOT proposed. They are the
|
|
5
|
+
// hierarchical purpose helpers that have shipped in `src/core/data-lifecycle.ts` since
|
|
6
|
+
// before this module existed, re-exported here so that both reference SDKs agree on where
|
|
7
|
+
// purpose membership lives.
|
|
8
|
+
//
|
|
9
|
+
// WHY THE RE-EXPORT. The Python SDK had no port of either function. Adding them there under
|
|
10
|
+
// a `data_lifecycle` module, to hold two functions, would have put the same primitive at two
|
|
11
|
+
// unrelated paths in the two languages, which becomes a cross-language test annoyance the
|
|
12
|
+
// first time a vector references it. Both SDKs now expose them from the bounds module, and
|
|
13
|
+
// the TypeScript original stays exported from its old path too, so nothing that imports it
|
|
14
|
+
// today changes.
|
|
15
|
+
//
|
|
16
|
+
// PURPOSE MEMBERSHIP IS NOT PURPOSE EXHAUSTION, and the distinction is the reason this file
|
|
17
|
+
// carries a comment at all. `isPurposePermitted` answers whether a requested purpose falls
|
|
18
|
+
// inside a set of allowed purposes. It answers `true` for the second compressor purchase
|
|
19
|
+
// exactly as it does for the first. Membership can therefore never decide exhaustion, and a
|
|
20
|
+
// boundary that checks only membership is the defective implementation the purpose-bound
|
|
21
|
+
// case corpus exists to catch. `evaluateBound` is the exhaustion question.
|
|
22
|
+
export { isPurposePermitted, purposeCategory } from '../../core/data-lifecycle.js';
|
|
23
|
+
//# sourceMappingURL=purpose.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"purpose.js","sourceRoot":"","sources":["../../../../src/v2/bounds/purpose.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,sCAAsC;AACtC,EAAE;AACF,sFAAsF;AACtF,uFAAuF;AACvF,0FAA0F;AAC1F,4BAA4B;AAC5B,EAAE;AACF,4FAA4F;AAC5F,6FAA6F;AAC7F,0FAA0F;AAC1F,2FAA2F;AAC3F,2FAA2F;AAC3F,iBAAiB;AACjB,EAAE;AACF,4FAA4F;AAC5F,2FAA2F;AAC3F,yFAAyF;AACzF,4FAA4F;AAC5F,yFAAyF;AACzF,2EAA2E;AAE3E,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAA"}
|