chainlesschain 0.162.181 → 0.162.183

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 (195) hide show
  1. package/package.json +2 -1
  2. package/scripts/build-windows-sandbox-helper.ps1 +163 -0
  3. package/src/assets/web-panel/assets/{AIOps-cq0dwbnf.js → AIOps-BapS7lz4.js} +1 -1
  4. package/src/assets/web-panel/assets/{ActionButton-CvcgGl3w.js → ActionButton-CXYdXEUI.js} +1 -1
  5. package/src/assets/web-panel/assets/{Analytics-hM2-jFqg.js → Analytics-CKR5Lexn.js} +3 -3
  6. package/src/assets/web-panel/assets/{AppLayout-B9_Gsd_g.js → AppLayout-DATVUOXB.js} +5 -5
  7. package/src/assets/web-panel/assets/{Artifacts-B7bu52Og.js → Artifacts-vb_0ZlV1.js} +1 -1
  8. package/src/assets/web-panel/assets/{Audit-DThfDgqB.js → Audit-BI1l9GWt.js} +1 -1
  9. package/src/assets/web-panel/assets/{BackgroundAgents-DjlFiD4v.js → BackgroundAgents-BFXbaUEf.js} +1 -1
  10. package/src/assets/web-panel/assets/{Backup-CK9xJKnG.js → Backup-DEYBJJ6H.js} +1 -1
  11. package/src/assets/web-panel/assets/{BaseInput-DEiSU8K8.js → BaseInput-COdzeO0M.js} +1 -1
  12. package/src/assets/web-panel/assets/{Chat-CpT96czj.js → Chat-oSN6sfM5.js} +6 -6
  13. package/src/assets/web-panel/assets/ChatBubbleRenderer-CI_jT0ru.js +1 -0
  14. package/src/assets/web-panel/assets/{Checkbox-C1GfDnO0.js → Checkbox-BezEa4tm.js} +1 -1
  15. package/src/assets/web-panel/assets/{Codegen-3DAKgiLx.js → Codegen-CNEL0Ife.js} +1 -1
  16. package/src/assets/web-panel/assets/{Col-74cOwZU1.js → Col-Bf2Y2Bn1.js} +1 -1
  17. package/src/assets/web-panel/assets/{Community-tn9Kkz9j.js → Community-BfUlu4Hc.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compact-BcoXH7m4.js → Compact-BN4xWP9e.js} +1 -1
  19. package/src/assets/web-panel/assets/{Compliance-DIPGUBgi.js → Compliance-Bt6BKmEP.js} +1 -1
  20. package/src/assets/web-panel/assets/{Cowork-doD5_91c.js → Cowork-DKLp8YxO.js} +2 -2
  21. package/src/assets/web-panel/assets/{Cron-C-IDvubz.js → Cron-o7Hhw6ky.js} +2 -2
  22. package/src/assets/web-panel/assets/{Crosschain-CdcCoBdj.js → Crosschain-DaNXWJIw.js} +1 -1
  23. package/src/assets/web-panel/assets/{DID-DdH5aMMA.js → DID-B-Qa2mha.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dashboard-DHLA4mm0.js → Dashboard-CMX0Qnxw.js} +2 -2
  25. package/src/assets/web-panel/assets/{Dropdown-dEeCt7Md.js → Dropdown-BLuLyRu_.js} +1 -1
  26. package/src/assets/web-panel/assets/{EmailListRenderer-BMaecFv9.js → EmailListRenderer-CFBAeMij.js} +1 -1
  27. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DUaUukTN.js → FamilyGuardDashboard-DWzXQ67V.js} +1 -1
  28. package/src/assets/web-panel/assets/{Federation-CMBE0_rp.js → Federation-DB1QSLgr.js} +1 -1
  29. package/src/assets/web-panel/assets/{FormItemContext-PG-JDbXq.js → FormItemContext-C-OKCToP.js} +1 -1
  30. package/src/assets/web-panel/assets/{GenericCardRenderer-Bcb0p88m.js → GenericCardRenderer-DMJFtFZf.js} +1 -1
  31. package/src/assets/web-panel/assets/{Git-Bgv15myB.js → Git-DsGSujOV.js} +2 -2
  32. package/src/assets/web-panel/assets/{Governance-DB8YTArI.js → Governance-B0iS9NEW.js} +1 -1
  33. package/src/assets/web-panel/assets/{Inference-BQMwCWaS.js → Inference-CH004H7c.js} +1 -1
  34. package/src/assets/web-panel/assets/{KnowledgeGraph-B1_ZziiB.js → KnowledgeGraph-Q9MTQ83c.js} +1 -1
  35. package/src/assets/web-panel/assets/{Logs-DovEEnt_.js → Logs-B_fyjZK9.js} +2 -2
  36. package/src/assets/web-panel/assets/{MarkdownRenderer-D201OL4T.js → MarkdownRenderer-C0o4FtpD.js} +1 -1
  37. package/src/assets/web-panel/assets/{Marketplace-BlCXSpyB.js → Marketplace-BIStF9d1.js} +1 -1
  38. package/src/assets/web-panel/assets/{McpTools-CsCR09Wj.js → McpTools-pGfal768.js} +5 -5
  39. package/src/assets/web-panel/assets/{Memory-CBVRLKno.js → Memory-xbNqpIqB.js} +2 -2
  40. package/src/assets/web-panel/assets/{MobileBridge-C9OIafgA.js → MobileBridge-B5EQGrIK.js} +1 -1
  41. package/src/assets/web-panel/assets/MobileProjects-VTc3gT1y.js +1 -0
  42. package/src/assets/web-panel/assets/{Mtc-vE-HdvLj.js → Mtc-a_rmfxJH.js} +4 -4
  43. package/src/assets/web-panel/assets/{MtcAudit-CPLaekCd.js → MtcAudit-BmKuofUr.js} +4 -4
  44. package/src/assets/web-panel/assets/{Multisig-C_UP9C2o.js → Multisig-BQbJ-CAN.js} +3 -3
  45. package/src/assets/web-panel/assets/{NLProgramming-2nODJcU1.js → NLProgramming-JtPJKX25.js} +1 -1
  46. package/src/assets/web-panel/assets/{Notes-BhE-SJGu.js → Notes-ZFKznTSG.js} +3 -3
  47. package/src/assets/web-panel/assets/{NotificationSettings-D21q7BNU.js → NotificationSettings-B6aHRBBR.js} +1 -1
  48. package/src/assets/web-panel/assets/{OrderTableRenderer-0b62GYOD.js → OrderTableRenderer-DdcsOqEz.js} +1 -1
  49. package/src/assets/web-panel/assets/{Organization-CEqmw_sb.js → Organization-BFDTAUgS.js} +4 -4
  50. package/src/assets/web-panel/assets/{Overflow-MW-gMDO_.js → Overflow-0FoTfbWH.js} +1 -1
  51. package/src/assets/web-panel/assets/{P2P-CY0hjI_G.js → P2P-CWd90etw.js} +2 -2
  52. package/src/assets/web-panel/assets/{PdhVaultBrowser-BbWh7Man.js → PdhVaultBrowser-DtCGC-W-.js} +3 -3
  53. package/src/assets/web-panel/assets/{Permissions-ChqEA_4Q.js → Permissions-CvQ7nr7T.js} +4 -4
  54. package/src/assets/web-panel/assets/{PersonalDataHub-B3YrbYfD.js → PersonalDataHub-rdNPcR-Z.js} +5 -5
  55. package/src/assets/web-panel/assets/{Pipeline-B8WBhhlW.js → Pipeline-CmrfiNOs.js} +1 -1
  56. package/src/assets/web-panel/assets/{Privacy-Cmb0PXNx.js → Privacy-D7ep1h_t.js} +1 -1
  57. package/src/assets/web-panel/assets/{ProjectInit-hF6zW3Nz.js → ProjectInit-C0xKINHS.js} +2 -2
  58. package/src/assets/web-panel/assets/{ProjectSettings-BFSVfpW0.js → ProjectSettings-AOmZFp-F.js} +2 -2
  59. package/src/assets/web-panel/assets/Projects-BWHSkXZP.js +1 -0
  60. package/src/assets/web-panel/assets/{Providers-B8yux8Dx.js → Providers-Cb7JCTPL.js} +1 -1
  61. package/src/assets/web-panel/assets/{QrScannerModal-N76cQluO.js → QrScannerModal-BDMehcXC.js} +1 -1
  62. package/src/assets/web-panel/assets/{QuickAsk-ClvZ0KYR.js → QuickAsk-BF6_1nvx.js} +1 -1
  63. package/src/assets/web-panel/assets/{Recommend-B-GfgBpT.js → Recommend-BHfT-A28.js} +1 -1
  64. package/src/assets/web-panel/assets/RemoteSession-B6EEf8hh.js +5 -0
  65. package/src/assets/web-panel/assets/{Reputation-DJIZzQeG.js → Reputation-CsWHLEcj.js} +1 -1
  66. package/src/assets/web-panel/assets/{Row-COzxu_bb.js → Row-D6srnWhm.js} +1 -1
  67. package/src/assets/web-panel/assets/{RssFeed-CoYsJQuE.js → RssFeed-Xhr-KyVd.js} +3 -3
  68. package/src/assets/web-panel/assets/{Search-DC77Mq9S.js → Search-vIbIJvwL.js} +1 -1
  69. package/src/assets/web-panel/assets/{Security-Loy2EdMO.js → Security-Bzi5Aiko.js} +4 -4
  70. package/src/assets/web-panel/assets/{Services-GUD07Eu0.js → Services-BHtVX52P.js} +2 -2
  71. package/src/assets/web-panel/assets/{Skeleton-DWzkptYU.js → Skeleton-C0R8B2jf.js} +1 -1
  72. package/src/assets/web-panel/assets/{Skills-CEDn1r-Z.js → Skills-DtT6rWOX.js} +1 -1
  73. package/src/assets/web-panel/assets/{Sla-ub_k4pXh.js → Sla-0B37mxVU.js} +1 -1
  74. package/src/assets/web-panel/assets/{SpeechSettings-D7HLX9CA.js → SpeechSettings-0V2jE1Bs.js} +1 -1
  75. package/src/assets/web-panel/assets/{SyncSettings-DbwOvl6m.js → SyncSettings-CYedRzaj.js} +2 -2
  76. package/src/assets/web-panel/assets/Tasks-D-R1x8vm.js +1 -0
  77. package/src/assets/web-panel/assets/{Templates-BNVeIhud.js → Templates-BKoHztGT.js} +1 -1
  78. package/src/assets/web-panel/assets/{Tenant-PS9AzhXU.js → Tenant--17nwVNZ.js} +1 -1
  79. package/src/assets/web-panel/assets/{Terminal-Cgb4eLB_.js → Terminal-Dnkos7vW.js} +2 -2
  80. package/src/assets/web-panel/assets/{TimelineRenderer-CrmXMOkg.js → TimelineRenderer-C5jx4AE3.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tokens-DD-VDHw1.js → Tokens-DYJKYa9t.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trigger-BsoN_n-n.js → Trigger-DChpWiQ9.js} +1 -1
  83. package/src/assets/web-panel/assets/{Trust-n8LmN4ZV.js → Trust-DfWG52EA.js} +1 -1
  84. package/src/assets/web-panel/assets/{UkeySign-C9_7MImA.js → UkeySign-CMugYcyA.js} +1 -1
  85. package/src/assets/web-panel/assets/{VideoEditing-DyBteNgn.js → VideoEditing-BOSmrHAd.js} +1 -1
  86. package/src/assets/web-panel/assets/{Wallet-BS5ixeXI.js → Wallet-D5g3k3Sa.js} +4 -4
  87. package/src/assets/web-panel/assets/{WebAuthn-spc4UImU.js → WebAuthn-D-7u4Mkc.js} +3 -3
  88. package/src/assets/web-panel/assets/{WorkflowEditor-D7iVvaBO.js → WorkflowEditor-CFzZMSUJ.js} +1 -1
  89. package/src/assets/web-panel/assets/{chat-6CmBkHrL.js → chat-VbR6l6mc.js} +1 -1
  90. package/src/assets/web-panel/assets/{colors-BGoCLkxI.js → colors-BSZn8EDS.js} +1 -1
  91. package/src/assets/web-panel/assets/{compact-item-fYZBetMO.js → compact-item-y74obMEq.js} +1 -1
  92. package/src/assets/web-panel/assets/{createContext-BeM-1UVj.js → createContext-C326bjex.js} +1 -1
  93. package/src/assets/web-panel/assets/devWarning-D3Bho_6u.js +1 -0
  94. package/src/assets/web-panel/assets/{hasIn-CE7ZuEnV.js → hasIn-D_INJQT_.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-ukg99D1V.js → index-4PIeTM--.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-B2U-ObMq.js → index-4eyH-eC2.js} +1 -1
  97. package/src/assets/web-panel/assets/index-5iAFwYx1.js +1 -0
  98. package/src/assets/web-panel/assets/{index-CRLjEP1H.js → index-9PIVuXqo.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BfPL-m46.js → index-B7SrC-On.js} +1 -1
  100. package/src/assets/web-panel/assets/{index--lap6cf7.js → index-BJi3UqBt.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-B3CDgvNW.js → index-BY8-nCgs.js} +1 -1
  102. package/src/assets/web-panel/assets/index-BfnB7LPx.js +1 -0
  103. package/src/assets/web-panel/assets/{index-De0quFDw.js → index-Bfw2hf2s.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-BunaQCa0.js → index-BjcWKg1S.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-BsMfoaeo.js → index-BnSfnSMP.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-C0v6YKKO.js → index-Bnua8IX3.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-C4SJVjs4.js → index-C-ZCaUJc.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-BNZDILcO.js → index-C2NyllnW.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-YjcumOZ4.js → index-C327pLbw.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-CRnUE8Cb.js → index-CMHqs3Jb.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-CIpVrf5P.js → index-CfLJ42kv.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-BEVm0lCS.js → index-Cr3uuz0C.js} +3 -3
  113. package/src/assets/web-panel/assets/{index-Dw1PyYPm.js → index-CsovTpx9.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-lJBjB1QX.js → index-CzE53HiB.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-CpIGIB85.js → index-DBkzrpiL.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-DoXk5KJ8.js → index-DNMxIsDg.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DsvfrESp.js → index-DUU2606o.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-Cip8emOQ.js → index-DdyjrCAu.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-ATcSr_2O.js → index-DkH1JvEt.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-BV551878.js → index-Dlxh9D8D.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-BU_2qiDk.js → index-DuIkfnTF.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-zb7rVOhV.js → index-DwHSZLXg.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-MtOuq2i6.js → index-E_v1ZCTP.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-B8BsdNV_.js → index-FQBsuExX.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-WUrJ6S1j.js → index-GA80ir_u.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-RMZ8a7Yt.js → index-IZAWt0H8.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-D1r9tT3J.js → index-Iw0FfqUz.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-BowH1eLQ.js → index-KF9Zmqln.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-Puq6Luf1.js → index-abmn_8Yz.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-QIpnpZgz.js → index-gINyI1rh.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-C9Y3k0HI.js → index-jYaogFE8.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-B4wiTEOM.js → index-nSn2-C4N.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-DT3zPSVX.js → index-qMA4GYdQ.js} +1 -1
  134. package/src/assets/web-panel/assets/{initDefaultProps-CYHMs1ag.js → initDefaultProps-DI0Zaf8-.js} +1 -1
  135. package/src/assets/web-panel/assets/{motion-DDB2Ffk5.js → motion-BZDKSy3Z.js} +1 -1
  136. package/src/assets/web-panel/assets/{move-Bg3cD-dX.js → move-DsIW01Vp.js} +1 -1
  137. package/src/assets/web-panel/assets/{mtc-parser-B5nedjTS.js → mtc-parser-CohkDhsf.js} +1 -1
  138. package/src/assets/web-panel/assets/{omit-BHyuUILu.js → omit-DpiN5rzg.js} +1 -1
  139. package/src/assets/web-panel/assets/{pickAttrs-C9YQnEN9.js → pickAttrs-qbuqni3y.js} +1 -1
  140. package/src/assets/web-panel/assets/{placementArrow-DBUFYUe7.js → placementArrow-mBky6714.js} +1 -1
  141. package/src/assets/web-panel/assets/{responsiveObserve-nBs2Obnk.js → responsiveObserve-Bas3eQ2K.js} +1 -1
  142. package/src/assets/web-panel/assets/{slide-DkCEaXNU.js → slide-CBx_SKoK.js} +1 -1
  143. package/src/assets/web-panel/assets/{statusUtils-aqE1Wi6U.js → statusUtils-BlYguJSV.js} +1 -1
  144. package/src/assets/web-panel/assets/{styleChecker-CN5bhfHB.js → styleChecker-BCYQmRGv.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFlexGapSupport-B_oX_kvJ.js → useFlexGapSupport-Dp5dybLM.js} +1 -1
  146. package/src/assets/web-panel/assets/{useFs-rCuXHeme.js → useFs-DHAMBgA2.js} +1 -1
  147. package/src/assets/web-panel/assets/{usePersonalDataHub-DZR9Abyd.js → usePersonalDataHub-W6jsSw76.js} +1 -1
  148. package/src/assets/web-panel/assets/{vnode-ConCYQlX.js → vnode-BkI6aayc.js} +1 -1
  149. package/src/assets/web-panel/assets/{zoom-CUdDxG5M.js → zoom-C_IMGueq.js} +1 -1
  150. package/src/assets/web-panel/index.html +1 -1
  151. package/src/commands/agenda.js +115 -3
  152. package/src/commands/agent.js +15 -0
  153. package/src/commands/background-session.js +49 -0
  154. package/src/commands/plugin.js +235 -23
  155. package/src/commands/session.js +13 -0
  156. package/src/data/changelog.json +26 -0
  157. package/src/gateways/terminal/PtyManager.js +45 -4
  158. package/src/gateways/ws/ws-server.js +10 -1
  159. package/src/harness/background-task-manager.js +70 -2
  160. package/src/harness/jsonl-session-store.js +6 -4
  161. package/src/harness/worktree-isolator.js +14 -3
  162. package/src/lib/agent-core.js +1 -0
  163. package/src/lib/agent-schedule-store.js +45 -22
  164. package/src/lib/agent-team/team-runner.js +19 -1
  165. package/src/lib/background-agent-supervisor.js +49 -0
  166. package/src/lib/hook-runner.js +6 -2
  167. package/src/lib/packer/pkg-config-generator.js +3 -1
  168. package/src/lib/plugin-runtime/bin.js +1148 -70
  169. package/src/lib/plugin-runtime/install.js +226 -7
  170. package/src/lib/plugin-runtime/manifest.js +68 -12
  171. package/src/lib/plugin-runtime/scopes.js +33 -12
  172. package/src/lib/plugin-usage-attribution.js +44 -0
  173. package/src/lib/process-execution-broker/index.js +626 -48
  174. package/src/lib/process-execution-broker/platform-sandbox.js +4971 -266
  175. package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
  176. package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
  177. package/src/lib/process-execution-broker/windows-sandbox.cs +3856 -0
  178. package/src/lib/repl-bang-memorize.js +67 -10
  179. package/src/lib/session-usage.js +77 -0
  180. package/src/lib/slash-commands.js +27 -4
  181. package/src/repl/agent-repl.js +10 -9
  182. package/src/runtime/agent-core.js +376 -52
  183. package/src/runtime/agent-runtime.js +13 -1
  184. package/src/runtime/headless-runner.js +13 -4
  185. package/src/runtime/headless-stream.js +20 -1
  186. package/src/runtime/mcp-config.js +15 -5
  187. package/src/assets/web-panel/assets/ChatBubbleRenderer-BKPPNmZI.js +0 -1
  188. package/src/assets/web-panel/assets/MobileProjects-D_zoJ8Xs.js +0 -1
  189. package/src/assets/web-panel/assets/Projects-DAWkVFkc.js +0 -1
  190. package/src/assets/web-panel/assets/RemoteSession-mlglCdQi.js +0 -5
  191. package/src/assets/web-panel/assets/Tasks-CBQzoAu5.js +0 -1
  192. package/src/assets/web-panel/assets/devWarning-BzPwHnw8.js +0 -1
  193. package/src/assets/web-panel/assets/index-DacrAdc-.js +0 -1
  194. package/src/assets/web-panel/assets/index-EHzNJozo.js +0 -1
  195. package/src/lib/process-execution-broker/windows-sandbox.ps1 +0 -999
@@ -38,6 +38,7 @@ import {
38
38
  postSpawnSandbox as _postSpawnSandbox,
39
39
  SANDBOX_BOUNDARIES,
40
40
  } from "./platform-sandbox.js";
41
+ import { consumeIssuedPluginSandboxExecutionContract } from "../plugin-runtime/bin.js";
41
42
  import { credentialAgent } from "./credential-agent.js";
42
43
 
43
44
  const SUPPORTED_SANDBOX_BOUNDARIES = new Set(Object.values(SANDBOX_BOUNDARIES));
@@ -197,6 +198,222 @@ class ProcessExecutionBroker extends EventEmitter {
197
198
  return safe;
198
199
  }
199
200
 
201
+ _normalizePluginExecutableIdentity(raw) {
202
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
203
+ const realPath =
204
+ typeof raw.realPath === "string" && raw.realPath ? raw.realPath : null;
205
+ const sha256 =
206
+ typeof raw.sha256 === "string" && /^[a-f0-9]{64}$/i.test(raw.sha256)
207
+ ? raw.sha256.toLowerCase()
208
+ : null;
209
+ if (!realPath || !sha256) return null;
210
+ return {
211
+ contractVersion: 1,
212
+ realPath,
213
+ sha256,
214
+ bytes:
215
+ Number.isSafeInteger(raw.bytes) && raw.bytes >= 0 ? raw.bytes : null,
216
+ fileId:
217
+ raw.dev !== undefined && raw.ino !== undefined
218
+ ? {
219
+ dev: String(raw.dev),
220
+ ino: String(raw.ino),
221
+ }
222
+ : null,
223
+ mtimeMs: Number.isFinite(raw.mtimeMs) ? raw.mtimeMs : null,
224
+ attestation: "realpath-file-id-sha256",
225
+ };
226
+ }
227
+
228
+ _freezeExecutableIdentity(identity) {
229
+ if (!identity) return null;
230
+ return Object.freeze({
231
+ ...identity,
232
+ fileId: identity.fileId ? Object.freeze({ ...identity.fileId }) : null,
233
+ });
234
+ }
235
+
236
+ _normalizePluginRootIdentity(raw) {
237
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
238
+ if (
239
+ typeof raw.realPath !== "string" ||
240
+ !raw.realPath ||
241
+ raw.dev === undefined ||
242
+ raw.ino === undefined
243
+ ) {
244
+ return null;
245
+ }
246
+ return Object.freeze({
247
+ realPath: raw.realPath,
248
+ fileId: Object.freeze({
249
+ dev: String(raw.dev),
250
+ ino: String(raw.ino),
251
+ }),
252
+ attestation: "realpath-directory-file-id",
253
+ });
254
+ }
255
+
256
+ /**
257
+ * Normalize the private execution contract produced by agent-core for one
258
+ * direct, already-attested strict Plugin Node or static-native bin. Plugin
259
+ * manifests cannot provide this top-level option; they can only add
260
+ * required boundaries.
261
+ */
262
+ _normalizeSandboxExecutionContract(raw, options, requiredBoundaries, launch) {
263
+ if (raw === undefined) return null;
264
+ const invalid = (message) => {
265
+ throw this._sandboxBoundaryError(
266
+ "invalid_sandbox_execution_contract",
267
+ message,
268
+ {
269
+ requiredBoundaries,
270
+ missingBoundaries: requiredBoundaries,
271
+ },
272
+ );
273
+ };
274
+ if (
275
+ !consumeIssuedPluginSandboxExecutionContract(raw, {
276
+ origin: options.origin,
277
+ command: launch?.command,
278
+ args: launch?.args,
279
+ cwd: options.cwd,
280
+ pluginId: options.pluginId,
281
+ pluginVersion: options.pluginVersion,
282
+ pluginSource: options.pluginSource,
283
+ pluginExecutableIdentity: options.pluginExecutableIdentity,
284
+ requiredBoundaries,
285
+ sync: launch?.sync === true,
286
+ })
287
+ ) {
288
+ return invalid(
289
+ "sandboxExecutionContract was not issued for this plugin launch provenance",
290
+ );
291
+ }
292
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
293
+ return invalid("sandboxExecutionContract must be an object");
294
+ }
295
+ const supportedKeys = new Set([
296
+ "contractVersion",
297
+ "kind",
298
+ "pluginRoot",
299
+ "workingDirectory",
300
+ "runtimePath",
301
+ "rootIdentity",
302
+ "entryIdentity",
303
+ "runtimeIdentity",
304
+ ]);
305
+ const unsupportedKey = Object.keys(raw).find(
306
+ (key) => !supportedKeys.has(key),
307
+ );
308
+ if (unsupportedKey) {
309
+ return invalid(
310
+ `sandboxExecutionContract contains unsupported field: ${unsupportedKey}`,
311
+ );
312
+ }
313
+ if (
314
+ raw.contractVersion !== 1 ||
315
+ ![
316
+ "strict-plugin-node-bin",
317
+ "strict-plugin-native-static-elf-bin",
318
+ ].includes(raw.kind)
319
+ ) {
320
+ return invalid("unsupported sandboxExecutionContract kind or version");
321
+ }
322
+ if (
323
+ options.origin !== "plugin:bin" ||
324
+ typeof options.pluginId !== "string" ||
325
+ !options.pluginId ||
326
+ options.shell !== false
327
+ ) {
328
+ return invalid(
329
+ "sandboxExecutionContract is restricted to direct plugin:bin shell:false launches",
330
+ );
331
+ }
332
+
333
+ for (const [label, value] of [
334
+ ["pluginRoot", raw.pluginRoot],
335
+ ["workingDirectory", raw.workingDirectory],
336
+ ["runtimePath", raw.runtimePath],
337
+ ]) {
338
+ if (
339
+ typeof value !== "string" ||
340
+ !value ||
341
+ value.includes("\0") ||
342
+ !path.isAbsolute(value)
343
+ ) {
344
+ return invalid(`sandboxExecutionContract.${label} must be absolute`);
345
+ }
346
+ }
347
+ const entryIdentity = this._normalizePluginExecutableIdentity(
348
+ raw.entryIdentity,
349
+ );
350
+ const runtimeIdentity = this._normalizePluginExecutableIdentity(
351
+ raw.runtimeIdentity,
352
+ );
353
+ const rootIdentity = this._normalizePluginRootIdentity(raw.rootIdentity);
354
+ if (!rootIdentity || !entryIdentity || !runtimeIdentity) {
355
+ return invalid(
356
+ "sandboxExecutionContract requires attested root, entry, and runtime identities",
357
+ );
358
+ }
359
+ if (
360
+ rootIdentity.realPath !== raw.pluginRoot ||
361
+ raw.runtimeIdentity?.requestedPath !== path.resolve(process.execPath) ||
362
+ raw.runtimePath !== runtimeIdentity.realPath ||
363
+ !path.isAbsolute(entryIdentity.realPath) ||
364
+ !path.isAbsolute(runtimeIdentity.realPath)
365
+ ) {
366
+ return invalid(
367
+ "sandboxExecutionContract identity paths do not match the launch contract",
368
+ );
369
+ }
370
+
371
+ const provenanceIdentity = this._normalizePluginExecutableIdentity(
372
+ options.pluginExecutableIdentity,
373
+ );
374
+ if (
375
+ !provenanceIdentity ||
376
+ provenanceIdentity.realPath !== entryIdentity.realPath ||
377
+ provenanceIdentity.sha256 !== entryIdentity.sha256
378
+ ) {
379
+ return invalid(
380
+ "sandboxExecutionContract entry identity does not match plugin provenance",
381
+ );
382
+ }
383
+ const entryRelative = path.relative(
384
+ path.resolve(raw.pluginRoot),
385
+ path.resolve(entryIdentity.realPath),
386
+ );
387
+ if (
388
+ entryRelative === "" ||
389
+ entryRelative === ".." ||
390
+ entryRelative.startsWith(`..${path.sep}`) ||
391
+ path.isAbsolute(entryRelative)
392
+ ) {
393
+ return invalid(
394
+ "sandboxExecutionContract entry must be inside pluginRoot",
395
+ );
396
+ }
397
+
398
+ return Object.freeze({
399
+ contractVersion: 1,
400
+ kind: raw.kind,
401
+ pluginRoot: raw.pluginRoot,
402
+ workingDirectory: raw.workingDirectory,
403
+ runtimePath: raw.runtimePath,
404
+ rootIdentity,
405
+ entryIdentity: this._freezeExecutableIdentity(entryIdentity),
406
+ runtimeIdentity: this._freezeExecutableIdentity(runtimeIdentity),
407
+ });
408
+ }
409
+
410
+ _stripPluginControlOptions(options) {
411
+ delete options.pluginId;
412
+ delete options.pluginVersion;
413
+ delete options.pluginSource;
414
+ delete options.pluginExecutableIdentity;
415
+ }
416
+
200
417
  _sandboxStrictEnabled() {
201
418
  return process.env.CC_SANDBOX_STRICT === "1";
202
419
  }
@@ -213,7 +430,7 @@ class ProcessExecutionBroker extends EventEmitter {
213
430
  * @param {Object} options
214
431
  * @returns {{profile: "default"|"strict"|"network-only"|null, requiredBoundaries: string[]}}
215
432
  */
216
- _normalizeSandboxPolicy(options = {}) {
433
+ _normalizeSandboxPolicy(options = {}, launch = {}) {
217
434
  const rawPolicy = options.sandboxPolicy;
218
435
  if (
219
436
  rawPolicy !== undefined &&
@@ -269,12 +486,19 @@ class ProcessExecutionBroker extends EventEmitter {
269
486
  { requiredBoundaries },
270
487
  );
271
488
  }
272
- return { profile, requiredBoundaries };
489
+ const executionContract = this._normalizeSandboxExecutionContract(
490
+ options.sandboxExecutionContract,
491
+ options,
492
+ requiredBoundaries,
493
+ launch,
494
+ );
495
+ return { profile, requiredBoundaries, executionContract };
273
496
  }
274
497
 
275
498
  _stripSandboxControlOptions(options) {
276
499
  delete options.sandboxPolicy;
277
500
  delete options.requiredBoundaries;
501
+ delete options.sandboxExecutionContract;
278
502
  }
279
503
 
280
504
  _sandboxUnavailablePlan(command, args, options, reason, sandboxPolicy = {}) {
@@ -318,6 +542,7 @@ class ProcessExecutionBroker extends EventEmitter {
318
542
  typeof metadata.sandboxPolicyAttested === "boolean"
319
543
  ? metadata.sandboxPolicyAttested
320
544
  : null;
545
+ error.sandboxPolicyDigest = metadata.sandboxPolicyDigest || null;
321
546
  error.sandboxCandidateReason = metadata.sandboxCandidateReason || null;
322
547
  return error;
323
548
  }
@@ -400,6 +625,16 @@ class ProcessExecutionBroker extends EventEmitter {
400
625
  "Sandbox policy attestation must be boolean",
401
626
  );
402
627
  }
628
+ const policyDigest = plan.policyDigest ?? null;
629
+ if (
630
+ policyDigest !== null &&
631
+ (typeof policyDigest !== "string" || !/^[a-f0-9]{64}$/.test(policyDigest))
632
+ ) {
633
+ throw this._sandboxError(
634
+ "invalid_sandbox_plan",
635
+ "Sandbox policy digest must be a lowercase SHA-256 value",
636
+ );
637
+ }
403
638
  let runtimeProbe = null;
404
639
  if (plan.runtimeProbe !== null && plan.runtimeProbe !== undefined) {
405
640
  if (
@@ -416,12 +651,314 @@ class ProcessExecutionBroker extends EventEmitter {
416
651
  "Sandbox runtime probe must use the typed probe contract",
417
652
  );
418
653
  }
654
+ for (const field of [
655
+ "probeRuntime",
656
+ "targetRuntime",
657
+ "contentSnapshotScope",
658
+ "contentSnapshotMechanism",
659
+ "pluginTreeContentSnapshotScope",
660
+ "pluginTreeContentSnapshotMechanism",
661
+ "pluginTreeSnapshotConsistency",
662
+ ]) {
663
+ if (
664
+ plan.runtimeProbe[field] !== undefined &&
665
+ (typeof plan.runtimeProbe[field] !== "string" ||
666
+ !plan.runtimeProbe[field])
667
+ ) {
668
+ throw this._sandboxError(
669
+ "invalid_sandbox_plan",
670
+ `Sandbox runtime probe ${field} must be a non-empty string`,
671
+ );
672
+ }
673
+ }
674
+ for (const field of [
675
+ "contentSnapshot",
676
+ "handleAtomic",
677
+ "pluginTreeContentSnapshot",
678
+ "pluginTreeSnapshotContractBound",
679
+ "pluginTreeSnapshotAtomic",
680
+ ]) {
681
+ if (
682
+ plan.runtimeProbe[field] !== undefined &&
683
+ typeof plan.runtimeProbe[field] !== "boolean"
684
+ ) {
685
+ throw this._sandboxError(
686
+ "invalid_sandbox_plan",
687
+ `Sandbox runtime probe ${field} must be boolean`,
688
+ );
689
+ }
690
+ }
691
+ for (const field of [
692
+ "pluginTreeContentSnapshotFiles",
693
+ "pluginTreeContentSnapshotBytes",
694
+ ]) {
695
+ if (
696
+ plan.runtimeProbe[field] !== undefined &&
697
+ (!Number.isSafeInteger(plan.runtimeProbe[field]) ||
698
+ plan.runtimeProbe[field] < 0)
699
+ ) {
700
+ throw this._sandboxError(
701
+ "invalid_sandbox_plan",
702
+ `Sandbox runtime probe ${field} must be a non-negative safe integer`,
703
+ );
704
+ }
705
+ }
706
+ if (
707
+ plan.runtimeProbe.pluginTreeContentSnapshotDigest !== undefined &&
708
+ (typeof plan.runtimeProbe.pluginTreeContentSnapshotDigest !==
709
+ "string" ||
710
+ !/^[a-f0-9]{64}$/.test(
711
+ plan.runtimeProbe.pluginTreeContentSnapshotDigest,
712
+ ))
713
+ ) {
714
+ throw this._sandboxError(
715
+ "invalid_sandbox_plan",
716
+ "Sandbox runtime probe pluginTreeContentSnapshotDigest must be a lowercase SHA-256 value",
717
+ );
718
+ }
719
+ const pluginTreeSnapshot =
720
+ plan.runtimeProbe.pluginTreeContentSnapshot === true;
721
+ const pluginTreeEvidenceFields = [
722
+ "pluginTreeContentSnapshotScope",
723
+ "pluginTreeContentSnapshotMechanism",
724
+ "pluginTreeContentSnapshotFiles",
725
+ "pluginTreeContentSnapshotBytes",
726
+ "pluginTreeContentSnapshotDigest",
727
+ "pluginTreeSnapshotConsistency",
728
+ "pluginTreeSnapshotContractBound",
729
+ "pluginTreeSnapshotAtomic",
730
+ ];
731
+ if (
732
+ pluginTreeSnapshot &&
733
+ (plan.applied !== true ||
734
+ plan.platform !== "linux" ||
735
+ plan.enforcement !== "linux-bwrap" ||
736
+ backend !== "linux-bwrap" ||
737
+ candidateBackend !== null ||
738
+ policyAttested !== true ||
739
+ policyDigest === null ||
740
+ !guarantees.includes(SANDBOX_BOUNDARIES.FILESYSTEM) ||
741
+ !guarantees.includes(SANDBOX_BOUNDARIES.NETWORK) ||
742
+ plan.runtimeProbe.attempted !== true ||
743
+ plan.runtimeProbe.runnable !== true ||
744
+ plan.runtimeProbe.reason !== null ||
745
+ plan.runtimeProbe.kind !== "linux-bwrap-plugin-node-policy-v1" ||
746
+ plan.runtimeProbe.probeRuntime !== "node" ||
747
+ plan.runtimeProbe.targetRuntime !== "node" ||
748
+ plan.runtimeProbe.contentSnapshot !== true ||
749
+ plan.runtimeProbe.contentSnapshotScope !== "plugin-entry-source" ||
750
+ plan.runtimeProbe.contentSnapshotMechanism !==
751
+ "verified-o_tmpfile-copy-bwrap-ro-bind-data-v1" ||
752
+ plan.runtimeProbe.handleAtomic !== false ||
753
+ plan.runtimeProbe.supervisorDescriptorBound !== true ||
754
+ plan.runtimeProbe.pluginTreeContentSnapshotScope !==
755
+ "all-pinned-plugin-regular-files" ||
756
+ plan.runtimeProbe.pluginTreeContentSnapshotMechanism !==
757
+ "verified-o_tmpfile-copy-bwrap-ro-bind-data-v1" ||
758
+ !Number.isSafeInteger(
759
+ plan.runtimeProbe.pluginTreeContentSnapshotFiles,
760
+ ) ||
761
+ plan.runtimeProbe.pluginTreeContentSnapshotFiles < 1 ||
762
+ plan.runtimeProbe.pluginTreeContentSnapshotFiles > 256 ||
763
+ !Number.isSafeInteger(
764
+ plan.runtimeProbe.pluginTreeContentSnapshotBytes,
765
+ ) ||
766
+ plan.runtimeProbe.pluginTreeContentSnapshotBytes < 0 ||
767
+ plan.runtimeProbe.pluginTreeContentSnapshotBytes >
768
+ 256 * 1024 * 1024 ||
769
+ !/^[a-f0-9]{64}$/.test(
770
+ plan.runtimeProbe.pluginTreeContentSnapshotDigest || "",
771
+ ) ||
772
+ plan.runtimeProbe.pluginTreeSnapshotConsistency !==
773
+ "per-file-pin-to-launch" ||
774
+ plan.runtimeProbe.pluginTreeSnapshotContractBound !== false ||
775
+ plan.runtimeProbe.pluginTreeSnapshotAtomic !== false)
776
+ ) {
777
+ throw this._sandboxError(
778
+ "invalid_sandbox_plan",
779
+ "Sandbox runtime probe plugin tree snapshot evidence must use the typed complete-tree contract",
780
+ );
781
+ }
782
+ if (
783
+ !pluginTreeSnapshot &&
784
+ pluginTreeEvidenceFields.some(
785
+ (field) => plan.runtimeProbe[field] !== undefined,
786
+ )
787
+ ) {
788
+ throw this._sandboxError(
789
+ "invalid_sandbox_plan",
790
+ "Sandbox runtime probe plugin tree snapshot evidence requires pluginTreeContentSnapshot",
791
+ );
792
+ }
793
+ const supervisorStringFields = [
794
+ "supervisorBindingScope",
795
+ "supervisorDescriptorBindingMechanism",
796
+ "supervisorPid1ExecutableExposure",
797
+ ];
798
+ const supervisorBooleanFields = [
799
+ "supervisorDescriptorBound",
800
+ "supervisorExecutablePinned",
801
+ "supervisorDescriptorContained",
802
+ "supervisorDescriptorConsumedBeforeTarget",
803
+ "supervisorStagingPathHidden",
804
+ "supervisorTemporaryCopyObscured",
805
+ ];
806
+ for (const field of supervisorStringFields) {
807
+ if (
808
+ plan.runtimeProbe[field] !== undefined &&
809
+ (typeof plan.runtimeProbe[field] !== "string" ||
810
+ !plan.runtimeProbe[field])
811
+ ) {
812
+ throw this._sandboxError(
813
+ "invalid_sandbox_plan",
814
+ `Sandbox runtime probe ${field} must be a non-empty string`,
815
+ );
816
+ }
817
+ }
818
+ for (const field of supervisorBooleanFields) {
819
+ if (
820
+ plan.runtimeProbe[field] !== undefined &&
821
+ typeof plan.runtimeProbe[field] !== "boolean"
822
+ ) {
823
+ throw this._sandboxError(
824
+ "invalid_sandbox_plan",
825
+ `Sandbox runtime probe ${field} must be boolean`,
826
+ );
827
+ }
828
+ }
829
+ const supervisorIdentity = plan.runtimeProbe.supervisorExecutableIdentity;
830
+ if (supervisorIdentity !== undefined) {
831
+ const fileId = supervisorIdentity?.fileId;
832
+ if (
833
+ !supervisorIdentity ||
834
+ typeof supervisorIdentity !== "object" ||
835
+ Array.isArray(supervisorIdentity) ||
836
+ typeof supervisorIdentity.path !== "string" ||
837
+ !supervisorIdentity.path.startsWith("/") ||
838
+ !fileId ||
839
+ typeof fileId !== "object" ||
840
+ Array.isArray(fileId) ||
841
+ typeof fileId.dev !== "string" ||
842
+ !/^\d+$/.test(fileId.dev) ||
843
+ typeof fileId.ino !== "string" ||
844
+ !/^\d+$/.test(fileId.ino) ||
845
+ typeof supervisorIdentity.sha256 !== "string" ||
846
+ !/^[a-f0-9]{64}$/.test(supervisorIdentity.sha256) ||
847
+ !Number.isSafeInteger(supervisorIdentity.bytes) ||
848
+ supervisorIdentity.bytes <= 0 ||
849
+ supervisorIdentity.bytes > 256 * 1024 * 1024 ||
850
+ !Number.isFinite(supervisorIdentity.mtimeMs) ||
851
+ !Number.isSafeInteger(supervisorIdentity.mode) ||
852
+ supervisorIdentity.mode <= 0 ||
853
+ (supervisorIdentity.mode & 0o170000) !== 0o100000 ||
854
+ (supervisorIdentity.mode & 0o111) === 0 ||
855
+ (supervisorIdentity.mode & 0o022) !== 0 ||
856
+ !Number.isSafeInteger(supervisorIdentity.uid) ||
857
+ supervisorIdentity.uid !== 0 ||
858
+ !Number.isSafeInteger(supervisorIdentity.gid) ||
859
+ supervisorIdentity.gid < 0
860
+ ) {
861
+ throw this._sandboxError(
862
+ "invalid_sandbox_plan",
863
+ "Sandbox runtime probe supervisorExecutableIdentity must use the typed executable identity contract",
864
+ );
865
+ }
866
+ }
867
+ const supervisorBound =
868
+ plan.runtimeProbe.supervisorDescriptorBound === true;
869
+ if (
870
+ supervisorBound &&
871
+ (plan.runtimeProbe.supervisorExecutablePinned !== true ||
872
+ supervisorIdentity === undefined ||
873
+ plan.runtimeProbe.supervisorBindingScope !==
874
+ "host-path-replacement" ||
875
+ plan.runtimeProbe.supervisorDescriptorBindingMechanism !==
876
+ "pinned-child-fd3-file-consume-run-overmount-v1" ||
877
+ plan.runtimeProbe.supervisorPid1ExecutableExposure !== "procfs")
878
+ ) {
879
+ throw this._sandboxError(
880
+ "invalid_sandbox_plan",
881
+ "Sandbox runtime probe bound supervisor evidence must include its typed identity and binding contract",
882
+ );
883
+ }
884
+ for (const field of [
885
+ "supervisorDescriptorContained",
886
+ "supervisorDescriptorConsumedBeforeTarget",
887
+ "supervisorStagingPathHidden",
888
+ "supervisorTemporaryCopyObscured",
889
+ ]) {
890
+ if (
891
+ (plan.runtimeProbe[field] === true &&
892
+ (!supervisorBound || plan.runtimeProbe.runnable !== true)) ||
893
+ (supervisorBound &&
894
+ plan.runtimeProbe[field] !== plan.runtimeProbe.runnable)
895
+ ) {
896
+ throw this._sandboxError(
897
+ "invalid_sandbox_plan",
898
+ `Sandbox runtime probe ${field} requires a runnable bound supervisor`,
899
+ );
900
+ }
901
+ }
419
902
  runtimeProbe = {
420
903
  kind: plan.runtimeProbe.kind,
421
904
  attempted: plan.runtimeProbe.attempted,
422
905
  runnable: plan.runtimeProbe.runnable,
423
906
  reason: plan.runtimeProbe.reason,
907
+ ...(plan.runtimeProbe.probeRuntime !== undefined
908
+ ? { probeRuntime: plan.runtimeProbe.probeRuntime }
909
+ : {}),
910
+ ...(plan.runtimeProbe.targetRuntime !== undefined
911
+ ? { targetRuntime: plan.runtimeProbe.targetRuntime }
912
+ : {}),
913
+ ...(plan.runtimeProbe.contentSnapshot !== undefined
914
+ ? { contentSnapshot: plan.runtimeProbe.contentSnapshot }
915
+ : {}),
916
+ ...(plan.runtimeProbe.handleAtomic !== undefined
917
+ ? { handleAtomic: plan.runtimeProbe.handleAtomic }
918
+ : {}),
919
+ ...(plan.runtimeProbe.contentSnapshotScope !== undefined
920
+ ? {
921
+ contentSnapshotScope: plan.runtimeProbe.contentSnapshotScope,
922
+ }
923
+ : {}),
924
+ ...(plan.runtimeProbe.contentSnapshotMechanism !== undefined
925
+ ? {
926
+ contentSnapshotMechanism:
927
+ plan.runtimeProbe.contentSnapshotMechanism,
928
+ }
929
+ : {}),
424
930
  };
931
+ for (const field of [
932
+ "pluginTreeContentSnapshot",
933
+ ...pluginTreeEvidenceFields,
934
+ ]) {
935
+ if (plan.runtimeProbe[field] !== undefined) {
936
+ runtimeProbe[field] = plan.runtimeProbe[field];
937
+ }
938
+ }
939
+ for (const field of [
940
+ ...supervisorStringFields,
941
+ ...supervisorBooleanFields,
942
+ ]) {
943
+ if (plan.runtimeProbe[field] !== undefined) {
944
+ runtimeProbe[field] = plan.runtimeProbe[field];
945
+ }
946
+ }
947
+ if (supervisorIdentity !== undefined) {
948
+ runtimeProbe.supervisorExecutableIdentity = {
949
+ path: supervisorIdentity.path,
950
+ fileId: {
951
+ dev: supervisorIdentity.fileId.dev,
952
+ ino: supervisorIdentity.fileId.ino,
953
+ },
954
+ sha256: supervisorIdentity.sha256,
955
+ bytes: supervisorIdentity.bytes,
956
+ mtimeMs: supervisorIdentity.mtimeMs,
957
+ mode: supervisorIdentity.mode,
958
+ uid: supervisorIdentity.uid,
959
+ gid: supervisorIdentity.gid,
960
+ };
961
+ }
425
962
  }
426
963
  const postSpawn = plan.postSpawn || { required: false, mode: "none" };
427
964
  if (
@@ -442,6 +979,7 @@ class ProcessExecutionBroker extends EventEmitter {
442
979
  guarantees: [...new Set(guarantees)],
443
980
  candidateBackend,
444
981
  policyAttested,
982
+ policyDigest,
445
983
  runtimeProbe,
446
984
  postSpawn: { ...postSpawn },
447
985
  };
@@ -465,6 +1003,7 @@ class ProcessExecutionBroker extends EventEmitter {
465
1003
  sandboxCandidateBackend: plan.candidateBackend,
466
1004
  sandboxRuntimeProbe: plan.runtimeProbe,
467
1005
  sandboxPolicyAttested: plan.policyAttested,
1006
+ sandboxPolicyDigest: plan.policyDigest,
468
1007
  sandboxCandidateReason: plan.candidateBackend ? plan.reason : null,
469
1008
  },
470
1009
  );
@@ -517,55 +1056,70 @@ class ProcessExecutionBroker extends EventEmitter {
517
1056
  const adapterRequest = Object.freeze({
518
1057
  profile,
519
1058
  requiredBoundaries: Object.freeze([...requiredBoundaries]),
1059
+ sync,
1060
+ ...(sandboxPolicy.executionContract
1061
+ ? { executionContract: sandboxPolicy.executionContract }
1062
+ : {}),
520
1063
  });
521
- let plan = this._validateSandboxPlan(
522
- // Keep the legacy string profile in argument four. The built-in adapter
523
- // reserves argument five for runtime injection, so the typed request is
524
- // additive in argument six and legacy injected adapters can ignore it.
525
- this._sandboxAdapter.applySandbox(
526
- command,
527
- args || [],
528
- options,
529
- profile,
530
- undefined,
531
- adapterRequest,
532
- ),
1064
+ // Keep the legacy string profile in argument four. The built-in adapter
1065
+ // reserves argument five for runtime injection, so the typed request is
1066
+ // additive in argument six and legacy injected adapters can ignore it.
1067
+ const rawPlan = this._sandboxAdapter.applySandbox(
1068
+ command,
1069
+ args || [],
1070
+ options,
1071
+ profile,
1072
+ undefined,
1073
+ adapterRequest,
533
1074
  );
534
- plan = this._assertRequiredSandboxBoundaries(plan, requiredBoundaries);
535
-
536
- if (!plan.applied && strict) {
537
- throw this._sandboxError(
538
- plan.reason || "sandbox_unavailable",
539
- `Sandbox is unavailable in strict mode: ${
540
- plan.reason || "unknown reason"
541
- }`,
542
- );
543
- }
1075
+ let plan;
1076
+ try {
1077
+ plan = this._validateSandboxPlan(rawPlan);
1078
+ plan = this._assertRequiredSandboxBoundaries(plan, requiredBoundaries);
544
1079
 
545
- if (plan.applied && plan.postSpawn.required) {
546
- if (typeof this._sandboxAdapter.postSpawnSandbox !== "function") {
1080
+ if (!plan.applied && strict) {
547
1081
  throw this._sandboxError(
548
- "post_spawn_adapter_unavailable",
549
- "Required post-spawn sandbox adapter is unavailable",
1082
+ plan.reason || "sandbox_unavailable",
1083
+ `Sandbox is unavailable in strict mode: ${
1084
+ plan.reason || "unknown reason"
1085
+ }`,
550
1086
  );
551
1087
  }
552
- if (sync) {
553
- throw this._sandboxError(
554
- "post_spawn_unavailable_for_sync",
555
- "spawnSync cannot satisfy required post-spawn sandbox enforcement",
556
- );
1088
+
1089
+ if (plan.applied && plan.postSpawn.required) {
1090
+ if (typeof this._sandboxAdapter.postSpawnSandbox !== "function") {
1091
+ throw this._sandboxError(
1092
+ "post_spawn_adapter_unavailable",
1093
+ "Required post-spawn sandbox adapter is unavailable",
1094
+ );
1095
+ }
1096
+ if (sync) {
1097
+ throw this._sandboxError(
1098
+ "post_spawn_unavailable_for_sync",
1099
+ "spawnSync cannot satisfy required post-spawn sandbox enforcement",
1100
+ );
1101
+ }
1102
+ if (
1103
+ (strict || requiredBoundaries.length > 0) &&
1104
+ plan.postSpawn.mode !== "sync"
1105
+ ) {
1106
+ throw this._sandboxError(
1107
+ "async_post_spawn_disallowed_in_strict_mode",
1108
+ "Fail-closed sandbox enforcement requires synchronous post-spawn enforcement",
1109
+ );
1110
+ }
557
1111
  }
558
- if (
559
- (strict || requiredBoundaries.length > 0) &&
560
- plan.postSpawn.mode !== "sync"
561
- ) {
562
- throw this._sandboxError(
563
- "async_post_spawn_disallowed_in_strict_mode",
564
- "Fail-closed sandbox enforcement requires synchronous post-spawn enforcement",
565
- );
1112
+ return plan;
1113
+ } catch (error) {
1114
+ if (typeof rawPlan?.cleanup === "function") {
1115
+ try {
1116
+ rawPlan.cleanup();
1117
+ } catch {
1118
+ // Preserve the boundary/contract failure that prevented execution.
1119
+ }
566
1120
  }
1121
+ throw error;
567
1122
  }
568
- return plan;
569
1123
  }
570
1124
 
571
1125
  _applySandboxAudit(auditEntry, plan, applied) {
@@ -580,6 +1134,7 @@ class ProcessExecutionBroker extends EventEmitter {
580
1134
  : null;
581
1135
  auditEntry.sandboxPolicyAttested =
582
1136
  typeof plan?.policyAttested === "boolean" ? plan.policyAttested : null;
1137
+ auditEntry.sandboxPolicyDigest = plan?.policyDigest || null;
583
1138
  auditEntry.sandboxCandidateReason = plan?.candidateBackend
584
1139
  ? plan?.reason || null
585
1140
  : null;
@@ -616,6 +1171,8 @@ class ProcessExecutionBroker extends EventEmitter {
616
1171
  typeof error.sandboxPolicyAttested === "boolean"
617
1172
  ? error.sandboxPolicyAttested
618
1173
  : (auditEntry.sandboxPolicyAttested ?? null);
1174
+ auditEntry.sandboxPolicyDigest =
1175
+ error.sandboxPolicyDigest || auditEntry.sandboxPolicyDigest || null;
619
1176
  auditEntry.sandboxCandidateReason =
620
1177
  error.sandboxCandidateReason || auditEntry.sandboxCandidateReason || null;
621
1178
  auditEntry.deniedReason = `sandbox-init-failed: ${error.message}`;
@@ -923,6 +1480,9 @@ class ProcessExecutionBroker extends EventEmitter {
923
1480
  pluginId: options.pluginId || null,
924
1481
  pluginVersion: options.pluginVersion || null,
925
1482
  pluginSource: options.pluginSource || null,
1483
+ pluginExecutableIdentity: this._normalizePluginExecutableIdentity(
1484
+ options.pluginExecutableIdentity,
1485
+ ),
926
1486
  sandboxRequired: [],
927
1487
  sandboxGuarantees: [],
928
1488
  sandboxBackend: null,
@@ -930,7 +1490,11 @@ class ProcessExecutionBroker extends EventEmitter {
930
1490
 
931
1491
  let sandboxPolicy;
932
1492
  try {
933
- sandboxPolicy = this._normalizeSandboxPolicy(options);
1493
+ sandboxPolicy = this._normalizeSandboxPolicy(options, {
1494
+ command,
1495
+ args,
1496
+ sync: false,
1497
+ });
934
1498
  auditEntry.sandboxRequired = [...sandboxPolicy.requiredBoundaries];
935
1499
  } catch (sandboxPolicyError) {
936
1500
  this._recordSandboxDenial(auditEntry, sandboxPolicyError, startTime);
@@ -966,6 +1530,7 @@ class ProcessExecutionBroker extends EventEmitter {
966
1530
  // 传播traceparent环境变量
967
1531
  const spawnOpts = this._sanitizeOptions(options);
968
1532
  this._stripSandboxControlOptions(spawnOpts);
1533
+ this._stripPluginControlOptions(spawnOpts);
969
1534
  if (traceCtx) {
970
1535
  spawnOpts.env = { ...(spawnOpts.env || process.env) };
971
1536
  spawnOpts.env.TRACEPARENT = traceCtx.traceparent;
@@ -1138,6 +1703,9 @@ class ProcessExecutionBroker extends EventEmitter {
1138
1703
  pluginId: options.pluginId || null,
1139
1704
  pluginVersion: options.pluginVersion || null,
1140
1705
  pluginSource: options.pluginSource || null,
1706
+ pluginExecutableIdentity: this._normalizePluginExecutableIdentity(
1707
+ options.pluginExecutableIdentity,
1708
+ ),
1141
1709
  sandboxRequired: [],
1142
1710
  sandboxGuarantees: [],
1143
1711
  sandboxBackend: null,
@@ -1145,7 +1713,11 @@ class ProcessExecutionBroker extends EventEmitter {
1145
1713
 
1146
1714
  let sandboxPolicy;
1147
1715
  try {
1148
- sandboxPolicy = this._normalizeSandboxPolicy(options);
1716
+ sandboxPolicy = this._normalizeSandboxPolicy(options, {
1717
+ command,
1718
+ args,
1719
+ sync: true,
1720
+ });
1149
1721
  auditEntry.sandboxRequired = [...sandboxPolicy.requiredBoundaries];
1150
1722
  } catch (sandboxPolicyError) {
1151
1723
  this._recordSandboxDenial(auditEntry, sandboxPolicyError, startTime);
@@ -1174,6 +1746,7 @@ class ProcessExecutionBroker extends EventEmitter {
1174
1746
 
1175
1747
  const spawnOpts = this._sanitizeOptions(options);
1176
1748
  this._stripSandboxControlOptions(spawnOpts);
1749
+ this._stripPluginControlOptions(spawnOpts);
1177
1750
  if (traceCtx) {
1178
1751
  spawnOpts.env = { ...(spawnOpts.env || process.env) };
1179
1752
  spawnOpts.env.TRACEPARENT = traceCtx.traceparent;
@@ -1291,10 +1864,17 @@ class ProcessExecutionBroker extends EventEmitter {
1291
1864
  pluginId: options.pluginId || null,
1292
1865
  pluginVersion: options.pluginVersion || null,
1293
1866
  pluginSource: options.pluginSource || null,
1867
+ pluginExecutableIdentity: this._normalizePluginExecutableIdentity(
1868
+ options.pluginExecutableIdentity,
1869
+ ),
1294
1870
  };
1295
1871
  let sandboxPolicy;
1296
1872
  try {
1297
- sandboxPolicy = this._normalizeSandboxPolicy(options);
1873
+ sandboxPolicy = this._normalizeSandboxPolicy(options, {
1874
+ command,
1875
+ args,
1876
+ sync: false,
1877
+ });
1298
1878
  auditEntry.sandboxRequired = [...sandboxPolicy.requiredBoundaries];
1299
1879
  } catch (sandboxPolicyError) {
1300
1880
  this._recordSandboxDenial(auditEntry, sandboxPolicyError, startTime);
@@ -1331,12 +1911,10 @@ class ProcessExecutionBroker extends EventEmitter {
1331
1911
 
1332
1912
  const spawnOptions = { ...options, args: [...auditEntry.args] };
1333
1913
  this._stripSandboxControlOptions(spawnOptions);
1914
+ this._stripPluginControlOptions(spawnOptions);
1334
1915
  delete spawnOptions.origin;
1335
1916
  delete spawnOptions.policy;
1336
1917
  delete spawnOptions.scope;
1337
- delete spawnOptions.pluginId;
1338
- delete spawnOptions.pluginVersion;
1339
- delete spawnOptions.pluginSource;
1340
1918
  try {
1341
1919
  if (this._credentialBoundaryEnabled()) {
1342
1920
  spawnOptions.credentialContext = this._createCredentialContext(