发 v1.0.9 前发现两个真问题,都会直接影响用户拿到的附件。 一、docker-compose.yml 里的镜像标签是硬编码的 1.0.8 这两个文件是**直接挂到 GitHub Release 上的附件**,用户照着抄命令。 早先它们硬编码具体版本号,每次发版要人工 sed 一遍 —— 这次就漏了: 附件里写着 `image: drouter:1.0.8`,而镜像 tar 加载后的标签是 `drouter:1.0.9`, `docker compose up` 直接报「找不到镜像」。DOCKER-GUIDE.md 另有 14 处同样问题。 改成 __VERSION__ 模板,由 build-docker.sh 渲染(版本从 packaging/VERSION 读)。 渲染分两步,顺序不能反:先删 TEMPLATE-NOTE 标记块(那是给维护者看的 「这是模板」提示,留着用户会看到「1.0.9 是占位符」这种自相矛盾的话), 再替换占位符。先替换的话,标记块里的 __VERSION__ 也会被换掉。 retag-docker-image.py 同样问题:NEW_TAGS 硬编码。改完参数化。 这个 bug 更隐蔽 —— 拿 1.0.9 的镜像跑重标记会打上 1.0.8 的标签, 用户 load 完看到的标签与附件说明对不上。 t-packaging.py 补 12 条判据卡住这些(4 条已做反向验证:注入即红、还原即绿)。 判据只抓「紧挨 drouter 标识或产物文件名」的版本号 —— 一刀切拦所有 x.y 会 误伤「1.0.1 起 Web 终端绕开 init」这种历史沿革说明和「GPL-3.0」许可证名。 二、t-worktree-clean.py 抓不到「注释掉整行代码」型注入 跑回归时 t-107 红了 1 项,查出来是 t-107-inject-wg.py 把 `'env': _vpn_env(),` 注释掉了没还原(SIGTERM 打断,finally 没执行)—— 和 v1.0.8 那次 `/nonexistent` 残留一模一样的坑,但**形态不同**: 不含任何哨兵字样,原判据的 4 个哨兵全都抓不到。 后果很实:_vpn_status 不返回 env,前端拿不到四态诊断, VPN 页面的三个修复按钮全废。这正是 v1.0.8 声称修好的那个 bug。 补两条判据: - 扫「被注释掉的整行代码」:去掉 # 后能 ast.parse 成功,且含调用/赋值/return/dict 项 - 扫 CRLF:Windows 工具写文件会整篇改行尾,sync.sh 预检才拦太晚 判据本身踩了三个坑,都记在注释里: - dict 项 `'env': _vpn_env(),` 单独 ast.parse 会 SyntaxError(没大括号), 真正的注入反而被放过 → 补大括号再解析 - dict 项的键**通常带引号**,正则只写 ^[A-Za-z_] 认不出来 → 改成同时认引号键 - 分隔线注释 `# ------ radvd` 里的 ----- 会被解析成负号表达式 → 按前缀排掉 双向验证:4 种注入形态(赋值/dict项/bool/列表)全部精确报到行号, 基线零误报(排掉了分隔线注释和「# module: (service, action, 中文名)」这类 长得像 dict 项的文档注释)。 三、_dev/dl-verify.py(新增) 从目标机往 Windows 拉大产物时发现的坑,记成脚本省得下次重踩: - `ssh host 'cat f' > out` 在 Windows 上做**文本模式换行转换**,二进制被破坏 (实测 deb 少 4 字节,sha256 直接对不上)→ 走 base64 再本地解码 - Windows Python 看不到 Git Bash 的 /tmp,必须给 C:/ 绝对路径 - scp 传完一定要判 sha256 —— scp/ssh 都可能「返回 0 却落地 0 字节」 - 落地走 .part + os.replace,避免写一半失败留下半个产物 顺带修了 build-docker.sh 里一处路径笔误 (packaging/docker/packaging/docker/DOCKER-GUIDE.md)和步骤编号 1/3→1/4。
44 lines
1.5 KiB
Python
44 lines
1.5 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: utf-8 -*-
|
|
"""把 Git Bash 里 /tmp 下的 .b64 解成目标二进制文件,并核对字节数与 sha256。
|
|
|
|
为什么需要它(Windows 上的三个坑):
|
|
1) `ssh host 'cat f' > out` 在 Windows 上会做**文本模式换行转换**,
|
|
二进制被破坏 —— 实测 deb 少了 4 字节,sha256 直接对不上。
|
|
所以走 base64(纯 ASCII,不受转换影响),再本地解码。
|
|
2) Windows Python **看不到** Git Bash 的 /tmp。/tmp 实际映射到
|
|
%TEMP%,两边指的是同一个目录,但 Python 必须给 C:/ 开头的绝对路径。
|
|
3) 传完一定要判 sha256 —— scp/ssh 都可能「返回 0 却落地 0 字节」。
|
|
|
|
用法:dl-verify.py <b64文件> <落地路径> <期望字节数> <期望sha256>
|
|
"""
|
|
import base64
|
|
import hashlib
|
|
import os
|
|
import sys
|
|
|
|
b64path, outpath, nbytes, sha = sys.argv[1:5]
|
|
nbytes = int(nbytes)
|
|
|
|
with open(b64path, 'rb') as f:
|
|
raw = f.read()
|
|
blob = base64.b64decode(raw)
|
|
|
|
ok_len = len(blob) == nbytes
|
|
h = hashlib.sha256(blob).hexdigest()
|
|
ok_sha = (h == sha)
|
|
|
|
# 先写临时文件再原子替换:避免「写到一半失败」留下半个产物
|
|
tmp = outpath + '.part'
|
|
with open(tmp, 'wb') as f:
|
|
f.write(blob)
|
|
os.replace(tmp, outpath)
|
|
|
|
print(' 落地 : %s' % outpath)
|
|
print(' 字节数 : %d (期望 %d) %s'
|
|
% (len(blob), nbytes, 'OK' if ok_len else 'FAIL'))
|
|
print(' sha256 : %s' % h)
|
|
print(' 期望 sha : %s' % sha)
|
|
print(' sha256 : %s' % ('OK' if ok_sha else 'FAIL'))
|
|
sys.exit(0 if (ok_len and ok_sha) else 1)
|