fix(public-safety): recognize drive-qualified, UNC and /data paths and quoted secrets - #4426
Conversation
…d quoted secrets The shared local-path rule only treated `X:\Users` and `X:\Documents and Settings` as local paths, so any other drive-qualified path, every UNC share and `/data/...` roots passed the public boundary. The secret rule required the key to touch its separator, so JSON-shaped and quoted forms such as `"token": "..."` and `access_key='...'` were never classified. Both rules are widened. The lookbehind still excludes URL schemes, clock times and ratios; a boundary test pins those shapes on both sides. Behavior change, disclosed: a drive-qualified path-shaped opaque ref is now reported as an absolute local path before the opaque-reference shape check. The value was rejected before and is rejected now; only the diagnostic differs. The turn-executor contract records the intended diagnostic per shape. Split out of loopx-project#4360, which only needs the rules that already exist. Signed-off-by: song <liusongstep@gmail.com>
huangruiteng
left a comment
There was a problem hiding this comment.
动机
公共安全面(public-safe)判定是 LoopX 对外文字的唯一门禁:PR 正文、release body、研究包、host 结果回执都要先过它。原来 LOCAL_PATH_SURFACE_PATTERN 只认 X:\Users、X:\Documents and Settings 和一小撮 POSIX 根目录,SECRET_LIKE_SURFACE_PATTERN 又要求键名紧贴分隔符,所以 Windows 盘符路径(C:\build\...、C:/workspace/...)、UNC 共享(\\server\share\...)、/data/... 以及 JSON 形状的凭据("token": "..."、access_key='...')都能被判成 public-safe。我在 origin/main(c979cf11c)上实测确认:这 5 类值全部被接受,属真实的发布边界缺口,不是文档问题。
改动思路
修在唯一 owner 里,而不是给调用方加规则:loopx/control_plane/runtime/public_safety.py 被 82 个模块导入,扩宽它一次即可覆盖所有发布方;新增第二个校验器或按调用方放宽都会重新制造仓库已经消除过一次的漂移。负向 lookbehind (?<![:/A-Za-z0-9]) 被保留,用来继续排除 https://、s3://、时钟时间和比例(12:30/45、ratio 3:4/5)。测试写成一个薄的双向边界文件,并把 turn host-result 的期望参数化,区分"同一个拒绝、不同诊断"的排序契约。
具体改动
public_safety.py:11LOCAL_PATH_SURFACE_PATTERN:POSIX 根目录加/data;Windows 分支由"仅 Users / Documents and Settings"扩为"任意盘符路径";新增 UNC 分支\\server\share\...。public_safety.py:22SECRET_LIKE_SURFACE_PATTERN:键名与值各允许一个可选引号,于是"token": "..."、access_key='...'、sk = '...'被归类;未加引号的旧形态保持被拒。- 新增
tests/control_plane/test_public_safety_path_shapes.py(77 行):6 个必须被拒的私密形状、8 个必须被接受的公开形状(URL/s3/时间/比例/相对路径/普通散文),外加 1 个诊断顺序契约。 tests/test_loopx_turn_executor.py:737:把"路径形状的 opaque ref"从单一期望改成按字段给期望——C:/workspace/private/worker.json现在由路径规则先命中,file:/tmp/...仍走 opaque 规则。
对主干的风险
- 扩宽分类器的主要风险是误报:一旦某段合法公开文本含有引号包起来的
"token": "rotation"之类片段,发布会被 fail-closed 拦住。 - 次生风险是"第二个 owner":
packages/dsh-loopx-plugin/src/observer.ts:72-84另有一份LOCAL_PATH_SURFACES/SECRET_LIKE_SURFACES副本,本 PR 只改了 Python 侧,两份规则现在对新形状不一致,且没有任何测试把 TS 列表绑到共享语料。这属 P2、不阻塞本 PR,但需要显式收口(见下)。 - 影响面有界:仅一个常量文件,回滚是单文件回滚,不涉及持久化状态或 schema。
验证(exact head 30b73424d,均在真实模块上跑):
pytest tests/control_plane/test_public_safety_path_shapes.py tests/test_loopx_turn_executor.py -q→ 74 passed。- 覆盖全部 public_safety 消费者的聚焦集(9 个文件,含
test_public_safe_text_owner_parity.py)→ 316 passed。 - 自建 base/head 对照探针:5 类私密形状 base 接受→head 拒绝;
https://example.org/data/report、s3://bucket/key、12:30/45、ratio 3:4/5 done、docs/evidence.md、access key rotation guide两个版本都接受。 - 远端检查:GitHub 上该 head 的 checks 全绿(pytest、stage2c、windows-powershell、postgresql-authority、merge-gate 等)。
我的整体评价
方向正确、体量合适、验证双向:它在正确的 owner 上做了一次外科式扩宽,并补齐了原来缺失的负向边界,没有引入新模块、开关或状态。给出 APPROVE。
P2(不阻塞,建议同批次或紧随其后处理):把新增的 UNC/盘符//data/带引号凭据形状并入 tests/fixtures/public_safe_text_corpus.json,让四 owner 的 parity 测试一起覆盖,并同步 packages/dsh-loopx-plugin/src/observer.ts 的列表(或明确写成"观察器更窄规则"并登记类型化 follow-up),否则同一规则的两个 owner 会继续靠人工对齐。
English verdict: APPROVE at exact head 30b7342. The widening lives in the single shared owner (loopx/control_plane/runtime/public_safety.py) and I reproduced the gap on origin/main (UNC, drive-qualified, /data and quoted-JSON credential shapes were accepted) and the fix on this head (all five rejected, while https://, s3://, clock times, ratios, relative paths and prose stay accepted); focused runs are 74 passed plus 316 passed across the public-safety consumers and remote checks are green. One P2, non-blocking: packages/dsh-loopx-plugin/src/observer.ts:72-84 keeps a hand-copied pattern list that now diverges from the Python owner, so add the new shapes to the shared parity corpus and align or explicitly bound that second owner.
Behavior
Widens the two shared public-safety surface rules in
loopx/control_plane/runtime/public_safety.py:LOCAL_PATH_SURFACE_PATTERN: every drive-qualified path (X:\...,X:/...), UNC shares (\\server\share\...) and/data/...roots are local paths. Previously onlyX:\UsersandX:\Documents and Settingswere.SECRET_LIKE_SURFACE_PATTERN: quoted keys and values are classified ("token": "...",access_key='...',sk = '...'). Previously the key had to touch its separator, so JSON-shaped assignments were never classified.The existing lookbehind still excludes URL schemes (
https://,s3://), clock times and ratios; a boundary test pins those on both sides.Disclosed behavior change
A drive-qualified, path-shaped opaque reference is now reported as
contains an absolute local pathbefore the opaque-reference shape check runs. The value was rejected before and is rejected now; only which diagnostic wins differs.tests/test_loopx_turn_executor.pyrecords the intended diagnostic per shape. This is a deliberate tightening, not parity.Split out of #4360, which only needs the rules that already exist. Shared consumers: turn-executor result validation, Goal projections, reliability diagnostics and every
public_safe_compact_textcaller.Validation
tests/control_plane/test_public_safety_path_shapes.py(new, 20 cases),tests/test_loopx_turn_executor.py,test_public_safe_text_owner_parity.py,test_public_safe_decision_replay.py: 158 passed.Signed-off, single commit on top of
upstream/main(cd9cfa6d4).