Replies: 5 comments
|
补充一份独立复现与修复验证,可以给上面的根因分析补三块目前缺的证据:最小复现、排除项、以及"上游修法在本机确认真能救活沙箱"。 环境:Windows 11(build 26200)、桌面端 1. 最小复现(不经 DSH 包,证明根因不在 ACL/路径/包版本)用 koffi 直接调用 Win32,复刻沙箱的进程创建:
同一矩阵用真实 补充:Electron 侧换任意版本(Electron 35/37/44 的四个不同 Electron 应用)结果相同;vanilla node v22 与 v24 均正常。 2. 排除项(这些常见修法都无效,别再试)
不是 Microsoft 二进制签名/进程缓解策略:对 Electron 进程与 vanilla node 进程做 不是包版本回归:从桌面端 3. 修复方向已在本机验证(不只是推测)"给宿主一个控制台再生成受限子进程"这一条,实测能够彻底恢复:
这与上游 anywhere-labs/dsh-desktop 的提交一致—— Harness 侧若要独立于桌面外壳兜底,建议仍是上面这条已验证的路径(探测 4. 一处需要修正的细节本楼写道「read-only 模式在没有控制台时也能跑」。我这边只复测了 |
|
Same exit code and same shape as the other threads in this family, and there is a diagnostic for it today: |
|
已收到这条反馈。 |
|
补一块本楼明确缺的读数(回应楼上补充里「未复测 read-only,建议以 read-only 复测结果为准」):read-only 在无控制台宿主下可以跑,workspace-write 才是死的。两次独立读数,同一台机器(DSH 0.2.0-rc.2 桌面版,Windows 11 build 26100,profile 1) 真机会话(桌面端,会话预设
2) out-of-band A/B:用从
→ 同一个无控制台宿主,read-only 通、workspace-write 死。也就是说「宿主没有可继承的控制台」恐怕不是充分条件,workspace-write 那条路径上还有别的变量(temp 授权 / restricting SID 列表 / 创建标志)值得对照——这一格读数可以给上游定位时当参照。 另两条独立证据:
(备注:本机 Windows 的 Issues 是关闭的,所以按现有讨论补证据而非新开帖。) |
补充:控制台必须补在上游独立进程,在 runner 内部补无效(附实测数据 + creation flags)感谢 @llwinty 与 @lybym 的定位。我在同类环境(Windows 11 build 26200 / 桌面端 0.2.0-rc.2 / Electron 44.0.0 / Node 24.18.1 / 1. 环境
2. 先确认前提:DSH 全部进程确实没有控制台对活着的 DSH 进程逐一用 再用与 DSH 相同的方式(Electron-as-node + 管道 stdio + "runner 无控制台"这一条件成立,楼主的分析在此处得到独立复现。 3. 实测 A(失败):在 runner 内部补控制台 —— 无效在 asar 内 import { createRequire as __dshCreateRequire } from "node:module";
try{globalThis.__dshRunnerPath=import.meta.url;
__dshCreateRequire(import.meta.url)("<shim>.cjs")}catch{}垫片在 runner 内执行
解读(重要):这不说明"补控制台"方向无效。它说明在已经运行的 runner 进程内部、于 ESM 求值时补控制台,无法满足受限子进程的继承条件。 对照上游
上游提交说明(第 19 行)明确要求:trampoline 在仍未受限时分配控制台,且之后才导入上游 runner module。本次实测 A 恰恰违反了这两点,因此失败是预期的。 建议:实现或复现时不要采用"在 runner 内部注入"的形式;控制台必须由上游独立进程在受限子进程创建之前建立并使其可继承。 4. 实测 B:creation flags 不是原因(已排除)从 // 受限进程(workspace-write 路径)
spawnJobProcess(..., (si, pi) =>
createRestrictedProcess(api, options, commandLine, 4, si, pi));
// ^ dwCreationFlags = 4
// = CREATE_SUSPENDED
// 目标进程
api.createProcessW(options.applicationName, commandLine, null, null, 1,
1028, environment, options.cwd, startupInfo, processInfo);
// ^ 1028 = CREATE_SUSPENDED(4) | CREATE_UNICODE_ENVIRONMENT(1024)不含 5. 已排除:PowerShell 版本 / 文件权限
6. 一个需要解释的差异:
|
Uh oh!
There was an error while loading. Please reload this page.
...
这台机器的默认沙箱下 shell 无法启动(0xC0000142),我是用提权模式读到状态的,后续每条引擎命令都会弹一次批准,家长点一下即可。
22:30
先核实解决沙箱下shell无法启动的问题
22:31
已完成
已完成,用时 10分52秒
结论:已核实,根因定位到 DSH 沙箱本身(不是你的仓库问题)
一句话:DSH 在 Windows 上的 workspace-write 沙箱,被限制的(WRITE_RESTRICTED + Low 完整性)子进程必须继承一个已存在的控制台;而 DSH 用它自带的 Electron 二进制(process.execPath)承载所有子进程/沙箱 runner,Electron 没有控制台。于是受限子进程只能自己新建控制台——这在该令牌下必然失败,进程在 DLL 初始化阶段就以 STATUS_DLL_INIT_FAILED (0xC0000142 = 3221225794) 死掉,没有任何输出。这与你看到的「每条命令都 (no output) / exit code 3221225794」完全一致。
核实过程与证据
我从 app.asar 里取出 DSH 自己的沙箱实现(dsh-sandbox-windows-acl、dsh-win32-process、dsh-subprocess-local、koffi),在你的机器上用同一份代码做了对照实验:
承载沙箱的宿主进程 是否有控制台 read-only 沙箱 workspace-write 沙箱
node.exe(从终端启动) 有 ✅ 正常 ✅ 正常(输出 TARGET-OK)
node.exe + DETACHED_PROCESS 无 — ❌ 0xC0000142
Electron-as-node(DSH 的做法) 无(实测 GetConsoleWindow=0、GetConsoleProcessList=0) ✅ 正常 ❌ 0xC0000142
node.exe + windowsHide:true 有(仅隐藏) ✅ 正常 ✅ 正常
关键点:
变量是「有没有可继承的控制台」,与 windowsHide 无关(dsh-subprocess-local 里的 windowsHide: true 不是元凶)。
read-only 模式在没有控制台时也能跑,所以问题只出在 workspace-write(浏览器/桌面端默认就是这个模式)。
子进程死亡时 runner 不会报自己的错误(runner 自身失败会打印 windows-acl-run: … 并退出 127),所以工具层只剩一个裸退出码——这解释了「无输出」。
承载 runner 的可执行文件在代码里是硬编码的 process.execPath(spawnRunnerInvocation()),没有任何配置项能换成真正的 node.exe;dsh.cmd 命令行入口同样用 Electron。所以 GUI 和 CLI 两种启动方式都会中招。
该失败模式 DSH 自己的文档里也记录为已知边界:「控制台隔离不可用——以 CREATE_NO_WINDOW/CREATE_NEW_CONSOLE 创建的子进程在 DLL 初始化期间以 STATUS_DLL_INIT_FAILED (0xC0000142) 死亡;子进程共享宿主控制台」。
版本信息(便于反馈):DeepSeek Harness 0.2.0-rc.2(Electron 44.0.0 / Node 24.18.1),Windows 11 企业版 build 26200。
All reactions