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