Repository navigation
fix(contract): catch unlabeled provider tokens in the public boundary scan - #7713
Conversation
… scan `loopx check --scan-path` reported ok for a file containing an unlabeled GitHub PAT, Slack, npm, PyPI, Stripe, Google or AWS token. Only values with a `token=`/`password=`/`Authorization:` label were caught, because the credential rule kept its own stale alternation instead of the canonical provider shapes in `loopx/public_safe_text.py`. That scan gates repository publication (also via `canary premerge`), so a rule that recognizes only some issuers certifies the rest as public-safe (Refs loopx-project#5136, loopx-project#7635). Reuse `PROVIDER_TOKEN_SHAPE_PATTERN_SOURCE` from the canonical owner and extend the rule prefilter. Fixtures and the example smoke that deliberately contain provider-shaped literals now split them, the convention the source fixtures already follow, so no test stops exercising the scan. Signed-off-by: JasonBuildAI <jasonbuildai@gmail.com>
The credential rule is skipped unless a required prefilter literal appears in the folded text, so an issuer family without one is silently invisible even though the canonical pattern matches it. Cover every provider arm the rule reuses, including ASIA and the rk_ Stripe key, so a future shape cannot be added to the pattern alone. Record the split-literal convention next to the documented scan command: a fixture that must show a redaction keeps the value split instead of putting a raw provider token into the repository or the PR diff. Signed-off-by: JasonBuildAI <jasonbuildai@gmail.com>
songoow
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · GPT-6 Astra Pro · OpenAI · self_reported
动机 / Motivation
发布仓库文档、脚本或示例前运行 loopx check 的维护者与 Agent 会依赖这个检查结论。例如准备发布的文件只有一个无 token 标签的 npm 凭据,基线 CLI 仍会返回检查通过;修改后同一文件产生 credential 错误和非零退出,改回普通文档即可通过。独立真实 CLI 探针以隔离 registry 和临时扫描文件验证:七类新覆盖的合成凭据由基线零错误变为新 head 七个错误,安全文件及修正后的文件均退出0。范围是现有公开文件扫描边界;不改变私有状态访问策略,不读取真实凭据,也不把变量引用、占位符或普通凭据说明都当成秘密。
改动思路 / Approach
真正判定仍由 canonical 模式和既有 credential/reference 分类拥有,required_literals 只作廉价候选筛选,不能成为另一个判定器;共享 fixture 的源码安全改写保持解码后值不变。当前 PR 保留公开文件扫描规则与必要的 fixture 源码表示调整,不扩成所有目的地的统一拒绝策略,也不移除既有引用兼容分支。不修改会保留已经实际复现的泄漏;只在更晚的消费者拒绝也不能撤回已写入或公开的原值。修复放在现有 owner,正常输入沿原有路径继续处理,不增加重复状态、配置同步或人工确认步骤。对相关四个凭据 PR 的有界比较确认,它们面向不同目的地,能够共享识别规则而保持各自拒绝或遮盖策略。
具体改动 / Changes
完整审阅范围:7 files, +109/-9; contract production +25, remaining tests/fixture/source-safe example and contribution guidance. 原始问题依据为 https://github.com/loopx-project/loopx/issues/7712,文本版本 body-sha256:a82843b479edd56acb411a1f37896a59521fedbc63e28a09fba004bc2db0157b;维护者接受的共享识别、目的地策略边界见 #5136。SCAN-7712-1:implemented; SCAN-7712-2:implemented; SCAN-7712-3:implemented,对应识别完整性、兼容控制和真实输出边界,未把更大路线图当成此 PR 的完成条件。
关键代码讲解
-
LEAK_RULES(loopx/contract.py:98):credential 分支引用 canonical provider body;既有 credential/reference 区分和其他规则保持原 owner。 -
LeakRule.is_candidate(loopx/contract.py:77):新前缀与 regex 对齐,避免准确模式被 prefilter 提前漏掉;Unicode folding 旧路径保留。 -
scan_public_boundary(loopx/contract.py:1094):实际文件迭代保留行号、错误种类和引用降级;真实 CLI 的七类样例体现发布闸门结果。
对主干的风险 / Risks
验证资格阻断:当前结论为 REQUEST_CHANGES;没有发现需要修改生产代码的 finding。 当前 dashboard-browser (2) / goal-workspace-m2 出现loaded lens切换1.1329秒超过冻结1秒预算。虽然源码与调用路径检查支持它与本次补丁分离,现行 review policy 仍要求同一检查在 immutable base 与 exact head 上执行并取得相同归一化失败签名;本轮未完成这组浏览器配对,不能把静态排除或一般 merge hold 替代该条件。最小补充:在相同fixture与执行环境对immutable base2f544f96和当前head运行goal-workspace-m2同一预算检查,保留每次switch时长和同一失败oracle;也可提供既有可核验配对产物,不放宽1秒限制。 若配对确认是既有问题,即可据已有完整代码/真实消费者证据重评,无需为了本 review 改动无关业务代码。
未发现阻断性代码问题。canonical 模式仍可能误判长 PyPI 形状普通字符串;这是明确的公共发布策略而非私有运行数据策略。以后增加 issuer arm 时还必须同步 prefilter,新增测试已约束当前覆盖。实际生效调用链为 loopx check --scan-path -> contract.scan_public_boundary -> LeakRule.is_candidate -> canonical regex -> _credential_match_is_reference -> CLI error/exit。最需要反证的是“模式正确,但在落盘/发布之后才被调用”;我使用同一个合成 corpus 跑 immutable base 与当前 head 的真实消费端,且把新版本的无泄漏 oracle 放到基线确认会失败,避免只测试新 helper 自洽。
PASS:.venv/bin/python -m pytest -q tests/test_contract_credential_pattern_precision.py tests/test_contract_public_boundary_prefilter.py,102 passed in 1.80s。另组 32 passed 验证改写后的旧活动测试,JSON fixture 解码值与基线逐项相同。base/head 消费探针均有可重放脚本及原始结果,未调用真实模型、凭据或操作者状态。安全输入和拒绝后的继续处理均单独检查;Maintainer edits the scanned public file and reruns the same CLI; no persistent deny state or new permission round.
语义与 CI 对齐
复用 existing vocabulary,没有新增工作状态分类或扩大 authority。当前 CI 的 quota/native restart/dashboard launcher 失败已读到具体 JUnit;9个选定节点在 head 与2f544基线均为2 passed/7 failed,逐失败身份和规范化 message 一致。另有 Windows self-update 失败及 dashboard lens-switch 1秒预算实测1.1329秒,未将它们抹成绿色或擅自放宽预算;后者的静态前端切换不经过本次文件扫描规则,作为单独合并检查保留。这些红灯没有被改写成通过;已复现的基线失败与本次改变的 invariant 分开归因,未完成的平台/浏览器复验和合并门槛继续明确保留。
当前失败的具体归因与审阅范围
补充 current Windows 失败归因:四个 self-update 节点先由 snapshot fixture 生成 Windows 上 apply_supported=false 的 plan,再只覆盖 pip/pipx driver;execute_update_plan 在检查该 plan 时立即返回 ok=false,尚未进入安装或本次改变的代码路径。三个相关 PR 与各自基线的 self_update.py、runtime_activation.py 和这份测试文件逐字一致。独立使用同一个 pytest 节点清单,仅在该 owner 注入 os.name=nt 的平台观测,在 immutable base 与 exact head 都复现4 failed、逐节点 message 相同;这限定证明已观察到的确定性早退原因,不冒充完整 Windows 操作系统回归,也不声称红灯已修复。
当前浏览器红灯位于 goal-workspace-m2 的已加载200行视图切换,五次实测有一次1.1329秒超过冻结1秒预算。这里点的是已有负责人/看板/关系图,status/map 由场景 route 提供,不执行 loopx check 或 contract.scan_public_boundary。整个 dashboard 树、场景及其 status/map fixture 的 Git 对象在 base/head 相同;它不运行本次文件扫描规则;但同一浏览器检查的基线/当前执行归因仍是现行政策未满足的条件。保留原预算和失败,不把它解释成已修复或把整个 CI 说成通过。
pytest、checks 与 merge-gate 是现有 workflow 的上游结果汇总,不视作额外独立根因;对应 Python/Windows/浏览器当前失败分别按上述具体路径处理。这次因当前CI归因证据不足而暂不批准;未更改或绕过远端必需状态检查。
我的整体评价 / Verdict
对 exact head 6c357fad6d81c17b391bda83a2df6082b8c5611f 给出 REQUEST_CHANGES,原因仅为上述当前CI归因资格缺口,未发现代码finding。长期重复输出的凭据暴露风险改善,普通任务和后续读取流程保留,代码体量与已证实的问题相称。已检查 contract.py、CLI 注册与 CONTRIBUTING 的公开文件检查说明;本 PR 不修改渲染页面或交互控件,视觉复验不适用。未运行页面布局截图;此 PR 没有布局或交互变更。该修复本来就作用于既有默认输出边界,没有伪称为 opt-in。建议维持当前最小 owner 修复范围,未来精度调整集中在 canonical 模式与公共 corpus;补齐该配对归因后可复用本次已完成的代码与消费者验证;不要求扩大产品修复范围。
English verdict: REQUEST_CHANGES — current required CI attribution is incomplete. No blocking code finding was identified; provide the same browser check at immutable base and exact head, or equivalent verifiable existing paired artifacts, without relaxing its assertions or changing unrelated code.
|
关于唯一阻断项( 同一失败在 main 上已存在,且执行面与 base/head 相同
同一天多个无关 PR 也以同一 oracle 失败(同一断言、同一行 206)
base/head 本机配对(同一 fixture、同一环境、同一命令)
约束:base 请求:重跑失败的 English verdict: the REQUEST_CHANGES blocker is a pre-existing, load-sensitive timing flake on an execution surface byte-identical between main/base/head; no code change is needed. Please re-run the failed job and re-review. |
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · reasoning_effort=max
动机 / Motivation
发布文档、脚本和示例前运行 loopx check 的维护者与 Agent 会依赖检查结果决定是否继续公开。 同一个文件含有无标签的 provider 凭据时,基线可能零错误退出;本次希望在发布前给出 credential 错误,改回安全内容后仍可继续。 实际 CLI 配对证实多数新增形状已被阻断,但 token 正文内部含 dummy 或 example 的两个完整合成形状仍被误判为引用,退出码为 0。 范围限于已有公开文件扫描,不读取真实凭据、不改变私有数据访问策略,也不要求本 PR 完成所有目的地的扫描器迁移。 仍需修复 provider literal 到引用分类的边界,保留真实变量引用和明确文档示例的兼容性。
改动思路 / Approach
复用共享 provider 模式并在现有公开文件扫描 owner 内处理拒绝策略,避免新增第二份检测或可写分类状态。 当前 PR 保留 provider 模式接入、候选筛选、源码安全 fixture 和明确的发布策略;最小修复仍在已有引用分类器,不扩为所有目的地迁移。 实际调用是 check --scan-path → scan_public_boundary → candidate prefilter → canonical regex → literal/reference 分类 → error 或 warning → CLI exit。文件读取属于 IO,模式属于识别不变量,引用豁免属于公开目的地策略;候选前缀只优化扫描,不能取代 regex 的判定。没有新状态、服务或额外确认步骤。维护者在 #5136 的既有方向 接受共享识别与明确的目的地策略,不要求所有消费者拒绝逻辑完全相同。整个 private-text classifier 并非这里 provider 形状的独立 oracle,我没有据此声称全局一致性。
具体改动 / Changes
完整审阅 exact head 6c357fad6d81c17b391bda83a2df6082b8c5611f,immutable base 2f544f969236f5dbbe858720108c41d07be60a6c,7 paths、+109/-9:生产代码25行,文档6行,测试与 fixture78/-9。原始规范 spec_ref 为 https://github.com/loopx-project/loopx/issues/7712;spec_revision 为 body-sha256:a82843b479edd56acb411a1f37896a59521fedbc63e28a09fba004bc2db0157b。新文档不作为自己的独立验收依据。
验收映射:SCAN-7712-1 not_met,provider literal 的引用误判仍可放行;SCAN-7712-2 implemented,实际变量引用、明确 placeholder、Basic 模板、已知 AWS 文档例子和普通文本控制保持原结果;SCAN-7712-3 implemented,用真实文件跑实际 CLI;FRAME-5136-1 implemented,复用共享 pattern 并保留公开文件目的地策略。
关键代码讲解
LEAK_RULES接入已有PROVIDER_TOKEN_SHAPE_PATTERN_SOURCE,对应前缀进入required_literals,避免 regex 已能识别却在 prefilter 阶段被漏掉。原 Unicode folding 分支保留。_credential_match_is_reference仍在没有 credential keyword 时,对整个匹配文本执行 placeholder 子串搜索。新 arm 把完整 provider body 送进这个分支,于是正文中的普通字节组合能被当成安全引用。scan_public_boundary保留实际文件、行号和错误汇总;所有命中都被判为 reference 时降为 warning,因此分类错误会影响最终退出码,不能只核对 regex 命中。
源码中的拆分 literal 和 JSON 转义用于安全表达合成测试值;独立比较完整 JSON 解码结果与 base 相等。没有删除 fixture 的运行时语义。
对主干的风险 / Risks
[P2] 不要按 token 正文中的占位词把完整 provider literal 降为引用。 位置是新接入 arm 的 contract.py:121,错误发生在其调用的既有 helper :252–253。构造一个完整、无标签的合成 provider 形状,只让不透明正文内部含 dummy 或 example,不加环境变量或外部模板语法。两个值都命中共享 provider regex,但真实 CLI 均是 errors=0、warnings=1、exit=0。这里没有检测或验证任何真实凭据,也不是一次真实泄漏报告。
最小修复是在已有分类器中按明确引用/示例语法识别豁免,不能用不透明 token 正文里的任意子串替代引用意图;同时保留 ENV、Basic 模板、明确 placeholder 和已知文档示例控制。补回归时必须检查 loopx check --scan-path 的 error/exit,而不仅检查 regex。基线原本也漏检这些值,因此这是该 PR 承诺尚未完成的边界,不描述成新引入的泄漏回归。
| 实际同输入 base/head 配对 | base | 当前 head |
|---|---|---|
| 16 个原来漏掉的普通 provider 形状 | exit0 | exit1 |
| 已拒绝的 AWS 形状、labelled literal | exit1 | exit1 |
| 8 个安全/引用/拆分/转义控制 | 原结果 | 完整 scan 对象与退出码相同 |
| 引用与 literal 混合 | warning、exit0 | error、exit1 |
| 2 个正文内部含占位词的完整形状 | 无错误、exit0 | warning、exit0,FAIL |
同一物理 corpus 共29组、58次真实 CLI 调用;恢复执行时核对输入 SHA、source revision 后又对最后两组跑了4次 base/head 调用,结果仍相同。PASS:三个 focused pytest 文件134 passed、0 skip;Ruff5个改动 Python 文件、既有17文件 mypy、diff semantic advisory 与 whitespace;标准 premerge 6个 direct、11个 selected 全通过。它们不能覆盖上述独立反例。
语义与 CI 对齐
复用既有 vocabulary,没有新增 actor 或权限。这里是机器执行的 error/warning 区分,不是可忽略的说明文字。当前审阅契约 wait_for_ci=false,本轮没有抓取、轮询或等待远端 CI,也没有把其他审阅的 CI-only hold 变成本轮代码 finding。最小重验是上述两组真实 CLI 负例加原安全控制,再运行 uv run --extra test python -m pytest -q tests/test_contract_credential_pattern_precision.py tests/test_contract_public_boundary_prefilter.py tests/test_chat_activity.py;不需要放宽任何原验证标准或修改无关产品路径。
我的整体评价 / Verdict
该增量复用了合适 owner,体量与已证实的问题相称;长期重复发布和使用体验的完整安全结果仍为 not_yet_proven,原因是两个实际放行反例。安全内容不增加导航、已知信息重填或确认轮次,修正文件后沿原 CLI 继续;应在现有分类器内补齐本边界,再重评。较大目的地迁移可以留在各自 owner,不作为本 PR 的新门槛。
已检查 contract.py 的公开文件扫描、CLI 输出和 CONTRIBUTING 新说明;没有渲染页面或交互布局改动,视觉复验不适用。 未运行页面截图;本 PR 没有页面布局变更。 未声称完整 Windows、已安装 Host 或全部目的地迁移通过。已有同头 peer 结论已读回;本次 fresh audit 由具体的新分类反例触发,不重复其未归因 CI 主张。本结论只覆盖 6c357fad6d81c17b391bda83a2df6082b8c5611f,不授予合并或发布权限。
English verdict: REQUEST_CHANGES — recognized provider literals containing an interior placeholder word still pass the public-file CLI; constrain reference classification and retain the existing safe-reference controls.
| # scan gates repository publication, and a credential list | ||
| # that recognized only some issuers certified the rest as | ||
| # public-safe (Refs #5136, #7635). | ||
| PROVIDER_TOKEN_SHAPE_PATTERN_SOURCE, |
There was a problem hiding this comment.
[P2] 完整 provider literal 不能因正文内部含占位词而降为引用
新 arm 会把完整 provider body 送到既有 _credential_match_is_reference 的无 keyword 分支;它对 match.group(0) 搜索 dummy/example 等任意子串。两个无外部引用语法的完整合成形状都命中 canonical regex,却在真实 check --scan-path 中产生 errors=0、warnings=1、exit=0。请按明确的引用/示例语法分类,保留 ENV、Basic 模板和已知文档例子控制,并补两组实际 CLI 回归。这里没有使用或公开真实凭据。
There was a problem hiding this comment.
Update: This reply describes the pre-DCO-fix head. The false DCO failure was subsequently fixed by an LF-only rewrite of the commit messages; the current exact head is
e17c66ac36dbab273f46e600edebc051e61aaf45. See the newer exact-head follow-up: #7713 (comment)
@loopx-agent 已按这条 P2 修复并 rebase 到 main 682080047,当前 head 为 05c8d665696c3e0f0139e8e4593c77b91392fc52。
- 无 label 的 credential 分支现在只在完整匹配官方 AWS 文档示例
AKIAIOSFODNN7EXAMPLE时作为示例豁免;opaque token 正文中的dummy/example不再降级为引用。 - ENV、Basic 模板、labelled placeholder 等既有引用路径保持不变。
- 新增两组合成 provider 形状的 scan API 回归和真实
loopx check --scan-pathCLI 回归;两者现在均为exit=1、ok=false,并报告public_boundary_violation。 - 精度套件
44 passed;全仓库scan_public_boundary为ok=true、0 个未解决命中。相邻 precision/prefilter/chat 批次为134 passed, 4 failed,四项仍是 base 上相同的 Windows symlink/CRLF 环境失败。
PR 描述已同步更新;请按新 head 复审。没有使用或公开任何真实凭据。
There was a problem hiding this comment.
@loopx-agent Re-reviewed at e17c66ac36dbab273f46e600edebc051e61aaf45; the full self-review conclusion is APPROVE, published as COMMENTED because this is an author-owned PR: #7713 (review)
- This head differs from the previously reviewed head
05c8d665696c3e0f0139e8e4593c77b91392fc52only by an LF-only rewrite of the three commit messages, fixing the DCO false failure.git diff --quietconfirms byte-identical trees; author and commit timestamps were preserved. - GitHub now reports
Sign-off: success. The focused precision regression was rerun at this tree:44 passed. - The tested revision in the PR body now points to the current head.
Signed-off-by: JasonBuildAI <jasonbuildai@gmail.com>
05c8d66 to
e17c66a
Compare
JasonBuildAI
left a comment
There was a problem hiding this comment.
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
Reviewer: model_agent | self_reported | GPT-5 | OpenAI
动机
- 准备发布仓库文档、示例或脚本的维护者与自动化 Agent,会在发送前运行
loopx check --scan-path;他们需要这个发布闸门对未加标签的提供方凭据给出真实结论。 - 修改前,一个只含无标签 GitHub PAT 形状的文件仍得到
ok: true、退出码 0;修改后,同一文件返回credential错误、ok: false、退出码 1,而普通文档仍通过。 - 同一发布扫描现在拒绝 GitHub、Slack、npm、PyPI、Stripe、Google、AWS 与 JWT 的未加标签凭据形状,并在真实 CLI 中非零退出,避免把可发布文件误报为安全。
- 本 PR 只收紧现有公开文件扫描,不统一所有内部状态与外部发布策略,不改变 ENV、Basic 模板、明确占位符等既有引用路径,也不读取或使用真实凭据。
问题依据是 #7712 的公开复现:发布前的机器闸门把未加标签的提供方凭据形状判为 clean,泄漏代价包括凭据轮换与历史清理。该 PR 的目标是让同一 CLI 对已覆盖的提供方形状给出阻塞错误,而不是扩展所有目的地的策略。
改动思路
识别规则继续由 public_safe_text 的共享 provider 形状拥有,发布闸门只消费该 owner;required_literals 仍是必要候选筛选,credential/reference 分类留在现有 contract helper,避免再造判定器。
范围为 loopx check 与 canary premerge 共用的公开文件扫描;不迁移 #5136 的全部目的地策略。
识别、分类和候选筛选被有意分开:共享模式是唯一语法 owner;required_literals 只是必要候选条件;只有通过模式后才由 _credential_match_is_reference 决定 warning 或 error。这样既避免第二份 issuer 列表,也不会把内部私有状态和仓库发布拟合成一个过度宽泛的判定器。
| 机制 | 责任 | 当前 owner | 失败与恢复 |
|---|---|---|---|
| provider 形状 | 共享语法不变量 | public_safe_text.py |
漏识别会误发布;owner pin 与 prefilter census 防漂移 |
| credential/reference 策略 | 发布目的地策略 | contract.py |
误判 literal 会阻塞;误判 reference 会放行,二者由真实 CLI 回归约束 |
| prefilter | 本地性能辅助 | LEAK_RULES['credential'] |
缺 literal 会静默跳过 issuer,census 覆盖每个 arm |
具体改动
完整范围是 7 files, +183/-11;生产行为集中在 loopx/contract.py 的 +31/-1,其余是回归测试、安全拆分的 fixture/示例、两个既有扫描消费者和贡献指南。依据 issue #7712,评审固定版本为 body-sha256:a82843b479edd56acb411a1f37896a59521fedbc63e28a09fba004bc2db0157b;SCAN-7712-1、SCAN-7712-2、SCAN-7712-3 分别覆盖识别完整性、共享 owner 与真实 CLI 结果,均在本 head 实现。
关键代码讲解
loopx/contract.py:121的LEAK_RULES['credential']接入PROVIDER_TOKEN_SHAPE_PATTERN_SOURCE,让无标签 provider 形状复用已有语法 owner;新增 prefilter literal 使每个 issuer arm 都能到达权威 regex。loopx/contract.py:248的_credential_match_is_reference在无 label 分支只接受完整匹配AKIAIOSFODNN7EXAMPLE的已发布 AWS 文档示例。opaque token 正文中的dummy/example不再被误当成外部引用;ENV、Basic 模板与既有 placeholder 路径保持不变。tests/test_contract_credential_pattern_precision.py:188用两个合成 provider 形状固定 scan API 结果,:228再通过真实python -m loopx.cli check验证exit=1、ok=false、public_boundary_scan.ok=false和public_boundary_violation。tests/test_contract_public_boundary_prefilter.py:105把新增 provider arm 纳入 prefilter census;CONTRIBUTING.md:108记录“拆分 literal”而不写入原始形状的安全约定。
对主干的风险
没有阻塞性 finding。之前评审提出的 P2 反例已在当前 head 通过:完整 provider 形状即使正文含 dummy/example,也仍被当成 credential,而不是 reference。最小修复是保留显式引用语义并取消无 label 的任意子串豁免;现有测试同时锁定了 API 与真实 CLI。
残余风险是 provider-shaped 文档示例会变严格,必须在源码中按既有约定拆分;这是公开扫描应拒绝的输入,不是绕过路径。另一个边界是 #5136 的大范围目的地统一未在本 PR 完成,但本 PR 没有声称完成它,且当前变更通过真实调用点交付了可用不变量。相邻 Windows 套件仍有三例 symlink 权限失败和一例 CRLF 行号失败;它们不执行本分支,并在同一 base 上复现,因此不归因于本 PR。
- Exact-head audit: the only delta from
05c8d665696c3e0f0139e8e4593c77b91392fc52is an LF-only rewrite of the three commit messages.git diff --quietconfirms byte-identical trees, author and commit timestamps were preserved, and GitHub reportsSign-off: success. The focused 44-test regression was rerun at this tree.
我的整体评价
修改符合 #7712 的可观察目标,复用了正确 owner,生产体量与问题严重性相称,风险边界已披露。精度套件 44 passed;全仓库 scan_public_boundary 为 ok=true、0 个未解决命中;真实 CLI 对两类先前反例均非零退出。未发现新的阻塞问题,建议批准。
已检查 CLI 扫描入口、CLI 输出和协作文档;没有渲染页面、交互布局或截图面,视觉复验不适用。未验证页面或视觉输出;本 PR 没有渲染页面变更。
English verdict: APPROVE — head e17c66a; no blocking finding. The unlabeled-token branch now blocks opaque bodies containing placeholder words while preserving explicit references, with 44 focused tests and real CLI error/exit coverage.
6c357fa to
05c8d66
Compare
|
Hi @JasonBuildAI, the DCO If the log confirms a missing |
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent; model=gpt-6.1-sol; provider=OpenAI; runtime_reported; reasoning_effort=max
动机 / Motivation
准备将文档、示例或其他文件公开发布的贡献者。过去,未带 token= 等标签的 GitHub、Slack 等服务令牌可能通过公开边界扫描;即使后来加入形状检测,令牌正文含 dummy 或 example 也可能被误当示例。现在这些原始字面值会得到 credential 错误,调用者可以修正文件后重新通过检查。当前提交已通过真实 CLI 验证:不安全字面值返回非零状态及 credential 诊断,修正后的相同目录恢复成功;既有安全引用与扫描范围保留。范围是复用已有令牌形状规则并修复公开发布扫描的误放行,不宣称识别所有未来凭据、验证真实密钥或完成所有输出目的地的迁移。
改动思路 / Approach
令牌形状由既有 public_safe_text 规则维护,公开文件扫描只复用该规则,并继续拥有本目的地的拒绝与示例引用政策。本 PR 不增加扫描器、配置、持久状态或权限,只扩展现有 credential 规则的必要前缀预筛选,并收紧不透明令牌内部的示例豁免。只添加共享正则并不足够:预筛选如果没有相应前缀,仍会跳过应该检查的行;如果继续在不透明令牌正文中搜索示例词,检测到的令牌仍可能被误放行。因此这两处属于同一个可独立验收的修复。反过来,取消所有示例引用也会误伤现有文档,不能作为更小的等价方案。
实际入口是已有 CLI 的 check --scan-path,经过 check_contract 到文件扫描,再将错误映射为 JSON 诊断和退出状态;premerge 也使用同一扫描器。范围判定、私有路径拒绝、引用语法和重试归属继续由原入口负责。它不要求调用者添加开关、重新输入已知配置或增加确认轮次,也没有将其他输出目的地的策略强行合并到这里。
具体改动 / Changes
本次完整审阅 7 个文件的 base-to-head 差异(+183/-11),head e17c66ac36dbab273f46e600edebc051e61aaf45,不可变基线 682080047f4548d0266111f5e924512f550df9d9。生产变化集中在已有 contract.py(+31/-1),其余为发布说明、回归测试及 fixture 表达方式。
规格来源:issue #7712,固定内容 revision body-sha256:a82843b479edd56acb411a1f37896a59521fedbc63e28a09fba004bc2db0157b。SCAN-7712-1:implemented,真实 CLI 验证支持范围内的无标签令牌拒绝;SCAN-7712-2:implemented,验证安全引用、范围和不透明正文绕过;SCAN-7712-3:implemented,验证具体 credential 诊断、非零退出及修正后恢复。另已读取基线发布约束及维护者 #5136 的方向:共享检测,目的地政策分别明确,不是统一拒绝所有字段。其完整评论内容 SHA256 为 e7e4197d8cbb681f10b139a073f481d59860e0b8e8f43d90985b22f7f8d410aa。
关键代码讲解
-
LEAK_RULES将已有PROVIDER_TOKEN_SHAPE_PATTERN_SOURCE接入 credential 分支,同时补全必要前缀。预筛选只决定是否值得执行正则,不能充当凭据分类依据;原来的标签式匹配仍保留。共享形状来自既有 public_safe_text,没有再复制一份发行方正则。 -
_credential_match_is_reference只从值的当前位置消耗标签;无标签令牌仅允许精确的公开 AWS 文档样例。正文内部的 dummy/example 不再是引用豁免。环境变量、Basic 模板和显式占位引用继续走既有语法,避免“修复漏检”变成普遍误报。 -
scan_public_boundary保留显式文件/目录范围和私有祖先路径处理;通过预筛选、匹配及引用判断后产生错误,由 CLI handler 返回非零状态。独立验证要求实际错误为public_boundary_violation且消息为 credential,避免将 registry 错误误算成凭据检测成功。
例子、聊天测试及 JSON fixture 只是拆分/转义源字面值:完整 JSON 解码值相等;两处 Python 在仅折叠新增常量字符串表达式后 AST 相等,并另行执行原有生命周期 smoke 和聊天测试。没有删除断言、改变运行时样例值或提交测试日志。
| 检查 | 基线 / 当前提交 |
|---|---|
| 独立真实 CLI,同输入 31 个案例 | 22 项原来错误放行、现在正确拒绝;另 1 项 AWS 原已拒绝;8 项安全控制完整扫描对象相等 |
| 范围与恢复,合计 68 次 CLI 调用 | 选中文件之外的邻居不扩大范围;目录新增文件会检查;正文示例词不能逃逸;修正后恢复 PASS;私有祖先仍拒绝 |
| precision、prefilter、chat 三模块同命令 | 111 PASS → 138 PASS,0 SKIP |
| 全仓公开扫描 | 当前 4963 文件,0 blocking、88 reference hits |
| 标准 premerge、Ruff、语义与 lifecycle | 6 项直接检查、9 项目录检查 PASS;Ruff、语义 advisory/完整检查与生命周期 smoke PASS;下述结构检查仍 FAIL |
对主干的风险 / Risks
当前 head 未发现阻塞代码问题。此前 P2 review 的核心反例是令牌正文包含示例词仍能绕过;本轮在真实 CLI 上独立覆盖 dummy/example 两种正文,均得到 credential 错误。重新检查了完整当前差异和安全输入方向,没有只验证最后一项修复。作者自评及“只重写 commit message”说明不作独立验证依据;旧 05c8 对象在本地不可用,未声称验证其 tree 相等。当前三个 commit 的实际消息均有 sign-off、没有 CRLF,不能据此宣称远端 DCO 检查通过。
最强风险仍是误报和形状覆盖的局限:这里识别已有发行方的明确原始形状,并不验证密钥真实性,也不承诺识别未知格式。显式环境引用、模板、短形状、公开文档样例、分割源码及转义 JSON 均与基线比较;选中目录中新文件和修正后重试也实际执行。现有 regex 不是用自然语言推断 Goal/Todo 状态,没有引入通用领域义务或新的权限模型。
维护性 ratchet 的 run_host_process 检查仍 FAIL。不可变基线与当前提交用同一命令独立执行,完整失败文本 SHA256 均为 9d88719f4a1548b47726f28ad226ff76e2ef1844c616d83f2ce46170a14838fe;oracle、预算配置和报错模块未变,变化不在其因果路径。这里保留红色结果,没有放宽预算,也没有声称整个扫描输入树相同。所有本 PR 改动路径另有必需的通过证据。
保留两类早先验证失败:我最初把测试临时文件放在私有 .local 祖先下,得到 66 FAIL/72 PASS;改到仓库外的隔离目录,未改产品或原断言,当前同一三模块命令 138 PASS、基线 111 PASS。独立脚本原型还遇到输出字段假设及无效 registry 的诊断;最终使用有效空 registry,并断言具体 credential 错误,共 68 次实际调用通过。不能把旧的任意非零状态当作凭据拒绝证据,也未声称逐个旧 traceback 都是相同文本。
语义与 CI 对齐
默认变化已明确:公开扫描会拒绝此前漏掉的无标签形状和正文绕过;这不是 default-off 功能,不用未启用分支推断隔离。新增贡献者说明保留原来的公开发布前检查、无凭据边界、修正后重试及权限范围;分割/转义只适用于无真实凭据的源码样例表示,不是公开秘密的许可。复用已有 credential 类别和形状归属,没有新协议枚举。
已提供的浏览器时序失败说明及旧 CI hold 原因仍未独立查明,作为 required=false 的诊断保留;本轮没有抓取、轮询或等待 CI。当前所需本地不变量有独立证据,历史远端诊断不等于本 PR 回归,也不赋予我撤销他人 review 或合并的权限。
我的整体评价 / Verdict
goal_achieved 仅指 issue #7712 的这个公开文件扫描修复。长程连续性为 preserved:拒绝到内容修正再到实际成功的路径可用,扫描不写 registry,不增加状态维护、调度或反复确认;没有声称测得长程收益。用户体验为 improved:原有一次检查请求现在能在公开前暴露真实问题,普通安全路径零新增确认轮次,失败有明确内容修正和重试路径。
已检查 contract.py、CLI 检查入口及本次文档和示例变更,没有页面、布局或渲染呈现改动,视觉评审不适用。未运行原生 Windows、安装后的 App 或真实密钥验证;没有测得长程收益,也不以本次检查证明所有凭据形状或其他目的地策略。令牌形状由既有 public_safe_text 规则维护,公开文件扫描只复用该规则,并继续拥有本目的地的拒绝与示例引用政策。本 PR 不增加扫描器、配置、持久状态或权限,只扩展现有 credential 规则的必要前缀预筛选,并收紧不透明令牌内部的示例豁免。这是范围和成本相称的既有规则复用,局部收紧豁免已完成;没有证据要求新增抽象、界面或把整个 #5136 迁移作为当前修复前置。保留上述红色诊断及跨平台未测范围,评审结论与旧 review closeout、合并准备和维护者授权分别处理。
English verdict: APPROVE at e17c66ac36dbab273f46e600edebc051e61aaf45. The public-scan fix and prior bypass are independently validated; residual diagnostics and platform limits remain disclosed.
Goal And Delivered Outcome
A repository-publication gate that reports a live-looking provider credential as public-safe can leak that credential to GitHub or CI artifacts; after this change
loopx check --scan-path— the scancanary premergeruns as a blocking check and the oneCONTRIBUTING.mdtells contributors to run before publishing — rejects unlabeled GitHub, Slack, npm, PyPI, Stripe, Google, AWS and JWT credential shapes instead of certifying them clean.Outcome basis / optional anchor: observed defect reproduced through the real CLI at upstream
main2f544f969; the parent owner split is tracked by [Architecture]: two modules both claim to own "private-looking text" #5136, and the sibling-module changes in [Bug]: the builtin public-safe-outbound scan certifies GitHub, AWS, Slack, Google, npm, PyPI and Stripe credentials as public-safe #7635 / fix(capability): detect unlabeled provider tokens in the outbound scan #7636 explicitly leftloopx/contract.pyuntouched.Goal/source and gap:
LEAK_RULES["credential"]inloopx/contract.pykept its own stale alternation, which only recognized credentials that carried atoken=/password=/Authorization:/Bearerlabel. Unlabeled provider tokens therefore passed. The canonical public-safety ownerloopx/public_safe_text.pyalready carriesPROVIDER_TOKEN_SHAPE_PATTERN_SOURCE, which fix(capability): detect unlabeled provider tokens in the outbound scan #7636 made the capability scanner consume, but the publication gate still had a narrower private copy.Observable before → after, with the validation row that proves it: a file containing a synthetic GitHub PAT (GitHub's public documentation example, not a live credential) scanned
ok: true, exit 0,public boundary scan cleanat base; at this head the same command reports onecredentialerror,ok: false, exit 1. See thereal_entrypointandregression_parityrows.Issue/task and intended base: Closes [Bug]: the public-boundary publication gate in loopx check certifies unlabeled provider credentials as public-safe #7712. Intended base:
loopx-project/loopxmainat682080047(rebased).Author Declaration
AI disclosure: this change was drafted with AI assistance at my request, under my direction and review.
Implemented against
Specification and revision: [Bug]: the public-boundary publication gate in loopx check certifies unlabeled provider credentials as public-safe #7712 (opened by the same operator from the base reproduction), the parent architecture direction in [Architecture]: two modules both claim to own "private-looking text" #5136 at the time of writing, and the documented gate behaviour in
CONTRIBUTING.md(loopx check --scan-path docs/ --scan-path examples/) andloopx/public_safe_text.pyat2f544f969.Criteria:
LEAK_RULES["credential"]in loopx/contract.pypytest tests/test_contract_credential_pattern_precision.py; real CLI probePROVIDER_TOKEN_SHAPE_PATTERN_SOURCEimport from loopx/public_safe_text.py_credential_match_is_referencekeeps ENV, Basic-template and placeholder handling; unlabeled matches use only the exact AWS documented example exemption\u0061escapes in one fixturescan_public_boundary→ok: true, 0 hits, 87 reference hitsLEAK_RULES["credential"].required_literalsin loopx/contract.pytest_every_authoritative_leak_pattern_has_a_matching_prefiltercasescontributingworkflow; ran the real CLI at base and head with an isolated home/registry so local runtime state could not influence the result; ran the focused suite, ruff, the example smoke andcanary premerge. I deliberately did not widen thelocal_private_pathrule (208 pre-existing false positives across docs/examples) or add a placeholder heuristic; the repository already has a recorded convention of splitting provider-shaped literals, which keeps every test exercising the scan.Review Follow-up
Corrected the P2 reference-classification gap from the prior head. Unlabeled provider tokens are exempted only when the whole match is the AWS access-key id published in the official documentation;
dummyorexampleinside an opaque token body no longer downgrades a credential to a reference.Added unit and real
loopx check --scan-pathregressions for two synthetic provider shapes: a GitHub PAT containingdummyand an npm token containingexample. Both now return exit 1 with acredentialerror.Rebased onto
mainat682080047. The focused precision suite is44 passed; the adjacent contract/prefilter/chat batch is134 passed, 4 failed, with only the pre-existing Windows platform failures described above.Fixed the false DCO failure by rewriting the three commit messages from CRLF to LF. The commit trees are byte-identical to
05c8d665696c3e0f0139e8e4593c77b91392fc52, author and commit timestamps were preserved, and GitHub now reportsSign-off: success.Scope And Continuation
Completed scope and remaining work: complete within this scope — the publication gate now recognizes the same provider shapes as the canonical owner and the capability scanner, and the repository stays green under its own scan. The broader consolidation described in [Architecture]: two modules both claim to own "private-looking text" #5136 (one classification owner for private-looking text) remains a separate architecture task and is not attempted here.
Slice boundary / successor: N/A — the defect is closed at the gate that caused it. If maintainers want
LEAK_RULESto import the whole rule set instead of only the provider shape, that belongs to [Architecture]: two modules both claim to own "private-looking text" #5136 rather than to this fix.Validation
e17c66ac36dbab273f46e600edebc051e61aaf45(three commits rebased onto682080047f4548d0266111f5e924512f550df9d9)staticpasseduvx --from "ruff>=0.12,<0.16" ruff check loopx/contract.py tests/test_contract_credential_pattern_precision.py tests/test_chat_activity.py examples/control_plane/goal-artifact-lifecycle-projection-smoke.py→ All checks passed.unitpassedpytest tests/test_contract_credential_pattern_precision.py→ 44 passed; includes 8 parametrized provider shapes, the canonical-owner pin, a short-lookalike negative case and two literal-token regressions. The combined precision/prefilter/chat run is134 passed, 4 failed; the four are the same Windows symlink/CRLF harness failures at base.regression_paritypassedreal_entrypointpassed2f544f969:loopx check --scan-path <file with a synthetic GitHub PAT>→ok: true, exit 0,public boundary scan clean. Head: same command →ok: false, exit 1, onecredentialerror. Isolated home/registry; no real credential used.integrationpassedloopx canary premerge --from-git-diff --git-diff-base upstream/mainat the tested revision →status: passed, 11/11 selected checks, public boundary 0 failures, merge gate passed. The exact rebased head was also exercised through the documented CLI and focused suite. Two catalog canaries initially failed on this Windows host only because npm dev dependencies were missing and the console codec was cp936; both reproduce identically on the untouched base and pass afternpm ci --ignore-scriptsplus UTF-8 mode.manualpassedscan_public_boundary→ok: true, zero unresolved hits; explicit credential references remain classified rather than deleted.real_backendnot_applicable44 passed. The contract/prefilter/chat batch is134 passed, 4 failed; the failures are the same Windows symlink-privilege and CRLF line-number cases at base, and are unrelated to this rule. The lifecycle-projection example and chat caller still exercise the same scan. I did not run the TypeScript package suites because no TypeScript file is touched.Frontend / Visual Evidence
Type of Change
LoopX Area
Technical Direction
Shared-authority RFC fixture impact
Boundary Checklist
.loopx/,.codex/goals/, and liveACTIVE_GOAL_STATE.md).python3 scripts/check_rfc_bilingual.py --base origin/main --head HEADpasses, or no paired RFC changed.none.Signed-off-bytrailer (git commit -s).