6.3 KiB
6.3 KiB
id, title, phase, deps, status, created, issue, context_ref, claim_branch, work_branch, write_paths
| id | title | phase | deps | status | created | issue | context_ref | claim_branch | work_branch | write_paths | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| T-501 | 机器指纹 machine_hash | 5 |
|
DONE | 2026-07-19 | null | 94ea334487d7180b4af0fb59c129ff678d2c4ad0 | null | agent/codex/T-501 |
|
问题 / 背景
MVP 许可证必须在离线验签前可靠地比较 machine_hash,但仓库尚没有 core/licensing 或平台机器标识采集实现。machine_hash 必须在 modern 和 Win7 两端得到相同的稳定值;它只能是可传递给许可证的摘要,不能使原始设备标识、MAC、卷序列号或注册表值进入许可证、存储、事件、UI 或日志。
此前协议只说“多个稳定硬件标识清洗生成 hash”,同时又把来源和加权算法列为待定。这不足以让许可证签发端、两个客户端和后续 T-502 使用同一不可歧义的值。本任务冻结 v1 的最小双来源算法;它不假装解决硬件更换容错或换绑工作流。
方案
- 在 Go 1.20 兼容且不 import Windows/Gio 的
core/licensing新增纯函数DeriveMachineHash(machineGUID string, systemVolumeSerial uint32) (string, error)。它只接受严格的 Windows GUID(去首尾空白后为 36 位 ASCII UUID,统一为小写)和 uint32 卷序列号;输出为 64 个小写十六进制字符:SHA-256("softbox.machine-hash.v1\\x00" || normalized_machine_guid || "\\x00" || 8 位小写十六进制 volume_serial)。GUID 缺失、非 ASCII、格式不合法或控制字符均返回稳定的无敏感值错误;不提供单来源、MAC 或环境变量回退。 - 在两端
platform/windows提供同名MachineHash() (string, error)composition 边界。Windows 实现仅在进程内短暂读取HKLM\\SOFTWARE\\Microsoft\\Cryptography的MachineGuid,并通过GetWindowsDirectory定位 Windows 目录所在根卷,再以 Win7 已支持的GetVolumeInformationWwrapper 读取卷序列号,最后调用 core 纯函数。采集或规范化失败只返回泛化 sentinel,错误文本不得包含原始标识、卷号、路径或注册表值;不写文件、不发事件、不打日志。 - 为非 Windows 构建提供可测试的 fail-closed stub,返回既有
ErrUnsupported。保留采集拼装的注入 seam,使 Linux 无头测试能覆盖“任一来源失败/非法值不泄漏且不降级”及与 core 输出相同的结果;Windows API 调用本身通过交叉编译验证,不将宿主机器的真实标识写进测试或测试输出。 - 固定 API、架构、路线图和项目快照中的 v1 来源、规范化、算法和隐私边界。明确 v1 要求两个来源都可用;设备或系统卷变化须由后续许可证 rebind 策略处理,不能在客户端悄悄采用加权、部分匹配或降级 hash。T-502 只消费此函数返回的 hash 并完成 Ed25519 许可证解析/验签/比对。
验收要点
- 纯 core 算法在 Go 1.20 可编译,对大小写/首尾空白等价 GUID 生成确定的 64 字符小写 SHA-256;非法 GUID、空值、控制字符和不同卷号均有受测的 fail-closed 结果,不存在隐式 MAC、单来源或随机回退。
- 双端 Windows 层均使用相同的 core 算法与相同的两个来源;不修改宽泛
Platform接口、不把 Windows API 带入 core,也不在静态导入表中引入 Win7 不支持 API。Windows 目录/卷查询、注册表读取或 core 拒绝时不暴露任何 raw identifier,且不产生持久化副作用。 - Linux/非 Windows 下
MachineHash稳定返回ErrUnsupported;可注入的采集 seam 覆盖 GUID 读取失败、卷读取失败和非法 GUID,测试断言错误文本不含伪造 raw input。测试资料、断言、文档和执行记录均不得记录真实主机标识。 go -C core vet ./...、go -C core test -count=1 ./...、modern 与 Win7 的go test -count=1 ./...、双端 Windows amd64 主程序构建、./scripts/verify_phase0.ps1、python scripts/validate_agent_context.py与python scripts/validate_harness_governance.py全部通过。
边界(不改什么)
- 不实现许可证 JSON 解析、Ed25519 验签、公钥、导入/试用/换绑 UI、撤销名单、许可证存储、服务端签发或子软件 SDK;这些属于 T-502/T-503 与仓库外服务端。
- 不收集 MAC、BIOS/CPU/磁盘序列号、用户名、网络信息或广告标识;不持久化、显示、上传或记录
MachineGuid、卷序列号或其他原始标识。 - 不修改 Catalog、下载、安装、更新、自更新、Gio Layout、数据目录或 Windows API 兼容策略;不把开发机实际机器摘要写入源码、fixtures、文档或提交。
协作约束
- 当前项目为单 Agent 串行模式;当前 Agent 独占全部
write_paths,自行完成规格、实现、测试、审查、状态更新和提交,不启动子 Agent。 - 本规格提交后才领取任务:将本文件改为
DOING,记录当时 HEAD 至context_ref与work_branch: agent/codex/T-501,重跑基线后再实现。完成后只更新本任务为DONE,不提前落成或实现 T-502。
执行记录
- 2026-07-19:正式落成。冻结 machine_hash v1 的两个必需来源、严格规范化和带域分隔的 SHA-256 输入;拒绝单来源/加权回退,避免后续许可证签发端与双客户端生成不一致的摘要。确认两套现有
x/sys/windows版本均提供 Win7 可用的GetWindowsDirectory和GetVolumeInformation。 - 2026-07-19:领取任务,基于
94ea334487d7180b4af0fb59c129ff678d2c4ad0在agent/codex/T-501执行;先重跑基线,再实现纯 core 算法和双端受限采集边界。 - 2026-07-19:完成。新增 Go 1.20 兼容的
core/licensing.DeriveMachineHash,以严格 ASCII GUID 规范化、固定域分隔和卷序列号生成小写 SHA-256;无效输入只返回无敏感值 sentinel。双端platform/windows.MachineHash短暂读取注册表和 Windows 目录所在卷,所有采集/规范化失败均折叠为不泄漏原始值的错误;非 Windows stub 保持ErrUnsupported。局部 core/双端平台测试、完整 core/双端 app 测试和 Windows amd64 构建、./scripts/verify_phase0.ps1、上下文与治理校验均通过。