chainlesschain 0.166.16 → 0.166.17
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 +3 -3
- package/completions/_cc +1 -1
- package/completions/cc.bash +1 -1
- package/completions/cc.fish +1 -1
- package/completions/cc.ps1 +1 -1
- package/package.json +2 -2
- package/src/assets/web-panel/assets/{AIOps-CTxa2Wbq.js → AIOps-CVW2n2rh.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DHrQyYhy.js → ActionButton-DtuM163O.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DQiUqcNl.js → Analytics-BXvl_qHu.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-_Iz4r6wt.js → AppLayout-VDBTFKOp.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-BNs63YHo.js → Artifacts-BNz2xCiG.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-BgHIqRLn.js → Audit-DTu9Hn9P.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-DUQ5axBB.js → BackgroundAgents-D2OCPzLe.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CJ51E9Vw.js → Backup-C9M-vG7G.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-o-5toA_R.js → BaseInput-BUkCNiUQ.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-Cu7a-x1L.js → Chat-OJ2ajF7l.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-BUyYkAXr.js → ChatBubbleRenderer-BdZt76Ab.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-DwdmZ71L.js → Checkbox-C1gXKDsc.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BrH2eYiP.js → Codegen-BXbznLg7.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BVJQEP2j.js → Col-CbCq5N0i.js} +1 -1
- package/src/assets/web-panel/assets/{Community-FGO3vZPq.js → Community-V8Ks6Yun.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DYGAFVnT.js → Compact-DkeHQTpQ.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-CRvc8Bdt.js → Compliance-JeLKwn4Q.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-D6Ah2m7A.js → Cowork-azfetcBz.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-AXbU2ifR.js → Cron-Q691i_Gp.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-C5DXgEFd.js → Crosschain-BLjDRbr_.js} +1 -1
- package/src/assets/web-panel/assets/{DID-Bxh9QV9v.js → DID-D8ptXplK.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-B-ZHEta-.js → Dashboard-Ctj2VVZL.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-66Ik1jqa.js → Dropdown-D8VgkMJ8.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CCWk1BIM.js → EmailListRenderer-CQPe5S6q.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard--9faIULK.js → FamilyGuardDashboard-ySA-7SiN.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-CejW9CgX.js → Federation-1PMD-fBf.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-acHgcXki.js → FormItemContext-C_jr6U4Q.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-D2ghd_K4.js → GenericCardRenderer-Bu3bKf2B.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BOe1YJrV.js → Git-Dv4Fa_T5.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BjgzJsof.js → Governance-DOEy1n1k.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CXCD5rnP.js → Inference-DkvqzWcJ.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-CHA8QgJT.js → KnowledgeGraph-DdUJK949.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-DORPMcL6.js → Logs-CRelcdUZ.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-CPPHz01z.js → MarkdownRenderer-0AHbbTA4.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-BCFlo1Yx.js → Marketplace-BuuBKsev.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-Dl_uZAKh.js → McpTools-DlgpEmA1.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-DupHamwz.js → Memory-DTfdqUGy.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-BRSMPJxW.js → MobileBridge-CXLE5ZFO.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-BHpuzsDl.js → MobileProjects-Dz25OB0n.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-Ch0jOQfZ.js → Mtc-kEL0fhgD.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-qzwQrDi7.js → MtcAudit-BE4UvFJU.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-B5wHzUcm.js → Multisig-CSApSn8c.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Hy9uAiA0.js → NLProgramming-D11FpKWx.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-DkuchMC7.js → Notes-CDL-D2CS.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-CYZhD7Pi.js → NotificationSettings-C0Q6lO-c.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-ZRE0OKbj.js +1 -0
- package/src/assets/web-panel/assets/{Organization-D9AXn6j8.js → Organization-Dc-maVAq.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Bg15J6hX.js → Overflow-B5mUpSvi.js} +1 -1
- package/src/assets/web-panel/assets/{P2P--B54HoQn.js → P2P-TjXV53wq.js} +2 -2
- package/src/assets/web-panel/assets/PdhVaultBrowser-DvV2btIr.js +7 -0
- package/src/assets/web-panel/assets/{Permissions-DHx38eS1.js → Permissions-DKRzQ2O6.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-Dw8i2hAs.js → PersonalDataHub-Dx2eqft8.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-B2o6Ur2G.js → Pipeline-CnYZMB5p.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-8g-h2fnu.js → Privacy-BonKpPnp.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-DuVTcINx.js → ProjectInit-DWO0Du3J.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-C8njvdZX.js → ProjectSettings-C9jqyYRv.js} +2 -2
- package/src/assets/web-panel/assets/Projects-CYpKwXbz.js +1 -0
- package/src/assets/web-panel/assets/{Providers-wFqgod_W.js → Providers-CW-fkwJq.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-9NCXrpmA.js → QrScannerModal-Cw0J3Zud.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-WUTNvFkY.js → QuickAsk-BH4A4IpR.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-xT4nYmju.js → Recommend-CDwMwJus.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-fak1PBGC.js → RemoteSession-DKIPwzTf.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-D1AkQvD-.js → Reputation-CklDj7qS.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DVfm6xGt.js → Row-DJWZKsH0.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BDunoLSE.js → RssFeed-BfSLCewo.js} +2 -2
- package/src/assets/web-panel/assets/{Search-OPycRoU3.js → Search-B0IST--x.js} +1 -1
- package/src/assets/web-panel/assets/{Security-C8-Fm3Dt.js → Security-h1sYNWtt.js} +3 -3
- package/src/assets/web-panel/assets/{Services-qM_sMpMl.js → Services-Gh0-oxI_.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-D3HBJjVF.js → Skeleton-CNDV_jOs.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-jr67X-tP.js → Skills-ByCLTh1n.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CS3ggyCg.js → Sla-BfyrJTJz.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-CTOCYxOi.js → SpeechSettings-BQzo9kNX.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-D3s3cLT5.js → SyncSettings-B6fS6z_1.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-CdfoJ25m.js → Tasks-C-uKCP-l.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-Drb4AI8X.js → Templates-D6oDy7wL.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DzwR3Qkz.js → Tenant-D3LT2wNQ.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-D-ESq7xp.js → Terminal-BteLcv_O.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-BK-AUuws.js → TimelineRenderer-DHHuxfqH.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-xGTouuNp.js → Tokens-BRQeykXw.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BvZj-v2H.js → Trigger-p2XaFWEu.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-BLC9CGmc.js → Trust-BxadBMft.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-BSuCXpmE.js → UkeySign-DRBP7LDk.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-DT3A-_Ql.js → VideoEditing-CZ3NZkh7.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-c1OXao85.js → Wallet-C3NTBN7G.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-CuA-F7KJ.js → WebAuthn-C7LVgMlb.js} +2 -2
- package/src/assets/web-panel/assets/{WorkflowEditor-MANZrf82.js → WorkflowEditor-0_Iveog7.js} +1 -1
- package/src/assets/web-panel/assets/{chat-D4Y4Ey0O.js → chat-DzzluYo3.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DDH06hKO.js → colors-DSMYXpaj.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-Cym756Xj.js → compact-item-W76u1VSV.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-By4Nb1k-.js → createContext-otsESjb5.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BztaXF84.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-Ch7OY258.js → hasIn-3sNLrvug.js} +1 -1
- package/src/assets/web-panel/assets/index-4jP_hG_4.js +1 -0
- package/src/assets/web-panel/assets/{index-DtGValNi.js → index-B1I1AYJs.js} +1 -1
- package/src/assets/web-panel/assets/{index-B51otVoZ.js → index-B5LOYdYm.js} +1 -1
- package/src/assets/web-panel/assets/{index-BBBUn5v7.js → index-B9X_jqXe.js} +1 -1
- package/src/assets/web-panel/assets/{index-6CpOV3Pn.js → index-BA8mZxd-.js} +1 -1
- package/src/assets/web-panel/assets/{index-CUSUzaB8.js → index-BDlDO2px.js} +1 -1
- package/src/assets/web-panel/assets/{index-oBsfUbyH.js → index-BJsQio5O.js} +1 -1
- package/src/assets/web-panel/assets/{index-q-s04OKn.js → index-BRsD1PT2.js} +1 -1
- package/src/assets/web-panel/assets/{index-XGeQMvWK.js → index-BXLx9HfA.js} +1 -1
- package/src/assets/web-panel/assets/{index-CjNUTBwe.js → index-BcGJtmHM.js} +1 -1
- package/src/assets/web-panel/assets/{index-D9le0-dc.js → index-BdtmEKat.js} +1 -1
- package/src/assets/web-panel/assets/{index-mL3nOcH6.js → index-BpcQYzP7.js} +1 -1
- package/src/assets/web-panel/assets/{index-BZB9q-Lp.js → index-C2aht9-M.js} +1 -1
- package/src/assets/web-panel/assets/{index-CF3Lhyns.js → index-CE7tSow-.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZn6dmZe.js → index-CENWwjef.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bo20BfdS.js → index-CKoFyHYQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-tZ5BUdad.js → index-Cg86EzNp.js} +1 -1
- package/src/assets/web-panel/assets/{index-CT-3FYwd.js → index-ClOFeZ-t.js} +1 -1
- package/src/assets/web-panel/assets/{index-6-2eYBXr.js → index-CtFOt5x1.js} +1 -1
- package/src/assets/web-panel/assets/{index-DvnywwUj.js → index-D7A5U2IH.js} +1 -1
- package/src/assets/web-panel/assets/{index-CGsvEbbq.js → index-DH4cl52p.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJPks33Y.js → index-DLDh1OW3.js} +1 -1
- package/src/assets/web-panel/assets/{index-CV8qXTvb.js → index-DMmdIpLA.js} +1 -1
- package/src/assets/web-panel/assets/{index-CykROEJA.js → index-DS9WYDMf.js} +1 -1
- package/src/assets/web-panel/assets/{index-jx7kr6mB.js → index-DTA8Iavv.js} +3 -3
- package/src/assets/web-panel/assets/{index-CpudmDhf.js → index-DZKAzEge.js} +1 -1
- package/src/assets/web-panel/assets/{index-DAkk1M7x.js → index-DdU7IkKX.js} +1 -1
- package/src/assets/web-panel/assets/{index-DNlxihs8.js → index-Ddd4mird.js} +1 -1
- package/src/assets/web-panel/assets/{index-BIrRX-ra.js → index-DmpaC2yk.js} +1 -1
- package/src/assets/web-panel/assets/{index-CV1UC4zo.js → index-GlIOE4ja.js} +1 -1
- package/src/assets/web-panel/assets/{index-ArMrnx0v.js → index-MhQQ3h8q.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjwgJ5Jd.js → index-NaO9AE-F.js} +1 -1
- package/src/assets/web-panel/assets/{index-DNEJzc0r.js → index-UUHCwfNq.js} +1 -1
- package/src/assets/web-panel/assets/{index-BFydNU6a.js → index-pVm_iUre.js} +1 -1
- package/src/assets/web-panel/assets/{index-ZY2Qs_Sn.js → index-q7ftLqNt.js} +1 -1
- package/src/assets/web-panel/assets/{index-D5sADPGY.js → index-uSCkbpZH.js} +1 -1
- package/src/assets/web-panel/assets/{index-DiewptTL.js → index-vBKPcmAP.js} +1 -1
- package/src/assets/web-panel/assets/{index-OU8DZ9BL.js → index-vUmYkqmu.js} +1 -1
- package/src/assets/web-panel/assets/index-zxwuAXL5.js +1 -0
- package/src/assets/web-panel/assets/{initDefaultProps-DGcX9iPP.js → initDefaultProps-DF6llUXV.js} +1 -1
- package/src/assets/web-panel/assets/{motion-2SeL1D8A.js → motion-vtDV8_5K.js} +1 -1
- package/src/assets/web-panel/assets/{move-3cYbQCpS.js → move-B6c0bdy2.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-IDdxfw0z.js → mtc-parser-DlLYWuBK.js} +1 -1
- package/src/assets/web-panel/assets/{omit-BNswdKO6.js → omit-BH0zOxLN.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-BwCnem2I.js → pickAttrs-D9di8_In.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-B9PtZ5rq.js → placementArrow-BDSngufM.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-CPB6iSzV.js → responsiveObserve-C_EawMvP.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DZgyblZa.js → slide-B_4wShxA.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-D82IBdsx.js → statusUtils-CbQu6qJ-.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-qSHtosM-.js → styleChecker-CvXJWYXb.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CmWO7h0I.js → useFlexGapSupport-jjY1XknO.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-yLrs_ub4.js → useFs-CMXBdsK_.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CJ1VW6rh.js → usePersonalDataHub-YbAhhPXx.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CzY_moQ4.js → vnode-BFCTKc0H.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DAa7rEY5.js → zoom-CY9aBl5O.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +2 -2
- package/src/command-manifest.json +2 -2
- package/src/commands/evolution.js +30 -17
- package/src/commands/learning.js +24 -8
- package/src/data/changelog.json +13 -0
- package/src/lib/evolution/bounded-skill-improvement-pilot.js +498 -0
- package/src/lib/evolution/evolution-run-runtime-adapter.js +5 -0
- package/src/lib/evolution/skill-evaluated-promotion-durability.js +899 -0
- package/src/lib/evolution/skill-evaluated-promotion.js +481 -0
- package/src/lib/evolution/skill-promotion-controller.js +114 -2
- package/src/lib/evolution/wiki-informed-skill-proposer.js +343 -0
- package/src/lib/graph-kernel/evolution-run-runtime-adapter.js +5 -0
- package/src/lib/hooks-v2-runtime.js +20 -0
- package/src/runtime/agent-core.js +68 -0
- package/src/assets/web-panel/assets/OrderTableRenderer-DKOoqajt.js +0 -1
- package/src/assets/web-panel/assets/PdhVaultBrowser-Cz9Kk2Nb.js +0 -7
- package/src/assets/web-panel/assets/Projects-Ca9BAfu7.js +0 -1
- package/src/assets/web-panel/assets/devWarning-KO3pAGeO.js +0 -1
- package/src/assets/web-panel/assets/index-Bh4Rgkg2.js +0 -1
- package/src/assets/web-panel/assets/index-Dox_coTY.js +0 -1
|
@@ -0,0 +1,899 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { types as utilTypes } from "node:util";
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
SKILL_EVALUATED_PROMOTION_RECEIPT_RESOLUTION_REQUEST_SCHEMA,
|
|
6
|
+
SKILL_EVALUATED_PROMOTION_RECEIPT_RESOLUTION_SCHEMA,
|
|
7
|
+
SKILL_EVALUATED_PROMOTION_RECEIPT_RESOLVER_SCHEMA,
|
|
8
|
+
buildSkillEvaluatedPromotionReceiptEnvelope,
|
|
9
|
+
} from "./skill-evaluated-promotion.js";
|
|
10
|
+
|
|
11
|
+
export const SKILL_EVALUATED_PROMOTION_DURABILITY_AUTHORITY_SCHEMA =
|
|
12
|
+
"chainlesschain.skill-evaluated-promotion-durability-authority/v1";
|
|
13
|
+
export const SKILL_EVALUATED_PROMOTION_DURABILITY_RETAIN_REQUEST_SCHEMA =
|
|
14
|
+
"chainlesschain.skill-evaluated-promotion-durability-retain-request/v1";
|
|
15
|
+
export const SKILL_EVALUATED_PROMOTION_DURABILITY_RESOLVE_REQUEST_SCHEMA =
|
|
16
|
+
"chainlesschain.skill-evaluated-promotion-durability-resolve-request/v1";
|
|
17
|
+
export const SKILL_EVALUATED_PROMOTION_DURABILITY_RECEIPT_SCHEMA =
|
|
18
|
+
"chainlesschain.skill-evaluated-promotion-durability-receipt/v1";
|
|
19
|
+
export const SKILL_EVALUATED_PROMOTION_DURABILITY_RESOLUTION_SCHEMA =
|
|
20
|
+
"chainlesschain.skill-evaluated-promotion-durability-resolution/v1";
|
|
21
|
+
export const SKILL_EVALUATED_PROMOTION_DURABILITY_ATTESTATION_PURPOSES =
|
|
22
|
+
Object.freeze({
|
|
23
|
+
retain: "skill-evaluated-promotion-durability-retain",
|
|
24
|
+
resolve: "skill-evaluated-promotion-durability-resolve",
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const DIGEST_PATTERN = /^sha256:[a-f0-9]{64}$/u;
|
|
28
|
+
const ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,255}$/u;
|
|
29
|
+
const ADAPTER_OPTION_KEYS = new Set([
|
|
30
|
+
"authority",
|
|
31
|
+
"maximumEvidenceAgeMs",
|
|
32
|
+
"maximumGracePeriodMs",
|
|
33
|
+
"maximumOperationMs",
|
|
34
|
+
"now",
|
|
35
|
+
]);
|
|
36
|
+
const MAXIMUM_OPERATION_MS = 60_000;
|
|
37
|
+
const MAXIMUM_EVIDENCE_AGE_MS = 24 * 60 * 60 * 1000;
|
|
38
|
+
const MAXIMUM_GRACE_PERIOD_MS = 7 * 24 * 60 * 60 * 1000;
|
|
39
|
+
const CLOCK_SKEW_MS = 5_000;
|
|
40
|
+
const NATIVE_SET_TIMEOUT = globalThis.setTimeout.bind(globalThis);
|
|
41
|
+
const NATIVE_CLEAR_TIMEOUT = globalThis.clearTimeout.bind(globalThis);
|
|
42
|
+
const NATIVE_PROMISE = globalThis.Promise;
|
|
43
|
+
const NATIVE_PROMISE_RACE = NATIVE_PROMISE.race.bind(NATIVE_PROMISE);
|
|
44
|
+
const NATIVE_PROMISE_RESOLVE = NATIVE_PROMISE.resolve.bind(NATIVE_PROMISE);
|
|
45
|
+
const AUTHORITY_KEYS = new Set([
|
|
46
|
+
"schema",
|
|
47
|
+
"authorityId",
|
|
48
|
+
"trust",
|
|
49
|
+
"revision",
|
|
50
|
+
"handlerArtifactDigest",
|
|
51
|
+
"attestationTrust",
|
|
52
|
+
"attestationGraceTrusts",
|
|
53
|
+
"attestationRevocations",
|
|
54
|
+
"retain",
|
|
55
|
+
"resolve",
|
|
56
|
+
"verifyAttestation",
|
|
57
|
+
]);
|
|
58
|
+
const RESOLVE_REQUEST_KEYS = new Set(["schema", "tenantId", "receiptDigest"]);
|
|
59
|
+
const DURABILITY_RECEIPT_KEYS = new Set([
|
|
60
|
+
"schema",
|
|
61
|
+
"authenticated",
|
|
62
|
+
"durable",
|
|
63
|
+
"authorityId",
|
|
64
|
+
"revision",
|
|
65
|
+
"handlerArtifactDigest",
|
|
66
|
+
"tenantId",
|
|
67
|
+
"receiptDigest",
|
|
68
|
+
"persistedAt",
|
|
69
|
+
"persistenceReceiptDigest",
|
|
70
|
+
"attestation",
|
|
71
|
+
]);
|
|
72
|
+
const DURABILITY_RESOLUTION_KEYS = new Set([
|
|
73
|
+
"schema",
|
|
74
|
+
"authenticated",
|
|
75
|
+
"durable",
|
|
76
|
+
"authorityId",
|
|
77
|
+
"revision",
|
|
78
|
+
"handlerArtifactDigest",
|
|
79
|
+
"tenantId",
|
|
80
|
+
"receiptDigest",
|
|
81
|
+
"matrixReceipt",
|
|
82
|
+
"resolvedAt",
|
|
83
|
+
"resolutionReceiptDigest",
|
|
84
|
+
"attestation",
|
|
85
|
+
]);
|
|
86
|
+
const TRUST_KEYS = new Set([
|
|
87
|
+
"algorithm",
|
|
88
|
+
"issuer",
|
|
89
|
+
"keyId",
|
|
90
|
+
"trustPolicyDigest",
|
|
91
|
+
]);
|
|
92
|
+
const ATTESTATION_KEYS = new Set([...TRUST_KEYS, "value"]);
|
|
93
|
+
const GRACE_TRUST_KEYS = new Set(["trust", "notAfter"]);
|
|
94
|
+
const REVOCATION_KEYS = new Set(["revision", "keyIds"]);
|
|
95
|
+
const MAX_GRACE_TRUSTS = 8;
|
|
96
|
+
const MAX_REVOKED_KEYS = 64;
|
|
97
|
+
const RETAIN_ATTESTATION_CORE_KEYS = new Set([
|
|
98
|
+
"schema",
|
|
99
|
+
"authenticated",
|
|
100
|
+
"durable",
|
|
101
|
+
"authorityId",
|
|
102
|
+
"revision",
|
|
103
|
+
"handlerArtifactDigest",
|
|
104
|
+
"tenantId",
|
|
105
|
+
"receiptDigest",
|
|
106
|
+
"persistedAt",
|
|
107
|
+
"persistenceReceiptDigest",
|
|
108
|
+
]);
|
|
109
|
+
const RESOLVE_ATTESTATION_CORE_KEYS = new Set([
|
|
110
|
+
"schema",
|
|
111
|
+
"authenticated",
|
|
112
|
+
"durable",
|
|
113
|
+
"authorityId",
|
|
114
|
+
"revision",
|
|
115
|
+
"handlerArtifactDigest",
|
|
116
|
+
"tenantId",
|
|
117
|
+
"receiptDigest",
|
|
118
|
+
"resolvedAt",
|
|
119
|
+
"resolutionReceiptDigest",
|
|
120
|
+
]);
|
|
121
|
+
|
|
122
|
+
export class SkillEvaluatedPromotionDurabilityError extends Error {
|
|
123
|
+
constructor(code, message, details = {}) {
|
|
124
|
+
super(message, details.cause ? { cause: details.cause } : undefined);
|
|
125
|
+
this.name = "SkillEvaluatedPromotionDurabilityError";
|
|
126
|
+
this.code = code;
|
|
127
|
+
for (const [key, value] of Object.entries(details)) {
|
|
128
|
+
if (key !== "cause") this[key] = value;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function failure(code, message, details = {}) {
|
|
134
|
+
return new SkillEvaluatedPromotionDurabilityError(code, message, details);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function assertRecord(value, keys, label) {
|
|
138
|
+
if (
|
|
139
|
+
!value ||
|
|
140
|
+
typeof value !== "object" ||
|
|
141
|
+
Array.isArray(value) ||
|
|
142
|
+
utilTypes.isProxy(value) ||
|
|
143
|
+
![Object.prototype, null].includes(Object.getPrototypeOf(value))
|
|
144
|
+
) {
|
|
145
|
+
throw failure(
|
|
146
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
147
|
+
`${label} must be a plain object`,
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
const ownKeys = Reflect.ownKeys(value);
|
|
151
|
+
if (
|
|
152
|
+
ownKeys.length !== keys.size ||
|
|
153
|
+
ownKeys.some((key) => typeof key !== "string" || !keys.has(key))
|
|
154
|
+
) {
|
|
155
|
+
throw failure(
|
|
156
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
157
|
+
`${label} must contain exactly the supported fields`,
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
for (const key of ownKeys) {
|
|
161
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
162
|
+
if (!descriptor || !("value" in descriptor) || !descriptor.enumerable) {
|
|
163
|
+
throw failure(
|
|
164
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
165
|
+
`${label}.${String(key)} must be an enumerable own data property`,
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function normalizeId(value, label) {
|
|
172
|
+
if (typeof value !== "string" || !ID_PATTERN.test(value)) {
|
|
173
|
+
throw failure(
|
|
174
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
175
|
+
`${label} is invalid`,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
return value;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function normalizeDigest(value, label) {
|
|
182
|
+
if (typeof value !== "string" || !DIGEST_PATTERN.test(value)) {
|
|
183
|
+
throw failure(
|
|
184
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
185
|
+
`${label} must be a lowercase SHA-256 digest`,
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
return value;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
function normalizeSignature(value, label) {
|
|
192
|
+
if (typeof value !== "string" || value.length < 1 || value.length > 16_384) {
|
|
193
|
+
throw failure(
|
|
194
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
195
|
+
`${label} must be a bounded signature`,
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
return value;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function normalizeTrust(value, label) {
|
|
202
|
+
assertRecord(value, TRUST_KEYS, label);
|
|
203
|
+
return deepFreeze({
|
|
204
|
+
algorithm: normalizeId(value.algorithm, `${label}.algorithm`),
|
|
205
|
+
issuer: normalizeId(value.issuer, `${label}.issuer`),
|
|
206
|
+
keyId: normalizeId(value.keyId, `${label}.keyId`),
|
|
207
|
+
trustPolicyDigest: normalizeDigest(
|
|
208
|
+
value.trustPolicyDigest,
|
|
209
|
+
`${label}.trustPolicyDigest`,
|
|
210
|
+
),
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function normalizeAttestation(value, label) {
|
|
215
|
+
assertRecord(value, ATTESTATION_KEYS, label);
|
|
216
|
+
return deepFreeze({
|
|
217
|
+
algorithm: normalizeId(value.algorithm, `${label}.algorithm`),
|
|
218
|
+
issuer: normalizeId(value.issuer, `${label}.issuer`),
|
|
219
|
+
keyId: normalizeId(value.keyId, `${label}.keyId`),
|
|
220
|
+
trustPolicyDigest: normalizeDigest(
|
|
221
|
+
value.trustPolicyDigest,
|
|
222
|
+
`${label}.trustPolicyDigest`,
|
|
223
|
+
),
|
|
224
|
+
value: normalizeSignature(value.value, `${label}.value`),
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function sameTrust(left, right) {
|
|
229
|
+
for (const key of TRUST_KEYS) {
|
|
230
|
+
if (left[key] !== right[key]) return false;
|
|
231
|
+
}
|
|
232
|
+
return true;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function normalizeGraceTrusts(value, activeTrust) {
|
|
236
|
+
if (
|
|
237
|
+
!Array.isArray(value) ||
|
|
238
|
+
utilTypes.isProxy(value) ||
|
|
239
|
+
Object.getPrototypeOf(value) !== Array.prototype ||
|
|
240
|
+
value.length > MAX_GRACE_TRUSTS
|
|
241
|
+
) {
|
|
242
|
+
throw failure(
|
|
243
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
244
|
+
`attestationGraceTrusts must be a standard array with at most ${MAX_GRACE_TRUSTS} entries`,
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
const ownKeys = Reflect.ownKeys(value);
|
|
248
|
+
const expectedKeys = new Set([
|
|
249
|
+
"length",
|
|
250
|
+
...Array.from({ length: value.length }, (_, index) => String(index)),
|
|
251
|
+
]);
|
|
252
|
+
if (
|
|
253
|
+
ownKeys.length !== expectedKeys.size ||
|
|
254
|
+
ownKeys.some((key) => typeof key !== "string" || !expectedKeys.has(key))
|
|
255
|
+
) {
|
|
256
|
+
throw failure(
|
|
257
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
258
|
+
"attestationGraceTrusts must be dense and contain only indexes",
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
const seenKeyIds = new Set([activeTrust.keyId]);
|
|
262
|
+
const normalized = [];
|
|
263
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
264
|
+
const entryDescriptor = Object.getOwnPropertyDescriptor(
|
|
265
|
+
value,
|
|
266
|
+
String(index),
|
|
267
|
+
);
|
|
268
|
+
if (
|
|
269
|
+
!entryDescriptor ||
|
|
270
|
+
!("value" in entryDescriptor) ||
|
|
271
|
+
!entryDescriptor.enumerable
|
|
272
|
+
) {
|
|
273
|
+
throw failure(
|
|
274
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
275
|
+
`attestationGraceTrusts[${index}] must be an enumerable own data property`,
|
|
276
|
+
);
|
|
277
|
+
}
|
|
278
|
+
const entry = entryDescriptor.value;
|
|
279
|
+
assertRecord(entry, GRACE_TRUST_KEYS, `attestationGraceTrusts[${index}]`);
|
|
280
|
+
const trust = normalizeTrust(
|
|
281
|
+
entry.trust,
|
|
282
|
+
`attestationGraceTrusts[${index}].trust`,
|
|
283
|
+
);
|
|
284
|
+
if (seenKeyIds.has(trust.keyId)) {
|
|
285
|
+
throw failure(
|
|
286
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
287
|
+
"attestation active and grace keyId values must be globally unique",
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
seenKeyIds.add(trust.keyId);
|
|
291
|
+
normalized.push(
|
|
292
|
+
deepFreeze({
|
|
293
|
+
trust,
|
|
294
|
+
notAfter: normalizeTime(
|
|
295
|
+
entry.notAfter,
|
|
296
|
+
`attestationGraceTrusts[${index}].notAfter`,
|
|
297
|
+
),
|
|
298
|
+
}),
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
return deepFreeze(normalized);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function normalizeRevocations(value, activeTrust) {
|
|
305
|
+
assertRecord(value, REVOCATION_KEYS, "attestationRevocations");
|
|
306
|
+
if (!Number.isSafeInteger(value.revision) || value.revision < 1) {
|
|
307
|
+
throw failure(
|
|
308
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
309
|
+
"attestationRevocations.revision must be a positive safe integer",
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
const keyIds = value.keyIds;
|
|
313
|
+
if (
|
|
314
|
+
!Array.isArray(keyIds) ||
|
|
315
|
+
utilTypes.isProxy(keyIds) ||
|
|
316
|
+
Object.getPrototypeOf(keyIds) !== Array.prototype ||
|
|
317
|
+
keyIds.length > MAX_REVOKED_KEYS
|
|
318
|
+
) {
|
|
319
|
+
throw failure(
|
|
320
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
321
|
+
`attestationRevocations.keyIds must be a standard array with at most ${MAX_REVOKED_KEYS} entries`,
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
const ownKeys = Reflect.ownKeys(keyIds);
|
|
325
|
+
const expectedKeys = new Set([
|
|
326
|
+
"length",
|
|
327
|
+
...Array.from({ length: keyIds.length }, (_, index) => String(index)),
|
|
328
|
+
]);
|
|
329
|
+
if (
|
|
330
|
+
ownKeys.length !== expectedKeys.size ||
|
|
331
|
+
ownKeys.some((key) => typeof key !== "string" || !expectedKeys.has(key))
|
|
332
|
+
) {
|
|
333
|
+
throw failure(
|
|
334
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
335
|
+
"attestationRevocations.keyIds must be dense and contain only indexes",
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
const normalizedKeyIds = [];
|
|
339
|
+
const seenKeyIds = new Set();
|
|
340
|
+
for (let index = 0; index < keyIds.length; index += 1) {
|
|
341
|
+
const entryDescriptor = Object.getOwnPropertyDescriptor(
|
|
342
|
+
keyIds,
|
|
343
|
+
String(index),
|
|
344
|
+
);
|
|
345
|
+
if (
|
|
346
|
+
!entryDescriptor ||
|
|
347
|
+
!("value" in entryDescriptor) ||
|
|
348
|
+
!entryDescriptor.enumerable
|
|
349
|
+
) {
|
|
350
|
+
throw failure(
|
|
351
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
352
|
+
`attestationRevocations.keyIds[${index}] must be an enumerable own data property`,
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
const keyId = normalizeId(
|
|
356
|
+
entryDescriptor.value,
|
|
357
|
+
`attestationRevocations.keyIds[${index}]`,
|
|
358
|
+
);
|
|
359
|
+
if (seenKeyIds.has(keyId)) {
|
|
360
|
+
throw failure(
|
|
361
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
362
|
+
"attestationRevocations.keyIds must be unique",
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
seenKeyIds.add(keyId);
|
|
366
|
+
normalizedKeyIds.push(keyId);
|
|
367
|
+
}
|
|
368
|
+
if (seenKeyIds.has(activeTrust.keyId)) {
|
|
369
|
+
throw failure(
|
|
370
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_REVOKED",
|
|
371
|
+
"active attestation keyId is revoked",
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
return deepFreeze({
|
|
375
|
+
revision: value.revision,
|
|
376
|
+
keyIds: normalizedKeyIds,
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function normalizeTime(value, label) {
|
|
381
|
+
if (
|
|
382
|
+
typeof value !== "string" ||
|
|
383
|
+
!Number.isFinite(Date.parse(value)) ||
|
|
384
|
+
new Date(value).toISOString() !== value
|
|
385
|
+
) {
|
|
386
|
+
throw failure(
|
|
387
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
388
|
+
`${label} must be a canonical ISO timestamp`,
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
return value;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function normalizeMaximumOperationMs(value) {
|
|
395
|
+
if (
|
|
396
|
+
!Number.isSafeInteger(value) ||
|
|
397
|
+
value < 1 ||
|
|
398
|
+
value > MAXIMUM_OPERATION_MS
|
|
399
|
+
) {
|
|
400
|
+
throw failure(
|
|
401
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
402
|
+
`maximumOperationMs must be an integer from 1 through ${MAXIMUM_OPERATION_MS}`,
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
return value;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function normalizeMaximumEvidenceAgeMs(value) {
|
|
409
|
+
if (
|
|
410
|
+
!Number.isSafeInteger(value) ||
|
|
411
|
+
value < 1 ||
|
|
412
|
+
value > MAXIMUM_EVIDENCE_AGE_MS
|
|
413
|
+
) {
|
|
414
|
+
throw failure(
|
|
415
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
416
|
+
`maximumEvidenceAgeMs must be an integer from 1 through ${MAXIMUM_EVIDENCE_AGE_MS}`,
|
|
417
|
+
);
|
|
418
|
+
}
|
|
419
|
+
return value;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function normalizeMaximumGracePeriodMs(value) {
|
|
423
|
+
if (
|
|
424
|
+
!Number.isSafeInteger(value) ||
|
|
425
|
+
value < 1 ||
|
|
426
|
+
value > MAXIMUM_GRACE_PERIOD_MS
|
|
427
|
+
) {
|
|
428
|
+
throw failure(
|
|
429
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
430
|
+
`maximumGracePeriodMs must be an integer from 1 through ${MAXIMUM_GRACE_PERIOD_MS}`,
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
return value;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
function captureClock(value) {
|
|
437
|
+
if (typeof value !== "function" || utilTypes.isProxy(value)) {
|
|
438
|
+
throw failure(
|
|
439
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
440
|
+
"now must be a trusted clock function",
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
return Object.freeze(() => normalizeTime(value(), "trusted clock result"));
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
function assertFreshEvidence(value, trustedNow, maximumEvidenceAgeMs, label) {
|
|
447
|
+
const evidenceMs = Date.parse(value);
|
|
448
|
+
const nowMs = Date.parse(trustedNow);
|
|
449
|
+
if (
|
|
450
|
+
evidenceMs > nowMs + CLOCK_SKEW_MS ||
|
|
451
|
+
nowMs - evidenceMs > maximumEvidenceAgeMs
|
|
452
|
+
) {
|
|
453
|
+
throw failure(
|
|
454
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_STALE",
|
|
455
|
+
`${label} is outside the accepted evidence window`,
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function assertBoundedGraceWindows(
|
|
461
|
+
descriptor,
|
|
462
|
+
trustedNow,
|
|
463
|
+
maximumGracePeriodMs,
|
|
464
|
+
) {
|
|
465
|
+
const nowMs = Date.parse(trustedNow);
|
|
466
|
+
for (const grace of descriptor.attestationGraceTrusts) {
|
|
467
|
+
if (Date.parse(grace.notAfter) - nowMs > maximumGracePeriodMs) {
|
|
468
|
+
throw failure(
|
|
469
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
470
|
+
"attestation grace trust exceeds maximumGracePeriodMs",
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
function deepFreeze(value, seen = new WeakSet()) {
|
|
477
|
+
if (!value || typeof value !== "object" || seen.has(value)) return value;
|
|
478
|
+
if (utilTypes.isProxy(value)) {
|
|
479
|
+
throw failure(
|
|
480
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
481
|
+
"durability evidence must not contain proxies",
|
|
482
|
+
);
|
|
483
|
+
}
|
|
484
|
+
seen.add(value);
|
|
485
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
486
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
487
|
+
if (!descriptor || !("value" in descriptor)) {
|
|
488
|
+
throw failure(
|
|
489
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
490
|
+
"durability evidence must contain only data properties",
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
deepFreeze(descriptor.value, seen);
|
|
494
|
+
}
|
|
495
|
+
return Object.freeze(value);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
function receiptIdentity(matrixReceipt) {
|
|
499
|
+
const envelope = JSON.parse(
|
|
500
|
+
buildSkillEvaluatedPromotionReceiptEnvelope(matrixReceipt),
|
|
501
|
+
);
|
|
502
|
+
const tenantId = normalizeId(
|
|
503
|
+
Object.getOwnPropertyDescriptor(matrixReceipt, "tenantId")?.value,
|
|
504
|
+
"matrix receipt tenantId",
|
|
505
|
+
);
|
|
506
|
+
return { tenantId, receiptDigest: envelope.receiptDigest };
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
function captureAuthority(value) {
|
|
510
|
+
assertRecord(value, AUTHORITY_KEYS, "durability authority");
|
|
511
|
+
if (
|
|
512
|
+
value.schema !== SKILL_EVALUATED_PROMOTION_DURABILITY_AUTHORITY_SCHEMA ||
|
|
513
|
+
value.trust !== "trusted" ||
|
|
514
|
+
!Number.isSafeInteger(value.revision) ||
|
|
515
|
+
value.revision < 1 ||
|
|
516
|
+
typeof value.retain !== "function" ||
|
|
517
|
+
typeof value.resolve !== "function" ||
|
|
518
|
+
typeof value.verifyAttestation !== "function" ||
|
|
519
|
+
utilTypes.isProxy(value.retain) ||
|
|
520
|
+
utilTypes.isProxy(value.resolve) ||
|
|
521
|
+
utilTypes.isProxy(value.verifyAttestation)
|
|
522
|
+
) {
|
|
523
|
+
throw failure(
|
|
524
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
525
|
+
"durability authority descriptor is invalid",
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
const attestationTrust = normalizeTrust(
|
|
529
|
+
value.attestationTrust,
|
|
530
|
+
"authority attestationTrust",
|
|
531
|
+
);
|
|
532
|
+
const descriptor = deepFreeze({
|
|
533
|
+
authorityId: normalizeId(value.authorityId, "authorityId"),
|
|
534
|
+
trust: value.trust,
|
|
535
|
+
revision: value.revision,
|
|
536
|
+
handlerArtifactDigest: normalizeDigest(
|
|
537
|
+
value.handlerArtifactDigest,
|
|
538
|
+
"handlerArtifactDigest",
|
|
539
|
+
),
|
|
540
|
+
attestationTrust,
|
|
541
|
+
attestationGraceTrusts: normalizeGraceTrusts(
|
|
542
|
+
value.attestationGraceTrusts,
|
|
543
|
+
attestationTrust,
|
|
544
|
+
),
|
|
545
|
+
attestationRevocations: normalizeRevocations(
|
|
546
|
+
value.attestationRevocations,
|
|
547
|
+
attestationTrust,
|
|
548
|
+
),
|
|
549
|
+
});
|
|
550
|
+
const retain = value.retain.bind(value);
|
|
551
|
+
const resolve = value.resolve.bind(value);
|
|
552
|
+
const verifyAttestation = value.verifyAttestation.bind(value);
|
|
553
|
+
Object.freeze(value);
|
|
554
|
+
return { descriptor, retain, resolve, verifyAttestation };
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
function attestationCore(value, keys, label) {
|
|
558
|
+
const core = {};
|
|
559
|
+
for (const key of keys) {
|
|
560
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
561
|
+
if (!descriptor || !("value" in descriptor)) {
|
|
562
|
+
throw failure(
|
|
563
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
564
|
+
`${label}.${key} must be an own data property`,
|
|
565
|
+
);
|
|
566
|
+
}
|
|
567
|
+
core[key] = descriptor.value;
|
|
568
|
+
}
|
|
569
|
+
return core;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
export function computeSkillEvaluatedPromotionDurabilityAttestationDigest(
|
|
573
|
+
value,
|
|
574
|
+
) {
|
|
575
|
+
if (!value || typeof value !== "object" || utilTypes.isProxy(value)) {
|
|
576
|
+
throw failure(
|
|
577
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
578
|
+
"durability attestation payload must be a plain object",
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
const schema = Object.getOwnPropertyDescriptor(value, "schema")?.value;
|
|
582
|
+
const keys =
|
|
583
|
+
schema === SKILL_EVALUATED_PROMOTION_DURABILITY_RECEIPT_SCHEMA
|
|
584
|
+
? RETAIN_ATTESTATION_CORE_KEYS
|
|
585
|
+
: schema === SKILL_EVALUATED_PROMOTION_DURABILITY_RESOLUTION_SCHEMA
|
|
586
|
+
? RESOLVE_ATTESTATION_CORE_KEYS
|
|
587
|
+
: null;
|
|
588
|
+
if (keys === null) {
|
|
589
|
+
throw failure(
|
|
590
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
591
|
+
"durability attestation payload schema is invalid",
|
|
592
|
+
);
|
|
593
|
+
}
|
|
594
|
+
const purpose =
|
|
595
|
+
schema === SKILL_EVALUATED_PROMOTION_DURABILITY_RECEIPT_SCHEMA
|
|
596
|
+
? SKILL_EVALUATED_PROMOTION_DURABILITY_ATTESTATION_PURPOSES.retain
|
|
597
|
+
: SKILL_EVALUATED_PROMOTION_DURABILITY_ATTESTATION_PURPOSES.resolve;
|
|
598
|
+
return `sha256:${createHash("sha256")
|
|
599
|
+
.update(
|
|
600
|
+
`chainlesschain.skill-evaluated-promotion-durability-attestation/v1\0${purpose}\0${JSON.stringify(attestationCore(value, keys, "attestation payload"))}`,
|
|
601
|
+
"utf8",
|
|
602
|
+
)
|
|
603
|
+
.digest("hex")}`;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
function selectAttestationTrust(descriptor, attestation, trustedNow, label) {
|
|
607
|
+
if (descriptor.attestationRevocations.keyIds.includes(attestation.keyId)) {
|
|
608
|
+
throw failure(
|
|
609
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_REVOKED",
|
|
610
|
+
`${label} uses a revoked attestation key`,
|
|
611
|
+
);
|
|
612
|
+
}
|
|
613
|
+
if (sameTrust(attestation, descriptor.attestationTrust)) {
|
|
614
|
+
return descriptor.attestationTrust;
|
|
615
|
+
}
|
|
616
|
+
const trustedNowMs = Date.parse(trustedNow);
|
|
617
|
+
for (const grace of descriptor.attestationGraceTrusts) {
|
|
618
|
+
if (sameTrust(attestation, grace.trust)) {
|
|
619
|
+
if (trustedNowMs <= Date.parse(grace.notAfter) + CLOCK_SKEW_MS) {
|
|
620
|
+
return grace.trust;
|
|
621
|
+
}
|
|
622
|
+
throw failure(
|
|
623
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_STALE",
|
|
624
|
+
`${label} uses an expired grace key`,
|
|
625
|
+
);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
throw failure(
|
|
629
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_REJECTED",
|
|
630
|
+
`${label} does not match an active or grace trust identity`,
|
|
631
|
+
);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
async function verifyAuthorityAttestation(
|
|
635
|
+
captured,
|
|
636
|
+
result,
|
|
637
|
+
purpose,
|
|
638
|
+
trustedNow,
|
|
639
|
+
label,
|
|
640
|
+
) {
|
|
641
|
+
const attestation = normalizeAttestation(
|
|
642
|
+
result.attestation,
|
|
643
|
+
`${label} attestation`,
|
|
644
|
+
);
|
|
645
|
+
const selectedTrust = selectAttestationTrust(
|
|
646
|
+
captured.descriptor,
|
|
647
|
+
attestation,
|
|
648
|
+
trustedNow,
|
|
649
|
+
label,
|
|
650
|
+
);
|
|
651
|
+
const payloadDigest =
|
|
652
|
+
computeSkillEvaluatedPromotionDurabilityAttestationDigest(result);
|
|
653
|
+
let verified;
|
|
654
|
+
try {
|
|
655
|
+
verified = await captured.verifyAttestation(
|
|
656
|
+
deepFreeze({
|
|
657
|
+
purpose,
|
|
658
|
+
payloadDigest,
|
|
659
|
+
attestation,
|
|
660
|
+
selectedTrust,
|
|
661
|
+
revocationRevision: captured.descriptor.attestationRevocations.revision,
|
|
662
|
+
}),
|
|
663
|
+
);
|
|
664
|
+
} catch (cause) {
|
|
665
|
+
throw failure(
|
|
666
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_UNAVAILABLE",
|
|
667
|
+
`${label} attestation verifier failed`,
|
|
668
|
+
{ cause },
|
|
669
|
+
);
|
|
670
|
+
}
|
|
671
|
+
if (verified !== true) {
|
|
672
|
+
throw failure(
|
|
673
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_REJECTED",
|
|
674
|
+
`${label} attestation is invalid`,
|
|
675
|
+
);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
async function runAuthorityOperation(
|
|
680
|
+
operation,
|
|
681
|
+
request,
|
|
682
|
+
maximumOperationMs,
|
|
683
|
+
label,
|
|
684
|
+
) {
|
|
685
|
+
const controller = new AbortController();
|
|
686
|
+
let timer;
|
|
687
|
+
const timeout = new NATIVE_PROMISE((_, reject) => {
|
|
688
|
+
timer = NATIVE_SET_TIMEOUT(() => {
|
|
689
|
+
controller.abort(
|
|
690
|
+
failure(
|
|
691
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_TIMEOUT",
|
|
692
|
+
`${label} exceeded its bounded deadline`,
|
|
693
|
+
),
|
|
694
|
+
);
|
|
695
|
+
reject(controller.signal.reason);
|
|
696
|
+
}, maximumOperationMs);
|
|
697
|
+
});
|
|
698
|
+
try {
|
|
699
|
+
return await NATIVE_PROMISE_RACE([
|
|
700
|
+
NATIVE_PROMISE_RESOLVE(
|
|
701
|
+
operation(request, Object.freeze({ signal: controller.signal })),
|
|
702
|
+
),
|
|
703
|
+
timeout,
|
|
704
|
+
]);
|
|
705
|
+
} finally {
|
|
706
|
+
NATIVE_CLEAR_TIMEOUT(timer);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
function assertAuthorityBinding(result, authority, identity, label) {
|
|
711
|
+
if (
|
|
712
|
+
result.authenticated !== true ||
|
|
713
|
+
result.durable !== true ||
|
|
714
|
+
result.authorityId !== authority.authorityId ||
|
|
715
|
+
result.revision !== authority.revision ||
|
|
716
|
+
result.handlerArtifactDigest !== authority.handlerArtifactDigest ||
|
|
717
|
+
result.tenantId !== identity.tenantId ||
|
|
718
|
+
result.receiptDigest !== identity.receiptDigest
|
|
719
|
+
) {
|
|
720
|
+
throw failure(
|
|
721
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_REJECTED",
|
|
722
|
+
`${label} is not authenticated, durable, and exactly bound`,
|
|
723
|
+
);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
export function createSkillEvaluatedPromotionDurabilityAdapter(options = {}) {
|
|
728
|
+
assertRecord(options, ADAPTER_OPTION_KEYS, "durability adapter options");
|
|
729
|
+
const captured = captureAuthority(options.authority);
|
|
730
|
+
const maximumEvidenceAgeMs = normalizeMaximumEvidenceAgeMs(
|
|
731
|
+
options.maximumEvidenceAgeMs,
|
|
732
|
+
);
|
|
733
|
+
const maximumGracePeriodMs = normalizeMaximumGracePeriodMs(
|
|
734
|
+
options.maximumGracePeriodMs,
|
|
735
|
+
);
|
|
736
|
+
const maximumOperationMs = normalizeMaximumOperationMs(
|
|
737
|
+
options.maximumOperationMs,
|
|
738
|
+
);
|
|
739
|
+
const now = captureClock(options.now);
|
|
740
|
+
assertBoundedGraceWindows(captured.descriptor, now(), maximumGracePeriodMs);
|
|
741
|
+
const retain = async (matrixReceipt) => {
|
|
742
|
+
const identity = receiptIdentity(matrixReceipt);
|
|
743
|
+
const request = deepFreeze({
|
|
744
|
+
schema: SKILL_EVALUATED_PROMOTION_DURABILITY_RETAIN_REQUEST_SCHEMA,
|
|
745
|
+
...identity,
|
|
746
|
+
matrixReceipt,
|
|
747
|
+
});
|
|
748
|
+
let result;
|
|
749
|
+
try {
|
|
750
|
+
result = await runAuthorityOperation(
|
|
751
|
+
captured.retain,
|
|
752
|
+
request,
|
|
753
|
+
maximumOperationMs,
|
|
754
|
+
"durability retain",
|
|
755
|
+
);
|
|
756
|
+
} catch (cause) {
|
|
757
|
+
if (cause instanceof SkillEvaluatedPromotionDurabilityError) throw cause;
|
|
758
|
+
throw failure(
|
|
759
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_UNAVAILABLE",
|
|
760
|
+
"durability authority failed to retain the matrix receipt",
|
|
761
|
+
{ cause },
|
|
762
|
+
);
|
|
763
|
+
}
|
|
764
|
+
assertRecord(result, DURABILITY_RECEIPT_KEYS, "durability receipt");
|
|
765
|
+
if (result.schema !== SKILL_EVALUATED_PROMOTION_DURABILITY_RECEIPT_SCHEMA) {
|
|
766
|
+
throw failure(
|
|
767
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_REJECTED",
|
|
768
|
+
"durability receipt schema is invalid",
|
|
769
|
+
);
|
|
770
|
+
}
|
|
771
|
+
assertAuthorityBinding(result, captured.descriptor, identity, "receipt");
|
|
772
|
+
const persistedAt = normalizeTime(result.persistedAt, "persistedAt");
|
|
773
|
+
const trustedNow = now();
|
|
774
|
+
assertFreshEvidence(
|
|
775
|
+
persistedAt,
|
|
776
|
+
trustedNow,
|
|
777
|
+
maximumEvidenceAgeMs,
|
|
778
|
+
"durability receipt",
|
|
779
|
+
);
|
|
780
|
+
normalizeDigest(
|
|
781
|
+
result.persistenceReceiptDigest,
|
|
782
|
+
"persistenceReceiptDigest",
|
|
783
|
+
);
|
|
784
|
+
await verifyAuthorityAttestation(
|
|
785
|
+
captured,
|
|
786
|
+
result,
|
|
787
|
+
SKILL_EVALUATED_PROMOTION_DURABILITY_ATTESTATION_PURPOSES.retain,
|
|
788
|
+
trustedNow,
|
|
789
|
+
"durability receipt",
|
|
790
|
+
);
|
|
791
|
+
return deepFreeze({ ...result });
|
|
792
|
+
};
|
|
793
|
+
const resolverDescriptor = {
|
|
794
|
+
authorityId: captured.descriptor.authorityId,
|
|
795
|
+
trust: captured.descriptor.trust,
|
|
796
|
+
revision: captured.descriptor.revision,
|
|
797
|
+
handlerArtifactDigest: captured.descriptor.handlerArtifactDigest,
|
|
798
|
+
};
|
|
799
|
+
const resolver = {
|
|
800
|
+
schema: SKILL_EVALUATED_PROMOTION_RECEIPT_RESOLVER_SCHEMA,
|
|
801
|
+
...resolverDescriptor,
|
|
802
|
+
async resolve(input) {
|
|
803
|
+
assertRecord(input, RESOLVE_REQUEST_KEYS, "receipt resolver request");
|
|
804
|
+
if (
|
|
805
|
+
input.schema !==
|
|
806
|
+
SKILL_EVALUATED_PROMOTION_RECEIPT_RESOLUTION_REQUEST_SCHEMA
|
|
807
|
+
) {
|
|
808
|
+
throw failure(
|
|
809
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_INVALID",
|
|
810
|
+
"receipt resolver request schema is invalid",
|
|
811
|
+
);
|
|
812
|
+
}
|
|
813
|
+
const identity = {
|
|
814
|
+
tenantId: normalizeId(input.tenantId, "resolver tenantId"),
|
|
815
|
+
receiptDigest: normalizeDigest(
|
|
816
|
+
input.receiptDigest,
|
|
817
|
+
"resolver receiptDigest",
|
|
818
|
+
),
|
|
819
|
+
};
|
|
820
|
+
const request = deepFreeze({
|
|
821
|
+
schema: SKILL_EVALUATED_PROMOTION_DURABILITY_RESOLVE_REQUEST_SCHEMA,
|
|
822
|
+
...identity,
|
|
823
|
+
});
|
|
824
|
+
let result;
|
|
825
|
+
try {
|
|
826
|
+
result = await runAuthorityOperation(
|
|
827
|
+
captured.resolve,
|
|
828
|
+
request,
|
|
829
|
+
maximumOperationMs,
|
|
830
|
+
"durability resolve",
|
|
831
|
+
);
|
|
832
|
+
} catch (cause) {
|
|
833
|
+
if (cause instanceof SkillEvaluatedPromotionDurabilityError)
|
|
834
|
+
throw cause;
|
|
835
|
+
throw failure(
|
|
836
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_UNAVAILABLE",
|
|
837
|
+
"durability authority failed to resolve the matrix receipt",
|
|
838
|
+
{ cause },
|
|
839
|
+
);
|
|
840
|
+
}
|
|
841
|
+
assertRecord(result, DURABILITY_RESOLUTION_KEYS, "durability resolution");
|
|
842
|
+
if (
|
|
843
|
+
result.schema !== SKILL_EVALUATED_PROMOTION_DURABILITY_RESOLUTION_SCHEMA
|
|
844
|
+
) {
|
|
845
|
+
throw failure(
|
|
846
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_REJECTED",
|
|
847
|
+
"durability resolution schema is invalid",
|
|
848
|
+
);
|
|
849
|
+
}
|
|
850
|
+
assertAuthorityBinding(
|
|
851
|
+
result,
|
|
852
|
+
captured.descriptor,
|
|
853
|
+
identity,
|
|
854
|
+
"resolution",
|
|
855
|
+
);
|
|
856
|
+
const resolvedIdentity = receiptIdentity(result.matrixReceipt);
|
|
857
|
+
if (
|
|
858
|
+
resolvedIdentity.tenantId !== identity.tenantId ||
|
|
859
|
+
resolvedIdentity.receiptDigest !== identity.receiptDigest
|
|
860
|
+
) {
|
|
861
|
+
throw failure(
|
|
862
|
+
"SKILL_EVALUATED_PROMOTION_DURABILITY_REJECTED",
|
|
863
|
+
"resolved matrix receipt differs from the durable lookup subject",
|
|
864
|
+
);
|
|
865
|
+
}
|
|
866
|
+
const resolvedAt = normalizeTime(result.resolvedAt, "resolvedAt");
|
|
867
|
+
const trustedNow = now();
|
|
868
|
+
assertFreshEvidence(
|
|
869
|
+
resolvedAt,
|
|
870
|
+
trustedNow,
|
|
871
|
+
maximumEvidenceAgeMs,
|
|
872
|
+
"durability resolution",
|
|
873
|
+
);
|
|
874
|
+
normalizeDigest(
|
|
875
|
+
result.resolutionReceiptDigest,
|
|
876
|
+
"resolutionReceiptDigest",
|
|
877
|
+
);
|
|
878
|
+
await verifyAuthorityAttestation(
|
|
879
|
+
captured,
|
|
880
|
+
result,
|
|
881
|
+
SKILL_EVALUATED_PROMOTION_DURABILITY_ATTESTATION_PURPOSES.resolve,
|
|
882
|
+
trustedNow,
|
|
883
|
+
"durability resolution",
|
|
884
|
+
);
|
|
885
|
+
return deepFreeze({
|
|
886
|
+
schema: SKILL_EVALUATED_PROMOTION_RECEIPT_RESOLUTION_SCHEMA,
|
|
887
|
+
...resolverDescriptor,
|
|
888
|
+
tenantId: identity.tenantId,
|
|
889
|
+
receiptDigest: identity.receiptDigest,
|
|
890
|
+
matrixReceipt: result.matrixReceipt,
|
|
891
|
+
resolvedAt: result.resolvedAt,
|
|
892
|
+
});
|
|
893
|
+
},
|
|
894
|
+
};
|
|
895
|
+
return Object.freeze({
|
|
896
|
+
retain: Object.freeze(retain),
|
|
897
|
+
resolver: Object.freeze(resolver),
|
|
898
|
+
});
|
|
899
|
+
}
|