Repository navigation
fix(githubreview): 证据的 redacted 与 truncated 标记各自跟随自己的真实工作 - #484
Open
Qiyuanqiii wants to merge 2 commits into
Open
Qiyuanqiii wants to merge 2 commits into
Qiyuanqiii wants to merge 2 commits into
Conversation
SanitizeRemoteText decided its Redacted flag by comparing the redacted text with outputsafe.Sanitize of the raw input, but Sanitize already runs redact.String and the escaping pipeline had rewritten the other side. A redacted GitHub token therefore reported Redacted=false while a benign link or an oversized plain body reported true. Let outputsafe say whether redaction changed the text and keep Sanitize's output identical by construction.
…lied SanitizeRemoteText also ORed "the stored text is shorter than the input" into Truncated, so a 47-byte payload holding one credential reported Truncated=true against a 4096-byte bound simply because masking made it shorter. The two real truncation passes already track the boundary, and OriginalBytes plus StoredBytes carry any shrinkage, so reserve Truncated for the limit actually being reached.
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.
SanitizeRemoteText用redacted != outputsafe.Sanitize([]byte(value))决定TextEvidence.Redacted(model.go:285的json:"redacted",随 PR 标题、评论正文、Actions 日志一起持久化)。这个比较的两端基线不一致:左边是经过“远程语法转义 + 去 CR + 裁剪 + 截断 + 二次脱敏”的文本,右边是Sanitize的产物,而Sanitize内部本来就调用redact.String(internal/outputsafe/stream.go:369-372)。所以它度量的是“转义管线有没有改动文本”,而不是“有没有脱敏”。两个方向都会错,合成数据实测:
SanitizeRemoteText("ghp_abcdefghijklmnopqrstuvwxyz0123456789", 100)的Text已经是[REDACTED:github-token],但两侧都脱敏过、字面相等,于是Redacted报false——真被脱敏的证据自称没被脱敏。see [docs](https://example.com/doc)和 200 个a的正文都不含任何机密,却因为链接被换成占位符、文本被截短而报true。修法是把“脱敏是否改动了文本”交回给真正做脱敏的那个函数:
outputsafe新增SanitizeWithRedaction(data) (string, bool),先取控制字符剥离后的inert,再比较redact.String(inert);Sanitize改成它的薄包装,返回文本按构造完全不变。SanitizeRemoteText由此能分别拿到第一次(Sanitize内部)与第二次(转义截断之后补打)脱敏的增量,Redacted取两者之或。没有动
Truncated。它当前的含义是“存下来的字节少于原始字节”,占位符替换也算缩短,这与Redacted的语义不是一回事;改它会改变既有证据的Truncated/SHA256组合,超出本 PR 范围。Redacted目前也没有判定型消费方(只被序列化进 API 视图),所以本修复不改变任何门禁、授权或执行行为,只纠正证据元数据。验证:
origin/main上三条全红:token only: Redacted=false, want true、inert link: Redacted=true, want false、oversized plain text: Redacted=true, want false;修复后go test ./internal/githubreview ./internal/outputsafe -count=1通过。outputsafe侧另加一条用例,同时断言“含机密时redacted为真”和“仅控制字符被剥离时redacted为假”,并断言SanitizeWithRedaction的文本与Sanitize逐字相等。TextEvidence.Redacted(internal/httpapi/ui_evidence_test.go里的Redacted: true属于uievidence.ArtifactMetadata,不是同一结构体),没有既有断言依赖旧值;outputsafe.Sanitize(的非测试调用点共 14 处、分布在 7 个文件(toolgateway5、runner3、browserruntime3、githubreview1、application1),它们拿到的文本不变。gofmt -l internal/githubreview internal/outputsafe无输出;go vet ./internal/githubreview ./internal/outputsafe通过;git diff --check干净。本机 Go 全量套件有与本次无关的环境性缺口,见 fix(ui): 终端关闭响应迟到时保留新的会话绑定 #479 正文记录。ocr delegate preview --from origin/main --to HEAD给出 2 个可复核文件 / 共 4 个改动文件(merge_base513c9510,+49/-4),两个_test.go被默认路径规则排除,已另行人工复核。按system / **/*.go规则组重点核对:无被忽略的 error、无 nil 接口与锁拷贝(Stream只有state/pending两个字段,每次调用新建实例,返回的是字符串副本,不存在跨调用的可变缓冲)、无数值边界或并发状态改动、测试沿用同文件既有的合成 token 而非真实凭据。无发现。无 Surface 变化;
docs/openapi.json无需再生成(只改字段取值,未改 DTO 结构);不含凭据与本地运行数据;不触碰权限、Scope、沙箱与持久化边界。同一函数里
Truncated还带着同类问题,我按同样的判据一起修了(第二个提交22081d5c)。internal/githubreview/sanitize.go结尾原本写作truncated = truncated || secondTruncation || originalBytes > len([]byte(clean)),第三个 OR 项的含义是"存下来的比原载荷短",而不是"撞到了字节上界"。脱敏本身就是缩短文本的:github=ghp_<36 位合成 token>共 47 字节,[REDACTED:github-token]之后只剩 30 字节,于是这条 47 字节的证据在对 4096 上界毫无压力的情况下报告Truncated=true。实测(-run TestSanitizeRemoteTextTruncatedFlagTracksTheByteBound,加在本 PR 已有的sanitize_test.go上):新用例把三种情形分开了:界内脱敏(
Truncated=false、Redacted=true、StoredBytes < OriginalBytes)、单次上界截断(true)、脱敏标记撑过上界后的第二次截断(true)。前两条在本 PR 的既有断言里已经钉住(sanitize_test.go:15与:69都对确实越界的载荷要求Truncated),删掉这一项不会让真实截断变成false;两条界内/界外断言在改动前后都绿,只有界内脱敏那条从红转绿,说明本项确实是多余的。OriginalBytes与StoredBytes一并序列化,任何"存下来的比原来少"的判断都能直接比较这两个数,而转义丢失本来就在正文里留下[remote link omitted]之类的标记,所以收窄Truncated不会把信息缺口藏起来。我也确认没有消费方按Truncated分支:网页侧只是带着这个字段——它出现在生成的web/src/api/schema.d.ts:9942和两个测试夹具里(github-review-panel.test.tsx:43-44/62、task-review-tools.test.tsx:52),web/src/api/client/responses下没有它的解析器(original_bytes0 命中),github-review-panel.tsx与task-review-tools.tsx对truncated0 引用;Go 侧读这条证据的文件(internal/application/github_review_service.go、pr_followup.go、pr_followup_changes.go、internal/app/github_review_command.go、agent_code_tools.go)对Truncated0 处引用,internal/httpapi不引用TextEvidence类型,全仓grep里internal/githubreview之外没有针对该字段的断言或分支。第二个提交后重跑:
go test -count=1 ./internal/githubreview/通过(0.907s);gofmt -l对本 PR 四个文件无输出;go vet ./internal/githubreview/通过;git diff --check干净。ocr delegate preview --from 513c9510 --to HEAD→ 仍是 2 个可复核文件 / 共 4 个改动文件(+70/-5),两个_test.go依旧被default_path排除并已人工复核。新增改动的规则组核对:契约变化只收窄一个布尔标记的含义且已在上文给出影响面证据;originalBytes变量仍用于OriginalBytes字段,无未使用变量;无新增 error 路径、无锁与共享状态、无数值边界。无发现。