Skip to content

test(windows): automate W1a-W1h on a real Windows host (issue #119) - #128

Open
FuRongJun-1999 wants to merge 4 commits into
T-Auto:mainfrom
FuRongJun-1999:test/windows-host-verification
Open

FuRongJun-1999 wants to merge 4 commits into
T-Auto:mainfrom
FuRongJun-1999:test/windows-host-verification

Conversation

@FuRongJun-1999

Copy link
Copy Markdown

这是什么

issue #119 要的两样交付,这一份 PR 都带上了:真 Windows x64 宿主的实测,以及作者更想要的那个结果——把 A 半场自动化成随门禁跑的套件。

实测宿主:Windows 11 Pro x64 · NTFS · Node v24.18.0 · worker 由本仓源码构建(npm run build:ptc)。

新套件:test/windows-security.test.mjs(8 检查,全绿)

项 结果 说明
W1a finding 确认,且比预期更糟 显式只读授权(user:(R)、已断继承)在替换后变成 user:(F) 完全控制——不只是丢 DACL,是放大了访问。icacls before/after 原文在套件输出里
W1b finding 确认 他者主体的 deny ACE(Guest:(DENY)(W))在成功替换后消失——限制被无声移除
W1c 同用户属主不变 跨用户场景仍需第二账号,保持 manual
W1d 确认 READONLY 目标以结构化错误拒绝(error.code 在场),原文未动,无残片
W1e 确认 无共享打开的目标同样结构化拒绝、无残片。实测细节:deny(W)/deny(D) 连 Node 自己的 readFileSync 都挡(libuv 打开请求超出被允许的位),因此夹具在释放持有者之后才断言
W1g 确认 sidecar 锁下无竞争替换成功;竞速败者拿到结构化 REVISION_CONFLICT(非裸平台错误)
W1h 确认 替换飞行中连续读目标/目录 0 次被拒(8 次替换 × 持续读)

W1a/W1b 以 finding 模式锁定当前行为——测试名里写明这是 finding;ReplaceFileW 修复落地时,CI 会强迫这次翻转是有意识的而不是顺手的。

顺带的 harness 修复(1 行)

test/lib/harness.mjs 的清理 rmSync 加了 maxRetries:Windows 对刚碰过的路径会瞬态 EPERM(Defender 扫描、句柄交接),一次 EPERM 就崩掉整个门禁的清理——审计 W1 时实测撞上。rmSync 的文档契约本就覆盖 EPERM 重试。

已知与本机环境预存、与本 PR 无关

本机的 bash-ipc(MSYS 私有 runtime 校验)与 permissions/ptc 在干净基线(stash 本 PR 全部改动后)同样失败,属宿主环境预存;CI hosted runner 不受影响(issue 正文已列它们在云上跑通)。

边界

)

docs/windows-verification.md listed what only a real Windows host can answer
about ops_replace. This adds test/windows-security.test.mjs, which runs the
shipped worker through the standard boundary and answers all of it:

- W1a/W1b in finding mode: an explicit DACL does not survive a replacement -
  measured: the read-only grant comes back as (F) full control (widened); a
  deny ACE for another principal is dropped. Assertions lock the finding in
  so the ReplaceFileW fix must flip them consciously.
- W1c: same-user owner unchanged (two-user case stays manual).
- W1d/W1e: READONLY and no-share targets refuse with structured errors,
  nothing rewritten, no debris. Measured: deny(W)/deny(D) on the target also
  blocks Node's own readFileSync, so fixtures assert after releasing holders.
- W1g/W1h: uncontended replace succeeds under the sidecar lock, a racing
  loser reports structured REVISION_CONFLICT, reads never fail in flight.

harness: rmSync gains maxRetries - Windows transiently denies a just-touched
path (Defender scans, handle handoff) and one EPERM at cleanup crashed the
whole gate; documented rmSync contract covers EPERM retries.

Measured on Windows 11 Pro x64, NTFS, Node v24.18.0, worker from this tree.
Raw icacls before/after is in the suite output and summarized in
docs/windows-verification.md. Pre-existing on this host and unrelated:
bash-ipc MSYS acceptance and permissions/ptc provisioning (verified by a
clean-baseline stash experiment).
@T-Auto

T-Auto commented Oct 18, 2026

Copy link
Copy Markdown
Owner

本轮检查发现 main 已有 #187 的 Windows owner/group/DACL/时间戳保留修复及对应真实 worker 覆盖,但本 PR 不能直接当重复关闭:W1d/e/g/h 与清理重试仍有价值。合入前需把 W1a/W1b 旧的“权限丢失即通过”断言改为精确保留或明确拒绝,更新历史测量文案并跑新 head CI。跨账号与 ADS/MOTW 未测部分请继续显式保留,不能把别的 metadata 套件通过视为全部 W1 验收完成。

…doc the fixed state

Per the T-Auto#128 review: main now carries T-Auto#187 (Windows owner/group/DACL/timestamp
preservation in the private-sibling path), so the W1a/W1b assertions that used
to lock in the pre-fix finding must flip to exact preservation.

- W1a: explicit `(R)` survives the replacement unchanged; no inherited ACE
  comes back (before/after icacls printed by the suite).
- W1b: the `Guest:(DENY)(W)` ACE survives a successful replacement.
- Header and docs/windows-verification.md now describe the fixed state;
  the 2026-10-15 pre-fix measurement is kept as the historical record.
- Rebuilt the win32-x64 native runtime from the merged tree (build:ptc).

Verified on a real Windows 11 x64 host: windows-security suite 8/8 passed
(W1a before/after icacls identical; W1b DENY present after replace).
@FuRongJun-1999

Copy link
Copy Markdown
Author

@T-Auto 更新好了,麻烦再看一下:

  1. 冲突:已经把最新的 main 合进来了(合并提交 1f49b94)。
  2. 断言按你说的改了:
    • W1a:以前是「授权丢了就算过」,现在改成「授权必须原样保留」——改完后用户组的 (R) 还在,继承的权限不会回来。
    • W1b:改完后拒绝项(Guest 的 DENY)必须还在,不能丢。
  3. 文档:docs/windows-verification.md 改成了「已经修好」的说法;10 月 15 日那次旧测量留着当历史记录,标了「修复前」。
  4. 本机真跑(Windows 11 x64,用合并后的代码重新编译 worker):
    • W1a:改之前和改之后的 icacls 输出一样((R) 没变,没有 (I))。
    • W1b:改完之后 DENY 还在。
    • 8 项检查全过(8/8)。
  5. 还没测的:跨账号(两个用户)、ADS/MOTW 这些还是「没测」,文档里照实写着,没有当成已经测完。

新提交已经推上来了,CI 会在新 head 上跑。

@FuRongJun-1999

Copy link
Copy Markdown
Author

@T-Auto 看了一下,这里不是代码冲突:

  • 分支已经合进最新 main(4b51b63),合并状态是 MERGEABLE,diff 里没有冲突标记。
  • 红色「Merging is blocked」是两道门:
    1. 需要你这边批准(review required);
    2. 「Cross-platform validation」工作流在等批准——首次贡献者要手动点一次,那个红色 action_required 就是这个。

你在页面里点「Approve and run」后 CI 就会跑;跑完如果哪项没通过,我再修。

本机 Windows 11 x64 真跑:8 项检查全过(W1a / W1b 的 icacls before/after 就在套件输出里)。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants