chainlesschain 0.166.37 → 0.166.39
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/package.json +7 -2
- package/scripts/governed-learning-local-attestor-service.mjs +222 -0
- package/scripts/governed-learning-local-attestor-trust-approval-service.mjs +338 -0
- package/scripts/governed-learning-local-attestor-trust-operations-service.mjs +575 -0
- package/scripts/governed-learning-windows-secure-pipe-broker.ps1 +375 -0
- package/src/assets/web-panel/assets/{AIOps-B_Nt1Qe4.js → AIOps-qWUdiFr5.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CHQbie4X.js → ActionButton-B_f7go3E.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-Bm9364Lw.js → Analytics-hSGFlSkB.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DTwlIh2v.js → AppLayout-CCYGgj71.js} +3 -3
- package/src/assets/web-panel/assets/{Artifacts-OibP0qB4.js → Artifacts-BdS1H9gq.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-B8Fwavkg.js → Audit-Cck9IebC.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-p1Vb2K2B.js → BackgroundAgents-DZzoM_QS.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BI3QT-wI.js → Backup-D8H_QtGu.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BW_VRWWu.js → BaseInput-CTsNF_pu.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CUEhDQfq.js → Chat-CcEiTYY8.js} +4 -4
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-C5UVXdVE.js → ChatBubbleRenderer-9BY1DPuc.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-URYsaaxv.js → Checkbox-BPB9NNJx.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DJAwC80a.js → Codegen-CKKMf7jD.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DfRKFzc9.js → Col-DpSSB4Uu.js} +1 -1
- package/src/assets/web-panel/assets/{Community-GOkGHuly.js → Community-CfR6ikoH.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-CIMs13NC.js → Compact-CqnkGGjK.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BE-TQIxV.js → Compliance-9IzhdVQb.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CYmbJiWw.js → Cowork-eXsgH33N.js} +4 -4
- package/src/assets/web-panel/assets/{Cron-Be3OIWyM.js → Cron-DvkzHFRi.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-2xB2HS2D.js → Crosschain--az9d9f7.js} +1 -1
- package/src/assets/web-panel/assets/{DID-B_lJO2yF.js → DID-_Eb4kpnJ.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-DnVWqUER.js → Dashboard-aDVisdXj.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-C7ZJvHVa.js → Dropdown-oQ54XzS9.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-DLevT-0F.js → EmailListRenderer-BUPdMau1.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BwhQ5BRU.js → FamilyGuardDashboard-DtQTOCQI.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BkGI-Xkq.js → Federation-Cpnb3Moe.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BgIIbMd7.js → FormItemContext-DmsrJkeU.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-qL-qN8Nb.js → GenericCardRenderer-CpFDYnh3.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BTzgrC4U.js → Git-HFG17p7Q.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-p28vdCN4.js → Governance-D5Z5c7N8.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-Cqephrur.js → Inference-DH159h74.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-C3v5Q4Zp.js → KnowledgeGraph-DuL1pcJD.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-T6f0w32w.js → Logs-Gqn8hFsM.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-Dj5XPm3S.js → MarkdownRenderer-NHJaejHI.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-ClDsvHDH.js → Marketplace-BArcWifg.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-C4P-_snx.js → McpTools-Q1BfBSnd.js} +2 -2
- package/src/assets/web-panel/assets/{Memory-BZZfG6y6.js → Memory-Cz8nRL7N.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DpIv_BLs.js → MobileBridge-CRuxLRJw.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-Buz3NIQg.js → MobileProjects-B1CQIAGp.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-HS2PJB79.js → Mtc-CFhXZbPk.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-UmBrcU27.js → MtcAudit-C69LqcZ5.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-C00sXiZf.js → Multisig-y7yZeTTG.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Dj1ng_ph.js → NLProgramming-DgjhoWea.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-C4LEVKlk.js → Notes-DRc2WTDh.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-BWXwnekv.js → NotificationSettings-CLPx24yn.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-CZHfK8Nn.js → OrderTableRenderer-CMSNA4CO.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-CFEtFPrV.js → Organization-Dm6LIyhZ.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-DSz4MJK1.js → Overflow-DP4DOYd-.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-DyTEytwG.js → P2P-HFwvtFI1.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-B5QNGLVx.js → PdhVaultBrowser-D9gPfKRM.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-wEC_X7x4.js → Permissions-Bdtxniwh.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-If5GZlGZ.js → PersonalDataHub-Dgl2AbES.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-LB4gqqmX.js → Pipeline-DpZrzYwK.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-QVLhoxcN.js → Privacy-EQ551c0t.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-FaAbTYTo.js → ProjectInit-xUSeczsM.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-DhMeNA21.js → ProjectSettings-B66Sr_t8.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-5L4lkWAZ.js → Projects-B4zikj95.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-DhZFp8fO.js → Providers-DjLbqQPh.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BZuJ7_xi.js → QrScannerModal-KVsAQCd_.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-TXddPYYb.js → QuickAsk-C4noJXu8.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DDuXIKYt.js → Recommend-Cn15clqY.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-CDrTXImv.js → RemoteSession-DdonMFwH.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-B2xKaKzt.js → Reputation-Bqe3NwWN.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DzAjWAOX.js → Row-CnxBgjkD.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CKH38BLF.js → RssFeed-CSRrgZyK.js} +2 -2
- package/src/assets/web-panel/assets/{Search-CuPqJYoQ.js → Search-DTUYUfFx.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DmAd2hxz.js → Security-BHExHVIm.js} +4 -4
- package/src/assets/web-panel/assets/{Services-Bt3nljnY.js → Services-B_IWqPes.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CP7RH093.js → Skeleton-C_oAtzmX.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-DKNeMBTx.js → Skills-maJNokSL.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CbpM8Nrd.js → Sla-CMM_ZsLH.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-DTk-vTzF.js → SpeechSettings-D7w_oNwK.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DKiplwmc.js → SyncSettings-D0Zl3NIr.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-z-lOm8fx.js → Tasks-Bs0H0ctR.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-Rb-Q0DGX.js → Templates-C6T6oCpR.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-C2sqDUnR.js → Tenant-ByL-kAYO.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DcyzskEE.js → Terminal-6JXNhc3b.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-lg0Eam7N.js → TimelineRenderer-KiuUtCsl.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-D9USIMIA.js → Tokens-C0TWTIER.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BQpaQJ5k.js → Trigger-DpC5aaJu.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-C-Mik04s.js → Trust-lqqflCwv.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DrnZ_o56.js → UkeySign-BYSlVfBc.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BDOsoZi0.js → VideoEditing-DX08oo_R.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Ct_bleI7.js → Wallet-CcIFPvzL.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-B6b6FDao.js → WebAuthn-D8DfxfVT.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-ZUJMaIHr.js → WorkflowEditor-Csadpaln.js} +1 -1
- package/src/assets/web-panel/assets/{chat-BII20OJy.js → chat-CewHWc_T.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DEsJRV3n.js → colors-B8at89r3.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DoDYAzN9.js → compact-item-v_gxtF5-.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-o_nofnVW.js → createContext-BOwFpJqA.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DenB_kSS.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CAsABTHC.js → hasIn-DjHUzt7E.js} +1 -1
- package/src/assets/web-panel/assets/{index-CeJSTcXw.js → index-1Tfwr_GA.js} +1 -1
- package/src/assets/web-panel/assets/{index-CVQSl1uY.js → index-5qmLo1us.js} +1 -1
- package/src/assets/web-panel/assets/index-B8bNwM9U.js +1 -0
- package/src/assets/web-panel/assets/{index-CQE-WMEU.js → index-BC20EQ7h.js} +1 -1
- package/src/assets/web-panel/assets/{index-DciLb_Ww.js → index-BGrmPk8T.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bqyg3PME.js → index-BPJ7uL2Q.js} +1 -1
- package/src/assets/web-panel/assets/{index-DU2Rpx1m.js → index-BRNyE3Kb.js} +1 -1
- package/src/assets/web-panel/assets/{index-CeWJqXNX.js → index-BVPsegMN.js} +1 -1
- package/src/assets/web-panel/assets/{index-DWZNYecl.js → index-B_egGFcR.js} +3 -3
- package/src/assets/web-panel/assets/{index-TSwbtCYG.js → index-BdZLA7k9.js} +1 -1
- package/src/assets/web-panel/assets/{index-BrIIJ2s-.js → index-Bk_Te9OR.js} +1 -1
- package/src/assets/web-panel/assets/{index-D5Fd4tdL.js → index-Bz8C8VXx.js} +1 -1
- package/src/assets/web-panel/assets/{index-B4SfcwZA.js → index-C7MHbmwn.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bn2ZPUXO.js → index-CFL1Hewx.js} +1 -1
- package/src/assets/web-panel/assets/{index-DsoFTdA2.js → index-CV1SgaBd.js} +1 -1
- package/src/assets/web-panel/assets/{index-B9hYHPhs.js → index-CXIPAeAB.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dgt1mKby.js → index-Ca8YZU2B.js} +1 -1
- package/src/assets/web-panel/assets/{index-DRAA2McB.js → index-Caf9UjhG.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcYbQoY7.js → index-Cb1uNDOv.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bycj011d.js → index-CquUCUzS.js} +1 -1
- package/src/assets/web-panel/assets/{index-BzMA6Ra3.js → index-CwHoF-TP.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dbb34cAr.js → index-Cxk0mCoQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BxT8yTwS.js → index-D3o-pacB.js} +1 -1
- package/src/assets/web-panel/assets/{index-DrsAF-Ar.js → index-DA3n0Y28.js} +1 -1
- package/src/assets/web-panel/assets/index-DC0cpgIP.js +1 -0
- package/src/assets/web-panel/assets/{index-B9Z75LfA.js → index-DRRK_8Eg.js} +1 -1
- package/src/assets/web-panel/assets/{index-kIyLNyoF.js → index-DUMvVGyf.js} +1 -1
- package/src/assets/web-panel/assets/{index-DQmX_-hk.js → index-DdHdbXpy.js} +1 -1
- package/src/assets/web-panel/assets/{index-tCeNfxv4.js → index-Ddw05Myq.js} +1 -1
- package/src/assets/web-panel/assets/{index-BDRh3v44.js → index-Dfrb3Prv.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bmwo5wQG.js → index-DiKaYIdo.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1YDdyQ1.js → index-DmZLZsyC.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dhnau6uw.js → index-FgUrhq_H.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cf3sFEoE.js → index-Khw7wzVk.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0ApxOMw.js → index-San3zacc.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_CMB_wC.js → index-coOi37of.js} +1 -1
- package/src/assets/web-panel/assets/{index-BnbnmRqg.js → index-hyeBuocp.js} +1 -1
- package/src/assets/web-panel/assets/{index-DDQzBK3l.js → index-uk59xr0W.js} +1 -1
- package/src/assets/web-panel/assets/{index-CE2J04dA.js → index-wjvn8-9F.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-CNjeeoKE.js → initDefaultProps-Id2dFdjh.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CBT8IZDm.js → motion-DRxtwxng.js} +1 -1
- package/src/assets/web-panel/assets/{move-h1MOxjqv.js → move-BDYvdTb6.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-C_3pqNmn.js → mtc-parser-cz8LGI8Z.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CMUnPFDk.js → omit-DHJeh6tH.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-p8_c1xq0.js → pickAttrs-XJEQIp7e.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-D6O67r23.js → placementArrow-AFcf8lEn.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DquhepAK.js → responsiveObserve-CDEeBxs1.js} +1 -1
- package/src/assets/web-panel/assets/{slide-CZ-m6gmS.js → slide-CvbVfi6T.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-k9ejZFtd.js → statusUtils-DtCyuEnq.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-NX6_137R.js → styleChecker--UgmTsGY.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-bCqR70lP.js → useFlexGapSupport-D9i1as-Y.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-2l0vSqyY.js → useFs-CJx3zw01.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-1yccm4O7.js → usePersonalDataHub-ZsIKYdZv.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CxQzajDo.js → vnode-B2RGEQG4.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-CrTKwFyb.js → zoom-ob-0px2z.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +1 -1
- package/src/commands/evolution-attestor-trust.js +113 -0
- package/src/commands/evolution.js +2 -0
- package/src/commands/learning.js +34 -5
- package/src/data/changelog.json +26 -0
- package/src/lib/evolution/evolution-artifact-ports.js +21 -0
- package/src/lib/evolution/evolution-deployment-loader.js +56 -0
- package/src/lib/evolution/evolution-immutable-ledger-segment-store.js +812 -0
- package/src/lib/evolution/evolution-ledger-file-manifest-catalog.js +218 -0
- package/src/lib/evolution/evolution-ledger-manifest-catalog.js +472 -0
- package/src/lib/evolution/evolution-ledger-manifest-chain.js +997 -0
- package/src/lib/evolution/evolution-ledger-manifest-head-store.js +408 -0
- package/src/lib/evolution/evolution-ledger-manifest-witness-adapter.js +554 -0
- package/src/lib/evolution/evolution-ledger-v2-manifest-backend.js +460 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-ipc-endpoint.js +94 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-approval-client.js +485 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-ipc-capability.js +200 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-ledger.js +1222 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-operations-cli-host.js +802 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-operations-client.js +445 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-operations.js +1082 -0
- package/src/lib/evolution/governed-skill-synthesis-attestor-trust-operator-registry.js +1453 -0
- package/src/lib/evolution/governed-skill-synthesis-candidate-evaluator.js +147 -0
- package/src/lib/evolution/governed-skill-synthesis-cli-host.js +115 -0
- package/src/lib/evolution/governed-skill-synthesis-evaluation-ledger-adapter.js +715 -0
- package/src/lib/evolution/governed-skill-synthesis-external-attestor.js +499 -0
- package/src/lib/evolution/governed-skill-synthesis-model-evaluator.js +514 -0
- package/src/lib/evolution/governed-skill-synthesis-process-attestor-worker.mjs +208 -0
- package/src/lib/evolution/governed-skill-synthesis-process-attestor.js +557 -0
- package/src/lib/evolution/governed-skill-synthesis-process-grader-worker.mjs +143 -0
- package/src/lib/evolution/governed-skill-synthesis-process-grader.js +444 -0
- package/src/lib/evolution/governed-skill-synthesis-provider-chat.js +220 -0
- package/src/lib/evolution/governed-skill-synthesis-windows-secure-pipe-host.js +236 -0
- package/src/lib/hook-audit-store.js +68 -2
- package/src/lib/hooks-v2-runtime.js +52 -26
- package/src/lib/learning/skill-synthesizer.js +66 -5
- package/src/lib/remote-read-loop-guard.js +30 -3
- package/src/assets/web-panel/assets/devWarning-0tgDCszN.js +0 -1
- package/src/assets/web-panel/assets/index-CFF8XEFE.js +0 -1
- package/src/assets/web-panel/assets/index-DVUEISry.js +0 -1
|
@@ -0,0 +1,802 @@
|
|
|
1
|
+
import { createHash, createPublicKey } from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { types as utilTypes } from "node:util";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
sameFileStatIdentity,
|
|
8
|
+
samePathHandleFileIdentity,
|
|
9
|
+
withTrustedFileParentSync,
|
|
10
|
+
} from "../secure-file-identity.js";
|
|
11
|
+
import { readBoundedDescriptor } from "./bounded-descriptor-read.js";
|
|
12
|
+
import { isGovernedSkillSynthesisAttestorTrustApprovalClient } from "./governed-skill-synthesis-attestor-trust-approval-client.js";
|
|
13
|
+
import {
|
|
14
|
+
GOVERNED_SKILL_SYNTHESIS_ATTESTOR_TRUST_OPERATIONS_CLIENT_SCHEMA,
|
|
15
|
+
isGovernedSkillSynthesisAttestorTrustOperationsClient,
|
|
16
|
+
} from "./governed-skill-synthesis-attestor-trust-operations-client.js";
|
|
17
|
+
import {
|
|
18
|
+
GOVERNED_SKILL_SYNTHESIS_ATTESTOR_TRUST_OPERATION_REQUEST_SCHEMA,
|
|
19
|
+
digestGovernedSkillSynthesisAttestorTrustOperationRequest,
|
|
20
|
+
} from "./governed-skill-synthesis-attestor-trust-operations.js";
|
|
21
|
+
import { validateGovernedSkillSynthesisAttestorTrustOperatorRegistryChangeRequest } from "./governed-skill-synthesis-attestor-trust-operator-registry.js";
|
|
22
|
+
|
|
23
|
+
export const GOVERNED_SKILL_SYNTHESIS_ATTESTOR_TRUST_OPERATIONS_CLI_HOST_SCHEMA =
|
|
24
|
+
"chainlesschain.governed-skill-synthesis-attestor-trust-operations-cli-host/v3";
|
|
25
|
+
|
|
26
|
+
const HOSTS = new WeakSet();
|
|
27
|
+
const MAX_DOCUMENT_BYTES = 256 * 1024;
|
|
28
|
+
const MAX_APPROVAL_FILES = 16;
|
|
29
|
+
const MAX_REQUEST_TTL_MS = 15 * 60 * 1000;
|
|
30
|
+
const FUTURE_SKEW_MS = 30 * 1000;
|
|
31
|
+
const DIGEST = /^sha256:[a-f0-9]{64}$/u;
|
|
32
|
+
const KEY_ID = /^key:ed25519:[a-f0-9]{64}$/u;
|
|
33
|
+
const SERVICE_ID = /^[a-z][a-z0-9]*(?:[.:_-][a-z0-9]+){1,7}$/u;
|
|
34
|
+
const REQUEST_KEYS = new Set([
|
|
35
|
+
"expiresAt",
|
|
36
|
+
"keyId",
|
|
37
|
+
"operation",
|
|
38
|
+
"policyDigest",
|
|
39
|
+
"priorKeyId",
|
|
40
|
+
"publicKeySpki",
|
|
41
|
+
"reason",
|
|
42
|
+
"requestDigest",
|
|
43
|
+
"requestedAt",
|
|
44
|
+
"requiredApprovals",
|
|
45
|
+
"schema",
|
|
46
|
+
"serviceId",
|
|
47
|
+
"tenantId",
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
function exact(value, keys, label) {
|
|
51
|
+
if (
|
|
52
|
+
!value ||
|
|
53
|
+
typeof value !== "object" ||
|
|
54
|
+
Array.isArray(value) ||
|
|
55
|
+
utilTypes.isProxy(value) ||
|
|
56
|
+
Object.getPrototypeOf(value) !== Object.prototype ||
|
|
57
|
+
Reflect.ownKeys(value).length !== keys.size ||
|
|
58
|
+
Reflect.ownKeys(value).some((key) => {
|
|
59
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
60
|
+
return (
|
|
61
|
+
typeof key !== "string" ||
|
|
62
|
+
!keys.has(key) ||
|
|
63
|
+
!descriptor ||
|
|
64
|
+
!("value" in descriptor) ||
|
|
65
|
+
descriptor.enumerable !== true
|
|
66
|
+
);
|
|
67
|
+
})
|
|
68
|
+
) {
|
|
69
|
+
throw new TypeError(`${label} is invalid`);
|
|
70
|
+
}
|
|
71
|
+
return value;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function filePath(value, label) {
|
|
75
|
+
if (
|
|
76
|
+
typeof value !== "string" ||
|
|
77
|
+
value.trim() !== value ||
|
|
78
|
+
value.length < 1 ||
|
|
79
|
+
value.length > 4096 ||
|
|
80
|
+
value.includes("\0")
|
|
81
|
+
) {
|
|
82
|
+
throw new TypeError(`${label} is invalid`);
|
|
83
|
+
}
|
|
84
|
+
return path.resolve(value);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function decodeJson(bytes, label) {
|
|
88
|
+
let value;
|
|
89
|
+
try {
|
|
90
|
+
value = JSON.parse(new TextDecoder("utf-8", { fatal: true }).decode(bytes));
|
|
91
|
+
} catch {
|
|
92
|
+
throw new Error(`${label} is not valid UTF-8 JSON`);
|
|
93
|
+
}
|
|
94
|
+
if (
|
|
95
|
+
!value ||
|
|
96
|
+
typeof value !== "object" ||
|
|
97
|
+
Array.isArray(value) ||
|
|
98
|
+
Object.getPrototypeOf(value) !== Object.prototype
|
|
99
|
+
) {
|
|
100
|
+
throw new TypeError(`${label} must contain one JSON object`);
|
|
101
|
+
}
|
|
102
|
+
return value;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function readSecureJson(requestedPath, label) {
|
|
106
|
+
const target = filePath(requestedPath, `${label} path`);
|
|
107
|
+
return withTrustedFileParentSync(
|
|
108
|
+
fs,
|
|
109
|
+
target,
|
|
110
|
+
({ canonicalPath, parentDevice, parentDescriptor }) => {
|
|
111
|
+
if (
|
|
112
|
+
process.platform !== "win32" &&
|
|
113
|
+
(Number(fs.fstatSync(parentDescriptor).mode) & 0o022) !== 0
|
|
114
|
+
) {
|
|
115
|
+
throw new Error(`${label} parent must not be group/world writable`);
|
|
116
|
+
}
|
|
117
|
+
let before;
|
|
118
|
+
try {
|
|
119
|
+
before = fs.lstatSync(canonicalPath, { bigint: true });
|
|
120
|
+
} catch (error) {
|
|
121
|
+
if (error?.code === "ENOENT") throw new Error(`${label} was not found`);
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
if (
|
|
125
|
+
before.isSymbolicLink() ||
|
|
126
|
+
!before.isFile() ||
|
|
127
|
+
Number(before.nlink) !== 1
|
|
128
|
+
) {
|
|
129
|
+
throw new Error(`${label} must be a regular, single-link file`);
|
|
130
|
+
}
|
|
131
|
+
if (process.platform !== "win32" && (Number(before.mode) & 0o077) !== 0) {
|
|
132
|
+
throw new Error(`${label} permissions must be 0600`);
|
|
133
|
+
}
|
|
134
|
+
const size = Number(before.size);
|
|
135
|
+
if (
|
|
136
|
+
!Number.isSafeInteger(size) ||
|
|
137
|
+
size < 1 ||
|
|
138
|
+
size > MAX_DOCUMENT_BYTES
|
|
139
|
+
) {
|
|
140
|
+
throw new Error(
|
|
141
|
+
`${label} must be between 1 and ${MAX_DOCUMENT_BYTES} bytes`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
let descriptor = null;
|
|
145
|
+
try {
|
|
146
|
+
descriptor = fs.openSync(
|
|
147
|
+
canonicalPath,
|
|
148
|
+
fs.constants.O_RDONLY | Number(fs.constants.O_NOFOLLOW ?? 0),
|
|
149
|
+
);
|
|
150
|
+
const opened = fs.fstatSync(descriptor, { bigint: true });
|
|
151
|
+
if (
|
|
152
|
+
!opened.isFile() ||
|
|
153
|
+
Number(opened.nlink) !== 1 ||
|
|
154
|
+
!samePathHandleFileIdentity(before, opened, parentDevice)
|
|
155
|
+
) {
|
|
156
|
+
throw new Error(`${label} identity changed while opening`);
|
|
157
|
+
}
|
|
158
|
+
const bytes = readBoundedDescriptor(
|
|
159
|
+
fs,
|
|
160
|
+
descriptor,
|
|
161
|
+
size,
|
|
162
|
+
MAX_DOCUMENT_BYTES,
|
|
163
|
+
);
|
|
164
|
+
const after = fs.fstatSync(descriptor, { bigint: true });
|
|
165
|
+
if (!sameFileStatIdentity(opened, after)) {
|
|
166
|
+
throw new Error(`${label} changed while being read`);
|
|
167
|
+
}
|
|
168
|
+
return decodeJson(bytes, label);
|
|
169
|
+
} finally {
|
|
170
|
+
if (descriptor !== null) fs.closeSync(descriptor);
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function writeExclusiveJson(requestedPath, value, label) {
|
|
177
|
+
const target = filePath(requestedPath, `${label} path`);
|
|
178
|
+
const contents = `${JSON.stringify(value, null, 2)}\n`;
|
|
179
|
+
if (Buffer.byteLength(contents, "utf8") > MAX_DOCUMENT_BYTES) {
|
|
180
|
+
throw new Error(`${label} exceeds the ${MAX_DOCUMENT_BYTES}-byte limit`);
|
|
181
|
+
}
|
|
182
|
+
return withTrustedFileParentSync(
|
|
183
|
+
fs,
|
|
184
|
+
target,
|
|
185
|
+
({ canonicalPath, parentDescriptor }) => {
|
|
186
|
+
if (
|
|
187
|
+
process.platform !== "win32" &&
|
|
188
|
+
(Number(fs.fstatSync(parentDescriptor).mode) & 0o022) !== 0
|
|
189
|
+
) {
|
|
190
|
+
throw new Error(`${label} parent must not be group/world writable`);
|
|
191
|
+
}
|
|
192
|
+
let descriptor = null;
|
|
193
|
+
let created = false;
|
|
194
|
+
try {
|
|
195
|
+
descriptor = fs.openSync(canonicalPath, "wx", 0o600);
|
|
196
|
+
created = true;
|
|
197
|
+
fs.writeFileSync(descriptor, contents, "utf8");
|
|
198
|
+
fs.fsyncSync(descriptor);
|
|
199
|
+
fs.closeSync(descriptor);
|
|
200
|
+
descriptor = null;
|
|
201
|
+
if (process.platform !== "win32") fs.fsyncSync(parentDescriptor);
|
|
202
|
+
return canonicalPath;
|
|
203
|
+
} catch (error) {
|
|
204
|
+
if (descriptor !== null) {
|
|
205
|
+
try {
|
|
206
|
+
fs.closeSync(descriptor);
|
|
207
|
+
} catch {
|
|
208
|
+
/* Preserve the authoritative write failure. */
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (created) {
|
|
212
|
+
try {
|
|
213
|
+
fs.unlinkSync(canonicalPath);
|
|
214
|
+
} catch {
|
|
215
|
+
/* Clean only the file exclusively created by this attempt. */
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
throw error;
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function canonicalTimestamp(value, label) {
|
|
225
|
+
const milliseconds = Date.parse(value);
|
|
226
|
+
if (
|
|
227
|
+
typeof value !== "string" ||
|
|
228
|
+
!Number.isFinite(milliseconds) ||
|
|
229
|
+
new Date(milliseconds).toISOString() !== value
|
|
230
|
+
) {
|
|
231
|
+
throw new TypeError(`${label} is invalid`);
|
|
232
|
+
}
|
|
233
|
+
return milliseconds;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function publicKeyBinding(value, label) {
|
|
237
|
+
let publicKey;
|
|
238
|
+
try {
|
|
239
|
+
publicKey = createPublicKey(value);
|
|
240
|
+
} catch {
|
|
241
|
+
throw new TypeError(`${label} is invalid`);
|
|
242
|
+
}
|
|
243
|
+
if (publicKey.asymmetricKeyType !== "ed25519") {
|
|
244
|
+
throw new TypeError(`${label} must be Ed25519`);
|
|
245
|
+
}
|
|
246
|
+
const spki = publicKey.export({ type: "spki", format: "der" });
|
|
247
|
+
return Object.freeze({
|
|
248
|
+
keyId: `key:ed25519:${createHash("sha256").update(spki).digest("hex")}`,
|
|
249
|
+
publicKeySpki: spki.toString("base64url"),
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function normalizeOperation(value) {
|
|
254
|
+
if (
|
|
255
|
+
!value ||
|
|
256
|
+
typeof value !== "object" ||
|
|
257
|
+
Array.isArray(value) ||
|
|
258
|
+
!["register", "rotate", "revoke"].includes(value.operation) ||
|
|
259
|
+
!SERVICE_ID.test(value.serviceId ?? "")
|
|
260
|
+
) {
|
|
261
|
+
throw new TypeError("attestor trust operation file is invalid");
|
|
262
|
+
}
|
|
263
|
+
if (value.operation === "register") {
|
|
264
|
+
exact(
|
|
265
|
+
value,
|
|
266
|
+
new Set(["operation", "publicKey", "serviceId"]),
|
|
267
|
+
"attestor trust registration operation",
|
|
268
|
+
);
|
|
269
|
+
return Object.freeze({
|
|
270
|
+
input: value,
|
|
271
|
+
expected: {
|
|
272
|
+
operation: value.operation,
|
|
273
|
+
serviceId: value.serviceId,
|
|
274
|
+
priorKeyId: null,
|
|
275
|
+
reason: null,
|
|
276
|
+
...publicKeyBinding(value.publicKey, "attestor public key"),
|
|
277
|
+
},
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
if (value.operation === "rotate") {
|
|
281
|
+
exact(
|
|
282
|
+
value,
|
|
283
|
+
new Set(["operation", "priorKeyId", "publicKey", "reason", "serviceId"]),
|
|
284
|
+
"attestor trust rotation operation",
|
|
285
|
+
);
|
|
286
|
+
const key = publicKeyBinding(value.publicKey, "attestor public key");
|
|
287
|
+
if (
|
|
288
|
+
!KEY_ID.test(value.priorKeyId ?? "") ||
|
|
289
|
+
value.priorKeyId === key.keyId ||
|
|
290
|
+
typeof value.reason !== "string" ||
|
|
291
|
+
value.reason.trim() !== value.reason ||
|
|
292
|
+
value.reason.length < 1 ||
|
|
293
|
+
value.reason.length > 2048
|
|
294
|
+
) {
|
|
295
|
+
throw new TypeError("attestor trust rotation operation is invalid");
|
|
296
|
+
}
|
|
297
|
+
return Object.freeze({
|
|
298
|
+
input: value,
|
|
299
|
+
expected: {
|
|
300
|
+
operation: value.operation,
|
|
301
|
+
serviceId: value.serviceId,
|
|
302
|
+
priorKeyId: value.priorKeyId,
|
|
303
|
+
reason: value.reason,
|
|
304
|
+
...key,
|
|
305
|
+
},
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
exact(
|
|
309
|
+
value,
|
|
310
|
+
new Set(["keyId", "operation", "reason", "serviceId"]),
|
|
311
|
+
"attestor trust revocation operation",
|
|
312
|
+
);
|
|
313
|
+
if (
|
|
314
|
+
!KEY_ID.test(value.keyId ?? "") ||
|
|
315
|
+
typeof value.reason !== "string" ||
|
|
316
|
+
value.reason.trim() !== value.reason ||
|
|
317
|
+
value.reason.length < 1 ||
|
|
318
|
+
value.reason.length > 2048
|
|
319
|
+
) {
|
|
320
|
+
throw new TypeError("attestor trust revocation operation is invalid");
|
|
321
|
+
}
|
|
322
|
+
return Object.freeze({
|
|
323
|
+
input: value,
|
|
324
|
+
expected: {
|
|
325
|
+
operation: value.operation,
|
|
326
|
+
serviceId: value.serviceId,
|
|
327
|
+
keyId: value.keyId,
|
|
328
|
+
publicKeySpki: null,
|
|
329
|
+
priorKeyId: null,
|
|
330
|
+
reason: value.reason,
|
|
331
|
+
},
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function normalizeOperatorChangeOperation(value) {
|
|
336
|
+
if (
|
|
337
|
+
!value ||
|
|
338
|
+
typeof value !== "object" ||
|
|
339
|
+
Array.isArray(value) ||
|
|
340
|
+
!["register", "rotate", "revoke"].includes(value.operation) ||
|
|
341
|
+
!/^[A-Za-z0-9][A-Za-z0-9._:@/-]{0,255}$/u.test(value.operatorId ?? "")
|
|
342
|
+
) {
|
|
343
|
+
throw new TypeError("operator registry change operation is invalid");
|
|
344
|
+
}
|
|
345
|
+
if (value.operation === "register") {
|
|
346
|
+
exact(
|
|
347
|
+
value,
|
|
348
|
+
new Set(["operation", "operatorId", "publicKey"]),
|
|
349
|
+
"operator registration operation",
|
|
350
|
+
);
|
|
351
|
+
return Object.freeze({
|
|
352
|
+
input: value,
|
|
353
|
+
expected: {
|
|
354
|
+
operation: value.operation,
|
|
355
|
+
operatorId: value.operatorId,
|
|
356
|
+
priorKeyId: null,
|
|
357
|
+
reason: null,
|
|
358
|
+
...publicKeyBinding(value.publicKey, "operator public key"),
|
|
359
|
+
},
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
if (value.operation === "rotate") {
|
|
363
|
+
exact(
|
|
364
|
+
value,
|
|
365
|
+
new Set(["operation", "operatorId", "priorKeyId", "publicKey", "reason"]),
|
|
366
|
+
"operator rotation operation",
|
|
367
|
+
);
|
|
368
|
+
const key = publicKeyBinding(value.publicKey, "operator public key");
|
|
369
|
+
if (
|
|
370
|
+
!KEY_ID.test(value.priorKeyId ?? "") ||
|
|
371
|
+
value.priorKeyId === key.keyId ||
|
|
372
|
+
typeof value.reason !== "string" ||
|
|
373
|
+
value.reason.trim() !== value.reason ||
|
|
374
|
+
value.reason.length < 1 ||
|
|
375
|
+
value.reason.length > 2048
|
|
376
|
+
) {
|
|
377
|
+
throw new TypeError("operator rotation operation is invalid");
|
|
378
|
+
}
|
|
379
|
+
return Object.freeze({
|
|
380
|
+
input: value,
|
|
381
|
+
expected: {
|
|
382
|
+
operation: value.operation,
|
|
383
|
+
operatorId: value.operatorId,
|
|
384
|
+
priorKeyId: value.priorKeyId,
|
|
385
|
+
reason: value.reason,
|
|
386
|
+
...key,
|
|
387
|
+
},
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
exact(
|
|
391
|
+
value,
|
|
392
|
+
new Set(["keyId", "operation", "operatorId", "reason"]),
|
|
393
|
+
"operator revocation operation",
|
|
394
|
+
);
|
|
395
|
+
if (
|
|
396
|
+
!KEY_ID.test(value.keyId ?? "") ||
|
|
397
|
+
typeof value.reason !== "string" ||
|
|
398
|
+
value.reason.trim() !== value.reason ||
|
|
399
|
+
value.reason.length < 1 ||
|
|
400
|
+
value.reason.length > 2048
|
|
401
|
+
) {
|
|
402
|
+
throw new TypeError("operator revocation operation is invalid");
|
|
403
|
+
}
|
|
404
|
+
return Object.freeze({
|
|
405
|
+
input: value,
|
|
406
|
+
expected: {
|
|
407
|
+
operation: value.operation,
|
|
408
|
+
operatorId: value.operatorId,
|
|
409
|
+
keyId: value.keyId,
|
|
410
|
+
publicKeySpki: null,
|
|
411
|
+
priorKeyId: null,
|
|
412
|
+
reason: value.reason,
|
|
413
|
+
},
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function validatePreparedRequest(value, service, currentTime) {
|
|
418
|
+
if (!Number.isFinite(currentTime)) {
|
|
419
|
+
throw new TypeError("attestor trust operations CLI clock is invalid");
|
|
420
|
+
}
|
|
421
|
+
exact(value, REQUEST_KEYS, "prepared attestor trust request");
|
|
422
|
+
const requestedAt = canonicalTimestamp(value.requestedAt, "requestedAt");
|
|
423
|
+
const expiresAt = canonicalTimestamp(value.expiresAt, "expiresAt");
|
|
424
|
+
if (
|
|
425
|
+
value.schema !==
|
|
426
|
+
GOVERNED_SKILL_SYNTHESIS_ATTESTOR_TRUST_OPERATION_REQUEST_SCHEMA ||
|
|
427
|
+
value.tenantId !== service.tenantId ||
|
|
428
|
+
value.policyDigest !== service.policyDigest ||
|
|
429
|
+
value.requiredApprovals !== service.requiredApprovals ||
|
|
430
|
+
!DIGEST.test(value.requestDigest ?? "") ||
|
|
431
|
+
!SERVICE_ID.test(value.serviceId ?? "") ||
|
|
432
|
+
!KEY_ID.test(value.keyId ?? "") ||
|
|
433
|
+
!["register", "rotate", "revoke"].includes(value.operation) ||
|
|
434
|
+
requestedAt > currentTime + FUTURE_SKEW_MS ||
|
|
435
|
+
expiresAt <= currentTime ||
|
|
436
|
+
expiresAt <= requestedAt ||
|
|
437
|
+
expiresAt > requestedAt + MAX_REQUEST_TTL_MS ||
|
|
438
|
+
value.requestDigest !==
|
|
439
|
+
digestGovernedSkillSynthesisAttestorTrustOperationRequest(value)
|
|
440
|
+
) {
|
|
441
|
+
throw new Error("prepared attestor trust request is not policy-bound");
|
|
442
|
+
}
|
|
443
|
+
if (value.operation === "register" || value.operation === "rotate") {
|
|
444
|
+
if (typeof value.publicKeySpki !== "string") {
|
|
445
|
+
throw new Error("prepared attestor trust public key is missing");
|
|
446
|
+
}
|
|
447
|
+
let publicKey;
|
|
448
|
+
try {
|
|
449
|
+
const bytes = Buffer.from(value.publicKeySpki, "base64url");
|
|
450
|
+
if (bytes.toString("base64url") !== value.publicKeySpki)
|
|
451
|
+
throw new Error();
|
|
452
|
+
publicKey = createPublicKey({ key: bytes, type: "spki", format: "der" });
|
|
453
|
+
} catch {
|
|
454
|
+
throw new Error("prepared attestor trust public key is invalid");
|
|
455
|
+
}
|
|
456
|
+
const keyId = `key:ed25519:${createHash("sha256")
|
|
457
|
+
.update(publicKey.export({ type: "spki", format: "der" }))
|
|
458
|
+
.digest("hex")}`;
|
|
459
|
+
if (publicKey.asymmetricKeyType !== "ed25519" || keyId !== value.keyId) {
|
|
460
|
+
throw new Error("prepared attestor trust public key binding is invalid");
|
|
461
|
+
}
|
|
462
|
+
if (
|
|
463
|
+
(value.operation === "register" &&
|
|
464
|
+
(value.priorKeyId !== null || value.reason !== null)) ||
|
|
465
|
+
(value.operation === "rotate" &&
|
|
466
|
+
(!KEY_ID.test(value.priorKeyId ?? "") ||
|
|
467
|
+
value.priorKeyId === value.keyId ||
|
|
468
|
+
typeof value.reason !== "string" ||
|
|
469
|
+
value.reason.trim() !== value.reason ||
|
|
470
|
+
value.reason.length < 1 ||
|
|
471
|
+
value.reason.length > 2048))
|
|
472
|
+
) {
|
|
473
|
+
throw new Error("prepared attestor trust operation fields are invalid");
|
|
474
|
+
}
|
|
475
|
+
} else if (
|
|
476
|
+
value.publicKeySpki !== null ||
|
|
477
|
+
value.priorKeyId !== null ||
|
|
478
|
+
typeof value.reason !== "string" ||
|
|
479
|
+
value.reason.trim() !== value.reason ||
|
|
480
|
+
value.reason.length < 1 ||
|
|
481
|
+
value.reason.length > 2048
|
|
482
|
+
) {
|
|
483
|
+
throw new Error("prepared attestor trust revocation fields are invalid");
|
|
484
|
+
}
|
|
485
|
+
return Object.freeze(structuredClone(value));
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function bindPreparedRequest(request, expected) {
|
|
489
|
+
for (const field of [
|
|
490
|
+
"operation",
|
|
491
|
+
"serviceId",
|
|
492
|
+
"keyId",
|
|
493
|
+
"publicKeySpki",
|
|
494
|
+
"priorKeyId",
|
|
495
|
+
"reason",
|
|
496
|
+
]) {
|
|
497
|
+
if (request[field] !== expected[field]) {
|
|
498
|
+
throw new Error(
|
|
499
|
+
"prepared attestor trust request substituted its operation",
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
return request;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function bindPreparedOperatorChangeRequest(request, expected) {
|
|
507
|
+
for (const field of [
|
|
508
|
+
"operation",
|
|
509
|
+
"operatorId",
|
|
510
|
+
"keyId",
|
|
511
|
+
"publicKeySpki",
|
|
512
|
+
"priorKeyId",
|
|
513
|
+
"reason",
|
|
514
|
+
]) {
|
|
515
|
+
if (request[field] !== expected[field]) {
|
|
516
|
+
throw new Error("prepared operator change substituted its operation");
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
return request;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
function readApprovalFiles(approvalPaths, requiredApprovals) {
|
|
523
|
+
if (
|
|
524
|
+
!Array.isArray(approvalPaths) ||
|
|
525
|
+
approvalPaths.length !== requiredApprovals ||
|
|
526
|
+
approvalPaths.length > MAX_APPROVAL_FILES
|
|
527
|
+
) {
|
|
528
|
+
throw new Error(
|
|
529
|
+
`exactly ${requiredApprovals} approval file(s) are required`,
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
const normalizedPaths = approvalPaths.map((entry) =>
|
|
533
|
+
filePath(entry, "approval file path"),
|
|
534
|
+
);
|
|
535
|
+
const comparablePaths = normalizedPaths.map((entry) =>
|
|
536
|
+
process.platform === "win32" ? entry.toLowerCase() : entry,
|
|
537
|
+
);
|
|
538
|
+
if (new Set(comparablePaths).size !== comparablePaths.length) {
|
|
539
|
+
throw new Error("approval file paths must be distinct");
|
|
540
|
+
}
|
|
541
|
+
return normalizedPaths.map((entry) => readSecureJson(entry, "approval file"));
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
export function createGovernedSkillSynthesisAttestorTrustOperationsCliHost({
|
|
545
|
+
approvalClient = null,
|
|
546
|
+
client,
|
|
547
|
+
now = Date.now,
|
|
548
|
+
} = {}) {
|
|
549
|
+
if (!isGovernedSkillSynthesisAttestorTrustOperationsClient(client)) {
|
|
550
|
+
throw new TypeError(
|
|
551
|
+
"a branded attestor trust operations client is required",
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
if (typeof now !== "function" || utilTypes.isProxy(now)) {
|
|
555
|
+
throw new TypeError("attestor trust operations CLI clock is invalid");
|
|
556
|
+
}
|
|
557
|
+
if (
|
|
558
|
+
approvalClient !== null &&
|
|
559
|
+
!isGovernedSkillSynthesisAttestorTrustApprovalClient(approvalClient)
|
|
560
|
+
) {
|
|
561
|
+
throw new TypeError("approvalClient must be a branded approval client");
|
|
562
|
+
}
|
|
563
|
+
const prepareRemote = client.prepare.bind(client);
|
|
564
|
+
const executeRemote = client.execute.bind(client);
|
|
565
|
+
const prepareOperatorChangeRemote = client.prepareOperatorChange.bind(client);
|
|
566
|
+
const executeOperatorChangeRemote = client.executeOperatorChange.bind(client);
|
|
567
|
+
const service = client.descriptor.service;
|
|
568
|
+
const approvalService = approvalClient?.descriptor.service ?? null;
|
|
569
|
+
if (
|
|
570
|
+
approvalService &&
|
|
571
|
+
(approvalService.tenantId !== service.tenantId ||
|
|
572
|
+
approvalService.policyId !== service.policyId ||
|
|
573
|
+
approvalService.revision !== service.revision ||
|
|
574
|
+
approvalService.policyDigest !== service.policyDigest)
|
|
575
|
+
) {
|
|
576
|
+
throw new Error("approval signer crossed the operations policy boundary");
|
|
577
|
+
}
|
|
578
|
+
if (
|
|
579
|
+
approvalService &&
|
|
580
|
+
!service.operators.some(
|
|
581
|
+
(operator) =>
|
|
582
|
+
operator.operatorId === approvalService.operatorId &&
|
|
583
|
+
operator.keyId === approvalService.keyId,
|
|
584
|
+
)
|
|
585
|
+
) {
|
|
586
|
+
throw new Error("approval signer is not an active registry operator");
|
|
587
|
+
}
|
|
588
|
+
const approveRemote = approvalClient?.approve.bind(approvalClient) ?? null;
|
|
589
|
+
const approveOperatorChangeRemote =
|
|
590
|
+
approvalClient?.approveOperatorChange.bind(approvalClient) ?? null;
|
|
591
|
+
const descriptor = Object.freeze({
|
|
592
|
+
schema: GOVERNED_SKILL_SYNTHESIS_ATTESTOR_TRUST_OPERATIONS_CLI_HOST_SCHEMA,
|
|
593
|
+
clientSchema:
|
|
594
|
+
GOVERNED_SKILL_SYNTHESIS_ATTESTOR_TRUST_OPERATIONS_CLIENT_SCHEMA,
|
|
595
|
+
isolation: client.descriptor.isolation,
|
|
596
|
+
transport: client.descriptor.transport,
|
|
597
|
+
endpointDigest: client.descriptor.endpointDigest,
|
|
598
|
+
approvalSigner:
|
|
599
|
+
approvalService === null
|
|
600
|
+
? null
|
|
601
|
+
: Object.freeze({
|
|
602
|
+
isolation: approvalClient.descriptor.isolation,
|
|
603
|
+
transport: approvalClient.descriptor.transport,
|
|
604
|
+
endpointDigest: approvalClient.descriptor.endpointDigest,
|
|
605
|
+
signerId: approvalService.signerId,
|
|
606
|
+
operatorId: approvalService.operatorId,
|
|
607
|
+
keyId: approvalService.keyId,
|
|
608
|
+
policyId: approvalService.policyId,
|
|
609
|
+
revision: approvalService.revision,
|
|
610
|
+
policyDigest: approvalService.policyDigest,
|
|
611
|
+
}),
|
|
612
|
+
service,
|
|
613
|
+
});
|
|
614
|
+
const host = Object.freeze({
|
|
615
|
+
descriptor,
|
|
616
|
+
async prepare(input) {
|
|
617
|
+
exact(
|
|
618
|
+
input,
|
|
619
|
+
new Set(["operationPath", "outputPath"]),
|
|
620
|
+
"attestor trust prepare CLI input",
|
|
621
|
+
);
|
|
622
|
+
const operation = normalizeOperation(
|
|
623
|
+
readSecureJson(input.operationPath, "operation file"),
|
|
624
|
+
);
|
|
625
|
+
const request = bindPreparedRequest(
|
|
626
|
+
validatePreparedRequest(
|
|
627
|
+
await prepareRemote(operation.input),
|
|
628
|
+
service,
|
|
629
|
+
Number(now()),
|
|
630
|
+
),
|
|
631
|
+
operation.expected,
|
|
632
|
+
);
|
|
633
|
+
const outputPath = writeExclusiveJson(
|
|
634
|
+
input.outputPath,
|
|
635
|
+
request,
|
|
636
|
+
"request plan",
|
|
637
|
+
);
|
|
638
|
+
return Object.freeze({
|
|
639
|
+
created: true,
|
|
640
|
+
outputPath,
|
|
641
|
+
requestDigest: request.requestDigest,
|
|
642
|
+
operation: request.operation,
|
|
643
|
+
serviceId: request.serviceId,
|
|
644
|
+
requiredApprovals: request.requiredApprovals,
|
|
645
|
+
expiresAt: request.expiresAt,
|
|
646
|
+
});
|
|
647
|
+
},
|
|
648
|
+
async execute(input) {
|
|
649
|
+
exact(
|
|
650
|
+
input,
|
|
651
|
+
new Set(["approvalPaths", "requestPath"]),
|
|
652
|
+
"attestor trust execute CLI input",
|
|
653
|
+
);
|
|
654
|
+
const approvals = readApprovalFiles(
|
|
655
|
+
input.approvalPaths,
|
|
656
|
+
service.requiredApprovals,
|
|
657
|
+
);
|
|
658
|
+
const request = validatePreparedRequest(
|
|
659
|
+
readSecureJson(input.requestPath, "request plan"),
|
|
660
|
+
service,
|
|
661
|
+
Number(now()),
|
|
662
|
+
);
|
|
663
|
+
return executeRemote({ request, approvals });
|
|
664
|
+
},
|
|
665
|
+
async approve(input) {
|
|
666
|
+
exact(
|
|
667
|
+
input,
|
|
668
|
+
new Set(["outputPath", "requestPath"]),
|
|
669
|
+
"attestor trust approve CLI input",
|
|
670
|
+
);
|
|
671
|
+
if (!approveRemote) {
|
|
672
|
+
throw new Error("attestor trust approval signer is unavailable");
|
|
673
|
+
}
|
|
674
|
+
const request = validatePreparedRequest(
|
|
675
|
+
readSecureJson(input.requestPath, "request plan"),
|
|
676
|
+
service,
|
|
677
|
+
Number(now()),
|
|
678
|
+
);
|
|
679
|
+
const approval = await approveRemote(request);
|
|
680
|
+
const outputPath = writeExclusiveJson(
|
|
681
|
+
input.outputPath,
|
|
682
|
+
approval,
|
|
683
|
+
"approval receipt",
|
|
684
|
+
);
|
|
685
|
+
return Object.freeze({
|
|
686
|
+
created: true,
|
|
687
|
+
outputPath,
|
|
688
|
+
requestDigest: request.requestDigest,
|
|
689
|
+
receiptDigest: approval.receiptDigest,
|
|
690
|
+
operatorId: approval.operatorId,
|
|
691
|
+
keyId: approval.attestation.keyId,
|
|
692
|
+
expiresAt: approval.expiresAt,
|
|
693
|
+
});
|
|
694
|
+
},
|
|
695
|
+
async prepareOperatorChange(input) {
|
|
696
|
+
exact(
|
|
697
|
+
input,
|
|
698
|
+
new Set(["operationPath", "outputPath"]),
|
|
699
|
+
"operator change prepare CLI input",
|
|
700
|
+
);
|
|
701
|
+
const operation = normalizeOperatorChangeOperation(
|
|
702
|
+
readSecureJson(input.operationPath, "operator change operation file"),
|
|
703
|
+
);
|
|
704
|
+
const request = bindPreparedOperatorChangeRequest(
|
|
705
|
+
validateGovernedSkillSynthesisAttestorTrustOperatorRegistryChangeRequest(
|
|
706
|
+
await prepareOperatorChangeRemote(operation.input),
|
|
707
|
+
{
|
|
708
|
+
tenantId: service.tenantId,
|
|
709
|
+
policyId: service.policyId,
|
|
710
|
+
revision: service.revision,
|
|
711
|
+
policyDigest: service.policyDigest,
|
|
712
|
+
requiredApprovals: service.requiredApprovals,
|
|
713
|
+
},
|
|
714
|
+
Number(now()),
|
|
715
|
+
),
|
|
716
|
+
operation.expected,
|
|
717
|
+
);
|
|
718
|
+
const outputPath = writeExclusiveJson(
|
|
719
|
+
input.outputPath,
|
|
720
|
+
request,
|
|
721
|
+
"operator change request plan",
|
|
722
|
+
);
|
|
723
|
+
return Object.freeze({
|
|
724
|
+
created: true,
|
|
725
|
+
outputPath,
|
|
726
|
+
requestDigest: request.requestDigest,
|
|
727
|
+
operation: request.operation,
|
|
728
|
+
operatorId: request.operatorId,
|
|
729
|
+
requiredApprovals: request.requiredApprovals,
|
|
730
|
+
revision: request.revision,
|
|
731
|
+
expiresAt: request.expiresAt,
|
|
732
|
+
});
|
|
733
|
+
},
|
|
734
|
+
async executeOperatorChange(input) {
|
|
735
|
+
exact(
|
|
736
|
+
input,
|
|
737
|
+
new Set(["approvalPaths", "requestPath"]),
|
|
738
|
+
"operator change execute CLI input",
|
|
739
|
+
);
|
|
740
|
+
const approvals = readApprovalFiles(
|
|
741
|
+
input.approvalPaths,
|
|
742
|
+
service.requiredApprovals,
|
|
743
|
+
);
|
|
744
|
+
const request =
|
|
745
|
+
validateGovernedSkillSynthesisAttestorTrustOperatorRegistryChangeRequest(
|
|
746
|
+
readSecureJson(input.requestPath, "operator change request plan"),
|
|
747
|
+
{
|
|
748
|
+
tenantId: service.tenantId,
|
|
749
|
+
policyId: service.policyId,
|
|
750
|
+
revision: service.revision,
|
|
751
|
+
policyDigest: service.policyDigest,
|
|
752
|
+
requiredApprovals: service.requiredApprovals,
|
|
753
|
+
},
|
|
754
|
+
Number(now()),
|
|
755
|
+
);
|
|
756
|
+
return executeOperatorChangeRemote({ request, approvals });
|
|
757
|
+
},
|
|
758
|
+
async approveOperatorChange(input) {
|
|
759
|
+
exact(
|
|
760
|
+
input,
|
|
761
|
+
new Set(["outputPath", "requestPath"]),
|
|
762
|
+
"operator change approve CLI input",
|
|
763
|
+
);
|
|
764
|
+
if (!approveOperatorChangeRemote) {
|
|
765
|
+
throw new Error("attestor trust approval signer is unavailable");
|
|
766
|
+
}
|
|
767
|
+
const request =
|
|
768
|
+
validateGovernedSkillSynthesisAttestorTrustOperatorRegistryChangeRequest(
|
|
769
|
+
readSecureJson(input.requestPath, "operator change request plan"),
|
|
770
|
+
{
|
|
771
|
+
tenantId: service.tenantId,
|
|
772
|
+
policyId: service.policyId,
|
|
773
|
+
revision: service.revision,
|
|
774
|
+
policyDigest: service.policyDigest,
|
|
775
|
+
requiredApprovals: service.requiredApprovals,
|
|
776
|
+
},
|
|
777
|
+
Number(now()),
|
|
778
|
+
);
|
|
779
|
+
const approval = await approveOperatorChangeRemote(request);
|
|
780
|
+
const outputPath = writeExclusiveJson(
|
|
781
|
+
input.outputPath,
|
|
782
|
+
approval,
|
|
783
|
+
"operator change approval receipt",
|
|
784
|
+
);
|
|
785
|
+
return Object.freeze({
|
|
786
|
+
created: true,
|
|
787
|
+
outputPath,
|
|
788
|
+
requestDigest: request.requestDigest,
|
|
789
|
+
receiptDigest: approval.receiptDigest,
|
|
790
|
+
operatorId: approval.operatorId,
|
|
791
|
+
keyId: approval.attestation.keyId,
|
|
792
|
+
expiresAt: approval.expiresAt,
|
|
793
|
+
});
|
|
794
|
+
},
|
|
795
|
+
});
|
|
796
|
+
HOSTS.add(host);
|
|
797
|
+
return host;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
export function isGovernedSkillSynthesisAttestorTrustOperationsCliHost(value) {
|
|
801
|
+
return HOSTS.has(value);
|
|
802
|
+
}
|