Files
lixi f17e6f1215
CI / docs-build (push) Successful in 34s
docs: M3 第一波收口——报告 09~14 与契约草案入档挂导航
- 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>
2026-09-08 17:13:49 +08:00

81 lines
6.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 关键校准(避免误伤的两处设计)
1. **PRIVATE-KEY 采用「PEM 头独占一行」判据**patbond-api 有两处合法的 PEM 头字面量——`TestJwtKeys.java`(测试密钥**运行时生成**,无入库密钥材料)与 `RsaPrivateKeyLoader.java`(解析代码的 `.replace(...)`)。两处 PEM 头都嵌在代码字符串中而非独占一行,该判据下自然通过,无需路径白名单;真实 .pem 文件或粘进 yaml 的密钥块(头行独立)仍必中。
2. **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` 必须同步修改、同波提交。