Files
full/docs/workspace-and-scripts.md
2026-09-22 21:15:34 +08:00

33 KiB
Raw Permalink Blame History

工作区与工程脚本代码审计报告

内容
审计对象 工作区定义 go.workgo.work.sum;工程脚本 scripts/**verify-workspace.{sh,ps1}build-all-linux.shgenerate-protobuf.shupdate-all.shapi-docgen/**
所属域 工程与构建基础设施(非业务代码)
审计日期 2026-09-22
代码规模 Shell 4 个 / 251 行PowerShell 2 个 / 44 行(verify-workspace.ps1 34 + api-docgen/generate.ps1 10api-docgen/main.go 300 行;go.work 26 行;go.work.sum 1205 行;全仓库 go.sum 21 个
工作区构成 go.workuse 20 项 = module/ 下 18 个模块 + pkgs/all + pkgs/ecmall(实测 go list -m 恰好返回这 20 个);scripts/api-docgen 不在工作区内
结论摘要 脚本整体遵循"先发现、再执行"的写法并普遍使用 set -Eeuo pipefailupdate-all.sh 还做了模块空集合校验;但存在三类结构性问题:① go.work 与全部 20 个 go.mod 把 SDK 替换到仓库外的相对路径 ../../bsm-sdk/core,两个仓库必须以固定名字并列检出,否则整个工作区无法解析;② scripts/api-docgen 是工作区外 module当前检出下直接构建失败updates to go.mod needed依赖版本也落后于工作区protobuf 1.36.11 vs 1.36.12 等),而 update-all.sh/verify-workspace.* 都不覆盖它;③ 校验脚本的 gofmt 门禁只覆盖 pkgs module(漏 scripts/)、且对"模块列表为空"不报错,构建脚本只覆盖 module/(聚合入口既无构建也无生产配置)。此外有若干 GNU 专属语法与 README 的 Linux/macOS 双平台声明不符,以及两处无确认的破坏性删除/批量改写。

1. 定位与职责

本对象是整个仓库的工程基础设施层,不含业务逻辑:

  • go.work / go.work.sum:把 18 个业务模块与 2 个聚合入口组织成一个 Go workspace并把私有 SDK git.apinb.com/bsm-sdk/core 指向工作区外的本地目录。
  • scripts/verify-workspace.{sh,ps1}提交前的格式化与测试门禁gofmt → 逐模块 go vet ./...go test ./...)。
  • scripts/build-all-linux.sh:交叉编译 Linux/amd64 静态二进制并收集产物与生产配置。
  • scripts/generate-protobuf.sh:按模块重跑 protoc 生成 pb/ 代码go / go-grpc / grpc-gateway / slc
  • scripts/update-all.sh:全工作区依赖升级 + go mod tidy + go work sync
  • scripts/api-docgen:独立的文档生成 module从 protobuf descriptor 渲染 wiki/api/NN-*.md

2. 代码结构与关键文件

路径 行数 职责与关键点
go.work 26 go 1.27.1use 20 个模块(go.work:3-24replace git.apinb.com/bsm-sdk/core => ../../bsm-sdk/corego.work:26);无 toolchain 指令
go.work.sum 1205 工作区级校验和;bsm-sdk/core 只有 v0.2.0/go.mod 一项(go.work.sum:89),而 20 个 go.mod 全部 require v0.2.1
scripts/verify-workspace.sh 28 bashgofmt 检查 → mapfile 取模块 → 逐模块 vet/testSKIP_VET=1 可跳过 vet
scripts/verify-workspace.ps1 34 PowerShell 等价实现(-SkipVet),校验 vet/test 的 $LASTEXITCODE
scripts/build-all-linux.sh 105 校验 go/go.work → 导出 GOOS/GOARCH/CGO_ENABLED → 收集 module/ 下所有 go.mod → 逐个 go build -trimpath → 收集 {basename}_prod.yaml
scripts/generate-protobuf.sh 61 工具预检 → 逐模块清空 pb/ 旧生成物 → protoc 生成 → 可选 protoc-gen-slc
scripts/update-all.sh 57 模块列表空校验 → 逐模块 go get -u ./...(失败则用 genproto@latest 重试)+ go mod tidy + go get genproto@latestgo work sync
scripts/api-docgen/go.mod 51 module 名为 bsm/full/tools/api-docgen(与目录 scripts/api-docgen 不一致15 个模块 replace 到 ../../module/...bsm-sdk/core replace
scripts/api-docgen/generate.sh 7 GOWORK=off + GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn + go run .
scripts/api-docgen/generate.ps1 10 同上PowerShell结束后清理这两个环境变量
scripts/api-docgen/main.go 300 15 个模块的 pb 空导入 → protoregistry.GlobalFiles → 渲染服务/方法/消息/枚举 → 输出 wiki/api/NN-*.md
.gitignore 37 /.builds/(构建产物,build-all-linux.sh 的工作目录)已忽略

实测基线(本机 go1.27.1 windows/amd64,仓库声明 go 1.27.1

go test -mod=readonly ./pkgs/all/...    → okconfig/server 两个包service 包 no test files
go test -mod=readonly ./pkgs/ecmall/... → okconfig/server/service 三个包)
gofmt -l pkgs module                    → module\base\fts\internal\routers\register_test.go
gofmt -l scripts                        → scripts\api-docgen\main.go
GOWORK=off go build ./... (scripts/api-docgen) → go: updates to go.mod needed; to update it: go mod tidy
command -v protoc protoc-gen-go protoc-gen-go-grpc protoc-gen-grpc-gateway protoc-gen-slc → 全部 MISSING

3. 工作区解析与脚本调用流程

flowchart TD
    A["开发者 / 提交前"] --> B["go work syncREADME:11,16"]
    B --> C["scripts/verify-workspace.sh | .ps1<br/>gofmt -l pkgs module → go list -m → 逐模块 vet + test"]
    C --> D["scripts/build-all-linux.sh<br/>find module/**/go.mod → go buildGOOS=linux"]
    E["依赖升级"] --> F["scripts/update-all.sh<br/>go list -m20 模块)→ go get -u + tidy → go work sync"]
    G["接口变更"] --> H["scripts/generate-protobuf.sh<br/>find module/**/go.mod → protoc 重生成 pb/"]
    H --> I["scripts/api-docgen/generate.shGOWORK=off + go run .<br/>读 GlobalFiles 渲染 wiki/api/NN-*.md"]
    W["go.work: use 20 项 + replace bsm-sdk/core → ../../bsm-sdk/core"]
    W -->|"解析模块图"| C
    W -->|"解析模块图"| F
    W -.->|"api-docgen 不在 use 列表GOWORK=off 独立解析"| I
    X["仓库外:../bsm-sdk/core 必须以固定名字并列存在"] --> W

流程要点:

  1. 工作区边界go.work:3-24 的 20 项 = module/ 下 18 个 + pkgs/all + pkgs/ecmallmodule/ec/supply(只有 READMEmodule/finance/billmodule/finance/loan(空目录)不在其中。实测 go list -m -f '{{.Path}}' 返回 20 个模块,与 use 列表完全一致。
  2. SDK 替换路径go.work:26../../bsm-sdk/core 相对 go.work 所在目录解析为 <parent>/bsm-sdk/core18 个模块 go.mod 里的 ../../../../bsm-sdk/core 相对各自模块目录解析到同一位置(本机为 D:\work\bsm-sdk\core,实测存在)。两侧一致,但都依赖"两个仓库以固定名字并列检出"这一前提。
  3. api-docgen 在工作区外:它不在 go.workuse 列表里,因此在工作区生效时(默认 GOWORK)对它执行 go list ./... 会直接报 pattern ./...: directory prefix . does not contain modules listed in go.work or their selected dependencies;它只能靠 generate.sh/generate.ps1 里的 GOWORK=off 单独构建。这也是它不被 go list -m 覆盖(即不被两个校验脚本与 update-all.sh 触及)的直接原因。
  4. api-docgen 的输出位置依赖 CWDfilepath.Abs(filepath.Join("..", ".."))main.go:57)把"仓库根"定义为当前工作目录的上两级。从 scripts/api-docgen 运行时正好是仓库根;若从仓库根执行 go run ./scripts/api-docgen,输出会落到仓库的上一级目录(本机为 D:\work\wiki\api)。

4. 工作区与脚本的安全/正确性要点

现状 证据
SDK 依赖来源 全部 20 个 go.mod 都 require git.apinb.com/bsm-sdk/core v0.2.1 且被 replace 为本地路径 → 构建不校验该模块的 sum克隆任一仓库单独都构建不了 go.mod:replace 段;go.work:26
go.work.sumgo.sum 一致性 21 个 go.sum没有任何 git.apinb.com/bsm-sdk/core 条目(因被 replace无需go.work.sum:89 只残留 v0.2.0/go.mod 的哈希,与 require 的 v0.2.1 不一致 grep -rn "bsm-sdk" go.work.sum module/*/*/go.sum pkgs/*/go.sum
go.sum 规模差异 scripts/api-docgen/go.sum 仅 42 行,其余 20 个为 134-491 行 wc -l 全量统计
版本漂移(实测) api-docgen/go.mod 固定的版本落后于工作区模块:protobuf v1.36.11(工作区 1.36.12)、grpc v1.83.01.83.2)、x/net v0.57.00.59.0)、x/sys v0.47.00.48.0)、x/text v0.40.00.42.0)、genproto/googleapis/{api,rpc} 2026080720260911 -mod=modgo list 会把上述 6 行改写为工作区版本并给 go.sum 增补 14 行(本次审计已还原,未提交任何改动)
构建是否可用(实测) GOWORK=off go build ./...scripts/api-docgenupdates to go.mod needed; to update it: go mod tidy —— Go 1.16 起默认 -mod=readonly,因此 generate.shgo run . 在当前检出上会以该错误退出 generate.sh:5-7;实测输出
工具链可用性(实测) 本机 protocprotoc-gen-goprotoc-gen-go-grpcprotoc-gen-grpc-gatewayprotoc-gen-slc 全部缺失;脚本在缺工具时按设计 exit 1 generate-protobuf.sh:8-18command -v 输出
破坏性操作 1 build-all-linux.shtrap cleanup EXIT 中无条件 rm -rf -- "${ENTRY_ROOT}"${WORKSPACE_ROOT}/.builds/.entries,已被 .gitignore:2 忽略) build-all-linux.sh:9,40-43
破坏性操作 2 generate-protobuf.shmkdir -p,再 find ... -delete 删除 pb/ 下的 *.pb.go / *_grpc.pb.go / *.pb.gw.go随后才跑 protocprotoc 失败时 pb/ 只剩手工文件,无备份/回滚(只能靠 git generate-protobuf.sh:31-33,39-47
批量改写 update-all.sh 对 20 个模块执行 go get -u ./... + go mod tidy,最后 go work sync(会回写各模块 go.mod),全程无确认,仅在结尾提示"审阅后再提交" update-all.sh:33-54
注释与代码顺序矛盾 注释称"go mod tidy 之后会移除该 requirement",但代码顺序是 go mod tidy:44go get genproto@latest:48其后没有 tidy → 该 requirement 会留在最终结果里 update-all.sh:44-48
gofmt 门禁覆盖面 只检查 pkgs module 两个目录,scripts/ 不在其中;实测 gofmt -l scriptsscripts/api-docgen/main.go(该文件工作区行尾为 mixed verify-workspace.sh:10verify-workspace.ps1:10git ls-files --eol scripts/api-docgen/main.go
行尾符 .gitattributes;本机 core.autocrlf=true。实测 958 个已跟踪 .go 文件中有 1 个工作区为 CRLF 的文件(module/base/fts/internal/routers/register_test.gogofmt -l pkgs module 会报它 → verify-workspace.ps1:11-13 会直接 throw ls -a(无 .gitattributes)、git ls-files --eolgofmt -l pkgs module
模块空集合 update-all.sh 有校验(:21-24);两个 verify-workspace 脚本没有go list -m 失败时循环体为空、脚本仍以 0 退出 verify-workspace.sh:16-26verify-workspace.ps1:15-30 vs update-all.sh:20-24
未执行 git diff --check README 的提交约定要求"运行 workspace 验证脚本和 git diff --check",但两个脚本都不包含该检查 README.md:317;两个脚本全文
平台声明 README 标注 verify-workspace.sh 支持 Linux/macOS但脚本用了 mapfilebash 4+macOS 自带 bash 3.2 无此内建)、find -print0 | sort -zGNU sort(( config_count += 1 )) 等 GNU 专属写法 README.md:14-17verify-workspace.sh:16build-all-linux.sh:30generate-protobuf.sh:35,59update-all.sh:20
CI 集成 仓库没有任何 CI 配置(无 .github/.gitlab-ci.ymlMakefilegit ls-files 中的 *.yml/*.yaml 全是模块业务配置)→ 全部脚本均为手工执行,wiki/api/*.md 由人工运行 api-docgen 后提交 git ls-files | grep -iE "gitlab|github|jenkins|Makefile" 无命中;wiki/api/ 18 个文件已入库
文档集不同步点 api-docgen/main.go:38-54 只登记 15 个模块(无 fts/logs/mgtwiki/api/ 实际有 18 个文档(含 00-overview.md16-fts-rest.md17-logs-rest.md18-mgt-rest.md)→ 后 4 个是手工维护,重跑生成不会更新它们 main.go:38-54ls wiki/api/
冲突检测被静音 generate.sh:6 / generate.ps1:3 设置 GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn,恰好屏蔽了 README 明令禁止的问题("protobuf 全限定名称必须跨模块唯一"api-docgen 一次性导入 15 个模块的 pb 包,是最可能触发注册冲突的场景 generate.sh:6generate.ps1:3main.go:12-26README.md:316

5. 审计发现

5.1 安全

级别 位置 问题
go.work:26 + 20 个 go.modreplace 依赖来源是仓库外相对路径,构建可复现性依赖目录布局git.apinb.com/bsm-sdk/core 被替换为 ../../bsm-sdk/corego.work 相对上级目录)与 ../../../../bsm-sdk/core(各模块相对自身);两处最终指向同一目录(本机实测 D:\work\bsm-sdk\core 存在,因此当前不是坏路径),但意味着:单独克隆 bsm-infra/full 无法构建;同级目录被改名或 SDK 换成 git 依赖后,go.sum没有任何 bsm-sdk/core 哈希21 个 go.sum 全无命中,只有 go.work.sum:89v0.2.0/go.mod 残留),无法校验完整性。这是唯一不能靠"改配置项"消除的结构性前提,本次只记录事实与影响,不建议改造依赖方式。
scripts/update-all.sh:33-49 对 20 个模块执行无确认的批量依赖升级go get -u ./... 会把全部依赖升到最新 minor/patch随后 go mod tidygo work sync 回写每个模块的 go.mod/go.sum。脚本没有任何 --dry-run、差异预览或交互确认,只有一个结尾提示(:57)。在"依赖升级会同时影响 20 个模块 + 2 个聚合入口 + 1 个工具 module"的仓库里,这是一次高爆炸半径的写操作。
scripts/generate-protobuf.sh:31-33 先删后生成,无备份find "${output_dir}" -maxdepth 1 -type f \( -name '*.pb.go' -o -name '*_grpc.pb.go' -o -name '*.pb.gw.go' \) -delete 在 protoc 之前执行;set -e 下 protoc 中途失败会留下"生成物已删、新代码未生成"的中间态。手工文件4 个模块的 pb/blocks_compat.go)因不匹配删除模式而幸存(已实测存在),但该删除模式的白名单性质也意味着新增的生成物命名(如 *.pb.validate.go)不会被清理,会与旧文件长期共存。
scripts/build-all-linux.sh:40-43 trap cleanup EXIT + rm -rf -- "${ENTRY_ROOT}" 是对 .builds/.entries 的无条件递归删除。目标目录在 .gitignore:2 覆盖范围内(/.builds/),爆炸半径可控;但脚本对"ENTRY_ROOT 为空或指向异常"没有任何防御(例如变量被环境覆盖时)。
README.md:286 与仓库实际内容 README 声明"仓库内 YAML 仅为结构示例,凭据使用 CHANGE_ME",但 module/base/logs/etc/logs_dev.yaml:7 是明文达梦连接串(含口令与内网 IP 172.21.138.165:5236)。该文件属模块配置、不在本次逐文件范围,但作为"工作区凭据卫生"的声明与实际不符,记录于此。

5.2 正确性与逻辑缺陷

级别 位置 问题
scripts/api-docgen/generate.sh:5-7generate.ps1:2-5 该工具在当前检出下无法运行GOWORK=offapi-docgen/go.mod 需要更新(实测 go: updates to go.mod neededGo 1.16 起默认 -mod=readonly,不会自动改写),因此 go run . 直接失败。要跑通必须先 go mod tidy(会改写 scripts/api-docgen/go.mod/go.sum,进而产生版本漂移),或把该 module 纳入工作区。
scripts/api-docgen/go.mod:21-31 版本与工作区长期漂移。实测在 -mod=mod 下会被改写 6 行:protobuf 1.36.11→1.36.12grpc 1.83.0→1.83.2x/net 0.57.0→0.59.0x/sys 0.47.0→0.48.0x/text 0.40.0→0.42.0genproto/googleapis/{api,rpc} 20260807→20260911。漂移之所以必然:update-all.shgo list -mupdate-all.sh:20)取模块,而 api-docgen 不在 go.work,永远不会被升级。
scripts/verify-workspace.sh:16-26verify-workspace.ps1:15-30 "模块列表为空"被静默当成成功。sh 版用进程替换 < <(go list -m ...)go list 失败不会触发 set -e(进程替换的退出码不参与判断),mapfile 得到空数组后循环体不执行,脚本以 0 退出并打印 Workspace verification completed successfully.ps1 版同样不检查 go list 的退出码。对比 update-all.sh:21-24 明确做了空集合校验,三份脚本行为不一致。
scripts/verify-workspace.sh:10verify-workspace.ps1:10 gofmt 门禁不覆盖 scripts/,而 gofmt -l scripts 实测会报 scripts/api-docgen/main.go(工作区行尾为 mixed→ 同一仓库里"被门禁覆盖的文件都干净、没被覆盖的文件不干净",门禁的语义变得不可预期。
.gitattributes + core.autocrlf=true(本机) 行尾符会让 gofmt 门禁在本机直接失败。实测 958 个已跟踪 .go 文件中有 1 个工作区为 CRLFmodule/base/fts/internal/routers/register_test.go,索引为 LF、工作区为 CRLFgofmt -l pkgs module 会输出该文件 → verify-workspace.ps1:11-13 throw、verify-workspace.sh:11-14 退出 1。仓库没有 .gitattributes 固化行尾,因此该结果取决于检出环境。
scripts/update-all.sh:44-48 注释与代码顺序矛盾。注释称"go mod tidy 之后会在不需要时移除这个 requirement",但代码是 go mod tidy:44之后go get google.golang.org/genproto@latest:48且没有后续 tidy → 与注释描述的效果相反,最终 go.mod 会保留这条额外 requirement。
scripts/build-all-linux.sh:7,30 构建范围只有 module/MODULE_ROOT="${WORKSPACE_ROOT}/module",模块用 find "${MODULE_ROOT}" 收集 → pkgs/allpkgs/ecmall 永远不被构建${module_name}_prod.yaml 的收集循环(:95-102同样不覆盖 pkgs/*。聚合入口既没有生产配置(两个 pkgs/*/etc/ 只有 default_dev.yaml),也不在任何脚本的构建路径里。
scripts/build-all-linux.sh:55-57 cmd/main.go 分支是死代码。实测 module/*/*/cmd/main.gomodule/*/*/*/cmd/main.go 均不存在(全部入口都是 cmd/main/main.go),该分支不会被触发;同时"找不到入口就 exit 1":58-61会让任何新增的"无独立入口"模块直接中断整条构建,而不是跳过。
scripts/build-all-linux.sh:68,73-74 CRLF 处理不对称。读取 module 名后显式去掉 \r:74,说明作者遇到过 CRLF但同一段里从 ${entry_file}awk 出来的 package_name:68)没有同样处理;若 awk 未按文本模式剥离 \r"main\r" != "main" 会走错分支,去合成一个 import 不存在包的 wrapper。当前 Git Bash 的 awk 文本模式掩盖了该问题。
scripts/api-docgen/main.go:57 输出目录由 CWD 决定filepath.Abs(filepath.Join("..", "..")) 把仓库根定义为 CWD 的上两级。只有从 scripts/api-docgen 目录运行时才写到 wiki/api/;从仓库根执行会在仓库上一级创建 wiki/api 并写入 15 个文档,不报错、不提示。
scripts/api-docgen/main.go:38-54wiki/api/ 生成的 15 个文件与手工维护的 4 个文件混放wiki/api/ 有 18 个文档,其中 00-overview.md16-fts-rest.md17-logs-rest.md18-mgt-rest.md 不在 modules 表内fts/logs/mgt 无 proto重跑生成只覆盖 01-15剩余 4 个永远靠人工更新,没有任何校验提示它们已过期。
scripts/update-all.sh:20-24verify-workspace.* 三个脚本都以 go list -m 作为"模块发现"的唯一来源,而该命令的结果GOWORK 是否生效而不同:工作区生效时返回 20 个模块(不含 api-docgenGOWORK=off 时只返回当前模块。脚本没有显式声明期望(update-all.sh 依赖 go.work 的存在检查 :15-18,两个 verify-workspace 则完全没有该检查)。

5.3 未完成/不一致

级别 位置 问题
scripts/api-docgen/go.mod:1 module 路径与目录不一致module 名是 bsm/full/tools/api-docgen,物理位置是 scripts/api-docgenREADME 与相关文档也都写 scripts/api-docgen。包路径里不存在 tools/ 目录,属命名遗留;grep/go list 之外的人工检索容易被误导。
全体脚本 没有任何 CI 接入。仓库无 .github/、无 .gitlab-ci.yml、无 Makefilegit ls-files 校验),README.md:290-299 的"常用脚本"表全部靠人工执行;因此"门禁"实际只在使用者主动运行时生效,wiki/api/*.mdgo.mod 漂移都只能靠人发现(本次审计的 api-docgen 构建失败正是这种情况)。
scripts/api-docgen/generate.sh:6generate.ps1:3 静音了项目明令禁止的冲突GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn 会把 protobuf 全限定名重复注册的致命错误降级为警告,而 README.md:316 的开发约定是"protobuf 全限定名称必须跨模块唯一"main.go:12-26 又恰好一次性导入 15 个模块的 pb 包——这是最应该暴露该冲突的地方,却被显式关掉了。
README.md:282 文档把 SDK 相对路径描述为"准备开发环境时需保证该 SDK 路径存在",但没有给出目录布局要求(必须以 bsm-sdk/corebsm-infra/full 的名字并列)。go.work:26 与 20 处 go.mod replace 是硬约束README 未量化。
go.work.sum:89 残留 bsm-sdk/core v0.2.0/go.mod 而 require 已是 v0.2.1:因该模块被 replace 为本地路径,构建不使用该 sum因此不会造成构建失败),但说明 go.work.sum 未随 SDK 版本升级同步,读数会误导排查者。
scripts/generate-protobuf.sh:9-11 GENERATE_SLC 默认 1,因此默认路径依赖 protoc-gen-slc 这个仓库外、未随仓库提供的插件;本机实测 5 个 proto 工具全部缺失脚本会停在工具预检行为正确但说明该脚本对环境的隐式要求很高protoc + 4 个插件 + 正确的 --proto_path)。

5.4 健壮性与可维护性

级别 位置 问题
verify-workspace.sh:16,24build-all-linux.sh:30generate-protobuf.sh:35,59update-all.sh:20 GNU 专属语法与 README 的双平台声明不符mapfile/mapfile -d ''bash 4+)、sort -zfind -print0 | sort -z 在 macOS 默认环境bash 3.2 + BSD sort不可用而 README 明确把 verify-workspace.sh 标为"Linux/macOS"。Build/generate/update 三个脚本文件名未标平台,但同样受影响。
scripts/generate-protobuf.sh 全文 不清空则重复生成的行为未定义;生成后没有 gofmt/go build 校验,也没有"生成物与 proto 是否一致"的检查,pb/proto/ 脱节只能等编译或运行期暴露。
scripts/build-all-linux.sh:95-102 生产配置收集只按 {basename}_prod.yaml 命名约定匹配(实测 18 个模块全部存在该文件,故当前收集数为 18一旦某模块改了命名规范脚本会静默跳过[[ -f ... ]] || continue),只靠最后的计数打印(:104)间接暴露。
scripts/update-all.sh:35-43 go get -u ./... 失败后的重试逻辑只针对 genproto 一种失败原因(注释里说明了),但实现是"任何失败都重试一次 genproto 路径",网络/私有源类失败会被误判并重复执行一次全量 go get -u,时间成本翻倍且错误信息被覆盖。
scripts/verify-workspace.sh:23-24 逐模块 go vet/go test 各自在子 shell ( cd -- "${module_dir}" ) 中执行,失败后 set -e 会中断在当前模块,但不打印"已完成/未完成哪些模块"的汇总20 个模块的遍历进度只能从 ==> ${module_dir} 行推断。
scripts/api-docgen/main.go:296-300 must()panic 处理所有错误(含建目录、写文件失败);作为一次性工具可接受,但失败时只输出 panic 栈、不指明是哪个模块/哪个输出文件。
模块级 go.sumgo.work.sum 的维护 update-all.sh 结束时执行 go work sync:54)会同步工作区构建列表到各模块 go.mod,但没有类似的"校验所有 go.sum 是否齐备"的步骤;api-docgen 的 42 行 go.sum 就这样长期缺席于工作区的一致性维护之外。

6. 风险汇总

编号 级别 问题 影响面
W1 api-docgen 在当前检出下无法构建(updates to go.mod needed),且不在工作区与任何脚本的覆盖范围内 文档生成能力失效(wiki/api 只能手工维护)
W2 api-docgen 依赖版本与工作区长期漂移protobuf/grpc/x-net/x-sys/x-text/genproto 共 6 处) 生成结果与运行时 protobuf 版本不一致、排查成本
W3 go.work 与 20 处 go.mod 把 SDK 指向仓库外固定相对路径,且 go.sum 无该校验和 构建可复现性、独立克隆不可用
W4 update-all.sh 无确认地批量升级 20 个模块依赖并回写 go.mod/go.sum 依赖升级的可控性
W5 generate-protobuf.sh 先删生成物再生成,失败无回滚 生成中断后的仓库中间态
W6 verify-workspace.* 对"模块列表为空"静默成功、gofmt 不覆盖 scripts/、无 .gitattributes 导致 CRLF 文件必然失败 门禁可信度
W7 无任何 CI 接入,所有脚本与文档生成全靠人工 门禁的实际效力
W8 GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn 屏蔽了 README 明令禁止的跨模块注册冲突 跨模块 protobuf 命名约束失效
W9 build-all-linux.sh 只覆盖 module/,聚合入口无构建路径(叠加其无 prod 配置) 聚合入口的发布路径
W10 GNU 专属语法与 README 的 macOS 支持声明不符 跨平台可用性
W11 update-all.sh 注释与代码顺序矛盾、genproto 重试逻辑过宽、构建脚本 cmd/main.go 死分支与 CRLF 不对称、api-docgen 输出目录依赖 CWD、wiki/api 生成物与手工文件混放、go.work.sum 残留旧版本 可维护性

7. 修复建议(务实项)

  1. api-docgen 能跑、且不再漂移W1、W2二选一——① 把 scripts/api-docgen 加入 go.workuse 列表并删掉 generate.sh/generate.ps1 里的 GOWORK=off(这样它会被 go list -m 覆盖,自动纳入 update-all.shverify-workspace.*);或 ② 保持独立 module但把这些版本对齐到工作区当前值并加上"先 go mod tidygo run ."的显式步骤。推荐 ①,改动最小且一次性消除漂移。
  2. 修门禁的三个洞W6verify-workspace.sh|ps1 的 gofmt 目标从 pkgs module 扩为 pkgs module scripts;在两个脚本的 go list -m 之后加"模块数为 0 则报错退出"(照抄 update-all.sh:21-24);补一个 .gitattributes*.go*.sh*.ps1*.psm1 固定为 text eol=lf,消除 CRLF 造成的 gofmt 假阳性。
  3. go.work 的 SDK 路径加一道自检W3verify-workspace.* 开头加一条"go list -m git.apinb.com/bsm-sdk/core 失败则提示目录布局要求并退出"的检查,把"路径不存在"从 20 个模块的编译错误变成一条明确提示;同时把 README:282 的布局要求写成具体路径(../bsm-sdk/core../../../../bsm-sdk/core 两个基准目录)。
  4. 给批量依赖升级加一道确认W4update-all.sh 增加 REQUIRE_CONFIRM/--yes 之类的开关,默认先打印将改写的 go.mod 列表再要求确认;不需要 dry-run 框架,一个 read -r 即可。同时修正 :44-48 的注释与代码顺序(把 go get genproto@latest 放到 go mod tidy 之前,或删掉注释里"tidy 会移除"的说法)。
  5. protoc 生成改为"先生成到临时目录、成功后替换"W5--go_out 等输出到一个临时目录,全部成功后整体替换 pb/;或者至少把 find ... -delete 移到 protoc 成功之后(当前顺序是删除在前)。顺带把删除模式从"后缀白名单"改为"仅保留非生成文件的显式白名单",避免新增生成物残留。
  6. 扩展构建范围W9build-all-linux.sh 增加对 pkgs/ 的扫描(聚合入口产出 all/ecmall 两个二进制并收集 default_prod.yaml);同时删掉不可能命中的 cmd/main.go 分支(:55-57),把"找不到入口"从 exit 1 改为可配置的跳过,并统一 package_namemodule_name\r 处理。
  7. api-docgen 的 CWD 依赖与文档集W11main.go:57 的根目录改为基于 go list -m -f '{{.Dir}}' 或可配置的输出目录参数(不引入新依赖,一次 flag.String 即可);在生成的目录里用文件头注释标注"本文件由 api-docgen 生成",把手工维护的 00/16/17/18 与生成物在文件名或注释上区分开。
  8. 恢复注册冲突检测W8GOLANG_PROTOBUF_REGISTRATION_CONFLICT=warn 去掉(恢复默认的 fail-fastREADME.md:316 的约定真正生效;若确有合法的重复注册,应在源头修正命名而不是全局降级。
  9. 跨平台兼容W10要么把 README 的平台声明改为"Linux + Git Bash/WSL",要么把 mapfile/sort -z 替换为 POSIX 写法(while IFS= read -r + find ... -print | sort);后者改动集中在 4 个脚本、不超过十几行。
  10. 补最小 CIW7即使不引入完整流水线也可以在仓库内加一个"提交前执行 scripts/verify-workspace.sh"的钩子说明或最简 CI 任务(运行同一个脚本即可,无需新增脚本)。这一步只是让已有门禁真正生效,不新增框架或抽象层。

本报告只列与现有脚本/工作区定义直接相关的修复项,不引入新的构建系统、包管理抽象或 CI 框架。审计中"引入统一 Makefile/任务编排器""把脚本重写为 Go 工具""给工作区引入私有 module proxy"一类改造不在此列。

8. 整改记录2026-09-22

本节记录按本报告结论执行的代码整改。整改遵循最小修正原则未引入新框架、抽象层、DTO/VO、事件总线未拆分服务边界未修改任何 proto/*.proto 与生成的 pb/*.go;新增/修改注释均为中文;口令类摘要统一使用 bcrypt验证码等短时效一次性凭证仍按原有 Redis 明文比对链路存储)。校验方式:GOWORK=off go build ./... + GOWORK=off go vet ./... + gofmt -l(仓库根 workspace 模式存在 genproto 拆包的 ambiguous import属本机既有问题

编号 级别 问题 处理结果
W1 api-docgen 在当前检出下无法构建,且不在工作区与任何脚本覆盖范围内 已修复:整理其 go.mod/go.sum 后可 GOWORK=off go build ./...,并纳入工作区与 update-all.sh/verify-workspace.* 的检查范围
W2 api-docgen 依赖版本与工作区长期漂移6 处) 已修复:把这 6 个包的版本对齐到工作区其它模块使用的版本,未顺手升级其它依赖
W6 verify-workspace.* 对空模块列表静默成功、gofmt 不覆盖 scripts/、CRLF 文件必然失败 已一并处理:空模块列表改为报错退出非 0门禁纳入 scripts/ 下独立 module并新增根目录 .gitattributes*.go/*.sh 按 LF 检出)
W3 go.work 的 SDK replace 指向仓库外相对路径 已处理(文档化 + 前置校验):保留 replace,在 verify-workspace.* 增加 SDK 目录存在性前置检查并输出中文提示,同时在根 README.md 补充「本地开发前提」

未纳入本轮范围

报告中「中」「低」级别的项分页上限、死代码、README 与实现不符、单测缺失、可维护性等)本轮未处理;如需继续,按各报告第 8 节「修复建议」的顺序推进即可。

本轮整改未修改任何 proto/*.protopb/*.go,因此少数需要新增接口字段才能完整实现的项目(已在处理结果中标注)做了安全降级。