chainlesschain 0.165.4 → 0.165.6

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.
Files changed (214) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/.build-hash +1 -1
  3. package/src/assets/web-panel/assets/{AIOps-C__nnraW.js → AIOps-vfoDb6HZ.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-CsKWHEZ-.js → ActionButton-Cm5f7p93.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-BhIjfjWO.js → Analytics-yRuvgWxa.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-BjuXFzWZ.js → AppLayout-BROsC4h1.js} +4 -4
  7. package/src/assets/web-panel/assets/{Artifacts-k6whDkZJ.js → Artifacts-CimHApb1.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-C4FBMYRh.js → Audit-DI8kr8zI.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-C_vRrSXk.js → BackgroundAgents-DSLzKy-n.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-CngFZeVp.js → Backup-DkH_n2r1.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-B_H9EBRm.js → BaseInput-CKSrUoRA.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-DLEC5kt7.js → Chat-ClwfMXUS.js} +3 -3
  13. package/src/assets/web-panel/assets/ChatBubbleRenderer-CjMaqfL7.js +1 -0
  14. package/src/assets/web-panel/assets/{Checkbox-m3ClR4xh.js → Checkbox-BYTehcQG.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-CmLSFrgp.js → Codegen-B8AMcp6J.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-DFGQteHN.js → Col-BNSogPo3.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-EUUVORHE.js → Community-JxPvGb8O.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-2PSg0Yr7.js → Compact-DF7bFAgE.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-CcKur7gB.js → Compliance-Bvhqnwrq.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-DK_Fezfa.js → Cowork-BDS0CJvM.js} +3 -3
  21. package/src/assets/web-panel/assets/{Cron-Dbw89xl7.js → Cron-DqvRfxoQ.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-CH66h_Ec.js → Crosschain-CDcIvnqS.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-D1igRb17.js → DID-D7jaUxU3.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-DVAsrobk.js → Dashboard-B5A18wEV.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-Dl7W8AQs.js → Dropdown-_6IVkGag.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-D5tpaEQC.js → EmailListRenderer-C9PeiKCG.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-O_VQf8gq.js → FamilyGuardDashboard-DXjuEHrX.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-BTVcgS9n.js → Federation-B4IAR9zv.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-BRnkJAIz.js → FormItemContext-CxQeSNx1.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-8OWSCkDj.js → GenericCardRenderer-B8GS-Y3N.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-WXLYTQj2.js → Git-BS8SouUX.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-BezaUhtc.js → Governance-Dq9aYb5Q.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-CuRay3Gu.js → Inference-BrCEe9AJ.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-DfWLDW1m.js → KnowledgeGraph-DybOpiY2.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-C55y2pPY.js → Logs-DBpzbRfx.js} +2 -2
  36. package/src/assets/web-panel/assets/MarkdownRenderer-CFyt8iUd.js +1 -0
  37. package/src/assets/web-panel/assets/{Marketplace-Dk08Uycg.js → Marketplace-Cc7CCSCu.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-C11fSB5V.js → McpTools-DFaIhOfu.js} +3 -3
  39. package/src/assets/web-panel/assets/{Memory-mr0eZc97.js → Memory-KCqlp9ol.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-C0iCSRbb.js → MobileBridge-Bys84ySN.js} +1 -1
  41. package/src/assets/web-panel/assets/{MobileProjects-CY-xMG8Z.js → MobileProjects-B-6qU-je.js} +1 -1
  42. package/src/assets/web-panel/assets/{Mtc-Bplqc_Wc.js → Mtc-BgY-fvCq.js} +4 -4
  43. package/src/assets/web-panel/assets/{MtcAudit-BlzwsoSM.js → MtcAudit-B8pCmqQJ.js} +4 -4
  44. package/src/assets/web-panel/assets/{Multisig-BBLmTty6.js → Multisig-BbOmYutA.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-DtT1uf1W.js → NLProgramming-BocLQz_M.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-DcqQAxTK.js → Notes-CSwbxEop.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-cb0kWoZe.js → NotificationSettings-CqFNSYG3.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-kw9HZQNN.js → OrderTableRenderer-C6gMfAk7.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-DlTlbkUN.js → Organization-QrDXVdMJ.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-pp1qs-oY.js → Overflow-Cxntotjt.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-BESLnyYz.js → P2P-CIdBOwNq.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-B-J1mGuf.js → PdhVaultBrowser-CT5aP8rD.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-B36PeT1_.js → Permissions-DH7OM8XU.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-CTK2ad-3.js → PersonalDataHub-CnJqbWce.js} +3 -3
  55. package/src/assets/web-panel/assets/{Pipeline-zJNGXsac.js → Pipeline-5C3HG1kH.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-b9fz0Qf0.js → Privacy-B4yIp7xK.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-DjZbZgiB.js → ProjectInit-BMvt-2M0.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-C-hHJXlD.js → ProjectSettings-CvSTEMRG.js} +2 -2
  59. package/src/assets/web-panel/assets/Projects-BKBJxEek.js +1 -0
  60. package/src/assets/web-panel/assets/Providers-BdwUqFWN.js +1 -0
  61. package/src/assets/web-panel/assets/{QrScannerModal-A0yoQ3-3.js → QrScannerModal-DtnCKlTm.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-DrFgFJNC.js → QuickAsk-sTbgwyNr.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-KC8hF1g4.js → Recommend-Bzr14gSb.js} +1 -1
  64. package/src/assets/web-panel/assets/{RemoteSession-DGTPIk6u.js → RemoteSession-C_TF5IaJ.js} +2 -2
  65. package/src/assets/web-panel/assets/{Reputation-QmbwM7Yk.js → Reputation-GCAM4H2K.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-BxjJylia.js → Row-Dir0r6OQ.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-B7Wda1J6.js → RssFeed-CpGnlecX.js} +2 -2
  68. package/src/assets/web-panel/assets/{Search-_plQ_YSA.js → Search-DMMamC6u.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-CD2YJZfx.js → Security-yqay5yG-.js} +4 -4
  70. package/src/assets/web-panel/assets/{Services-qQE7NmwE.js → Services-C5i2wh9G.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-DgQqkFf7.js → Skeleton-vUqk35yj.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-C4C0oFFt.js → Skills-DzcSkhot.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-Px2N2B5c.js → Sla-CB6qbYNr.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-DN6C3lQd.js → SpeechSettings-BHUI7cox.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-jm5aH_m7.js → SyncSettings-D-RrsxTJ.js} +2 -2
  76. package/src/assets/web-panel/assets/{Tasks-DlkJcv67.js → Tasks-DFxdOJiq.js} +1 -1
  77. package/src/assets/web-panel/assets/{Templates-DyrTHUBs.js → Templates-SKAob_Aq.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-mC434PtL.js → Tenant-BPfsfHQ-.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-o0_s3NgK.js → Terminal-8iw7FpUf.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-DAGlAXOw.js → TimelineRenderer-C4Gjj5Su.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-BnulS_bs.js → Tokens-COYhN18e.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-suQbVXYM.js → Trigger-B-JzXcf6.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-DbIJAPo5.js → Trust-BJ5bg0nI.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-CQNpbIHi.js → UkeySign-BG_ByRMf.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-D8aWCERk.js → VideoEditing-B3kOnSiU.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-CuLpYfZc.js → Wallet-CcoGFnK7.js} +2 -2
  87. package/src/assets/web-panel/assets/{WebAuthn-CsfG8ZMc.js → WebAuthn-DdT8vRC_.js} +4 -4
  88. package/src/assets/web-panel/assets/{WorkflowEditor-BYsEAZbd.js → WorkflowEditor-CZu3M9N8.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-FT4Um3-I.js → chat-DxJt3Qba.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-CKbS_Wlt.js → colors-DdYfwJaB.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-CFJtzuJM.js → compact-item-BG3SUzwj.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-B9kSRW6K.js → createContext-By51z2-1.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-DorRZcI9.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-DR-x0Xpi.js → hasIn-B0apZ3KJ.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-DjEP7WkH.js → index-3jWkIu5j.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-7jHr_A_k.js → index-B3rWuPMW.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-DcfxhKXR.js → index-B5rLiEo0.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-tqSEHPRT.js → index-BBPf3TpM.js} +1 -1
  99. package/src/assets/web-panel/assets/index-BETiL0a3.js +1 -0
  100. package/src/assets/web-panel/assets/{index-Cr2FLUsD.js → index-BIrJfqO4.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-Bt4fS2eL.js → index-BLIbGOLX.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-BwR7yc2h.js → index-BP94CrBV.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BVPU43b1.js → index-BWF8_mkx.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DShSkww-.js → index-BYINoRLK.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-Bzz0C1BZ.js → index-BZ_0qm4g.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-KqDaCApw.js → index-BewKYrX9.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BW-t9n-q.js → index-BfWYsB9t.js} +1 -1
  108. package/src/assets/web-panel/assets/index-BhAVHuW8.js +1 -0
  109. package/src/assets/web-panel/assets/{index-B7osrXqy.js → index-Bissefox.js} +3 -3
  110. package/src/assets/web-panel/assets/{index-DW4BWjTk.js → index-BkvcEo4p.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DdkIhfi-.js → index-Bos5_aMV.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-DTxNy0ZU.js → index-C1C9i79A.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-QBSeNVO3.js → index-CAhHirVH.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-D4LfPvWA.js → index-CNIxXMmN.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-C_enk9I_.js → index-CW93tZDv.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-WE08gMJP.js → index-CWEuZWCK.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-r2VI1Ikk.js → index-Cp6e-hGw.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-Dap9c3eD.js → index-CpjZhgNd.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-DWdqx7zI.js → index-CzmQElZy.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BGbPnC5x.js → index-DCn8IcxV.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-DiNUEpSQ.js → index-DE76D-kA.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DtkFqPVA.js → index-DaIz0NAW.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CGaXUsIs.js → index-Da_WBdLX.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-B3ZX81mK.js → index-Dz49VOyQ.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-BK3TiKVq.js → index-Q2SCX-MI.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-CJmIQ9XR.js → index-RD6O-0C6.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-CvrCCqJt.js → index-SQqOlR3d.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BI5hP_qy.js → index-ZFbps9po.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-DeSgw-WV.js → index-ZxtP8jG7.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-DMGmg497.js → index-bP_VlDb4.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-BfFCQHL3.js → index-kf57LJ93.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-OSzjTzGM.js → index-oxRrmFO9.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-C2JvmYRc.js → index-p1_8SbI1.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-Dd7n7VgI.js → initDefaultProps-BWJktcg8.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-BwxouRw1.js → motion-BEXBzUFV.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-DObN0PG9.js → move-BUKwn2sx.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-B3nOUQc7.js → mtc-parser-FTI7btqQ.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-o9WU2Nbl.js → omit-CsLtSPH3.js} +1 -1
  139. package/src/assets/web-panel/assets/parsers-YNLm7sQ0.js +4 -0
  140. package/src/assets/web-panel/assets/{pickAttrs-CL_vvfQ_.js → pickAttrs-DWZxsT_S.js} +1 -1
  141. package/src/assets/web-panel/assets/{placementArrow-CYrM2tyK.js → placementArrow-Bcfs43CX.js} +1 -1
  142. package/src/assets/web-panel/assets/{responsiveObserve-k_06cQ96.js → responsiveObserve-a9bcC1p-.js} +1 -1
  143. package/src/assets/web-panel/assets/{slide-CPKG0pxS.js → slide-BDTzgOXN.js} +1 -1
  144. package/src/assets/web-panel/assets/{statusUtils-BDDEeLTw.js → statusUtils-Iq1j_HUg.js} +1 -1
  145. package/src/assets/web-panel/assets/{styleChecker-Cmb7RTh7.js → styleChecker-DAZEYxeh.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFlexGapSupport-e2IedC4N.js → useFlexGapSupport-DVkjyDrh.js} +1 -1
  147. package/src/assets/web-panel/assets/{useFs-CE_gxVnm.js → useFs-wXTpNTHt.js} +1 -1
  148. package/src/assets/web-panel/assets/{usePersonalDataHub-BkMIIKMz.js → usePersonalDataHub-CtQM_aZr.js} +1 -1
  149. package/src/assets/web-panel/assets/{vnode-DW886XV1.js → vnode-hjEoG85v.js} +1 -1
  150. package/src/assets/web-panel/assets/{zoom-Dwo_adaf.js → zoom-BHVpyKg_.js} +1 -1
  151. package/src/assets/web-panel/index.html +1 -1
  152. package/src/command-help-index.json +3 -3
  153. package/src/commands/agent.js +14 -2
  154. package/src/commands/artifacts.js +235 -0
  155. package/src/commands/background-session.js +100 -10
  156. package/src/commands/cowork.js +86 -57
  157. package/src/commands/mcp.js +5 -0
  158. package/src/commands/plugin.js +145 -29
  159. package/src/commands/remote-control.js +295 -110
  160. package/src/commands/session-location.js +20 -1
  161. package/src/commands/session-message.js +171 -0
  162. package/src/commands/session.js +75 -69
  163. package/src/data/changelog.json +29 -3
  164. package/src/gateways/ws/message-dispatcher.js +57 -0
  165. package/src/harness/mcp-client.js +141 -10
  166. package/src/lib/artifact-access-ledger.js +1 -0
  167. package/src/lib/artifact-deletion-ledger.js +1 -0
  168. package/src/lib/artifact-recovery.js +970 -0
  169. package/src/lib/artifact-workbench-projection.js +171 -0
  170. package/src/lib/background-session-transport.js +153 -27
  171. package/src/lib/dynamic-workflow-runtime.js +408 -1
  172. package/src/lib/execution-location-target.js +4 -2
  173. package/src/lib/mcp-client.js +2 -0
  174. package/src/lib/mcp-headers-helper.js +47 -5
  175. package/src/lib/mcp-oauth.js +55 -6
  176. package/src/lib/mcp-stdio-executable-identity.js +16 -0
  177. package/src/lib/mcp-stdio-native-code-policy.js +74 -0
  178. package/src/lib/mcp-stdio-package-materialization.js +12 -3
  179. package/src/lib/mcp-tls.js +230 -0
  180. package/src/lib/output-styles.js +12 -0
  181. package/src/lib/plugin-runtime/install.js +614 -71
  182. package/src/lib/plugin-runtime/marketplace-archive-source.js +331 -0
  183. package/src/lib/plugin-runtime/marketplace-catalog.js +52 -6
  184. package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +1 -0
  185. package/src/lib/plugin-runtime/marketplace-source-adapter.js +163 -0
  186. package/src/lib/plugin-runtime/marketplace-source-cache.js +11 -1
  187. package/src/lib/plugin-runtime/remote-source.js +435 -55
  188. package/src/lib/plugin-security.js +393 -41
  189. package/src/lib/plugin-source-identity.js +850 -0
  190. package/src/lib/process-execution-broker/index.js +112 -0
  191. package/src/lib/process-execution-broker/platform-sandbox.js +57 -3
  192. package/src/lib/process-execution-broker/workspace-transaction.js +26 -0
  193. package/src/lib/remote-approval-bridge.js +136 -46
  194. package/src/lib/remote-control.js +217 -31
  195. package/src/lib/session-message-fabric.js +1105 -0
  196. package/src/lib/session-projection.js +171 -12
  197. package/src/lib/session-runtime-retention.js +155 -0
  198. package/src/lib/settings-loader.cjs +29 -0
  199. package/src/repl/agent-repl.js +51 -14
  200. package/src/repl/permission-prompt.js +31 -8
  201. package/src/repl/repl-keybindings.js +55 -0
  202. package/src/runtime/agent-core.js +63 -2
  203. package/src/runtime/headless-runner.js +47 -66
  204. package/src/runtime/headless-stream.js +18 -24
  205. package/src/runtime/mcp-config.js +2 -0
  206. package/src/runtime/policies/agent-policy.js +2 -0
  207. package/src/assets/web-panel/assets/ChatBubbleRenderer-xijcWkJe.js +0 -1
  208. package/src/assets/web-panel/assets/MarkdownRenderer-hDpWdiBc.js +0 -1
  209. package/src/assets/web-panel/assets/Projects-BC9KSDM6.js +0 -1
  210. package/src/assets/web-panel/assets/Providers-Dz-CAYYU.js +0 -1
  211. package/src/assets/web-panel/assets/devWarning-DJZ0gAMu.js +0 -1
  212. package/src/assets/web-panel/assets/index-Bizb4hkw.js +0 -1
  213. package/src/assets/web-panel/assets/index-OHSl-xCh.js +0 -1
  214. package/src/assets/web-panel/assets/parsers-UEvh_ShA.js +0 -4
@@ -0,0 +1,331 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { gunzipSync } from "node:zlib";
5
+ import { getElectronUserDataDir } from "../paths.js";
6
+ import {
7
+ assertSafeInstalledPluginStructure,
8
+ buildMarketplacePayloadSbom,
9
+ } from "./marketplace-artifact-readback.js";
10
+ import { createMarketplaceNetworkTransport } from "./marketplace-network.js";
11
+ import { fetchMarketplaceRemoteArtifact } from "./marketplace-remote-artifacts.js";
12
+
13
+ export const MARKETPLACE_ARCHIVE_SOURCE_SCHEMA =
14
+ "cc-plugin-marketplace-archive-source/v1";
15
+ export const MARKETPLACE_ARCHIVE_LIMITS = Object.freeze({
16
+ compressedBytes: 64 * 1024 * 1024,
17
+ expandedBytes: 256 * 1024 * 1024,
18
+ entries: 10_000,
19
+ });
20
+
21
+ function sha256(value) {
22
+ return crypto.createHash("sha256").update(value).digest("hex");
23
+ }
24
+
25
+ function octal(header, offset, length) {
26
+ const text = header
27
+ .subarray(offset, offset + length)
28
+ .toString("ascii")
29
+ .replace(/\0.*$/u, "")
30
+ .trim();
31
+ return text ? Number.parseInt(text, 8) : 0;
32
+ }
33
+
34
+ function cString(header, offset, length) {
35
+ const bytes = header.subarray(offset, offset + length);
36
+ const end = bytes.indexOf(0);
37
+ return bytes.subarray(0, end < 0 ? bytes.length : end).toString("utf8");
38
+ }
39
+
40
+ function checksumValid(header) {
41
+ const expected = octal(header, 148, 8);
42
+ let actual = 0;
43
+ for (let index = 0; index < 512; index += 1) {
44
+ actual += index >= 148 && index < 156 ? 0x20 : header[index];
45
+ }
46
+ return expected === actual;
47
+ }
48
+
49
+ function safeArchivePath(raw) {
50
+ const value = String(raw || "");
51
+ if (
52
+ !value ||
53
+ value.includes("\\") ||
54
+ value.includes("\0") ||
55
+ value.startsWith("/") ||
56
+ /^[a-z]:/iu.test(value)
57
+ ) {
58
+ throw new Error("archive contains an unsafe path");
59
+ }
60
+ const segments = value.split("/").filter((part) => part && part !== ".");
61
+ const unsafePortableSegment = (part) =>
62
+ part === ".." ||
63
+ Buffer.byteLength(part, "utf8") > 255 ||
64
+ /[\u0000-\u001f:]/u.test(part) ||
65
+ /[ .]$/u.test(part) ||
66
+ /^(?:con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/iu.test(part);
67
+ if (
68
+ value.length > 4096 ||
69
+ segments.some(unsafePortableSegment) ||
70
+ segments[0] !== "package"
71
+ ) {
72
+ throw new Error("archive must contain only a package/ root");
73
+ }
74
+ return segments.slice(1);
75
+ }
76
+
77
+ function parsePax(data) {
78
+ const values = {};
79
+ let offset = 0;
80
+ while (offset < data.length) {
81
+ const space = data.indexOf(0x20, offset);
82
+ if (space < 0) throw new Error("archive PAX header is malformed");
83
+ const length = Number.parseInt(data.toString("ascii", offset, space), 10);
84
+ if (
85
+ !Number.isSafeInteger(length) ||
86
+ length <= 0 ||
87
+ offset + length > data.length
88
+ ) {
89
+ throw new Error("archive PAX record length is invalid");
90
+ }
91
+ const record = data.toString("utf8", space + 1, offset + length - 1);
92
+ const equals = record.indexOf("=");
93
+ if (equals > 0) values[record.slice(0, equals)] = record.slice(equals + 1);
94
+ offset += length;
95
+ }
96
+ return values;
97
+ }
98
+
99
+ function extractVerifiedTgz(bytes, destination) {
100
+ let tar;
101
+ try {
102
+ tar = gunzipSync(bytes, {
103
+ maxOutputLength: MARKETPLACE_ARCHIVE_LIMITS.expandedBytes,
104
+ });
105
+ } catch {
106
+ throw new Error("Marketplace archive is not a bounded valid gzip stream");
107
+ }
108
+ const seen = new Set();
109
+ let offset = 0;
110
+ let records = 0;
111
+ let extractedEntries = 0;
112
+ let extractedBytes = 0;
113
+ let pendingLongName = null;
114
+ let pendingPax = null;
115
+ while (offset + 512 <= tar.length) {
116
+ const header = tar.subarray(offset, offset + 512);
117
+ if (header.every((value) => value === 0)) break;
118
+ if (!checksumValid(header))
119
+ throw new Error("archive tar checksum mismatch");
120
+ const size = octal(header, 124, 12);
121
+ if (!Number.isSafeInteger(size) || size < 0) {
122
+ throw new Error("archive tar entry size is invalid");
123
+ }
124
+ const typeByte = header[156];
125
+ const type = typeByte === 0 ? "0" : String.fromCharCode(typeByte);
126
+ const dataStart = offset + 512;
127
+ const dataEnd = dataStart + size;
128
+ if (dataEnd > tar.length) throw new Error("archive tar entry is truncated");
129
+ const data = tar.subarray(dataStart, dataEnd);
130
+ offset = dataStart + Math.ceil(size / 512) * 512;
131
+ records += 1;
132
+ if (records > MARKETPLACE_ARCHIVE_LIMITS.entries) {
133
+ throw new Error("archive contains too many entries");
134
+ }
135
+
136
+ if (type === "L") {
137
+ pendingLongName = data.toString("utf8").replace(/\0+$/u, "");
138
+ continue;
139
+ }
140
+ if (type === "x" || type === "X") {
141
+ pendingPax = parsePax(data);
142
+ continue;
143
+ }
144
+ if (type === "g") continue;
145
+ if (!new Set(["0", "5"]).has(type)) {
146
+ throw new Error(
147
+ "archive links, devices, and special entries are rejected",
148
+ );
149
+ }
150
+
151
+ const name = cString(header, 0, 100);
152
+ const prefix = cString(header, 345, 155);
153
+ let archivePath = prefix ? `${prefix}/${name}` : name;
154
+ if (pendingLongName != null) archivePath = pendingLongName;
155
+ if (typeof pendingPax?.path === "string" && pendingPax.path) {
156
+ archivePath = pendingPax.path;
157
+ }
158
+ pendingLongName = null;
159
+ pendingPax = null;
160
+ const parts = safeArchivePath(archivePath);
161
+ if (parts.length === 0) continue;
162
+ const relativePath = parts.join("/");
163
+ const collisionKey = relativePath.normalize("NFC").toLowerCase();
164
+ if (seen.has(collisionKey)) {
165
+ throw new Error("archive contains duplicate or case-colliding paths");
166
+ }
167
+ seen.add(collisionKey);
168
+ extractedEntries += 1;
169
+ const target = path.join(destination, ...parts);
170
+ const relative = path.relative(destination, target);
171
+ if (!relative || relative.startsWith("..") || path.isAbsolute(relative)) {
172
+ throw new Error("archive extraction escaped its package root");
173
+ }
174
+ if (type === "5") {
175
+ fs.mkdirSync(target, { recursive: true, mode: 0o755 });
176
+ continue;
177
+ }
178
+ extractedBytes += data.length;
179
+ if (extractedBytes > MARKETPLACE_ARCHIVE_LIMITS.expandedBytes) {
180
+ throw new Error("archive expanded payload exceeds its byte limit");
181
+ }
182
+ fs.mkdirSync(path.dirname(target), { recursive: true, mode: 0o755 });
183
+ const mode = octal(header, 100, 8) & 0o111 ? 0o755 : 0o644;
184
+ fs.writeFileSync(target, data, { flag: "wx", mode });
185
+ }
186
+ if (extractedEntries === 0) throw new Error("archive package is empty");
187
+ assertSafeInstalledPluginStructure(destination);
188
+ return buildMarketplacePayloadSbom(destination);
189
+ }
190
+
191
+ function cacheRoot(configured) {
192
+ return (
193
+ configured || path.join(getElectronUserDataDir(), "plugin-archive-sources")
194
+ );
195
+ }
196
+
197
+ function readAuthority(root, expected) {
198
+ const authorityPath = path.join(root, "authority.json");
199
+ const packagePath = path.join(root, "package");
200
+ const rootStat = fs.lstatSync(root);
201
+ const authorityStat = fs.lstatSync(authorityPath);
202
+ if (
203
+ !rootStat.isDirectory() ||
204
+ rootStat.isSymbolicLink() ||
205
+ !authorityStat.isFile() ||
206
+ authorityStat.isSymbolicLink() ||
207
+ authorityStat.nlink !== 1 ||
208
+ authorityStat.size <= 0 ||
209
+ authorityStat.size > 64 * 1024
210
+ ) {
211
+ throw new Error("Marketplace archive source cache structure is unsafe");
212
+ }
213
+ const authority = JSON.parse(fs.readFileSync(authorityPath, "utf8"));
214
+ if (
215
+ authority.schemaVersion !== MARKETPLACE_ARCHIVE_SOURCE_SCHEMA ||
216
+ authority.status !== "digest-verified-and-extracted" ||
217
+ authority.url !== expected.url ||
218
+ authority.registryOrigin !== expected.registryOrigin ||
219
+ authority.archiveSha256 !== expected.archiveSha256 ||
220
+ authority.compressedBytes !== expected.compressedBytes
221
+ ) {
222
+ throw new Error("Marketplace archive source cache authority mismatch");
223
+ }
224
+ assertSafeInstalledPluginStructure(packagePath);
225
+ const payload = buildMarketplacePayloadSbom(packagePath);
226
+ if (
227
+ payload.digest !== authority.payloadSha256 ||
228
+ payload.fileCount !== authority.fileCount ||
229
+ payload.totalBytes !== authority.totalBytes
230
+ ) {
231
+ throw new Error("Marketplace archive extracted payload digest mismatch");
232
+ }
233
+ return { authority, packagePath };
234
+ }
235
+
236
+ export async function fetchAndMaterializeMarketplaceArchive(options = {}) {
237
+ const networkTransport =
238
+ options.offline !== true &&
239
+ typeof options.fetchImpl !== "function" &&
240
+ (options.proxyUrl || options.pacFile || options.caFile)
241
+ ? createMarketplaceNetworkTransport(options)
242
+ : null;
243
+ let artifact;
244
+ try {
245
+ artifact = await fetchMarketplaceRemoteArtifact({
246
+ kind: "archive",
247
+ url: options.url,
248
+ expectedSha256: options.sha256,
249
+ registryOrigin: new URL(options.registryUrl).origin,
250
+ authorizationOrigin: new URL(options.registryUrl).origin,
251
+ token: options.token,
252
+ allowInsecure: options.allowInsecure === true,
253
+ offline: options.offline === true,
254
+ cacheDir: options.artifactCacheDir,
255
+ timeoutMs: options.timeoutMs,
256
+ fetchImpl: options.fetchImpl || networkTransport?.fetch,
257
+ resolveHostname: options.resolveHostname,
258
+ });
259
+ } finally {
260
+ await networkTransport?.close();
261
+ }
262
+ if (artifact.bytes.length > MARKETPLACE_ARCHIVE_LIMITS.compressedBytes) {
263
+ throw new Error("Marketplace archive exceeds its compressed byte limit");
264
+ }
265
+
266
+ const root = cacheRoot(options.sourceCacheDir);
267
+ fs.mkdirSync(root, { recursive: true, mode: 0o700 });
268
+ const rootStat = fs.lstatSync(root);
269
+ if (!rootStat.isDirectory() || rootStat.isSymbolicLink()) {
270
+ throw new Error("Marketplace archive source cache root is unsafe");
271
+ }
272
+ const key = sha256(`${artifact.url}\0${artifact.sha256}`);
273
+ const finalRoot = path.join(root, key);
274
+ const expected = {
275
+ url: artifact.url,
276
+ registryOrigin: new URL(options.registryUrl).origin,
277
+ archiveSha256: artifact.sha256,
278
+ compressedBytes: artifact.bytes.length,
279
+ };
280
+ if (fs.existsSync(finalRoot)) {
281
+ try {
282
+ const cached = readAuthority(finalRoot, expected);
283
+ return {
284
+ dir: cached.packagePath,
285
+ authority: { ...cached.authority, fromCache: artifact.fromCache },
286
+ };
287
+ } catch (error) {
288
+ const stat = fs.lstatSync(finalRoot);
289
+ if (!stat.isDirectory() || stat.isSymbolicLink()) throw error;
290
+ fs.rmSync(finalRoot, { recursive: true, force: true });
291
+ }
292
+ }
293
+
294
+ const temporary = fs.mkdtempSync(path.join(root, `.tmp-${key}-`));
295
+ try {
296
+ const packagePath = path.join(temporary, "package");
297
+ fs.mkdirSync(packagePath, { mode: 0o755 });
298
+ const payload = extractVerifiedTgz(artifact.bytes, packagePath);
299
+ const authority = {
300
+ schemaVersion: MARKETPLACE_ARCHIVE_SOURCE_SCHEMA,
301
+ status: "digest-verified-and-extracted",
302
+ url: artifact.url,
303
+ registryOrigin: new URL(options.registryUrl).origin,
304
+ archiveSha256: artifact.sha256,
305
+ compressedBytes: artifact.bytes.length,
306
+ payloadSha256: payload.digest,
307
+ fileCount: payload.fileCount,
308
+ totalBytes: payload.totalBytes,
309
+ fromCache: artifact.fromCache,
310
+ };
311
+ fs.writeFileSync(
312
+ path.join(temporary, "authority.json"),
313
+ `${JSON.stringify(authority)}\n`,
314
+ { encoding: "utf8", flag: "wx", mode: 0o600 },
315
+ );
316
+ try {
317
+ fs.renameSync(temporary, finalRoot);
318
+ } catch (error) {
319
+ if (!fs.existsSync(finalRoot)) throw error;
320
+ }
321
+ const cached = readAuthority(finalRoot, expected);
322
+ return {
323
+ dir: cached.packagePath,
324
+ authority: { ...cached.authority, fromCache: artifact.fromCache },
325
+ };
326
+ } finally {
327
+ if (fs.existsSync(temporary)) {
328
+ fs.rmSync(temporary, { recursive: true, force: true });
329
+ }
330
+ }
331
+ }
@@ -16,6 +16,7 @@ import {
16
16
  import { describeCapabilities, normalizeCapabilities } from "./capabilities.js";
17
17
  import { normalizePublisherDeclaration } from "./publisher-trust.js";
18
18
  import { normalizeMarketplaceNetworkAuthority } from "./marketplace-network.js";
19
+ import { normalizeMarketplacePackageSource } from "./marketplace-source-adapter.js";
19
20
 
20
21
  export const PLUGIN_MARKETPLACE_CATALOG_SCHEMA =
21
22
  "cc-plugin-marketplace-catalog/v1";
@@ -461,22 +462,50 @@ function normalizeCandidate(entry, context) {
461
462
  ? boundedString(raw.version, 128) || null
462
463
  : null;
463
464
  const description = boundedString(raw.description, 2048);
464
- const sourceValue =
465
- typeof raw.source === "string" ? boundedString(raw.source, 4096) : "";
466
- const sourceUrl = sanitizeUrl(sourceValue) || sourceValue || null;
467
- const ref = boundedString(raw.ref, 256) || null;
468
465
  const blockers = [];
469
466
  const warnings = [];
467
+ let packageSource = null;
468
+ try {
469
+ packageSource = normalizeMarketplacePackageSource(raw);
470
+ } catch (error) {
471
+ blockers.push(issue(error?.code || "INVALID_PACKAGE_SOURCE"));
472
+ }
473
+ if (packageSource?.type === "dynamic-disabled") {
474
+ blockers.push(
475
+ issue("DYNAMIC_SOURCE_DISABLED", packageSource.requestedType),
476
+ );
477
+ }
478
+ const sourceValue =
479
+ packageSource?.type === "archive"
480
+ ? packageSource.url
481
+ : packageSource?.type === "git"
482
+ ? packageSource.source
483
+ : "";
484
+ const sourceUrl = sanitizeUrl(sourceValue) || sourceValue || null;
485
+ const ref = packageSource?.type === "git" ? packageSource.ref : null;
470
486
 
471
487
  if (!rawName || !/^[a-zA-Z0-9._@/-]+$/.test(rawName)) {
472
488
  blockers.push(issue("INVALID_NAME"));
473
489
  }
474
490
  if (!version || !semver.valid(version))
475
491
  blockers.push(issue("INVALID_VERSION"));
476
- if (!sourceValue) blockers.push(issue("MISSING_PACKAGE_SOURCE"));
492
+ if (!sourceValue && packageSource?.type !== "dynamic-disabled") {
493
+ blockers.push(issue("MISSING_PACKAGE_SOURCE"));
494
+ }
477
495
  if (hasUrlCredentials(sourceValue)) {
478
496
  blockers.push(issue("SOURCE_CREDENTIALS_EMBEDDED"));
479
497
  }
498
+ if (packageSource?.type === "archive") {
499
+ try {
500
+ if (
501
+ new URL(packageSource.url).origin !== new URL(context.source.url).origin
502
+ ) {
503
+ blockers.push(issue("ARCHIVE_SOURCE_ORIGIN_MISMATCH"));
504
+ }
505
+ } catch {
506
+ blockers.push(issue("ARCHIVE_SOURCE_ORIGIN_MISMATCH"));
507
+ }
508
+ }
480
509
 
481
510
  const integrity = normalizeIntegrity(raw, blockers, warnings);
482
511
  const license = normalizeLicense(raw.license);
@@ -601,7 +630,24 @@ function normalizeCandidate(entry, context) {
601
630
  ? { networkAuthority: context.source.networkAuthority }
602
631
  : {}),
603
632
  },
604
- package: { source: sourceUrl, ref },
633
+ package:
634
+ packageSource?.type === "archive"
635
+ ? {
636
+ type: "archive",
637
+ source: sourceUrl,
638
+ ref: null,
639
+ archiveSha256: packageSource.sha256,
640
+ format: packageSource.format,
641
+ }
642
+ : packageSource?.type === "dynamic-disabled"
643
+ ? {
644
+ type: "dynamic-disabled",
645
+ source: null,
646
+ ref: null,
647
+ requestedType: packageSource.requestedType,
648
+ enabled: false,
649
+ }
650
+ : { source: sourceUrl, ref },
605
651
  integrity,
606
652
  license,
607
653
  capabilities: {
@@ -21,6 +21,7 @@ export const MAX_MARKETPLACE_ARTIFACT_REDIRECTS = 3;
21
21
  export const DEFAULT_MARKETPLACE_ARTIFACT_TIMEOUT_MS = 15_000;
22
22
  export const MAX_MARKETPLACE_ARTIFACT_URL_LENGTH = 4096;
23
23
  export const MARKETPLACE_REMOTE_ARTIFACT_LIMITS = Object.freeze({
24
+ archive: 64 * 1024 * 1024,
24
25
  signature: 16 * 1024,
25
26
  publicKey: 64 * 1024,
26
27
  sbom: 16 * 1024 * 1024,
@@ -0,0 +1,163 @@
1
+ const SHA256_RE = /^[a-f0-9]{64}$/u;
2
+ const DYNAMIC_SOURCE_TYPES = new Set([
3
+ "command",
4
+ "headers-helper",
5
+ "headershelper",
6
+ ]);
7
+
8
+ export const MARKETPLACE_DYNAMIC_SOURCE_DISABLED_CODE =
9
+ "CC_MARKETPLACE_DYNAMIC_SOURCE_DISABLED";
10
+
11
+ function sourceError(code, message) {
12
+ const error = new Error(message);
13
+ error.code = code;
14
+ return error;
15
+ }
16
+
17
+ function bounded(value, max) {
18
+ const text = typeof value === "string" ? value.trim() : "";
19
+ return text.length > 0 && text.length <= max ? text : null;
20
+ }
21
+
22
+ function safeUrl(value, label) {
23
+ const raw = bounded(value, 4096);
24
+ if (!raw) throw sourceError("INVALID_SOURCE_URL", `${label} URL is missing`);
25
+ let url;
26
+ try {
27
+ url = new URL(raw);
28
+ } catch {
29
+ throw sourceError("INVALID_SOURCE_URL", `${label} URL is invalid`);
30
+ }
31
+ if (url.username || url.password) {
32
+ throw sourceError(
33
+ "SOURCE_CREDENTIALS_REJECTED",
34
+ `${label} URL must not contain credentials`,
35
+ );
36
+ }
37
+ if (!new Set(["https:", "http:"]).has(url.protocol)) {
38
+ throw sourceError(
39
+ "INVALID_SOURCE_URL",
40
+ `${label} URL must use HTTPS or loopback HTTP`,
41
+ );
42
+ }
43
+ const requestUrl = url.href;
44
+ url.search = "";
45
+ url.hash = "";
46
+ return { url: url.href, requestUrl };
47
+ }
48
+
49
+ function disabledDynamicSource(type) {
50
+ return Object.freeze({
51
+ type: "dynamic-disabled",
52
+ requestedType: type,
53
+ enabled: false,
54
+ code: MARKETPLACE_DYNAMIC_SOURCE_DISABLED_CODE,
55
+ reason:
56
+ "dynamic Marketplace source/auth adapters are disabled by product policy",
57
+ });
58
+ }
59
+
60
+ /**
61
+ * Normalize one registry package source without executing it. Git strings keep
62
+ * the legacy shape. Archive sources require an HTTPS URL and exact compressed
63
+ * byte digest. Dynamic command/helper adapters remain representable for UI
64
+ * diagnostics but can never become executable materialization authority.
65
+ */
66
+ export function normalizeMarketplacePackageSource(entry, options = {}) {
67
+ const row = entry && typeof entry === "object" ? entry : {};
68
+ if (row.command != null || row.headersHelper != null) {
69
+ const disabled = disabledDynamicSource(
70
+ row.command != null ? "command" : "headers-helper",
71
+ );
72
+ if (options.forExecution === true) {
73
+ throw sourceError(disabled.code, disabled.reason);
74
+ }
75
+ return disabled;
76
+ }
77
+
78
+ const source = row.source;
79
+ if (typeof source === "string") {
80
+ const value = bounded(source, 4096);
81
+ if (!value) {
82
+ throw sourceError("MISSING_PACKAGE_SOURCE", "plugin source is missing");
83
+ }
84
+ return Object.freeze({
85
+ type: "git",
86
+ source: value,
87
+ ref: bounded(row.ref, 256),
88
+ });
89
+ }
90
+ if (!source || typeof source !== "object" || Array.isArray(source)) {
91
+ throw sourceError("MISSING_PACKAGE_SOURCE", "plugin source is missing");
92
+ }
93
+ if (source.command != null || source.headersHelper != null) {
94
+ const disabled = disabledDynamicSource(
95
+ source.command != null ? "command" : "headers-helper",
96
+ );
97
+ if (options.forExecution === true) {
98
+ throw sourceError(disabled.code, disabled.reason);
99
+ }
100
+ return disabled;
101
+ }
102
+
103
+ const type = String(source.type || "")
104
+ .trim()
105
+ .toLowerCase();
106
+ if (DYNAMIC_SOURCE_TYPES.has(type)) {
107
+ const disabled = disabledDynamicSource(type);
108
+ if (options.forExecution === true) {
109
+ throw sourceError(disabled.code, disabled.reason);
110
+ }
111
+ return disabled;
112
+ }
113
+ if (type === "git") {
114
+ const value = bounded(source.url ?? source.source, 4096);
115
+ if (!value) {
116
+ throw sourceError("MISSING_PACKAGE_SOURCE", "git source URL is missing");
117
+ }
118
+ return Object.freeze({
119
+ type: "git",
120
+ source: value,
121
+ ref: bounded(source.ref ?? row.ref, 256),
122
+ });
123
+ }
124
+ if (type !== "archive") {
125
+ throw sourceError(
126
+ "UNSUPPORTED_PACKAGE_SOURCE",
127
+ `unsupported Marketplace source type: ${type || "unknown"}`,
128
+ );
129
+ }
130
+
131
+ const archiveUrl = safeUrl(source.url, "archive source");
132
+ const sha256 = String(source.sha256 || "")
133
+ .trim()
134
+ .toLowerCase();
135
+ if (!SHA256_RE.test(sha256)) {
136
+ throw sourceError(
137
+ "ARCHIVE_DIGEST_REQUIRED",
138
+ "archive source requires a 64-character lowercase SHA-256 digest",
139
+ );
140
+ }
141
+ const format = String(source.format || "tgz").toLowerCase();
142
+ if (!new Set(["tgz", "tar.gz"]).has(format)) {
143
+ throw sourceError(
144
+ "ARCHIVE_FORMAT_UNSUPPORTED",
145
+ "archive source format must be tgz or tar.gz",
146
+ );
147
+ }
148
+ const normalized = {
149
+ type: "archive",
150
+ url: archiveUrl.url,
151
+ sha256,
152
+ format: "tgz",
153
+ };
154
+ Object.defineProperty(normalized, "requestUrl", {
155
+ value: archiveUrl.requestUrl,
156
+ enumerable: false,
157
+ });
158
+ return Object.freeze(normalized);
159
+ }
160
+
161
+ export function assertMarketplaceSourceExecutable(entry) {
162
+ return normalizeMarketplacePackageSource(entry, { forExecution: true });
163
+ }
@@ -29,6 +29,9 @@ export function marketplaceSourceCacheSpec(
29
29
  if (sourceMetadata?.type !== "registry") return null;
30
30
  const source = cleanString(sourceMetadata.resolvedSource, 4096);
31
31
  const ref = cleanString(sourceMetadata.ref, 256);
32
+ const sourceDigest =
33
+ normalizeSha256(sourceMetadata.resolvedSourceDigest) ||
34
+ (source ? sha256Canonical({ source, ref }) : null);
32
35
  const expectations = sourceMetadata.catalogAuthority?.artifactExpectations;
33
36
  const manifestSha256 = normalizeSha256(expectations?.manifest?.sha256);
34
37
  let payloadSchemaVersion = cleanString(expectations?.sbom?.format, 128);
@@ -57,6 +60,7 @@ export function marketplaceSourceCacheSpec(
57
60
  }
58
61
  if (
59
62
  !source ||
63
+ !sourceDigest ||
60
64
  !manifestSha256 ||
61
65
  !payloadSha256 ||
62
66
  !isMarketplacePayloadSbomFormat(payloadSchemaVersion)
@@ -66,6 +70,7 @@ export function marketplaceSourceCacheSpec(
66
70
  const keyAuthority = {
67
71
  schemaVersion: PLUGIN_MARKETPLACE_SOURCE_CACHE_SCHEMA,
68
72
  source,
73
+ sourceDigest,
69
74
  ref,
70
75
  manifestSha256,
71
76
  payload: {
@@ -180,6 +185,7 @@ function buildCacheAuthority(payload, spec) {
180
185
  schemaVersion: PLUGIN_MARKETPLACE_SOURCE_CACHE_SCHEMA,
181
186
  cacheKey: spec.cacheKey,
182
187
  source: spec.source,
188
+ sourceDigest: spec.sourceDigest,
183
189
  ref: spec.ref,
184
190
  manifestSha256,
185
191
  payload: {
@@ -279,7 +285,11 @@ function readAuthority(file) {
279
285
  } catch {
280
286
  throw new Error("Marketplace source cache authority is not valid UTF-8");
281
287
  }
282
- return JSON.parse(text);
288
+ try {
289
+ return JSON.parse(text);
290
+ } catch {
291
+ throw new Error("Marketplace source cache authority is invalid JSON");
292
+ }
283
293
  } finally {
284
294
  if (descriptor != null) fs.closeSync(descriptor);
285
295
  }