fix(verify): secret 门禁加上精确 (path, literal) 假凭据夹具登记簿——放行面从「零」变成 13 条逐字登记、逐条带 owner/review/reason,让脱敏测试重新可搬家,并把 #2296 刻意留下的 13 个 TestSanitizeSubAgentResult_* 搬出巨石文件(ADR-028,#2295) - #2307
Merged
Conversation
…登记、逐条带 owner/review/reason,让脱敏测试重新可搬家,并把 #2296 刻意留下的 13 个 TestSanitizeSubAgentResult_* 搬出巨石文件(ADR-028,#2295) ## 缺陷本体(实测复现,不是推断) check-secrets.sh 的六条字面量规则对 diff **新增行**无条件生效,而脱敏测试的被测对象 恰恰是「真形状的假凭据」⇒ 这类测试文件结构上不可重构。把 #2296 刻意留下的 13 个 TestSanitizeSubAgentResult_* 逐字搬到 subagent_result_sanitize_test.go、登记簿缺席时实测: secret guard: …/subagent_result_sanitize_test.go:55: possible API key detected …(55/56/57/58/62/63/179/204/252 共 **9 行**判红) 安全测试因为安全门禁本身而不可重构。#2296 因此把 13 个 Test 留在 546 行的巨石文件里; 本 PR 用登记簿把它们搬出来(546 → 188 行 + 新文件 364 行)。 ## 放行面怎么收窄的(ADR-028) `scripts/verify/secret-fixture-allowlist.json`:条目 = 精确 `(path, literal)` + 强制非空 `owner` / `review` / `reason`。 * **禁止**目录级 / glob / 包级 / regex 豁免——加载器对 `*?[]\`、绝对路径、`..`、 尾斜杠一律 fail-closed; * `literal` 必须**逐字**等于某条字面量规则的贪婪匹配结果,且**确实出现在**登记路径里 (同 literal 换路径 = 红;死条目 = 红); * `maxEntries` 是计数棘轮:13 条,增长必须在同一 PR 里显式抬高它,让评审看见放行面变宽; * **只有这六条字面量规则可登记**:私钥块(含空白,而登记器禁止空白 literal)、 secret-like 赋值规则、敏感路径规则都不可登记 ⇒ 放行面不因本机制变宽; * **登记簿自己没有路径豁免**:它也走同一套字面量规则,里面出现的凭据形状字面量必须是 已登记 literal 之一 —— 往 `reason` 里塞一个未登记的真凭据同样判红。 顺带修一处真实漏检:旧实现每规则每行只看**第一处**正则匹配,所以「已登记夹具 + 未登记真凭据」同一行时后者被前者掩盖。改成对一行里的每一处匹配都判一次。 ## 暗卷(11 发变异,逐发证明断言真的在管) | 变异 | 翻红的自测 | |---|---| | M1 完全不查登记簿 | registered (path, literal) fixture passes | | M2 去掉「登记簿自身按已登记 literal 放行」 | 同上(证明它靠规则、不靠路径豁免) | | M3 每行只看第一处匹配 | unregistered literal after a registered one on the same line fails | | M4 加载器不校验 literal 是否真在登记路径 | registered literal absent from its path fails | | M5 加载器不校验 maxEntries | entry count over maxEntries fails | | M6c 加载器对树不做任何校验 | non-existent path / literal absent / glob path 三条一起翻 | | M7 加载器不拒绝死条目 | dead entry (literal is not a credential shape) fails | | M8 加载器不拒绝空字段 | entry with an empty owner fails | | M9 只按 literal 匹配、忽略 path | registered literal moved to another path fails | | M10 只按 path 匹配、忽略 literal | 3 条一起翻 | | M11 只去掉 isfile 检查 | **不翻**(如实登记:`open()` 的 OSError die 是第二道 fail-closed,与它冗余) | 自测 23 → **36 全绿**。其中 7 条完整性用例**只 stage 登记簿自己**、夹具文件只留在磁盘上, 这样退出码非 0 只可能来自加载器校验——第一版把它们和夹具一起 stage,实测会因为 「夹具字面量未登记」这条无关路径而假绿(M4~M8 五发变异一发都不翻)。 ## 搬家守恒(13 个 Test,0 行 src 改动) * Test 名集合:21 = 8 + 13,`sorted(old) == sorted(new1+new2)`,missing/extra 均为空; * 非空行多重集合:A-only = **0 行**,B-only = 5 行 = 新文件 header 6 行减去从旧文件 移走的 `"unicode/utf8"`(两文件共有,抵消); * 546 → 188 + 364 = 552 行,+6 = header 8 − import 1 − gofmt 收掉的连续空行 1; * 整包 `go test -v`:`=== RUN` 379 = 379、`--- PASS` 378 = 378、`--- SKIP` 1 = 1、 FAIL 0 = 0,且两次 `=== RUN` 名称集合的 `diff` 为空; * 这 13 个 Test 里没有 `time.Sleep` ⇒ test-sleep 双基线无需改动。 ## leak_guard 取证(本地 hook 用 LEAK_GUARD_SKIP=1 提交,没有改夹具内容绕过) 登记簿必须逐字写明被放行的 literal,本地 hook 会拦其中 5 条(ghp_ ×2、AKIA ×2、JWT ×1)。 取证:13 条 literal **全部已在 origin/master 的跟踪文件里逐字存在**(`git grep -F` 逐条 实测),本 PR 没有给仓库新增任何一个凭据形状字符串,只是把其中 8 条从 process_executor_test.go 搬到同包的 subagent_result_sanitize_test.go;CI 门禁对同一份 staged 内容 `check-secrets.sh --staged` rc=0;且这 13 条无一为真凭据 (AKIAIOSFODNN7EXAMPLE 是 AWS 官方文档示例 key,那条 JWT 是 jwt.io 公开调试令牌 sub=1234567890,其余是 abc123def456 / 1234567890abcdefghijklmnopqrstuvwxyz 合成阶梯)。 Co-authored-by: Cursor <cursor@vectorcontrol.tech>
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Team Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
缺陷本体(实测复现,不是推断)
check-secrets.sh 的六条字面量规则对 diff 新增行无条件生效,而脱敏测试的被测对象
恰恰是「真形状的假凭据」⇒ 这类测试文件结构上不可重构。把 #2296 刻意留下的 13 个
TestSanitizeSubAgentResult_* 逐字搬到 subagent_result_sanitize_test.go、登记簿缺席时实测:
安全测试因为安全门禁本身而不可重构。#2296 因此把 13 个 Test 留在 546 行的巨石文件里;
本 PR 用登记簿把它们搬出来(546 → 188 行 + 新文件 364 行)。
放行面怎么收窄的(ADR-028)
scripts/verify/secret-fixture-allowlist.json:条目 = 精确(path, literal)+强制非空
owner/review/reason。*?[]\、绝对路径、..、尾斜杠一律 fail-closed;
literal必须逐字等于某条字面量规则的贪婪匹配结果,且确实出现在登记路径里(同 literal 换路径 = 红;死条目 = 红);
maxEntries是计数棘轮:13 条,增长必须在同一 PR 里显式抬高它,让评审看见放行面变宽;secret-like 赋值规则、敏感路径规则都不可登记 ⇒ 放行面不因本机制变宽;
已登记 literal 之一 —— 往
reason里塞一个未登记的真凭据同样判红。顺带修一处真实漏检:旧实现每规则每行只看第一处正则匹配,所以「已登记夹具 +
未登记真凭据」同一行时后者被前者掩盖。改成对一行里的每一处匹配都判一次。
暗卷(11 发变异,逐发证明断言真的在管)
open()的 OSError die 是第二道 fail-closed,与它冗余)自测 23 → 36 全绿。其中 7 条完整性用例只 stage 登记簿自己、夹具文件只留在磁盘上,
这样退出码非 0 只可能来自加载器校验——第一版把它们和夹具一起 stage,实测会因为
「夹具字面量未登记」这条无关路径而假绿(M4~M8 五发变异一发都不翻)。
搬家守恒(13 个 Test,0 行 src 改动)
sorted(old) == sorted(new1+new2),missing/extra 均为空;移走的
"unicode/utf8"(两文件共有,抵消);go test -v:=== RUN379 = 379、--- PASS378 = 378、--- SKIP1 = 1、FAIL 0 = 0,且两次
=== RUN名称集合的diff为空;time.Sleep⇒ test-sleep 双基线无需改动。leak_guard 取证(本地 hook 用 LEAK_GUARD_SKIP=1 提交,没有改夹具内容绕过)
登记簿必须逐字写明被放行的 literal,本地 hook 会拦其中 5 条(ghp_ ×2、AKIA ×2、JWT ×1)。
取证:13 条 literal 全部已在 origin/master 的跟踪文件里逐字存在(
git grep -F逐条实测),本 PR 没有给仓库新增任何一个凭据形状字符串,只是把其中 8 条从
process_executor_test.go 搬到同包的 subagent_result_sanitize_test.go;CI 门禁对同一份
staged 内容
check-secrets.sh --stagedrc=0;且这 13 条无一为真凭据(AKIAIOSFODNN7EXAMPLE 是 AWS 官方文档示例 key,那条 JWT 是 jwt.io 公开调试令牌
sub=1234567890,其余是 abc123def456 / 1234567890abcdefghijklmnopqrstuvwxyz 合成阶梯)。
Co-authored-by: Cursor cursor@vectorcontrol.tech