aps-agent/docs/development/packaging-smoke.md

163 lines
11 KiB
Markdown
Raw Normal View History

# Defender 冒烟与离线安装包完整性校验
> round-43 并行 sub agent 方向 CC(矩阵 99 / 118 本地可测部分)。
> 执行日期:2026-08-02;环境:Windows(PowerShell),Node v22.13.0。
## 1. 验收矩阵与本方向范围
| 矩阵行 | 条目 | 本地可测部分 | 剩余(外部项) |
|--------|------|--------------|----------------|
| 99 | Defender 和真实 APS 求解通过 | Defender 静态扫描冒烟(本机 MpCmdRun.exe,见 §3);真实 APS 求解通过由四引擎黄金测试覆盖(既有测试体系,非本方向交付) | Defender for Endpoint 门户/API 入 CI 门禁;实时防护真实拦截演练 |
| 118 | 干净离线机安装冒烟 | 离线安装包完整性校验:安装包存在/体积/SHA-256 校验和清单 + dry-run 安装路径(见 §4) | 干净离线机(无 Python、无网络)实机安装 + 冷启动 + 升级/回滚验收,需外部验证机 |
硬性纪律遵守情况:未修改 server/**、apps/desktop/**、packaging/**(仅只读读取 apps/desktop/package.json 与 packaging 配置推导产物路径);未 commit/push/merge;未重启 8003/5173。
## 2. 涉及文件
新增(本方向写范围):
- scripts/defender-scan.mjs — Defender 静态扫描冒烟
- scripts/offline-install-check.mjs — 离线安装包完整性校验
- tests/node/packaging-smoke.test.mjs — 两个脚本可测逻辑的 node 单测
- docs/development/packaging-smoke.md — 本文档
运行时产物(build/ 已被 .gitignore 忽略,不入库):
- build/offline-check/offline-install-manifest.json — 校验和清单(机器可读)
- build/offline-check/checksums.sha256 — sha256sum 格式校验和(可随安装包转移)
- build/offline-check/aps-agent-desktop-0.1.0.exe — portable 模式拷贝的安装包
只读引用的既有产物(构建于 2026-07-31,来源见下):
- dist/sidecar/aps-sidecar/aps-sidecar.exe — PyInstaller Sidecar(scripts/build-sidecar.mjs 产出)
- apps/desktop/release/win-unpacked/工业智核 APS.exe — electron-builder win-unpacked 冻结桌面包
- apps/desktop/release/win-unpacked/resources/sidecar/aps-sidecar.exe — 桌面包内置 Sidecar
- apps/desktop/release/aps-agent-desktop-0.1.0.exe — NSIS 安装包(electron-builder,artifactName aps-agent-desktop-0.1.0.exe)
## 3. Defender 静态扫描冒烟(scripts/defender-scan.mjs)
原理:调用本机 Windows Defender 命令行工具做按需静态扫描:
MpCmdRun.exe -Scan -ScanType 3 -File <path> -DisableRemediation
- -ScanType 3 = 自定义文件/目录扫描(目录递归)。
- -DisableRemediation = 只检出不清理,构建产物不会被删除/隔离(本脚本默认开启;如确有威胁,只报告不处理)。
- 退出码按任务约定区分:0 = 通过/无威胁;2 = MpCmdRun 不可用(跳过);非 0(1)= 检出威胁或扫描失败;另定义 3 = 无产物可扫。
用法:
node scripts/defender-scan.mjs # 自动发现并扫描 4 个产物
node scripts/defender-scan.mjs <file-or-dir> ... # 显式指定目标(支持目录递归)
node scripts/defender-scan.mjs --timeout 900000 # 单文件超时(默认 600000 ms,已覆盖百 MB 级安装包)
node scripts/defender-scan.mjs --mpcmdrun <path> # 严格指定 MpCmdRun 路径(不存在则 exit 2)
node scripts/defender-scan.mjs --json # 输出机器可读摘要
node scripts/defender-scan.mjs --no-copy-fallback # 关闭非 ASCII 路径的临时拷贝回退
node scripts/defender-scan.mjs --self-test # 解析器/产物发现自检(不调用真实扫描)
自动发现目标(由 apps/desktop/package.json 只读推导):sidecar-exe、desktop-frozen-exe、
bundled-sidecar-exe、nsis-installer。缺失目标打印 [MISSING] 并跳过。
已知行为(实测确认):
- MpCmdRun 无法解析非 ASCII 路径:对 D:\ItemSpace\14.工业智核\... 下的文件原路径扫描会失败
(node spawn 场景报 CmdTool: Failed with hr = 0x80508023,exit 2;PowerShell 调用场景报
"was skipped",exit 0)。本脚本默认将含非 ASCII 字符的文件拷贝到 ASCII 临时目录后扫描
拷贝(字节相同,结论等价),输出标记 [temp-copy];目录不拷贝、原位递归扫描。
- 威胁检出文本是权威信号(MpCmdRun 在 -DisableRemediation 模式下威胁时 exit 2 且打印
LIST OF DETECTED THREATS;默认清理模式威胁时 exit 0 但打印 found N threats),解析器两种
模式都覆盖,并以输出文本为准判定 clean/threat/skipped/error。
- 扫描结果只输出摘要(状态/威胁名/耗时/策略),不输出大段日志(--json 附 outputTail 便于排查)。
威胁输出解析的正确性已用真实 EICAR 测试文件验证(开发期探测):
- 默认模式:exit 0,输出 Scanning ... found 1 threats.,随后 Cleaning started/finished,文件被清除(约 21.5s)。
- -DisableRemediation 模式:exit 2,输出 LIST OF DETECTED THREATS + Threat : Virus:DOS/EICAR_Test_File,文件保留(约 79ms)。
- 脚本内不自带 EICAR 生成(避免污染本机 Defender 事件),解析用例固化在 --self-test 与单测中。
## 4. 离线安装包完整性校验(scripts/offline-install-check.mjs)
职责:NSIS 安装包(以及相关产物)SHA-256 校验和清单的生成与校验 + dry-run 安装路径检查。
用法:
node scripts/offline-install-check.mjs # 生成清单并立即校验 + dry-run
node scripts/offline-install-check.mjs --verify # 只校验既有清单
node scripts/offline-install-check.mjs --portable # 便携包:拷贝安装包到输出目录并生成相对路径清单
node scripts/offline-install-check.mjs --out-dir <dir> # 默认 build/offline-check
node scripts/offline-install-check.mjs --root <dir> # 解析清单路径的基准目录(默认仓库根)
node scripts/offline-install-check.mjs --localappdata <p> # dry-run 时覆盖 %LOCALAPPDATA%
node scripts/offline-install-check.mjs --json # 机器可读报告
node scripts/offline-install-check.mjs --self-test # 内部冒烟(临时文件,不依赖真实产物)
校验规则:
- 安装包存在性:缺失即 FAIL。
- 体积门禁:安装包 >= 50 MB,其余产物 >= 5 MB(PyInstaller/Electron 产物异常偏小视为失败)。
- 校验和:逐文件流式 SHA-256 与清单比对(存在/大小/哈希全匹配才 PASS;篡改文件会检出 mismatch)。
- dry-run 安装路径:由 apps/desktop/package.json(只读)的 productName 推导 NSIS per-user 默认安装目录
%LOCALAPPDATA%\Programs\<productName>,即 C:\Users\<user>\AppData\Local\Programs\工业智核 APS;
当前目录不存在时报告 dry-run 通过但注明需外部干净离线机实装;若已存在则校验 app 主程序与
resources/sidecar/aps-sidecar.exe 布局是否完整。
离线转移流程(便携包):
1. 构建机执行 node scripts/offline-install-check.mjs --portable
→ build/offline-check/ 内含安装包 + checksums.sha256 + offline-install-manifest.json(路径相对该目录)。
2. 将整个目录拷入 U 盘等介质,在目标离线机执行:
node scripts/offline-install-check.mjs --verify --root <介质目录>
3. 实装后用 dry-run 输出的预期路径核对安装落点。
说明:checksums.sha256 为 UTF-8 编码;中文 Windows 下 PowerShell Get-Content 可能按 GBK 显示乱码
(文件本身正确,可用 node 或 UTF-8 工具读取);机器可读校验以 JSON 清单为准。
## 5. 测试
- 脚本内自检:node scripts/defender-scan.mjs --self-test(8/8 PASS)、
node scripts/offline-install-check.mjs --self-test(7/7 PASS)。
- node 单测:node --test tests/node/packaging-smoke.test.mjs(12/12 PASS)。
覆盖:MpCmdRun 输出解析(clean/threat/skipped/计数/威胁名)、verdict 分类、安装包名模板解析、
产物发现、sha256 确定性、checksums 往返解析、预期安装目录、dry-run 布局检测、体积门禁、篡改检出。
## 6. 本地实测记录(2026-08-02)
Defender 扫描(MpCmdRun: C:\Program Files\Windows Defender\MpCmdRun.exe,签名 1.455.456.0):
[PASS] sidecar-exe dist/sidecar/aps-sidecar/aps-sidecar.exe (17.5 MB) clean 0.2s [temp-copy]
[PASS] desktop-frozen-exe apps/desktop/release/win-unpacked/工业智核 APS.exe (215.2 MB) clean 0.1s [temp-copy]
[PASS] bundled-sidecar-exe apps/desktop/release/win-unpacked/resources/sidecar/aps-sidecar.exe (17.5 MB) clean 0.2s [temp-copy]
[PASS] nsis-installer apps/desktop/release/aps-agent-desktop-0.1.0.exe (163.1 MB) clean 1.0s [temp-copy]
Verdict: PASS(exit 0,无威胁,skippedCount 0)
副产品验证:--no-copy-fallback 对非 ASCII 路径原位扫描 → 正确报失败(hr 0x80508023,exit 1),
佐证 temp-copy 回退是必要且正确的。
离线安装包校验:
generate(4 条目): PASS — nsis-installer / sidecar-exe / desktop-frozen-exe / bundled-sidecar-exe
verify(复用清单): PASS
portable 便携包 : PASS(build/offline-check/ 内含 aps-agent-desktop-0.1.0.exe 171,025,378 B)
verify --root build/offline-check(模拟介质目录): PASS
dry-run 安装路径 : C:\Users\andy_\AppData\Local\Programs\工业智核 APS — 当前机器未安装(存在性 false),
实机安装需外部干净离线机
SHA-256 清单(与 build/offline-check/offline-install-manifest.json 一致):
nsis-installer 044c4a83aaf28476a1e2405a7a08185b5aff0dfab27f0299b8bcf16c8d32bf21
sidecar-exe 88abc8b1ae0d4bbd715ee9a263cf107198c183b040728711c28c1ae65a8e8f39
desktop-frozen-exe f5b4b22b3c7bd0dbb5708d90238b744f7b51f8ef682081b2458732954cf6cef4
bundled-sidecar-exe 88abc8b1ae0d4bbd715ee9a263cf107198c183b040728711c28c1ae65a8e8f39
产物来源说明:全部产物为 2026-07-31 既有构建(scripts/build-sidecar.mjs 产出 Sidecar;
electron-builder 产出 win-unpacked 与 NSIS 安装包,apps/desktop/release/),本次未重建、未修改。
## 7. 矩阵达成情况与剩余风险
矩阵 99(Defender + 真实 APS 求解):
- 本地部分达成:Defender 静态扫描冒烟 4/4 产物 clean;解析器经真实 EICAR 输出格式验证。
- 真实 APS 求解通过:由四引擎黄金测试覆盖(既有体系,本方向不重复交付)。
- 剩余(外部):Defender for Endpoint 门户/API 入 CI 门禁;实时防护真实拦截演练(本机实时防护已开启,
但真实拦截需受控样本与策略配合)。
矩阵 118(干净离线机安装冒烟):
- 本地部分达成:安装包存在/体积/校验和/清单生成与校验/dry-run 路径全部通过。
- 剩余(外部):干净离线机(无 Python、无网络)实机安装 + 冷启动 + 升级/回滚验收;需外部验证机,
可用 §4 portable 流程随 U 盘执行。
已知限制:
- 本机非管理员,无法读取 MpPreference 排除项;若存在路径排除,Defender 会 skipped(exit 0 + WARNING),
需在门禁前人工复核排除策略。
- 扫描为静态按需扫描(-ScanType 3),不等价于实时防护全链路;安装包未签名(既有事实,需签名证书)。