ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Substrate 代码树校验流水线:深入解析 hack/verify 脚本体系与 verify-all.sh 聚合入口

Substrate 代码树校验流水线:深入解析 hack/verify 脚本体系与 verify-all.sh 聚合入口 Substrate 代码树校验流水线深入解析 hack/verify 脚本体系与 verify-all.sh 聚合入口【免费下载链接】substrateAgent Substrate: the core system项目地址: https://gitcode.com/GitHub_Trending/substrate7/substrateAgent Substrate 仓库在hack/verify/目录下维护了一套轻量、单一职责的代码树校验脚本用于在 CI 与本地开发中验证当前代码树的正确性如生成代码是否过期、格式是否规范、许可证与指标注册表是否合规。本文将完整继承官方 hack/verify/README.md 的说明并以仓库内全部 13 个校验脚本及聚合入口 hack/verify-all.sh 的源码为证据逐类讲解每个脚本的作用、关键实现与运行方式帮助你快速掌握该仓库校验即工程的开发实践。一、hack/verify/ 目录是什么README 的原始定义仓库官方文档 hack/verify/README.md 对目录的定位极为精炼全文如下This directory holds simple scripts which verify the current tree in some way (e.g. generated code). Most of the scripts in this directory should have a corresponding entry in../verify-all.sh.翻译过来即两点核心约定单一校验目标目录中的每个脚本都是简单脚本各自以某种方式验证当前代码树例如生成代码是否与手写代码一致、是否被篡改或过期。统一聚合入口目录中大多数脚本都应在../verify-all.sh即仓库根下的 hack/verify-all.sh中有对应入口保证一键全量校验可行。从仓库实际内容看该目录下共有 13 个脚本脚本校验对象boilerplate.sh源码文件版权头boilerplatecodegen.sh生成代码codegen是否过期go-modules.shgo.mod / go.sum 是否同步gofmt.shGo 代码格式golangci-lint.shGo 静态检查golangci-lintkube-api-linter.shKubernetes API 类型约定licenses.shGo 依赖许可证合规metrics.sh指标注册表OpenTelemetry Weaverpostgresql-migrations.shPostgreSQL 迁移文件规则proto-fmt.shprotobuf 格式python-licenses.shPython 依赖许可证合规shellcheck.shShell 脚本静态检查threats.sh威胁模型文档与 JSON 同步所有脚本统一以set -o errexit -o nounset -o pipefail开头详见各脚本第 17 行并通过ROOT$(git rev-parse --show-toplevel)定位仓库根目录后cd进入保证无论从哪个目录调用都能在正确的上下文中执行。二、统一入口 hack/verify-all.sh如何聚合 13 个校验hack/verify-all.sh 是 README 中提到的聚合入口全量校验通过它一键触发。其核心逻辑第 17-28 行如下set -o errexit -o nounset -o pipefail ROOT$(git rev-parse --show-toplevel) cd ${ROOT} export LC_ALLC # for sorting to be consistent across locales # shellcheck disable2044 # for-loop over find output is intentional for F in $(find ./hack/verify -name *.sh | sort); do echo Running ${F} ${F} $ done几个值得注意的工程细节自动发现 确定性顺序使用find ./hack/verify -name *.sh | sort动态发现目录下所有脚本并按名称排序执行新增校验脚本无需修改聚合入口export LC_ALLC确保不同 locale 下排序结果一致否则中文/英文环境下 sort 顺序可能不同影响 CI 可复现性。严格失败模式errexit使任一脚本非零退出即终止整条流水线保证所有校验必须全部通过的语义nounset和pipefail分别防止未定义变量与管道静默吞错。参数透传${F} $将命令行参数透传给每个子脚本例如./hack/verify-all.sh --something会把--something传给所有脚本供需要额外参数如postgresql-migrations.sh的released-ref的脚本使用。从源码结构看这种目录自发现 逐脚本执行的模式与 Kubernetes 上游 hack 脚本一脉相承仓库中多个脚本codegen、gofmt、licenses、proto-fmt、go-modules、shellcheck也直接复用了 hack/third_party/kubernetes/ 下的第三方封装脚本。三、生成代码与格式类校验codegen / gofmt / proto-fmt / go-modulesREADME 明确点名的典型校验场景就是generated code生成代码。这一类别在目录中占比最大且实现高度统一——codegen.sh、gofmt.sh、proto-fmt.sh、go-modules.sh、licenses.sh、shellcheck.sh六个脚本的主体都是同一行调用./hack/third_party/kubernetes/verify-generated.sh codegen $ ./hack/third_party/kubernetes/verify-generated.sh gofmt $ ./hack/third_party/kubernetes/verify-generated.sh proto-fmt $ ./hack/third_party/kubernetes/verify-generated.sh go-modules $ ./hack/third_party/kubernetes/verify-generated.sh licenses $ ./hack/third_party/kubernetes/verify-shellcheck.sh $对应文件codegen.sh、gofmt.sh、proto-fmt.sh、go-modules.sh、licenses.sh、shellcheck.sh。其设计思路是生成 → 对比 → 失败的通用校验范式先运行与hack/update/侧仓库维护有 hack/update/codegen.sh、hack/update/gofmt.sh、hack/update/go-modules.sh、hack/update/licenses.sh、hack/update/proto-fmt.sh 等重新生成脚本完全相同的生成逻辑再对比工作区是否产生差异若有差异即说明生成产物未同步脚本非零退出并提示重新生成。各校验的具体目标codegen验证代码生成器包括cmd/ate-setup、cmd/ateapi、pkg/api/v1alpha1等处的 CRD 类型、deepcopy、clientset、informers 等派生代码是否与源定义保持一致。仓库中 pkg/client/clientset、pkg/client/informers、pkg/client/listers 等目录即为生成产物。gofmt验证所有 Go 源码是否符合gofmt格式规范。proto-fmt验证internal/proto/与 pkg/proto 下的.proto定义如ateletpb、ateompb、glutton、grpcechopb、ateapipb、credproviderpb格式化是否合规。go-modules验证 go.mod 与 go.sum 是否与依赖树同步即go mod tidy后无差异。licensesGo 侧依赖许可证检查与python-licenses.sh相对。四、静态检查类golangci-lint 与 kube-api-linter4.1 golangci-lint.sh跨平台类型检查的 GOOSlinux 技巧golangci-lint.sh 是目录中最能体现工程细节的脚本之一其核心第 22-30 行# Resolve the tool path under the hosts native GOOS so the binary is # executable on the developers machine, then invoke it with GOOSlinux so # the linter analyzes the code the same way it would on the Linux CI # runners. Without the GOOSlinux override, platform-gated packages # (notably the netlink bindings used by ateom-gvisor) fail to typecheck on # macOS and golangci-lints typecheck fail-stop suppresses all other # findings in the affected files. BIN$(${ROOT}/hack/run-tool.sh --print-bin-path golangci-lint) exec env GOOSlinux ${BIN} run ./... | { grep -v ^0 issues.$ || true; }这里包含两个精妙设计工具版本托管通过 hack/run-tool.sh 的--print-bin-path解析 golangci-lint 二进制路径工具链版本由仓库统一管理hack/tools/下维护各工具的独立 go.mod如 golangci-lint 工具模块避免我机器上能过、CI 上过不了的版本漂移问题。GOOSlinux 交叉分析二进制按宿主原生 GOOS 解析以保证可执行但运行时用env GOOSlinux强制按 Linux 平台做类型检查。注释明确解释了原因cmd/ateom-gvisor依赖 netlink 绑定internal/ateomnet/net_linux_test.go 等平台门控文件若在 macOS 上按默认平台检查会因平台差异导致 typecheck 失败而 golangci-lint 的 typecheck fail-stop 会连带压制同文件的其他检查结果。强制 GOOSlinux 后本地与 Linux CI 的分析结果完全一致。输出净化grep -v ^0 issues.$ || true过滤掉0 issues这类无信息输出避免 CI 日志噪音。4.2 kube-api-linter.shKubernetes API 类型约定检查kube-api-linter.sh 针对仓库的 Kubernetes API 类型做上游约定API conventions合规检查# Lint the Kubernetes API types against the upstream API conventions. # Same GOOSlinux override as golangci-lint.sh: analyze the code the same # way the Linux CI runners do. BIN$(${ROOT}/hack/run-tool.sh --print-bin-path golangci-lint-kube-api-linter) exec env GOOSlinux ${BIN} run --config .golangci-kal.yaml ./pkg/api/... | { grep -v ^0 issues.$ || true; }它只针对 pkg/api/v1alpha1 下的 API 类型做检查并使用独立配置文件.golangci-kal.yaml仓库根目录同样应用 GOOSlinux 覆盖以保证与 CI 一致。五、许可证合规类Go 与 Python 双轨检查5.1 licenses.shGo 侧licenses.sh 委托verify-generated.sh licenses检查 Go 依赖树的许可证合规性。仓库根目录下维护了完整的 go.mod 与 go.sum并配套 hack/update/licenses.sh 与 hack/update/go-modules.sh 用于重新生成许可证清单。仓库还把全部第三方依赖的许可证文本固化在 _LICENSES/ 目录中覆盖 cel.dev、cloud.google.com、github.com、k8s.io、sigs.k8s.io 等数十个模块这也是licenses.sh校验所依赖的基线。5.2 python-licenses.sh按需 venv 黑名单策略python-licenses.sh 是 Python 侧的许可证校验设计上比 Go 侧更复杂因为它要处理每个项目独立、可能临时的 venv动态发现项目第 36-50 行用git ls-files -cmo --exclude-standard同时列出已跟踪cached与未跟踪others但不被忽略的requirements.txt再排除vendor/*与_LICENSES/*取目录名去重后逐个检查。仓库中的benchmarking/locust/requirements.txt、benchmarking/nighthawk-ingress/requirements.txt、benchmarking/automation/requirements.txt等都会进入检查范围。按需构建 venv第 60-88 行复用 hack/util/venv.sh 的ensure_venv与venv_sync_requirements创建并同步dir/venv然后在子 shell 中激活并安装pip-licenses执行pip-licenses --fail-on${DISALLOWED}。黑名单而非白名单第 52-58 行DISALLOWEDAGPL;GPLv2;GPLv3;GPL-2.0;GPL-3.0;GNU General Public License;GNU Affero General Public License;Server Side Public License;SSPL;Commons Clause。脚本注释解释了原因pip-licenses 的许可证字符串在不同包间差异极大classifier、License 字段、PEP-639 表达式黑名单子串匹配更稳健该清单对齐 CNCF allowed third-party license policy。六、指标注册表校验metrics.sh 与 OpenTelemetry Weavermetrics.sh 负责校验指标注册表是整个目录中版本锁定做得最严格的脚本。其工作对象是 docs/metrics/registry 目录下的指标注册表文件配套规则文件为 docs/metrics/substrate.yaml。核心机制第 29-83 行WEAVER_VERSIONv0.25.1 WEAVER_IMAGEdocker.io/otel/weaver:v0.25.1sha256:9ad46ca9cd4fa5974b121f886aa3e9946a8ef8ea905001a96c018d21f9db87ca工具版本双重锁定脚本固定weaver工具版本v0.25.1。若本机 PATH 中存在weaver二进制则先校验其版本必须恰好等于v0.25.1weaver --version | awk {print $NF}提取版本号版本不一致时直接报错退出并提示本地版本与 CI 版本不一致会导致本地通过但 CI 失败第 47-57 行——这是对可复现校验的强制约束。镜像摘要锁定若本机没有 weaver则使用 Docker 镜像docker.io/otel/weaver:v0.25.1并以sha256 摘要精确定位镜像第 35 行防止上游 tag 被覆盖导致结果漂移注释明确digest 就是 CI 实际拉取的版本必须与 WEAVER_IMAGE 保持同步。只读挂载 用户隔离第 71-77 行docker run --rm --user $(id -u):$(id -g) --volume ${ROOT}:/workspace:ro以只读方式挂载仓库、以当前用户身份运行避免污染工作区与产生 root 文件。--future 严格模式第 80-83 行weaver registry check --registry ${REGISTRY_DIR} --future。注释说明--future会把 Weaver 计划默认执行的检查如重复 metric_name从警告升级为错误否则重复指标名只会打印警告并返回 0导致漏检。失败提示精准定位失败时提示修改docs/metrics/registry/metrics.yaml后重跑并说明docs/metrics/substrate.yaml这类Weaver 无法约束的附加规则文件必须放在 registry 目录旁边而非目录内——因为 Weaver 拒绝包含除groups或imports之外顶层键的注册表文件第 84-93 行。七、数据库迁移校验postgresql-migrations.sh 的硬规则postgresql-migrations.sh 针对 cmd/ateapi/internal/store/atepg/migrations 下的 PostgreSQL 迁移文件实施一套非常严格的规则可视为仓库数据库演进策略参见 docs/dev/postgresql-schema-evolution.md的执行层。该脚本还支持可选参数released-ref用法为$0 [released-ref]。文件命名与连续性第 38-48 行迁移文件必须匹配^([0-9]{6})_[a-z0-9_]\.sql$即NNNNNN_name.sql如000001_init.sql且版本号必须从 1 开始严格连续递增expected变量逐文件累加比对跳过任何版本或断号都会失败。迁移内容约束第 50-73 行每条规则都有明确理由规则原因必须包含-- goose Up注解声明正向迁移禁止-- goose Down注解该仓库策略不支持回滚与已发布迁移不可修改配合禁止-- goose no transaction迁移必须在 PostgreSQL 事务内原子执行禁止IF NOT EXISTS守卫依赖版本连续性保证幂等而非 SQL 层守卫禁止-- goose ENVSUB迁移文件不接受环境变量注入禁止显式BEGIN/START TRANSACTION/COMMIT/ROLLBACK;事务必须完全由 Goose 控制已发布迁移不可变更第 77-93 行脚本接受released-ref参数若未提供则遍历git tag --merged HEAD --sort-version:refname找到第一个符合vX.Y.Z且迁移目录下含.sql文件的发布 tag 作为 released-ref。随后执行git diff --quiet --diff-filterMD对比该 tag 与 HEAD 在迁移目录下的修改M与删除D任何变更都会导致失败并列出具体文件——只允许新增迁移文件。八、头文件与威胁模型校验boilerplate.sh 与 threats.sh8.1 boilerplate.sh版权头一致性boilerplate.sh 内容最简仅调用hack/util/verify-boilerplate.py。仓库维护的版权头模板位于 hack/boilerplate/go.txtGo 源码用与 hack/boilerplate/sh.txtShell 脚本用各源码文件顶部统一的 Apache License 2.0 头即由该脚本保证例如仓库中每个.go文件开头的# Copyright 2026 Google LLC注释块。8.2 threats.sh威胁模型文档与数据同步threats.sh 验证威胁模型文档与其机器可读导出是否一致TMP_DIR$(mktemp -d) trap rm -rf ${TMP_DIR} EXIT hack/export-threats.py --md docs/threat-model.md --out ${TMP_DIR}/threats.json /dev/null if ! diff -u docs/threats.json ${TMP_DIR}/threats.json; then echo FAIL: docs/threats.json is out of date. 2 echo Please run hack/export-threats.py to regenerate it. 2 exit 1 fi它运行 hack/export-threats.py 从 docs/threat-model.md 重新生成threats.json到临时目录再与仓库内的 docs/threats.json 做diff不一致则失败并提示重新运行导出脚本。这保证了安全文档与其结构化数据供自动化消费始终同步配套资产还包括 docs/assets/threat-model-diagram.svg 与 hack/verify/threats.sh 对应的 hack/update 侧工具。九、使用方式与工程实践总结一键全量校验在仓库根目录直接运行./hack/verify-all.sh单独运行某个校验直接执行对应脚本例如./hack/verify/gofmt.sh ./hack/verify/metrics.sh ./hack/verify/postgresql-migrations.sh # 无 released-ref 时自动探测发布 tag ./hack/verify/postgresql-migrations.sh v1.2.3 # 显式指定发布基线修复流程校验失败时多数脚本会提示修复方式——生成类/格式类脚本提示运行hack/update/下对应的重新生成脚本hack/update/codegen.sh、hack/update/gofmt.sh、hack/update/go-modules.sh、hack/update/licenses.sh、hack/update/proto-fmt.sh指标与威胁模型脚本则提示分别修改注册表/文档后重跑。从整体设计看这套校验体系体现了几个可复用的工程模式单一职责 自动聚合每个脚本只验证一件事verify-all.sh通过 findsort 自动发现全部脚本新增校验零成本接入生成对比范式几乎所有产物类校验codegen、go.mod、threats.json都采用重新生成 → diff → 失败提示的幂等校验保证提交的产物永远与源定义同步CI/本地一致性通过GOOSlinux强制跨平台分析、weaver 版本与镜像摘要双重锁定、LC_ALLC固定排序等手段消除本地通过、CI 失败的环境差异策略代码化数据库迁移的命名、连续性、事务、不可变规则全部固化为可执行检查使 docs/dev/postgresql-schema-evolution.md 中的演进策略得以在每次提交时强制执行。如果你正在为 Substrate 仓库做贡献提交前运行./hack/verify-all.sh是确认代码树健康的最高效方式如果你在自己的 Go/Kubernetes 项目中需要一套轻量校验体系这个目录的脚本结构与实现细节也值得直接借鉴。【免费下载链接】substrateAgent Substrate: the core system项目地址: https://gitcode.com/GitHub_Trending/substrate7/substrate创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表