技术札记

实战 FlowGuard:我用 HHY 写了一个可进 CI 的项目质量门禁

用 HHY 把文件检查、凭据扫描、质量命令、HTTP 健康检查和结构化报告串成一条可验证的 CI/CD Flow。

HOUHUIYANG.COM

扫码继续阅读

正在生成…

实战 FlowGuard:我用 HHY 写了一个可进 CI 的项目质量门禁

houhuiyang.com/zh/notes/building-flowguard-with-hhy

我一直不太愿意用“能打印 Hello World”证明一门语言已经可用。

对 HHY 这样的系统脚本语言,更有价值的问题是:它能不能接住一个有文件系统、子进程、HTTP、并发、失败隔离、结构化输出和稳定退出码的完整任务?FlowGuard 就是我给出的第一个实战答案。

它接收项目目录、JSON 配置和报告路径,检查必需文件,扫描大文件与疑似凭据,并发执行质量命令与服务健康检查,最后原子写入 JSON 报告。没有失败返回 0,有失败返回 1,参数错误返回 3。

质量门禁不是一串命令,而是一条即使局部失败,也必须完整收集事实的工作流。

FlowGuard 的真实项目目录

入口只负责编排

flowguard.hhy 没有塞进所有业务细节。结构、文件、命令、HTTP 和报告分别放进六个模块,入口只负责组合:

let structure_checks = inspect_structure(root, config.required_files)
let file_checks = inspect_files(root, config.limits.large_file)
let command_checks = inspect_commands(root, config.commands)
let health_checks = inspect_health(config.health_checks)
let checks = combine([structure_checks, file_checks, command_checks, health_checks])
let report = build_report(config.project.name, args[0], checks)

report
    |> encode_json({ pretty: true })
    |> save_text(output_path, { atomic: true })

这段代码是我希望 HHY 表达出来的形状:输入、变换、副作用和结果边界都清楚。模块不是为了展示语法,而是为了让某一类检查可以独立修改和测试。

attempt 比“一遇错就退出”更重要

门禁最常见的错误,是第一项失败后整个脚本退出。这样 CI 只能告诉你测试失败,却来不及继续检查健康接口、缺失文件和凭据风险。

FlowGuard 把每条外部命令包装进 attempt,将运行错误变成普通数据;HTTP 检查也采用同样方式。失败会形成一条 status: "fail" 的检查记录,而不是终止整份报告。

let execution = attempt {
    run(command.argv, {
        cwd: root,
        timeout: 15s,
        max_output: 1mib
    })
}

命令参数始终以 argv 数组交给 run,不拼接 shell 字符串;每个命令还有 15 秒和 1 MiB 输出上限。这里的重点不是少写几行,而是默认把注入、失控进程和无限输出排除在正常路径之外。

并发需要上限,扫描需要脱敏

质量命令使用 parallel(3),健康检查使用 parallel(4)。这些任务大多在等待进程或网络,有界并发能缩短总时间,又不会让配置里增加十几个服务后瞬间打满资源。

文件扫描会寻找私钥头、DEMO_TOKEN=password= 等模式,但报告只保存文件名与 content_redacted: true。检测工具发现秘密,不代表它有权复制秘密。

Bytes 也直接进入业务逻辑。文件大小不是模糊的数字,配置里的 256b1kib4kib1mib 会被解析成 Bytes 后再比较,避免单位被藏在变量名和约定里。

测试失败场景,才能证明门禁有效

自测准备了两个确定性项目。healthy-project 包含必需文件、成功命令和 2xx 健康接口,八项检查全部通过。risky-project 故意缺少 LICENSE,放入假的 DEMO_TOKEN,执行失败命令并请求 404 接口。

第二个场景返回 1 不是测试失败,而是门禁正确工作。测试脚本随后读取报告,断言五项失败都被记录,敏感内容没有泄露。

FlowGuard 健康与风险场景的端到端自测

sh practical-projects/flowguard/self-test.sh

这个项目验证了什么

FlowGuard 让我确认,HHY 最有辨识度的方向不是替代某一条 shell 命令,而是把文件、进程、HTTP 和 Stream 放进同一套可读的错误与资源模型。

Shell 很适合把几个成功路径连起来;当任务开始要求并发上限、错误聚合、脱敏报告、原子写入和稳定退出码时,脚本已经在长成一个应用。HHY 要做的,就是让这个增长过程仍然保持直接。

参考

返回技术札记