chainlesschain 0.165.1 → 0.165.2
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 +248 -2
- package/package.json +4 -1
- package/src/assets/web-panel/assets/{AIOps-CYxFDrcm.js → AIOps-lS1R0Cza.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CPBtdiU2.js → ActionButton-BmlgBPsj.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-Dayq7Dp7.js → Analytics-CNKczv1S.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-6U7bPb2s.js → AppLayout-BuZGJARQ.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-D2Iqg_3D.js → Artifacts-Dm73Sl-O.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CdoOB7WV.js → Audit-BGMW7A5e.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-DrnAVB8w.js → BackgroundAgents-BQ6M54JR.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CesMi5cy.js → Backup-DBzGP0bR.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DaX9ptax.js → BaseInput-D1mLCoOV.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-OrwOPxDS.js → Chat-BUfcN7p8.js} +4 -4
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CvPZFRxM.js → ChatBubbleRenderer-CY5m8ZHg.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-DiHbcysC.js → Checkbox-Du0Yg5Pi.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-CbgCkaBJ.js → Codegen-B2RXziHW.js} +1 -1
- package/src/assets/web-panel/assets/{Col-Du5hgrh4.js → Col-DWhekOrR.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DsPOBW-p.js → Community-HQhrkon4.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-BwHIFkNC.js → Compact-izHNb4uz.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BvrDQSgd.js → Compliance-BDwLy41-.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-gwAE6arx.js → Cowork-DFJhLa7K.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-DW-0l4uF.js → Cron-DYY9RG7-.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-j-NsLesB.js → Crosschain-rr7tJTtv.js} +1 -1
- package/src/assets/web-panel/assets/{DID-CibVEBOI.js → DID-D2sfHRLi.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-W4z9vSfe.js → Dashboard-q_eGdhha.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-DAcrkKxG.js → Dropdown-Cufrh2Bz.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-6GXah-89.js → EmailListRenderer-B-kdv10f.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-TKDCq8Ku.js → FamilyGuardDashboard-D21XjgfG.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-BXBLlcNm.js → Federation-CAwRTLZH.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-BoJJBkG3.js → FormItemContext-vx3daNDF.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-okjsl46v.js → GenericCardRenderer-CRWY2wU4.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Rvs7i6nn.js → Git-Q6SwauyD.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CHSUxXXS.js → Governance-BJ1q4IQZ.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-V3BlfxsB.js → Inference-CSWjROgD.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-C_NlD4aR.js → KnowledgeGraph-fzuQsWuY.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-Nn4LNxhA.js → Logs-DVF8Mnns.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-BLif4QSg.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-DEmjFcg-.js → Marketplace-BQP7LOA4.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DlopXipI.js → McpTools-BNlJCmNc.js} +4 -4
- package/src/assets/web-panel/assets/{Memory-BG3ynX60.js → Memory-DLLg5WQ4.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DeRzWOfT.js → MobileBridge-CR2skNAF.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-Tyd3o2A0.js → MobileProjects-BxVavObl.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-BoPbOv1C.js → Mtc-B17pgqMI.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-un-rTHp7.js → MtcAudit-4UmV5cIL.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-Ds0oveEB.js → Multisig-DoMEXEcU.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-D09JI-yY.js → NLProgramming-h9DMXFX4.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-DTRhiKJn.js → Notes-Cihn-xX8.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-BAnnNCim.js → NotificationSettings-BE6ZGa3R.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-Yr-1fSYi.js → OrderTableRenderer-CnwojoSI.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-S9EAolpj.js → Organization-B2vpwmjb.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CqcLKqJ8.js → Overflow-C4z28R0-.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-Dw0F9EcU.js → P2P-BVlFkwhW.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BDRwUevN.js → PdhVaultBrowser-BXbEdL5B.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-D3_c3nKB.js → Permissions-C28xs4lp.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-CxdMV98x.js → PersonalDataHub-Dgl_rBjM.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-CgjNQFLI.js → Pipeline-3QUIhrKI.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-BHghIIht.js → Privacy-8Gh33OZ5.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-De6pqaKM.js → ProjectInit-BNmg4tZi.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-Bg4ZkNYQ.js → ProjectSettings-vgMfeCf9.js} +2 -2
- package/src/assets/web-panel/assets/Projects-BhtAVilc.js +1 -0
- package/src/assets/web-panel/assets/{Providers-CUnHbNf-.js → Providers-CXoOa8eX.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-DA2f3Wts.js → QrScannerModal-BhfTF0oS.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-C1FeHDqp.js → QuickAsk-C746HEAj.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-B5guaUMN.js → Recommend-BSej8Eo0.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-PDADSds3.js → RemoteSession-f3gmnlG3.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-eTlRhgvK.js → Reputation-CyvybpkN.js} +1 -1
- package/src/assets/web-panel/assets/{Row-D7AqSGY0.js → Row-DwV2PeYn.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-JiuLm4Ja.js → RssFeed-11GrzjZy.js} +3 -3
- package/src/assets/web-panel/assets/{Search-CwruahW3.js → Search-BjKXkrAY.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CdhqaR0b.js → Security-eWiFb9Yk.js} +4 -4
- package/src/assets/web-panel/assets/{Services-CU0ZIlcT.js → Services-CdCsMAtt.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-CtduPfAb.js → Skeleton-4Q2UTKQ5.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CROXm6AY.js → Skills-v4rtYrRj.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-DiZiABFD.js → Sla-CRhsFvd_.js} +1 -1
- package/src/assets/web-panel/assets/SpeechSettings-DLjKsDVu.js +1 -0
- package/src/assets/web-panel/assets/{SyncSettings-DBX6J1Oe.js → SyncSettings-D16zonl7.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-BLyRJd3-.js → Tasks-Xxozz0i_.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-BKa5qzmk.js → Templates-CXJpPtCT.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DnD3a4M6.js → Tenant-XRV0L1ZF.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-DEitQeTb.js → Terminal-CYuO1i_w.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-CjHggTDq.js → TimelineRenderer-BXqitWsu.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-CsGT7sfl.js → Tokens-BvPrDHIy.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-yr4rFDrW.js → Trigger-DhCrSTf5.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CLvu1Sjp.js → Trust-DmsuZD6K.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-B0m7yUP8.js → UkeySign-D_yrts5C.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-C0VvP4lc.js → VideoEditing-B01ihPrm.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-kllBAG1M.js → Wallet-DpUjKa-N.js} +3 -3
- package/src/assets/web-panel/assets/{WebAuthn-C54UQNLx.js → WebAuthn-CL07yON6.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-B7y8qSvU.js → WorkflowEditor-CLMflnRr.js} +1 -1
- package/src/assets/web-panel/assets/{chat-DRzTh8CJ.js → chat-DtUqe8h_.js} +1 -1
- package/src/assets/web-panel/assets/{colors-BSMwSnCx.js → colors-DPKrgVfy.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BTg602H5.js → compact-item-BTt2GtOm.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-B6EGsdvp.js → createContext-D_VeUc1J.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-Bj5nUW2v.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-DDKqJ8RD.js → hasIn-1kndiylj.js} +1 -1
- package/src/assets/web-panel/assets/{index-CUEU48o1.js → index-2eyAXE3d.js} +1 -1
- package/src/assets/web-panel/assets/{index-rjzk9z1Q.js → index-4bna2_SR.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmAubjDi.js → index-8nz_fmlj.js} +1 -1
- package/src/assets/web-panel/assets/{index-Co7oM1qr.js → index-B9KvcS7R.js} +1 -1
- package/src/assets/web-panel/assets/{index-BMuGd2--.js → index-BAXfRKfG.js} +1 -1
- package/src/assets/web-panel/assets/{index-BVTAl5N2.js → index-BHpBMWCh.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpTHIRfZ.js → index-BaZAbw9A.js} +1 -1
- package/src/assets/web-panel/assets/{index-CWGax2QW.js → index-BepLZwgB.js} +1 -1
- package/src/assets/web-panel/assets/{index-DiW0sDkz.js → index-Bhudc_Ez.js} +1 -1
- package/src/assets/web-panel/assets/{index-CGNklbP6.js → index-BlDNVgBt.js} +1 -1
- package/src/assets/web-panel/assets/{index-u2YVld9W.js → index-By5n8up9.js} +1 -1
- package/src/assets/web-panel/assets/{index-pqfux8vZ.js → index-CHG-KcS4.js} +1 -1
- package/src/assets/web-panel/assets/index-CPcM-eqo.js +1 -0
- package/src/assets/web-panel/assets/{index-BRqt4fO-.js → index-CX81qSM4.js} +1 -1
- package/src/assets/web-panel/assets/{index-BsR7Y2NG.js → index-CauoBQkH.js} +1 -1
- package/src/assets/web-panel/assets/{index-C_JzIXUq.js → index-CcO04eDn.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQlHFN_g.js → index-CtF7EN49.js} +1 -1
- package/src/assets/web-panel/assets/{index-CwPUZbMI.js → index-CzjkKUmR.js} +1 -1
- package/src/assets/web-panel/assets/{index-th2ihDc0.js → index-D95OFht7.js} +1 -1
- package/src/assets/web-panel/assets/{index-CHfLYwcW.js → index-DFIZ_1Sf.js} +1 -1
- package/src/assets/web-panel/assets/{index-C1GFfuqN.js → index-DG2MZQ3f.js} +1 -1
- package/src/assets/web-panel/assets/{index-D1naNj4U.js → index-DJ8vXGOa.js} +1 -1
- package/src/assets/web-panel/assets/{index-DLdrHhML.js → index-Dbbymxpj.js} +1 -1
- package/src/assets/web-panel/assets/{index-DBT3YeQ9.js → index-DdkplL9R.js} +1 -1
- package/src/assets/web-panel/assets/{index-BICn3Qh1.js → index-DfGl8CqG.js} +1 -1
- package/src/assets/web-panel/assets/{index-DqFXGzzC.js → index-DfKBRdSS.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bx044qDj.js → index-DsJCDUJG.js} +1 -1
- package/src/assets/web-panel/assets/{index-XFe-1twF.js → index-Dwqmtk65.js} +1 -1
- package/src/assets/web-panel/assets/{index-C66NpWy5.js → index-DxdTdBix.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmAInUkX.js → index-FzdwcSy2.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cf23wVMs.js → index-GsoUQ2M7.js} +1 -1
- package/src/assets/web-panel/assets/{index-D5CsBShd.js → index-brCInrzq.js} +1 -1
- package/src/assets/web-panel/assets/{index-323Hhxxt.js → index-dVc-CXY4.js} +1 -1
- package/src/assets/web-panel/assets/{index-p2HYn89m.js → index-fk2Rjacw.js} +3 -3
- package/src/assets/web-panel/assets/{index-Dfv2lKu3.js → index-l1BETrDb.js} +1 -1
- package/src/assets/web-panel/assets/{index-CNxg61YP.js → index-m31Ka8hZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-CDTvsX8t.js → index-ocf06EVQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dc77VR3H.js → index-sDoMHTNA.js} +1 -1
- package/src/assets/web-panel/assets/index-xeSyVoRe.js +1 -0
- package/src/assets/web-panel/assets/{initDefaultProps-C3Djh9fa.js → initDefaultProps-CvyYJd7z.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BzqFmbSe.js → motion-DYZkhUdz.js} +1 -1
- package/src/assets/web-panel/assets/{move-DJo_FFaW.js → move-slnJRVT1.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-_tlTiBvk.js → mtc-parser-DVc0CKmy.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CB2ZyxUg.js → omit-BCXAtHCq.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DZwIFD4u.js → pickAttrs-DBsemz_K.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-DxZY0dgk.js → placementArrow-BRtkJ-nv.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-CzzGt7GL.js → responsiveObserve-Cebq7EZn.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BaIK52yz.js → slide-DT7qvId2.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-3-FHu9_M.js → statusUtils-pQiITLkG.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BkRT68fK.js → styleChecker-c-19BVKQ.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DHYwKS-s.js → useFlexGapSupport-DsS5-0bE.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-DVVUhV8p.js → useFs-CxGiMe5n.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-CkrFKAzQ.js → usePersonalDataHub-D9btVID5.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-BuBLFz0c.js → vnode-CUYFsFEN.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-kpm6LtXU.js → zoom-CXmn_35j.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +1 -1
- package/src/commands/cowork.js +280 -5
- package/src/commands/plugin.js +819 -64
- package/src/commands/session-location.js +318 -7
- package/src/constants.js +2 -2
- package/src/data/changelog.json +14 -1
- package/src/gateways/ws/action-protocol.js +1 -1
- package/src/harness/jsonl-session-store.js +638 -2
- package/src/harness/prompt-compressor.js +4 -0
- package/src/lib/background-agent-keeper-client.js +29 -0
- package/src/lib/background-agent-keeper-protocol.js +4 -0
- package/src/lib/background-agent-supervisor.js +59 -29
- package/src/lib/cowork-task-runner.js +70 -0
- package/src/lib/cowork-workflow.js +42 -9
- package/src/lib/doctor-checkup.js +34 -10
- package/src/lib/dynamic-workflow-draft.js +535 -0
- package/src/lib/dynamic-workflow-facade.js +11 -11
- package/src/lib/dynamic-workflow-runtime.js +2974 -0
- package/src/lib/execution-location-contract.js +111 -7
- package/src/lib/execution-location-runtime.js +3 -1
- package/src/lib/execution-location-target.js +910 -0
- package/src/lib/llm-providers.js +1 -0
- package/src/lib/mcp-call-ledger-store.js +35 -0
- package/src/lib/mcp-call-ledger.js +30 -0
- package/src/lib/plugin-runtime/__tests__/remote-source.test.js +34 -16
- package/src/lib/plugin-runtime/install.js +4956 -657
- package/src/lib/plugin-runtime/manifest.js +3 -1
- package/src/lib/plugin-runtime/marketplace-artifact-readback.js +671 -31
- package/src/lib/plugin-runtime/marketplace-catalog.js +68 -2
- package/src/lib/plugin-runtime/marketplace-impact.js +208 -15
- package/src/lib/plugin-runtime/marketplace-network.js +317 -0
- package/src/lib/plugin-runtime/marketplace-pac-worker.js +15 -0
- package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +25 -2
- package/src/lib/plugin-runtime/marketplace-source-cache.js +359 -0
- package/src/lib/plugin-runtime/policy.js +21 -6
- package/src/lib/plugin-runtime/publisher-trust.js +332 -0
- package/src/lib/plugin-runtime/remote-source.js +323 -27
- package/src/lib/plugin-runtime/scopes.js +317 -41
- package/src/lib/plugin-runtime/transaction-journal.js +806 -0
- package/src/lib/public-ide-capability-manifest.js +1 -1
- package/src/lib/remote-membership-coordinator.js +8 -6
- package/src/lib/sub-agent-context.js +268 -2
- package/src/lib/task-model-selector.js +1 -1
- package/src/lib/with-file-lock.js +95 -5
- package/src/runtime/agent-core.js +595 -41
- package/src/workers/background-agent-keeper.js +40 -10
- package/src/assets/web-panel/assets/MarkdownRenderer-SVAgNnkt.js +0 -1
- package/src/assets/web-panel/assets/Projects-CP8vPvzs.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-B5pLcXUw.js +0 -1
- package/src/assets/web-panel/assets/devWarning-Dol8jLEP.js +0 -1
- package/src/assets/web-panel/assets/index-C3QX5tOl.js +0 -1
- package/src/assets/web-panel/assets/index-xYybvEic.js +0 -1
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { getElectronUserDataDir } from "../paths.js";
|
|
5
|
+
import { parsePluginManifest, isWithin } from "./manifest.js";
|
|
6
|
+
import {
|
|
7
|
+
PLUGIN_MARKETPLACE_STAGED_SOURCE_EXCLUSIONS,
|
|
8
|
+
buildMarketplacePayloadSbom,
|
|
9
|
+
isMarketplacePayloadSbomFormat,
|
|
10
|
+
} from "./marketplace-artifact-readback.js";
|
|
11
|
+
|
|
12
|
+
export const PLUGIN_MARKETPLACE_SOURCE_CACHE_SCHEMA =
|
|
13
|
+
"cc-plugin-marketplace-source-cache/v1";
|
|
14
|
+
export const SOURCE_CACHE_AUTHORITY_FILENAME = "authority.json";
|
|
15
|
+
const SHA256_RE = /^[a-f0-9]{64}$/;
|
|
16
|
+
const MAX_SOURCE_CACHE_AUTHORITY_BYTES = 64 * 1024;
|
|
17
|
+
|
|
18
|
+
export function marketplaceSourceCacheRoot(value) {
|
|
19
|
+
return path.resolve(
|
|
20
|
+
value ||
|
|
21
|
+
path.join(getElectronUserDataDir(), "plugin-marketplace-source-cache"),
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function marketplaceSourceCacheSpec(
|
|
26
|
+
sourceMetadata,
|
|
27
|
+
{ remoteSbomBytes = null } = {},
|
|
28
|
+
) {
|
|
29
|
+
if (sourceMetadata?.type !== "registry") return null;
|
|
30
|
+
const source = cleanString(sourceMetadata.resolvedSource, 4096);
|
|
31
|
+
const ref = cleanString(sourceMetadata.ref, 256);
|
|
32
|
+
const expectations = sourceMetadata.catalogAuthority?.artifactExpectations;
|
|
33
|
+
const manifestSha256 = normalizeSha256(expectations?.manifest?.sha256);
|
|
34
|
+
let payloadSchemaVersion = cleanString(expectations?.sbom?.format, 128);
|
|
35
|
+
let payloadSha256 = normalizeSha256(
|
|
36
|
+
expectations?.sbom?.payloadSha256 ?? expectations?.sbom?.sha256,
|
|
37
|
+
);
|
|
38
|
+
const comparison =
|
|
39
|
+
sourceMetadata.catalogAuthority?.remoteSbomPayloadComparison;
|
|
40
|
+
if (!payloadSha256 && comparison?.status === "matched") {
|
|
41
|
+
payloadSchemaVersion = cleanString(comparison.format, 128);
|
|
42
|
+
payloadSha256 = normalizeSha256(comparison.remotePayload?.digest);
|
|
43
|
+
}
|
|
44
|
+
if (!payloadSha256 && Buffer.isBuffer(remoteSbomBytes)) {
|
|
45
|
+
try {
|
|
46
|
+
const remotePayload = JSON.parse(
|
|
47
|
+
new TextDecoder("utf-8", { fatal: true }).decode(remoteSbomBytes),
|
|
48
|
+
);
|
|
49
|
+
if (remotePayload?.schemaVersion === payloadSchemaVersion) {
|
|
50
|
+
payloadSha256 = normalizeSha256(remotePayload.digest);
|
|
51
|
+
}
|
|
52
|
+
} catch {
|
|
53
|
+
throw new Error(
|
|
54
|
+
"Marketplace source cache remote payload SBOM is invalid",
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (
|
|
59
|
+
!source ||
|
|
60
|
+
!manifestSha256 ||
|
|
61
|
+
!payloadSha256 ||
|
|
62
|
+
!isMarketplacePayloadSbomFormat(payloadSchemaVersion)
|
|
63
|
+
) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
const keyAuthority = {
|
|
67
|
+
schemaVersion: PLUGIN_MARKETPLACE_SOURCE_CACHE_SCHEMA,
|
|
68
|
+
source,
|
|
69
|
+
ref,
|
|
70
|
+
manifestSha256,
|
|
71
|
+
payload: {
|
|
72
|
+
schemaVersion: payloadSchemaVersion,
|
|
73
|
+
sha256: payloadSha256,
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
return {
|
|
77
|
+
...keyAuthority,
|
|
78
|
+
cacheKey: sha256Canonical(keyAuthority),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function publishMarketplaceSourceCache(
|
|
83
|
+
sourceDir,
|
|
84
|
+
sourceMetadata,
|
|
85
|
+
{ cacheDir, remoteSbomBytes = null } = {},
|
|
86
|
+
) {
|
|
87
|
+
const spec = marketplaceSourceCacheSpec(sourceMetadata, { remoteSbomBytes });
|
|
88
|
+
if (!spec) return { status: "not-cacheable", cacheKey: null, dir: null };
|
|
89
|
+
const root = marketplaceSourceCacheRoot(cacheDir);
|
|
90
|
+
const target = path.join(root, spec.cacheKey);
|
|
91
|
+
if (fs.existsSync(target)) {
|
|
92
|
+
const cached = readMarketplaceSourceCache(sourceMetadata, {
|
|
93
|
+
cacheDir,
|
|
94
|
+
remoteSbomBytes,
|
|
95
|
+
});
|
|
96
|
+
return { status: "reused", cacheKey: spec.cacheKey, dir: cached.dir };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
fs.mkdirSync(root, { recursive: true, mode: 0o700 });
|
|
100
|
+
assertDirectory(root, "Marketplace source cache root");
|
|
101
|
+
const stage = path.join(
|
|
102
|
+
root,
|
|
103
|
+
`.tmp-${process.pid}-${crypto.randomBytes(12).toString("hex")}`,
|
|
104
|
+
);
|
|
105
|
+
const payload = path.join(stage, "payload");
|
|
106
|
+
try {
|
|
107
|
+
fs.mkdirSync(payload, { recursive: true, mode: 0o700 });
|
|
108
|
+
copySourcePayload(sourceDir, payload, payload, sourceDir);
|
|
109
|
+
const authority = buildCacheAuthority(payload, spec);
|
|
110
|
+
writeAuthority(
|
|
111
|
+
path.join(stage, SOURCE_CACHE_AUTHORITY_FILENAME),
|
|
112
|
+
authority,
|
|
113
|
+
);
|
|
114
|
+
fsyncDirectoryBestEffort(payload);
|
|
115
|
+
fsyncDirectoryBestEffort(stage);
|
|
116
|
+
try {
|
|
117
|
+
fs.renameSync(stage, target);
|
|
118
|
+
fsyncDirectoryBestEffort(root);
|
|
119
|
+
} catch (error) {
|
|
120
|
+
if (error?.code !== "EEXIST" && error?.code !== "ENOTEMPTY") throw error;
|
|
121
|
+
}
|
|
122
|
+
const cached = readMarketplaceSourceCache(sourceMetadata, {
|
|
123
|
+
cacheDir,
|
|
124
|
+
remoteSbomBytes,
|
|
125
|
+
});
|
|
126
|
+
return { status: "published", cacheKey: spec.cacheKey, dir: cached.dir };
|
|
127
|
+
} finally {
|
|
128
|
+
fs.rmSync(stage, { recursive: true, force: true });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function readMarketplaceSourceCache(
|
|
133
|
+
sourceMetadata,
|
|
134
|
+
{ cacheDir, remoteSbomBytes = null } = {},
|
|
135
|
+
) {
|
|
136
|
+
const spec = marketplaceSourceCacheSpec(sourceMetadata, { remoteSbomBytes });
|
|
137
|
+
if (!spec) {
|
|
138
|
+
throw new Error(
|
|
139
|
+
"offline source cache requires registry manifest SHA-256 and a repository-defined payload SBOM digest",
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
const target = path.join(marketplaceSourceCacheRoot(cacheDir), spec.cacheKey);
|
|
143
|
+
const payload = path.join(target, "payload");
|
|
144
|
+
if (!fs.existsSync(target)) {
|
|
145
|
+
throw new Error(
|
|
146
|
+
`OFFLINE_SOURCE_CACHE_MISS: verified source package ${spec.cacheKey} is unavailable`,
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
assertDirectory(target, "Marketplace source cache entry");
|
|
150
|
+
assertDirectory(payload, "Marketplace source cache payload");
|
|
151
|
+
assertSafeCachePayload(payload);
|
|
152
|
+
const stored = readAuthority(
|
|
153
|
+
path.join(target, SOURCE_CACHE_AUTHORITY_FILENAME),
|
|
154
|
+
);
|
|
155
|
+
const actual = buildCacheAuthority(payload, spec);
|
|
156
|
+
if (canonicalJson(stored) !== canonicalJson(actual)) {
|
|
157
|
+
throw new Error("Marketplace source cache authority or payload changed");
|
|
158
|
+
}
|
|
159
|
+
return { dir: payload, cacheKey: spec.cacheKey, authority: actual };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function buildCacheAuthority(payload, spec) {
|
|
163
|
+
const manifest = parsePluginManifest(payload);
|
|
164
|
+
if (!manifest.ok) {
|
|
165
|
+
throw new Error(
|
|
166
|
+
`Marketplace source cache manifest is invalid: ${manifest.errors.join("; ")}`,
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
const manifestSha256 = sha256(fs.readFileSync(manifest.manifestPath));
|
|
170
|
+
if (manifestSha256 !== spec.manifestSha256) {
|
|
171
|
+
throw new Error("Marketplace source cache manifest digest mismatch");
|
|
172
|
+
}
|
|
173
|
+
const payloadSbom = buildMarketplacePayloadSbom(payload, {
|
|
174
|
+
schemaVersion: spec.payload.schemaVersion,
|
|
175
|
+
});
|
|
176
|
+
if (payloadSbom.digest !== spec.payload.sha256) {
|
|
177
|
+
throw new Error("Marketplace source cache payload digest mismatch");
|
|
178
|
+
}
|
|
179
|
+
const withoutDigest = {
|
|
180
|
+
schemaVersion: PLUGIN_MARKETPLACE_SOURCE_CACHE_SCHEMA,
|
|
181
|
+
cacheKey: spec.cacheKey,
|
|
182
|
+
source: spec.source,
|
|
183
|
+
ref: spec.ref,
|
|
184
|
+
manifestSha256,
|
|
185
|
+
payload: {
|
|
186
|
+
schemaVersion: payloadSbom.schemaVersion,
|
|
187
|
+
sha256: payloadSbom.digest,
|
|
188
|
+
fileCount: payloadSbom.fileCount,
|
|
189
|
+
totalBytes: payloadSbom.totalBytes,
|
|
190
|
+
},
|
|
191
|
+
};
|
|
192
|
+
return {
|
|
193
|
+
...withoutDigest,
|
|
194
|
+
authorityDigest: sha256Canonical(withoutDigest),
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function copySourcePayload(source, destination, root, sourceRoot) {
|
|
199
|
+
assertDirectory(source, "Marketplace source material");
|
|
200
|
+
for (const entry of fs.readdirSync(source, { withFileTypes: true })) {
|
|
201
|
+
const from = path.join(source, entry.name);
|
|
202
|
+
const relative = path.relative(sourceRoot, from).replace(/\\/g, "/");
|
|
203
|
+
if (
|
|
204
|
+
PLUGIN_MARKETPLACE_STAGED_SOURCE_EXCLUSIONS.some(
|
|
205
|
+
(excluded) =>
|
|
206
|
+
relative === excluded || relative.startsWith(`${excluded}/`),
|
|
207
|
+
)
|
|
208
|
+
) {
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
const to = path.join(destination, entry.name);
|
|
212
|
+
if (!isWithin(root, to)) {
|
|
213
|
+
throw new Error("Marketplace source cache copy escaped its payload root");
|
|
214
|
+
}
|
|
215
|
+
const stat = fs.lstatSync(from);
|
|
216
|
+
if (stat.isSymbolicLink()) continue;
|
|
217
|
+
if (stat.isDirectory()) {
|
|
218
|
+
fs.mkdirSync(to, { recursive: false, mode: 0o700 });
|
|
219
|
+
copySourcePayload(from, to, root, sourceRoot);
|
|
220
|
+
} else if (stat.isFile()) {
|
|
221
|
+
fs.copyFileSync(from, to, fs.constants.COPYFILE_EXCL);
|
|
222
|
+
} else {
|
|
223
|
+
throw new Error("Marketplace source material contains a special file");
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function writeAuthority(file, value) {
|
|
229
|
+
const bytes = Buffer.from(`${JSON.stringify(value, null, 2)}\n`, "utf8");
|
|
230
|
+
if (bytes.length > MAX_SOURCE_CACHE_AUTHORITY_BYTES) {
|
|
231
|
+
throw new Error(
|
|
232
|
+
"Marketplace source cache authority exceeds its size limit",
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
const descriptor = fs.openSync(file, "wx", 0o600);
|
|
236
|
+
try {
|
|
237
|
+
fs.writeFileSync(descriptor, bytes);
|
|
238
|
+
fs.fsyncSync(descriptor);
|
|
239
|
+
} finally {
|
|
240
|
+
fs.closeSync(descriptor);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function readAuthority(file) {
|
|
245
|
+
let descriptor = null;
|
|
246
|
+
try {
|
|
247
|
+
const linkStat = fs.lstatSync(file);
|
|
248
|
+
if (
|
|
249
|
+
!linkStat.isFile() ||
|
|
250
|
+
linkStat.isSymbolicLink() ||
|
|
251
|
+
linkStat.nlink !== 1 ||
|
|
252
|
+
linkStat.size <= 0 ||
|
|
253
|
+
linkStat.size > MAX_SOURCE_CACHE_AUTHORITY_BYTES
|
|
254
|
+
) {
|
|
255
|
+
throw new Error(
|
|
256
|
+
"Marketplace source cache authority is not a bounded single-link regular file",
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
descriptor = fs.openSync(
|
|
260
|
+
file,
|
|
261
|
+
fs.constants.O_RDONLY | (fs.constants.O_NOFOLLOW || 0),
|
|
262
|
+
);
|
|
263
|
+
const fileStat = fs.fstatSync(descriptor);
|
|
264
|
+
if (
|
|
265
|
+
!fileStat.isFile() ||
|
|
266
|
+
fileStat.nlink !== 1 ||
|
|
267
|
+
fileStat.size !== linkStat.size ||
|
|
268
|
+
fileStat.size <= 0 ||
|
|
269
|
+
fileStat.size > MAX_SOURCE_CACHE_AUTHORITY_BYTES
|
|
270
|
+
) {
|
|
271
|
+
throw new Error(
|
|
272
|
+
"Marketplace source cache authority changed during inspection",
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
const bytes = fs.readFileSync(descriptor);
|
|
276
|
+
let text;
|
|
277
|
+
try {
|
|
278
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
279
|
+
} catch {
|
|
280
|
+
throw new Error("Marketplace source cache authority is not valid UTF-8");
|
|
281
|
+
}
|
|
282
|
+
return JSON.parse(text);
|
|
283
|
+
} finally {
|
|
284
|
+
if (descriptor != null) fs.closeSync(descriptor);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function assertSafeCachePayload(root, current = root) {
|
|
289
|
+
for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
|
|
290
|
+
const absolute = path.join(current, entry.name);
|
|
291
|
+
if (!isWithin(root, absolute)) {
|
|
292
|
+
throw new Error("Marketplace source cache payload escaped its root");
|
|
293
|
+
}
|
|
294
|
+
const stat = fs.lstatSync(absolute);
|
|
295
|
+
if (stat.isSymbolicLink()) {
|
|
296
|
+
throw new Error(
|
|
297
|
+
"Marketplace source cache payload contains a symbolic link",
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
if (stat.isDirectory()) {
|
|
301
|
+
assertSafeCachePayload(root, absolute);
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
if (!stat.isFile() || stat.nlink !== 1) {
|
|
305
|
+
throw new Error(
|
|
306
|
+
"Marketplace source cache payload contains a non-regular or hard-linked file",
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function assertDirectory(directory, label) {
|
|
313
|
+
const stat = fs.lstatSync(directory);
|
|
314
|
+
if (!stat.isDirectory() || stat.isSymbolicLink()) {
|
|
315
|
+
throw new Error(`${label} is not a directory`);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function fsyncDirectoryBestEffort(directory) {
|
|
320
|
+
let descriptor = null;
|
|
321
|
+
try {
|
|
322
|
+
descriptor = fs.openSync(directory, fs.constants.O_RDONLY);
|
|
323
|
+
fs.fsyncSync(descriptor);
|
|
324
|
+
} catch {
|
|
325
|
+
// Windows and some filesystems do not support directory fsync.
|
|
326
|
+
} finally {
|
|
327
|
+
if (descriptor != null) fs.closeSync(descriptor);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function cleanString(value, max) {
|
|
332
|
+
if (typeof value !== "string") return null;
|
|
333
|
+
const clean = value.replace(/\p{Cc}/gu, "").trim();
|
|
334
|
+
return clean ? clean.slice(0, max) : null;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function normalizeSha256(value) {
|
|
338
|
+
const digest = cleanString(value, 64)?.toLowerCase() || null;
|
|
339
|
+
return digest && SHA256_RE.test(digest) ? digest : null;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function sha256(value) {
|
|
343
|
+
return crypto.createHash("sha256").update(value).digest("hex");
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function sha256Canonical(value) {
|
|
347
|
+
return sha256(canonicalJson(value));
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function canonicalJson(value) {
|
|
351
|
+
if (value == null || typeof value !== "object") return JSON.stringify(value);
|
|
352
|
+
if (Array.isArray(value)) {
|
|
353
|
+
return `[${value.map((item) => canonicalJson(item)).join(",")}]`;
|
|
354
|
+
}
|
|
355
|
+
return `{${Object.keys(value)
|
|
356
|
+
.sort()
|
|
357
|
+
.map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`)
|
|
358
|
+
.join(",")}}`;
|
|
359
|
+
}
|
|
@@ -26,6 +26,7 @@ import { enforcePluginPolicy } from "../plugin-security.js";
|
|
|
26
26
|
import { loadManagedSettings } from "../settings-loader.cjs";
|
|
27
27
|
import { verifyInstalledSignature } from "./signature.js";
|
|
28
28
|
import { isPluginCapabilityConsented } from "./capability-consent.js";
|
|
29
|
+
import { verifyInstalledManagedPublisherAuthority } from "./publisher-trust.js";
|
|
29
30
|
|
|
30
31
|
// Managed settings are org-admin controlled and effectively static for a
|
|
31
32
|
// session, and discoverPlugins is called by every collector — memoize the load
|
|
@@ -86,17 +87,17 @@ export function _resetPolicyCache() {
|
|
|
86
87
|
* @returns {{ kept: Array, dropped: Array<{name, reason}> }}
|
|
87
88
|
*/
|
|
88
89
|
export function filterByManagedPolicy(plugins, managed) {
|
|
89
|
-
|
|
90
|
+
const policy = managed || {};
|
|
90
91
|
// requireSignedPlugins (fail-closed): every plugin must carry a valid recorded
|
|
91
92
|
// signature whose locked manifest hash still matches on disk. Optionally the
|
|
92
93
|
// signing key must be among managed.trustedPluginKeySha256.
|
|
93
94
|
const requireSigned =
|
|
94
|
-
|
|
95
|
-
|
|
95
|
+
policy.requireSignedPlugins === true ||
|
|
96
|
+
policy.requireSignedPlugins === "require";
|
|
96
97
|
const trustedKeys = requireSigned
|
|
97
98
|
? new Set(
|
|
98
|
-
(Array.isArray(
|
|
99
|
-
?
|
|
99
|
+
(Array.isArray(policy.trustedPluginKeySha256)
|
|
100
|
+
? policy.trustedPluginKeySha256
|
|
100
101
|
: []
|
|
101
102
|
)
|
|
102
103
|
.map((k) => String(k || "").trim())
|
|
@@ -109,12 +110,26 @@ export function filterByManagedPolicy(plugins, managed) {
|
|
|
109
110
|
try {
|
|
110
111
|
enforcePluginPolicy(
|
|
111
112
|
{ name: p.name, source: null, action: "load" },
|
|
112
|
-
|
|
113
|
+
policy,
|
|
113
114
|
);
|
|
114
115
|
} catch (err) {
|
|
115
116
|
dropped.push({ name: p.name, reason: err.message });
|
|
116
117
|
continue;
|
|
117
118
|
}
|
|
119
|
+
const publisher = verifyInstalledManagedPublisherAuthority(
|
|
120
|
+
{ root: p.root, name: p.name },
|
|
121
|
+
policy,
|
|
122
|
+
);
|
|
123
|
+
if (
|
|
124
|
+
(publisher.present && !publisher.verified) ||
|
|
125
|
+
(policy.requireTrustedPluginPublishers === true && !publisher.verified)
|
|
126
|
+
) {
|
|
127
|
+
dropped.push({
|
|
128
|
+
name: p.name,
|
|
129
|
+
reason: `trusted publisher: ${publisher.reason || "authority missing"}`,
|
|
130
|
+
});
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
118
133
|
if (requireSigned) {
|
|
119
134
|
// Fail closed when no signing keys are pinned: a lock's signature can be
|
|
120
135
|
// SELF-signed by whoever authored the plugin (the lock lives in a
|