chainlesschain 0.163.8 → 0.164.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -1
- package/scripts/macos-mcp-launcher-build.mjs +317 -0
- package/scripts/macos-mcp-launcher-postinstall.sh +54 -0
- package/scripts/macos-mcp-launcher-preinstall.sh +61 -0
- package/src/assets/web-panel/assets/{AIOps-CavM7W3k.js → AIOps-D2MEn7fI.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CUvZGabQ.js → ActionButton-lCW_4Gf0.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-DeBnWnbe.js → Analytics-Bs7i-nsS.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-DbI5kxvd.js → AppLayout-CK7B6S_j.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-D93bigKm.js → Artifacts-C8ILjpyo.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CBNvfUZa.js → Audit-Bb9cNaWc.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-CJLyh_YU.js → BackgroundAgents-sC9ooXIf.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-D_0yoehD.js → Backup-D-DrsplT.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-TJxmbObW.js → BaseInput-uCNZpwSK.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CE0dto1q.js → Chat-CsDK1uE9.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CZ5-yYiD.js → ChatBubbleRenderer-OqSDt50w.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-Ck1RVIVo.js → Checkbox-JhTXM1-K.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-qpoyf6DK.js → Codegen-BbzZLnyD.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DUyPWjIE.js → Col-D4VW4m4j.js} +1 -1
- package/src/assets/web-panel/assets/{Community-D_S1BemS.js → Community-BXrYawxV.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BjxeK-Gc.js → Compact-DCihGy1u.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-Dd3CEJsu.js → Compliance-DlyZ-lk8.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-B4QG7-ad.js → Cowork-DvGZrhbO.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-BtZnids5.js → Cron-DUncZi8h.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CHPfCBFD.js → Crosschain-C_hLuUcm.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DT8DCEOK.js → DID-b6YSUqxr.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-COQab5_U.js → Dashboard-uvM15Cfb.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-BY1PsQuU.js → Dropdown-D1-Nd4qY.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-CsuAuaq3.js → EmailListRenderer-8ApvL6Zc.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BqpinD-j.js → FamilyGuardDashboard-LYJt8811.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-D0gkfQFv.js → Federation-BbI3HGpv.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BqgE-axK.js → FormItemContext-DSoEKuFu.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-D0hJ2KvC.js → GenericCardRenderer-B0S9OWd5.js} +1 -1
- package/src/assets/web-panel/assets/{Git-CmMB0uPY.js → Git-DIs9Zhf3.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-BnVEI0Dk.js → Governance-jzZXrxcl.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-YTAMihRP.js → Inference-JUPjf2ZI.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-0ax7VHop.js → KnowledgeGraph-DxnfJvlP.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-B9TRcokL.js → Logs-iXiz8BEE.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-GmB6DOr6.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-B6CSuD_H.js → Marketplace-Y3Xch312.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CjMXvOVU.js → McpTools-D7kGGbO7.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-CXRF71U3.js → Memory-Do_hVxzh.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DQgNp_oS.js → MobileBridge-CtrR0Tas.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-BL0Czcoj.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-6hDTRPe1.js → Mtc-qo5QCTGd.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-BlVHU1DS.js → MtcAudit-cq5mnjYj.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-DP9pzEbV.js → Multisig-Bq0MAQHw.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Djorh8EV.js → NLProgramming-DdWE6Vi2.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-oLZ-JkUg.js → Notes-BxMBFcIp.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-Cg288VH3.js → NotificationSettings-RTrAcbUe.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-Bb1O3Ofr.js → OrderTableRenderer-DJbpGqzT.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-CBdo-bHs.js → Organization-SQzIPdqC.js} +2 -2
- package/src/assets/web-panel/assets/{Overflow-qZdnVumx.js → Overflow-02yECh22.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-D4kNfGNQ.js → P2P-BNg4pNCM.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-DnlMemM7.js → PdhVaultBrowser-BxPJZsD3.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-DHucHFBJ.js → Permissions-CLnDnPAz.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-BovlOIPR.js → PersonalDataHub-C5m0AjGf.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-Deru3CQY.js → Pipeline-VwOf5Dhv.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-Bq5oTTbU.js → Privacy-CC0W2hZd.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-BfzxVWAz.js → ProjectInit-Dz893Bob.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CKC6XBtH.js → ProjectSettings-CxQkvl0k.js} +2 -2
- package/src/assets/web-panel/assets/Projects-DDAjkUkT.js +1 -0
- package/src/assets/web-panel/assets/{Providers-C_jx4TWX.js → Providers-DeB9IkxK.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-BdIHeVGC.js → QrScannerModal-OCeoaswn.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BwZwAcPD.js → QuickAsk-DenotaAj.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BNTt0L-m.js → Recommend-Cies_jjI.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-Biyn2-Ro.js → RemoteSession-Dxzl5n2T.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-D6VpG32B.js → Reputation-CW0mvxgZ.js} +1 -1
- package/src/assets/web-panel/assets/{Row-D_74OvQQ.js → Row-SEd32qZU.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-BTr0a-BQ.js → RssFeed-BSwnJ3Lm.js} +3 -3
- package/src/assets/web-panel/assets/{Search-C3MCFoNU.js → Search-xe2m8bkC.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CqW9aJ6s.js → Security-Mq2F9Nro.js} +3 -3
- package/src/assets/web-panel/assets/{Services-Cw5GNaHF.js → Services-BKGw2V3P.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DZps5qeY.js → Skeleton-DW95-Rxf.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-C6NQ1znT.js → Skills-CHgChCv_.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DFP8G2Sh.js → Sla-tKh6k3R7.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-ESt6MB6v.js → SpeechSettings-D6UL3dA5.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-BHnN98aM.js → SyncSettings-D0Fw8fVL.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-NiSCaOf-.js → Tasks-20x1GB3D.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-DsKFhW2C.js → Templates-DJ-lts-a.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-CQ0E0ze5.js → Tenant-BFdGpbs7.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-D_rBu_by.js → Terminal-Xpx61vHL.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-D3Vm4Po4.js → TimelineRenderer-C6UIvyZQ.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DNTxRH6q.js → Tokens-Dellq08f.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-Dgprz1ms.js → Trigger-VKw8d0J-.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-B2rUnVBD.js → Trust-DNftdKT5.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-DEGQNc6_.js → UkeySign-DX9VAKJI.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-jlsAx3Eh.js → VideoEditing-B2h3jO8q.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-8jQih1ij.js → Wallet-CjGkof7f.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-XLeO6xIB.js → WebAuthn-2Zfcu55P.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-De_dgDAG.js → WorkflowEditor-B9eZ8UxZ.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CI19R_Sk.js → chat-CQNfD-YO.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DsYTOYN3.js → colors-D4usyFT2.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-CM3-t_Qr.js → compact-item-s4TpjvjX.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BjxlBRZv.js → createContext-BRCSvYxj.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DKJjSWRn.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-RDaWX_4i.js → hasIn-AdkUbkV-.js} +1 -1
- package/src/assets/web-panel/assets/{index-BN6UPD2E.js → index--00U6vXZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CiECJi-Q.js → index-B2V-eKfK.js} +1 -1
- package/src/assets/web-panel/assets/{index-CnHH7bnD.js → index-B4JJCfQ2.js} +1 -1
- package/src/assets/web-panel/assets/{index-CjTrRt13.js → index-BIoG5yYf.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dxge-xWl.js → index-BMcimU-2.js} +1 -1
- package/src/assets/web-panel/assets/{index-9R6BxAr0.js → index-BPhkFZ1I.js} +1 -1
- package/src/assets/web-panel/assets/{index-BHNYPO0b.js → index-BQ3DXBtD.js} +3 -3
- package/src/assets/web-panel/assets/{index-Cpqm1qfU.js → index-Bad4VNvz.js} +1 -1
- package/src/assets/web-panel/assets/{index-B9O9YyWE.js → index-BgiXR_-_.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5REnKt8.js → index-BtobShro.js} +1 -1
- package/src/assets/web-panel/assets/{index-D6sm5-Xq.js → index-Bw2MEnUk.js} +1 -1
- package/src/assets/web-panel/assets/{index-DcPFB8qJ.js → index-C1mJtE6q.js} +1 -1
- package/src/assets/web-panel/assets/{index-BKJr-TZp.js → index-C484EJiS.js} +1 -1
- package/src/assets/web-panel/assets/{index-Drlnwr8F.js → index-C5KAQFPQ.js} +1 -1
- package/src/assets/web-panel/assets/index-C61cnl3K.js +1 -0
- package/src/assets/web-panel/assets/{index-Dsij_KsN.js → index-C7Y8Aluc.js} +1 -1
- package/src/assets/web-panel/assets/{index-IeiL9RKc.js → index-CCsM_Ybx.js} +1 -1
- package/src/assets/web-panel/assets/{index-B-Z8eFUJ.js → index-CJCFe2Qf.js} +1 -1
- package/src/assets/web-panel/assets/{index-CyOGN6a5.js → index-CJVEOa4i.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0PMlbMs.js → index-CJdQrZth.js} +1 -1
- package/src/assets/web-panel/assets/{index-nAH87mQP.js → index-CKC1t3Ic.js} +1 -1
- package/src/assets/web-panel/assets/{index-BGqqJfL0.js → index-CQhAVU5t.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cd9OJhHG.js → index-CYdoQsa1.js} +1 -1
- package/src/assets/web-panel/assets/{index-D0zcy54x.js → index-Cduu2Hhr.js} +1 -1
- package/src/assets/web-panel/assets/{index-DIUnNOjG.js → index-CkwiSLhU.js} +1 -1
- package/src/assets/web-panel/assets/{index-CVQMeiwH.js → index-Cvyt-zhm.js} +1 -1
- package/src/assets/web-panel/assets/{index-BlT2VAEK.js → index-D2GjI2oe.js} +1 -1
- package/src/assets/web-panel/assets/index-D4XFHxBr.js +1 -0
- package/src/assets/web-panel/assets/{index-C0yx-jtQ.js → index-DARsAyUp.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bi46Xu4u.js → index-DVKfQ0Ux.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cd3euP_4.js → index-DZT36ZYq.js} +1 -1
- package/src/assets/web-panel/assets/{index-BCnZyIMA.js → index-D_XBHopw.js} +1 -1
- package/src/assets/web-panel/assets/{index-C4gkzxkw.js → index-DdCB70SS.js} +1 -1
- package/src/assets/web-panel/assets/{index-B7WBt_4T.js → index-DzRjHxEv.js} +1 -1
- package/src/assets/web-panel/assets/{index-DX7tuWVJ.js → index-MMN9V6JF.js} +1 -1
- package/src/assets/web-panel/assets/{index-DoQA0-52.js → index-RfMr79MW.js} +1 -1
- package/src/assets/web-panel/assets/{index-DXXtGMUJ.js → index-_IRVsV9X.js} +1 -1
- package/src/assets/web-panel/assets/{index-pPL66J85.js → index-nXyk8GZ9.js} +1 -1
- package/src/assets/web-panel/assets/{index-DyIWssPC.js → index-s_buFMEG.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-BTL88of4.js → initDefaultProps-Blmpk7HL.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BUB2pXwB.js → motion-DPBJMv1n.js} +1 -1
- package/src/assets/web-panel/assets/{move-egCkkOMm.js → move-ButdzCM7.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-DAWhZC8c.js → mtc-parser-cyRC_QCe.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CvOxe_6d.js → omit-1epSV7hz.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DZUSLZ5Z.js → pickAttrs-DuPY8xJs.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BERxGNMY.js → placementArrow-6XZqarhe.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DZuDfZ9n.js → responsiveObserve-B40pXBWM.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DO756sgI.js → slide-jbZ9Wu4n.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BRQlIz28.js → statusUtils-BKQQcVy4.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-DCSfdybl.js → styleChecker-NiKfWjUT.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-LD8dWVve.js → useFlexGapSupport-bQUCvPeb.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BX9uW2LK.js → useFs-CUGji7ph.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BPSlPuHU.js → usePersonalDataHub-4veyN2N2.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-BmOILC9V.js → vnode-1-nLug-Z.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-1iKowKGg.js → zoom-dhCeRDMo.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +3 -3
- package/src/commands/cowork.js +174 -19
- package/src/commands/permissions.js +240 -16
- package/src/commands/plugin.js +1293 -56
- package/src/commands/session-location.js +276 -0
- package/src/commands/session.js +2 -0
- package/src/data/changelog.json +15 -2
- package/src/gateways/ws/action-protocol.js +35 -10
- package/src/gateways/ws/remote-session-protocol.js +24 -1
- package/src/gateways/ws/ws-agent-handler.js +12 -0
- package/src/gateways/ws/ws-server.js +48 -12
- package/src/harness/jsonl-session-store.js +341 -24
- package/src/harness/mcp-client.js +8 -1
- package/src/harness/remote-session-audit.js +1 -0
- package/src/harness/remote-session-crypto.js +210 -2
- package/src/harness/remote-session-registry.js +159 -6
- package/src/harness/session-list-index.js +233 -14
- package/src/lib/agent-authority.js +6 -0
- package/src/lib/background-agent-keeper-client.js +248 -0
- package/src/lib/background-agent-keeper-protocol.js +147 -0
- package/src/lib/background-agent-supervisor.js +520 -40
- package/src/lib/background-interaction-resolver.js +12 -0
- package/src/lib/background-turn-bootstrap-protocol.js +126 -0
- package/src/lib/cowork-workflow.js +336 -16
- package/src/lib/dynamic-workflow-facade.js +648 -0
- package/src/lib/execution-location-contract.js +551 -0
- package/src/lib/execution-location-runtime.js +130 -0
- package/src/lib/ide-context.js +94 -6
- package/src/lib/mcp-stdio-package-materialization.js +166 -14
- package/src/lib/packer/pkg-config-generator.js +2 -0
- package/src/lib/permission-authority.js +77 -0
- package/src/lib/permission-side-effect-center.js +495 -0
- package/src/lib/plugin-runtime/install.js +514 -13
- package/src/lib/plugin-runtime/marketplace-artifact-readback.js +900 -0
- package/src/lib/plugin-runtime/marketplace-catalog.js +1181 -0
- package/src/lib/plugin-runtime/marketplace-impact.js +408 -0
- package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +1567 -0
- package/src/lib/plugin-security.js +60 -3
- package/src/lib/process-execution-broker/index.js +1095 -57
- package/src/lib/process-execution-broker/linux-bwrap-descriptor-launch.js +375 -0
- package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +90 -16
- package/src/lib/process-execution-broker/linux-generic-bwrap.js +159 -18
- package/src/lib/process-execution-broker/macos-mcp-launcher-contract.js +278 -0
- package/src/lib/process-execution-broker/macos-mcp-launcher-protocol.json +23 -0
- package/src/lib/process-execution-broker/macos-mcp-launcher.c +1497 -0
- package/src/lib/process-execution-broker/mcp-fd-entry-bootstrap.js +37 -0
- package/src/lib/process-execution-broker/platform-sandbox.js +2330 -279
- package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
- package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
- package/src/lib/process-execution-broker/windows-sandbox.cs +50 -4
- package/src/lib/public-ide-capability-manifest.js +3 -0
- package/src/lib/remote-approval-bridge.js +123 -17
- package/src/lib/remote-membership-authority.js +632 -0
- package/src/lib/remote-membership-coordinator.js +2409 -0
- package/src/lib/remote-membership-host-store.js +1750 -0
- package/src/lib/scoped-permission-store.js +369 -0
- package/src/lib/session-anti-rollback-anchor.js +262 -5
- package/src/lib/sub-agent-context.js +4 -0
- package/src/lib/workflow-definition-contract.js +149 -0
- package/src/repl/agent-repl.js +41 -7
- package/src/repl/chat-repl.js +2 -0
- package/src/repl/clipboard-image.js +735 -16
- package/src/repl/ide-status.js +1 -1
- package/src/repl/prompt-interactions.js +59 -6
- package/src/runtime/agent-core.js +83 -3
- package/src/runtime/headless-runner.js +30 -25
- package/src/runtime/headless-stream.js +32 -25
- package/src/workers/background-agent-keeper.js +498 -0
- package/src/workers/background-agent-worker.js +358 -13
- package/src/workers/background-turn-bootstrap.js +143 -0
- package/src/assets/web-panel/assets/MarkdownRenderer-yySN5YNM.js +0 -1
- package/src/assets/web-panel/assets/MobileProjects-DlPwcCbq.js +0 -1
- package/src/assets/web-panel/assets/Projects-CMolGhae.js +0 -1
- package/src/assets/web-panel/assets/devWarning-S1ld2LwU.js +0 -1
- package/src/assets/web-panel/assets/index-Drz6yq0m.js +0 -1
- package/src/assets/web-panel/assets/index-uWiUs7S_.js +0 -1
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
import fs from "fs";
|
|
20
20
|
import os from "os";
|
|
21
21
|
import path from "path";
|
|
22
|
+
import crypto from "node:crypto";
|
|
22
23
|
import { parsePluginManifest, isWithin } from "./manifest.js";
|
|
23
24
|
import {
|
|
24
25
|
pluginNameDir,
|
|
@@ -65,7 +66,7 @@ const pendingPluginTransactions = new WeakMap();
|
|
|
65
66
|
/**
|
|
66
67
|
* Install a plugin from a local directory into a scope's immutable version dir.
|
|
67
68
|
* @param {string} srcDir directory containing the plugin (with its manifest)
|
|
68
|
-
* @param {object} opts { scope="user", cwd, force=false }
|
|
69
|
+
* @param {object} opts { scope="user", cwd, force=false, expectedIdentity? }
|
|
69
70
|
* @returns {{ name, version, scope, dir, warnings }}
|
|
70
71
|
*/
|
|
71
72
|
export function installFromDirectory(srcDir, opts = {}) {
|
|
@@ -82,6 +83,7 @@ export function installFromDirectory(srcDir, opts = {}) {
|
|
|
82
83
|
);
|
|
83
84
|
}
|
|
84
85
|
const { name, version } = manifest.metadata;
|
|
86
|
+
assertExpectedPluginIdentity(name, version, opts.expectedIdentity);
|
|
85
87
|
const sourceMetadata = normalizeSourceMetadata(opts.sourceMetadata);
|
|
86
88
|
if (opts.managedPolicy) {
|
|
87
89
|
enforcePluginPolicy(
|
|
@@ -107,11 +109,16 @@ export function installFromDirectory(srcDir, opts = {}) {
|
|
|
107
109
|
expectedSha256: sig.sha256,
|
|
108
110
|
signatureFile: sig.signatureFile,
|
|
109
111
|
publicKeyFile: sig.publicKeyFile,
|
|
112
|
+
expectedSignatureSha256: sig.expectedSignatureSha256 || null,
|
|
113
|
+
expectedPublicKeyDocumentSha256:
|
|
114
|
+
sig.expectedPublicKeyDocumentSha256 || null,
|
|
115
|
+
expectedPublicKeySha256: sig.expectedPublicKeySha256 || null,
|
|
110
116
|
requireSignature: sig.requireSignature === true,
|
|
111
117
|
trustedKeySha256: sig.trustedKeySha256 || null,
|
|
112
118
|
requireTrustedKey: sig.requireTrustedKey === true,
|
|
113
119
|
});
|
|
114
120
|
}
|
|
121
|
+
assertRemoteSignatureInstallBinding(sourceMetadata, verification);
|
|
115
122
|
|
|
116
123
|
const dest = pluginVersionDir(scope, name, version, { cwd: opts.cwd });
|
|
117
124
|
const destExists = _deps.existsSync(dest);
|
|
@@ -148,10 +155,11 @@ export function installFromDirectory(srcDir, opts = {}) {
|
|
|
148
155
|
);
|
|
149
156
|
}
|
|
150
157
|
|
|
151
|
-
// Record
|
|
152
|
-
//
|
|
153
|
-
//
|
|
154
|
-
|
|
158
|
+
// Record only a cryptographically verified signature into the staged
|
|
159
|
+
// immutable version. A hash-only registry check is re-run below but must
|
|
160
|
+
// not create a signature lock or imply that the publisher was verified.
|
|
161
|
+
// Signed installs also bind the complete component SBOM before activation.
|
|
162
|
+
if (verification?.signatureVerified === true) {
|
|
155
163
|
const stagedManifest = path.join(
|
|
156
164
|
staged,
|
|
157
165
|
path.relative(src, manifest.manifestPath),
|
|
@@ -243,13 +251,14 @@ export function installFromSource(source, opts = {}) {
|
|
|
243
251
|
: { type: "local", source: path.resolve(String(source || "")) },
|
|
244
252
|
);
|
|
245
253
|
const res = installFromDirectory(dir, { ...opts, sourceMetadata });
|
|
246
|
-
return
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
254
|
+
if (!info) return res;
|
|
255
|
+
const result = {
|
|
256
|
+
...res,
|
|
257
|
+
source: sourceMetadata?.source || null,
|
|
258
|
+
ref: sourceMetadata?.ref || null,
|
|
259
|
+
};
|
|
260
|
+
transferPendingTransaction(res, result);
|
|
261
|
+
return result;
|
|
253
262
|
});
|
|
254
263
|
}
|
|
255
264
|
|
|
@@ -300,6 +309,7 @@ export function updatePlugin(source, opts = {}) {
|
|
|
300
309
|
);
|
|
301
310
|
}
|
|
302
311
|
const { name, version } = manifest.metadata;
|
|
312
|
+
assertExpectedPluginIdentity(name, version, opts.expectedIdentity);
|
|
303
313
|
const sourceMetadata =
|
|
304
314
|
normalizeSourceMetadata(opts.sourceMetadata) ||
|
|
305
315
|
normalizeSourceMetadata(
|
|
@@ -743,9 +753,463 @@ function normalizeSourceMetadata(value) {
|
|
|
743
753
|
if (resolvedSource) metadata.resolvedSource = resolvedSource;
|
|
744
754
|
if (packageName) metadata.package = packageName;
|
|
745
755
|
if (value.offline === true) metadata.offline = true;
|
|
756
|
+
if (value.catalogAuthority != null) {
|
|
757
|
+
metadata.catalogAuthority = normalizeCatalogAuthority(
|
|
758
|
+
value.catalogAuthority,
|
|
759
|
+
);
|
|
760
|
+
}
|
|
761
|
+
assertCatalogRemoteArtifactBindings(metadata);
|
|
746
762
|
return metadata;
|
|
747
763
|
}
|
|
748
764
|
|
|
765
|
+
function assertCatalogRemoteArtifactBindings(metadata) {
|
|
766
|
+
const authority = metadata.catalogAuthority;
|
|
767
|
+
const evidence = authority?.remoteArtifactEvidence;
|
|
768
|
+
if (!evidence) return;
|
|
769
|
+
if (metadata.type !== "registry" || !metadata.registry) {
|
|
770
|
+
throw new Error(
|
|
771
|
+
"remote marketplace artifact evidence requires registry source metadata",
|
|
772
|
+
);
|
|
773
|
+
}
|
|
774
|
+
let registryOrigin;
|
|
775
|
+
try {
|
|
776
|
+
registryOrigin = new URL(metadata.registry).origin;
|
|
777
|
+
} catch {
|
|
778
|
+
throw new Error("remote marketplace artifact registry URL is invalid");
|
|
779
|
+
}
|
|
780
|
+
if (registryOrigin !== evidence.registryOrigin) {
|
|
781
|
+
throw new Error(
|
|
782
|
+
"remote marketplace artifact evidence registry origin does not match the selected registry",
|
|
783
|
+
);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
const expectations = authority.artifactExpectations || {};
|
|
787
|
+
const expectedSignature = expectations.signature || {};
|
|
788
|
+
const expectsRemoteSignature = Boolean(
|
|
789
|
+
expectedSignature.url &&
|
|
790
|
+
expectedSignature.publicKeyUrl &&
|
|
791
|
+
expectedSignature.publicKeySha256,
|
|
792
|
+
);
|
|
793
|
+
if (expectsRemoteSignature !== Boolean(evidence.signature)) {
|
|
794
|
+
throw new Error(
|
|
795
|
+
"remote signature evidence does not match the catalog artifact declaration",
|
|
796
|
+
);
|
|
797
|
+
}
|
|
798
|
+
if (evidence.signature) {
|
|
799
|
+
const actual = evidence.signature;
|
|
800
|
+
if (
|
|
801
|
+
actual.url !== expectedSignature.url ||
|
|
802
|
+
actual.publicKey.url !== expectedSignature.publicKeyUrl ||
|
|
803
|
+
actual.publicKey.spkiSha256 !== expectedSignature.publicKeySha256 ||
|
|
804
|
+
(expectedSignature.documentSha256 &&
|
|
805
|
+
actual.signatureSha256 !== expectedSignature.documentSha256) ||
|
|
806
|
+
(expectedSignature.publicKeyDocumentSha256 &&
|
|
807
|
+
actual.publicKey.documentSha256 !==
|
|
808
|
+
expectedSignature.publicKeyDocumentSha256)
|
|
809
|
+
) {
|
|
810
|
+
throw new Error(
|
|
811
|
+
"remote signature evidence does not match catalog URL or digest expectations",
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
const expectedSbom = expectations.sbom || {};
|
|
817
|
+
const expectsRemoteSbom = Boolean(
|
|
818
|
+
expectedSbom.url && expectedSbom.documentSha256,
|
|
819
|
+
);
|
|
820
|
+
if (expectsRemoteSbom !== Boolean(evidence.sbom)) {
|
|
821
|
+
throw new Error(
|
|
822
|
+
"remote SBOM evidence does not match the catalog artifact declaration",
|
|
823
|
+
);
|
|
824
|
+
}
|
|
825
|
+
if (evidence.sbom) {
|
|
826
|
+
const actual = evidence.sbom;
|
|
827
|
+
if (
|
|
828
|
+
actual.url !== expectedSbom.url ||
|
|
829
|
+
actual.expectedDocumentSha256 !== expectedSbom.documentSha256 ||
|
|
830
|
+
actual.documentSha256 !== expectedSbom.documentSha256 ||
|
|
831
|
+
actual.format !== expectedSbom.format
|
|
832
|
+
) {
|
|
833
|
+
throw new Error(
|
|
834
|
+
"remote SBOM evidence does not match catalog URL, format, or digest expectations",
|
|
835
|
+
);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
function assertRemoteSignatureInstallBinding(sourceMetadata, verification) {
|
|
841
|
+
const signature =
|
|
842
|
+
sourceMetadata?.catalogAuthority?.remoteArtifactEvidence?.signature;
|
|
843
|
+
if (!signature) return;
|
|
844
|
+
if (verification?.signatureVerified !== true) {
|
|
845
|
+
throw new Error(
|
|
846
|
+
"remote marketplace signature was not verified against the fetched plugin manifest",
|
|
847
|
+
);
|
|
848
|
+
}
|
|
849
|
+
if (
|
|
850
|
+
verification.signatureSha256 !== signature.signatureSha256 ||
|
|
851
|
+
verification.publicKeyDocumentSha256 !==
|
|
852
|
+
signature.publicKey.documentSha256 ||
|
|
853
|
+
verification.publicKeySha256 !== signature.publicKey.spkiSha256
|
|
854
|
+
) {
|
|
855
|
+
throw new Error(
|
|
856
|
+
"remote marketplace signature bytes changed before installer verification",
|
|
857
|
+
);
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
function normalizeCatalogAuthority(value) {
|
|
862
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
863
|
+
throw new Error("catalogAuthority must be an object");
|
|
864
|
+
}
|
|
865
|
+
const catalogDigest = cleanBounded(value.catalogDigest, 64);
|
|
866
|
+
const candidateId = cleanBounded(value.candidateId, 64);
|
|
867
|
+
const candidateDigest = cleanBounded(value.candidateDigest, 64);
|
|
868
|
+
const selectionDigest = cleanBounded(value.selectionDigest, 64);
|
|
869
|
+
const updateImpactDigest = cleanBounded(value.updateImpactDigest, 64);
|
|
870
|
+
const artifactExpectations = normalizeArtifactExpectations(
|
|
871
|
+
value.artifactExpectations,
|
|
872
|
+
);
|
|
873
|
+
const remoteArtifactEvidence = normalizeRemoteArtifactEvidence(
|
|
874
|
+
value.remoteArtifactEvidence,
|
|
875
|
+
);
|
|
876
|
+
if (!/^[a-f0-9]{64}$/.test(catalogDigest || "")) {
|
|
877
|
+
throw new Error(
|
|
878
|
+
"catalogAuthority.catalogDigest must be a SHA-256 hex digest",
|
|
879
|
+
);
|
|
880
|
+
}
|
|
881
|
+
if (!/^candidate-[a-f0-9]{20}$/.test(candidateId || "")) {
|
|
882
|
+
throw new Error("catalogAuthority.candidateId is invalid");
|
|
883
|
+
}
|
|
884
|
+
if (candidateDigest && !/^[a-f0-9]{64}$/.test(candidateDigest)) {
|
|
885
|
+
throw new Error(
|
|
886
|
+
"catalogAuthority.candidateDigest must be a SHA-256 hex digest",
|
|
887
|
+
);
|
|
888
|
+
}
|
|
889
|
+
if (selectionDigest && !/^[a-f0-9]{64}$/.test(selectionDigest)) {
|
|
890
|
+
throw new Error(
|
|
891
|
+
"catalogAuthority.selectionDigest must be a SHA-256 hex digest",
|
|
892
|
+
);
|
|
893
|
+
}
|
|
894
|
+
if (updateImpactDigest && !/^[a-f0-9]{64}$/.test(updateImpactDigest)) {
|
|
895
|
+
throw new Error(
|
|
896
|
+
"catalogAuthority.updateImpactDigest must be a SHA-256 hex digest",
|
|
897
|
+
);
|
|
898
|
+
}
|
|
899
|
+
const governanceStatus = ["complete", "incomplete"].includes(
|
|
900
|
+
value.governanceStatus,
|
|
901
|
+
)
|
|
902
|
+
? value.governanceStatus
|
|
903
|
+
: "incomplete";
|
|
904
|
+
const registryStatus = ["online", "cached"].includes(value.registryStatus)
|
|
905
|
+
? value.registryStatus
|
|
906
|
+
: "online";
|
|
907
|
+
const versionAuthority = [
|
|
908
|
+
"registry-declared-unverified",
|
|
909
|
+
"deferred-to-plugin-manifest",
|
|
910
|
+
].includes(value.versionAuthority)
|
|
911
|
+
? value.versionAuthority
|
|
912
|
+
: "deferred-to-plugin-manifest";
|
|
913
|
+
const selectionSourceCount = Number.isInteger(value.selectionSourceCount)
|
|
914
|
+
? value.selectionSourceCount
|
|
915
|
+
: null;
|
|
916
|
+
if (
|
|
917
|
+
selectionDigest &&
|
|
918
|
+
(!selectionSourceCount ||
|
|
919
|
+
selectionSourceCount < 1 ||
|
|
920
|
+
selectionSourceCount > 16)
|
|
921
|
+
) {
|
|
922
|
+
throw new Error(
|
|
923
|
+
"catalogAuthority.selectionSourceCount must be between 1 and 16",
|
|
924
|
+
);
|
|
925
|
+
}
|
|
926
|
+
return {
|
|
927
|
+
schemaVersion: "cc-plugin-marketplace-catalog/v1",
|
|
928
|
+
installPreflightSchemaVersion: "cc-plugin-marketplace-install-preflight/v1",
|
|
929
|
+
catalogDigest,
|
|
930
|
+
candidateId,
|
|
931
|
+
...(candidateDigest ? { candidateDigest } : {}),
|
|
932
|
+
...(selectionDigest
|
|
933
|
+
? {
|
|
934
|
+
selectionSchemaVersion:
|
|
935
|
+
"cc-plugin-marketplace-candidate-selection/v1",
|
|
936
|
+
selectionDigest,
|
|
937
|
+
selectionSourceCount,
|
|
938
|
+
}
|
|
939
|
+
: {}),
|
|
940
|
+
...(updateImpactDigest ? { updateImpactDigest } : {}),
|
|
941
|
+
...(artifactExpectations ? { artifactExpectations } : {}),
|
|
942
|
+
...(remoteArtifactEvidence ? { remoteArtifactEvidence } : {}),
|
|
943
|
+
preflightStatus: "allowed",
|
|
944
|
+
governanceStatus,
|
|
945
|
+
registryStatus,
|
|
946
|
+
versionAuthority,
|
|
947
|
+
};
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
function normalizeArtifactExpectations(value) {
|
|
951
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
952
|
+
const digest = (candidate, label) => {
|
|
953
|
+
const normalized = cleanBounded(candidate, 64);
|
|
954
|
+
if (normalized && !/^[a-f0-9]{64}$/i.test(normalized)) {
|
|
955
|
+
throw new Error(`${label} must be a SHA-256 hex digest`);
|
|
956
|
+
}
|
|
957
|
+
return normalized?.toLowerCase() || null;
|
|
958
|
+
};
|
|
959
|
+
const status = (candidate) =>
|
|
960
|
+
["declared", "missing"].includes(candidate) ? candidate : "missing";
|
|
961
|
+
const manifestSha256 = digest(
|
|
962
|
+
value.manifest?.sha256,
|
|
963
|
+
"catalogAuthority.artifactExpectations.manifest.sha256",
|
|
964
|
+
);
|
|
965
|
+
const signatureKeySha256 = digest(
|
|
966
|
+
value.signature?.publicKeySha256,
|
|
967
|
+
"catalogAuthority.artifactExpectations.signature.publicKeySha256",
|
|
968
|
+
);
|
|
969
|
+
const sbomSha256 = digest(
|
|
970
|
+
value.sbom?.payloadSha256 ?? value.sbom?.sha256,
|
|
971
|
+
"catalogAuthority.artifactExpectations.sbom.sha256",
|
|
972
|
+
);
|
|
973
|
+
const signatureDocumentSha256 = digest(
|
|
974
|
+
value.signature?.documentSha256,
|
|
975
|
+
"catalogAuthority.artifactExpectations.signature.documentSha256",
|
|
976
|
+
);
|
|
977
|
+
const signaturePublicKeyDocumentSha256 = digest(
|
|
978
|
+
value.signature?.publicKeyDocumentSha256,
|
|
979
|
+
"catalogAuthority.artifactExpectations.signature.publicKeyDocumentSha256",
|
|
980
|
+
);
|
|
981
|
+
const sbomDocumentSha256 = digest(
|
|
982
|
+
value.sbom?.documentSha256,
|
|
983
|
+
"catalogAuthority.artifactExpectations.sbom.documentSha256",
|
|
984
|
+
);
|
|
985
|
+
return {
|
|
986
|
+
manifest: {
|
|
987
|
+
status: status(value.manifest?.status),
|
|
988
|
+
sha256: manifestSha256,
|
|
989
|
+
},
|
|
990
|
+
signature: {
|
|
991
|
+
status: status(value.signature?.status),
|
|
992
|
+
algorithm: cleanBounded(value.signature?.algorithm, 64),
|
|
993
|
+
publicKeySha256: signatureKeySha256,
|
|
994
|
+
documentSha256: signatureDocumentSha256,
|
|
995
|
+
publicKeyDocumentSha256: signaturePublicKeyDocumentSha256,
|
|
996
|
+
url: sanitizeSource(value.signature?.url),
|
|
997
|
+
publicKeyUrl: sanitizeSource(value.signature?.publicKeyUrl),
|
|
998
|
+
},
|
|
999
|
+
sbom: {
|
|
1000
|
+
status: status(value.sbom?.status),
|
|
1001
|
+
format: cleanBounded(value.sbom?.format, 128),
|
|
1002
|
+
sha256: sbomSha256,
|
|
1003
|
+
payloadSha256: sbomSha256,
|
|
1004
|
+
documentSha256: sbomDocumentSha256,
|
|
1005
|
+
url: sanitizeSource(value.sbom?.url),
|
|
1006
|
+
},
|
|
1007
|
+
license: {
|
|
1008
|
+
status: status(value.license?.status),
|
|
1009
|
+
expression: cleanBounded(value.license?.expression, 256),
|
|
1010
|
+
},
|
|
1011
|
+
};
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
function normalizeRemoteArtifactEvidence(value) {
|
|
1015
|
+
if (value == null) return null;
|
|
1016
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
1017
|
+
throw new Error(
|
|
1018
|
+
"catalogAuthority.remoteArtifactEvidence must be an object",
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
if (
|
|
1022
|
+
value.schemaVersion !== "cc-plugin-marketplace-remote-artifact-evidence/v1"
|
|
1023
|
+
) {
|
|
1024
|
+
throw new Error(
|
|
1025
|
+
"catalogAuthority.remoteArtifactEvidence schemaVersion is invalid",
|
|
1026
|
+
);
|
|
1027
|
+
}
|
|
1028
|
+
const digest = (candidate, label) => {
|
|
1029
|
+
const normalized = cleanBounded(candidate, 64)?.toLowerCase() || null;
|
|
1030
|
+
if (!normalized || !/^[a-f0-9]{64}$/.test(normalized)) {
|
|
1031
|
+
throw new Error(`${label} must be a SHA-256 hex digest`);
|
|
1032
|
+
}
|
|
1033
|
+
return normalized;
|
|
1034
|
+
};
|
|
1035
|
+
const boundedBytes = (candidate, maximum, label) => {
|
|
1036
|
+
if (
|
|
1037
|
+
!Number.isSafeInteger(candidate) ||
|
|
1038
|
+
candidate < 0 ||
|
|
1039
|
+
candidate > maximum
|
|
1040
|
+
) {
|
|
1041
|
+
throw new Error(`${label} is outside the allowed byte limit`);
|
|
1042
|
+
}
|
|
1043
|
+
return candidate;
|
|
1044
|
+
};
|
|
1045
|
+
const normalizeArtifactUrl = (candidate, label) => {
|
|
1046
|
+
const sanitized = sanitizeSource(candidate);
|
|
1047
|
+
if (!sanitized || !/^https?:\/\//i.test(sanitized)) {
|
|
1048
|
+
throw new Error(`${label} must be an http(s) URL`);
|
|
1049
|
+
}
|
|
1050
|
+
return sanitized;
|
|
1051
|
+
};
|
|
1052
|
+
const normalizeRegistryOrigin = (candidate) => {
|
|
1053
|
+
const sanitized = normalizeArtifactUrl(
|
|
1054
|
+
candidate,
|
|
1055
|
+
"catalogAuthority.remoteArtifactEvidence.registryOrigin",
|
|
1056
|
+
);
|
|
1057
|
+
return new URL(sanitized).origin;
|
|
1058
|
+
};
|
|
1059
|
+
const signature = value.signature
|
|
1060
|
+
? {
|
|
1061
|
+
status:
|
|
1062
|
+
value.signature.status === "fetched"
|
|
1063
|
+
? "fetched"
|
|
1064
|
+
: (() => {
|
|
1065
|
+
throw new Error(
|
|
1066
|
+
"catalogAuthority.remoteArtifactEvidence.signature.status is invalid",
|
|
1067
|
+
);
|
|
1068
|
+
})(),
|
|
1069
|
+
url: normalizeArtifactUrl(
|
|
1070
|
+
value.signature.url,
|
|
1071
|
+
"catalogAuthority.remoteArtifactEvidence.signature.url",
|
|
1072
|
+
),
|
|
1073
|
+
signatureSha256: digest(
|
|
1074
|
+
value.signature.signatureSha256,
|
|
1075
|
+
"catalogAuthority.remoteArtifactEvidence.signature.signatureSha256",
|
|
1076
|
+
),
|
|
1077
|
+
bytes: boundedBytes(
|
|
1078
|
+
value.signature.bytes,
|
|
1079
|
+
16 * 1024,
|
|
1080
|
+
"catalogAuthority.remoteArtifactEvidence.signature.bytes",
|
|
1081
|
+
),
|
|
1082
|
+
fromCache: value.signature.fromCache === true,
|
|
1083
|
+
publicKey: {
|
|
1084
|
+
url: normalizeArtifactUrl(
|
|
1085
|
+
value.signature.publicKey?.url,
|
|
1086
|
+
"catalogAuthority.remoteArtifactEvidence.signature.publicKey.url",
|
|
1087
|
+
),
|
|
1088
|
+
documentSha256: digest(
|
|
1089
|
+
value.signature.publicKey?.documentSha256,
|
|
1090
|
+
"catalogAuthority.remoteArtifactEvidence.signature.publicKey.documentSha256",
|
|
1091
|
+
),
|
|
1092
|
+
spkiSha256: digest(
|
|
1093
|
+
value.signature.publicKey?.spkiSha256,
|
|
1094
|
+
"catalogAuthority.remoteArtifactEvidence.signature.publicKey.spkiSha256",
|
|
1095
|
+
),
|
|
1096
|
+
bytes: boundedBytes(
|
|
1097
|
+
value.signature.publicKey?.bytes,
|
|
1098
|
+
64 * 1024,
|
|
1099
|
+
"catalogAuthority.remoteArtifactEvidence.signature.publicKey.bytes",
|
|
1100
|
+
),
|
|
1101
|
+
fromCache: value.signature.publicKey?.fromCache === true,
|
|
1102
|
+
},
|
|
1103
|
+
}
|
|
1104
|
+
: null;
|
|
1105
|
+
const sbom = value.sbom
|
|
1106
|
+
? {
|
|
1107
|
+
status:
|
|
1108
|
+
value.sbom.status === "digest-verified"
|
|
1109
|
+
? "digest-verified"
|
|
1110
|
+
: (() => {
|
|
1111
|
+
throw new Error(
|
|
1112
|
+
"catalogAuthority.remoteArtifactEvidence.sbom.status is invalid",
|
|
1113
|
+
);
|
|
1114
|
+
})(),
|
|
1115
|
+
url: normalizeArtifactUrl(
|
|
1116
|
+
value.sbom.url,
|
|
1117
|
+
"catalogAuthority.remoteArtifactEvidence.sbom.url",
|
|
1118
|
+
),
|
|
1119
|
+
format: cleanBounded(value.sbom.format, 128),
|
|
1120
|
+
expectedDocumentSha256: digest(
|
|
1121
|
+
value.sbom.expectedDocumentSha256,
|
|
1122
|
+
"catalogAuthority.remoteArtifactEvidence.sbom.expectedDocumentSha256",
|
|
1123
|
+
),
|
|
1124
|
+
documentSha256: digest(
|
|
1125
|
+
value.sbom.documentSha256,
|
|
1126
|
+
"catalogAuthority.remoteArtifactEvidence.sbom.documentSha256",
|
|
1127
|
+
),
|
|
1128
|
+
bytes: boundedBytes(
|
|
1129
|
+
value.sbom.bytes,
|
|
1130
|
+
16 * 1024 * 1024,
|
|
1131
|
+
"catalogAuthority.remoteArtifactEvidence.sbom.bytes",
|
|
1132
|
+
),
|
|
1133
|
+
fromCache: value.sbom.fromCache === true,
|
|
1134
|
+
}
|
|
1135
|
+
: null;
|
|
1136
|
+
if (!signature && !sbom) {
|
|
1137
|
+
throw new Error(
|
|
1138
|
+
"catalogAuthority.remoteArtifactEvidence must bind at least one artifact",
|
|
1139
|
+
);
|
|
1140
|
+
}
|
|
1141
|
+
if (sbom && sbom.expectedDocumentSha256 !== sbom.documentSha256) {
|
|
1142
|
+
throw new Error(
|
|
1143
|
+
"catalogAuthority.remoteArtifactEvidence SBOM digest is not verified",
|
|
1144
|
+
);
|
|
1145
|
+
}
|
|
1146
|
+
const claims = {
|
|
1147
|
+
publisherIdentityVerified: value.claims?.publisherIdentityVerified === true,
|
|
1148
|
+
signatureBytesFetched: value.claims?.signatureBytesFetched === true,
|
|
1149
|
+
publicKeyFingerprintVerified:
|
|
1150
|
+
value.claims?.publicKeyFingerprintVerified === true,
|
|
1151
|
+
manifestSignatureVerified: value.claims?.manifestSignatureVerified === true,
|
|
1152
|
+
sbomDocumentDigestVerified:
|
|
1153
|
+
value.claims?.sbomDocumentDigestVerified === true,
|
|
1154
|
+
sbomPayloadCompared: value.claims?.sbomPayloadCompared === true,
|
|
1155
|
+
};
|
|
1156
|
+
if (claims.publisherIdentityVerified || claims.manifestSignatureVerified) {
|
|
1157
|
+
throw new Error(
|
|
1158
|
+
"remote artifact fetch evidence cannot assert publisher identity or manifest verification",
|
|
1159
|
+
);
|
|
1160
|
+
}
|
|
1161
|
+
if (
|
|
1162
|
+
(!signature &&
|
|
1163
|
+
(claims.signatureBytesFetched || claims.publicKeyFingerprintVerified)) ||
|
|
1164
|
+
(!sbom && claims.sbomDocumentDigestVerified) ||
|
|
1165
|
+
claims.sbomPayloadCompared
|
|
1166
|
+
) {
|
|
1167
|
+
throw new Error(
|
|
1168
|
+
"remote artifact fetch evidence claims do not match the recorded artifacts",
|
|
1169
|
+
);
|
|
1170
|
+
}
|
|
1171
|
+
if (
|
|
1172
|
+
signature &&
|
|
1173
|
+
(!claims.signatureBytesFetched || !claims.publicKeyFingerprintVerified)
|
|
1174
|
+
) {
|
|
1175
|
+
throw new Error(
|
|
1176
|
+
"remote signature artifact evidence is missing verification claims",
|
|
1177
|
+
);
|
|
1178
|
+
}
|
|
1179
|
+
if (sbom && !claims.sbomDocumentDigestVerified) {
|
|
1180
|
+
throw new Error(
|
|
1181
|
+
"remote SBOM artifact evidence is missing digest verification",
|
|
1182
|
+
);
|
|
1183
|
+
}
|
|
1184
|
+
if (value.status !== "verified") {
|
|
1185
|
+
throw new Error(
|
|
1186
|
+
"catalogAuthority.remoteArtifactEvidence.status must be verified",
|
|
1187
|
+
);
|
|
1188
|
+
}
|
|
1189
|
+
const authority = {
|
|
1190
|
+
schemaVersion: "cc-plugin-marketplace-remote-artifact-evidence/v1",
|
|
1191
|
+
status: "verified",
|
|
1192
|
+
registryOrigin: normalizeRegistryOrigin(value.registryOrigin),
|
|
1193
|
+
signature,
|
|
1194
|
+
sbom,
|
|
1195
|
+
claims,
|
|
1196
|
+
};
|
|
1197
|
+
const evidenceDigest = digest(
|
|
1198
|
+
value.evidenceDigest,
|
|
1199
|
+
"catalogAuthority.remoteArtifactEvidence.evidenceDigest",
|
|
1200
|
+
);
|
|
1201
|
+
const actualDigest = crypto
|
|
1202
|
+
.createHash("sha256")
|
|
1203
|
+
.update(canonicalJson(authority))
|
|
1204
|
+
.digest("hex");
|
|
1205
|
+
if (evidenceDigest !== actualDigest) {
|
|
1206
|
+
throw new Error(
|
|
1207
|
+
"catalogAuthority.remoteArtifactEvidence.evidenceDigest does not match its authority",
|
|
1208
|
+
);
|
|
1209
|
+
}
|
|
1210
|
+
return { ...authority, evidenceDigest };
|
|
1211
|
+
}
|
|
1212
|
+
|
|
749
1213
|
function sanitizeSource(value, preservePath = false) {
|
|
750
1214
|
const raw = cleanBounded(value, 4096);
|
|
751
1215
|
if (!raw) return null;
|
|
@@ -768,6 +1232,32 @@ function cleanBounded(value, max) {
|
|
|
768
1232
|
return clean ? clean.slice(0, max) : null;
|
|
769
1233
|
}
|
|
770
1234
|
|
|
1235
|
+
function canonicalJson(value) {
|
|
1236
|
+
if (value == null || typeof value !== "object") return JSON.stringify(value);
|
|
1237
|
+
if (Array.isArray(value)) {
|
|
1238
|
+
return `[${value.map((item) => canonicalJson(item)).join(",")}]`;
|
|
1239
|
+
}
|
|
1240
|
+
return `{${Object.keys(value)
|
|
1241
|
+
.sort()
|
|
1242
|
+
.map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`)
|
|
1243
|
+
.join(",")}}`;
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
function assertExpectedPluginIdentity(name, version, expectedIdentity) {
|
|
1247
|
+
const expectedName = cleanBounded(expectedIdentity?.name, 256);
|
|
1248
|
+
const expectedVersion = cleanBounded(expectedIdentity?.version, 128);
|
|
1249
|
+
if (expectedName && name !== expectedName) {
|
|
1250
|
+
throw new Error(
|
|
1251
|
+
`plugin identity mismatch: registry selected ${expectedName}, fetched manifest declares ${name}`,
|
|
1252
|
+
);
|
|
1253
|
+
}
|
|
1254
|
+
if (expectedVersion && version !== expectedVersion) {
|
|
1255
|
+
throw new Error(
|
|
1256
|
+
`plugin version mismatch: registry selected ${expectedVersion}, fetched manifest declares ${version}`,
|
|
1257
|
+
);
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
|
|
771
1261
|
// ── guarded recursive copy ────────────────────────────────────────────────
|
|
772
1262
|
|
|
773
1263
|
/**
|
|
@@ -801,13 +1291,24 @@ function validateStagedInstall(root, { name, version, verification }) {
|
|
|
801
1291
|
: "";
|
|
802
1292
|
throw new Error(`staged plugin failed load validation${details}`);
|
|
803
1293
|
}
|
|
804
|
-
if (verification) {
|
|
1294
|
+
if (verification?.signatureVerified === true) {
|
|
805
1295
|
const signature = verifyInstalledSignature({ root });
|
|
806
1296
|
if (!signature.signed) {
|
|
807
1297
|
throw new Error(
|
|
808
1298
|
`staged plugin failed signature/SBOM validation: ${signature.reason || "unknown error"}`,
|
|
809
1299
|
);
|
|
810
1300
|
}
|
|
1301
|
+
} else if (verification?.sha256) {
|
|
1302
|
+
try {
|
|
1303
|
+
verifyPluginManifest({
|
|
1304
|
+
manifestFile: parsed.manifestPath,
|
|
1305
|
+
expectedSha256: verification.sha256,
|
|
1306
|
+
});
|
|
1307
|
+
} catch (error) {
|
|
1308
|
+
throw new Error(
|
|
1309
|
+
`staged plugin failed manifest digest validation: ${error.message}`,
|
|
1310
|
+
);
|
|
1311
|
+
}
|
|
811
1312
|
}
|
|
812
1313
|
}
|
|
813
1314
|
|