- 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>
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
# 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` 必须同步修改、同波提交。
|
||||
Reference in New Issue
Block a user