Skip to content

test(edge-server): 全仓最大测试文件 process_executor_test.go(3283行/67Test)按生产域归位——拆出 10 个镜像生产文件的新测试文件 + 3 个既有域文件各追加 1 个,巨石瘦身到 510 行;四路守恒 + 逐行守恒 2973→2970(少的 3 行是分节注释、0 行新增)、import 0 越界、0 src 改动;3 处 sleep 经 --update-baseline 重新键控(全局 47 不变);13 个脱敏 Test 因 #2295 刻意不搬 - #2296

Merged
DeliciousBuding merged 1 commit into
masterfrom
test/edge-lifecycle-test-split
Sep 3, 2026

Conversation

@DeliciousBuding

Copy link
Copy Markdown
Collaborator

一句话

edge-server/internal/lifecycle/process_executor_test.go3283 行 / 67 Test,全仓最大的测试文件)按生产域归位:拆出 10 个镜像生产文件的新测试文件 + 3 个既有域文件各追加 1 个 Test,共享夹具与 4 个 mock adapter 收进既有 testutil_test.go,巨石瘦身到 510 行(16 文件,+2932 / −2815,净 +117 行=拆文件的 package/import 头固有成本)。纯搬家,0 个 src 改动。

该包 30 个测试文件里 29 个早已按域命名(env_sanitizer_test.goevidence_gate_test.goprocess_executor_hub_callback_test.goresult_aggregator_test.go…),process_executor_test.go 是最后一个"一个文件装整包"的 leftovers。同批已合的 #2288(edge-api 3792→184)、#2294(hub agentteam 3176→0、repository 2221→0)做的是同一件事。

拆分映射(每个新文件镜像哪个生产文件)

新/改文件 Test 数 镜像的生产文件(判据=Test 实际调用的符号定义处)
process_executor_start_test.go 9 process_executor_start.go / _run.go / _publish.go(Start→RunStarted→output→terminal 发布链)
process_profile_test.go 8 process_profile.govalidatePlaceholders/expandPlaceholders/runPlaceholderValue/parseEnvTemplate
process_executor_pure_adapter_test.go 7 process_executor_pure_adapter.go(adapter 契约、fixture 流映射、NeedsStdin 闸门)
process_executor_cancel_test.go 6 process_executor_cancel.go(Cancel/grace/race/级联)
process_executor_finish_test.go 5 process_executor_finish.go:166 sendSubAgentResult
process_executor_build_test.go 2 process_executor_build.goRunCheckpoint 在 build 阶段发出)
fault_escalation_test.go 2 fault_escalation.go
process_executor_helper_test.go 2 假子进程 helper(TestHelperProcess 模式,5s real_protocol sleep 在此)
process_arg_log_test.go 2 process_arg_log.go:16 summarizeProcessArgsForLog
runtime_evidence_test.go 1 runtime_evidence.go
hub_output_text_test.go(既有,追加 1) +1 hub_output_text.go splitHubCallbackText
thread_transcript_test.go(既有,追加 1) +1 thread_transcript.go
testutil_test.go(既有,追加 22 个单元) 0 共享夹具:recordingLifecycleEmitterrecordingContextAdapterfixtureSDKStreamAdapterneedsStdinTestAdapternewTestProcessExecutorcollectEventsUntilRunDoneoutputChunksTextwithoutEnvKeyhasArg/hasEventType/findEventType/eventTypeListstringSliceContains、两个 Eventually 预算常量
process_executor_test.go(瘦身 3283→510) 8 + 13 process_executor.goNewProcessExecutor 构造/依赖校验/重复 Start/并发上限 8 个;另 13 个 TestSanitizeSubAgentResult_* 刻意留在此处,见下

为什么 13 个 TestSanitizeSubAgentResult_* 没搬(如实)

它们的夹具是故意的假凭据字面量sk-proj-abc123…AIzaSyDabc123…ghp_abc123…AKIA1234567890ABCDEFeyJhbGci…),而 scripts/verify/check-secrets.sh 的字面量规则对 range diff 的新增行无条件生效、且除 *.env.example 外没有 fixture allowlist ⇒ 逐字搬家实测判红 9 行。这些字面量自导入提交 372a2119(2026-08-14)就在仓里,range 门禁从未判过它们。

守恒证据(全部本机实跑,diff rc=0)

守恒项 master 本分支 diff
整包 func Test* 名集合 283(uniq 283) 283(uniq 283) rc=0
整包小写顶层 helper 集合 47 47 rc=0
go test -v=== RUN 排序集合(含子测试路径) 379 379 rc=0
--- PASS 名集合 282 282 rc=0
--- SKIP 1 1 同名:TestSanitizedEnvIncludesWindowsSpecificVars(Windows-only)
--- FAIL 0 0
逐行搬运守恒 2973 非空行(去 package/import 头) 2970 少的 3 行全是巨石内的分节注释// ── Result aggregation tests ───// ── SanitizeSubAgentResult tests ───// --- Process executor error path tests ---)——域已成文件,分节标记随之失去意义;分支侧 0 行新增(B-only = 0)
import 纪律 原文件 import 并集 22 个 11 个新/改文件的 import 全在该并集内 越界 = 0goimports 只裁剪、没有注入任何新依赖)
src 改动 0 个非 _test.go 文件 git diff --name-only origin/master 过滤后为空

time.Sleep 双基线重新键控(本 PR 唯一的非测试改动)

3 处 sleep 随域搬家:80ms(CancelGraceNotImmediateKill,negative_window)+ 10ms(StartCancelRace,simulated_slow)→ process_executor_cancel_test.go;5000ms(TestProcessExecutorHelper 的假子进程 sleep 模式,real_protocol)→ process_executor_helper_test.goverify-test-sleep-ratchet.py 对"有 sleep 但无预算条目"是 fail-closed,所以走它自己规定的被跟踪审批步骤

$ python3 scripts/verify/verify-test-sleep-ratchet.py --update-baseline
  CHG  edge-server/internal/lifecycle/process_executor_test.go : 3 -> 0
  NEW  edge-server/internal/lifecycle/process_executor_cancel_test.go : 2
  NEW  edge-server/internal/lifecycle/process_executor_helper_test.go : 1
  DEL  edge-server/internal/lifecycle/process_executor_test.go(源码已无 sleep,条目移除)

随后人工补全 --update-baseline 留空的审批字段(owner/review/reason)与 kind(工具对新条目一律写 unclassified):

  • 全局 sleep 总数不变:47 → 47;文件数 21 → 22(一个键变成两个)。
  • 逐值逐 kind 保留:80/negative_window10/simulated_slow5000/real_protocoltotal_ms 5090 → 90 + 5000 = 5090。
  • reason 里写明原始审批出处(2026-08-29,test(edge): process_executor 轮询睡眠改 Eventually(sleep 治理第二批) #2038)与本次 re-key 的原因(round-72 按域拆分,纯搬家、零新增 sleep)。
  • 复跑 verify-test-sleep-ratchet.py → rc=0 PASS test-sleep ratchet + value budget hold (47 sleeps across 22 files, count baseline 22 files)

门禁(本机 huawei-dev 实跑)

命令 结果
go build ./...(edge-server) rc=0
go vet ./internal/lifecycle/ rc=0
gofmt -l internal/lifecycle 空输出
go test ./internal/lifecycle/ -v -count=1 rc=0(379 RUN / 282 PASS / 1 SKIP / 0 FAIL,7.8s)
golangci-lint run ./internal/lifecycle/...(v2.12.2,仓库配置) 1 issue=process_executor_build.go 的 gocyclo 22,与 edge-lint-baseline.json 里那条逐字相同(既有、生产文件、非本 PR 引入);新拆的测试文件 0 finding
python3 scripts/verify/verify-edge-lint-ratchet.py rc=0(9 findings, all baseline-registered
python3 scripts/verify/verify-test-sleep-ratchet.py rc=0(47 sleeps / 22 files)
bash /tmp/run-validate-H.sh <worktree>(61 条 CI validate 命令) PASS=61 FAIL=0 SKIP(merge-ref)=1(1m01s)
bash scripts/verify/verify-commit-messages.sh origin/master HEAD rc=0
git diff --check origin/master...HEAD rc=0
bash scripts/verify/check-secrets.sh --range "origin/master...HEAD" --staged 双双 rc=0(Secret guard passed.)——正因 13 个 sanitize Test 没搬

暗卷(变异测试,证明搬家后断言仍在管,且落点在新文件)

  1. process_arg_log.goappendConfigKeyName:把 value-like 参数的 redactedCount + 1 改成 redactedCount(脱敏计数不再累加)→ --- FAIL: TestSummarizeProcessArgsForLogRedactsValueLikeArgs,落点 process_arg_log_test.go:105(新文件);git checkout -- 还原后 ok
  2. process_profile.govalidatePlaceholders:函数体改成 return nil(不再拒绝未知占位符)→ --- FAIL: TestProcessExecutorRejectsUnknownPlaceholder--- FAIL: TestProcessExecutorRejectsInvalidEnvTemplate,落点 process_profile_test.go:194:217(新文件);还原后 ok 7.733sgit status --short 无 src 残留。

未验证 / 边界

…产域归位——拆出 10 个镜像生产文件的新测试文件(start 9/profile 8/build 2/cancel 6/fault_escalation 2/pure_adapter 7/helper 2/arg_log 2/finish 5/runtime_evidence 1)+ 3 个既有域文件各追加 1 个 Test(hub_output_text/thread_transcript),共享夹具与 4 个 mock adapter 收进既有 testutil_test.go,巨型文件 3283→510 行只留 NewProcessExecutor 构造/依赖校验/并发上限 8 个 + SanitizeSubAgentResult 13 个;四路守恒 diff rc=0(整包 Test 名 283=283、小写 helper 47=47、=== RUN 379=379、--- PASS 282=282、SKIP 1=1、0 FAIL)、逐行守恒 2973→2970 非空行(少的 3 行是巨石内分节注释,0 行新增)、11 个新/改文件 import 全在原文件 22 个 import 的并集内、0 个 src 改动;3 处 sleep 随域搬家 ⇒ test-sleep 双基线经 --update-baseline 重新键控(全局 47 sleeps 不变、21→22 文件,80ms negative_window/10ms simulated_slow/5000ms real_protocol 逐值保留,owner/review/reason 人工补全)。13 个 SanitizeSubAgentResult Test 刻意不搬:其夹具是故意的假凭据字面量,而 check-secrets.sh 的字面量规则对 range diff 新增行无条件生效且无 fixture allowlist ⇒ 逐字搬家实测 9 行判红,另开 issue 交裁决

Co-authored-by: Cursor <cursor@vectorcontrol.tech>
@coderabbitai

coderabbitai Bot commented Sep 3, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Team

Run ID: 08efdd9c-cb1c-4877-9c03-ad80a2640ee8

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@DeliciousBuding
DeliciousBuding enabled auto-merge (squash) September 3, 2026 16:27
@DeliciousBuding
DeliciousBuding merged commit 4949846 into master Sep 3, 2026
41 checks passed
@DeliciousBuding
DeliciousBuding deleted the test/edge-lifecycle-test-split branch September 3, 2026 16:31
DeliciousBuding added a commit that referenced this pull request Sep 3, 2026
…登记、逐条带 owner/review/reason,让脱敏测试重新可搬家,并把 #2296 刻意留下的 13 个 TestSanitizeSubAgentResult_* 搬出巨石文件(ADR-028,#2295) (#2307)

## 缺陷本体(实测复现,不是推断)

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: DeliciousBuding <DeliciousBuding@users.noreply.github.com>
Co-authored-by: Cursor <cursor@vectorcontrol.tech>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant