fix(harness): fail closed at review and privacy boundaries - #19
Merged
Conversation
Honor workspace, filesystem, and review boundaries before collecting evidence, and propagate invalid paths, Git refs, and collector failures as explicit errors. Normalize write-tool payloads and preserve severe findings without silently lowering risk. Implements QoderAI#11, QoderAI#12, QoderAI#13, QoderAI#14, QoderAI#15, QoderAI#16, QoderAI#17, and QoderAI#18 using docs/specs/2026-07-29-11-18-review-boundary-hardening.md. The change splits cleanly across Secret Guard, Qoder session ownership, quickstart input validation, Git/review failure propagation, severity repair, and cloc containment. Validated with npm run check (852 tests plus package verification), the 6-test documentation link graph, focused boundary tests, syntax checks, and staged diff checks. Constraint: Preserve successful-path and non-blocking finding behavior across supported hosts Rejected: Treat boundary failures as empty or warning-only evidence | this hides review and privacy failures Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep workspace, Git, and filesystem boundary failures explicit when adding collectors Tested: npm run check; node --test test/doc-link-graph.test.mjs; focused 68-test boundary run; node --check; git diff --cached --check Not-tested: Hostile concurrent symlink replacement on platforms without O_NOFOLLOW Co-authored-by: OmX <omx@oh-my-codex.dev>
There was a problem hiding this comment.
Pull request overview
该 PR 聚焦于 Better Harness 的“隐私边界 + 审查边界”加固:当无法验证 review / git / cwd / filesystem 边界时改为 fail closed,并补齐 Secret Guard 对多种工具事件形状与写入内容的扫描覆盖,同时保持成功路径的既有语义与降级策略。
Changes:
- Secret Guard:统一 snake_case / camelCase / args / nested / freeform 的 PreToolUse 事件形状,并扫描 Write/Edit/apply_patch 的内容字段(且不回显 secret)。
- Qoder 会话分析:workspace 模式下默认排除无法证明归属的 home-only sessions;
report --no-sessions跳过 session probe 并走静态software-fluency路由;report --cwd在 collector 前进行目录有效性校验。 - Blast-radius / Findings / CLOC:验证 git base ref、在 git 失败时返回明确 fail-closed 报告;severity 修复对已知“重度”标签做保守映射并拒绝任意未知值;cloc 读取加入 realpath/类型/边界与(可用时)O_NOFOLLOW 防护并跳过非 regular 文件。
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| test/session-usage-summary.test.mjs | 增加 usage-summary CLI 覆盖:验证 workspace 结果不包含无关 home-only session。 |
| test/session-analysis.test.mjs | 覆盖 Qoder analyzer 在 sessions/show/facets/insights/file-reads 等路径上排除无关 home-only session。 |
| test/review-trigger.test.mjs | 覆盖 review-trigger CLI 参数/运行时失败必须非零退出且不泄露输入;覆盖 base ref 不可用时 fail closed。 |
| test/harness-quickstart.test.mjs | 覆盖 --no-sessions 静态路由与 --cwd 非法值的提前拒绝;验证有效目录仍保留部分降级。 |
| test/harness-findings-repair.test.mjs | 覆盖 severity:对 Critical/Blocker 做保守映射(High),未知值不再被静默降级并应触发校验失败。 |
| test/cloc.test.mjs | 覆盖 tracked symlink、outside-repo 路径候选与 dotdot 段名边界行为,确保不泄露外部目标。 |
| test/blast-radius.test.mjs | 覆盖 base ref 有效且 clean 的保持 clean;base ref 不可用时 fail closed 并带清晰原因。 |
| test/agent-guardrails-secret-scan.test.mjs | 覆盖 Write/Edit/apply_patch 内容扫描、freeform apply_patch、camelCase 与 args/nested 规范化,且不回显 secret。 |
| scripts/session-analysis/platforms/qoder.mjs | home-session 探针加入 workspace 归属验证与 planningScope 标注,避免将无关 home-only 归入 workspace。 |
| scripts/review-trigger/cli.mjs | CLI 参数错误/运行时错误输出标准化失败 envelope(JSON/非 JSON),并对 cwd 做目录断言;不再吞掉关键边界失败。 |
| scripts/harness-quickstart/cli.mjs | --no-sessions 静态 session route;--cwd 在收集前校验并返回结构化错误。 |
| scripts/harness-analysis/repair-findings-json.mjs | severity 映射扩展为保守的“重度”标签集合;未知 severity 不再被自动降级到 Medium。 |
| scripts/cloc/count-file.mjs | 增加路径 containment(logical+realpath)、file-type 检查与(可用时)O_NOFOLLOW 打开策略,跳过非 regular/越界目标。 |
| scripts/agent-guardrails/secret-scan.mjs | PreToolUse 事件规范化并新增写入内容扫描目标集合(Write/Edit/apply_patch),保持 redact。 |
| hooks/git-scripts/blast-radius/git.mjs | 引入 GitFailureError 与 baseRef 校验;diff/numstat/untracked 收集失败不再被当作“空 diff”。 |
| hooks/git-scripts/blast-radius/analysis.mjs | 将 GitFailureError 转换为明确的 fail-closed 报告(critical + shouldReview)。 |
| docs/specs/2026-07-29-11-18-review-boundary-hardening.md | 新增与 #11-#18 对齐的规格文档(AC/非目标/计划/测试证据映射)。 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Filter Qoder home-session evidence per record while preserving explicit user-global analysis. Fail review-trigger on Git probe errors, reject empty report cwd values, and bound cloc reads before loading file content. Completes the PR review follow-ups for QoderAI#12, QoderAI#15, QoderAI#16, and QoderAI#18 under docs/specs/2026-07-29-11-18-review-boundary-hardening.md. Validated with the 80-test focused boundary run, npm run check, the documentation link graph, syntax checks, and staged diff checks.
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.
Summary
apply_patchpayloads across supported snake_case, camelCase,args, nested, and freeform event shapesuser-globalpassreport --no-sessionsbypass session probing and reject empty, missing, or non-directory cwd values before collectionThe implementation and acceptance evidence are recorded in
docs/specs/2026-07-29-11-18-review-boundary-hardening.md.Issue mapping
user-global--no-sessionsdirectly to the static fallbackreport --cwdvalues before starting collectorsReview
--cwd=, and unbounded cloc reads. All are fixed with regressions indb3963f.WATCH.O_NOFOLLOWretain a narrow hostile concurrent swap-to-symlink race. Stable symlinks and outside paths are rejected before reading.Validation
npm run check— full Node suite and package verification passednode --test test/doc-link-graph.test.mjs— 6 tests passednode --checkfor every modified implementation modulegit diff --cached --checkand post-updategit diff --checkCloses #11
Closes #12
Closes #13
Closes #14
Closes #15
Closes #16
Closes #17
Closes #18