# 交付包校验和审计：缺失、多余与字节更改

确认收到的文件夹恰含预期本地普通文件，且字节内容一致。校验和只检测相对可信副本的变化，不是作者签名或媒体质量检查。

完整包只使用 Node 标准库。不需要安装媒体工具。

在本目录运行，并选择不存在的新输出目录，脚本拒绝覆盖。受内存管理的工作站可在 Node 命令前加本地串行执行包装器。不需要提供商密钥，夹具不会向设备外发请求。

```sh
node run-recipe.mjs --out ./my-run
```

实际记录：9项检查通过，包含6项预期拒绝，Node v24.18.0。未启动 FFmpeg 子进程。

准备

- 准备 Node.js，仅使用内置文件与加密模块。原创 delivery/ 中包含 delivery-notes.txt、shots.json、captions.srt。
- 查看放在 delivery/ 之外的 delivery-manifest.json，三行分别绑定 basename、字节数与 SHA-256；不对清单自己求哈希，以免循环自引用。
- 使用新输出目录，把预期清单与可编辑接收文件分开保留。配套三个原始交付文件合计171字节，不包括回执和说明。

## 01. 固定预期文件集合

脚本创建原创小型交付包，记录排序文件名、字节数与 SHA-256。要求文件集合完全相同：多出的文件应成为可复核差异，不能默默忽略。

## 02. 只接受安全普通文件

先验证唯一且安全的 basename，比较预期与实际集合，再用 lstat 在读取内容前拒绝符号链接。本例只审计一层目录，不是任意嵌套压缩包或并发不可信文件系统审计。

## 03. 同时比较大小与完整字节哈希

逐文件检查大小及 SHA-256。等长变体实际翻转 delivery-notes.txt 的一个字节，证明只看大小不够。SHA-256 证明相对这份预期清单一致，不自动证明清单作者可信。

## 04. 恢复后再次审计交付包

脚本临时移走文件、添加多余文件、修改字节和替换为符号链接，并在 finally 恢复原文件；另测重复清单路径和 ../outside.txt。恢复后的交付包再次通过，九项检查有回执。

验收

- 干净 delivery/ 恰好包含声明的三份普通文件。
- 所有预期 SHA-256 都为64位小写十六进制摘要。
- 缺少文件和出现额外文件分别被拒绝。
- 保持文件大小的单字节修改仍会校验失败。
- 重复清单路径、父目录路径与符号链接均被拒绝。
- 所有负向夹具恢复后，交付包再次通过，九项检查全部通过。

排错

字节数全都一致，审计仍失败。只对照报告文件的实际 SHA-256 与预期行，恢复正确字节，不移除哈希检查。

交付包多出一份导出。先决定该文件是否属于交付；只移除误放文件，或明确修改预期清单并重新审查。

快捷方式或符号链接被拒绝。只把该条目换为真正的本地普通文件，再记录目标字节并重跑集合与 SHA-256 检查。

公开回执副本仅归一化本地 checkout 路径，publicPathNormalization 保存原始回执 SHA-256；未改动原件保留在非公开资产之外。真实回执位于 executed/。failure-receipt.json 记录预期负向案例，不表示套件断言失败。原创新夹具会重新生成到指定新目录，包内保留实跑输入输出便于复核。临时原始数据和本机 HTTP 服务在 finally 清理。

checksums.json 覆盖自身与 ZIP 以外的全部分发文件，避免循环自引用；ZIP 内包含同份清单。下载后可重算，但比较前提是预期清单可信。execution-receipt.json 记录实际脚本运行前后哈希，ZIP 也会由发布目录的资产清单绑定。

把可信清单与实际审计回执一同交付。本检查不解码视频、不证明作者身份，也不能保护一份本身已被替换的清单。

2026-10-14 实际读取的来源

- Node.js filesystem API: local file inspection：https://nodejs.org/api/fs.html
- Node.js crypto API: SHA-256 hashing：https://nodejs.org/api/crypto.html
