Files
HomeAgent/cmd/waiter
JianFeeeee 3da060f5a1 fix: 修 CI 抓到的两类真实缺陷(.syso 破坏 arm64 + 测试硬编码 /etc)
第一次 CI 跑出 2 类失败,都是**本地以 root/amd64 跑永远看不见**的问题。
这正是建 CI 的价值:换一个环境就暴露了。

## 一、.syso 无条件被链进所有平台 → arm64 交叉编译必炸

CI 报:
  $WORK/b001/_pkg_.a(waiter.syso): 310766: unknown ARM64 relocation type 3
  (linux/arm64 与 darwin/arm64 两个 job 都红;amd64 两个都绿)

根因(已在本地用 Go 1.25.9 + arm64 精确复现):Go 会把**同目录的 *.syso
无条件链进任何 GOOS/GOARCH**,而这两个 .syso 是 Windows 资源对象
(x86-64 COFF,只含 .rsrc 图标段)。链进 arm64 目标即报「未知 ARM64 重定位」。

仓库其实**早就知道**这件事 —— deploy/packaging/build.sh:86-90 写着
「Go 会把同目录的 .syso 无条件链进任何目标」,并留了 hide_syso_for_target()
绕过,注释还点名「这正是 arm64 产物长期缺失的原因(曾被误判为缺 g++
交叉编译器)」。但那是打包脚本里的私有绕道:任何**直接 go build** 的路径
(包括 CI、包括本机原生 arm64 构建)都仍会撞上。修在源头而不是再加一层绕道。

修法分两种,因为两个文件的处境**完全不同**:

1. cmd/waiter/waiter_windows_amd64.syso(原 waiter.syso,git mv)
   waiter **仍支持 Windows**(package-windows.sh:68 明确构建 waiter.exe),
   所以不能删。按 Go 的文件名约定加 _windows_amd64 后缀 ⇒ 只在
   windows/amd64 被链入。实测:linux/amd64、linux/arm64、darwin/arm64、
   windows/amd64 四平台全部通过,且 Windows 产物的 .rsrc 段大小
   (00049eb8 字节)与改动前**逐字节一致** —— 图标没丢。

2. cmd/homed/{homed.syso,homed.rc} 删除
   homed 的 Windows 原生支持**已放弃**,五处独立来源一致:
     - README.md:251「homed 放弃 Windows 原生支持改走 WSL2」
     - cmd/homed/platform_windows.go 的 requireSupportedPlatform 直接拒绝启动
       (理由是设计性的:fd 继承 + 同段内偏移解引用,Windows 句柄模型无法表达)
     - package-windows.sh:4「❗安装器不往 Windows 装 homed」
     - build.sh:35「Windows 不再安装 homed.exe」
     - installer.nsi:230「homed 不再装到 Windows」
   即 homed.exe 即便构建出来也拒绝运行 ⇒ 图标资源毫无意义,却是 arm64
   构建失败的来源之一。顺带查明:homed.syso 与 waiter.syso 本是**同一个
   blob**(两个 .rc 指向同一 icon),属纯重复。

★ 由此留下一处**未修的残留**(已确认,不在本次范围):installer.nsi:297,313
  仍在创建指向 homed.exe 的快捷方式与 Run 注册项,而同文件 230 行已声明
  homed 不装 Windows。那是 Windows 安装器的独立缺陷,需单独处理。

## 二、internal/system 测试硬编码 /etc → 非 root 必失败

CI 报:
  system_test.go:51: expected archive to happen
  system_test.go:97: expected restore to happen

测试写死 target := "/etc/xxx.test.tmp" 并**忽略了 os.WriteFile 的错误**。
GitHub Actions runner 以非 root 运行 ⇒ 写 /etc permission denied ⇒ 文件
不存在 ⇒ ArchiveBeforeWrite 按「新建文件无需留档」返回 false ⇒ 断言失败。
本地以 root 跑则一路通过 —— 缺陷因此长期不可见。

修法:用仓库**已有**的 SetProtectedPaths([]string{临时目录}) 显式声明受保护
前缀(不再碰真实 /etc),defer SetProtectedPaths(nil) 复原默认。既去掉了对
root 的隐式依赖,也没有削弱被测语义(保护的仍是「受保护前缀下的文件」)。

## 验证

- go test ./... -count=1        全绿
- go build ./...                通过
- waiter 四平台交叉编译          全通过(含此前必红的 arm64)
- homed linux/amd64 原生构建     通过(确认删除 .syso 无害)
- Windows 产物 .rsrc 段          改动前后一致(00049eb8 字节)
2026-09-29 13:18:27 +08:00
..