Skip to content

fix(#21-#24) 多方案-sol-d:全面修复 4 个 issue - #28

Closed
Nicholas023 wants to merge 4 commits into
mainfrom
sol-d
Closed

Nicholas023 wants to merge 4 commits into
mainfrom
sol-d

Conversation

@Nicholas023

Copy link
Copy Markdown
Owner

fix(#21-#24) 多方案-sol-d:全面修复 4 个 issue

本 PR 为多方案并行中的 sol-d 方案:6 个文件,+149 / -31。四个 issue 各一个提交,可独立审阅。

按 issue 拆解(文件:行 = 修复点)

#21 model-provider.js:js-yaml 加载失败被静默吞掉

  • 位置:src/model-provider.js:63-80(loadProfileLlmConfig 的 catch 块)
  • 修复:catch 捕获 error 并 console.error 输出真实失败原因(junction 损坏 / 安装缺失可诊断),return null 契约绝不改变——scripts/switch-model-e2e.mjs:62-70 依赖 check('解析出端点', !!ep) + ep?.keyEnv ?? '' 安全链,改成抛异常会破坏调用方。
  • 实证:e2e-switch 中「解析出端点」「端点命中用户配置路由」两断言仍 ✔。

#22 e2e:key 缺失空等 180s + 泄露断言嵌套静默跳过

  • scripts/engine-e2e-smoke.mjs:108-130:key 未解析(undefined)时不再构造 OCR_LLM_TOKEN: key(字面量 "undefined")并 spawn 引擎空等——短路跳过引擎调用,check 输出「跳过引擎调用(key 缺失)」,skipped 计数独立于 failures,末尾文案显式区分。
  • scripts/sensitive-e2e-smoke.mjs:96-125:「引擎输出未含 .env 内容」断言从 if (candidates.length > 0) 嵌套中提出——reviewOnce 静默失败(报告未落盘)时断言仍执行,杜绝「评审失败 → 整段跳过 → 假绿」;text 非字符串时按空串处理,断言仍有可观察结论。

#23 set-config:report_dir 写前校验 + engine_bin setuid + 权限声明对齐(深度方案)

  • 深度方案(代码级校验 + 权限声明双落实),理由:scope 承诺必须与可观察行为一致(不自述、看实现);report_dir 原样落盘后被 report.js 当报告根目录(mkdir -p 后写 .md),仅改声明文本挡不住提示注入把报告写到任意目录。
  • src/set-config-tool.js writeReport 前校验:展开 ~ → resolve 绝对路径 → 必须在用户 home ∪ 会话工作目录内(允许根 = 用户可控位置;相对路径解析后自然落在会话目录)→ 已存在的最长祖先 realpath 解析符号链接后不得越出(目录遍历逃逸检查)。
  • 允许尚未创建的目录(报告目录是待建目录,与 engine_bin「必须存在」语义不同)。
  • 失败只剔除该字段并回显原因(与 engine_bin 同口径),整单只剩被拒字段才整体拒绝。
  • engine_bin 补 setuid/setgid 位检查(可执行文件 + 特权位 = 经典提权面)。
  • dsh-plugin.json:fs.write / process.spawn / credentials.read 三处 scope+reason 补齐,与实现同口径。

#24 sensitive-list:正则误收/漏收 + markdown 注入

  • src/sensitive-list.js:48,54:tokens? 两条规则补词边界 (?=[._-]|$)——tokenizer-decoder.yml / my-api-tokenizer-decoder.yml 业务命名不再被 token 前缀误收;token.json / api_token / my-tokens / refresh_token_backup.json 命中不变。
  • src/sensitive-list.js:31,60:重叠归一——\.[^/]*secret 与 (secrets?|credentials?)(\.|\/|$) 合并为一条交替正则(并集语义,两侧命中面全保留:.asecret/.secretfile/.secrets-cache.txt/secrets.yml/credentials.json…)。
  • src/sensitive-list.js:40:证书扩展名锚定与 .env 模式对齐——(\.|$) → (\.[^/]+)?$(扩展名后只允许「一个点 + 非斜杠后缀」至路径段结尾;server.key.bak/ 目录形态不再误收)。
  • src/sensitive-list.js:120:markdown 点名清洗类补 ~ # &(删除线 / 标题 / 实体引用注入)。

门禁结果(sol-d worktree 实测)

检查 结果 说明
npm run check ✔ exit 0 node --check 全量 src
npm run unit ✔ exit 0 unit-smoke + file-config-smoke
npm run selfcheck ✔ exit 0 结构 / 客户端包 / 单测 / 任务 API
e2e-engine 自然结束 exit 1 唯一失败 = 工作树无 bin/codecheck.exe(环境);✔ key 解析 / git 基线就绪
e2e-sensitive 自然结束 exit 1 唯一失败 = 引擎缺失报告未落盘(环境);✔ 敏感点名断言 4/4、泄露断言照常执行
e2e-switch 自然结束 exit 1 失败 = 引擎缺失 ENOENT + Ollama 无 key(环境);✔ 解析出端点 / 路由命中(#21 契约未破坏)

e2e 三项均 5 分钟内自然结束、无挂死、无新增异常形态;失败项全部为环境性(无引擎二进制 / 无对应 key),符合任务书允许形态。

已知取舍(有意为之)

  • engine_bin 刻意不做符号链接校验:brew / 系统包管理器合法 symlink 安装会被误拒;校验定位是提示性防线,dsh-plugin.json 声明与实现同口径(未承诺非符号链接)。
  • report_dir 允许根 = home ∪ 会话工作目录(而非仅 home):会话目录是用户可控且常见合法目标(如 D: 盘工作树里配置报告目录),strict home-only 会拒绝合法配置。
  • 敏感规则保守收紧:只修 issue 点名的误收/漏收形态,不扩大黑名单词表。
  • 未触碰 engine/ Go 源码与生产目录;所有修改限于本工作树。

…l 契约

js-yaml 依赖损坏(残损 junction/安装缺失)此前静默吞掉——路由表空 → 评审 0.0s 失败且文案只报端点未配置。catch 现在输出真实错误原因;返回值契约不变(switch-model-e2e 依赖解析失败=null 不抛)。
engine-e2e:key 未解析时不再以字面量 undefined 构造 OCR_LLM_TOKEN 并 spawn 空等——短路跳过引擎调用并显式 check(skipped 计入,末文案区分)。sensitive-e2e:引擎输出泄露断言从 candidates.length>0 嵌套提出来,reviewOnce 静默失败时断言照常执行(杜绝评审失败→整段跳过→假绿)。
report_dir:写入前展开 ~ 并 resolve 为绝对路径,必须位于用户 home 或会话工作目录下(允许根),已存在的最长祖先 realpath 解析符号链接后不得越出该范围(目录遍历逃逸检查);允许尚未创建的目录(报告目录是待建目录);校验失败只剔除该字段并回显原因,与 engine_bin 同口径(整单只剩被拒字段才整体拒绝)。
engine_bin:补 setuid/setgid 位检查(可执行文件+特权位=经典提权面,命中即拒)。刻意不做符号链接校验:brew/系统包管理器合法 symlink 安装会误拒;dsh-plugin.json 的 scope 声明与实现保持同口径(未承诺非符号链接)。
dsh-plugin.json:fs.write / process.spawn / credentials.read 三处 scope 与 reason 补齐与本提交实现一致的安全承诺文本。
1) tokens? 两条规则补词边界 (?=[._-]|$):tokenizer-decoder.yml / my-api-tokenizer-decoder.yml 等业务命名不再被误收,token.json / api_token / my-tokens / refresh_token_backup.json 命中不变。
2) 重叠正则归一:点开头段含 secret(.asecret/.secretfile/.secrets-cache.txt)与 secrets/credentials 词段+分隔符(secrets.yml/credentials.json/secrets/)合并为一条交替正则,语义=两者并集,全部原有命中面保留。
3) 证书扩展名锚定与 .env 模式对齐:(\\.|$) 改为 (\\.[^/]+)?$,敏感扩展名后只允许一个点+非斜杠后缀直到路径段结尾(server.key.bak/ 目录形态不再误收)。
4) markdown 点名清洗类补 ~ # &(删除线/标题/实体引用注入不再改报告格式)。
回归:unit-smoke 与 e2e-sensitive 的敏感命中/不命中断言逐项验证保持。
@Nicholas023

Copy link
Copy Markdown
Owner Author

整合 PR #29 已吸收本方案精华并合并(lead 实测比对后取舍)。本 PR 关闭存档,diff 仍可通过本页查看。

@Nicholas023
Nicholas023 deleted the sol-d branch October 20, 2026 07:18
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