mirror of
https://github.com/aiclientproxy/proxycast.git
synced 2026-10-16 15:34:08 +08:00
test(sandbox): expose Windows matrix failures
This commit is contained in:
@@ -5,7 +5,7 @@
|
||||
> upstream: `/Users/coso/Documents/dev/rust/codex`(当前观测 HEAD:`99660ab3c7b861c916e467581fa9b8723504d66b`)
|
||||
> checklist progress: `44/46 (95.7%)`;这是未加权任务数,不等于交付完成度,剩余项包含 Windows 平台安全、live/verifier 与正式分发硬门槛。
|
||||
|
||||
> 当前主目标(2026-08-26):关闭 C-3 Windows restricted execution 的真机证据。Codex current 的 per-user Windows Firewall 非 loopback/loopback 出站阻断、offline/online sandbox identity、`LimeSandboxUsers` 普通 token ACL、短生命周期 capability SID restricted ACL、clean-runner setup/read-back、原始 DACL rollback、sandbox-account command runner 与七项 evidence collector 已进入唯一 current owner。真机已证明 runner transport/MSVC 编译、内置 `Users` setup/read-back、默认平台/profile RX ACL setup/read-back 和 `%TEMP%/%TMP%` workspace-write ACL lease 成功;最新矩阵已达 `3/7`,普通 pipe 的 PowerShell、stdin、文件写入和 terminate 仍在标准 desktop 初始化前 exit `1`。当前下一刀是对齐 Codex `LaunchDesktop`,为 restricted child 创建并授权 sandbox logon SID 的短生命周期 desktop,保留到 child/descendants 完成后再关闭,再重跑真实 Windows/MSVC 矩阵。在证据通过前保持 `Planned/enforced=false`。
|
||||
> 当前主目标(2026-08-26):关闭 C-3 Windows restricted execution 的真机证据。Codex current 的 per-user Windows Firewall 非 loopback/loopback 出站阻断、offline/online sandbox identity、`LimeSandboxUsers` 普通 token ACL、短生命周期 capability SID restricted ACL、clean-runner setup/read-back、原始 DACL rollback、sandbox-account command runner 与七项 evidence collector 已进入唯一 current owner。真机已证明 runner transport/MSVC 编译、内置 `Users` setup/read-back、默认平台/profile RX ACL setup/read-back、`%TEMP%/%TMP%` workspace-write ACL lease 和 private desktop 路径可编译执行;最新矩阵仍为 `3/7`,说明 private desktop 不是 workspace write、offline network、allowlisted stdin 与 terminate 四个失败的单一根因。当前下一刀是先让四个真机断言稳定输出实时/终态 snapshot,再按 ACL 写入、stdio handle 和 descendant spawn 三条边界分别对照 Codex;在七项通过前保持 `Planned/enforced=false`。
|
||||
> 参考原则:`/Users/coso/Documents/dev/rust/codex` 是协议、Thread/Turn/Item、runtime lifecycle、tool/approval 和 GUI 语义的直接实现参考源;Lime 只在产品范围、provider 和桌面宿主边界做显式适配,不以旧矩阵或同名 legacy API 代替对齐。
|
||||
> 目标:把 Lime 的产品主链、协议字段、GUI 工作区、执行安全和真实 Desktop 证据推进到当前 Codex Desktop 语义;不恢复已退役 runtime、v0 或 `agentSession/*` 兼容主链。
|
||||
|
||||
@@ -397,6 +397,7 @@ Renderer typed gateway
|
||||
- 2026-08-26:Windows Quality run `32960057901`(SHA `f1bec2328`,artifact `9603664649`)再次通过 setup/MSVC 编译并完整执行 schema v3,但矩阵仍为 `1/7`;六项 restricted child 继续无有效输出 exit `1`,说明内置 `Users` 成员身份已正确写入/read-back,却不是唯一缺口。继续逐段对照 Codex `gather_read_roots -> run_setup_refresh -> apply_read_acls` 后确认 Lime 尚未刷新 `C:\Windows`、Program Files/ProgramData 与当前用户 profile 非敏感子目录的默认 RX ACL;这会让已创建的 restricted PowerShell 在加载 DLL、模块或 AppData 时静默失败。当前修复将该行为收归 Windows setup、补 read-back 并提升 setup marker version 强制旧安装重跑;完成度/readiness 不变。
|
||||
- 2026-08-26:Windows Quality run `32961870012`(SHA `740d5b61b`,artifact `9604315141`)证明默认平台/profile RX ACL 已通过 setup/read-back 与 MSVC 编译,但 schema v3 仍为 `1/7`;六项 PowerShell child 全部在首条输出前 exit `1`,因此 read roots 不是最后一个缺口。继续对照 Codex `PermissionProfile::workspace_write -> FileSystemSpecialPath::Tmpdir -> windows_temp_env_roots` 后确认 Lime ACL plan 只给 cwd/显式 grant 可写,遗漏 child 继承的 `%TEMP%/%TMP%`;sandbox account 对宿主 Temp 只有 RX,符合 PowerShell 初始化阶段无输出失败。当前修复把已过滤 child environment 中的 Windows Temp 根纳入 workspace-write ACL lease,保持原始 DACL rollback、metadata deny、完成度 `44/46 (95.7%)` 与 `Planned/enforced=false` 不变。
|
||||
- 2026-08-26:Windows Quality run `32963357155`(SHA `9af4c627a`,artifact `9604867800`)验证 `%TEMP%/%TMP%` workspace-write ACL lease 已生效,schema v3 从 `1/7` 提升至 `3/7`:`restricted_conpty_supports_stdin_resize_and_combined_output`、`restricted_execution_bounds_large_output`、`world_writable_audit_reports_everyone_write_acl` 通过;普通 pipe 的 workspace write、offline network、allowlisted stdin 与 terminate 仍失败,均表现为 PowerShell 在首条输出前 exit `1`,terminate 因 runner 已结束返回 `ControlClosed`。继续对照 Codex `windows-sandbox-rs::desktop::LaunchDesktop` 与 `process::spawn_process_with_pipes` 后确认 Lime 只填 `Winsta0\\Default` 字符串,未创建并授权 sandbox logon SID 的 desktop;当前修复新增 `windows_desktop::LaunchDesktop`,按 child token 的 logon SID 创建/授权短生命周期 desktop,并让 pipe/ConPTY 的 `STARTUPINFOEX` 复用同一 desktop,child/descendants 完成后再释放。新增 `windows-sys` 的 GDI/StationsAndDesktops features;本机 `test:rust:related` `373/373`、`cargo fmt --check`、`git diff --check` 通过,但无 Windows target,下一轮必须由 MSVC runner 验证,完成度继续 `44/46 (95.7%)`、readiness 继续 `Planned/enforced=false`。
|
||||
- 2026-08-26:Windows Quality run `32965197227`(SHA `07b04bfcb`,artifact `9605628837`)已通过 elevated setup 和 MSVC 编译,schema v3 七项矩阵完整执行仍为 `3/7`:ConPTY stdin/resize/combined output、bounded large output 和 Everyone-write audit 通过,workspace write、offline account/network block、allowlisted stdin 与 terminate/job cleanup 失败。该结果排除 private desktop 是四项失败的单一根因,但不证明该安全对齐无需保留。已收紧四个失败断言:workspace 在 child 提前终态时立即打印 snapshot,offline/stdin/large-output 打印终态 `retained_output`,terminate 在发送控制前记录早退状态;不新增矩阵项、不放宽 token/ACL/firewall。本机 `npm run test:rust:related -- lime-rs/crates/tool-runtime/tests/windows_restricted_execution.rs` 退出码 `0`,反向依赖链与 `tool-runtime 373/373` 通过;Windows-only 断言编译/执行待新的 MSVC run。完成度继续 `44/46 (95.7%)`,readiness 继续 `Planned/enforced=false`。
|
||||
|
||||
## 7. 阻塞与避让
|
||||
|
||||
|
||||
@@ -137,9 +137,15 @@ fn sddl_sids(sddl: &str) -> HashSet<String> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
async fn wait_for_path(path: &Path) {
|
||||
async fn wait_for_path(handle: &LocalExecutionProcessHandle, path: &Path) {
|
||||
tokio::time::timeout(Duration::from_secs(5), async {
|
||||
while !path.exists() {
|
||||
let snapshot = handle.status();
|
||||
assert!(
|
||||
!snapshot.status.is_terminal(),
|
||||
"restricted process exited before creating {}: {snapshot:#?}",
|
||||
path.display()
|
||||
);
|
||||
tokio::time::sleep(Duration::from_millis(25)).await;
|
||||
}
|
||||
})
|
||||
@@ -194,7 +200,7 @@ async fn workspace_write_allows_workspace_and_denies_metadata_and_external_paths
|
||||
request.stdin = true;
|
||||
let mut handle =
|
||||
start_local_execution_process(request).expect("restricted workspace process should start");
|
||||
wait_for_path(&inside).await;
|
||||
wait_for_path(&handle, &inside).await;
|
||||
|
||||
let baseline_workspace_sddl = &acl_baselines[0].1;
|
||||
let active_workspace_sddl = acl_sddl(&workspace);
|
||||
@@ -291,7 +297,11 @@ async fn restricted_execution_uses_offline_account_and_blocks_network() {
|
||||
)
|
||||
.await;
|
||||
assert_eq!(snapshot.status, ExecutionProcessStatus::Exited);
|
||||
assert_eq!(snapshot.exit_code, Some(0));
|
||||
assert_eq!(
|
||||
snapshot.exit_code,
|
||||
Some(0),
|
||||
"offline restricted process must exit successfully: {snapshot:#?}"
|
||||
);
|
||||
assert!(
|
||||
marker.is_file(),
|
||||
"offline process must execute inside the workspace"
|
||||
@@ -325,6 +335,11 @@ async fn restricted_execution_bounds_large_output() {
|
||||
.await;
|
||||
|
||||
assert_eq!(snapshot.status, ExecutionProcessStatus::Exited);
|
||||
assert_eq!(
|
||||
snapshot.exit_code,
|
||||
Some(0),
|
||||
"large-output restricted process must exit successfully: {snapshot:#?}"
|
||||
);
|
||||
assert!(snapshot.output_truncated, "large output must be truncated");
|
||||
assert!(
|
||||
snapshot.output_omitted_bytes > 0,
|
||||
@@ -349,7 +364,11 @@ async fn restricted_execution_preserves_allowlisted_stdin_handle() {
|
||||
let snapshot = run_to_terminal(handle).await;
|
||||
|
||||
assert_eq!(snapshot.status, ExecutionProcessStatus::Exited);
|
||||
assert_eq!(snapshot.exit_code, Some(0));
|
||||
assert_eq!(
|
||||
snapshot.exit_code,
|
||||
Some(0),
|
||||
"stdin restricted process must exit successfully: {snapshot:#?}"
|
||||
);
|
||||
assert!(
|
||||
snapshot.retained_output.contains("received:sandbox-input"),
|
||||
"child output should contain the stdin payload: {:?}",
|
||||
@@ -442,6 +461,11 @@ async fn terminate_ends_restricted_process_and_its_job() {
|
||||
.expect("long-running process should start");
|
||||
|
||||
tokio::time::sleep(Duration::from_millis(250)).await;
|
||||
let before_terminate = handle.status();
|
||||
assert!(
|
||||
!before_terminate.status.is_terminal(),
|
||||
"terminate target exited before control could be sent: {before_terminate:#?}"
|
||||
);
|
||||
handle
|
||||
.terminate()
|
||||
.expect("terminate should reach supervisor");
|
||||
|
||||
Reference in New Issue
Block a user