- 09 V5+community 骨架(191→206)、10 埋点队列三项(272→286)、 11 契约草案(13 路径/19 操作)、12 防泄漏三仓落地、 13 media MinIO 闭环 + auth 契约测试(→226,抓修 1 漂移)、14 收口总表 - backend-modules.md 更新五模块/六容器口径 - 媒体凭据形态已定型(契约冻结输入),剩余待定型点在 T3-04/05 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
6.7 KiB
12 M3 第一波:凭证防泄漏检查落地(ADR-021)
- 执行人:Git Workflow Master
- 日期:2026-09-08
- 依据:ADR-021(CI 兜底 grep 第一波必做、先于 MinIO 凭证进开发机)、iteration-3/08 §4 两层纯 shell 方案
- 交付边界:本报告只记录,不入 mkdocs 导航;T3-03 自本波 CI 全绿起解除对象存储凭证引入限制。
1. 落地形态
两层检查、同一规则表,单一来源为各仓入库的 scripts/check-secrets.sh(纯 shell + git + grep,零外部依赖、零外部 action,符合三仓 CI「手动克隆本实例」模式约束)。三仓副本内容逐字节同构(cp -p 分发),调整规则时三仓同步提交。
| 层 | 载体 | 触发 | 扫描范围 |
|---|---|---|---|
| 第一层(推荐) | scripts/hooks/pre-commit → 同一脚本 --staged |
本地 git commit(git config core.hooksPath scripts/hooks 启用,每人每仓一次) |
暂存区内容 + 暂存文件名 |
| 第二层(强制兜底) | 三仓 ci.yml checkout 后首个 step,同一脚本 --all |
每次 push / PR | 全部已跟踪文件(本次 push 变更文件的超集;--force-with-lease、--no-verify 均无法绕过) |
CI 采用 --all 而非「仅 diff 变更文件」的原因:三仓 CI 均为 depth-1 浅克隆,无可靠的 push 前基点可 diff;全量扫描是变更文件的严格超集且实测最慢仓仅 6.7 秒,顺带覆盖历史存量。ci.yml 只加 step,既有逻辑零改动。
2. 规则集清单(9 条)
内容规则 8 条(规则表内 ID):
| ID | 检测 | 形态 |
|---|---|---|
| AK-AWS | AWS/MinIO S3 兼容 AK | AKIA + 16 位大写字母数字 |
| AK-QCLOUD | 腾讯云 SecretId | AKID + 16 位以上字母数字 |
| AK-ALIYUN | 阿里云 AK | LTAI + 12 位以上字母数字 |
| MINIO-DEFAULT | MinIO 默认凭证 | minio·admin 及连写变体(忽略大小写) |
| PRIVATE-KEY | 私钥块 | 独占一行的 -----BEGIN …PRIVATE KEY----- PEM 头 |
| KEY-ASSIGN | access/secret key 实值赋值 | accessKey/secret_key/… 后接 :/= 与 8 位以上实值 |
| JWT-SECRET | JWT/签名密钥材料 | jwt-secret/signing-key/token-secret/hmac-key 赋值实值 |
| DB-PASSWORD | 数据库口令非注入形态 | 仅限配置类文件(yml/yaml/properties/toml/conf/ini 及其 .sample/.example),password/passwd/pwd 赋 6 位以上非 ${} 实值 |
文件名黑名单 1 条(NAME-DENY):.env/.env.*、credentials*、密钥导出 CSV(rootkey.csv、*accessKeys*.csv 形态)本体禁入版本库;.sample/.example 后缀豁免。
允许清单(行级放行):${…}/{{…}} 注入形态、changeme/change-me、your-xxx、<占位>、placeholder/example/sample/dummy/fake/redacted、***。二进制文件经 grep -I 自然跳过;脚本与 hook 自身(含规则文本)路径豁免。
2.1 关键校准(避免误伤的两处设计)
- PRIVATE-KEY 采用「PEM 头独占一行」判据:patbond-api 有两处合法的 PEM 头字面量——
TestJwtKeys.java(测试密钥运行时生成,无入库密钥材料)与RsaPrivateKeyLoader.java(解析代码的.replace(...))。两处 PEM 头都嵌在代码字符串中而非独占一行,该判据下自然通过,无需路径白名单;真实 .pem 文件或粘进 yaml 的密钥块(头行独立)仍必中。 - DB-PASSWORD 限定配置类文件:api 测试代码与 Readme 的 curl 示例大量使用
"password":"secret123"假值,Java/Markdown 不在该规则文件范围内;配置类文件中现有口令全部为${PATBOND_DB_PASSWORD:…}注入形态(docker-compose.yml、application.yml.sample 逐行核实),实值直写才会命中。
3. 误报实测:三仓现有全部已跟踪文件零误报
| 仓库 | 已跟踪文件数 | --all 扫描结果 |
耗时 |
|---|---|---|---|
| patbond-api | 194(+本次 3) | 零命中,exit 0 | 5.6s |
| patbond-flutter | 234(+本次 3) | 零命中,exit 0 | 6.7s |
| patbond-doc | 74(+本次 4) | 零命中,exit 0 | 2.1s |
另以 --staged 模式对本次新增文件(脚本、hook、ci.yml、git-workflow.md)复扫,同样零命中——即规则集对自身与规范文档不误伤。
4. 拦截自测(临时仓构造假凭证,验证后已删除,未入库)
在 scratchpad 一次性 git 仓中构造全假样本(编造值,无任何真实凭证),结果:
- 应拦 9 类全部命中:AKIA 假 AK、AKID、LTAI、minio·admin(连写形态)、独立 PEM 头、accessKey/secretKey 实值赋值、yml 中 password 实值、
.env文件本体(NAME-DENY)——--staged、--all、文件参数三种模式一致,exit 1。 - hook 真实阻断:
git config core.hooksPath scripts/hooks后git commit被 pre-commit 拒绝(exit 1),输出命中清单与处置指引(真凭证先轮换后清历史)。 - 应放行全部通过:
${PATBOND_DB_PASSWORD:patbond}注入、changeme/your-access-key占位、.env.sample——零误拦,exit 0。 - 顺带发现的既有防线:本机全局 gitignore 已含
.env,git add -A根本加不进暂存区,NAME-DENY 是其后的第二道。
5. 三仓提交与 CI 状态
| 仓库 | 分支 | 提交 | 内容 | CI |
|---|---|---|---|---|
| patbond-api | dev | 8330885 |
脚本 + hook + ci.yml 加 Secret scan step | 见下 |
| patbond-flutter | dev | 66f983d |
同上(同构副本) | 见下 |
| patbond-doc | main | 8e1fe2f |
脚本 + hook + ci.yml step + git-workflow.md「凭证防泄漏检查」节 | 见下 |
CI 状态(Gitea commit status API 逐仓核实,2026-09-08):三仓全部 success——api CI / backend-test (push)(16:35:08 完成)、flutter CI / flutter-gates (push)(16:37:29)、doc CI / docs-build (push)(16:38:14)。新增 Secret scan step 未破坏任何既有流水线。
patbond-doc 本地 mkdocs build --strict 通过后才提交;他人未提交内容(backend-modules.md 改动、09/10/11 号报告)未混入本次提交。启用说明见 patbond-doc docs/development/git-workflow.md「凭证防泄漏检查(ADR-021)」节,命令示例已按参数化路径规范书写(cd <你的工作区>/<仓名>)。
6. 遗留与提醒
- T3-03 解锁条件已满足后引入 MinIO 凭证时:AK/SK 只进被 gitignore 的
.env(compose${}注入),.sample用占位值——直写实值会被本规则集拦下。 - 两位开发者各自需在三仓执行一次
git config core.hooksPath scripts/hooks(CI 兜底不依赖此步,但本地拦截更早更省事)。 - 规则表若增补(如 M4 引入新云厂商),三仓
scripts/check-secrets.sh必须同步修改、同波提交。