chainlesschain 0.162.179 → 0.162.181
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 +6 -3
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-BF13YdB-.js → AIOps-cq0dwbnf.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-B9y67AjF.js → ActionButton-CvcgGl3w.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-FcdDHoSC.js → Analytics-hM2-jFqg.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-CRm_zwSp.js → AppLayout-B9_Gsd_g.js} +5 -5
- package/src/assets/web-panel/assets/{Artifacts-Cbo7-usf.js → Artifacts-B7bu52Og.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-vMaLpkHC.js → Audit-DThfDgqB.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-FiUY692t.js → BackgroundAgents-DjlFiD4v.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-BK80j_GQ.js → Backup-CK9xJKnG.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-ChNMuYR1.js → BaseInput-DEiSU8K8.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-928UREpm.js → Chat-CpT96czj.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-BKPPNmZI.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-dFW-zDbe.js → Checkbox-C1GfDnO0.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-BCcNJUj2.js → Codegen-3DAKgiLx.js} +1 -1
- package/src/assets/web-panel/assets/{Col-DcEkLv70.js → Col-74cOwZU1.js} +1 -1
- package/src/assets/web-panel/assets/{Community-DihBRRqg.js → Community-tn9Kkz9j.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-DGYxwWET.js → Compact-BcoXH7m4.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-OnYe1vS4.js → Compliance-DIPGUBgi.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CmWB54c2.js → Cowork-doD5_91c.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-BrANb2uw.js → Cron-C-IDvubz.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-2HgWzSxg.js → Crosschain-CdcCoBdj.js} +1 -1
- package/src/assets/web-panel/assets/{DID-DdDwNI6K.js → DID-DdH5aMMA.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-D6PnE78-.js → Dashboard-DHLA4mm0.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-ClzvSN4O.js → Dropdown-dEeCt7Md.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BUk9B727.js → EmailListRenderer-BMaecFv9.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-C8hi3v7i.js → FamilyGuardDashboard-DUaUukTN.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-B5SP8xkg.js → Federation-CMBE0_rp.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DWzJ8AU5.js → FormItemContext-PG-JDbXq.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-3E3Q3rjG.js → GenericCardRenderer-Bcb0p88m.js} +1 -1
- package/src/assets/web-panel/assets/{Git-z8IdCMId.js → Git-Bgv15myB.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-CgqCF9lX.js → Governance-DB8YTArI.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-zgS-AuH9.js → Inference-BQMwCWaS.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-BdbgmESJ.js → KnowledgeGraph-B1_ZziiB.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BHpknnjy.js → Logs-DovEEnt_.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-D201OL4T.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-Di9sAR7j.js → Marketplace-BlCXSpyB.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-DtnR9Z_A.js → McpTools-CsCR09Wj.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-BaX9uuXD.js → Memory-CBVRLKno.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-xelyKWTY.js → MobileBridge-C9OIafgA.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-BiFTOGBN.js → MobileProjects-D_zoJ8Xs.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-bV3OzTiO.js → Mtc-vE-HdvLj.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-BkwvFTdZ.js → MtcAudit-CPLaekCd.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-_6HQQ-oC.js → Multisig-C_UP9C2o.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BBYhmWQZ.js → NLProgramming-2nODJcU1.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-Cq-6dQnU.js → Notes-BhE-SJGu.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-ILZ9zkX6.js → NotificationSettings-D21q7BNU.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-DgmTBEvk.js → OrderTableRenderer-0b62GYOD.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-CkLnWwCk.js → Organization-CEqmw_sb.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-CWVHZbhf.js → Overflow-MW-gMDO_.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BXbqETkr.js → P2P-CY0hjI_G.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser--0JR-0ex.js → PdhVaultBrowser-BbWh7Man.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-Cz9_tfSy.js → Permissions-ChqEA_4Q.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-Dq7OWYtx.js → PersonalDataHub-B3YrbYfD.js} +5 -5
- package/src/assets/web-panel/assets/{Pipeline-DHPUNcc-.js → Pipeline-B8WBhhlW.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CEAbrDkS.js → Privacy-Cmb0PXNx.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CJYfclXE.js → ProjectInit-hF6zW3Nz.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-oCTgPCgp.js → ProjectSettings-BFSVfpW0.js} +2 -2
- package/src/assets/web-panel/assets/Projects-DAWkVFkc.js +1 -0
- package/src/assets/web-panel/assets/{Providers-BLTZtzTG.js → Providers-B8yux8Dx.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-C0b0TQB3.js → QrScannerModal-N76cQluO.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-tOl6N_gM.js → QuickAsk-ClvZ0KYR.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-DPzKr8yr.js → Recommend-B-GfgBpT.js} +1 -1
- package/src/assets/web-panel/assets/RemoteSession-mlglCdQi.js +5 -0
- package/src/assets/web-panel/assets/{Reputation-Cji1Vl79.js → Reputation-DJIZzQeG.js} +1 -1
- package/src/assets/web-panel/assets/{Row-D-NERWf2.js → Row-COzxu_bb.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-DzlgmAlB.js → RssFeed-CoYsJQuE.js} +3 -3
- package/src/assets/web-panel/assets/{Search-Cs0SWSa4.js → Search-DC77Mq9S.js} +1 -1
- package/src/assets/web-panel/assets/{Security-DL7EzcUO.js → Security-Loy2EdMO.js} +4 -4
- package/src/assets/web-panel/assets/{Services-CT-PzgTd.js → Services-GUD07Eu0.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-tByJWdJg.js → Skeleton-DWzkptYU.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-Dnr_6TTl.js → Skills-CEDn1r-Z.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-4O-yq0LY.js → Sla-ub_k4pXh.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-BYBVg1oR.js → SpeechSettings-D7HLX9CA.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-CpOYPbE5.js → SyncSettings-DbwOvl6m.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-CGVhOVh6.js → Tasks-CBQzoAu5.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-BuHFxR4X.js → Templates-BNVeIhud.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-DxDxHzgf.js → Tenant-PS9AzhXU.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-B9g_nISg.js → Terminal-Cgb4eLB_.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-DlrBC_4A.js → TimelineRenderer-CrmXMOkg.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DvBlYZ6i.js → Tokens-DD-VDHw1.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-Dg8G9bhF.js → Trigger-BsoN_n-n.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-COICx4E-.js → Trust-n8LmN4ZV.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-B4pOBv7T.js → UkeySign-C9_7MImA.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-Qt4NMA8Q.js → VideoEditing-DyBteNgn.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-X1EkQc2Z.js → Wallet-BS5ixeXI.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-CyeEFBE5.js → WebAuthn-spc4UImU.js} +3 -3
- package/src/assets/web-panel/assets/{WorkflowEditor-nwzbMiVQ.js → WorkflowEditor-D7iVvaBO.js} +1 -1
- package/src/assets/web-panel/assets/chat-6CmBkHrL.js +1 -0
- package/src/assets/web-panel/assets/{colors-5Isz5lhJ.js → colors-BGoCLkxI.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-DsFQS3Oy.js → compact-item-fYZBetMO.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-OcEXp2uz.js → createContext-BeM-1UVj.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BzPwHnw8.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CZvC4p09.js → hasIn-CE7ZuEnV.js} +1 -1
- package/src/assets/web-panel/assets/{index-BF1sab0Q.js → index--lap6cf7.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7yeL3rf.js → index-ATcSr_2O.js} +1 -1
- package/src/assets/web-panel/assets/{index-VkFXA9N-.js → index-B2U-ObMq.js} +1 -1
- package/src/assets/web-panel/assets/{index-DSmGGg5h.js → index-B3CDgvNW.js} +1 -1
- package/src/assets/web-panel/assets/{index-jrNIrpq4.js → index-B4wiTEOM.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8ibl7bc.js → index-B8BsdNV_.js} +1 -1
- package/src/assets/web-panel/assets/{index-DOLozRk8.js → index-BEVm0lCS.js} +10 -10
- package/src/assets/web-panel/assets/{index-BPgc_bdR.js → index-BNZDILcO.js} +1 -1
- package/src/assets/web-panel/assets/{index-BTZZzlMO.js → index-BU_2qiDk.js} +1 -1
- package/src/assets/web-panel/assets/{index-Vubi6Tf5.js → index-BV551878.js} +1 -1
- package/src/assets/web-panel/assets/{index-nXrnztXp.js → index-BfPL-m46.js} +1 -1
- package/src/assets/web-panel/assets/{index-CN8lPVpQ.js → index-BowH1eLQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-BgE2BZl2.js → index-BsMfoaeo.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cd5b2JHB.js → index-BunaQCa0.js} +1 -1
- package/src/assets/web-panel/assets/{index-CQlGw0nQ.js → index-C0v6YKKO.js} +1 -1
- package/src/assets/web-panel/assets/{index-Do6FJK32.js → index-C4SJVjs4.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bqvo1f9T.js → index-C9Y3k0HI.js} +1 -1
- package/src/assets/web-panel/assets/{index-LUdgPZg9.js → index-CIpVrf5P.js} +1 -1
- package/src/assets/web-panel/assets/{index-BpD2O7_p.js → index-CRLjEP1H.js} +1 -1
- package/src/assets/web-panel/assets/{index-r_9NG6P7.js → index-CRnUE8Cb.js} +1 -1
- package/src/assets/web-panel/assets/{index-FIgMAfBh.js → index-Cip8emOQ.js} +1 -1
- package/src/assets/web-panel/assets/{index-RsQ1lFDV.js → index-CpIGIB85.js} +1 -1
- package/src/assets/web-panel/assets/{index-DGJupV0S.js → index-D1r9tT3J.js} +1 -1
- package/src/assets/web-panel/assets/{index-BpglwPWl.js → index-DT3zPSVX.js} +1 -1
- package/src/assets/web-panel/assets/index-DacrAdc-.js +1 -0
- package/src/assets/web-panel/assets/{index-CG3B2wCF.js → index-De0quFDw.js} +1 -1
- package/src/assets/web-panel/assets/{index-CxA2PDK1.js → index-DoXk5KJ8.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaGKOVvQ.js → index-DsvfrESp.js} +1 -1
- package/src/assets/web-panel/assets/{index-C7CtJYXq.js → index-Dw1PyYPm.js} +1 -1
- package/src/assets/web-panel/assets/index-EHzNJozo.js +1 -0
- package/src/assets/web-panel/assets/{index-Bu9NXvIa.js → index-MtOuq2i6.js} +1 -1
- package/src/assets/web-panel/assets/{index-BsZkTaa3.js → index-Puq6Luf1.js} +1 -1
- package/src/assets/web-panel/assets/{index-CPE4zHXF.js → index-QIpnpZgz.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bsb-iylv.js → index-RMZ8a7Yt.js} +1 -1
- package/src/assets/web-panel/assets/{index-DMtGRQqw.js → index-WUrJ6S1j.js} +1 -1
- package/src/assets/web-panel/assets/{index-C3lWvhk4.js → index-YjcumOZ4.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmVbCGx_.js → index-lJBjB1QX.js} +1 -1
- package/src/assets/web-panel/assets/{index-A5SHQW_M.js → index-ukg99D1V.js} +1 -1
- package/src/assets/web-panel/assets/{index-CFJgt6qM.js → index-zb7rVOhV.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-Cdgep9YT.js → initDefaultProps-CYHMs1ag.js} +1 -1
- package/src/assets/web-panel/assets/{motion-7yn1ACEm.js → motion-DDB2Ffk5.js} +1 -1
- package/src/assets/web-panel/assets/{move-D8o133Xc.js → move-Bg3cD-dX.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-CClHIG9V.js → mtc-parser-B5nedjTS.js} +1 -1
- package/src/assets/web-panel/assets/{omit-CLnrPE2d.js → omit-BHyuUILu.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-1CTWoZWl.js → pickAttrs-C9YQnEN9.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-xNNtS4Sp.js → placementArrow-DBUFYUe7.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-ypzAofs7.js → responsiveObserve-nBs2Obnk.js} +1 -1
- package/src/assets/web-panel/assets/{slide-QsrY9UwD.js → slide-DkCEaXNU.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-DSdThzOB.js → statusUtils-aqE1Wi6U.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-B_kKM8Ob.js → styleChecker-CN5bhfHB.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-CcdTBNV9.js → useFlexGapSupport-B_oX_kvJ.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-BuAH2XFU.js → useFs-rCuXHeme.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-B3zWiG4A.js → usePersonalDataHub-DZR9Abyd.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-B45Rc-CQ.js → vnode-ConCYQlX.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DaYZDU5f.js → zoom-CUdDxG5M.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/commands/agent.js +4 -1
- package/src/commands/background-session.js +2 -1
- package/src/commands/context.js +69 -2
- package/src/commands/hub.js +30 -24
- package/src/data/changelog.json +27 -1
- package/src/gateways/ws/background-agent-protocol.js +38 -0
- package/src/gateways/ws/message-dispatcher.js +1 -0
- package/src/gateways/ws/remote-session-protocol.js +65 -6
- package/src/gateways/ws/ws-server.js +8 -1
- package/src/harness/feature-flags.js +15 -8
- package/src/harness/mcp-client.js +618 -43
- package/src/lazy-dispatch.js +30 -1
- package/src/lib/agent-authority.js +22 -0
- package/src/lib/agent-core.js +2 -0
- package/src/lib/agent-sandbox.js +161 -0
- package/src/lib/agent-team/team-runner.js +22 -0
- package/src/lib/artifact-store.js +35 -0
- package/src/lib/async-hook-supervisor.cjs +13 -2
- package/src/lib/audit-mtc.js +3 -2
- package/src/lib/background-agent-supervisor.js +104 -3
- package/src/lib/background-interaction-journal.js +407 -0
- package/src/lib/background-interaction-resolver.js +23 -34
- package/src/lib/background-session-transport.js +12 -2
- package/src/lib/capability-manifest.js +41 -3
- package/src/lib/capability-negotiation.js +1 -1
- package/src/lib/channels/channel-manager.js +33 -0
- package/src/lib/channels/telegram-channel.js +23 -5
- package/src/lib/channels/webhook-channel.js +38 -15
- package/src/lib/chrome-connector.js +169 -23
- package/src/lib/config-manager.js +23 -9
- package/src/lib/context-breakdown.js +31 -0
- package/src/lib/cowork-cron.js +274 -32
- package/src/lib/cross-chain-mtc.js +3 -2
- package/src/lib/durable-security-store.js +124 -0
- package/src/lib/event-runtime-host.js +67 -6
- package/src/lib/event-runtime-store.js +163 -0
- package/src/lib/goal-store.js +32 -12
- package/src/lib/headless-manifest.js +2 -1
- package/src/lib/hook-environment.cjs +58 -0
- package/src/lib/hook-manager.js +12 -5
- package/src/lib/hook-runner.cjs +122 -28
- package/src/lib/hook-runner.js +1 -0
- package/src/lib/hooks-v2-producers.js +36 -0
- package/src/lib/hooks-v2-runtime.js +329 -52
- package/src/lib/interaction-adapter.js +60 -19
- package/src/lib/interaction-binding.js +64 -0
- package/src/lib/json-schema-output.js +439 -14
- package/src/lib/json-schema-validate.js +514 -883
- package/src/lib/lan-pairing-tokens.js +115 -57
- package/src/lib/lsp/__tests__/lsp-client.test.js +32 -0
- package/src/lib/lsp/__tests__/lsp-manager.test.js +25 -0
- package/src/lib/lsp/lsp-client.js +4 -0
- package/src/lib/lsp/lsp-manager.js +3 -0
- package/src/lib/lsp/lsp-server-registry.js +18 -0
- package/src/lib/mcp-client.js +1 -0
- package/src/lib/mcp-oauth.js +35 -21
- package/src/lib/packer/pkg-config-generator.js +1 -0
- package/src/lib/permission-decision.js +99 -0
- package/src/lib/plugin-monitor-supervisor.js +3 -0
- package/src/lib/plugin-runtime/capabilities.js +50 -0
- package/src/lib/plugin-runtime/capability-consent.js +42 -35
- package/src/lib/plugin-runtime/hooks.js +36 -9
- package/src/lib/plugin-runtime/install.js +23 -7
- package/src/lib/plugin-runtime/lsp.js +4 -0
- package/src/lib/plugin-runtime/manifest.js +50 -2
- package/src/lib/plugin-runtime/mcp.js +30 -5
- package/src/lib/plugin-runtime/monitors.js +11 -0
- package/src/lib/plugin-runtime/plugin-options.js +94 -38
- package/src/lib/plugin-runtime/policy.js +29 -2
- package/src/lib/plugin-runtime/sandbox-policy.js +84 -0
- package/src/lib/plugin-runtime/scopes.js +7 -3
- package/src/lib/plugin-runtime/trust.js +36 -31
- package/src/lib/process-execution-broker/credential-agent.js +114 -16
- package/src/lib/process-execution-broker/credential-transport-worker.js +312 -0
- package/src/lib/process-execution-broker/credential-transport.js +378 -0
- package/src/lib/process-execution-broker/index.js +408 -19
- package/src/lib/process-execution-broker/platform-sandbox.js +561 -21
- package/src/lib/process-execution-broker/windows-sandbox.ps1 +999 -0
- package/src/lib/project-mcp-trust.js +21 -26
- package/src/lib/protocol-replay.js +19 -12
- package/src/lib/settings-hooks.cjs +13 -0
- package/src/lib/skill-loader.js +83 -10
- package/src/lib/sync-credentials.js +5 -4
- package/src/lib/turn-binding.js +8 -6
- package/src/repl/agent-repl.js +113 -28
- package/src/repl/repl-turn-binding.js +5 -2
- package/src/runtime/agent-core.js +331 -26
- package/src/runtime/coding-agent-contract-shared.cjs +3 -3
- package/src/runtime/headless-runner.js +101 -4
- package/src/runtime/headless-stream.js +209 -23
- package/src/runtime/mcp-config.js +29 -17
- package/src/runtime/policies/agent-policy.js +2 -0
- package/src/workers/background-agent-worker.js +128 -13
- package/src/assets/web-panel/assets/ChatBubbleRenderer-DvySUzxJ.js +0 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-DkxCweb1.js +0 -1
- package/src/assets/web-panel/assets/Projects-ClomCrN0.js +0 -1
- package/src/assets/web-panel/assets/RemoteSession-pRgaWsUK.js +0 -4
- package/src/assets/web-panel/assets/chat-Bvl-ojg2.js +0 -1
- package/src/assets/web-panel/assets/devWarning-CSVgo71Z.js +0 -1
- package/src/assets/web-panel/assets/index-DMIWh9fu.js +0 -1
- package/src/assets/web-panel/assets/index-ssTvV1l6.js +0 -1
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Platform enforcement currently available:
|
|
5
5
|
* - macOS: Seatbelt sandbox-exec profiles
|
|
6
|
-
* - Linux: prlimit resource-limit wrapper
|
|
7
|
-
*
|
|
8
|
-
*
|
|
6
|
+
* - Linux: prlimit resource-limit wrapper, plus a non-promoting bubblewrap
|
|
7
|
+
* runtime probe for explicitly requested filesystem/network boundaries
|
|
8
|
+
* - Windows: Win32 Job Object + restricted-token wrapper
|
|
9
9
|
*
|
|
10
10
|
* Security model:
|
|
11
11
|
* Adapters return a truthful spawn plan. An unavailable primitive is never
|
|
@@ -19,6 +19,60 @@ import os from "node:os";
|
|
|
19
19
|
import path from "node:path";
|
|
20
20
|
import * as fs from "node:fs";
|
|
21
21
|
import crypto from "node:crypto";
|
|
22
|
+
import { spawnSync as nativeSpawnSync } from "node:child_process";
|
|
23
|
+
import { fileURLToPath } from "node:url";
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Stable boundary identifiers shared by broker policies, platform plans, and
|
|
27
|
+
* audit records. A guarantee means that the named restriction is enforced by
|
|
28
|
+
* the selected backend; it does not merely describe a configured intent.
|
|
29
|
+
*/
|
|
30
|
+
export const SANDBOX_BOUNDARIES = Object.freeze({
|
|
31
|
+
FILESYSTEM: "filesystem",
|
|
32
|
+
NETWORK: "network",
|
|
33
|
+
PROCESS_EXEC: "process-exec",
|
|
34
|
+
PROCESS_TREE: "process-tree",
|
|
35
|
+
RESOURCE_LIMITS: "resource-limits",
|
|
36
|
+
PRIVILEGE_REDUCTION: "privilege-reduction",
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @typedef {typeof SANDBOX_BOUNDARIES[keyof typeof SANDBOX_BOUNDARIES]} SandboxBoundary
|
|
41
|
+
*
|
|
42
|
+
* @typedef {Object} SandboxGuaranteePlan
|
|
43
|
+
* @property {1} contractVersion
|
|
44
|
+
* @property {boolean} applied
|
|
45
|
+
* @property {string} platform
|
|
46
|
+
* @property {string} profile
|
|
47
|
+
* @property {string} command
|
|
48
|
+
* @property {readonly string[]} args
|
|
49
|
+
* @property {Readonly<Object>} options
|
|
50
|
+
* @property {string|null} enforcement
|
|
51
|
+
* @property {string|null} backend
|
|
52
|
+
* @property {readonly SandboxBoundary[]} guarantees
|
|
53
|
+
* @property {string|null} reason
|
|
54
|
+
* @property {{required: boolean, mode: "none"|"sync"|"async"}} postSpawn
|
|
55
|
+
*/
|
|
56
|
+
|
|
57
|
+
const MODULE_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
58
|
+
const WINDOWS_IDENTITY_WAIT = new Int32Array(new SharedArrayBuffer(4));
|
|
59
|
+
const LINUX_BWRAP_PATH = "/usr/bin/bwrap";
|
|
60
|
+
const LINUX_BWRAP_RUNTIME_PROBE_ARGS = Object.freeze([
|
|
61
|
+
"--die-with-parent",
|
|
62
|
+
"--new-session",
|
|
63
|
+
"--unshare-all",
|
|
64
|
+
"--ro-bind",
|
|
65
|
+
"/",
|
|
66
|
+
"/",
|
|
67
|
+
"--proc",
|
|
68
|
+
"/proc",
|
|
69
|
+
"--dev",
|
|
70
|
+
"/dev",
|
|
71
|
+
"--tmpfs",
|
|
72
|
+
"/tmp",
|
|
73
|
+
"--",
|
|
74
|
+
"/bin/true",
|
|
75
|
+
]);
|
|
22
76
|
const DEFAULT_RUNTIME = Object.freeze({
|
|
23
77
|
platform: os.platform(),
|
|
24
78
|
fs,
|
|
@@ -27,12 +81,49 @@ const DEFAULT_RUNTIME = Object.freeze({
|
|
|
27
81
|
randomBytes: (size) => crypto.randomBytes(size),
|
|
28
82
|
resolvePath: (value) => path.resolve(value),
|
|
29
83
|
joinPath: (...parts) => path.join(...parts),
|
|
84
|
+
windowsDir: () => process.env.WINDIR || "C:\\Windows",
|
|
85
|
+
moduleDir: MODULE_DIR,
|
|
86
|
+
now: () => Date.now(),
|
|
87
|
+
sleepSync: (milliseconds) =>
|
|
88
|
+
Atomics.wait(WINDOWS_IDENTITY_WAIT, 0, 0, milliseconds),
|
|
89
|
+
spawnSync: nativeSpawnSync,
|
|
30
90
|
});
|
|
31
91
|
|
|
32
92
|
function resolveRuntime(overrides = {}) {
|
|
33
93
|
return { ...DEFAULT_RUNTIME, ...overrides };
|
|
34
94
|
}
|
|
35
95
|
|
|
96
|
+
function normalizeSandboxRequest(profileOrRequest, explicitRequest) {
|
|
97
|
+
const legacyRequest =
|
|
98
|
+
profileOrRequest &&
|
|
99
|
+
typeof profileOrRequest === "object" &&
|
|
100
|
+
!Array.isArray(profileOrRequest)
|
|
101
|
+
? profileOrRequest
|
|
102
|
+
: { profile: profileOrRequest };
|
|
103
|
+
const request =
|
|
104
|
+
explicitRequest &&
|
|
105
|
+
typeof explicitRequest === "object" &&
|
|
106
|
+
!Array.isArray(explicitRequest)
|
|
107
|
+
? explicitRequest
|
|
108
|
+
: legacyRequest;
|
|
109
|
+
const profile =
|
|
110
|
+
typeof request.profile === "string"
|
|
111
|
+
? request.profile
|
|
112
|
+
: typeof legacyRequest.profile === "string"
|
|
113
|
+
? legacyRequest.profile
|
|
114
|
+
: "default";
|
|
115
|
+
const requiredBoundaries = Array.isArray(request.requiredBoundaries)
|
|
116
|
+
? [
|
|
117
|
+
...new Set(
|
|
118
|
+
request.requiredBoundaries.filter(
|
|
119
|
+
(boundary) => typeof boundary === "string",
|
|
120
|
+
),
|
|
121
|
+
),
|
|
122
|
+
]
|
|
123
|
+
: [];
|
|
124
|
+
return { profile, requiredBoundaries };
|
|
125
|
+
}
|
|
126
|
+
|
|
36
127
|
/**
|
|
37
128
|
* A native `spawn(..., { shell: true })` asks Node to execute one command
|
|
38
129
|
* string through the platform shell. Once a sandbox wrapper becomes the
|
|
@@ -45,7 +136,7 @@ function resolveRuntime(overrides = {}) {
|
|
|
45
136
|
* sandbox executable itself is always spawned directly.
|
|
46
137
|
*/
|
|
47
138
|
function normalizeWrappedInvocation(command, args, spawnOpts, platform) {
|
|
48
|
-
if (!spawnOpts?.shell
|
|
139
|
+
if (!spawnOpts?.shell) {
|
|
49
140
|
return {
|
|
50
141
|
command,
|
|
51
142
|
args: [...(args || [])],
|
|
@@ -53,6 +144,19 @@ function normalizeWrappedInvocation(command, args, spawnOpts, platform) {
|
|
|
53
144
|
};
|
|
54
145
|
}
|
|
55
146
|
|
|
147
|
+
if (platform === "win32") {
|
|
148
|
+
const shell =
|
|
149
|
+
typeof spawnOpts.shell === "string"
|
|
150
|
+
? spawnOpts.shell
|
|
151
|
+
: process.env.ComSpec || "C:\\Windows\\System32\\cmd.exe";
|
|
152
|
+
const shellCommand = [command, ...(args || [])].map(String).join(" ");
|
|
153
|
+
return {
|
|
154
|
+
command: shell,
|
|
155
|
+
args: ["/d", "/s", "/c", shellCommand],
|
|
156
|
+
options: { ...spawnOpts, shell: false },
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
56
160
|
const shell =
|
|
57
161
|
typeof spawnOpts.shell === "string" ? spawnOpts.shell : "/bin/sh";
|
|
58
162
|
const shellCommand = [command, ...(args || [])].map(String).join(" ");
|
|
@@ -82,6 +186,8 @@ function normalizeWrappedInvocation(command, args, spawnOpts, platform) {
|
|
|
82
186
|
* args: string[],
|
|
83
187
|
* options: Object,
|
|
84
188
|
* enforcement: string|null,
|
|
189
|
+
* backend: string|null,
|
|
190
|
+
* guarantees: readonly SandboxBoundary[],
|
|
85
191
|
* reason: string|null,
|
|
86
192
|
* cleanup?: Function,
|
|
87
193
|
* postSpawn: {required: boolean, mode: "none"|"sync"|"async"}
|
|
@@ -97,10 +203,16 @@ function createSandboxPlan(input) {
|
|
|
97
203
|
contractVersion: 1,
|
|
98
204
|
applied: false,
|
|
99
205
|
enforcement: null,
|
|
206
|
+
backend: null,
|
|
207
|
+
guarantees: Object.freeze([]),
|
|
100
208
|
reason: null,
|
|
101
209
|
...input,
|
|
102
210
|
args: Object.freeze([...(input.args || [])]),
|
|
103
211
|
options: Object.freeze({ ...(input.options || {}) }),
|
|
212
|
+
guarantees: Object.freeze([...(input.guarantees || [])]),
|
|
213
|
+
runtimeProbe: input.runtimeProbe
|
|
214
|
+
? Object.freeze({ ...input.runtimeProbe })
|
|
215
|
+
: null,
|
|
104
216
|
postSpawn,
|
|
105
217
|
});
|
|
106
218
|
}
|
|
@@ -132,6 +244,10 @@ export function generateMacSeatbeltProfile(opts = {}, runtimeOverrides = {}) {
|
|
|
132
244
|
const lines = [
|
|
133
245
|
"(version 1)",
|
|
134
246
|
"(deny default)",
|
|
247
|
+
// Apple's system baseline supplies the loader/device primitives required
|
|
248
|
+
// for ordinary command startup. Our explicit rules below still own
|
|
249
|
+
// process, filesystem write, and network policy.
|
|
250
|
+
'(import "system.sb")',
|
|
135
251
|
// Basic system operations always allowed
|
|
136
252
|
"(allow signal (target self))",
|
|
137
253
|
'(allow process-exec (literal "/usr/bin/env"))',
|
|
@@ -148,6 +264,10 @@ export function generateMacSeatbeltProfile(opts = {}, runtimeOverrides = {}) {
|
|
|
148
264
|
|
|
149
265
|
if (allowNetwork) {
|
|
150
266
|
lines.push("(allow network*)");
|
|
267
|
+
} else {
|
|
268
|
+
// Keep the imported system baseline from widening the caller's explicit
|
|
269
|
+
// no-network policy.
|
|
270
|
+
lines.push("(deny network*)");
|
|
151
271
|
}
|
|
152
272
|
|
|
153
273
|
// Allow read/write to specific paths
|
|
@@ -162,9 +282,17 @@ export function generateMacSeatbeltProfile(opts = {}, runtimeOverrides = {}) {
|
|
|
162
282
|
}
|
|
163
283
|
|
|
164
284
|
// Always allow read access to system paths needed for basic execution
|
|
285
|
+
lines.push('(allow file-read* (subpath "/bin"))');
|
|
286
|
+
lines.push('(allow file-read* (subpath "/usr/bin"))');
|
|
165
287
|
lines.push('(allow file-read* (subpath "/usr/lib"))');
|
|
288
|
+
lines.push('(allow file-read* (subpath "/usr/libexec"))');
|
|
166
289
|
lines.push('(allow file-read* (subpath "/System/Library"))');
|
|
290
|
+
lines.push('(allow file-read* (subpath "/Library/Frameworks"))');
|
|
167
291
|
lines.push('(allow file-read* (subpath "/usr/local/lib"))');
|
|
292
|
+
lines.push(
|
|
293
|
+
'(allow file-read* file-write* (literal "/dev/null") (literal "/dev/stdin") (literal "/dev/stdout") (literal "/dev/stderr"))',
|
|
294
|
+
);
|
|
295
|
+
lines.push('(allow file-read* (literal "/dev/urandom"))');
|
|
168
296
|
lines.push('(allow file-read* (literal "/etc/passwd"))');
|
|
169
297
|
|
|
170
298
|
return lines.join("\n");
|
|
@@ -199,6 +327,7 @@ export function applyMacSandbox(
|
|
|
199
327
|
const base = {
|
|
200
328
|
platform: runtime.platform,
|
|
201
329
|
profile: sandboxOpts.profileName || "default",
|
|
330
|
+
backend: "macos-seatbelt",
|
|
202
331
|
command,
|
|
203
332
|
args,
|
|
204
333
|
options: { ...(spawnOpts || {}) },
|
|
@@ -250,6 +379,11 @@ export function applyMacSandbox(
|
|
|
250
379
|
...base,
|
|
251
380
|
applied: true,
|
|
252
381
|
enforcement: "macos-seatbelt",
|
|
382
|
+
guarantees: [
|
|
383
|
+
SANDBOX_BOUNDARIES.FILESYSTEM,
|
|
384
|
+
...(sandboxOpts.allowNetwork ? [] : [SANDBOX_BOUNDARIES.NETWORK]),
|
|
385
|
+
...(sandboxOpts.allowExec ? [] : [SANDBOX_BOUNDARIES.PROCESS_EXEC]),
|
|
386
|
+
],
|
|
253
387
|
command: sandboxExecutable,
|
|
254
388
|
args: newArgs,
|
|
255
389
|
options: invocation.options,
|
|
@@ -264,12 +398,137 @@ export function applyMacSandbox(
|
|
|
264
398
|
}
|
|
265
399
|
|
|
266
400
|
// ---------------------------------------------------------------------------
|
|
267
|
-
// Windows Job Object
|
|
401
|
+
// Windows Job Object + Restricted Token
|
|
268
402
|
// ---------------------------------------------------------------------------
|
|
269
403
|
|
|
270
404
|
/**
|
|
271
|
-
*
|
|
272
|
-
*
|
|
405
|
+
* Materialize the shipped PowerShell/Win32 adapter into a physical temporary
|
|
406
|
+
* file. This is required for pkg builds where source assets live in a virtual
|
|
407
|
+
* snapshot that an external powershell.exe process cannot open directly.
|
|
408
|
+
*/
|
|
409
|
+
function materializeWindowsAdapter(runtime) {
|
|
410
|
+
const sourcePath =
|
|
411
|
+
runtime.windowsAdapterScriptPath ||
|
|
412
|
+
runtime.joinPath(runtime.moduleDir, "windows-sandbox.ps1");
|
|
413
|
+
let content = runtime.windowsAdapterContent;
|
|
414
|
+
if (content === undefined) {
|
|
415
|
+
if (!runtime.fs.existsSync(sourcePath)) {
|
|
416
|
+
return { reason: "windows_native_adapter_missing" };
|
|
417
|
+
}
|
|
418
|
+
try {
|
|
419
|
+
content = runtime.fs.readFileSync(sourcePath, "utf8");
|
|
420
|
+
} catch {
|
|
421
|
+
return { reason: "windows_native_adapter_unreadable" };
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
const adapterHash = crypto
|
|
425
|
+
.createHash("sha256")
|
|
426
|
+
.update(String(content))
|
|
427
|
+
.digest("hex")
|
|
428
|
+
.slice(0, 24);
|
|
429
|
+
const cacheExecutable = runtime.joinPath(
|
|
430
|
+
runtime.tmpdir(),
|
|
431
|
+
`chainless-win-sandbox-${adapterHash}.exe`,
|
|
432
|
+
);
|
|
433
|
+
if (runtime.fs.existsSync(cacheExecutable)) {
|
|
434
|
+
return {
|
|
435
|
+
cacheExecutable,
|
|
436
|
+
bootstrapRequired: false,
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
const scriptPath = runtime.joinPath(
|
|
440
|
+
runtime.tmpdir(),
|
|
441
|
+
`chainless-win-sandbox-${runtime.randomBytes(12).toString("hex")}.ps1`,
|
|
442
|
+
);
|
|
443
|
+
try {
|
|
444
|
+
runtime.fs.writeFileSync(scriptPath, content, { mode: 0o600 });
|
|
445
|
+
} catch {
|
|
446
|
+
return { reason: "windows_native_adapter_materialize_failed" };
|
|
447
|
+
}
|
|
448
|
+
return {
|
|
449
|
+
scriptPath,
|
|
450
|
+
cacheExecutable,
|
|
451
|
+
bootstrapRequired: true,
|
|
452
|
+
cleanup: () => {
|
|
453
|
+
try {
|
|
454
|
+
runtime.fs.unlinkSync(scriptPath);
|
|
455
|
+
} catch {
|
|
456
|
+
// The temporary adapter may already have been removed.
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
};
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
function waitForWindowsTargetIdentity(
|
|
463
|
+
proc,
|
|
464
|
+
identityPath,
|
|
465
|
+
runtime,
|
|
466
|
+
timeoutMs = 10_000,
|
|
467
|
+
) {
|
|
468
|
+
const deadline = runtime.now() + timeoutMs;
|
|
469
|
+
let lastError;
|
|
470
|
+
while (runtime.now() < deadline) {
|
|
471
|
+
try {
|
|
472
|
+
const identity = JSON.parse(
|
|
473
|
+
runtime.fs.readFileSync(identityPath, "utf8"),
|
|
474
|
+
);
|
|
475
|
+
if (identity?.error) {
|
|
476
|
+
throw new Error(
|
|
477
|
+
`Windows sandbox helper rejected the target: ${identity.error}`,
|
|
478
|
+
);
|
|
479
|
+
}
|
|
480
|
+
const targetPid = Number(identity?.targetPid);
|
|
481
|
+
const helperPid = Number(identity?.helperPid);
|
|
482
|
+
if (!Number.isSafeInteger(targetPid) || targetPid <= 0) {
|
|
483
|
+
throw new Error("Windows sandbox identity omitted a valid target PID");
|
|
484
|
+
}
|
|
485
|
+
if (
|
|
486
|
+
Number.isSafeInteger(helperPid) &&
|
|
487
|
+
helperPid > 0 &&
|
|
488
|
+
helperPid !== proc.pid
|
|
489
|
+
) {
|
|
490
|
+
throw new Error(
|
|
491
|
+
`Windows sandbox identity named unexpected helper PID ${helperPid}`,
|
|
492
|
+
);
|
|
493
|
+
}
|
|
494
|
+
if (targetPid === proc.pid) {
|
|
495
|
+
throw new Error(
|
|
496
|
+
"Windows sandbox target PID unexpectedly equals its helper PID",
|
|
497
|
+
);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const wrapperPid = proc.pid;
|
|
501
|
+
proc.sandboxWrapperPid = wrapperPid;
|
|
502
|
+
proc.sandboxTargetPid = targetPid;
|
|
503
|
+
// ChildProcess.pid is a writable data property. The native ChildProcess
|
|
504
|
+
// handle still points at the helper, so kill()/ref()/unref() retain Job
|
|
505
|
+
// lifetime semantics while callers observe and persist the real target.
|
|
506
|
+
proc.pid = targetPid;
|
|
507
|
+
return { targetPid, wrapperPid };
|
|
508
|
+
} catch (error) {
|
|
509
|
+
lastError = error;
|
|
510
|
+
if (
|
|
511
|
+
error?.code !== "ENOENT" &&
|
|
512
|
+
!(error instanceof SyntaxError) &&
|
|
513
|
+
!String(error?.message || "").includes("omitted a valid target PID")
|
|
514
|
+
) {
|
|
515
|
+
throw error;
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
runtime.sleepSync(10);
|
|
519
|
+
}
|
|
520
|
+
throw new Error(
|
|
521
|
+
`Timed out waiting for Windows sandbox target identity${
|
|
522
|
+
lastError?.message ? `: ${lastError.message}` : ""
|
|
523
|
+
}`,
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
/**
|
|
528
|
+
* Wrap a target with the built-in Windows PowerShell host. The shipped script
|
|
529
|
+
* P/Invokes Win32 to create a restricted primary token, starts the target
|
|
530
|
+
* suspended, assigns it to a kill-on-close Job Object, then resumes it. The
|
|
531
|
+
* target therefore cannot run before both native boundaries are active.
|
|
273
532
|
*
|
|
274
533
|
* @param {string} command
|
|
275
534
|
* @param {string[]} args
|
|
@@ -287,6 +546,7 @@ export function applyWindowsSandbox(
|
|
|
287
546
|
const base = {
|
|
288
547
|
platform: runtime.platform,
|
|
289
548
|
profile: sandboxOpts.profileName || "default",
|
|
549
|
+
backend: "windows-job-restricted-token",
|
|
290
550
|
command,
|
|
291
551
|
args,
|
|
292
552
|
options: spawnOpts,
|
|
@@ -298,19 +558,196 @@ export function applyWindowsSandbox(
|
|
|
298
558
|
});
|
|
299
559
|
}
|
|
300
560
|
|
|
301
|
-
//
|
|
302
|
-
//
|
|
303
|
-
//
|
|
304
|
-
//
|
|
561
|
+
// The hosted Windows restricted-token path cannot reliably preserve file
|
|
562
|
+
// descriptor backed stdout/stderr when its helper is itself detached. Mark
|
|
563
|
+
// that combination unavailable before launch: strict/required callers fail
|
|
564
|
+
// closed, while ordinary trusted control-plane callers retain the broker's
|
|
565
|
+
// explicit audited fallback instead of receiving a phantom target PID.
|
|
566
|
+
if (
|
|
567
|
+
spawnOpts?.detached === true &&
|
|
568
|
+
Array.isArray(spawnOpts?.stdio) &&
|
|
569
|
+
spawnOpts.stdio.slice(0, 3).some((entry) => Number.isInteger(entry))
|
|
570
|
+
) {
|
|
571
|
+
return createSandboxPlan({
|
|
572
|
+
...base,
|
|
573
|
+
reason: "windows_detached_file_stdio_unsupported",
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
const nodeIpcFd = Array.isArray(spawnOpts?.stdio)
|
|
578
|
+
? spawnOpts.stdio.findIndex((entry) => entry === "ipc")
|
|
579
|
+
: -1;
|
|
580
|
+
if (
|
|
581
|
+
Array.isArray(spawnOpts?.stdio) &&
|
|
582
|
+
spawnOpts.stdio
|
|
583
|
+
.slice(3)
|
|
584
|
+
.some(
|
|
585
|
+
(entry, offset) =>
|
|
586
|
+
offset + 3 !== nodeIpcFd &&
|
|
587
|
+
entry !== "ignore" &&
|
|
588
|
+
entry !== null &&
|
|
589
|
+
entry !== undefined,
|
|
590
|
+
)
|
|
591
|
+
) {
|
|
592
|
+
return createSandboxPlan({
|
|
593
|
+
...base,
|
|
594
|
+
reason: "windows_extra_descriptor_unsupported",
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
const adapter = materializeWindowsAdapter(runtime);
|
|
599
|
+
if (!adapter.cacheExecutable) {
|
|
600
|
+
return createSandboxPlan({
|
|
601
|
+
...base,
|
|
602
|
+
reason: adapter.reason,
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
const invocation = normalizeWrappedInvocation(
|
|
607
|
+
command,
|
|
608
|
+
args,
|
|
609
|
+
spawnOpts,
|
|
610
|
+
runtime.platform,
|
|
611
|
+
);
|
|
612
|
+
const profile = sandboxOpts.profileName || "default";
|
|
613
|
+
const limits = sandboxOpts.limits || {};
|
|
614
|
+
const identityPath =
|
|
615
|
+
spawnOpts?.detached === true
|
|
616
|
+
? runtime.joinPath(
|
|
617
|
+
runtime.tmpdir(),
|
|
618
|
+
`chainless-win-sandbox-identity-${runtime
|
|
619
|
+
.randomBytes(24)
|
|
620
|
+
.toString("hex")}.json`,
|
|
621
|
+
)
|
|
622
|
+
: null;
|
|
623
|
+
const launchSpec = {
|
|
624
|
+
cpuSeconds: Number(limits.cpu || 0),
|
|
625
|
+
processMemoryBytes: Number(
|
|
626
|
+
limits.as || (profile === "strict" ? 256 * 1024 * 1024 : 0),
|
|
627
|
+
),
|
|
628
|
+
activeProcessLimit: profile === "strict" ? 16 : 64,
|
|
629
|
+
command: invocation.command,
|
|
630
|
+
args: invocation.args,
|
|
631
|
+
nodeIpcFd,
|
|
632
|
+
detached: invocation.options.detached === true,
|
|
633
|
+
windowsHide: invocation.options.windowsHide === true,
|
|
634
|
+
};
|
|
635
|
+
if (identityPath) launchSpec.identityPath = identityPath;
|
|
636
|
+
const payload = Buffer.from(JSON.stringify(launchSpec), "utf8").toString(
|
|
637
|
+
"base64",
|
|
638
|
+
);
|
|
639
|
+
const helperArgs = [payload];
|
|
640
|
+
const options = {
|
|
641
|
+
...invocation.options,
|
|
642
|
+
shell: false,
|
|
643
|
+
env: {
|
|
644
|
+
...(invocation.options.env || process.env),
|
|
645
|
+
CC_WINDOWS_SANDBOXED: "1",
|
|
646
|
+
CC_WINDOWS_SANDBOX_PROFILE: profile,
|
|
647
|
+
},
|
|
648
|
+
};
|
|
649
|
+
const cleanupIdentity = () => {
|
|
650
|
+
if (!identityPath) return;
|
|
651
|
+
try {
|
|
652
|
+
runtime.fs.unlinkSync(identityPath);
|
|
653
|
+
} catch {
|
|
654
|
+
// The post-spawn handshake normally removes this file first.
|
|
655
|
+
}
|
|
656
|
+
};
|
|
657
|
+
const identityContract = identityPath
|
|
658
|
+
? {
|
|
659
|
+
postSpawn: { required: true, mode: "sync" },
|
|
660
|
+
postSpawnWindows: (proc) => {
|
|
661
|
+
try {
|
|
662
|
+
return waitForWindowsTargetIdentity(proc, identityPath, runtime);
|
|
663
|
+
} catch (error) {
|
|
664
|
+
try {
|
|
665
|
+
proc.kill?.();
|
|
666
|
+
} catch {
|
|
667
|
+
// Closing the helper is best-effort; the thrown failure remains
|
|
668
|
+
// authoritative and strict mode will fail closed.
|
|
669
|
+
}
|
|
670
|
+
throw error;
|
|
671
|
+
} finally {
|
|
672
|
+
cleanupIdentity();
|
|
673
|
+
}
|
|
674
|
+
},
|
|
675
|
+
}
|
|
676
|
+
: {};
|
|
677
|
+
|
|
678
|
+
if (adapter.bootstrapRequired) {
|
|
679
|
+
const powershell = runtime.joinPath(
|
|
680
|
+
runtime.windowsDir(),
|
|
681
|
+
"System32",
|
|
682
|
+
"WindowsPowerShell",
|
|
683
|
+
"v1.0",
|
|
684
|
+
"powershell.exe",
|
|
685
|
+
);
|
|
686
|
+
if (!runtime.fs.existsSync(powershell)) {
|
|
687
|
+
adapter.cleanup?.();
|
|
688
|
+
cleanupIdentity();
|
|
689
|
+
return createSandboxPlan({
|
|
690
|
+
...base,
|
|
691
|
+
reason: "windows_powershell_host_unavailable",
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
const compileResult = runtime.spawnSync(
|
|
695
|
+
powershell,
|
|
696
|
+
[
|
|
697
|
+
"-NoLogo",
|
|
698
|
+
"-NoProfile",
|
|
699
|
+
"-NonInteractive",
|
|
700
|
+
"-ExecutionPolicy",
|
|
701
|
+
"Bypass",
|
|
702
|
+
"-File",
|
|
703
|
+
adapter.scriptPath,
|
|
704
|
+
"-CacheExecutable",
|
|
705
|
+
adapter.cacheExecutable,
|
|
706
|
+
"-CompileOnly",
|
|
707
|
+
],
|
|
708
|
+
{
|
|
709
|
+
shell: false,
|
|
710
|
+
windowsHide: true,
|
|
711
|
+
encoding: "utf8",
|
|
712
|
+
timeout: 30_000,
|
|
713
|
+
env: invocation.options.env || process.env,
|
|
714
|
+
},
|
|
715
|
+
);
|
|
716
|
+
adapter.cleanup?.();
|
|
717
|
+
if (
|
|
718
|
+
compileResult?.error ||
|
|
719
|
+
compileResult?.status !== 0 ||
|
|
720
|
+
!runtime.fs.existsSync(adapter.cacheExecutable)
|
|
721
|
+
) {
|
|
722
|
+
cleanupIdentity();
|
|
723
|
+
return createSandboxPlan({
|
|
724
|
+
...base,
|
|
725
|
+
reason: "windows_native_adapter_compile_failed",
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
305
730
|
return createSandboxPlan({
|
|
306
731
|
...base,
|
|
307
|
-
|
|
732
|
+
applied: true,
|
|
733
|
+
enforcement: "windows-job-restricted-token",
|
|
734
|
+
guarantees: [
|
|
735
|
+
SANDBOX_BOUNDARIES.PROCESS_TREE,
|
|
736
|
+
SANDBOX_BOUNDARIES.RESOURCE_LIMITS,
|
|
737
|
+
SANDBOX_BOUNDARIES.PRIVILEGE_REDUCTION,
|
|
738
|
+
],
|
|
739
|
+
command: adapter.cacheExecutable,
|
|
740
|
+
args: helperArgs,
|
|
741
|
+
options,
|
|
742
|
+
...identityContract,
|
|
743
|
+
cleanup: cleanupIdentity,
|
|
308
744
|
});
|
|
309
745
|
}
|
|
310
746
|
|
|
311
747
|
/**
|
|
312
|
-
*
|
|
313
|
-
*
|
|
748
|
+
* Retained for injected adapters that elect to perform synchronous post-spawn
|
|
749
|
+
* enforcement. The built-in wrapper completes enforcement before target resume
|
|
750
|
+
* and therefore does not require this path.
|
|
314
751
|
*
|
|
315
752
|
* @param {ChildProcess} proc - The spawned child process
|
|
316
753
|
* @param {Object} sandboxResult - Result from applyWindowsSandbox
|
|
@@ -324,17 +761,83 @@ export function postSpawnWindowsSandbox(
|
|
|
324
761
|
if (runtime.platform !== "win32" || !sandboxResult?.postSpawn?.required) {
|
|
325
762
|
return;
|
|
326
763
|
}
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
error.code = "ERR_WINDOWS_SANDBOX_UNAVAILABLE";
|
|
331
|
-
throw error;
|
|
764
|
+
if (typeof sandboxResult.postSpawnWindows === "function") {
|
|
765
|
+
return sandboxResult.postSpawnWindows(proc);
|
|
766
|
+
}
|
|
332
767
|
}
|
|
333
768
|
|
|
334
769
|
// ---------------------------------------------------------------------------
|
|
335
770
|
// Linux resource-limit enforcement
|
|
336
771
|
// ---------------------------------------------------------------------------
|
|
337
772
|
|
|
773
|
+
/**
|
|
774
|
+
* Prove only that the installed bubblewrap binary can create the namespace and
|
|
775
|
+
* mount primitives needed by a future policy backend. This deliberately does
|
|
776
|
+
* not attest any filesystem/network policy and therefore must never promote a
|
|
777
|
+
* sandbox guarantee.
|
|
778
|
+
*/
|
|
779
|
+
function probeLinuxBubblewrapRuntime(runtime) {
|
|
780
|
+
let binaryPresent = false;
|
|
781
|
+
try {
|
|
782
|
+
binaryPresent = runtime.fs.existsSync(LINUX_BWRAP_PATH);
|
|
783
|
+
} catch {
|
|
784
|
+
return {
|
|
785
|
+
kind: "linux-bwrap-runtime-smoke-v1",
|
|
786
|
+
attempted: false,
|
|
787
|
+
runnable: false,
|
|
788
|
+
reason: "binary_probe_failed",
|
|
789
|
+
};
|
|
790
|
+
}
|
|
791
|
+
if (!binaryPresent) {
|
|
792
|
+
return {
|
|
793
|
+
kind: "linux-bwrap-runtime-smoke-v1",
|
|
794
|
+
attempted: false,
|
|
795
|
+
runnable: false,
|
|
796
|
+
reason: "binary_missing",
|
|
797
|
+
};
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
let result;
|
|
801
|
+
try {
|
|
802
|
+
result = runtime.spawnSync(
|
|
803
|
+
LINUX_BWRAP_PATH,
|
|
804
|
+
[...LINUX_BWRAP_RUNTIME_PROBE_ARGS],
|
|
805
|
+
{
|
|
806
|
+
shell: false,
|
|
807
|
+
stdio: "ignore",
|
|
808
|
+
timeout: 5_000,
|
|
809
|
+
env: {
|
|
810
|
+
PATH: "/usr/bin:/bin",
|
|
811
|
+
LANG: "C",
|
|
812
|
+
LC_ALL: "C",
|
|
813
|
+
},
|
|
814
|
+
},
|
|
815
|
+
);
|
|
816
|
+
} catch {
|
|
817
|
+
return {
|
|
818
|
+
kind: "linux-bwrap-runtime-smoke-v1",
|
|
819
|
+
attempted: true,
|
|
820
|
+
runnable: false,
|
|
821
|
+
reason: "probe_spawn_failed",
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
if (result?.error || result?.status !== 0) {
|
|
826
|
+
return {
|
|
827
|
+
kind: "linux-bwrap-runtime-smoke-v1",
|
|
828
|
+
attempted: true,
|
|
829
|
+
runnable: false,
|
|
830
|
+
reason: result?.error ? "probe_spawn_failed" : "probe_failed",
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
return {
|
|
834
|
+
kind: "linux-bwrap-runtime-smoke-v1",
|
|
835
|
+
attempted: true,
|
|
836
|
+
runnable: true,
|
|
837
|
+
reason: null,
|
|
838
|
+
};
|
|
839
|
+
}
|
|
840
|
+
|
|
338
841
|
/**
|
|
339
842
|
* Apply Linux resource limits through the util-linux `prlimit` wrapper.
|
|
340
843
|
*
|
|
@@ -360,6 +863,7 @@ export function applyLinuxSandbox(
|
|
|
360
863
|
const base = {
|
|
361
864
|
platform: runtime.platform,
|
|
362
865
|
profile: sandboxOpts.profileName || "default",
|
|
866
|
+
backend: "linux-prlimit",
|
|
363
867
|
command,
|
|
364
868
|
args,
|
|
365
869
|
options: { ...(spawnOpts || {}) },
|
|
@@ -372,6 +876,29 @@ export function applyLinuxSandbox(
|
|
|
372
876
|
}
|
|
373
877
|
|
|
374
878
|
const { limits = {} } = sandboxOpts;
|
|
879
|
+
const requiredBoundaries = Array.isArray(sandboxOpts.requiredBoundaries)
|
|
880
|
+
? sandboxOpts.requiredBoundaries
|
|
881
|
+
: [];
|
|
882
|
+
const requiresStrongLinuxBoundary = requiredBoundaries.some(
|
|
883
|
+
(boundary) =>
|
|
884
|
+
boundary === SANDBOX_BOUNDARIES.FILESYSTEM ||
|
|
885
|
+
boundary === SANDBOX_BOUNDARIES.NETWORK,
|
|
886
|
+
);
|
|
887
|
+
|
|
888
|
+
if (requiresStrongLinuxBoundary) {
|
|
889
|
+
const runtimeProbe = probeLinuxBubblewrapRuntime(runtime);
|
|
890
|
+
return createSandboxPlan({
|
|
891
|
+
...base,
|
|
892
|
+
backend: null,
|
|
893
|
+
candidateBackend: "linux-bwrap",
|
|
894
|
+
policyAttested: false,
|
|
895
|
+
runtimeProbe,
|
|
896
|
+
reason: runtimeProbe.runnable
|
|
897
|
+
? "linux_bwrap_policy_unattested"
|
|
898
|
+
: "linux_bwrap_unavailable",
|
|
899
|
+
guarantees: [],
|
|
900
|
+
});
|
|
901
|
+
}
|
|
375
902
|
|
|
376
903
|
const prlimitParts = [];
|
|
377
904
|
if (limits.cpu) prlimitParts.push(`--cpu=${limits.cpu}`);
|
|
@@ -404,6 +931,7 @@ export function applyLinuxSandbox(
|
|
|
404
931
|
...base,
|
|
405
932
|
applied: true,
|
|
406
933
|
enforcement: "linux-prlimit",
|
|
934
|
+
guarantees: [SANDBOX_BOUNDARIES.RESOURCE_LIMITS],
|
|
407
935
|
command: "/usr/bin/prlimit",
|
|
408
936
|
args: [...prlimitParts, "--", invocation.command, ...invocation.args],
|
|
409
937
|
options,
|
|
@@ -420,17 +948,28 @@ export function applyLinuxSandbox(
|
|
|
420
948
|
* @param {string} command
|
|
421
949
|
* @param {string[]} args
|
|
422
950
|
* @param {Object} spawnOpts - Original spawn options
|
|
423
|
-
* @param {"default"|"strict"|"network-only"
|
|
951
|
+
* @param {"default"|"strict"|"network-only"|{
|
|
952
|
+
* profile?: "default"|"strict"|"network-only",
|
|
953
|
+
* requiredBoundaries?: string[]
|
|
954
|
+
* }} profileOrRequest
|
|
955
|
+
* @param {Object} runtimeOverrides
|
|
956
|
+
* @param {{profile?: string, requiredBoundaries?: string[]}|null} explicitRequest
|
|
424
957
|
* @returns {ReturnType<typeof createSandboxPlan>}
|
|
425
958
|
*/
|
|
426
959
|
export function applySandbox(
|
|
427
960
|
command,
|
|
428
961
|
args,
|
|
429
962
|
spawnOpts,
|
|
430
|
-
|
|
963
|
+
profileOrRequest = "default",
|
|
431
964
|
runtimeOverrides = {},
|
|
965
|
+
explicitRequest = null,
|
|
432
966
|
) {
|
|
433
967
|
const runtime = resolveRuntime(runtimeOverrides);
|
|
968
|
+
const sandboxRequest = normalizeSandboxRequest(
|
|
969
|
+
profileOrRequest,
|
|
970
|
+
explicitRequest,
|
|
971
|
+
);
|
|
972
|
+
const profileName = sandboxRequest.profile;
|
|
434
973
|
const profiles = {
|
|
435
974
|
default: {
|
|
436
975
|
allowNetwork: false,
|
|
@@ -471,6 +1010,7 @@ export function applySandbox(
|
|
|
471
1010
|
const profile = {
|
|
472
1011
|
...(profiles[profileName] || profiles.default),
|
|
473
1012
|
profileName: profiles[profileName] ? profileName : "default",
|
|
1013
|
+
requiredBoundaries: sandboxRequest.requiredBoundaries,
|
|
474
1014
|
};
|
|
475
1015
|
|
|
476
1016
|
// Dispatch to platform handler
|