chainlesschain 0.163.7 → 0.164.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +5 -1
- package/scripts/macos-mcp-launcher-build.mjs +317 -0
- package/scripts/macos-mcp-launcher-postinstall.sh +54 -0
- package/scripts/macos-mcp-launcher-preinstall.sh +61 -0
- package/src/assets/web-panel/assets/{AIOps-axqQfwv8.js → AIOps-D2MEn7fI.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-DV-Ro0By.js → ActionButton-lCW_4Gf0.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-Bt72WEVu.js → Analytics-Bs7i-nsS.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-BtepG55E.js → AppLayout-CK7B6S_j.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-B7KaJ7S_.js → Artifacts-C8ILjpyo.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-FNFaUg7A.js → Audit-Bb9cNaWc.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-DFb6J2wQ.js → BackgroundAgents-sC9ooXIf.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CC7YBhyj.js → Backup-D-DrsplT.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-RkgTNVtj.js → BaseInput-uCNZpwSK.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-hHEmGZy-.js → Chat-CsDK1uE9.js} +6 -6
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-CAP9YhHv.js → ChatBubbleRenderer-OqSDt50w.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-z5wXOQP1.js → Checkbox-JhTXM1-K.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DVaDJnxy.js → Codegen-BbzZLnyD.js} +1 -1
- package/src/assets/web-panel/assets/{Col-CJmaRDR5.js → Col-D4VW4m4j.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DF29_2bI.js → Community-BXrYawxV.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DtkQkBzn.js → Compact-DCihGy1u.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-xoHDxp7I.js → Compliance-DlyZ-lk8.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-BUm-R7ht.js → Cowork-DvGZrhbO.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-Cgl14ZkB.js → Cron-DUncZi8h.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-BNcbmoqh.js → Crosschain-C_hLuUcm.js} +1 -1
- package/src/assets/web-panel/assets/{DID-Bwja0Zo9.js → DID-b6YSUqxr.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-Bk5XjEdJ.js → Dashboard-uvM15Cfb.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-Ci36Oitq.js → Dropdown-D1-Nd4qY.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer--U04ZN4q.js → EmailListRenderer-8ApvL6Zc.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-B2gNPR2s.js → FamilyGuardDashboard-LYJt8811.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-C4KghYn7.js → Federation-BbI3HGpv.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-QL7x_Q_0.js → FormItemContext-DSoEKuFu.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-F3Ryltwm.js → GenericCardRenderer-B0S9OWd5.js} +1 -1
- package/src/assets/web-panel/assets/{Git-2HassK5k.js → Git-DIs9Zhf3.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-DoBIp7oe.js → Governance-jzZXrxcl.js} +1 -1
- package/src/assets/web-panel/assets/{Inference--W01QhZ-.js → Inference-JUPjf2ZI.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-DmvwqGpT.js → KnowledgeGraph-DxnfJvlP.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BBJ4yAel.js → Logs-iXiz8BEE.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-BLCZMzhJ.js → MarkdownRenderer-GmB6DOr6.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-D5lNngSI.js → Marketplace-Y3Xch312.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CkEVOMKH.js → McpTools-D7kGGbO7.js} +4 -4
- package/src/assets/web-panel/assets/{Memory-B1Ow1xVE.js → Memory-Do_hVxzh.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-SgYbUfb6.js → MobileBridge-CtrR0Tas.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-BL0Czcoj.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-DcTXSSma.js → Mtc-qo5QCTGd.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-Dt3WG4oj.js → MtcAudit-cq5mnjYj.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-B9B38UZx.js → Multisig-Bq0MAQHw.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-B0S4GGvG.js → NLProgramming-DdWE6Vi2.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-DZ5U58Ng.js → Notes-BxMBFcIp.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-PjL5ZW34.js → NotificationSettings-RTrAcbUe.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DrAX2ESt.js → OrderTableRenderer-DJbpGqzT.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-Cv1GYs-c.js → Organization-SQzIPdqC.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Bbkp_PL3.js → Overflow-02yECh22.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BD8QUgoZ.js → P2P-BNg4pNCM.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BO-2PeaB.js → PdhVaultBrowser-BxPJZsD3.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-D_OPVa02.js → Permissions-CLnDnPAz.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-mh-pEmaB.js → PersonalDataHub-C5m0AjGf.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-6JC2EDdb.js → Pipeline-VwOf5Dhv.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CUshzUAG.js → Privacy-CC0W2hZd.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-Cs2Aalri.js → ProjectInit-Dz893Bob.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-1ak49tcj.js → ProjectSettings-CxQkvl0k.js} +2 -2
- package/src/assets/web-panel/assets/Projects-DDAjkUkT.js +1 -0
- package/src/assets/web-panel/assets/{Providers-CXXxvafH.js → Providers-DeB9IkxK.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-PTcDsF58.js → QrScannerModal-OCeoaswn.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-CDwucrJw.js → QuickAsk-DenotaAj.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-CJlLVRXR.js → Recommend-Cies_jjI.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-DlN-ETsO.js → RemoteSession-Dxzl5n2T.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-DI23LR6m.js → Reputation-CW0mvxgZ.js} +1 -1
- package/src/assets/web-panel/assets/{Row-Cl7UQMrM.js → Row-SEd32qZU.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CexHNfh8.js → RssFeed-BSwnJ3Lm.js} +3 -3
- package/src/assets/web-panel/assets/{Search-BneBWvRN.js → Search-xe2m8bkC.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DX7Phgrp.js → Security-Mq2F9Nro.js} +4 -4
- package/src/assets/web-panel/assets/{Services-BWXO8Mte.js → Services-BKGw2V3P.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DCyOjKPJ.js → Skeleton-DW95-Rxf.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CXqERsTB.js → Skills-CHgChCv_.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-bhbrbz8E.js → Sla-tKh6k3R7.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-3IPU0HBZ.js → SpeechSettings-D6UL3dA5.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DBNTQLbM.js → SyncSettings-D0Fw8fVL.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-quP0bkN-.js → Tasks-20x1GB3D.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-BouWmgho.js → Templates-DJ-lts-a.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-qv0D9s7z.js → Tenant-BFdGpbs7.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-BxvbE8BB.js → Terminal-Xpx61vHL.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-D-IeLnJ2.js → TimelineRenderer-C6UIvyZQ.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-CFMKKyVG.js → Tokens-Dellq08f.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-L8as3UuJ.js → Trigger-VKw8d0J-.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-MxmA4VZG.js → Trust-DNftdKT5.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-C0VvJYRi.js → UkeySign-DX9VAKJI.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-Bf5QZj8N.js → VideoEditing-B2h3jO8q.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BIJ9riRz.js → Wallet-CjGkof7f.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-B8p9Mhkw.js → WebAuthn-2Zfcu55P.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-BVsuaPen.js → WorkflowEditor-B9eZ8UxZ.js} +1 -1
- package/src/assets/web-panel/assets/{chat-BfkjoKpV.js → chat-CQNfD-YO.js} +1 -1
- package/src/assets/web-panel/assets/{colors-DeAlsWK8.js → colors-D4usyFT2.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-Cs97bz5j.js → compact-item-s4TpjvjX.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-BqbG60LH.js → createContext-BRCSvYxj.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-DKJjSWRn.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-i_RY0b1X.js → hasIn-AdkUbkV-.js} +1 -1
- package/src/assets/web-panel/assets/{index-BOVkf1K3.js → index--00U6vXZ.js} +1 -1
- package/src/assets/web-panel/assets/{index-B-3tEpTc.js → index-B2V-eKfK.js} +1 -1
- package/src/assets/web-panel/assets/{index-D2B4VPyP.js → index-B4JJCfQ2.js} +1 -1
- package/src/assets/web-panel/assets/{index-BkBi5TmC.js → index-BIoG5yYf.js} +1 -1
- package/src/assets/web-panel/assets/{index-79V_zv1s.js → index-BMcimU-2.js} +1 -1
- package/src/assets/web-panel/assets/{index-U4f5izHz.js → index-BPhkFZ1I.js} +1 -1
- package/src/assets/web-panel/assets/{index-DiSkx4UB.js → index-BQ3DXBtD.js} +3 -3
- package/src/assets/web-panel/assets/{index-dIHr4B_u.js → index-Bad4VNvz.js} +1 -1
- package/src/assets/web-panel/assets/{index-CIG8fQ2_.js → index-BgiXR_-_.js} +1 -1
- package/src/assets/web-panel/assets/{index-DqBgBpgp.js → index-BtobShro.js} +1 -1
- package/src/assets/web-panel/assets/{index-ZxO_-E8a.js → index-Bw2MEnUk.js} +1 -1
- package/src/assets/web-panel/assets/{index-DUUrv141.js → index-C1mJtE6q.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bm7lLR4c.js → index-C484EJiS.js} +1 -1
- package/src/assets/web-panel/assets/{index-COdGA-8n.js → index-C5KAQFPQ.js} +1 -1
- package/src/assets/web-panel/assets/index-C61cnl3K.js +1 -0
- package/src/assets/web-panel/assets/{index-CED2PL_y.js → index-C7Y8Aluc.js} +1 -1
- package/src/assets/web-panel/assets/{index-YXgLng0K.js → index-CCsM_Ybx.js} +1 -1
- package/src/assets/web-panel/assets/{index-0-agYlWL.js → index-CJCFe2Qf.js} +1 -1
- package/src/assets/web-panel/assets/{index-B5UkyA3c.js → index-CJVEOa4i.js} +1 -1
- package/src/assets/web-panel/assets/{index-B1CbOH1i.js → index-CJdQrZth.js} +1 -1
- package/src/assets/web-panel/assets/{index-s1opAL-M.js → index-CKC1t3Ic.js} +1 -1
- package/src/assets/web-panel/assets/{index-yObj1O4n.js → index-CQhAVU5t.js} +1 -1
- package/src/assets/web-panel/assets/{index-CgsqdnRV.js → index-CYdoQsa1.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dk7-v4hP.js → index-Cduu2Hhr.js} +1 -1
- package/src/assets/web-panel/assets/{index-B-JVTrpr.js → index-CkwiSLhU.js} +1 -1
- package/src/assets/web-panel/assets/{index-CeWoNHau.js → index-Cvyt-zhm.js} +1 -1
- package/src/assets/web-panel/assets/{index-CE2VtTlp.js → index-D2GjI2oe.js} +1 -1
- package/src/assets/web-panel/assets/index-D4XFHxBr.js +1 -0
- package/src/assets/web-panel/assets/{index-DmbfhJUP.js → index-DARsAyUp.js} +1 -1
- package/src/assets/web-panel/assets/{index-BESLFt4q.js → index-DVKfQ0Ux.js} +1 -1
- package/src/assets/web-panel/assets/{index-PT_5sBMA.js → index-DZT36ZYq.js} +1 -1
- package/src/assets/web-panel/assets/{index-gyFpvL7l.js → index-D_XBHopw.js} +1 -1
- package/src/assets/web-panel/assets/{index-BYUVuwKt.js → index-DdCB70SS.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcUXAB2s.js → index-DzRjHxEv.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dk2qouAz.js → index-MMN9V6JF.js} +1 -1
- package/src/assets/web-panel/assets/{index-D9evtvg2.js → index-RfMr79MW.js} +1 -1
- package/src/assets/web-panel/assets/{index-BuLQobzW.js → index-_IRVsV9X.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cf3WCLmy.js → index-nXyk8GZ9.js} +1 -1
- package/src/assets/web-panel/assets/{index-CG3PRyAL.js → index-s_buFMEG.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-C9h9yKL3.js → initDefaultProps-Blmpk7HL.js} +1 -1
- package/src/assets/web-panel/assets/{motion-BvmLsPdu.js → motion-DPBJMv1n.js} +1 -1
- package/src/assets/web-panel/assets/{move-CoL4ekU1.js → move-ButdzCM7.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-C4pMy6xV.js → mtc-parser-cyRC_QCe.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DPuJfNxx.js → omit-1epSV7hz.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-D0KEeaK2.js → pickAttrs-DuPY8xJs.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-BpkyINxt.js → placementArrow-6XZqarhe.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DQI_wOq8.js → responsiveObserve-B40pXBWM.js} +1 -1
- package/src/assets/web-panel/assets/{slide-DYfdDiRg.js → slide-jbZ9Wu4n.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-B5dtvb0D.js → statusUtils-BKQQcVy4.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-CF310mSj.js → styleChecker-NiKfWjUT.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-D1Qp4BLp.js → useFlexGapSupport-bQUCvPeb.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-C7_iyvJK.js → useFs-CUGji7ph.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DZUt_fIm.js → usePersonalDataHub-4veyN2N2.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-D3dsi0lZ.js → vnode-1-nLug-Z.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-WdbOlvdQ.js → zoom-dhCeRDMo.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +6 -6
- package/src/commands/automation.js +103 -1
- package/src/commands/cowork.js +174 -19
- package/src/commands/permissions.js +240 -16
- package/src/commands/plugin.js +1293 -56
- package/src/commands/session-location.js +276 -0
- package/src/commands/session.js +2 -0
- package/src/commands/team-merge-review.js +937 -0
- package/src/commands/team.js +2 -0
- package/src/data/changelog.json +27 -1
- package/src/gateways/ws/action-protocol.js +35 -10
- package/src/gateways/ws/remote-session-protocol.js +24 -1
- package/src/gateways/ws/ws-agent-handler.js +12 -0
- package/src/gateways/ws/ws-server.js +48 -12
- package/src/harness/jsonl-session-store.js +341 -24
- package/src/harness/mcp-client.js +8 -1
- package/src/harness/remote-session-audit.js +1 -0
- package/src/harness/remote-session-crypto.js +210 -2
- package/src/harness/remote-session-registry.js +159 -6
- package/src/harness/session-list-index.js +233 -14
- package/src/lib/agent-authority.js +6 -0
- package/src/lib/agent-schedule-store.js +139 -28
- package/src/lib/agent-team/team-merge-review-store.js +765 -0
- package/src/lib/agent-team/team-merge-review-transaction.js +1223 -0
- package/src/lib/agent-team/team-merge-review.js +1847 -0
- package/src/lib/automation-center-incidents.js +314 -0
- package/src/lib/automation-center-runtime.js +448 -0
- package/src/lib/automation-center.js +182 -38
- package/src/lib/automation-engine.js +41 -0
- package/src/lib/automation-execution-authority.js +241 -12
- package/src/lib/automation-execution-incident.js +737 -0
- package/src/lib/background-agent-keeper-client.js +248 -0
- package/src/lib/background-agent-keeper-protocol.js +147 -0
- package/src/lib/background-agent-supervisor.js +520 -40
- package/src/lib/background-interaction-resolver.js +12 -0
- package/src/lib/background-turn-bootstrap-protocol.js +126 -0
- package/src/lib/cowork-cron.js +85 -14
- package/src/lib/cowork-workflow.js +336 -16
- package/src/lib/dynamic-workflow-facade.js +648 -0
- package/src/lib/execution-location-contract.js +551 -0
- package/src/lib/execution-location-runtime.js +130 -0
- package/src/lib/ide-context.js +94 -6
- package/src/lib/mcp-stdio-package-materialization.js +166 -14
- package/src/lib/packer/pkg-config-generator.js +2 -0
- package/src/lib/permission-authority.js +77 -0
- package/src/lib/permission-side-effect-center.js +495 -0
- package/src/lib/plugin-runtime/install.js +514 -13
- package/src/lib/plugin-runtime/marketplace-artifact-readback.js +900 -0
- package/src/lib/plugin-runtime/marketplace-catalog.js +1181 -0
- package/src/lib/plugin-runtime/marketplace-impact.js +408 -0
- package/src/lib/plugin-runtime/marketplace-remote-artifacts.js +1567 -0
- package/src/lib/plugin-security.js +60 -3
- package/src/lib/process-execution-broker/index.js +1095 -57
- package/src/lib/process-execution-broker/linux-bwrap-descriptor-launch.js +375 -0
- package/src/lib/process-execution-broker/linux-generic-bwrap-runtime.js +90 -16
- package/src/lib/process-execution-broker/linux-generic-bwrap.js +159 -18
- package/src/lib/process-execution-broker/macos-mcp-launcher-contract.js +278 -0
- package/src/lib/process-execution-broker/macos-mcp-launcher-protocol.json +23 -0
- package/src/lib/process-execution-broker/macos-mcp-launcher.c +1497 -0
- package/src/lib/process-execution-broker/mcp-fd-entry-bootstrap.js +37 -0
- package/src/lib/process-execution-broker/platform-sandbox.js +2330 -279
- package/src/lib/process-execution-broker/windows-sandbox-helper.dll +0 -0
- package/src/lib/process-execution-broker/windows-sandbox-helper.exe +0 -0
- package/src/lib/process-execution-broker/windows-sandbox.cs +50 -4
- package/src/lib/public-ide-capability-manifest.js +3 -0
- package/src/lib/remote-approval-bridge.js +123 -17
- package/src/lib/remote-membership-authority.js +632 -0
- package/src/lib/remote-membership-coordinator.js +2409 -0
- package/src/lib/remote-membership-host-store.js +1750 -0
- package/src/lib/scheduler-kernel/agenda-adapter.js +17 -7
- package/src/lib/scheduler-kernel/automation-adapter.js +105 -11
- package/src/lib/scheduler-kernel/automation-event-adapter.js +87 -11
- package/src/lib/scheduler-kernel/contract.js +91 -0
- package/src/lib/scheduler-kernel/cowork-cron-adapter.js +12 -1
- package/src/lib/scheduler-kernel/loop-adapter.js +7 -1
- package/src/lib/scheduler-kernel/routine-adapter.js +7 -1
- package/src/lib/scheduler-kernel/runtime-control-capabilities.js +31 -0
- package/src/lib/scheduler-kernel/runtime.js +176 -3
- package/src/lib/scheduler-kernel/store.js +1253 -45
- package/src/lib/scoped-permission-store.js +369 -0
- package/src/lib/session-anti-rollback-anchor.js +262 -5
- package/src/lib/sub-agent-context.js +4 -0
- package/src/lib/workflow-definition-contract.js +149 -0
- package/src/repl/agent-repl.js +41 -7
- package/src/repl/chat-repl.js +2 -0
- package/src/repl/clipboard-image.js +735 -16
- package/src/repl/ide-status.js +1 -1
- package/src/repl/prompt-interactions.js +59 -6
- package/src/runtime/agent-core.js +93 -3
- package/src/runtime/headless-runner.js +30 -25
- package/src/runtime/headless-stream.js +32 -25
- package/src/runtime/mcp-config.js +81 -10
- package/src/workers/background-agent-keeper.js +498 -0
- package/src/workers/background-agent-worker.js +358 -13
- package/src/workers/background-turn-bootstrap.js +143 -0
- package/src/assets/web-panel/assets/MobileProjects-BWdOvQAj.js +0 -1
- package/src/assets/web-panel/assets/Projects-BV4oApsm.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DPty0mGN.js +0 -1
- package/src/assets/web-panel/assets/index-Bt7g0Vq_.js +0 -1
- package/src/assets/web-panel/assets/index-ChVT0p9u.js +0 -1
|
@@ -36,16 +36,32 @@ const require = createRequire(import.meta.url);
|
|
|
36
36
|
// platform-sandbox.js exports: applySandbox, postSpawnSandbox
|
|
37
37
|
import {
|
|
38
38
|
applySandbox as _applySandbox,
|
|
39
|
+
consumeMacMcpCodeSnapshotPlanBinding,
|
|
39
40
|
consumeWindowsMcpCodeSnapshotPlanBinding,
|
|
40
41
|
postSpawnSandbox as _postSpawnSandbox,
|
|
41
42
|
MCP_STDIO_FD_ENTRY_BOOTSTRAP_SHA256,
|
|
43
|
+
MCP_STDIO_MACOS_GATED_ENTRY_BOOTSTRAP_SHA256,
|
|
44
|
+
MACOS_PKG_EXECPATH_MAGIC,
|
|
42
45
|
SANDBOX_BOUNDARIES,
|
|
43
46
|
} from "./platform-sandbox.js";
|
|
47
|
+
import {
|
|
48
|
+
MACOS_MCP_LAUNCHER_INPUTS,
|
|
49
|
+
isMacosMcpLauncherPackageVersion,
|
|
50
|
+
} from "./macos-mcp-launcher-contract.js";
|
|
44
51
|
import {
|
|
45
52
|
admitLinuxGenericSandboxExecutionContract,
|
|
46
53
|
issueLinuxGenericSandboxExecutionContract,
|
|
47
54
|
LINUX_GENERIC_CONTRACT_KIND,
|
|
55
|
+
verifyLinuxGenericBubblewrapPlan,
|
|
48
56
|
} from "./linux-generic-bwrap.js";
|
|
57
|
+
import {
|
|
58
|
+
LINUX_BWRAP_DESCRIPTOR_SCRUBBER_KIND,
|
|
59
|
+
LINUX_BWRAP_DESCRIPTOR_SCRUBBER_MECHANISM,
|
|
60
|
+
LINUX_BWRAP_DESCRIPTOR_SCRUBBER_PASSES,
|
|
61
|
+
LINUX_BWRAP_DESCRIPTOR_SCRUBBER_PATH,
|
|
62
|
+
LINUX_BWRAP_DESCRIPTOR_SCRUBBER_SCRIPT_SHA256,
|
|
63
|
+
parseLinuxBwrapDescriptorScrubbedLaunch,
|
|
64
|
+
} from "./linux-bwrap-descriptor-launch.js";
|
|
49
65
|
import { consumeIssuedPluginSandboxExecutionContract } from "../plugin-runtime/bin.js";
|
|
50
66
|
import runtimeProvenanceLedger from "../runtime-provenance-ledger.js";
|
|
51
67
|
import { credentialAgent } from "./credential-agent.js";
|
|
@@ -65,6 +81,424 @@ const SUPPORTED_SANDBOX_PROFILES = new Set([
|
|
|
65
81
|
// Broker-private admission state. Public runtime-probe fields are audit
|
|
66
82
|
// evidence, not authority to invoke a privileged post-spawn closure.
|
|
67
83
|
const admittedWindowsMcpCodeSnapshotPlans = new WeakSet();
|
|
84
|
+
const admittedMacMcpCodeSnapshotPlans = new WeakSet();
|
|
85
|
+
|
|
86
|
+
const LINUX_RUNTIME_PATHNAME_POLICY_PREFIX = Object.freeze([
|
|
87
|
+
"--die-with-parent",
|
|
88
|
+
"--new-session",
|
|
89
|
+
"--unshare-user",
|
|
90
|
+
"--disable-userns",
|
|
91
|
+
"--assert-userns-disabled",
|
|
92
|
+
"--unshare-pid",
|
|
93
|
+
"--unshare-ipc",
|
|
94
|
+
"--unshare-net",
|
|
95
|
+
"--unshare-uts",
|
|
96
|
+
"--unshare-cgroup-try",
|
|
97
|
+
"--cap-drop",
|
|
98
|
+
"ALL",
|
|
99
|
+
"--hostname",
|
|
100
|
+
"chainless-sandbox",
|
|
101
|
+
"--clearenv",
|
|
102
|
+
]);
|
|
103
|
+
const LINUX_RUNTIME_PATHNAME_POLICY_DIRECTORIES = Object.freeze([
|
|
104
|
+
"/opt",
|
|
105
|
+
"/opt/chainless",
|
|
106
|
+
"/opt/chainless/runtime",
|
|
107
|
+
"/opt/chainless/plugin",
|
|
108
|
+
"/home",
|
|
109
|
+
"/home/sandbox",
|
|
110
|
+
"/tmp",
|
|
111
|
+
"/run",
|
|
112
|
+
"/var",
|
|
113
|
+
"/var/tmp",
|
|
114
|
+
"/proc",
|
|
115
|
+
"/dev",
|
|
116
|
+
]);
|
|
117
|
+
const LINUX_RUNTIME_PATHNAME_POLICY_ENVIRONMENT = Object.freeze([
|
|
118
|
+
["CHAINLESS_SANDBOXED", "1"],
|
|
119
|
+
["HOME", "/home/sandbox"],
|
|
120
|
+
["LANG", "C.UTF-8"],
|
|
121
|
+
["LC_ALL", "C.UTF-8"],
|
|
122
|
+
["OPENSSL_CONF", "/dev/null"],
|
|
123
|
+
["PATH", "/opt/chainless/runtime"],
|
|
124
|
+
["TMPDIR", "/tmp"],
|
|
125
|
+
["TZ", "UTC"],
|
|
126
|
+
]);
|
|
127
|
+
|
|
128
|
+
function denseOwnDataArraySnapshot(value) {
|
|
129
|
+
if (
|
|
130
|
+
!Array.isArray(value) ||
|
|
131
|
+
Object.getPrototypeOf(value) !== Array.prototype
|
|
132
|
+
) {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
136
|
+
const length = descriptors.length?.value;
|
|
137
|
+
if (
|
|
138
|
+
!Number.isSafeInteger(length) ||
|
|
139
|
+
length < 0 ||
|
|
140
|
+
Reflect.ownKeys(descriptors).length !== length + 1
|
|
141
|
+
) {
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
const snapshot = [];
|
|
145
|
+
for (let index = 0; index < length; index += 1) {
|
|
146
|
+
const descriptor = descriptors[String(index)];
|
|
147
|
+
if (!descriptor || !("value" in descriptor)) return null;
|
|
148
|
+
snapshot.push(descriptor.value);
|
|
149
|
+
}
|
|
150
|
+
return Object.freeze(snapshot);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function exactOwnDataDescriptors(value, expectedKeys) {
|
|
154
|
+
if (
|
|
155
|
+
!value ||
|
|
156
|
+
typeof value !== "object" ||
|
|
157
|
+
Array.isArray(value) ||
|
|
158
|
+
Object.getPrototypeOf(value) !== Object.prototype
|
|
159
|
+
) {
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
163
|
+
const keys = Reflect.ownKeys(descriptors);
|
|
164
|
+
if (
|
|
165
|
+
keys.some((key) => typeof key !== "string") ||
|
|
166
|
+
keys.length !== expectedKeys.length ||
|
|
167
|
+
expectedKeys.some((key) => !("value" in (descriptors[key] || {})))
|
|
168
|
+
) {
|
|
169
|
+
return null;
|
|
170
|
+
}
|
|
171
|
+
return descriptors;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function ownDataObjectSnapshot(value) {
|
|
175
|
+
if (
|
|
176
|
+
!value ||
|
|
177
|
+
typeof value !== "object" ||
|
|
178
|
+
Array.isArray(value) ||
|
|
179
|
+
Object.getPrototypeOf(value) !== Object.prototype
|
|
180
|
+
) {
|
|
181
|
+
return null;
|
|
182
|
+
}
|
|
183
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
184
|
+
const snapshot = {};
|
|
185
|
+
for (const key of Reflect.ownKeys(descriptors)) {
|
|
186
|
+
if (typeof key !== "string" || !("value" in descriptors[key])) {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
Object.defineProperty(snapshot, key, {
|
|
190
|
+
value: descriptors[key].value,
|
|
191
|
+
enumerable: true,
|
|
192
|
+
configurable: true,
|
|
193
|
+
writable: true,
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
return Object.freeze(snapshot);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const LINUX_DESCRIPTOR_SCRUBBER_EVIDENCE_KEYS = Object.freeze([
|
|
200
|
+
"kind",
|
|
201
|
+
"mechanism",
|
|
202
|
+
"scriptSha256",
|
|
203
|
+
"executableIdentity",
|
|
204
|
+
"executablePinned",
|
|
205
|
+
"argvFixed",
|
|
206
|
+
"callerEnvironmentFixed",
|
|
207
|
+
"nodeRuntimeEnvironmentInjection",
|
|
208
|
+
"nodeIpcChildFd",
|
|
209
|
+
"nodeIpcSerializationMode",
|
|
210
|
+
"procSelfFdPasses",
|
|
211
|
+
"closesUnknownInheritedDescriptors",
|
|
212
|
+
"verificationPassesFailClosed",
|
|
213
|
+
"policyBound",
|
|
214
|
+
"scrubberChildFd",
|
|
215
|
+
"preservedMaxFd",
|
|
216
|
+
"activeStdioThrough",
|
|
217
|
+
"executableChildFd",
|
|
218
|
+
]);
|
|
219
|
+
const LINUX_DESCRIPTOR_SCRUBBER_IDENTITY_KEYS = Object.freeze([
|
|
220
|
+
"path",
|
|
221
|
+
"fileId",
|
|
222
|
+
"sha256",
|
|
223
|
+
"bytes",
|
|
224
|
+
"mtimeMs",
|
|
225
|
+
"mode",
|
|
226
|
+
"uid",
|
|
227
|
+
"gid",
|
|
228
|
+
]);
|
|
229
|
+
|
|
230
|
+
function sanitizeLinuxDescriptorScrubberEvidence(value, launch) {
|
|
231
|
+
const descriptors = exactOwnDataDescriptors(
|
|
232
|
+
value,
|
|
233
|
+
LINUX_DESCRIPTOR_SCRUBBER_EVIDENCE_KEYS,
|
|
234
|
+
);
|
|
235
|
+
const identity = descriptors?.executableIdentity?.value;
|
|
236
|
+
const identityDescriptors = exactOwnDataDescriptors(
|
|
237
|
+
identity,
|
|
238
|
+
LINUX_DESCRIPTOR_SCRUBBER_IDENTITY_KEYS,
|
|
239
|
+
);
|
|
240
|
+
const fileId = identityDescriptors?.fileId?.value;
|
|
241
|
+
const fileIdDescriptors = exactOwnDataDescriptors(fileId, ["dev", "ino"]);
|
|
242
|
+
const nodeIpcChildFd = launch?.nodeIpcChildFd ?? null;
|
|
243
|
+
const expectedInjection =
|
|
244
|
+
nodeIpcChildFd === null ? "none" : "node-child-process-exact-ipc-v1";
|
|
245
|
+
const expectedSerialization = nodeIpcChildFd === null ? null : "json";
|
|
246
|
+
if (
|
|
247
|
+
!descriptors ||
|
|
248
|
+
!launch ||
|
|
249
|
+
!identityDescriptors ||
|
|
250
|
+
!fileIdDescriptors ||
|
|
251
|
+
descriptors.kind.value !== LINUX_BWRAP_DESCRIPTOR_SCRUBBER_KIND ||
|
|
252
|
+
descriptors.mechanism.value !== LINUX_BWRAP_DESCRIPTOR_SCRUBBER_MECHANISM ||
|
|
253
|
+
descriptors.scriptSha256.value !==
|
|
254
|
+
LINUX_BWRAP_DESCRIPTOR_SCRUBBER_SCRIPT_SHA256 ||
|
|
255
|
+
descriptors.executablePinned.value !== true ||
|
|
256
|
+
descriptors.argvFixed.value !== true ||
|
|
257
|
+
descriptors.callerEnvironmentFixed.value !== true ||
|
|
258
|
+
descriptors.nodeRuntimeEnvironmentInjection.value !== expectedInjection ||
|
|
259
|
+
descriptors.nodeIpcChildFd.value !== nodeIpcChildFd ||
|
|
260
|
+
descriptors.nodeIpcSerializationMode.value !== expectedSerialization ||
|
|
261
|
+
descriptors.procSelfFdPasses.value !==
|
|
262
|
+
LINUX_BWRAP_DESCRIPTOR_SCRUBBER_PASSES ||
|
|
263
|
+
descriptors.closesUnknownInheritedDescriptors.value !== true ||
|
|
264
|
+
descriptors.verificationPassesFailClosed.value !== true ||
|
|
265
|
+
descriptors.policyBound.value !== true ||
|
|
266
|
+
descriptors.scrubberChildFd.value !== launch.scrubberChildFd ||
|
|
267
|
+
descriptors.preservedMaxFd.value !== launch.preservedMaxFd ||
|
|
268
|
+
descriptors.activeStdioThrough.value !== launch.activeStdioThrough ||
|
|
269
|
+
descriptors.executableChildFd.value !== launch.executableChildFd ||
|
|
270
|
+
identityDescriptors.path.value !== LINUX_BWRAP_DESCRIPTOR_SCRUBBER_PATH ||
|
|
271
|
+
typeof fileIdDescriptors.dev.value !== "string" ||
|
|
272
|
+
!/^(0|[1-9]\d*)$/.test(fileIdDescriptors.dev.value) ||
|
|
273
|
+
typeof fileIdDescriptors.ino.value !== "string" ||
|
|
274
|
+
!/^(0|[1-9]\d*)$/.test(fileIdDescriptors.ino.value) ||
|
|
275
|
+
typeof identityDescriptors.sha256.value !== "string" ||
|
|
276
|
+
!/^[a-f0-9]{64}$/.test(identityDescriptors.sha256.value) ||
|
|
277
|
+
!Number.isSafeInteger(identityDescriptors.bytes.value) ||
|
|
278
|
+
identityDescriptors.bytes.value <= 0 ||
|
|
279
|
+
identityDescriptors.bytes.value > 256 * 1024 * 1024 ||
|
|
280
|
+
!Number.isFinite(identityDescriptors.mtimeMs.value) ||
|
|
281
|
+
!Number.isSafeInteger(identityDescriptors.mode.value) ||
|
|
282
|
+
(identityDescriptors.mode.value & 0o170000) !== 0o100000 ||
|
|
283
|
+
(identityDescriptors.mode.value & 0o111) === 0 ||
|
|
284
|
+
(identityDescriptors.mode.value & 0o022) !== 0 ||
|
|
285
|
+
identityDescriptors.uid.value !== 0 ||
|
|
286
|
+
!Number.isSafeInteger(identityDescriptors.gid.value) ||
|
|
287
|
+
identityDescriptors.gid.value < 0
|
|
288
|
+
) {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
const sanitizedIdentity = Object.freeze({
|
|
292
|
+
path: identityDescriptors.path.value,
|
|
293
|
+
fileId: Object.freeze({
|
|
294
|
+
dev: fileIdDescriptors.dev.value,
|
|
295
|
+
ino: fileIdDescriptors.ino.value,
|
|
296
|
+
}),
|
|
297
|
+
sha256: identityDescriptors.sha256.value,
|
|
298
|
+
bytes: identityDescriptors.bytes.value,
|
|
299
|
+
mtimeMs: identityDescriptors.mtimeMs.value,
|
|
300
|
+
mode: identityDescriptors.mode.value,
|
|
301
|
+
uid: identityDescriptors.uid.value,
|
|
302
|
+
gid: identityDescriptors.gid.value,
|
|
303
|
+
});
|
|
304
|
+
return Object.freeze({
|
|
305
|
+
kind: descriptors.kind.value,
|
|
306
|
+
mechanism: descriptors.mechanism.value,
|
|
307
|
+
scriptSha256: descriptors.scriptSha256.value,
|
|
308
|
+
executableIdentity: sanitizedIdentity,
|
|
309
|
+
executablePinned: true,
|
|
310
|
+
argvFixed: true,
|
|
311
|
+
callerEnvironmentFixed: true,
|
|
312
|
+
nodeRuntimeEnvironmentInjection: expectedInjection,
|
|
313
|
+
nodeIpcChildFd,
|
|
314
|
+
nodeIpcSerializationMode: expectedSerialization,
|
|
315
|
+
procSelfFdPasses: LINUX_BWRAP_DESCRIPTOR_SCRUBBER_PASSES,
|
|
316
|
+
closesUnknownInheritedDescriptors: true,
|
|
317
|
+
verificationPassesFailClosed: true,
|
|
318
|
+
policyBound: true,
|
|
319
|
+
scrubberChildFd: launch.scrubberChildFd,
|
|
320
|
+
preservedMaxFd: launch.preservedMaxFd,
|
|
321
|
+
activeStdioThrough: launch.activeStdioThrough,
|
|
322
|
+
executableChildFd: launch.executableChildFd,
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function parseLinuxRuntimePathnameClosurePolicyArgs(
|
|
327
|
+
args,
|
|
328
|
+
expectedLoadSetFiles,
|
|
329
|
+
) {
|
|
330
|
+
if (
|
|
331
|
+
!Array.isArray(args) ||
|
|
332
|
+
!Number.isSafeInteger(expectedLoadSetFiles) ||
|
|
333
|
+
expectedLoadSetFiles < 1 ||
|
|
334
|
+
expectedLoadSetFiles > 512
|
|
335
|
+
) {
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
const targetSeparator = args.indexOf("--");
|
|
339
|
+
if (targetSeparator < 1) return null;
|
|
340
|
+
const policyArgs = args.slice(0, targetSeparator);
|
|
341
|
+
let index = 0;
|
|
342
|
+
const consume = (...expected) => {
|
|
343
|
+
if (
|
|
344
|
+
expected.some(
|
|
345
|
+
(expectedValue, offset) => policyArgs[index + offset] !== expectedValue,
|
|
346
|
+
)
|
|
347
|
+
) {
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
index += expected.length;
|
|
351
|
+
return true;
|
|
352
|
+
};
|
|
353
|
+
if (!consume(...LINUX_RUNTIME_PATHNAME_POLICY_PREFIX)) return null;
|
|
354
|
+
|
|
355
|
+
const directories = [];
|
|
356
|
+
while (policyArgs[index] === "--dir") {
|
|
357
|
+
const directory = policyArgs[index + 1];
|
|
358
|
+
if (
|
|
359
|
+
typeof directory !== "string" ||
|
|
360
|
+
!path.posix.isAbsolute(directory) ||
|
|
361
|
+
path.posix.normalize(directory) !== directory ||
|
|
362
|
+
directory === "/"
|
|
363
|
+
) {
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
directories.push(directory);
|
|
367
|
+
index += 2;
|
|
368
|
+
}
|
|
369
|
+
const orderedDirectories = [...directories].sort((left, right) => {
|
|
370
|
+
const depth =
|
|
371
|
+
left.split("/").filter(Boolean).length -
|
|
372
|
+
right.split("/").filter(Boolean).length;
|
|
373
|
+
return depth || left.localeCompare(right);
|
|
374
|
+
});
|
|
375
|
+
if (
|
|
376
|
+
directories.length < LINUX_RUNTIME_PATHNAME_POLICY_DIRECTORIES.length ||
|
|
377
|
+
new Set(directories).size !== directories.length ||
|
|
378
|
+
JSON.stringify(directories) !== JSON.stringify(orderedDirectories) ||
|
|
379
|
+
!LINUX_RUNTIME_PATHNAME_POLICY_DIRECTORIES.every((directory) =>
|
|
380
|
+
directories.includes(directory),
|
|
381
|
+
)
|
|
382
|
+
) {
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (
|
|
387
|
+
!consume(
|
|
388
|
+
"--perms",
|
|
389
|
+
"0000",
|
|
390
|
+
"--file",
|
|
391
|
+
"3",
|
|
392
|
+
"/run/.chainless-bwrap-supervisor",
|
|
393
|
+
)
|
|
394
|
+
) {
|
|
395
|
+
return null;
|
|
396
|
+
}
|
|
397
|
+
const permittedLoadDestination = (destination) =>
|
|
398
|
+
typeof destination === "string" &&
|
|
399
|
+
path.posix.isAbsolute(destination) &&
|
|
400
|
+
path.posix.normalize(destination) === destination &&
|
|
401
|
+
(destination === "/opt/chainless/runtime/node" ||
|
|
402
|
+
destination === "/etc/ld.so.cache" ||
|
|
403
|
+
destination.startsWith("/opt/chainless/plugin/") ||
|
|
404
|
+
["/lib/", "/lib64/", "/usr/lib/", "/usr/lib64/"].some((prefix) =>
|
|
405
|
+
destination.startsWith(prefix),
|
|
406
|
+
));
|
|
407
|
+
const loadDestinations = [];
|
|
408
|
+
for (let mountIndex = 0; mountIndex < expectedLoadSetFiles; mountIndex += 1) {
|
|
409
|
+
const expectedChildFd = String(4 + mountIndex);
|
|
410
|
+
let destination;
|
|
411
|
+
let mountMode;
|
|
412
|
+
let permissions = null;
|
|
413
|
+
if (policyArgs[index] === "--ro-bind-fd") {
|
|
414
|
+
if (policyArgs[index + 1] !== expectedChildFd) return null;
|
|
415
|
+
mountMode = "ro-bind-fd";
|
|
416
|
+
destination = policyArgs[index + 2];
|
|
417
|
+
index += 3;
|
|
418
|
+
} else if (policyArgs[index] === "--perms") {
|
|
419
|
+
permissions = policyArgs[index + 1];
|
|
420
|
+
if (
|
|
421
|
+
(permissions !== "0400" && permissions !== "0500") ||
|
|
422
|
+
policyArgs[index + 2] !== "--ro-bind-data" ||
|
|
423
|
+
policyArgs[index + 3] !== expectedChildFd
|
|
424
|
+
) {
|
|
425
|
+
return null;
|
|
426
|
+
}
|
|
427
|
+
mountMode = "ro-bind-data";
|
|
428
|
+
destination = policyArgs[index + 4];
|
|
429
|
+
index += 5;
|
|
430
|
+
} else {
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
if (!permittedLoadDestination(destination)) return null;
|
|
434
|
+
const runtimeSnapshotDestination =
|
|
435
|
+
destination === "/opt/chainless/runtime/node";
|
|
436
|
+
const pluginSnapshotDestination = destination.startsWith(
|
|
437
|
+
"/opt/chainless/plugin/",
|
|
438
|
+
);
|
|
439
|
+
if (
|
|
440
|
+
(runtimeSnapshotDestination &&
|
|
441
|
+
(mountMode !== "ro-bind-data" || permissions !== "0500")) ||
|
|
442
|
+
(pluginSnapshotDestination && mountMode !== "ro-bind-data") ||
|
|
443
|
+
(!runtimeSnapshotDestination &&
|
|
444
|
+
!pluginSnapshotDestination &&
|
|
445
|
+
mountMode !== "ro-bind-fd")
|
|
446
|
+
) {
|
|
447
|
+
return null;
|
|
448
|
+
}
|
|
449
|
+
loadDestinations.push(destination);
|
|
450
|
+
}
|
|
451
|
+
if (new Set(loadDestinations).size !== loadDestinations.length) return null;
|
|
452
|
+
|
|
453
|
+
const requiredDirectories = new Set(
|
|
454
|
+
LINUX_RUNTIME_PATHNAME_POLICY_DIRECTORIES,
|
|
455
|
+
);
|
|
456
|
+
for (const destination of loadDestinations) {
|
|
457
|
+
let parent = path.posix.dirname(destination);
|
|
458
|
+
while (parent !== "/") {
|
|
459
|
+
requiredDirectories.add(parent);
|
|
460
|
+
parent = path.posix.dirname(parent);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
if (
|
|
464
|
+
![...requiredDirectories].every((directory) =>
|
|
465
|
+
directories.includes(directory),
|
|
466
|
+
) ||
|
|
467
|
+
directories.some(
|
|
468
|
+
(directory) =>
|
|
469
|
+
!requiredDirectories.has(directory) &&
|
|
470
|
+
!directory.startsWith("/opt/chainless/plugin/"),
|
|
471
|
+
)
|
|
472
|
+
) {
|
|
473
|
+
return null;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
if (
|
|
477
|
+
!consume("--seccomp", String(4 + expectedLoadSetFiles)) ||
|
|
478
|
+
!consume("--remount-ro", "/") ||
|
|
479
|
+
!consume(
|
|
480
|
+
"--perms",
|
|
481
|
+
"0755",
|
|
482
|
+
"--size",
|
|
483
|
+
String(16 * 1024 * 1024),
|
|
484
|
+
"--tmpfs",
|
|
485
|
+
"/run",
|
|
486
|
+
"--remount-ro",
|
|
487
|
+
"/run",
|
|
488
|
+
)
|
|
489
|
+
) {
|
|
490
|
+
return null;
|
|
491
|
+
}
|
|
492
|
+
for (const [key, value] of LINUX_RUNTIME_PATHNAME_POLICY_ENVIRONMENT) {
|
|
493
|
+
if (!consume("--setenv", key, value)) return null;
|
|
494
|
+
}
|
|
495
|
+
if (!consume("--chdir", "/opt/chainless/plugin")) return null;
|
|
496
|
+
if (index !== policyArgs.length) return null;
|
|
497
|
+
return Object.freeze({
|
|
498
|
+
targetSeparator,
|
|
499
|
+
loadDestinations: Object.freeze(loadDestinations),
|
|
500
|
+
});
|
|
501
|
+
}
|
|
68
502
|
|
|
69
503
|
// Keep the broker on the shared CommonJS trace singleton so CommonJS and ESM
|
|
70
504
|
// consumers observe the same AsyncLocalStorage without loader warnings.
|
|
@@ -1078,6 +1512,15 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1078
1512
|
"Sandbox adapter returned no spawn plan",
|
|
1079
1513
|
);
|
|
1080
1514
|
}
|
|
1515
|
+
const authorityPlan = plan;
|
|
1516
|
+
const planSnapshot = ownDataObjectSnapshot(plan);
|
|
1517
|
+
if (!planSnapshot) {
|
|
1518
|
+
throw this._sandboxError(
|
|
1519
|
+
"invalid_sandbox_plan",
|
|
1520
|
+
"Sandbox spawn plan must use own data properties",
|
|
1521
|
+
);
|
|
1522
|
+
}
|
|
1523
|
+
plan = planSnapshot;
|
|
1081
1524
|
if (plan.contractVersion !== 1) {
|
|
1082
1525
|
throw this._sandboxError(
|
|
1083
1526
|
"invalid_sandbox_plan",
|
|
@@ -1090,16 +1533,34 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1090
1533
|
"Sandbox spawn plan is missing applied:boolean",
|
|
1091
1534
|
);
|
|
1092
1535
|
}
|
|
1093
|
-
|
|
1536
|
+
let planCommand = null;
|
|
1537
|
+
try {
|
|
1538
|
+
const commandDescriptor = Object.getOwnPropertyDescriptor(
|
|
1539
|
+
plan,
|
|
1540
|
+
"command",
|
|
1541
|
+
);
|
|
1542
|
+
if (
|
|
1543
|
+
commandDescriptor &&
|
|
1544
|
+
"value" in commandDescriptor &&
|
|
1545
|
+
typeof commandDescriptor.value === "string"
|
|
1546
|
+
) {
|
|
1547
|
+
planCommand = commandDescriptor.value;
|
|
1548
|
+
}
|
|
1549
|
+
} catch {
|
|
1550
|
+
planCommand = null;
|
|
1551
|
+
}
|
|
1552
|
+
const planArgsSnapshot = denseOwnDataArraySnapshot(plan.args);
|
|
1553
|
+
if (planCommand === null || !planArgsSnapshot) {
|
|
1094
1554
|
throw this._sandboxError(
|
|
1095
1555
|
"invalid_sandbox_plan",
|
|
1096
|
-
"Sandbox spawn plan must provide command and args",
|
|
1556
|
+
"Sandbox spawn plan must provide command and dense data-property args",
|
|
1097
1557
|
);
|
|
1098
1558
|
}
|
|
1099
|
-
|
|
1559
|
+
const planOptionsSnapshot = ownDataObjectSnapshot(plan.options);
|
|
1560
|
+
if (!planOptionsSnapshot) {
|
|
1100
1561
|
throw this._sandboxError(
|
|
1101
1562
|
"invalid_sandbox_plan",
|
|
1102
|
-
"Sandbox spawn plan must provide options",
|
|
1563
|
+
"Sandbox spawn plan must provide data-property options",
|
|
1103
1564
|
);
|
|
1104
1565
|
}
|
|
1105
1566
|
if (plan.applied && typeof plan.enforcement !== "string") {
|
|
@@ -1159,6 +1620,129 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1159
1620
|
"Sandbox policy digest must be a lowercase SHA-256 value",
|
|
1160
1621
|
);
|
|
1161
1622
|
}
|
|
1623
|
+
const linuxDescriptorBackend =
|
|
1624
|
+
plan.applied === true &&
|
|
1625
|
+
(backend === "linux-bwrap" || backend === "linux-bwrap-workspace");
|
|
1626
|
+
const linuxFdCodeSnapshotBackend =
|
|
1627
|
+
plan.applied === true &&
|
|
1628
|
+
(backend === "linux-fd-code-snapshot" ||
|
|
1629
|
+
plan.enforcement === "linux-fd-code-snapshot");
|
|
1630
|
+
let linuxDescriptorLaunch = null;
|
|
1631
|
+
let linuxDescriptorPtyLaunch = false;
|
|
1632
|
+
let linuxBubblewrapExecutableArgs = planArgsSnapshot;
|
|
1633
|
+
let sanitizedDescriptorScrubber = null;
|
|
1634
|
+
if (linuxFdCodeSnapshotBackend) {
|
|
1635
|
+
if (plan.platform !== "linux") {
|
|
1636
|
+
throw this._sandboxError(
|
|
1637
|
+
"invalid_sandbox_plan",
|
|
1638
|
+
"Reserved Linux FD code snapshot backend requires platform linux",
|
|
1639
|
+
);
|
|
1640
|
+
}
|
|
1641
|
+
if (
|
|
1642
|
+
plan.backend !== "linux-fd-code-snapshot" ||
|
|
1643
|
+
plan.enforcement !== "linux-fd-code-snapshot"
|
|
1644
|
+
) {
|
|
1645
|
+
throw this._sandboxError(
|
|
1646
|
+
"invalid_sandbox_plan",
|
|
1647
|
+
"Reserved Linux FD code snapshot backend requires exact backend and enforcement names",
|
|
1648
|
+
);
|
|
1649
|
+
}
|
|
1650
|
+
if (launchContext.builtInSandboxAdapter !== true) {
|
|
1651
|
+
throw this._sandboxError(
|
|
1652
|
+
"invalid_sandbox_plan",
|
|
1653
|
+
"Applied Linux FD code snapshot plans require the built-in sandbox adapter",
|
|
1654
|
+
);
|
|
1655
|
+
}
|
|
1656
|
+
if (!guarantees.includes(SANDBOX_BOUNDARIES.CODE_SNAPSHOT)) {
|
|
1657
|
+
throw this._sandboxError(
|
|
1658
|
+
"invalid_sandbox_plan",
|
|
1659
|
+
"Reserved Linux FD code snapshot backend requires the code-snapshot guarantee",
|
|
1660
|
+
);
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
if (linuxDescriptorBackend) {
|
|
1664
|
+
if (plan.platform !== "linux") {
|
|
1665
|
+
throw this._sandboxError(
|
|
1666
|
+
"invalid_sandbox_plan",
|
|
1667
|
+
"Reserved Linux bubblewrap backends require platform linux",
|
|
1668
|
+
);
|
|
1669
|
+
}
|
|
1670
|
+
if (launchContext.builtInSandboxAdapter !== true) {
|
|
1671
|
+
throw this._sandboxError(
|
|
1672
|
+
"invalid_sandbox_plan",
|
|
1673
|
+
"Applied Linux bubblewrap plans require the built-in sandbox adapter",
|
|
1674
|
+
);
|
|
1675
|
+
}
|
|
1676
|
+
const descriptorEvidence = plan.runtimeProbe?.descriptorScrubber;
|
|
1677
|
+
const descriptorEvidenceDescriptors = exactOwnDataDescriptors(
|
|
1678
|
+
descriptorEvidence,
|
|
1679
|
+
LINUX_DESCRIPTOR_SCRUBBER_EVIDENCE_KEYS,
|
|
1680
|
+
);
|
|
1681
|
+
const activeStdioThrough =
|
|
1682
|
+
backend === "linux-bwrap-workspace"
|
|
1683
|
+
? descriptorEvidenceDescriptors?.activeStdioThrough?.value
|
|
1684
|
+
: 2;
|
|
1685
|
+
linuxDescriptorPtyLaunch =
|
|
1686
|
+
backend === "linux-bwrap-workspace" &&
|
|
1687
|
+
plan.ptyPolicy !== null &&
|
|
1688
|
+
plan.ptyPolicy !== undefined;
|
|
1689
|
+
if (linuxDescriptorPtyLaunch) {
|
|
1690
|
+
const innerArgs = Object.freeze([...planArgsSnapshot.slice(2)]);
|
|
1691
|
+
linuxDescriptorLaunch =
|
|
1692
|
+
planArgsSnapshot[0] === "--ctty" &&
|
|
1693
|
+
typeof planArgsSnapshot[1] === "string"
|
|
1694
|
+
? parseLinuxBwrapDescriptorScrubbedLaunch(
|
|
1695
|
+
planArgsSnapshot[1],
|
|
1696
|
+
innerArgs,
|
|
1697
|
+
planOptionsSnapshot,
|
|
1698
|
+
{ activeStdioThrough },
|
|
1699
|
+
)
|
|
1700
|
+
: null;
|
|
1701
|
+
} else {
|
|
1702
|
+
linuxDescriptorLaunch = parseLinuxBwrapDescriptorScrubbedLaunch(
|
|
1703
|
+
planCommand,
|
|
1704
|
+
planArgsSnapshot,
|
|
1705
|
+
planOptionsSnapshot,
|
|
1706
|
+
{ activeStdioThrough },
|
|
1707
|
+
);
|
|
1708
|
+
}
|
|
1709
|
+
sanitizedDescriptorScrubber = sanitizeLinuxDescriptorScrubberEvidence(
|
|
1710
|
+
descriptorEvidence,
|
|
1711
|
+
linuxDescriptorLaunch,
|
|
1712
|
+
);
|
|
1713
|
+
const expectedExecutableChildFd = linuxDescriptorPtyLaunch
|
|
1714
|
+
? activeStdioThrough + 2
|
|
1715
|
+
: backend === "linux-bwrap-workspace"
|
|
1716
|
+
? activeStdioThrough + 1
|
|
1717
|
+
: 3;
|
|
1718
|
+
const outerPtyDescriptorValid =
|
|
1719
|
+
!linuxDescriptorPtyLaunch ||
|
|
1720
|
+
(planCommand === `/proc/self/fd/${activeStdioThrough + 1}` &&
|
|
1721
|
+
Number.isSafeInteger(
|
|
1722
|
+
linuxDescriptorLaunch?.stdio?.[activeStdioThrough + 1],
|
|
1723
|
+
));
|
|
1724
|
+
if (
|
|
1725
|
+
!linuxDescriptorLaunch ||
|
|
1726
|
+
!sanitizedDescriptorScrubber ||
|
|
1727
|
+
linuxDescriptorLaunch.executableChildFd !== expectedExecutableChildFd ||
|
|
1728
|
+
!outerPtyDescriptorValid ||
|
|
1729
|
+
(backend === "linux-bwrap" &&
|
|
1730
|
+
(linuxDescriptorLaunch.activeStdioThrough !== 2 ||
|
|
1731
|
+
linuxDescriptorLaunch.nodeIpcChildFd !== null ||
|
|
1732
|
+
(plan.ptyPolicy !== null && plan.ptyPolicy !== undefined)))
|
|
1733
|
+
) {
|
|
1734
|
+
throw this._sandboxError(
|
|
1735
|
+
"invalid_sandbox_plan",
|
|
1736
|
+
"Applied Linux bubblewrap plans require the exact typed descriptor scrubber launch contract",
|
|
1737
|
+
);
|
|
1738
|
+
}
|
|
1739
|
+
linuxBubblewrapExecutableArgs = linuxDescriptorLaunch.executableArgs;
|
|
1740
|
+
} else if (plan.runtimeProbe?.descriptorScrubber !== undefined) {
|
|
1741
|
+
throw this._sandboxError(
|
|
1742
|
+
"invalid_sandbox_plan",
|
|
1743
|
+
"Linux descriptor scrubber evidence requires an applied bubblewrap backend",
|
|
1744
|
+
);
|
|
1745
|
+
}
|
|
1162
1746
|
let runtimeProbe = null;
|
|
1163
1747
|
let genericWorkspaceProbe = false;
|
|
1164
1748
|
let sanitizedFilesystemPolicy = null;
|
|
@@ -1166,6 +1750,7 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1166
1750
|
let sanitizedProcessTreePolicy = null;
|
|
1167
1751
|
let sanitizedPtyPolicy = null;
|
|
1168
1752
|
let windowsPlanBindingConsumed = false;
|
|
1753
|
+
let macPlanBindingConsumed = false;
|
|
1169
1754
|
if (plan.runtimeProbe !== null && plan.runtimeProbe !== undefined) {
|
|
1170
1755
|
if (
|
|
1171
1756
|
typeof plan.runtimeProbe !== "object" ||
|
|
@@ -1196,6 +1781,14 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1196
1781
|
"initialDynamicLoadClosureScope",
|
|
1197
1782
|
"initialDynamicLoadClosureMechanism",
|
|
1198
1783
|
"initialDynamicInterpreter",
|
|
1784
|
+
"runtimeSharedLibraryPathnameClosureExcludes",
|
|
1785
|
+
"runtimeSharedLibraryClosureScope",
|
|
1786
|
+
"runtimeSharedLibraryClosureMechanism",
|
|
1787
|
+
"targetDescriptorAllowlist",
|
|
1788
|
+
"targetRuntimeInvocationMode",
|
|
1789
|
+
"helperTeamIdentifier",
|
|
1790
|
+
"helperPackageIdentifier",
|
|
1791
|
+
"helperPackageVersion",
|
|
1199
1792
|
]) {
|
|
1200
1793
|
if (
|
|
1201
1794
|
plan.runtimeProbe[field] !== undefined &&
|
|
@@ -1220,6 +1813,35 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1220
1813
|
"runtimeLaunchAtomic",
|
|
1221
1814
|
"mcpCapsuleCodeSnapshot",
|
|
1222
1815
|
"runtimeDetachedChildSpawnVerified",
|
|
1816
|
+
"runtimeSharedLibraryPathnameClosure",
|
|
1817
|
+
"runtimeLoadSetPolicyBound",
|
|
1818
|
+
"runtimeWritableFilesystems",
|
|
1819
|
+
"runtimeProcfsMounted",
|
|
1820
|
+
"runtimeDevfsMounted",
|
|
1821
|
+
"runtimeScratchWritable",
|
|
1822
|
+
"runtimeDescriptorReopenPaths",
|
|
1823
|
+
"rootProtectedRuntimeSnapshot",
|
|
1824
|
+
"entryRootOwnedAnonymousSnapshot",
|
|
1825
|
+
"entrySourcePrePostStat",
|
|
1826
|
+
"entryWriterClosedBeforeReadonlyReopen",
|
|
1827
|
+
"entryReadonlyIdentityRechecked",
|
|
1828
|
+
"entryUnlinkedAndDirectoryFsyncedBeforeTarget",
|
|
1829
|
+
"targetInheritedEntrySnapshotOnly",
|
|
1830
|
+
"runtimeAndCapsuleSlotsNullBeforeExec",
|
|
1831
|
+
"bootstrapClosesNullAndReadyDescriptors",
|
|
1832
|
+
"actualRuntimeReadyHandshake",
|
|
1833
|
+
"runtimeSnapshotUnlinkedBeforeEntryRelease",
|
|
1834
|
+
"callerCredentialDropIrreversible",
|
|
1835
|
+
"relayParentCredentialsDropped",
|
|
1836
|
+
"callerLifelineWatched",
|
|
1837
|
+
"signalRelayNonblocking",
|
|
1838
|
+
"pkgExecPathMagicBound",
|
|
1839
|
+
"capsuleRootDescriptorBound",
|
|
1840
|
+
"capsulePathObjectAtomic",
|
|
1841
|
+
"sandboxProfileFixedAndDigestBound",
|
|
1842
|
+
"processForkExplicitlyDenied",
|
|
1843
|
+
"sandboxExecLiveGateContract",
|
|
1844
|
+
"globalLaunchSerialization",
|
|
1223
1845
|
]) {
|
|
1224
1846
|
if (
|
|
1225
1847
|
plan.runtimeProbe[field] !== undefined &&
|
|
@@ -1236,10 +1858,14 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1236
1858
|
"pluginTreeContentSnapshotBytes",
|
|
1237
1859
|
"initialDynamicDependencyCount",
|
|
1238
1860
|
"initialDynamicRuntimeFileCount",
|
|
1861
|
+
"initialDynamicRuntimeBytes",
|
|
1862
|
+
"runtimeSharedLibraryLoadSetFiles",
|
|
1863
|
+
"runtimeSharedLibraryLoadSetBytes",
|
|
1239
1864
|
"runtimeSnapshotBytes",
|
|
1240
1865
|
"runtimeAttestedBytes",
|
|
1241
1866
|
"entrySnapshotBytes",
|
|
1242
1867
|
"capabilityCount",
|
|
1868
|
+
"maximumStaleSnapshots",
|
|
1243
1869
|
]) {
|
|
1244
1870
|
if (
|
|
1245
1871
|
plan.runtimeProbe[field] !== undefined &&
|
|
@@ -1256,6 +1882,13 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1256
1882
|
"runtimeSnapshotSha256",
|
|
1257
1883
|
"runtimeAttestedSha256",
|
|
1258
1884
|
"entrySnapshotSha256",
|
|
1885
|
+
"entrySnapshotBootstrapSha256",
|
|
1886
|
+
"helperSha256",
|
|
1887
|
+
"helperSourceSha256",
|
|
1888
|
+
"helperProtocolSha256",
|
|
1889
|
+
"helperInstallContractSha256",
|
|
1890
|
+
"helperDesignatedRequirementSha256",
|
|
1891
|
+
"installAttestationDigest",
|
|
1259
1892
|
"planBindingDigest",
|
|
1260
1893
|
]) {
|
|
1261
1894
|
if (
|
|
@@ -1272,17 +1905,22 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1272
1905
|
const planBindingDeclared =
|
|
1273
1906
|
plan.runtimeProbe.planBindingMechanism !== undefined ||
|
|
1274
1907
|
plan.runtimeProbe.planBindingDigest !== undefined;
|
|
1908
|
+
const typedCodeSnapshotPlanBinding =
|
|
1909
|
+
(plan.platform === "win32" &&
|
|
1910
|
+
plan.runtimeProbe.planBindingMechanism ===
|
|
1911
|
+
"windows-mcp-code-snapshot-plan-binding-v1") ||
|
|
1912
|
+
(plan.platform === "darwin" &&
|
|
1913
|
+
plan.runtimeProbe.planBindingMechanism ===
|
|
1914
|
+
"macos-mcp-code-snapshot-plan-binding-v1");
|
|
1275
1915
|
if (
|
|
1276
1916
|
planBindingDeclared &&
|
|
1277
|
-
(
|
|
1917
|
+
(!typedCodeSnapshotPlanBinding ||
|
|
1278
1918
|
!guarantees.includes(SANDBOX_BOUNDARIES.CODE_SNAPSHOT) ||
|
|
1279
|
-
plan.runtimeProbe.planBindingMechanism !==
|
|
1280
|
-
"windows-mcp-code-snapshot-plan-binding-v1" ||
|
|
1281
1919
|
!/^[a-f0-9]{64}$/.test(plan.runtimeProbe.planBindingDigest || ""))
|
|
1282
1920
|
) {
|
|
1283
1921
|
throw this._sandboxError(
|
|
1284
1922
|
"invalid_sandbox_plan",
|
|
1285
|
-
"Sandbox runtime probe plan binding must use
|
|
1923
|
+
"Sandbox runtime probe plan binding must use a typed platform MCP code-snapshot contract",
|
|
1286
1924
|
);
|
|
1287
1925
|
}
|
|
1288
1926
|
if (
|
|
@@ -1311,6 +1949,19 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1311
1949
|
"Sandbox runtime probe initialDynamicLoadClosureDigest must be a lowercase SHA-256 value",
|
|
1312
1950
|
);
|
|
1313
1951
|
}
|
|
1952
|
+
if (
|
|
1953
|
+
plan.runtimeProbe.runtimeSharedLibraryLoadSetDigest !== undefined &&
|
|
1954
|
+
(typeof plan.runtimeProbe.runtimeSharedLibraryLoadSetDigest !==
|
|
1955
|
+
"string" ||
|
|
1956
|
+
!/^[a-f0-9]{64}$/.test(
|
|
1957
|
+
plan.runtimeProbe.runtimeSharedLibraryLoadSetDigest,
|
|
1958
|
+
))
|
|
1959
|
+
) {
|
|
1960
|
+
throw this._sandboxError(
|
|
1961
|
+
"invalid_sandbox_plan",
|
|
1962
|
+
"Sandbox runtime probe runtimeSharedLibraryLoadSetDigest must be a lowercase SHA-256 value",
|
|
1963
|
+
);
|
|
1964
|
+
}
|
|
1314
1965
|
const pluginTreeSnapshot =
|
|
1315
1966
|
plan.runtimeProbe.pluginTreeContentSnapshot === true;
|
|
1316
1967
|
const pluginTreeEvidenceFields = [
|
|
@@ -1486,6 +2137,8 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1486
2137
|
}
|
|
1487
2138
|
const supervisorBound =
|
|
1488
2139
|
plan.runtimeProbe.supervisorDescriptorBound === true;
|
|
2140
|
+
const runtimeSharedLibraryPathnameClosure =
|
|
2141
|
+
plan.runtimeProbe.runtimeSharedLibraryPathnameClosure === true;
|
|
1489
2142
|
if (
|
|
1490
2143
|
supervisorBound &&
|
|
1491
2144
|
(plan.runtimeProbe.supervisorExecutablePinned !== true ||
|
|
@@ -1494,7 +2147,10 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1494
2147
|
"host-path-replacement" ||
|
|
1495
2148
|
plan.runtimeProbe.supervisorDescriptorBindingMechanism !==
|
|
1496
2149
|
"pinned-child-fd3-file-consume-run-overmount-v1" ||
|
|
1497
|
-
plan.runtimeProbe.supervisorPid1ExecutableExposure !==
|
|
2150
|
+
plan.runtimeProbe.supervisorPid1ExecutableExposure !==
|
|
2151
|
+
(runtimeSharedLibraryPathnameClosure
|
|
2152
|
+
? "procfs-not-mounted"
|
|
2153
|
+
: "procfs"))
|
|
1498
2154
|
) {
|
|
1499
2155
|
throw this._sandboxError(
|
|
1500
2156
|
"invalid_sandbox_plan",
|
|
@@ -1527,6 +2183,7 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1527
2183
|
"initialDynamicInterpreter",
|
|
1528
2184
|
"initialDynamicDependencyCount",
|
|
1529
2185
|
"initialDynamicRuntimeFileCount",
|
|
2186
|
+
"initialDynamicRuntimeBytes",
|
|
1530
2187
|
"initialDynamicLoadClosureDigest",
|
|
1531
2188
|
];
|
|
1532
2189
|
const initialDynamicInterpreter =
|
|
@@ -1535,6 +2192,8 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1535
2192
|
plan.runtimeProbe.initialDynamicDependencyCount;
|
|
1536
2193
|
const initialDynamicRuntimeFileCount =
|
|
1537
2194
|
plan.runtimeProbe.initialDynamicRuntimeFileCount;
|
|
2195
|
+
const initialDynamicRuntimeBytes =
|
|
2196
|
+
plan.runtimeProbe.initialDynamicRuntimeBytes;
|
|
1538
2197
|
const successfulDynamicProbe =
|
|
1539
2198
|
plan.applied === true &&
|
|
1540
2199
|
plan.runtimeProbe.kind ===
|
|
@@ -1564,11 +2223,12 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1564
2223
|
plan.runtimeProbe.contentSnapshotMechanism !==
|
|
1565
2224
|
"verified-o_tmpfile-copy-bwrap-ro-bind-data-v1" ||
|
|
1566
2225
|
plan.runtimeProbe.handleAtomic !== false ||
|
|
2226
|
+
plan.runtimeProbe.sharedLibraryClosure !== false ||
|
|
1567
2227
|
!supervisorBound ||
|
|
1568
2228
|
plan.runtimeProbe.initialDynamicLoadClosureScope !==
|
|
1569
|
-
"initial-pt_interp-and-
|
|
2229
|
+
"initial-pt_interp-and-recursive-dt_needed-attested-system-graph" ||
|
|
1570
2230
|
plan.runtimeProbe.initialDynamicLoadClosureMechanism !==
|
|
1571
|
-
"parsed-elf-
|
|
2231
|
+
"recursive-parsed-elf-system-graph-to-attested-runtime-fds-v1" ||
|
|
1572
2232
|
typeof initialDynamicInterpreter !== "string" ||
|
|
1573
2233
|
!path.posix.isAbsolute(initialDynamicInterpreter) ||
|
|
1574
2234
|
path.posix.normalize(initialDynamicInterpreter) !==
|
|
@@ -1578,20 +2238,20 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1578
2238
|
) ||
|
|
1579
2239
|
!Number.isSafeInteger(initialDynamicDependencyCount) ||
|
|
1580
2240
|
initialDynamicDependencyCount < 0 ||
|
|
1581
|
-
initialDynamicDependencyCount >
|
|
2241
|
+
initialDynamicDependencyCount > 1024 ||
|
|
1582
2242
|
!Number.isSafeInteger(initialDynamicRuntimeFileCount) ||
|
|
1583
2243
|
initialDynamicRuntimeFileCount < 1 ||
|
|
1584
|
-
initialDynamicRuntimeFileCount >
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
2244
|
+
initialDynamicRuntimeFileCount > 256 ||
|
|
2245
|
+
!Number.isSafeInteger(initialDynamicRuntimeBytes) ||
|
|
2246
|
+
initialDynamicRuntimeBytes < 1 ||
|
|
2247
|
+
initialDynamicRuntimeBytes > 512 * 1024 * 1024 ||
|
|
1588
2248
|
!/^[a-f0-9]{64}$/.test(
|
|
1589
2249
|
plan.runtimeProbe.initialDynamicLoadClosureDigest || "",
|
|
1590
2250
|
))
|
|
1591
2251
|
) {
|
|
1592
2252
|
throw this._sandboxError(
|
|
1593
2253
|
"invalid_sandbox_plan",
|
|
1594
|
-
"Sandbox runtime probe initial dynamic
|
|
2254
|
+
"Sandbox runtime probe initial recursive dynamic system graph evidence must use the typed descriptor-bound contract",
|
|
1595
2255
|
);
|
|
1596
2256
|
}
|
|
1597
2257
|
if (
|
|
@@ -1602,13 +2262,89 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1602
2262
|
) {
|
|
1603
2263
|
throw this._sandboxError(
|
|
1604
2264
|
"invalid_sandbox_plan",
|
|
1605
|
-
"Sandbox runtime probe initial dynamic
|
|
2265
|
+
"Sandbox runtime probe initial recursive dynamic system graph evidence requires initialDynamicLoadClosureDescriptorBound",
|
|
1606
2266
|
);
|
|
1607
2267
|
}
|
|
1608
2268
|
if (successfulDynamicProbe && !initialDynamicLoadClosureBound) {
|
|
1609
2269
|
throw this._sandboxError(
|
|
1610
2270
|
"invalid_sandbox_plan",
|
|
1611
|
-
"Sandbox runtime probe successful dynamic ELF evidence requires a descriptor-bound initial
|
|
2271
|
+
"Sandbox runtime probe successful dynamic ELF evidence requires a descriptor-bound initial recursive system graph",
|
|
2272
|
+
);
|
|
2273
|
+
}
|
|
2274
|
+
const runtimePathnameClosureEvidenceFields = [
|
|
2275
|
+
"runtimeSharedLibraryPathnameClosureExcludes",
|
|
2276
|
+
"runtimeSharedLibraryClosureScope",
|
|
2277
|
+
"runtimeSharedLibraryClosureMechanism",
|
|
2278
|
+
"runtimeSharedLibraryLoadSetFiles",
|
|
2279
|
+
"runtimeSharedLibraryLoadSetBytes",
|
|
2280
|
+
"runtimeSharedLibraryLoadSetDigest",
|
|
2281
|
+
"runtimeLoadSetPolicyBound",
|
|
2282
|
+
"runtimeWritableFilesystems",
|
|
2283
|
+
"runtimeProcfsMounted",
|
|
2284
|
+
"runtimeDevfsMounted",
|
|
2285
|
+
"runtimeScratchWritable",
|
|
2286
|
+
"runtimeDescriptorReopenPaths",
|
|
2287
|
+
];
|
|
2288
|
+
const runtimePathnameMountPolicy =
|
|
2289
|
+
parseLinuxRuntimePathnameClosurePolicyArgs(
|
|
2290
|
+
linuxBubblewrapExecutableArgs,
|
|
2291
|
+
plan.runtimeProbe.runtimeSharedLibraryLoadSetFiles,
|
|
2292
|
+
) !== null;
|
|
2293
|
+
if (
|
|
2294
|
+
runtimeSharedLibraryPathnameClosure &&
|
|
2295
|
+
(!successfulDynamicProbe ||
|
|
2296
|
+
!initialDynamicLoadClosureBound ||
|
|
2297
|
+
plan.runtimeProbe.sharedLibraryClosure !== false ||
|
|
2298
|
+
plan.runtimeProbe.runtimeSharedLibraryPathnameClosureExcludes !==
|
|
2299
|
+
"anonymous-jit-and-custom-in-process-loader" ||
|
|
2300
|
+
plan.runtimeProbe.runtimeSharedLibraryClosureScope !==
|
|
2301
|
+
"all-pathname-visible-regular-files-in-read-only-bwrap-namespace" ||
|
|
2302
|
+
plan.runtimeProbe.runtimeSharedLibraryClosureMechanism !==
|
|
2303
|
+
"descriptor-pinned-hashed-ro-mount-set-plus-loader-fd-and-namespace-mutation-seccomp-v2" ||
|
|
2304
|
+
!Number.isSafeInteger(
|
|
2305
|
+
plan.runtimeProbe.runtimeSharedLibraryLoadSetFiles,
|
|
2306
|
+
) ||
|
|
2307
|
+
plan.runtimeProbe.runtimeSharedLibraryLoadSetFiles < 1 ||
|
|
2308
|
+
plan.runtimeProbe.runtimeSharedLibraryLoadSetFiles > 512 ||
|
|
2309
|
+
!Number.isSafeInteger(
|
|
2310
|
+
plan.runtimeProbe.runtimeSharedLibraryLoadSetBytes,
|
|
2311
|
+
) ||
|
|
2312
|
+
plan.runtimeProbe.runtimeSharedLibraryLoadSetBytes < 1 ||
|
|
2313
|
+
plan.runtimeProbe.runtimeSharedLibraryLoadSetBytes >
|
|
2314
|
+
1024 * 1024 * 1024 ||
|
|
2315
|
+
!/^[a-f0-9]{64}$/.test(
|
|
2316
|
+
plan.runtimeProbe.runtimeSharedLibraryLoadSetDigest || "",
|
|
2317
|
+
) ||
|
|
2318
|
+
plan.runtimeProbe.runtimeLoadSetPolicyBound !== true ||
|
|
2319
|
+
plan.runtimeProbe.runtimeWritableFilesystems !== false ||
|
|
2320
|
+
plan.runtimeProbe.runtimeProcfsMounted !== false ||
|
|
2321
|
+
plan.runtimeProbe.runtimeDevfsMounted !== false ||
|
|
2322
|
+
plan.runtimeProbe.runtimeScratchWritable !== false ||
|
|
2323
|
+
plan.runtimeProbe.runtimeDescriptorReopenPaths !== false ||
|
|
2324
|
+
plan.runtimeProbe.supervisorPid1ExecutableExposure !==
|
|
2325
|
+
"procfs-not-mounted" ||
|
|
2326
|
+
!runtimePathnameMountPolicy)
|
|
2327
|
+
) {
|
|
2328
|
+
throw this._sandboxError(
|
|
2329
|
+
"invalid_sandbox_plan",
|
|
2330
|
+
"Sandbox runtime probe pathname shared-library closure must use the typed read-only no-proc bwrap contract",
|
|
2331
|
+
);
|
|
2332
|
+
}
|
|
2333
|
+
if (
|
|
2334
|
+
!runtimeSharedLibraryPathnameClosure &&
|
|
2335
|
+
runtimePathnameClosureEvidenceFields.some(
|
|
2336
|
+
(field) => plan.runtimeProbe[field] !== undefined,
|
|
2337
|
+
)
|
|
2338
|
+
) {
|
|
2339
|
+
throw this._sandboxError(
|
|
2340
|
+
"invalid_sandbox_plan",
|
|
2341
|
+
"Sandbox runtime probe pathname shared-library evidence requires runtimeSharedLibraryPathnameClosure",
|
|
2342
|
+
);
|
|
2343
|
+
}
|
|
2344
|
+
if (successfulDynamicProbe && !runtimeSharedLibraryPathnameClosure) {
|
|
2345
|
+
throw this._sandboxError(
|
|
2346
|
+
"invalid_sandbox_plan",
|
|
2347
|
+
"Successful dynamic ELF evidence requires a runtime pathname shared-library closure",
|
|
1612
2348
|
);
|
|
1613
2349
|
}
|
|
1614
2350
|
const codeSnapshotGuaranteed = guarantees.includes(
|
|
@@ -1623,11 +2359,28 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1623
2359
|
plan.platform === "win32" &&
|
|
1624
2360
|
(plan.runtimeProbe.planBindingMechanism !== undefined ||
|
|
1625
2361
|
plan.runtimeProbe.planBindingDigest !== undefined);
|
|
1626
|
-
|
|
2362
|
+
const macPlanBindingDeclared =
|
|
2363
|
+
plan.platform === "darwin" &&
|
|
2364
|
+
(plan.runtimeProbe.planBindingMechanism !== undefined ||
|
|
2365
|
+
plan.runtimeProbe.planBindingDigest !== undefined);
|
|
2366
|
+
// Consume before evaluating any other privileged-helper evidence. A genuine
|
|
1627
2367
|
// one-launch plan is therefore burned by its first admission attempt,
|
|
1628
2368
|
// including an attempt with a mismatched command or contract.
|
|
1629
2369
|
windowsPlanBindingConsumed = windowsPlanBindingDeclared
|
|
1630
|
-
? consumeWindowsMcpCodeSnapshotPlanBinding(
|
|
2370
|
+
? consumeWindowsMcpCodeSnapshotPlanBinding(authorityPlan, {
|
|
2371
|
+
command: launchContext.command,
|
|
2372
|
+
args: launchArgs,
|
|
2373
|
+
cwd: launchContext.cwd,
|
|
2374
|
+
shell: launchContext.shell,
|
|
2375
|
+
detached: launchContext.detached,
|
|
2376
|
+
executionContract,
|
|
2377
|
+
profile: launchContext.profile,
|
|
2378
|
+
requiredBoundaries: launchContext.requiredBoundaries,
|
|
2379
|
+
sync: launchContext.sync,
|
|
2380
|
+
})
|
|
2381
|
+
: false;
|
|
2382
|
+
macPlanBindingConsumed = macPlanBindingDeclared
|
|
2383
|
+
? consumeMacMcpCodeSnapshotPlanBinding(authorityPlan, {
|
|
1631
2384
|
command: launchContext.command,
|
|
1632
2385
|
args: launchArgs,
|
|
1633
2386
|
cwd: launchContext.cwd,
|
|
@@ -1674,6 +2427,8 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1674
2427
|
executionContract?.runtimeIdentity?.bytes &&
|
|
1675
2428
|
plan.runtimeProbe.runtimeAttestedSha256 === undefined &&
|
|
1676
2429
|
plan.runtimeProbe.runtimeAttestedBytes === undefined;
|
|
2430
|
+
const macRuntimeSnapshotContractBound =
|
|
2431
|
+
linuxRuntimeSnapshotContractBound;
|
|
1677
2432
|
const windowsRuntimeAttestationContractBound =
|
|
1678
2433
|
plan.runtimeProbe.runtimeAttestedSha256 ===
|
|
1679
2434
|
executionContract?.runtimeIdentity?.sha256 &&
|
|
@@ -1712,6 +2467,7 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1712
2467
|
plan.runtimeProbe.entrySnapshotBytes >= 0 &&
|
|
1713
2468
|
plan.runtimeProbe.entrySnapshotBytes <= 64 * 1024 * 1024;
|
|
1714
2469
|
const linuxSnapshotEvidence =
|
|
2470
|
+
launchContext.builtInSandboxAdapter === true &&
|
|
1715
2471
|
plan.platform === "linux" &&
|
|
1716
2472
|
backend === "linux-fd-code-snapshot" &&
|
|
1717
2473
|
plan.enforcement === "linux-fd-code-snapshot" &&
|
|
@@ -1736,16 +2492,18 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1736
2492
|
Number.isSafeInteger(plan.runtimeProbe.runtimeSnapshotBytes) &&
|
|
1737
2493
|
plan.runtimeProbe.runtimeSnapshotBytes > 0 &&
|
|
1738
2494
|
plan.runtimeProbe.runtimeSnapshotBytes <= 256 * 1024 * 1024 &&
|
|
1739
|
-
/^\/proc\/self\/fd\/\d+$/.test(
|
|
1740
|
-
|
|
2495
|
+
/^\/proc\/self\/fd\/\d+$/.test(planCommand) &&
|
|
2496
|
+
planArgsSnapshot[0] === "-e" &&
|
|
1741
2497
|
crypto
|
|
1742
2498
|
.createHash("sha256")
|
|
1743
|
-
.update(
|
|
2499
|
+
.update(planArgsSnapshot[1] || "")
|
|
1744
2500
|
.digest("hex") === MCP_STDIO_FD_ENTRY_BOOTSTRAP_SHA256 &&
|
|
1745
|
-
|
|
1746
|
-
passthroughArgsMatch(
|
|
1747
|
-
const linuxBubblewrapTargetSeparator =
|
|
2501
|
+
planArgsSnapshot[2] === "--" &&
|
|
2502
|
+
passthroughArgsMatch(planArgsSnapshot.slice(3));
|
|
2503
|
+
const linuxBubblewrapTargetSeparator =
|
|
2504
|
+
linuxBubblewrapExecutableArgs.indexOf("--");
|
|
1748
2505
|
const linuxBubblewrapSnapshotEvidence =
|
|
2506
|
+
launchContext.builtInSandboxAdapter === true &&
|
|
1749
2507
|
plan.platform === "linux" &&
|
|
1750
2508
|
backend === "linux-bwrap" &&
|
|
1751
2509
|
plan.enforcement === "linux-bwrap" &&
|
|
@@ -1776,15 +2534,137 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1776
2534
|
Number.isSafeInteger(plan.runtimeProbe.runtimeSnapshotBytes) &&
|
|
1777
2535
|
plan.runtimeProbe.runtimeSnapshotBytes > 0 &&
|
|
1778
2536
|
plan.runtimeProbe.runtimeSnapshotBytes <= 256 * 1024 * 1024 &&
|
|
1779
|
-
/^\/proc\/self\/fd\/\d+$/.test(
|
|
2537
|
+
/^\/proc\/self\/fd\/\d+$/.test(planCommand) &&
|
|
1780
2538
|
linuxBubblewrapTargetSeparator >= 0 &&
|
|
1781
|
-
|
|
2539
|
+
linuxBubblewrapExecutableArgs[linuxBubblewrapTargetSeparator + 1] ===
|
|
1782
2540
|
plan.runtimeProbe.runtimeLaunchPath &&
|
|
1783
|
-
|
|
2541
|
+
linuxBubblewrapExecutableArgs[linuxBubblewrapTargetSeparator + 2] ===
|
|
1784
2542
|
plan.runtimeProbe.entrySnapshotPath &&
|
|
1785
2543
|
passthroughArgsMatch(
|
|
1786
|
-
|
|
2544
|
+
linuxBubblewrapExecutableArgs.slice(
|
|
2545
|
+
linuxBubblewrapTargetSeparator + 3,
|
|
2546
|
+
),
|
|
1787
2547
|
);
|
|
2548
|
+
const macProtocol = MACOS_MCP_LAUNCHER_INPUTS.protocol;
|
|
2549
|
+
const macStdio = planOptionsSnapshot.stdio;
|
|
2550
|
+
const macSnapshotPath = path.posix.join(
|
|
2551
|
+
macProtocol.snapshotRoot,
|
|
2552
|
+
planArgsSnapshot[1] || "invalid",
|
|
2553
|
+
"node",
|
|
2554
|
+
);
|
|
2555
|
+
const macSnapshotEvidence =
|
|
2556
|
+
plan.platform === "darwin" &&
|
|
2557
|
+
backend === macProtocol.backend &&
|
|
2558
|
+
plan.enforcement === macProtocol.backend &&
|
|
2559
|
+
policyAttested === true &&
|
|
2560
|
+
policyDigest !== null &&
|
|
2561
|
+
plan.runtimeProbe.kind === "darwin-mcp-capsule-code-snapshot-v2" &&
|
|
2562
|
+
plan.runtimeProbe.contentSnapshotScope ===
|
|
2563
|
+
"mcp-capsule-entry-and-node-runtime" &&
|
|
2564
|
+
plan.runtimeProbe.contentSnapshotMechanism ===
|
|
2565
|
+
"signed-root-runtime-path-and-anonymous-entry-fd-snapshots-v1" &&
|
|
2566
|
+
plan.runtimeProbe.handleAtomic === true &&
|
|
2567
|
+
plan.runtimeProbe.entrySnapshotAtomic === true &&
|
|
2568
|
+
plan.runtimeProbe.runtimeLaunchAtomic === true &&
|
|
2569
|
+
plan.runtimeProbe.runtimeLaunchMechanism ===
|
|
2570
|
+
"signed-root-helper-fd-copy-protected-path-ready-gate-v1" &&
|
|
2571
|
+
plan.runtimeProbe.entrySnapshotBootstrapSha256 ===
|
|
2572
|
+
MCP_STDIO_MACOS_GATED_ENTRY_BOOTSTRAP_SHA256 &&
|
|
2573
|
+
macRuntimeSnapshotContractBound &&
|
|
2574
|
+
plan.runtimeProbe.runtimeSnapshotBytes > 0 &&
|
|
2575
|
+
plan.runtimeProbe.runtimeSnapshotBytes <= 256 * 1024 * 1024 &&
|
|
2576
|
+
plan.runtimeProbe.entrySnapshotBytes <= 64 * 1024 * 1024 &&
|
|
2577
|
+
plan.runtimeProbe.rootProtectedRuntimeSnapshot === true &&
|
|
2578
|
+
plan.runtimeProbe.entryRootOwnedAnonymousSnapshot === true &&
|
|
2579
|
+
plan.runtimeProbe.entrySourcePrePostStat === true &&
|
|
2580
|
+
plan.runtimeProbe.entryWriterClosedBeforeReadonlyReopen === true &&
|
|
2581
|
+
plan.runtimeProbe.entryReadonlyIdentityRechecked === true &&
|
|
2582
|
+
plan.runtimeProbe.entryUnlinkedAndDirectoryFsyncedBeforeTarget ===
|
|
2583
|
+
true &&
|
|
2584
|
+
plan.runtimeProbe.targetInheritedEntrySnapshotOnly === true &&
|
|
2585
|
+
plan.runtimeProbe.runtimeAndCapsuleSlotsNullBeforeExec === true &&
|
|
2586
|
+
plan.runtimeProbe.bootstrapClosesNullAndReadyDescriptors === true &&
|
|
2587
|
+
plan.runtimeProbe.actualRuntimeReadyHandshake === true &&
|
|
2588
|
+
plan.runtimeProbe.runtimeSnapshotUnlinkedBeforeEntryRelease ===
|
|
2589
|
+
true &&
|
|
2590
|
+
plan.runtimeProbe.callerCredentialDropIrreversible === true &&
|
|
2591
|
+
plan.runtimeProbe.relayParentCredentialsDropped === true &&
|
|
2592
|
+
plan.runtimeProbe.callerLifelineWatched === true &&
|
|
2593
|
+
plan.runtimeProbe.signalRelayNonblocking === true &&
|
|
2594
|
+
((plan.runtimeProbe.targetRuntimeInvocationMode ===
|
|
2595
|
+
"node-executable-eval-v1" &&
|
|
2596
|
+
plan.runtimeProbe.pkgExecPathMagicBound === false) ||
|
|
2597
|
+
(plan.runtimeProbe.targetRuntimeInvocationMode ===
|
|
2598
|
+
"pkg-copied-executable-eval-v1" &&
|
|
2599
|
+
plan.runtimeProbe.pkgExecPathMagicBound === true &&
|
|
2600
|
+
planOptionsSnapshot.env?.PKG_EXECPATH ===
|
|
2601
|
+
MACOS_PKG_EXECPATH_MAGIC)) &&
|
|
2602
|
+
plan.runtimeProbe.targetDescriptorAllowlist ===
|
|
2603
|
+
"stdio-fd3-null-fd4-entry-fd5-null-fd6-gate-fd7-ready" &&
|
|
2604
|
+
plan.runtimeProbe.capsuleRootDescriptorBound === true &&
|
|
2605
|
+
plan.runtimeProbe.capsulePathObjectAtomic === false &&
|
|
2606
|
+
plan.runtimeProbe.sandboxProfileFixedAndDigestBound === true &&
|
|
2607
|
+
plan.runtimeProbe.processForkExplicitlyDenied === true &&
|
|
2608
|
+
plan.runtimeProbe.sandboxExecLiveGateContract === true &&
|
|
2609
|
+
plan.runtimeProbe.globalLaunchSerialization === true &&
|
|
2610
|
+
plan.runtimeProbe.maximumStaleSnapshots === 8 &&
|
|
2611
|
+
plan.runtimeProbe.helperSourceSha256 ===
|
|
2612
|
+
MACOS_MCP_LAUNCHER_INPUTS.sourceSha256 &&
|
|
2613
|
+
plan.runtimeProbe.helperProtocolSha256 ===
|
|
2614
|
+
MACOS_MCP_LAUNCHER_INPUTS.protocolSha256 &&
|
|
2615
|
+
[
|
|
2616
|
+
"helperSha256",
|
|
2617
|
+
"helperInstallContractSha256",
|
|
2618
|
+
"helperDesignatedRequirementSha256",
|
|
2619
|
+
"installAttestationDigest",
|
|
2620
|
+
"planBindingDigest",
|
|
2621
|
+
].every((field) =>
|
|
2622
|
+
/^[a-f0-9]{64}$/.test(plan.runtimeProbe[field] || ""),
|
|
2623
|
+
) &&
|
|
2624
|
+
/^[A-Z0-9]{10}$/.test(plan.runtimeProbe.helperTeamIdentifier || "") &&
|
|
2625
|
+
plan.runtimeProbe.helperPackageIdentifier ===
|
|
2626
|
+
macProtocol.packageIdentifier &&
|
|
2627
|
+
isMacosMcpLauncherPackageVersion(
|
|
2628
|
+
plan.runtimeProbe.helperPackageVersion,
|
|
2629
|
+
) &&
|
|
2630
|
+
plan.runtimeProbe.planBindingMechanism ===
|
|
2631
|
+
"macos-mcp-code-snapshot-plan-binding-v1" &&
|
|
2632
|
+
plan.runtimeProbe.runtimeLaunchPath === macSnapshotPath &&
|
|
2633
|
+
plan.runtimeProbe.entrySnapshotPath === "anonymous-root-owned-fd4" &&
|
|
2634
|
+
planCommand === macProtocol.helperInstallPath &&
|
|
2635
|
+
planArgsSnapshot.length >= 10 &&
|
|
2636
|
+
planArgsSnapshot[0] === "--launch-v1" &&
|
|
2637
|
+
/^[a-f0-9]{64}$/.test(planArgsSnapshot[1] || "") &&
|
|
2638
|
+
planArgsSnapshot[2] === MACOS_MCP_LAUNCHER_INPUTS.protocolSha256 &&
|
|
2639
|
+
planArgsSnapshot[3] === executionContract.runtimeIdentity.sha256 &&
|
|
2640
|
+
planArgsSnapshot[4] ===
|
|
2641
|
+
String(executionContract.runtimeIdentity.bytes) &&
|
|
2642
|
+
planArgsSnapshot[5] === executionContract.entryIdentity.sha256 &&
|
|
2643
|
+
planArgsSnapshot[6] ===
|
|
2644
|
+
String(executionContract.entryIdentity.bytes) &&
|
|
2645
|
+
/^[1-9]\d*$/.test(planArgsSnapshot[7] || "") &&
|
|
2646
|
+
/^[1-9]\d*$/.test(planArgsSnapshot[8] || "") &&
|
|
2647
|
+
planArgsSnapshot[9] === policyDigest &&
|
|
2648
|
+
passthroughArgsMatch(planArgsSnapshot.slice(10)) &&
|
|
2649
|
+
planOptionsSnapshot.cwd === "/" &&
|
|
2650
|
+
planOptionsSnapshot.shell === false &&
|
|
2651
|
+
planOptionsSnapshot.detached === false &&
|
|
2652
|
+
Array.isArray(macStdio) &&
|
|
2653
|
+
macStdio.length === 9 &&
|
|
2654
|
+
macStdio
|
|
2655
|
+
.slice(0, 3)
|
|
2656
|
+
.every((value) => ["pipe", "ignore"].includes(value)) &&
|
|
2657
|
+
macStdio.slice(3, 6).every(Number.isInteger) &&
|
|
2658
|
+
macStdio[6] === "ignore" &&
|
|
2659
|
+
macStdio[7] === "ignore" &&
|
|
2660
|
+
macStdio[8] === "pipe" &&
|
|
2661
|
+
launchContext.builtInSandboxAdapter === true &&
|
|
2662
|
+
macPlanBindingConsumed &&
|
|
2663
|
+
guarantees.includes(SANDBOX_BOUNDARIES.FILESYSTEM) &&
|
|
2664
|
+
guarantees.includes(SANDBOX_BOUNDARIES.NETWORK) &&
|
|
2665
|
+
guarantees.includes(SANDBOX_BOUNDARIES.PROCESS_EXEC) &&
|
|
2666
|
+
guarantees.includes(SANDBOX_BOUNDARIES.PROCESS_TREE) &&
|
|
2667
|
+
guarantees.includes(SANDBOX_BOUNDARIES.PRIVILEGE_REDUCTION);
|
|
1788
2668
|
const windowsSnapshotEvidence =
|
|
1789
2669
|
plan.platform === "win32" &&
|
|
1790
2670
|
[
|
|
@@ -1826,6 +2706,7 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1826
2706
|
!exactSnapshotEvidence ||
|
|
1827
2707
|
(!linuxSnapshotEvidence &&
|
|
1828
2708
|
!linuxBubblewrapSnapshotEvidence &&
|
|
2709
|
+
!macSnapshotEvidence &&
|
|
1829
2710
|
!windowsSnapshotEvidence)
|
|
1830
2711
|
) {
|
|
1831
2712
|
throw this._sandboxError(
|
|
@@ -1935,12 +2816,12 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1935
2816
|
ptyPolicy.launcherDescriptorConsumedBeforeTarget === true &&
|
|
1936
2817
|
ptyPolicy.launcherStagingPathHidden === true &&
|
|
1937
2818
|
ptyPolicy.bwrapNewSession === false &&
|
|
1938
|
-
|
|
1939
|
-
/^\/proc\/self\/fd\/\d+$/.test(
|
|
1940
|
-
!
|
|
2819
|
+
planArgsSnapshot[0] === "--ctty" &&
|
|
2820
|
+
/^\/proc\/self\/fd\/\d+$/.test(planArgsSnapshot[1] || "") &&
|
|
2821
|
+
!linuxBubblewrapExecutableArgs.includes("--new-session")
|
|
1941
2822
|
: ptyPolicy === null &&
|
|
1942
|
-
|
|
1943
|
-
|
|
2823
|
+
planArgsSnapshot[0] !== "--ctty" &&
|
|
2824
|
+
linuxBubblewrapExecutableArgs.includes("--new-session");
|
|
1944
2825
|
const workspaceRoot = filesystemPolicy?.workspaceRoot;
|
|
1945
2826
|
const workingDirectory = filesystemPolicy?.workingDirectory;
|
|
1946
2827
|
const workspaceRelative =
|
|
@@ -1948,7 +2829,19 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
1948
2829
|
typeof workingDirectory === "string"
|
|
1949
2830
|
? path.posix.relative(workspaceRoot, workingDirectory)
|
|
1950
2831
|
: "..";
|
|
2832
|
+
const genericExecutionContract = launchContext.executionContract;
|
|
2833
|
+
const genericExecutionContractBound =
|
|
2834
|
+
launchContext.builtInSandboxAdapter === true &&
|
|
2835
|
+
verifyLinuxGenericBubblewrapPlan(authorityPlan) &&
|
|
2836
|
+
genericExecutionContract?.contractVersion === 1 &&
|
|
2837
|
+
genericExecutionContract.kind === LINUX_GENERIC_CONTRACT_KIND &&
|
|
2838
|
+
genericExecutionContract.contractDigest ===
|
|
2839
|
+
plan.runtimeProbe.contractDigest &&
|
|
2840
|
+
genericExecutionContract.workspaceRoot === workspaceRoot &&
|
|
2841
|
+
genericExecutionContract.workingDirectory === workingDirectory &&
|
|
2842
|
+
launchContext.cwd === workingDirectory;
|
|
1951
2843
|
genericWorkspaceProbe =
|
|
2844
|
+
genericExecutionContractBound &&
|
|
1952
2845
|
plan.applied === true &&
|
|
1953
2846
|
plan.platform === "linux" &&
|
|
1954
2847
|
plan.enforcement === "linux-bwrap-workspace" &&
|
|
@@ -2036,20 +2929,20 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
2036
2929
|
processTreePolicy?.parentDeathSignal === "SIGKILL" &&
|
|
2037
2930
|
processTreePolicy?.asPid1 === false &&
|
|
2038
2931
|
processTreePolicy?.closeFence === "pid-namespace-empty-or-killed" &&
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
Array.isArray(
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
!
|
|
2051
|
-
|
|
2052
|
-
!
|
|
2932
|
+
planCommand.startsWith("/proc/self/fd/") &&
|
|
2933
|
+
linuxDescriptorLaunch.options.cwd === "/" &&
|
|
2934
|
+
linuxDescriptorLaunch.options.shell === false &&
|
|
2935
|
+
linuxDescriptorLaunch.options.detached === false &&
|
|
2936
|
+
Array.isArray(linuxDescriptorLaunch.stdio) &&
|
|
2937
|
+
linuxBubblewrapExecutableArgs.includes("--bind-fd") &&
|
|
2938
|
+
linuxBubblewrapExecutableArgs.includes("--ro-bind-fd") &&
|
|
2939
|
+
linuxBubblewrapExecutableArgs.includes("--remount-ro") &&
|
|
2940
|
+
linuxBubblewrapExecutableArgs.includes("--unshare-net") &&
|
|
2941
|
+
linuxBubblewrapExecutableArgs.includes("--unshare-pid") &&
|
|
2942
|
+
linuxBubblewrapExecutableArgs.includes("--die-with-parent") &&
|
|
2943
|
+
!linuxBubblewrapExecutableArgs.includes("--as-pid-1") &&
|
|
2944
|
+
linuxBubblewrapExecutableArgs.includes("--seccomp") &&
|
|
2945
|
+
!linuxBubblewrapExecutableArgs.includes("--ro-bind") &&
|
|
2053
2946
|
ptyPlanValid;
|
|
2054
2947
|
if (!genericWorkspaceProbe) {
|
|
2055
2948
|
throw this._sandboxError(
|
|
@@ -2230,11 +3123,62 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
2230
3123
|
runtimeProbe[field] = plan.runtimeProbe[field];
|
|
2231
3124
|
}
|
|
2232
3125
|
}
|
|
3126
|
+
for (const field of [
|
|
3127
|
+
"runtimeSharedLibraryPathnameClosure",
|
|
3128
|
+
...runtimePathnameClosureEvidenceFields,
|
|
3129
|
+
]) {
|
|
3130
|
+
if (plan.runtimeProbe[field] !== undefined) {
|
|
3131
|
+
runtimeProbe[field] = plan.runtimeProbe[field];
|
|
3132
|
+
}
|
|
3133
|
+
}
|
|
3134
|
+
for (const field of [
|
|
3135
|
+
"rootProtectedRuntimeSnapshot",
|
|
3136
|
+
"entryRootOwnedAnonymousSnapshot",
|
|
3137
|
+
"entrySourcePrePostStat",
|
|
3138
|
+
"entryWriterClosedBeforeReadonlyReopen",
|
|
3139
|
+
"entryReadonlyIdentityRechecked",
|
|
3140
|
+
"entryUnlinkedAndDirectoryFsyncedBeforeTarget",
|
|
3141
|
+
"targetInheritedEntrySnapshotOnly",
|
|
3142
|
+
"runtimeAndCapsuleSlotsNullBeforeExec",
|
|
3143
|
+
"bootstrapClosesNullAndReadyDescriptors",
|
|
3144
|
+
"actualRuntimeReadyHandshake",
|
|
3145
|
+
"runtimeSnapshotUnlinkedBeforeEntryRelease",
|
|
3146
|
+
"callerCredentialDropIrreversible",
|
|
3147
|
+
"relayParentCredentialsDropped",
|
|
3148
|
+
"callerLifelineWatched",
|
|
3149
|
+
"signalRelayNonblocking",
|
|
3150
|
+
"targetRuntimeInvocationMode",
|
|
3151
|
+
"pkgExecPathMagicBound",
|
|
3152
|
+
"targetDescriptorAllowlist",
|
|
3153
|
+
"capsuleRootDescriptorBound",
|
|
3154
|
+
"capsulePathObjectAtomic",
|
|
3155
|
+
"sandboxProfileFixedAndDigestBound",
|
|
3156
|
+
"processForkExplicitlyDenied",
|
|
3157
|
+
"sandboxExecLiveGateContract",
|
|
3158
|
+
"globalLaunchSerialization",
|
|
3159
|
+
"maximumStaleSnapshots",
|
|
3160
|
+
"helperSha256",
|
|
3161
|
+
"helperSourceSha256",
|
|
3162
|
+
"helperProtocolSha256",
|
|
3163
|
+
"helperInstallContractSha256",
|
|
3164
|
+
"helperDesignatedRequirementSha256",
|
|
3165
|
+
"helperTeamIdentifier",
|
|
3166
|
+
"helperPackageIdentifier",
|
|
3167
|
+
"helperPackageVersion",
|
|
3168
|
+
"installAttestationDigest",
|
|
3169
|
+
]) {
|
|
3170
|
+
if (plan.runtimeProbe[field] !== undefined) {
|
|
3171
|
+
runtimeProbe[field] = plan.runtimeProbe[field];
|
|
3172
|
+
}
|
|
3173
|
+
}
|
|
2233
3174
|
for (const field of genericWorkspaceEvidenceFields) {
|
|
2234
3175
|
if (plan.runtimeProbe[field] !== undefined) {
|
|
2235
3176
|
runtimeProbe[field] = plan.runtimeProbe[field];
|
|
2236
3177
|
}
|
|
2237
3178
|
}
|
|
3179
|
+
if (sanitizedDescriptorScrubber !== null) {
|
|
3180
|
+
runtimeProbe.descriptorScrubber = sanitizedDescriptorScrubber;
|
|
3181
|
+
}
|
|
2238
3182
|
if (supervisorIdentity !== undefined) {
|
|
2239
3183
|
runtimeProbe.supervisorExecutableIdentity = {
|
|
2240
3184
|
path: supervisorIdentity.path,
|
|
@@ -2277,10 +3221,29 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
2277
3221
|
"Required post-spawn enforcement must declare sync or async mode",
|
|
2278
3222
|
);
|
|
2279
3223
|
}
|
|
3224
|
+
const validatedArgs = linuxDescriptorLaunch
|
|
3225
|
+
? linuxDescriptorPtyLaunch
|
|
3226
|
+
? Object.freeze([
|
|
3227
|
+
"--ctty",
|
|
3228
|
+
`/proc/self/fd/${linuxDescriptorLaunch.scrubberChildFd}`,
|
|
3229
|
+
...linuxDescriptorLaunch.launchArgs,
|
|
3230
|
+
])
|
|
3231
|
+
: linuxDescriptorLaunch.launchArgs
|
|
3232
|
+
: planArgsSnapshot;
|
|
3233
|
+
const validatedOptions = linuxDescriptorLaunch
|
|
3234
|
+
? Object.freeze({
|
|
3235
|
+
...linuxDescriptorLaunch.options,
|
|
3236
|
+
stdio: Object.freeze([...linuxDescriptorLaunch.stdio]),
|
|
3237
|
+
env: Object.freeze({
|
|
3238
|
+
...linuxDescriptorLaunch.callerEnvironment,
|
|
3239
|
+
}),
|
|
3240
|
+
})
|
|
3241
|
+
: planOptionsSnapshot;
|
|
2280
3242
|
const validatedPlan = {
|
|
2281
3243
|
...plan,
|
|
2282
|
-
|
|
2283
|
-
|
|
3244
|
+
command: planCommand,
|
|
3245
|
+
args: [...validatedArgs],
|
|
3246
|
+
options: { ...validatedOptions },
|
|
2284
3247
|
backend,
|
|
2285
3248
|
guarantees: [...new Set(guarantees)],
|
|
2286
3249
|
candidateBackend,
|
|
@@ -2305,6 +3268,14 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
2305
3268
|
};
|
|
2306
3269
|
admittedWindowsMcpCodeSnapshotPlans.add(validatedPlan);
|
|
2307
3270
|
}
|
|
3271
|
+
if (macPlanBindingConsumed) {
|
|
3272
|
+
const upstreamCleanup = validatedPlan.cleanup;
|
|
3273
|
+
validatedPlan.cleanup = (...args) => {
|
|
3274
|
+
admittedMacMcpCodeSnapshotPlans.delete(validatedPlan);
|
|
3275
|
+
return upstreamCleanup?.(...args);
|
|
3276
|
+
};
|
|
3277
|
+
admittedMacMcpCodeSnapshotPlans.add(validatedPlan);
|
|
3278
|
+
}
|
|
2308
3279
|
return validatedPlan;
|
|
2309
3280
|
}
|
|
2310
3281
|
|
|
@@ -2353,6 +3324,15 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
2353
3324
|
};
|
|
2354
3325
|
admittedWindowsMcpCodeSnapshotPlans.add(assertedPlan);
|
|
2355
3326
|
}
|
|
3327
|
+
if (admittedMacMcpCodeSnapshotPlans.has(plan)) {
|
|
3328
|
+
admittedMacMcpCodeSnapshotPlans.delete(plan);
|
|
3329
|
+
const upstreamCleanup = assertedPlan.cleanup;
|
|
3330
|
+
assertedPlan.cleanup = (...args) => {
|
|
3331
|
+
admittedMacMcpCodeSnapshotPlans.delete(assertedPlan);
|
|
3332
|
+
return upstreamCleanup?.(...args);
|
|
3333
|
+
};
|
|
3334
|
+
admittedMacMcpCodeSnapshotPlans.add(assertedPlan);
|
|
3335
|
+
}
|
|
2356
3336
|
return assertedPlan;
|
|
2357
3337
|
}
|
|
2358
3338
|
|
|
@@ -3432,6 +4412,21 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
3432
4412
|
let proc;
|
|
3433
4413
|
let workspaceProcessClosed = null;
|
|
3434
4414
|
try {
|
|
4415
|
+
const macPlanBindingDeclared =
|
|
4416
|
+
sandboxPlan.platform === "darwin" &&
|
|
4417
|
+
sandboxPlan.runtimeProbe?.planBindingMechanism ===
|
|
4418
|
+
"macos-mcp-code-snapshot-plan-binding-v1";
|
|
4419
|
+
const builtInMacMcpPlan =
|
|
4420
|
+
admittedMacMcpCodeSnapshotPlans.has(sandboxPlan);
|
|
4421
|
+
if (macPlanBindingDeclared && !builtInMacMcpPlan) {
|
|
4422
|
+
throw this._sandboxError(
|
|
4423
|
+
"macos_mcp_plan_binding_consumed",
|
|
4424
|
+
"macOS MCP sandbox plan binding is unavailable or already consumed",
|
|
4425
|
+
);
|
|
4426
|
+
}
|
|
4427
|
+
if (builtInMacMcpPlan) {
|
|
4428
|
+
admittedMacMcpCodeSnapshotPlans.delete(sandboxPlan);
|
|
4429
|
+
}
|
|
3435
4430
|
if (mcpStdioExecutableIdentityAuthority !== undefined) {
|
|
3436
4431
|
const admitted = consumeMcpStdioExecutableIdentityAuthority(
|
|
3437
4432
|
mcpStdioExecutableIdentityAuthority,
|
|
@@ -3444,6 +4439,31 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
3444
4439
|
auditEntry.mcpStdioExecutableIdentityDigest = admitted.identityDigest;
|
|
3445
4440
|
}
|
|
3446
4441
|
proc = nativeSpawnFn(command, args, optsForSpawn);
|
|
4442
|
+
if (builtInMacMcpPlan) {
|
|
4443
|
+
const callerLifeline = proc?.stdio?.[8];
|
|
4444
|
+
if (
|
|
4445
|
+
!callerLifeline ||
|
|
4446
|
+
typeof callerLifeline !== "object" ||
|
|
4447
|
+
callerLifeline.destroyed === true ||
|
|
4448
|
+
typeof callerLifeline.destroy !== "function"
|
|
4449
|
+
) {
|
|
4450
|
+
try {
|
|
4451
|
+
proc?.kill?.("SIGKILL");
|
|
4452
|
+
} catch {
|
|
4453
|
+
// The missing lifeline is already a fail-closed launch failure.
|
|
4454
|
+
}
|
|
4455
|
+
throw this._sandboxError(
|
|
4456
|
+
"macos_mcp_caller_lifeline_unavailable",
|
|
4457
|
+
"macOS MCP launch did not retain its Broker-side caller lifeline",
|
|
4458
|
+
);
|
|
4459
|
+
}
|
|
4460
|
+
Object.defineProperty(proc, "macosMcpCallerLifeline", {
|
|
4461
|
+
configurable: false,
|
|
4462
|
+
enumerable: false,
|
|
4463
|
+
writable: false,
|
|
4464
|
+
value: callerLifeline,
|
|
4465
|
+
});
|
|
4466
|
+
}
|
|
3447
4467
|
workspaceProcessClosed = this._createWorkspaceProcessCloseFence(
|
|
3448
4468
|
auditEntry,
|
|
3449
4469
|
proc,
|
|
@@ -3477,15 +4497,16 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
3477
4497
|
sandboxPlan.applied === true &&
|
|
3478
4498
|
(sandboxPlan.backend === "linux-bwrap-workspace" ||
|
|
3479
4499
|
sandboxPlan.backend === "linux-bwrap" ||
|
|
3480
|
-
sandboxPlan.backend === "linux-fd-code-snapshot"
|
|
4500
|
+
sandboxPlan.backend === "linux-fd-code-snapshot" ||
|
|
4501
|
+
sandboxPlan.backend === "macos-signed-root-fd-launcher") &&
|
|
3481
4502
|
sandboxPlan.postSpawn.required === false
|
|
3482
4503
|
) {
|
|
3483
4504
|
// child_process.spawn() has synchronously duplicated every stdio entry
|
|
3484
4505
|
// into the launched process before returning. The generic/direct bwrap
|
|
3485
|
-
// backends and the MCP
|
|
3486
|
-
//
|
|
3487
|
-
//
|
|
3488
|
-
//
|
|
4506
|
+
// backends and the MCP code-snapshot backends are complete pre-spawn
|
|
4507
|
+
// plans. macOS retains its independently created stdio[8] lifeline on
|
|
4508
|
+
// ChildProcess for the full process lifetime; cleanup closes only the
|
|
4509
|
+
// three already-duplicated source pins.
|
|
3489
4510
|
cleanupSandbox();
|
|
3490
4511
|
}
|
|
3491
4512
|
try {
|
|
@@ -3735,6 +4756,23 @@ class ProcessExecutionBroker extends EventEmitter {
|
|
|
3735
4756
|
|
|
3736
4757
|
const nativeSpawnSyncFn = this._native?.spawnSync || nativeSpawnSync;
|
|
3737
4758
|
try {
|
|
4759
|
+
const macPlanBindingDeclared =
|
|
4760
|
+
sandboxPlan.platform === "darwin" &&
|
|
4761
|
+
sandboxPlan.runtimeProbe?.planBindingMechanism ===
|
|
4762
|
+
"macos-mcp-code-snapshot-plan-binding-v1";
|
|
4763
|
+
const builtInMacMcpPlan =
|
|
4764
|
+
admittedMacMcpCodeSnapshotPlans.has(sandboxPlan);
|
|
4765
|
+
if (macPlanBindingDeclared && !builtInMacMcpPlan) {
|
|
4766
|
+
throw this._sandboxError(
|
|
4767
|
+
"macos_mcp_plan_binding_consumed",
|
|
4768
|
+
"macOS MCP sandbox plan binding is unavailable or already consumed",
|
|
4769
|
+
);
|
|
4770
|
+
}
|
|
4771
|
+
if (builtInMacMcpPlan) {
|
|
4772
|
+
// spawnSync owns the parent endpoint for stdio[8] until the helper
|
|
4773
|
+
// exits; burning before entry prevents replay on every outcome.
|
|
4774
|
+
admittedMacMcpCodeSnapshotPlans.delete(sandboxPlan);
|
|
4775
|
+
}
|
|
3738
4776
|
const result = nativeSpawnSyncFn(command, args, optsForSync);
|
|
3739
4777
|
this._settleWorkspaceTransactionSpawn(auditEntry, {
|
|
3740
4778
|
exitCode: result.status,
|