Skip to content

test: trigger multi-review CI v3#85

Closed
Svtter wants to merge 1 commit into
mainfrom
test/multi-review-v3
Closed

test: trigger multi-review CI v3#85
Svtter wants to merge 1 commit into
mainfrom
test/multi-review-v3

Conversation

@Svtter
Copy link
Copy Markdown
Collaborator

@Svtter Svtter commented May 19, 2026

Summary

Test plan

  • Multi-Review CI triggers and runs successfully
  • Synthesized review comment posted on this PR

🤖 Generated with Claude Code

@github-actions
Copy link
Copy Markdown

可合并

Summary

此 PR 为零文件变更的测试 PR,仅用于验证 multi-review CI 工作流,不涉及任何代码改动。

  • 阻塞项:无
  • 建议项:无

New%20session%20-%202026-05-19T12%3A23%3A29.887Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

无遗漏。

该 PR 是纯粹的 CI 测试 PR(0 个文件变更,0 行新增/删除),目的是验证 multi-review workflow 的触发与执行。PR 标题和描述中没有任何功能实现需求,也不存在 linked issue 提供 spec。因此不存在遗漏实现的问题。

New%20session%20-%202026-05-19T12%3A23%3A31.376Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

架构合理

This PR contains zero file changes (0 additions, 0 deletions across 0 files). It is purely a CI test PR to verify the multi-review workflow. There are no architecture concerns to report.

阻塞项:无
建议项:无

New%20session%20-%202026-05-19T12%3A23%3A57.329Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

无遗漏

该 PR 为 CI 测试 PR(标题 "test: trigger multi-review CI v3"),无 linked issues,PR 描述明确说明仅用于验证 multi-review workflow 触发和执行。变更仅为 8 行调试日志增强(检查 run-opencode.sh 是否存在、打印模型信息、打印 reviewer error 输出),不存在任何需要实现的功能 spec,因此无遗漏。

New%20session%20-%202026-05-19T12%3A26%3A42.977Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

可合并

审查总结

此 PR 添加了 multi-review 工作流的调试日志,改动集中在 multi-review/run-multi-review.py

  1. 运行脚本存在性检查 — 在调用 run-opencode.sh 前检查文件是否存在,不存在时提前返回 1,避免后续运行时报出混淆性错误。
  2. 日志输出 — 打印使用的脚本路径和模型名称,便于调试跟踪。
  3. 失败 reviewer 输出 — 当 reviewer 状态为 error 时,打印其输出的最后 500 字符,帮助排查失败原因。

改动风格与已有代码一致、无安全风险、无性能问题。

阻塞项:无

建议项:无

New%20session%20-%202026-05-19T12%3A26%3A43.010Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

架构合理

此 PR 在 multi-review/run-multi-review.py 中添加了 8 行防御性检查和调试日志:

  • run-opencode.sh 存在性检查(提前 return 1,避免后续混乱的错误信息)
  • 运行时打印脚本路径和模型名称
  • reviewer 失败时输出最后 500 字符

所有改动局限在同一文件的 orchestration 层,未引入新的耦合、未破坏分层边界、未新增跨模块依赖。存在性检查的 early-return 模式与代码库中已有的 resolve_reviewers 配置检查一致,日志输出风格也与全文件使用的 print(..., file=sys.stderr) 一致。架构上无问题。

阻塞项:无
建议项:无

New%20session%20-%202026-05-19T12%3A27%3A20.919Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

已检查 PR 信息:

  • 标题: test: trigger multi-review CI v3
  • 描述: 测试 PR,用于验证 multi-review workflow 的触发和执行
  • 链接 Issues: 无
  • 变更: multi-review/run-multi-review.py 文件 +34/-2(3 个 commits)

结论: 无遗漏

该 PR 是一个纯 CI 测试 PR,不涉及任何功能实现需求。PR 标题和描述明确说明其目的是验证 multi-review workflow 是否正常触发和执行,而非实现新功能。

3 个 commits 的内容均为调试日志增强和 bug 修复(XDG cache 隔离),不存在任何 feature spec 需要对比验证,因此不存在遗漏实现的问题。

New%20session%20-%202026-05-19T12%3A32%3A50.674Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

可有条件合并

Summary

此 PR 对 multi-review/run-multi-review.py 做了 3 项改动:1) 为每个并行 reviewer 创建独立临时目录并设为 XDG_CACHE_HOME 以避免 SQLite 并发冲突;2) 在调用 run-opencode.sh 前增加存在性检查,缺失时提前 return 1;3) 在 reviewer 失败时打印其输出最后 500 字符,便于调试。整体改动质量良好,逻辑正确。

阻塞项

  • 潜在问题:run_reviewer 中调用 tempfile.mkdtemp() 后立即传入 _run_reviewer_inner,而 _run_reviewer_inner 内部如果提早 return(例如 remaining <= 0 的 timeout 分支),finally 块仍能清理临时目录,逻辑正确。但如果 _run_reviewer_inner 内部抛出异常且 run_reviewertry 块未捕获(比如 keyError),该异常会传播到 ThreadPoolExecutor 的 future,此时 finally 块(shutil.rmtree)不会执行,导致临时目录残留。虽然 ignore_errors=True 避免了删除时的错误,但未删除本身是目录泄漏。

    建议修复:用 try/finally 分别在 _run_reviewer_inner 外部和 _run_opencode 调用处兜底删除临时目录,或确保所有异常路径都进入 finally

建议项

  • Reviewer 失败时打印 output[-500:](末尾 500 字符),对于长输出中关键信息在开头的场景(如 traceback 开头、JSON parse error 行号),末尾可能不包含关键信息。可改为打印 output[:500] 或同时打印首尾。
  • import tempfile 作为标准库导入,位置合理。
  • 新增的 _run_reviewer_inner 函数签名较长(8 个参数),从可维护性角度可考虑后续折叠为 dataclass 或 TypedDict,当前改动量小,非阻塞。
  • 代码风格一致,与文件中已有 print(..., file=sys.stderr) 模式统一。

New%20session%20-%202026-05-19T12%3A32%3A52.064Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

架构合理

该 PR 在 multi-review/run-multi-review.py 中做了三项紧密相关的架构改进:(1) 提取 _run_reviewer_inner 将临时目录生命周期与 reviewer 执行逻辑分离;(2) 通过 XDG_CACHE_HOME 隔离解决并行 reviewer 的 SQLite 冲突;(3) 添加防御性脚本存在检查和调试日志。

所有改动局限在同一文件内,未引入跨模块依赖或循环引用。XRG 缓存隔离放置在 _run_opencode(基础设施/进程执行层),临时目录管理在 run_reviewer(编排层),分层清晰。workdir 参数使用可选默认值保持向后兼容。printf 调试风格和错误截断模式与已有代码一致。架构上无问题。

阻塞项:无
建议项:无

New%20session%20-%202026-05-19T12%3A33%3A35.264Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

无遗漏

该 PR 标题为 test: trigger multi-review CI v3,描述明确说明是用于验证 multi-review workflow 触发和执行的测试 PR。未链接任何 issue,不存在功能实现的 spec 或需求。实际变更为调试日志增强和 XDG 缓存隔离等运维改进,无 feature spec 可对照,因此不存在遗漏实现的问题。

New%20session%20-%202026-05-19T12%3A36%3A53.914Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

可有条件合并

总结

此 PR 对 multi-review/run-multi-review.py 做了三组改动:1) 为每个并行 reviewer 创建独立临时目录并通过 XDG_CACHE_HOME 隔离,避免 SQLite 并发冲突;2) run_opencode.sh 存在性检查及提前 return;3) 添加若干调试日志。整体改动方向正确,质量良好。

阻塞项

建议项

  1. output[-500:] 截断位置不合理 — 错误输出的关键信息(如 traceback 栈顶、JSON parse error 行号)通常在开头而非末尾,[-500:] 可能丢失有用信息。建议改为 output[:500] 或同时打印首尾各 250 字符。

  2. MODEL 调试日志的语义模糊 — 第 584 行 os.environ.get('MODEL', 'unknown') 打印的是进程级环境变量,而每个 reviewer 实际使用的模型是在 _run_opencode 中通过 env["MODEL"] = model 设置的 per-call 值。该日志仅反映全局默认值,对调试并行 reviewer 的模型分配没有帮助,反而可能造成混淆。建议删除此行或改为打印实际的 reviewer 模型列表。

New%20session%20-%202026-05-19T12%3A36%3A54.156Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

架构合理

此 PR 对 multi-review/run-multi-review.py 做了三组改动:(1) 提取 _run_reviewer_inner,将临时目录生命周期与 reviewer 执行逻辑分离;(2) 通过 XDG_CACHE_HOME 隔离解决并行 reviewer 的 SQLite 冲突;(3) 添加防御性脚本存在检查和调试日志。

所有改动局限在同一文件内,未引入新的跨模块依赖或循环引用。资源管理(run_reviewermkdtemp/rmtree)与业务逻辑(_run_reviewer_inner 中模型回退/超时处理)分离清晰。_run_opencode 新增可选 workdir 参数,默认值为 None,保持向后兼容。print(..., file=sys.stderr) 调试风格与全文件一致。整体分层和职责边界均被尊重。

阻塞项:无

建议项:无

New%20session%20-%202026-05-19T12%3A37%3A50.628Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

无遗漏。

该 PR 标题为 test: trigger multi-review CI v3,描述说明是纯测试 PR,用于验证 multi-review workflow 触发和执行。无关联的 linked issue,不存在功能实现的 spec 需要对照。

实际变更为 8 行调试日志增强和防御性检查(run-opencode.sh 存在性检查、XDG 缓存隔离修复 USE_GITHUB_TOKEN 默认值等),不涉及任何 feature 实现需求,因此不存在遗漏。

New%20session%20-%202026-05-19T12%3A39%3A30.113Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

可合并

审查总结

此 PR 在 multi-review/run-multi-review.py 中做了如下改动:1) 为每个并行 reviewer 创建独立临时目录,通过 XDG_CACHE_HOME 隔离以避免 SQLite 并发冲突;2) 将 USE_GITHUB_TOKEN"false" 改为 "true" 以防止 opencode OIDC crash;3) 新增 run-opencode.sh 存在性检查并在缺失时提前 return 1;4) 添加若干调试日志(脚本路径、模型名、error reviewer 输出尾段)。整体改动逻辑正确,资源管理(try/finally + shutil.rmtree)覆盖了正常和异常路径,无安全或性能问题。

阻塞项:无

建议项:

  1. output[-500:] 截取位置可优化(第 614 行)— 错误输出的关键信息(异常类型、traceback 头部、JSON 解析错误行号)通常在开头而非末尾。[-500:] 可能截取到较无用的下半部分。建议改为 output[:500],或当输出较长时同时保留头尾各 250 字符。
  2. workdir 参数名有歧义(第 192 行)— _run_opencodeworkdir 参数实际被用作 XDG_CACHE_HOME 的值,而非进程工作目录。命名不够直观,建议改为 cache_dir

New%20session%20-%202026-05-19T12%3A39%3A30.788Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

安全无虞

该 PR 为 CI 调试日志增强和并行 reviewer 缓存隔离改动,不涉及业务逻辑输入输出,代码变更范围有限。

分析说明:

  • _run_opencodeUSE_GITHUB_TOKEN"false" 改为 "true" 是有意为之的功能修复(避免 OIDC crash),该 token 在 CI 上下文中自带作用域限制,不属于新增敏感泄露;
  • tempfile.mkdtemp(prefix=f"opencode-review-{name}-")name 来自配置而非外部输入,且 mkdtemp 强制在系统临时目录创建,无路径穿越风险;
  • 所有 print(..., file=sys.stderr) 输出均为调试信息,无用户输入直接拼接;
  • run_script 路径硬编码、subprocess.run 参数为固定值,无命令注入面;
  • env = os.environ.copy() 传递敏感环境变量(如 GITHUB_TOKEN)属于已有行为,非本次引入;
  • 无外部网络请求、无数据库操作、无文件写入用户可控内容。

阻塞项:无

建议项:无

New%20session%20-%202026-05-19T12%3A40%3A32.296Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

架构合理

该 PR 对 multi-review/run-multi-review.py 做了三组改动:(1) 提取 _run_reviewer_inner,将临时目录生命周期与 reviewer 执行逻辑分离;(2) 通过 XDG_CACHE_HOME 隔离解决并行 reviewer 的 SQLite 冲突;(3) 添加防御性脚本存在检查和调试日志。

从架构角度看,这些改动尊重了现有的分层职责:_run_opencode(基础设施/进程执行层)新增可选 workdir 参数并设置 XDG_CACHE_HOMErun_reviewer(编排层)负责临时目录的创建和 try/finally 清理,_run_reviewer_inner(业务逻辑层)专注模型回退和超时处理。资源管理与业务逻辑分离清晰,是架构上的改进。

所有改动局限在同一文件,未引入跨模块依赖或循环引用。print(..., file=sys.stderr) 调试风格与全文件一致,防御性检查早期返回的模式也与已有代码风格统一。

阻塞项:无
建议项:无

New%20session%20-%202026-05-19T12%3A40%3A30.704Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

可合并

This PR enhances multi-review/run-multi-review.py with three improvements: (1) per-reviewer XDG_CACHE_HOME isolation via tempfile.mkdtemp + try/finally cleanup to avoid SQLite conflicts; (2) defensive run-opencode.sh existence check with early return; (3) debug logging for script path, model, and reviewer error output. The USE_GITHUB_TOKEN switch from "false" to "true" fixes an OIDC crash in the CI environment.

阻塞项:无

建议项:

  • _run_opencode 参数名 workdir(第 192 行)实际设置的是 XDG_CACHE_HOME 而非进程工作目录,命名可能引起歧义,建议改为 cache_dir
  • MODEL 调试日志(第 585 行)读取的是全局环境变量,而实际每个 reviewer 使用的模型在 _run_opencode 中通过 env["MODEL"] = model 逐调用设置。该日志反映的是配置层面的默认值,理解上需注意上下文。

New%20session%20-%202026-05-19T12%3A41%3A00.328Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

可合并

综合审查总结

本 PR 对 multi-review/run-multi-review.py 做了三组改进:(1) 为每个并行 reviewer 创建独立临时目录并通过 XDG_CACHE_HOME 隔离,避免 SQLite 并发冲突;(2) 添加 run-opencode.sh 存在性检查及提前 return;(3) 增加调试日志增强可观测性。USE_GITHUB_TOKEN"false" 改为 "true" 修复 CI 环境 OIDC crash。整体改动方向正确,逻辑清晰,资源管理(try/finally + shutil.rmtree)覆盖正常和异常路径。

阻塞项

一位 reviewer 提出 _run_reviewer_inner 异常传播到 ThreadPoolExecutorfinally 中的 shutil.rmtree 不会执行,此为误报——Python 的 try/finally 语义保证无论异常是否被捕获、是否传播,finally 块始终执行。所有其他 reviewer 均确认无阻塞项。

建议项

以下为不阻塞合并的改进建议:

  1. output[-500:] 截断方向不合理(多 reviewer 确认:quality、可合并 x3)— 错误输出的关键信息(traceback 栈顶、JSON parse error 行号)通常在开头而非末尾,[-500:] 可能丢失有用信息。建议改为 output[:500] 或同时打印首尾各 250 字符。

  2. MODEL 调试日志语义模糊(多 reviewer 确认:quality x2、可合并)— print(f"Model: {os.environ.get('MODEL', 'unknown')}") 读取的是进程级全局环境变量,而每个 reviewer 实际使用的模型在 _run_opencode 中通过 env["MODEL"] = model 按调用分别设置。在多模型场景下该日志值与实际 reviewer 使用的模型可能不符,建议删除此行或改为打印 reviewers 的模型列表。

  3. workdir 参数命名歧义(quality [codex] add review action with built-in defaults #2、可合并)— _run_opencodeworkdir 参数实际设置的是 XDG_CACHE_HOME 而非进程工作目录,建议改为 cache_dir

  4. _run_reviewer_inner 参数过多(可有条件合并)— 函数签名含 8 个参数,可考虑后续折叠为 dataclass 或 TypedDict 提升可维护性。

New%20session%20-%202026-05-19T12%3A41%3A44.408Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

Asserting permissions for user Svtter...
permission: admin
Adding reaction...
opencode session ses_1bfbe5b27ffeHhaV54kldg36D7
Fetching prompt data for PR...
Checking out local branch...
Sending message to opencode...
[12:41:45.482] INFO (#274): loop {
service: "session.prompt",
"session.id": "ses_1bfbe5b27ffeHhaV54kldg36D7",
step: 0,
}
[12:41:45.531] INFO (#288): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}
[12:41:45.612] INFO (#274): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}
�[0m
可合并

综合审查总结

本 PR 对 multi-review/run-multi-review.py 做了三组改进:(1) 为每个并行 reviewer 创建独立临时目录并通过 XDG_CACHE_HOME 隔离,避免 SQLite 并发冲突;(2) 添加 run-opencode.sh 存在性检查及提前 return;(3) 增加调试日志增强可观测性。USE_GITHUB_TOKEN"false" 改为 "true" 修复 CI 环境 OIDC crash。整体改动方向正确,逻辑清晰,资源管理(try/finally + shutil.rmtree)覆盖正常和异常路径。

阻塞项

一位 reviewer 提出 _run_reviewer_inner 异常传播到 ThreadPoolExecutorfinally 中的 shutil.rmtree 不会执行,此为误报——Python 的 try/finally 语义保证无论异常是否被捕获、是否传播,finally 块始终执行。所有其他 reviewer 均确认无阻塞项。

建议项

以下为不阻塞合并的改进建议:

  1. output[-500:] 截断方向不合理(多 reviewer 确认:quality、可合并 x3)— 错误输出的关键信息(traceback 栈顶、JSON parse error 行号)通常在开头而非末尾,[-500:] 可能丢失有用信息。建议改为 output[:500] 或同时打印首尾各 250 字符。

  2. MODEL 调试日志语义模糊(多 reviewer 确认:quality x2、可合并)— print(f"Model: {os.environ.get('MODEL', 'unknown')}") 读取的是进程级全局环境变量,而每个 reviewer 实际使用的模型在 _run_opencode 中通过 env["MODEL"] = model 按调用分别设置。在多模型场景下该日志值与实际 reviewer 使用的模型可能不符,建议删除此行或改为打印 reviewers 的模型列表。

  3. workdir 参数命名歧义(quality [codex] add review action with built-in defaults #2、可合并)— _run_opencodeworkdir 参数实际设置的是 XDG_CACHE_HOME 而非进程工作目录,建议改为 cache_dir

  4. _run_reviewer_inner 参数过多(可有条件合并)— 函数签名含 8 个参数,可考虑后续折叠为 dataclass 或 TypedDict 提升可维护性。
    �[0m
    [12:42:07.682] INFO (#274): loop {
    service: "session.prompt",
    "session.id": "ses_1bfbe5b27ffeHhaV54kldg36D7",
    step: 1,
    }
    [12:42:07.687] INFO (#274): exiting loop {
    service: "session.prompt",
    "session.id": "ses_1bfbe5b27ffeHhaV54kldg36D7",
    }
    Checking if branch is dirty...
    Creating comment...
    Removing reaction...


详细审查报告:

✅ security

Performing one time database migration, may take a few minutes...
sqlite-migration:done
Database migration complete.
Asserting permissions for user Svtter...
permission: admin
Adding reaction...
opencode session ses_1bfc063c6ffeIW1401hIHzRQ00
Fetching prompt data for PR...
Checking out local branch...
Sending message to opencode...
[12:39:32.962] INFO (#298): loop {
service: "session.prompt",
"session.id": "ses_1bfc063c6ffeIW1401hIHzRQ00",
step: 0,
}
[12:39:33.027] INFO (#311): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}
[12:39:33.138] INFO (#298): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}

�[91m�[1m| �[0m�[90m Shell �[0m{"command":"git diff main...HEAD","description":"Get diff of PR changes","workdir":"/home/runner/work/opencode-actions/opencode-actions"}
[12:39:35.824] INFO (#298): loop {
service: "session.prompt",
"session.id": "ses_1bfc063c6ffeIW1401hIHzRQ00",
step: 1,
}
[12:39:35.906] INFO (#298): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}

�[91m�[1m| �[0m�[90m Shell �[0m{"command":"git log --oneline -20","description":"Check recent git history","workdir":"/home/runner/work/opencode-actions/opencode-actions"}

�[91m�[1m| �[0m�[90m Shell �[0m{"command":"git branch -a","description":"List all branches","workdir":"/home/runner/work/opencode-actions/opencode-actions"}
[12:39:38.258] INFO (#298): loop {
service: "session.prompt",
"session.id": "ses_1bfc063c6ffeIW1401hIHzRQ00",
step: 2,
}
[12:39:38.330] INFO (#298): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}

�[91m�[1m| �[0m�[90m Shell �[0m{"command":"git diff 0040e7f HEAD -- multi-review/run-multi-review.py","description":"Get file diff of PR changes","workdir":"/home/runner/work/opencode-actions/opencode-actions"}
[12:39:44.126] INFO (#298): loop {
service: "session.prompt",
"session.id": "ses_1bfc063c6ffeIW1401hIHzRQ00",
step: 3,
}
[12:39:44.167] INFO (#298): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}
�[0m
安全无虞

本 PR 为 CI 测试 PR,对 multi-review/run-multi-review.py 的改动仅涉及调试日志增强和 XDG 缓存隔离,不引入安全风险。

分析要点:

  • 新增 tempfile.mkdtemp() 为每个 reviewer 创建独立临时目录,路径由标准库管理,不存在路径遍历风险
  • name 参数仅作为临时目录前缀使用,不会导致注入
  • subprocess.Popen 始终使用列表参数(无 shell=True),无命令注入
  • USE_GITHUB_TOKEN="true" 是 CI 环境下标准的 token 传递方式,且 GITHUB_TOKEN 作用域受限
  • run-opencode.sh 存在性检查属于防御性编程,避免执行不存在的脚本
  • 无新增外部依赖,无 SQL 操作,无用户输入参与 HTML/JS 渲染

阻塞项:无

建议项:无
�[0m
[12:40:12.615] INFO (#298): loop {
service: "session.prompt",
"session.id": "ses_1bfc063c6ffeIW1401hIHzRQ00",
step: 4,
}
[12:40:12.618] INFO (#298): exiting loop {
service: "session.prompt",
"session.id": "ses_1bfc063c6ffeIW1401hIHzRQ00",
}
Checking if branch is dirty...
Sending message to opencode...
[12:40:12.662] INFO (#5490): loop {
service: "session.prompt",
"session.id": "ses_1bfc063c6ffeIW1401hIHzRQ00",
step: 0,
}
[12:40:12.702] INFO (#5490): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}
安全无虞,CI测试PR无安全风险
�[0m
[12:40:14.221] INFO (#5490): loop {
service: "session.prompt",
"session.id": "ses_1bfc063c6ffeIW1401hIHzRQ00",
step: 1,
}
[12:40:14.224] INFO (#5490): exiting loop {
service: "session.prompt",
"session.id": "ses_1bfc063c6ffeIW1401hIHzRQ00",
}
Pushing to local branch...
Command failed with code 128: git push
remote: Permission to sun-praise/opencode-actions.git denied to github-actions[bot].
fatal: unable to access 'https://github.com/sun-praise/opencode-actions/': The requested URL returned error: 403
Creating comment...
Removing reaction...
::error::remote: Permission to sun-praise/opencode-actions.git denied to github-actions[bot].%0Afatal: unable to access 'https://github.com/sun-praise/opencode-actions/': The requested URL returned error: 403%0A
OpenCode attempt 1/3 failed, retrying in 15s...
Asserting permissions for user Svtter...
permission: admin
Adding reaction...
opencode session ses_1bfbf74d7ffev8gH0fMn7zrFvm
Fetching prompt data for PR...
Checking out local branch...
Sending message to opencode...
[12:40:33.371] INFO (#267): loop {
service: "session.prompt",
"session.id": "ses_1bfbf74d7ffev8gH0fMn7zrFvm",
step: 0,
}
[12:40:33.420] INFO (#281): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}
[12:40:33.511] INFO (#267): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}

�[91m�[1m| �[0m�[90m Shell �[0m{"command":"git diff HEAD~5..HEAD -- multi-review/run-multi-review.py 2>/dev/null || git fetch origin test/multi-review-v3 2>&1 && git diff origin/main...origin/test/multi-review-v3 -- multi-review/run-multi-review.py","description":"Get diff for PR changes","workdir":"/home/runner/work/opencode-actions/opencode-actions","timeout":30000}
[12:40:36.465] INFO (#267): loop {
service: "session.prompt",
"session.id": "ses_1bfbf74d7ffev8gH0fMn7zrFvm",
step: 1,
}
[12:40:36.505] INFO (#267): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}
�[0m
安全无虞

该 PR 为 CI 调试日志增强和并行 reviewer 缓存隔离改动,不涉及业务逻辑输入输出,代码变更范围有限。

分析说明:

  • _run_opencodeUSE_GITHUB_TOKEN"false" 改为 "true" 是有意为之的功能修复(避免 OIDC crash),该 token 在 CI 上下文中自带作用域限制,不属于新增敏感泄露;
  • tempfile.mkdtemp(prefix=f"opencode-review-{name}-")name 来自配置而非外部输入,且 mkdtemp 强制在系统临时目录创建,无路径穿越风险;
  • 所有 print(..., file=sys.stderr) 输出均为调试信息,无用户输入直接拼接;
  • run_script 路径硬编码、subprocess.run 参数为固定值,无命令注入面;
  • env = os.environ.copy() 传递敏感环境变量(如 GITHUB_TOKEN)属于已有行为,非本次引入;
  • 无外部网络请求、无数据库操作、无文件写入用户可控内容。

阻塞项:无

建议项:无
�[0m
[12:40:54.594] INFO (#267): loop {
service: "session.prompt",
"session.id": "ses_1bfbf74d7ffev8gH0fMn7zrFvm",
step: 2,
}
[12:40:54.599] INFO (#267): exiting loop {
service: "session.prompt",
"session.id": "ses_1bfbf74d7ffev8gH0fMn7zrFvm",
}
Checking if branch is dirty...
Creating comment...
Removing reaction...

✅ quality

Asserting permissions for user Svtter...
permission: admin
Adding reaction...
opencode session ses_1bfc06476ffeY13w5zzsh9gGH4
Fetching prompt data for PR...
Checking out local branch...
Sending message to opencode...
[12:39:32.493] INFO (#296): loop {
service: "session.prompt",
"session.id": "ses_1bfc06476ffeY13w5zzsh9gGH4",
step: 0,
}
[12:39:32.574] INFO (#304): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}
[12:39:32.857] INFO (#296): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}

�[91m�[1m| �[0m�[90m Shell �[0m{"command":"git fetch origin test/multi-review-v3 2>/dev/null; git diff origin/main...origin/test/multi-review-v3","description":"Get PR diff for review","workdir":"/home/runner/work/opencode-actions/opencode-actions"}
[12:39:35.957] INFO (#296): loop {
service: "session.prompt",
"session.id": "ses_1bfc06476ffeY13w5zzsh9gGH4",
step: 1,
}
[12:39:36.013] INFO (#296): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}

�[91m�[1m| �[0m�[90m Shell �[0m{"command":"git fetch origin test/multi-review-v3 2>&1 && git diff HEAD...FETCH_HEAD -- multi-review/run-multi-review.py","description":"Fetch PR branch and show diff","workdir":"/home/runner/work/opencode-actions/opencode-actions"}
[12:39:38.530] INFO (#296): loop {
service: "session.prompt",
"session.id": "ses_1bfc06476ffeY13w5zzsh9gGH4",
step: 2,
}
[12:39:38.658] INFO (#296): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}

�[91m�[1m| �[0m�[90m Shell �[0m{"command":"git log --oneline HEAD..FETCH_HEAD","description":"List commits in PR branch","workdir":"/home/runner/work/opencode-actions/opencode-actions"}
[12:39:40.901] INFO (#296): loop {
service: "session.prompt",
"session.id": "ses_1bfc06476ffeY13w5zzsh9gGH4",
step: 3,
}
[12:39:40.939] INFO (#296): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}

�[91m�[1m| �[0m�[90m Shell �[0m{"command":"git branch -a --list '*/test/multi-review-v3' && git rev-parse HEAD && git rev-parse origin/test/multi-review-v3","description":"Check branch and commit references","workdir":"/home/runner/work/opencode-actions/opencode-actions"}
[12:39:43.644] INFO (#296): loop {
service: "session.prompt",
"session.id": "ses_1bfc06476ffeY13w5zzsh9gGH4",
step: 4,
}
[12:39:43.703] INFO (#296): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}

�[91m�[1m| �[0m�[90m Shell �[0m{"command":"git log --oneline -5","description":"Check recent commits","workdir":"/home/runner/work/opencode-actions/opencode-actions"}
[12:39:46.996] INFO (#296): loop {
service: "session.prompt",
"session.id": "ses_1bfc06476ffeY13w5zzsh9gGH4",
step: 5,
}
[12:39:47.032] INFO (#296): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}

�[91m�[1m| �[0m�[90m Shell �[0m{"command":"git log --oneline origin/main..HEAD -- multi-review/run-multi-review.py","description":"Check commits touching the file","workdir":"/home/runner/work/opencode-actions/opencode-actions"}
[12:39:49.261] INFO (#296): loop {
service: "session.prompt",
"session.id": "ses_1bfc06476ffeY13w5zzsh9gGH4",
step: 6,
}
[12:39:49.296] INFO (#296): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}

�[91m�[1m| �[0m�[90m Shell �[0m{"command":"git diff origin/main HEAD 2>/dev/null || git log --oneline --all | head -20","description":"Find merge base diff","workdir":"/home/runner/work/opencode-actions/opencode-actions"}
[12:39:51.195] INFO (#296): loop {
service: "session.prompt",
"session.id": "ses_1bfc06476ffeY13w5zzsh9gGH4",
step: 7,
}
[12:39:51.232] INFO (#296): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}

�[91m�[1m| �[0m�[90m Shell �[0m{"command":"git fetch origin main 2>&1 && git diff origin/main HEAD -- multi-review/run-multi-review.py","description":"Get diff against main branch","workdir":"/home/runner/work/opencode-actions/opencode-actions"}
[12:39:53.379] INFO (#296): loop {
service: "session.prompt",
"session.id": "ses_1bfc06476ffeY13w5zzsh9gGH4",
step: 8,
}
[12:39:53.413] INFO (#296): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}

�[96m�[1m| �[0m�[90m Read �[0m{"filePath":"/home/runner/work/opencode-actions/opencode-actions/multi-review/run-multi-review.py","offset":560,"limit":20}

�[96m�[1m| �[0m�[90m Read �[0m{"filePath":"/home/runner/work/opencode-actions/opencode-actions/multi-review/run-multi-review.py","offset":230,"limit":50}
[12:40:16.709] INFO (#296): loop {
service: "session.prompt",
"session.id": "ses_1bfc06476ffeY13w5zzsh9gGH4",
step: 9,
}
[12:40:16.744] INFO (#296): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}
�[0m

可合并

总结

此 PR 对 multi-review/run-multi-review.py 做了以下改进:

  • XDG_CACHE_HOME 隔离:为每个并行 reviewer 创建独立临时目录并通过环境变量传入 _run_opencode,避免 SQLite 并发冲突
  • _run_reviewer_inner 提取:将 reviewer 执行逻辑从 run_reviewer 中抽离,职责更清晰,try/finally 确保临时目录正确清理
  • USE_GITHUB_TOKEN=true:修复 opencode CLI 因缺少认证导致的 OIDC crash
  • 超时逻辑修复remaining = max(0, ...) 避免负数;model_timeout > 0 分支防止 timeout=0 时产生歧义;timeout 状态码由 "error" 改为 "timeout"
  • 防御性检查run-opencode.sh 存在性检查及提前 return 1;调试日志增强

阻塞项

建议项

  1. output[-500:] 截断方向可能丢失关键信息(第 611 行):错误输出的关键信息(traceback 栈顶、JSON parse error 行号等)通常在开头而非末尾。建议改为 output[:500] 或同时打印首尾各 250 字符。

  2. print(f"Model: {os.environ.get('MODEL', 'unknown')}") 日志可能产生误导(第 581 行):该日志读取的是进程级全局环境变量,而每个 reviewer 实际使用的模型在 _run_opencode 内通过 env["MODEL"] = model 按调用分别设置。在多模型场景下,这个日志值与实际 reviewer 使用的模型可能不符,建议删除或改为打印 reviewers 的模型列表。
    �[0m
    [12:40:29.051] INFO (#296): loop {
    service: "session.prompt",
    "session.id": "ses_1bfc06476ffeY13w5zzsh9gGH4",
    step: 10,
    }
    [12:40:29.055] INFO (#296): exiting loop {
    service: "session.prompt",
    "session.id": "ses_1bfc06476ffeY13w5zzsh9gGH4",
    }
    Checking if branch is dirty...
    Sending message to opencode...
    [12:40:29.092] INFO (#6909): loop {
    service: "session.prompt",
    "session.id": "ses_1bfc06476ffeY13w5zzsh9gGH4",
    step: 0,
    }
    [12:40:29.131] INFO (#6909): llm runtime selected {
    "llm.runtime": "ai-sdk",
    "llm.provider": "deepseek",
    "llm.model": "deepseek-v4-flash",
    }
    可合并,建议修正 error 截断和 MODEL 日志
    �[0m
    [12:40:42.377] INFO (#6909): loop {
    service: "session.prompt",
    "session.id": "ses_1bfc06476ffeY13w5zzsh9gGH4",
    step: 1,
    }
    [12:40:42.380] INFO (#6909): exiting loop {
    service: "session.prompt",
    "session.id": "ses_1bfc06476ffeY13w5zzsh9gGH4",
    }
    Pushing to local branch...
    Command failed with code 128: git push
    remote: Permission to sun-praise/opencode-actions.git denied to github-actions[bot].
    fatal: unable to access 'https://github.com/sun-praise/opencode-actions/': The requested URL returned error: 403
    Creating comment...
    Removing reaction...
    ::error::remote: Permission to sun-praise/opencode-actions.git denied to github-actions[bot].%0Afatal: unable to access 'https://github.com/sun-praise/opencode-actions/': The requested URL returned error: 403%0A
    OpenCode attempt 1/3 failed, retrying in 15s...
    Asserting permissions for user Svtter...
    permission: admin
    Adding reaction...
    opencode session ses_1bfbf0757ffee4qoH9qRhQMqIH
    Fetching prompt data for PR...
    Checking out local branch...
    Sending message to opencode...
    [12:41:01.612] INFO (#267): loop {
    service: "session.prompt",
    "session.id": "ses_1bfbf0757ffee4qoH9qRhQMqIH",
    step: 0,
    }
    [12:41:01.661] INFO (#281): llm runt
    ... (output truncated)

…e conflicts

Two issues prevented multi-review from running in CI:

1. USE_GITHUB_TOKEN=false caused opencode CLI to attempt OIDC auth as
   fallback, which crashed with "undefined is not an object (evaluating
   'k.rest')". Fixed by using USE_GITHUB_TOKEN=true.

2. Parallel opencode instances shared the same XDG_CACHE_HOME SQLite
   database. Fixed by creating isolated temp directories per reviewer.

Also adds defensive run_script existence check and error output logging
for easier debugging of future failures.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@Svtter Svtter force-pushed the test/multi-review-v3 branch from 64c6e8f to 7c95ff1 Compare May 19, 2026 12:45
@github-actions
Copy link
Copy Markdown

无遗漏

该 PR 标题为 test: trigger multi-review CI v3,描述明确说明是用于验证 multi-review workflow 触发和执行的纯测试 PR。无关联的 linked issue,不存在功能实现的 spec。

实际变更为 multi-review/run-multi-review.py 的调试日志增强和运维改进(XDG 缓存隔离、脚本存在性检查、USE_GITHUB_TOKEN 修正、超时逻辑优化等),均为测试和调试目的,无可对照的 feature 需求,因此不存在遗漏实现的问题。

New%20session%20-%202026-05-19T12%3A46%3A02.995Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

可合并

审查总结

此 PR 修复了 multi-review 工作流中的两个实际运行问题:并行 reviewer 的 SQLite 缓存冲突和 opencode CLI 因缺少 GITHUB_TOKEN 导致的 OIDC crash。改动包括提取 _run_reviewer_inner 函数,为每个并行 reviewer 分配独立临时目录作为 XDG_CACHE_HOME,并通过 try/finally 确保清理;脚本存在性检查的防御性编码;以及失败时打印输出首 500 字符的调试日志增强。

阻塞项

建议项

  1. _run_reviewer_inner 参数过多(8 个):后续可考虑折叠为 dataclass 或 TypedDict 提升可维护性,但当前改动量小,不阻塞合并。
  2. line 320 第二个 _run_opencode 调用(coordinator)未传 cache_dir:当前行为正确(coordinator 串行执行,无需 XDG 隔离),后续若 coordinator 也并行化需要注意补上此参数。

New%20session%20-%202026-05-19T12%3A46%3A02.950Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

安全无虞

本 PR 为 CI 调试与运维改进,不引入安全风险。USE_GITHUB_TOKEN="true" 允许 opencode CLI 使用环境中已有的 GITHUB_TOKEN 避免 OIDC crash(作用域受限,非新泄露)。tempfile.mkdtemp 创建隔离缓存目录,name 来自配置而非用户输入,无路径遍历。subprocess.run 始终使用列表参数(无 shell=True),无命令注入。所有新增 print 为调试日志,无外部输入拼接。无 SQL 操作、无 XSS 面、无新增依赖。

阻塞项:无

建议项:无

New%20session%20-%202026-05-19T12%3A46%3A46.971Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

架构合理

该 PR 在 multi-review/run-multi-review.py 中做了三项改动:

  1. 提取 _run_reviewer_inner,将临时目录生命周期与 reviewer 执行逻辑分离
  2. 通过 XDG_CACHE_HOME 隔离解决并行 reviewer 的 SQLite 冲突
  3. 添加防御性脚本存在检查和调试日志

从架构角度看:

  • 耦合度:未引入跨模块依赖,新增仅 import tempfile(标准库);_run_opencodecache_dir 为可选参数,保持向后兼容
  • 分层职责:提取 _run_reviewer_inner 是架构改进——run_reviewer 负责资源生命周期(try/finally + mkdtemp/rmtree),_run_reviewer_inner 专注模型回退和超时处理,分层清晰
  • 模块放置:所有改动局限在同一文件内,未新增文件或包
  • 一致性:防御性 early-return(第 581 行)与已有 resolve_reviewers 中配置缺失检查(第 112 行)模式一致;print(..., file=sys.stderr) 调试风格与全文件统一
  • 霰弹修改:无需改动其他文件即可完成此功能

阻塞项:无
建议项:无

New%20session%20-%202026-05-19T12%3A46%3A57.990Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

可合并

总结

此 PR 对 multi-review/run-multi-review.py 做了以下改进:

  • XDG_CACHE_HOME 隔离:为每个并行 reviewer 创建独立临时目录,避免 SQLite 并发冲突,try/finally 确保清理
  • 提取 _run_reviewer_inner:将 reviewer 执行逻辑从 run_reviewer 中抽离,职责更清晰
  • USE_GITHUB_TOKEN="true":修复 CI 环境中 opencode CLI 因缺少认证导致的 OIDC crash
  • 防御性检查run-opencode.sh 存在性检查及提前 return 1
  • 调试日志增强:reviewer error 时打印输出首 500 字符

阻塞项

一位 reviewer 提出的"异常传播到 ThreadPoolExecutor 时 finally 中的 shutil.rmtree 不会执行"为误报——Python 的 try/finally 语义保证无论异常是否被捕获、是否传播,finally 块始终在离开 try 块前执行。

建议项

  1. _run_reviewer_inner 参数过多(8 个):后续可考虑折叠为 dataclass 或 TypedDict 提升可维护性,当前改动合理,非阻塞。
  2. 第 320 行 coordinator 的 _run_opencode 调用未传 cache_dir:当前正确(coordinator 串行执行,无需 XDG 隔离),若后续 coordinator 也并行化需注意补上。

New%20session%20-%202026-05-19T12%3A47%3A04.508Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

可合并

综合审查总结

本 PR 在 multi-review/run-multi-review.py 中做了以下改进:为每个并行 reviewer 创建独立临时目录通过 XDG_CACHE_HOME 隔离以避免 SQLite 并发冲突;提取 _run_reviewer_inner 函数,资源管理与业务逻辑分离;USE_GITHUB_TOKEN"false" 改为 "true" 修复 OIDC crash;添加 run-opencode.sh 存在性检查及提前 return;增加调试日志。所有 reviewer 确认改动质量良好,资源管理覆盖正常和异常路径。

一位 reviewer 提出的"异常传播到 ThreadPoolExecutor 时 finally 中的 shutil.rmtree 不会执行"为误报——Python 的 try/finally 语义保证无论异常是否被捕获、是否传播,finally 块始终在离开 try 块前执行。该 reviewer 后续综合报告中也已确认此误报。所有其他 reviewer 均确认无阻塞项。

阻塞项

建议项

  1. output[-500:] 截断方向不合理(多 reviewer 确认:quality ×2,可合并 ×4)— 错误输出的关键信息(traceback 栈顶、JSON parse error 行号)通常在开头而非末尾,[-500:] 可能丢失有用信息。建议改为 output[:500] 或同时打印首尾各 250 字符。

  2. MODEL 调试日志语义模糊(多 reviewer 确认:quality ×2,可合并 ×2)— print(f"Model: {os.environ.get('MODEL', 'unknown')}") 读取的是进程级全局环境变量,而每个 reviewer 实际使用的模型在 _run_opencode 中通过 env["MODEL"] = model 按调用分别设置。建议删除此行或改为打印 reviewers 的模型列表。

  3. workdir 参数命名歧义(可合并 ×2)— _run_opencodeworkdir 参数实际设置的是 XDG_CACHE_HOME 而非进程工作目录,建议改为 cache_dir

  4. _run_reviewer_inner 参数过多(quality,可有条件合并)— 函数签名含 8 个参数,可考虑后续折叠为 dataclass 或 TypedDict 提升可维护性,当前非阻塞。

  5. coordinator 未传 cache_dir(可合并 ×2)— 第 320 行 coordinator 的 _run_opencode 调用未传 cache_dir,当前串行执行无问题,后续若 coordinator 也并行化需注意补上。

New%20session%20-%202026-05-19T12%3A47%3A32.083Z
opencode session  |  github run

@github-actions
Copy link
Copy Markdown

Asserting permissions for user Svtter...
permission: admin
Adding reaction...
opencode session ses_1bfb90d0dffe5izMP2bKV6bXul
Fetching prompt data for PR...
Checking out local branch...
Sending message to opencode...
[12:47:33.840] INFO (#276): loop {
service: "session.prompt",
"session.id": "ses_1bfb90d0dffe5izMP2bKV6bXul",
step: 0,
}
[12:47:33.885] INFO (#290): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}
[12:47:33.967] INFO (#276): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}
�[0m
可合并

综合审查总结

本 PR 在 multi-review/run-multi-review.py 中做了以下改进:为每个并行 reviewer 创建独立临时目录通过 XDG_CACHE_HOME 隔离以避免 SQLite 并发冲突;提取 _run_reviewer_inner 函数,资源管理与业务逻辑分离;USE_GITHUB_TOKEN"false" 改为 "true" 修复 OIDC crash;添加 run-opencode.sh 存在性检查及提前 return;增加调试日志。所有 reviewer 确认改动质量良好,资源管理覆盖正常和异常路径。

一位 reviewer 提出的"异常传播到 ThreadPoolExecutor 时 finally 中的 shutil.rmtree 不会执行"为误报——Python 的 try/finally 语义保证无论异常是否被捕获、是否传播,finally 块始终在离开 try 块前执行。该 reviewer 后续综合报告中也已确认此误报。所有其他 reviewer 均确认无阻塞项。

阻塞项

建议项

  1. output[-500:] 截断方向不合理(多 reviewer 确认:quality ×2,可合并 ×4)— 错误输出的关键信息(traceback 栈顶、JSON parse error 行号)通常在开头而非末尾,[-500:] 可能丢失有用信息。建议改为 output[:500] 或同时打印首尾各 250 字符。

  2. MODEL 调试日志语义模糊(多 reviewer 确认:quality ×2,可合并 ×2)— print(f"Model: {os.environ.get('MODEL', 'unknown')}") 读取的是进程级全局环境变量,而每个 reviewer 实际使用的模型在 _run_opencode 中通过 env["MODEL"] = model 按调用分别设置。建议删除此行或改为打印 reviewers 的模型列表。

  3. workdir 参数命名歧义(可合并 ×2)— _run_opencodeworkdir 参数实际设置的是 XDG_CACHE_HOME 而非进程工作目录,建议改为 cache_dir

  4. _run_reviewer_inner 参数过多(quality,可有条件合并)— 函数签名含 8 个参数,可考虑后续折叠为 dataclass 或 TypedDict 提升可维护性,当前非阻塞。

  5. coordinator 未传 cache_dir(可合并 ×2)— 第 320 行 coordinator 的 _run_opencode 调用未传 cache_dir,当前串行执行无问题,后续若 coordinator 也并行化需注意补上。
    �[0m
    [12:47:50.699] INFO (#276): loop {
    service: "session.prompt",
    "session.id": "ses_1bfb90d0dffe5izMP2bKV6bXul",
    step: 1,
    }
    [12:47:50.702] INFO (#276): exiting loop {
    service: "session.prompt",
    "session.id": "ses_1bfb90d0dffe5izMP2bKV6bXul",
    }
    Checking if branch is dirty...
    Creating comment...
    Removing reaction...


详细审查报告:

✅ security

Performing one time database migration, may take a few minutes...
sqlite-migration:done
Database migration complete.
Asserting permissions for user Svtter...
permission: admin
Adding reaction...
opencode session ses_1bfba68c1ffe3S3N6YOrgRwxtK
Fetching prompt data for PR...
Checking out local branch...
Sending message to opencode...
[12:46:05.004] INFO (#295): loop {
service: "session.prompt",
"session.id": "ses_1bfba68c1ffe3S3N6YOrgRwxtK",
step: 0,
}
[12:46:05.048] INFO (#308): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}
[12:46:05.181] INFO (#295): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}

�[91m�[1m| �[0m�[90m Shell �[0m{"command":"git diff origin/main...origin/test/multi-review-v3 -- multi-review/run-multi-review.py 2>/dev/null || git fetch origin test/multi-review-v3 2>&1 && git diff origin/main...FETCH_HEAD -- multi-review/run-multi-review.py","description":"Get PR diff for security review","workdir":"/home/runner/work/opencode-actions/opencode-actions","timeout":30000}
[12:46:10.185] INFO (#295): loop {
service: "session.prompt",
"session.id": "ses_1bfba68c1ffe3S3N6YOrgRwxtK",
step: 1,
}
[12:46:10.234] INFO (#295): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}

�[91m�[1m| �[0m�[90m Shell �[0m{"description":"Get PR diff directly","command":"git log --oneline origin/test/multi-review-v3 -5 && echo "---DIFF---" && git diff origin/test/multi-review-v3~1..origin/test/multi-review-v3 -- multi-review/run-multi-review.py","timeout":30000,"workdir":"/home/runner/work/opencode-actions/opencode-actions"}
[12:46:12.623] INFO (#295): loop {
service: "session.prompt",
"session.id": "ses_1bfba68c1ffe3S3N6YOrgRwxtK",
step: 2,
}
[12:46:12.664] INFO (#295): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}
�[0m
安全无虞

本 PR 为 CI 测试 PR,对 multi-review/run-multi-review.py 的改动涉及调试日志增强、并行 reviewer XDG 缓存隔离及 USE_GITHUB_TOKEN 默认值修正,未引入安全风险

分析要点:

  • tempfile.mkdtemp(prefix=f"opencode-review-{name}-")name 来自 reviewer 配置(非用户外部输入),且 mkdtemp 强制在系统安全目录创建,无路径遍历风险
  • shutil.rmtree(cache_dir, ignore_errors=True)try/finally 中执行,清理路径来自 mkdtemp 返回值,不可被劫持
  • _run_opencode 始终使用列表参数调用 subprocess.Popenshell=False),无命令注入
  • USE_GITHUB_TOKEN"false" 改为 "true" 是 CI 环境下的功能性修复(避免 OIDC crash),GITHUB_TOKEN 早已通过 os.environ.copy() 存在于子进程环境变量中,不构成新增敏感泄露
  • run_script.exists() 检查的对象是硬编码路径,无可控注入面
  • output[:500] 截断 reviewer 输出仅用于 stderr 调试日志,无信息泄露
  • 无新增外部依赖,无 SQL 操作,无用户输入参与 HTML/JS 渲染

阻塞项:无

建议项:无
�[0m
[12:46:25.097] INFO (#295): loop {
service: "session.prompt",
"session.id": "ses_1bfba68c1ffe3S3N6YOrgRwxtK",
step: 3,
}
[12:46:25.101] INFO (#295): exiting loop {
service: "session.prompt",
"session.id": "ses_1bfba68c1ffe3S3N6YOrgRwxtK",
}
Checking if branch is dirty...
Sending message to opencode...
[12:46:25.140] INFO (#2935): loop {
service: "session.prompt",
"session.id": "ses_1bfba68c1ffe3S3N6YOrgRwxtK",
step: 0,
}
[12:46:25.181] INFO (#2935): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}
安全无虞:CI测试PR,无安全风险
�[0m
[12:46:28.367] INFO (#2935): loop {
service: "session.prompt",
"session.id": "ses_1bfba68c1ffe3S3N6YOrgRwxtK",
step: 1,
}
[12:46:28.371] INFO (#2935): exiting loop {
service: "session.prompt",
"session.id": "ses_1bfba68c1ffe3S3N6YOrgRwxtK",
}
Pushing to local branch...
Command failed with code 128: git push
remote: Permission to sun-praise/opencode-actions.git denied to github-actions[bot].
fatal: unable to access 'https://github.com/sun-praise/opencode-actions/': The requested URL returned error: 403
Creating comment...
Removing reaction...
::error::remote: Permission to sun-praise/opencode-actions.git denied to github-actions[bot].%0Afatal: unable to access 'https://github.com/sun-praise/opencode-actions/': The requested URL returned error: 403%0A
OpenCode attempt 1/3 failed, retrying in 15s...
Asserting permissions for user Svtter...
permission: admin
Adding reaction...
opencode session ses_1bfb9bd44ffeXcZ2pmAwibO26W
Fetching prompt data for PR...
Checking out local branch...
Sending message to opencode...
[12:46:48.493] INFO (#266): loop {
service: "session.prompt",
"session.id": "ses_1bfb9bd44ffeXcZ2pmAwibO26W",
step: 0,
}
[12:46:48.543] INFO (#280): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}
[12:46:48.622] INFO (#266): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}

�[91m�[1m| �[0m�[90m Shell �[0m{"command":"cd /home/runner/work/opencode-actions/opencode-actions && git diff origin/main...origin/test/multi-review-v3","description":"Get full PR diff"}

�[91m�[1m| �[0m�[90m Shell �[0m{"command":"cd /home/runner/work/opencode-actions/opencode-actions && git fetch origin test/multi-review-v3 2>/dev/null && git log --oneline origin/main..origin/test/multi-review-v3","description":"Check PR commits"}
[12:46:51.430] INFO (#266): loop {
service: "session.prompt",
"session.id": "ses_1bfb9bd44ffeXcZ2pmAwibO26W",
step: 1,
}
[12:46:51.466] INFO (#266): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}
�[0m
安全无虞

本 PR 为 CI 调试与运维改进,不引入安全风险。USE_GITHUB_TOKEN="true" 允许 opencode CLI 使用环境中已有的 GITHUB_TOKEN 避免 OIDC crash(作用域受限,非新泄露)。tempfile.mkdtemp 创建隔离缓存目录,name 来自配置而非用户输入,无路径遍历。subprocess.run 始终使用列表参数(无 shell=True),无命令注入。所有新增 print 为调试日志,无外部输入拼接。无 SQL 操作、无 XSS 面、无新增依赖。

阻塞项:无

建议项:无
�[0m
[12:47:01.407] INFO (#266): loop {
service: "session.prompt",
"session.id": "ses_1bfb9bd44ffeXcZ2pmAwibO26W",
step: 2,
}
[12:47:01.411] INFO (#266): exiting loop {
service: "session.prompt",
"session.id": "ses_1bfb9bd44ffeXcZ2pmAwibO26W",
}
Checking if branch is dirty...
Creating comment...
Removing reaction...

✅ quality

Asserting permissions for user Svtter...
permission: admin
Adding reaction...
opencode session ses_1bfba6949ffeqpTPfKMjTJ25VP
Fetching prompt data for PR...
Checking out local branch...
Sending message to opencode...
[12:46:04.738] INFO (#292): loop {
service: "session.prompt",
"session.id": "ses_1bfba6949ffeqpTPfKMjTJ25VP",
step: 0,
}
[12:46:04.795] INFO (#300): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}
[12:46:05.204] INFO (#292): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}

�[91m�[1m| �[0m�[90m Shell �[0m{"command":"git fetch origin test/multi-review-v3 2>/dev/null; git diff origin/main...origin/test/multi-review-v3 -- multi-review/run-multi-review.py","description":"Get PR diff for review","workdir":"/home/runner/work/opencode-actions/opencode-actions"}
[12:46:08.469] INFO (#292): loop {
service: "session.prompt",
"session.id": "ses_1bfba6949ffeqpTPfKMjTJ25VP",
step: 1,
}
[12:46:08.544] INFO (#292): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}

�[91m�[1m| �[0m�[90m Shell �[0m{"description":"Get PR diff by fetching first","command":"git fetch origin main test/multi-review-v3 2>&1 && git diff origin/main...origin/test/multi-review-v3 -- multi-review/run-multi-review.py","workdir":"/home/runner/work/opencode-actions/opencode-actions"}
[12:46:10.957] INFO (#292): loop {
service: "session.prompt",
"session.id": "ses_1bfba6949ffeqpTPfKMjTJ25VP",
step: 2,
}
[12:46:10.995] INFO (#292): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}

�[96m�[1m| �[0m�[90m Read �[0m{"filePath":"/home/runner/work/opencode-actions/opencode-actions/multi-review/run-multi-review.py","offset":180,"limit":120}

�[96m�[1m| �[0m�[90m Read �[0m{"filePath":"/home/runner/work/opencode-actions/opencode-actions/multi-review/run-multi-review.py","offset":570,"limit":50}
[12:46:14.858] INFO (#292): loop {
service: "session.prompt",
"session.id": "ses_1bfba6949ffeqpTPfKMjTJ25VP",
step: 3,
}
[12:46:14.897] INFO (#292): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}
�[0m
可合并

审查总结

此 PR 对 multi-review/run-multi-review.py 做了以下改进:

  • 为每个并行 reviewer 创建独立临时目录,通过 XDG_CACHE_HOME 隔离避免 SQLite 并发冲突
  • 提取 _run_reviewer_inner 函数,资源管理(try/finally 清理临时目录)与业务逻辑分离清晰
  • USE_GITHUB_TOKEN"false" 改为 "true"(修复 CI 环境下 opencode OIDC crash)
  • 增加 run-opencode.sh 存在性检查及提前 return 1(防御性编程)
  • 增加 reviewer 失败时输出前 500 字符的调试日志
  • 所有异常路径均已覆盖(finally 清理、except 捕获)

阻塞项:无

建议项:无
�[0m
[12:46:44.760] INFO (#292): loop {
service: "session.prompt",
"session.id": "ses_1bfba6949ffeqpTPfKMjTJ25VP",
step: 4,
}
[12:46:44.764] INFO (#292): exiting loop {
service: "session.prompt",
"session.id": "ses_1bfba6949ffeqpTPfKMjTJ25VP",
}
Checking if branch is dirty...
Sending message to opencode...
[12:46:44.813] INFO (#5084): loop {
service: "session.prompt",
"session.id": "ses_1bfba6949ffeqpTPfKMjTJ25VP",
step: 0,
}
[12:46:44.850] INFO (#5084): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}
可合并,缓存隔离+防御性检查
�[0m
[12:46:46.266] INFO (#5084): loop {
service: "session.prompt",
"session.id": "ses_1bfba6949ffeqpTPfKMjTJ25VP",
step: 1,
}
[12:46:46.269] INFO (#5084): exiting loop {
service: "session.prompt",
"session.id": "ses_1bfba6949ffeqpTPfKMjTJ25VP",
}
Pushing to local branch...
Command failed with code 128: git push
remote: Permission to sun-praise/opencode-actions.git denied to github-actions[bot].
fatal: unable to access 'https://github.com/sun-praise/opencode-actions/': The requested URL returned error: 403
Creating comment...
Removing reaction...
::error::remote: Permission to sun-praise/opencode-actions.git denied to github-actions[bot].%0Afatal: unable to access 'https://github.com/sun-praise/opencode-actions/': The requested URL returned error: 403%0A
OpenCode attempt 1/3 failed, retrying in 15s...
Asserting permissions for user Svtter...
permission: admin
Adding reaction...
opencode session ses_1bfb978c3ffem7QpgpfM33cK7v
Fetching prompt data for PR...
Checking out local branch...
Sending message to opencode...
[12:47:06.083] INFO (#269): loop {
service: "session.prompt",
"session.id": "ses_1bfb978c3ffem7QpgpfM33cK7v",
step: 0,
}
[12:47:06.133] INFO (#283): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}
[12:47:06.193] INFO (#269): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}

�[91m�[1m| �[0m�[90m Shell �[0m{"command":"cd /home/runner/work/opencode-actions/opencode-actions && git fetch origin test/multi-review-v3 2>&1 && git diff origin/main...origin/test/multi-review-v3 -- multi-review/run-multi-review.py","description":"Get PR diff for review","timeout":15000}
[12:47:11.753] INFO (#269): loop {
service: "session.prompt",
"session.id": "ses_1bfb978c3ffem7QpgpfM33cK7v",
step: 1,
}
[12:47:11.794] INFO (#269): llm runtime selected {
"llm.runtime": "ai-sdk",
"llm.provider": "deepseek",
"llm.model": "deepseek-v4-flash",
}
�[0m
可合并

总结

此 PR 对 multi-review/run-multi-review.py 做了以下改进:

  • XDG_CACHE_HOME 隔离:为每个并行 reviewer 创建独立临时目录,避免 SQLite 并发冲突,try/finally 确保清理
  • 提取 _run_reviewer_inner:将 reviewer 执行逻辑从 run_reviewer 中抽离,职责更清晰
  • USE_GITHUB_TOKEN="true":修复 CI 环境中 opencode CLI 因缺少认证导致的 OIDC crash
  • 防御性检查run-opencode.sh 存在性检查及提前 return 1
  • 调试日志增强:reviewer error 时打印输出首 500 字符

阻塞项

一位 reviewer 提出的"异常传播到 ThreadPoolExecutor 时 finally 中的 shutil.rmtree 不会执行"为误报——Python 的 try/finally 语义保证无论异常是否被捕获、是否传播,finally 块始终在离开 try 块前执行。

建议项

  1. _run_reviewer_inner 参数过多(8 个):后续可考虑折叠为 dataclass 或 TypedDict 提升可维护性,当前改动合理,非阻塞。
  2. 第 320 行 coordinator 的 _run_opencode 调用未传 cache_dir:当前正确(coordinator 串行执行,无需 XDG 隔离),若后续 coordinator 也并行化需注意补上。
    �[0m
    [12:47:29.156] INFO (#269): loop {
    service: "session.prompt",
    "session.id": "ses_1bfb978c3ffem7QpgpfM33cK7v",
    step: 2,
    }
    [12:47:29.160] INFO (#269): exiting loop {
    service: "session.prompt",
    "session.id": "ses_1bfb978c3ffem7QpgpfM33cK7v",
    }
    Checking if branch is dirty...
    Creating comment...
    Removing reaction...

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