Skip to content

feat: add Gitea CI compatibility via platform abstraction layer#119

Merged
Svtter merged 4 commits into
mainfrom
gitea-ci-support
May 27, 2026
Merged

feat: add Gitea CI compatibility via platform abstraction layer#119
Svtter merged 4 commits into
mainfrom
gitea-ci-support

Conversation

@Svtter
Copy link
Copy Markdown
Collaborator

@Svtter Svtter commented May 26, 2026

Summary

Introduce a platform abstraction layer (platform.ts) that auto-detects GitHub vs Gitea at runtime, enabling multi-review and review actions to run on Gitea Actions runners without modification.

Motivation

  • OpenCode SDK already decouples LLM inference from the Git platform
  • Platform coupling was only in comment.ts (PR diff, comment posting, error cleanup) and action.yml pr-context step
  • Gitea Actions is compatible with GitHub Actions syntax, making adaptation straightforward

Changes

New: multi-review/src/platform.ts

  • detectPlatform() — detects Gitea via GITEA_API_URL env var (Gitea injects this, GitHub does not)
  • fetchPRDiff() — GitHub: gh pr diff, Gitea: tea CLI → curl REST API fallback
  • postPRComment() — GitHub: gh pr comment, Gitea: REST API, fallback to stdout
  • cleanupErrorComments() — platform-specific implementations for both

Modified: multi-review/src/comment.ts

  • Refactored to thin proxy over platform.ts
  • parseExtraEnv() unchanged (platform-agnostic)

Modified: multi-review/src/index.ts

  • Diff fetching moved from action.yml bash into TS via fetchPRDiff()
  • Falls back to pre-fetched .pr-diff.txt file for backward compatibility

Modified: multi-review/action.yml

  • New input: gitea-token (falls back to GITEA_TOKEN env var)
  • GITEA_TOKEN passed to run step env
  • pr-context step simplified (no longer hard-requires gh)

Modified: review/action.yml

  • New input: gitea-token
  • Passed as GITHUB_RUN_OPENCODE_GITEA_TOKEN env var

Modified: github-run-opencode/run-github-opencode.py

  • New detect_platform() helper
  • cleanup_error_comments() split into _cleanup_error_comments_github() / _cleanup_error_comments_gitea()
  • Gitea path uses curl + REST API

Zero Impact Guarantee

  • All GitHub code paths are unchanged
  • New gitea-token input defaults to "" (no behavior change)
  • GITEA_API_URL only exists on Gitea runners — GitHub detection is unaffected
  • Build verified: npm run build passes, all platform functions bundled

Closes #55

- New platform.ts: auto-detect GitHub/Gitea via GITEA_API_URL env var
- Unified interfaces for PR diff fetch, comment posting, error comment cleanup
- Gitea: tea CLI (preferred) → curl REST API fallback
- GitHub: unchanged, zero-impact on existing workflows
- comment.ts refactored to thin proxy over platform.ts
- index.ts: platform-aware diff fetch with pre-fetched file fallback
- action.yml (multi-review, review): new gitea-token input
- Python: detect_platform() + Gitea error comment cleanup

Closes #55
@github-actions
Copy link
Copy Markdown

有条件合并

综合报告

已确认发现(≥2 位 reviewer 一致指出)

  1. platform.ts 中存在死代码 httpRequest 函数及未使用的 http/https import — quality(阻塞项)、security(建议项 review@v1 在恢复悬挂软链目标时失败 #4)、performance(建议项 [codex] add review action with built-in defaults #2)、architecture(建议项 [codex] set default review prompt from ralphplus workflow #1)四位 reviewer 一致指出。应移除该函数及对应 import。

  2. tsup.config.tshttps/http 标记为 external 但实际未使用 — architecture(建议项 review@v1 在恢复悬挂软链目标时失败 #4)、quality(阻塞项关联)。建议清理不一致的外部声明。

阻塞项(合并前必须修复)

# 问题 来源 说明
1 platform.tshttpRequest 死代码及未使用 import quality 阻塞项,security/performance/architecture 确认 函数定义了但从未被调用,http/https 模块 import 冗余。应整块移除。
2 GitHub 场景下 PR diff 被重复拉取 performance 阻塞项 action.yml shell 步骤预拉取 diff(gh pr diff),而 index.tsfetchPRDiff()fetchDiffGithub() 再次调用 gh pr diff,每次 API 调用和网络传输完全重复。建议两者合一,或让 Node.js 优先读取预拉取文件。

建议项

# 问题 来源 说明
1 Python 异常捕获冗余 quality 建议 #1 except (subprocess.TimeoutExpired, json.JSONDecodeError, Exception)Exception 已包含前两者。
2 Python 环境变量获取方式不一致 quality 建议 #2 detect_platform 直接使用 os.environ.get(),其他地方使用 get_env() 辅助函数。
3 Python run_link_pattern 变量名语义偏差 quality 建议 #3 虽兼容 Gitea,但变量名为 github_*,建议加注释说明。
4 pr-meta.json 移除需确认无外部依赖 quality 建议 #4 TS 代码已无引用,建议确认无其他使用者。
5 tea CLI 子命令兼容性 quality 建议 #5 tea pulls difftea issues comment 需确认是否标准,建议加 fallback 注释。
6 GITEA_API_URL 未强制 HTTPS security 建议 #1 允许 http:// 时 Token 明文传输,建议增加 HTTPS 检查或警告。
7 GITEA_API_URL 存在 SSRF 风险 security 建议 #2 api_base 直接拼入 URL 且未做白名单校验。
8 GITHUB_REPOSITORY 未做格式校验 security 建议 #3 直接拼入 API 请求路径,建议增加 /^[\w.-]+\/[\w.-]+$/ 正则校验。
9 hasTea() 重复调用子进程 performance 建议 #2 fetchPRDiffpostCommentGitea 各自执行 which,可惰性缓存。
10 Gitea 评论清理未处理分页 performance 建议 #3 相比 GitHub 版的 --paginate,Gitea 版可能遗漏评论。
11 platform.ts 文件职责过重 architecture 建议 #3 单文件 341 行承载平台检测、Diff 拉取、评论发布、清理四类职责,建议拆分。

总结:四个 reviewer 均确认有可改进项,其中 quality 和 performance 各提出一个阻塞项(死代码、diff 重复拉取)。修复阻塞项后建议合并。


📋 各 Reviewer 详细审查结果
quality

有条件合并

评审总结

这个 PR 为 multi-review 和 review action 添加了 Gitea 平台支持,通过 platform.ts 抽象层实现了 GitHub/Gitea 双平台适配。整体设计合理,错误处理完备,功能正确。

阻塞项

  1. platform.ts 中存在死代码 (multi-review/src/platform.ts): httpRequest 函数定义了但从未被调用;同时 http/https 的 import 仅被该函数使用,属于未使用的 import。应移除该函数及其相关 import,以减小 bundle 体积和降低认知负担。

建议项

  1. Python 异常捕获冗余 (github-run-opencode/run-github-opencode.py): _cleanup_error_comments_giteaexcept (subprocess.TimeoutExpired, json.JSONDecodeError, Exception)Exception 已包含前两者,建议简化。

  2. Python 环境变量获取方式不一致 (github-run-opencode/run-github-opencode.py): detect_platform 直接使用 os.environ.get(),而文件内其他函数使用 get_env() 辅助函数。建议统一使用 get_env 以保持风格一致。

  3. Python 字符串模板类型 (github-run-opencode/run-github-opencode.py): run_link_pattern 用 f-string 拼接路径,虽在 Gitea 中 GITHUB_REPOSITORY/GITHUB_RUN_ID 也兼容,但变量名仍是 github_*,存在轻微语义偏差,建议加注释说明 Gitea 兼容性。

  4. action.ymlpr-meta.json 的移除 (multi-review/action.yml): 移除了 gh pr viewpr-meta.json,经查 TS 代码中无对应读取,属于清理死代码。但需确认是否有其他外部依赖引用了该文件。

  5. tea CLI 子命令兼容性: fetchPRDifftea pulls diffpostCommentGiteatea issues comment 可能不是标准 tea CLI 的子命令,建议验证或加注释说明 fallback 路径能兜底。

security

存在风险

该 PR 为 multi-review 和 review action 增加了 Gitea 平台支持,整体安全性尚可,但在某些配置场景下存在若干安全隐患。

阻塞项:无

建议项:

  1. 未强制检查 GITEA_API_URL 使用 HTTPSGITEA_API_URL 可配置为 http:// 协议,此时 Gitea API Token 将通过明文传输,存在中间人窃听风险。建议在代码中增加 HTTPS 校验或至少输出警告日志。

  2. GITEA_API_URL 存在 SSRF 风险:该值由 workflow 配置方控制,可直接指向内网地址。虽然这是该功能的设计特性,但结合未严格校验的 URL 格式(如在 platform.ts:337 直接拼入 URL),攻击者若控制 workflow 配置可发起 SSRF 攻击。建议增加 URL 白名单或对 api_base 做基本校验(如确认不以 http://localhost 或内网 IP 开头)。

  3. GITHUB_REPOSITORY 未做输入校验直接拼入 API URLplatform.tsprocess.env.GITHUB_REPOSITORY 未经任何格式校验直接用于构造 API 请求路径(platform.ts:199 等)。若该环境变量包含 ../ 等路径穿越字符可能导致访问非预期的仓库资源。建议增加格式校验(如正则 /^[\w.-]+\/[\w.-]+$/)。

  4. 死代码包含不安全的 http 模块调用platform.ts 中定义了 httpRequest 函数但未被任何代码调用。该函数使用了 node:http 模块(非 HTTPS),若未来被误用可能导致 token 明文传输。建议删除未使用的 httpRequest 函数。

performance

性能问题严重

分析总结

本 PR 为 multi-review 和 review action 添加 Gitea 平台支持,整体架构合理。引入了一个 platform.ts 平台抽象层,将 diff 拉取、评论发布、错误评论清理等操作按平台分发。

主要性能问题:GitHub 场景下 PR diff 被重复拉取

multi-review/action.yml 中 shell 步骤仍然通过 gh pr diff 预拉取 diff 写入文件,而 multi-review/src/index.ts 中又通过 fetchPRDiff()fetchDiffGithub() 再次调用 gh pr diff。两者在 GitHub 上都会成功,导致 diff 被拉了两次,第二次的结果完全覆盖第一次:

  1. action.yml shell: gh pr diff "$pr" > .pr-diff.txt(每次运行都执行)
  2. src/index.ts: fetchPRDiff(prNumber)fetchDiffGithub() → 再次 gh pr diff(每次都执行,且因优先于文件回退,shell 预拉取成为死代码)

这导致每次 GitHub PR review 都浪费一次 API 调用和网络传输(大 diff 时更显著),属于引入的性能回退。

其他非阻塞问题

  • platform.ts 中定义了 httpRequest() 函数但未被任何调用者使用,属于死代码;同时引入了 httpshttp 模块的 ESM 包装,增加了 bundle 体积和模块初始化开销
  • hasTea()fetchPRDiffpostCommentGitea 中被重复调用(各自执行一次 which 子进程),可以通过惰性缓存优化
  • Gitea 评论清理函数 cleanupErrorCommentsGitea 未处理分页(不像 GitHub 版使用了 --paginate),若 PR 评论较多可能漏删

阻塞项

  • 重复拉取 PR diff(GitHub 场景):action.yml shell 预拉取 + Node.js 平台适配器再次拉取,两者均调用 gh pr diff,导致每次 GitHub PR review 浪费一次 API 调用和网络开销。建议在 action.yml 中移除 shell 预拉取(或将其改为仅作为 Node.js 失败后的回退),或让 Node.js 优先读取预拉取文件。

建议项

  • 删除 platform.ts 中未使用的 httpRequest() 函数及其 https/http 模块导入
  • hasTea() 结果可做惰性缓存,避免每次调用都 spawn which 子进程
  • Gitea 评论列表 API 应处理分页(类似 GitHub 版的 --paginate),防止大 PR 下漏删错误评论
architecture

架构有疑虑

本 PR 引入 Gitea 支持,核心思路是新建 multi-review/src/platform.ts 作为平台抽象层,将 GitHub/Gitea 的差异封装在统一接口之后。整体方向合理,但存在以下问题:

阻塞项:无

建议项:

  1. platform.ts:76-105 定义了 httpRequest(异步 HTTP 辅助函数),但整个文件从未调用它——实际代码统一使用 execFileSync("curl", ...) 的同步方式。这是死代码,应移除或替换为实际使用,否则误导维护者。
  2. github-run-opencode/run-github-opencode.pymulti-review/src/platform.ts 两套平台抽象存在风格不一致:Python 侧将 curl 命令内联在函数中,TS 侧则集中到 platform.ts 且设计了 detectPlatform() → dispatch 的模式。虽然跨语言无法避免,但建议未来统一设计模式(例如 Python 侧也提取一个 _platform 模块做同样的抽象)。
  3. platform.ts 单文件 341 行,承载了平台检测、Diff 拉取、评论发布、错误评论清理四类职责。虽不严重,但考虑拆分为 platform.ts(公共类型 + 检测)和 platform-api.ts(API 操作)。
  4. tsup.config.ts 中将 https/http 标记为 external,但 platform.ts 实际并未使用 Node.js 内置 http 模块发请求(用了 curl)。在 future-proof 和实际代码之间不一致,建议移除未使用的 external 声明或确认将来计划使用。

- Remove dead httpRequest code and unused http/https imports (阻塞项 #1)
- Reverse diff fetch priority: pre-fetched file first, platform fetch as
  fallback to avoid duplicate API calls on GitHub (阻塞项 #2)
- Fix redundant Python exception catches (Exception covers subclasses)
- Use get_env() in detect_platform() for consistency
- Add HTTPS warning for GITEA_API_URL using plain HTTP
- Validate GITHUB_REPOSITORY format before API calls
- Lazy-cache hasTea() result to avoid repeated which calls
- Add pagination support for Gitea comment cleanup
- Revert tsup externals (https/http no longer imported)
- Remove duplicate empty-diff check in index.ts
@github-actions
Copy link
Copy Markdown

可合并

四个 reviewer 一致认为无阻塞项。最严重发现为建议项,不阻止合并。

建议项(按优先级排序):

# 问题 提出者 分类
1 fetchAllGiteaComments() 分页无上限while(true) 串行直连,极端评论数下会阻塞事件循环 quality, performance 已确认
2 Python 异常捕获过宽 — 从 (subprocess.TimeoutExpired, json.JSONDecodeError, Exception) 收窄为 Exception,吞咽 KeyboardInterrupt 等信号 security, performance, architecture 已确认
3 Python HTTP 明文传输无警告 — Python 版 _cleanup_error_comments_gitea 未像 TS 版检测 http:// 并输出警告 security 独特
4 Python 缺少输入校验 — Python 版拼接 curl URL 前未对 GITEA_API_URL、repo、PR 号做格式校验 security 独特
5 getRepo() 格式非法时抛出异常 — 原行为是静默跳过,抛出会导致 pipeline 中断 quality 独特
6 detectPlatform() 未缓存结果 — 多次调用重复读取环境变量 performance 独特
7 getRepo()/getGiteaApiBase() 未缓存 — 每次调用重复正则验证和路径清理 performance 独特
8 删除评论逐条调 curl — Python 版每条错误评论启动一次 subprocess.run("curl") performance 独特
9 platform.ts 模块膨胀 — 建议按职责拆分为 platform/detect.tsplatform/comment.tsplatform/diff.ts architecture 独特
10 Python 参数命名混淆 — Gitea 函数仍用 github_repositorygithub_run_id 命名 architecture 独特
11 catch {} 缺注释 — 建议加 /* ignore */ 与现有风格保持一致 quality 独特
12 环境变量全量透传env: { ...process.env } 可能将 token 泄漏到子进程 security 独特
13 Token 环境变量命名不一致 — Python 版检查 GITHUB_RUN_OPENCODE_GITEA_TOKEN/GITEA_TOKEN,TS 版只检查 GITEA_TOKEN security 独特

阻塞项:


📋 各 Reviewer 详细审查结果
quality

import re 已在文件顶部,没有问题。


可合并

此 PR 为 multi-review 和 review action 添加了 Gitea 平台支持,代码结构清晰,抽象合理,错误处理较为完整。

阻塞项:无

建议项:

  1. platform.ts:getRepo() 校验 GITHUB_REPOSITORY 格式时使用 throw,若格式非法会导致 cleanupErrorComments() 直接崩溃,而原行为是静默跳过。建议将不合法的 repo 处理为返回空字符串并打印警告,而非抛出异常。
  2. fetchAllGiteaComments() 缺少最大页数上限作为安全阀,极端情况下若 Gitea API 异常返回不断有数据的非空数组(长度小于 limit),可能导致死循环。建议添加 MAX_PAGES 常量兜底。
  3. cleanupErrorCommentsGitea()cleanupErrorCommentsGithub() 中删除失败的空 catch {} 块,建议至少加 /* ignore */ 注释(现有代码风格已如此,此处仅为一致性建议)。
security

存在风险

本次 PR 主要添加了对 Gitea 平台的 CI 支持,包括在 Python 和 TypeScript 中实现 Gitea API 的评论管理、PR diff 获取等功能。整体安全性尚可,未发现可直接利用的命令注入或权限绕过漏洞,但存在若干安全改进点。

阻塞项

阻塞项:无

建议项

  1. Python 代码缺少 HTTP 明文传输警告
    run-github-opencode.py_cleanup_error_comments_gitea 函数直接使用 GITEA_API_URL 发起 curl 请求,未像 TS 版 platform.ts:67-73 那样在检测到 http:// 时输出警告。若管理员配置了 HTTP 的 API 地址,token 和 PR diff 将以明文传输。建议对齐 TS 版本的行为,添加同样的 HTTP 警告。

  2. Python 代码缺少对 GITEA_API_URLGITHUB_REPOSITORY、PR 号的输入校验
    platform.ts:55-61getRepo() 使用正则 /^[\w.-]+\/[\w.-]+$/ 校验了 repo 格式,resolvePRNumber() 也只提取纯数字。而 Python 版直接拼接字符串到 curl URL 中(run-github-opencode.py:246),没有做任何格式校验。虽然 CI 环境变量由平台注入、非用户可控,但建议对齐进行校验以提高安全纵深。

  3. 环境变量透传(env: { ...process.env })可能导致敏感信息泄漏到子进程
    platform.ts 多处使用 env: { ...process.env } 将全部环境变量透传给 ghteacurl 等子进程。如果子进程有日志/调试输出,可能意外泄漏 GITEA_TOKENGITHUB_TOKEN 等敏感值。虽为已有模式的延续,建议在新代码中最小化透传。

  4. Token 环境变量命名不一致
    Python 版检查 GITHUB_RUN_OPENCODE_GITEA_TOKENGITEA_TOKEN,TS 版只检查 GITEA_TOKEN(来自 action.ymlinputs.gitea-token)。两种命名间的 fallback 逻辑容易造成混淆,建议统一命名约定。

  5. Exception 捕获范围过宽
    run-github-opencode.py:232 将原来显式的 subprocess.TimeoutExpired, json.JSONDecodeError, Exception 简化为 Exception,虽然功能等效,但过于宽泛的异常捕获可能掩盖本应暴露的错误。建议保持显式列举或采用更精确的异常类型。

performance

性能有疑虑

本次 PR 主要新增 Gitea 平台支持,抽象出平台层(platform.ts),将原有的 GitHub-only 操作分发到各平台实现。整体架构合理,但存在一些非关键性能问题。

分析摘要

好的方面:

  • 会话清理移至 finally 块,确保资源释放,避免泄漏(orchestrator.ts)
  • hasTea() 使用模块级缓存 (_teaAvailable),避免多次 which 调用
  • PR diff 优先读取预缓存文件,失败才回退到 API 获取,减少不必要请求
  • 各函数职责单一,没有明显的冗余计算

问题方面:


阻塞项:无


建议项:

  1. fetchAllGiteaComments 分页循环无上限控制platform.ts:105-127
    使用 while(true) 串行分页拉取,每次调用同步 execFileSync("curl")。若某 PR 评论数极大(数百页),会阻塞事件循环数十秒甚至更久。建议设置最大页数限制(如 MAX_PAGES=20)或改用异步方式。

  2. detectPlatform() 被频繁调用且未缓存结果
    fetchPRDiffpostPRCommentcleanupErrorComments 中均被调用,每次读取 GITEA_API_URL 环境变量。虽然单次开销很小,但多次重复读取无意义。建议模块级缓存结果。

  3. getRepo() 每次调用都执行正则验证platform.ts:34-39
    若考虑极端情况多次调用,可缓存已验证的结果。同样 getGiteaApiBase() 每次做 replace(/\/+$/, "") 也可缓存。

  4. Python 端 _cleanup_error_comments_gitea 删除评论时每个评论启动一次 subprocess.run("curl")
    虽然错误评论数量通常极少,但若数量较多时(如 CI 重试多次),O(N) 次进程创建有可感知开销。可考虑批量删除(若 Gitea API 支持)或使用 Python requests/urllib 避免进程开销。

  5. Python 异常捕获范围过宽(原 (subprocess.TimeoutExpired, json.JSONDecodeError, Exception) → 现 except Exception
    这会导致 KeyboardInterrupt 等被意外吞咽,虽非性能问题,但异常路径处理可能影响排查效率。建议保持原有精确捕获。

architecture

架构合理

PR 通过新增 platform.ts 模块将 Gitea 平台适配集中化,comment.ts 改为薄委托层,整体遵循了"提取平台抽象"的正确架构方向。改动范围可控,无循环依赖,接口清晰。

建议项:

  1. platform.ts 逐渐成为"平台全能模块"(diff 拉取、评论发布、错误清理、token 管理混于一文件),随着未来更多平台或操作加入,建议按职责拆分为 platform/detect.tsplatform/comment.tsplatform/diff.ts 等,或使用策略模式接口
  2. run-github-opencode.py 中 Gitea 函数的参数仍名为 github_repositorygithub_run_id,虽然兼容但语义混淆,建议重命名为 repositoryrun_id,或在注释中统一说明命名缘由
  3. 异常捕获从 (subprocess.TimeoutExpired, json.JSONDecodeError, Exception) 收窄为 Exception,丢失了类型区分,建议保留具体异常类型以区分可重试/不可重试错误

阻塞项:无

TS (platform.ts):
- Cache detectPlatform() result to avoid repeated env reads (#6)
- getRepo() returns empty string + warn instead of throw (#5)
- fetchAllGiteaComments() capped at MAX_PAGES=20 (#1)
- getGiteaToken() checks both GITEA_TOKEN and GITHUB_RUN_OPENCODE_GITEA_TOKEN (#13)
- Add /* ignore */ comments to empty catch blocks (#11)

Python (run-github-opencode.py):
- Use specific exception types: (TimeoutExpired, JSONDecodeError) not bare Exception (#2)
- Add HTTP plaintext warning for GITEA_API_URL (#3)
- Validate repo/pr format before URL construction (#4)
- Add pagination for Gitea comment listing with max_pages=20 (#1)
- Unify token lookup to GITEA_TOKEN only (#13)
@github-actions
Copy link
Copy Markdown

决策:有条件合并

所有 reviewer 均未提出阻塞项,但 security reviewer 对 HTTP 明文传输 Token 的风险定性为"存在风险"。综合来看,建议修复建议项中的安全与行为一致性问题后合并。

阻塞项:无

建议项(已去重,共 8 项):

  1. 恢复 cleanupErrorCommentsGithub 的错误日志(platform.ts:297)— quality + architecture 同时指出,迁移后 catch 块吞掉了 console.error("cleanup-error-comments: failed to list comments"),Gitea 路径保留但 GitHub 路径丢失,属行为退化。已确认

  2. tea pulls diff 缺少 --repo 参数(platform.ts:147)— quality 指出,无法保证在所有 CI 场景下正确推断仓库,建议显式传递 --repo

  3. 明文 HTTP 传输 Token 应报错退出(platform.ts:82-87, run-github-opencode.py)— security 指出,GITEA_API_URL 使用 http:// 时仅打印警告,建议要求显式配置 GITEA_API_URL_INSECURE=allow 才能绕过 HTTPS。

  4. GITHUB_RUN_OPENCODE_GITEA_TOKEN 命名一致性问题review/action.yml:254)— security 指出,GITHUB_RUN_ 前缀易与 GitHub Token 混淆,建议改为 GITEA_TOKEN 与 multi-review 侧保持一致。

  5. 环境变量读取可缓存(platform.ts:64-68)— performance 指出,getRepo()/getGiteaToken()/getGiteaApiBase() 每次调用都重复读取 process.env 并做正则校验,建议缓存结果。

  6. fetchAllGiteaComments 串行翻页性能风险(platform.ts:87-113)— performance 指出,最多 20 页 × 50 条 = 20 串行 HTTP 请求,极端超时场景下总耗时可达 10 分钟。

  7. error_indicators 正则重复编译run-github-opencode.py:270-271)— performance 指出,每次调用 _cleanup_error_comments_gitea 都重新编译 regex,建议提取为模块级常量。

  8. Python Gitea 函数参数名中的 github_ 前缀run-github-opencode.py)— architecture 指出,参数名 github_repository/github_run_id 虽注释说明是兼容性命名,但易造成后续维护困惑,建议改为平台中立名称。


📋 各 Reviewer 详细审查结果
quality

有条件合并

本次 PR 为 multi-review 和 review 动作增加了 Gitea 平台支持,整体设计清晰、结构合理,平台抽象层(platform.ts + Python detect_platform)隔离得当。以下是审查意见:

阻塞项

建议项

  1. cleanupErrorCommentsGithub 丢失错误日志(platform.ts:297:原有 comment.tsgh api 列出评论失败时会输出 console.error("cleanup-error-comments: failed to list comments"),迁移到 platform.ts 后该日志被吞掉(catch 块仅写注释 /* ignore — list failed */)。而 Gitea 路径 cleanupErrorCommentsGitea 保留了错误日志。建议补回,保持两路径行为一致。
  2. tea pulls diff 缺少 --repo 参数(platform.ts:147:Gitea fallback 路径中调用 tea pulls diff {prNumber} 没有指定仓库。虽然 tea 可能从当前工作目录自动推断,但无法保证在所有 CI 场景下正确工作(而 GitHub 的 gh pr diff 显式传了 --repo)。建议补上 --repo 参数。
security

存在风险

本次 PR 增加了 Gitea 平台支持,整体采用了安全的编程实践(数组参数调用外部命令、输入格式校验等),未发现高危漏洞,但存在一个值得关注的非关键风险。

阻塞项:无

建议项:

  1. 明文 HTTP 传输 Tokenplatform.ts:82-87run-github-opencode.py 中,当 GITEA_API_URL 使用 http:// 时仅打印警告便继续执行。建议改为报错退出,或至少要求明确配置 GITEA_API_URL_INSECURE=allow 才能使用 HTTP。当前行为可能导致 Token 在网络中被明文截获。
  2. GITHUB_RUN_OPENCODE_GITEA_TOKEN 命名不一致review/action.yml:254 将该 Token 以 GITHUB_RUN_ 前缀命名,容易让人误以为是 GitHub Token,建议改为 GITEA_TOKEN 以保持与 multi-review 侧一致,减少维护者的混淆。
performance

性能良好

该 PR 主要新增 Gitea 平台支持,整体性能表现合理,无严重回归。

阻塞项:无

建议项:

  1. multi-review/src/platform.ts:64-68getRepo() 每次调用都从 process.env 读取并做正则校验,可考虑缓存结果;getGiteaToken()getGiteaApiBase() 同理。当前写法不影响正确性,但多次重复读取 env 是微优化机会。
  2. multi-review/src/platform.ts:87-113fetchAllGiteaComments 顺序翻页(最多 20 页 × 50 条/页 = 20 串行 HTTP 请求),在高延迟网络下累计等待时间可能较长。对于 cleanup 场景可接受,但极端情况下(每页超时 30s)总耗时可达 10 分钟。
  3. github-run-opencode/run-github-opencode.py:270-271error_indicators = re.compile(...) 定义在函数内部,每次调用 _cleanup_error_comments_gitea 都重新编译 regex,建议提取为模块级常量。
architecture

架构合理

该 PR 通过引入 platform.ts 模块将 GitHub/Gitea 差异封装在平台抽象层后,原有 comment.ts 退化为此模块的薄 facade。这种策略模式选择正确,改动范围集中(主要在新建的 platform.ts 和对应的 Python 文件),没有出现散弹式修改。模块放置位置合理,接口设计清晰。

阻塞项:无

建议项:

  • Python 中 Gitea 相关函数参数名为 github_repository/github_run_id,虽注释说明是兼容性命名,但可能导致后续维护困惑,建议重命名为 repository/run_id 或其他平台中立名称
  • platform.ts:cleanupErrorCommentsGithub 移除了原 comment.tscatch 块的 console.error("cleanup-error-comments: failed to list comments"),导致 GitHub 路径下列表失败时不再输出错误日志,属于非预期的行为退化,建议恢复该日志
  • multi-review/action.yml 中去掉了 gh pr view 获取 PR 元数据的逻辑(原 pr-meta.json),与 Gitea 支持无关,属于 drive-by 修改,建议独立提交或补充说明

- Restore error log in GitHub cleanup catch block (#1)
- Add --repo to tea pulls diff call (#2)
- Python Gitea token fallback: check both GITEA_TOKEN and GITHUB_RUN_OPENCODE_GITEA_TOKEN (#4)
@github-actions
Copy link
Copy Markdown

最终决策:可合并

所有 reviewer 均无阻塞项,PR 整体设计合理,可直接合并。

阻塞项:无

建议项:

  1. Token 泄露于进程参数(security)— Python 和 TypeScript 均将 token 通过 curl 的 -H 命令行参数传递,共享 CI Runner 上其他进程可通过 /proc/PID/cmdline 看到 token。建议改用临时文件或 stdin 传递,或使用 tea/gh 这类从环境变量读取 token 的 CLI 工具。

  2. GITEA_API_URL 缺乏校验与 HTTP 明文传输风险(security, quality)— 两方 reviewer 均指出此问题:security reviewer 指出未做 URL 白名单/协议校验存在 SSRF 风险;quality reviewer 指出 HTTP 协议下 token 明文传输风险持续存在(仅记警告而未拦截)。建议对 URL 做协议(仅 HTTPS)和格式校验,HTTP 时直接跳过或要求显式确认。

  3. comment.ts 沦为薄包装(architecture)— 提取后仅做重新导出和委托,建议让 index.ts 直接调用 platform.ts,移除中介层。

  4. Python/TypeScript 两端平台逻辑重复(architecture)— run-github-opencode.pyplatform.ts 的平台探测和 Gitea API 交互模式需独立维护,建议将共享策略收敛到文档或辅助脚本中。

  5. Python 端异常处理不一致(architecture)— run-github-opencode.pyException 从 except 子句中移除,而 TypeScript 端仍捕获一般异常,建议对齐。

  6. 分页拉取评论效率低(performance)— fetchAllGiteaComments 串行 curl 分页,最多可阻塞 10 分钟;GitHub 侧 gh api --paginate 一次完成。虽非热路径,仍建议后续优化。

  7. 重复读取环境变量(performance)— getRepo()getGiteaToken()getGiteaApiBase() 每次调用均重新读取 env,建议 module-level 缓存。

  8. Token 特殊字符与 header 注入(security)— 虽已用列表传参降低 shell 注入风险,但 token 含换行符等仍可能造成 header 注入,建议做字符校验。

  9. 环境变量命名不一致(quality)— multi-review/action.ymlGITEA_TOKENreview/action.ymlGITHUB_RUN_OPENCODE_GITEA_TOKEN,建议统一。

  10. 变量名 runLinkPattern 误导(quality)— 实为普通字符串而非正则,建议改名。


📋 各 Reviewer 详细审查结果
quality

可合并

该 PR 为 multi-review 和 review action 增加了 Gitea 平台支持,整体设计合理、改动清晰、错误处理完善。

阻塞项:无

建议项:

  1. multi-review/src/platform.ts:76 中变量名 runLinkPattern 实为普通字符串(用于 includes 判断),非正则模式,命名略误导
  2. multi-review/action.ymlGITEA_TOKENreview/action.ymlGITHUB_RUN_OPENCODE_GITEA_TOKEN,虽代码同时兼容两者,但两个 action 之间的环境变量命名不一致,建议统一
  3. Python _cleanup_error_comments_giteaapi_base 变量在 http:// 告警后仍会用于后续请求,若用户忽略告警则 token 明文传输风险持续存在,建议考虑在 HTTP 时直接跳过或要求显式确认
security

存在风险

安全分析摘要: 此 PR 为 multi-review action 增加了 Gitea 平台支持,引入通过 curl 和 tea CLI 与 Gitea API 交互的代码。整体上做了输入校验(repo 名和 PR 号正则验证)、HTTP 警告日志等安全防护,但仍存在值得关注的隐患。

阻塞项:无

建议项:

  1. Token 泄露于进程参数 — Python(_cleanup_error_comments_gitea)和 TypeScript(platform.ts)均将 token 作为 curl 命令行参数传递(-H "Authorization: token ${token}")。在共享 CI Runner 上,同一机器上的其他进程可通过 /proc/PID/cmdlineps aux 看到该 token。建议改为通过临时文件或 stdin 传递 token,或使用 gh/tea 这类从环境变量读取 token 的 CLI 工具。
  2. SSRF 风险GITEA_API_URL 未做 URL 白名单/格式校验,直接用于构造 curl 请求 URL。恶意方若可控制该环境变量,可诱导 action 请求内部服务。建议对 GITEA_API_URL 做 URL 格式和协议(仅允许 HTTPS)验证。
  3. token 中的特殊字符 — token 中若包含换行符等特殊字符,在 curl 的 -H 参数中可能造成 header 注入。建议对 token 做合法性校验(如仅允许字母数字字符),或使用 execFileSync / subprocess.run 的列表传参方式避免 shell 注入(目前已用列表方式,该风险较低但仍是防御深度的建议)。
performance

性能有疑虑

该 PR 增加了 Gitea 平台支持,核心逻辑是使用同步子进程方式调用 curl/tea CLI 替代 GitHub 的 gh CLI。总体性能风险可控,但有以下需要注意的点。

阻塞项:无
建议项:

  1. fetchAllGiteaComments (platform.ts:130) 使用 while 循环串行调用 execFileSync("curl", ...) 分页拉取评论,每页阻塞事件循环最多 30s,最多 20 页(含重试)最差情况下单次调用阻塞 10 分钟。GitHub 侧通过 gh api --paginate 一次调用完成,Gitea 侧的串行模式效率偏低。影响评估:cleanup 阶段调用,非热路径,不阻塞 merge 但值得优化。
  2. getRepo()getGiteaToken()getGiteaApiBase() 每次调用都重新读取环境变量,建议仿照 _platform/_teaAvailable 做 module-level 缓存,减少重复的 env 读取开销(虽成本很低,但调用频次高)。
  3. _cleanup_error_comments_gitea (Python) 和 cleanupErrorCommentsGitea (TS) 的删除循环均是串行执行,如果有大量匹配的错误评论(例如网络抖动导致数十条),总耗时线性增长。可考虑用 asyncio.gather 或并发子进程批量删除。
  4. fetchPRDifftea CLI 失败后回退到 curl,产生了额外的异常开销和重复 API 调用(失败概率低,影响有限)。
architecture

架构合理

本 PR 引入了平台抽象层(platform.ts),将 GitHub/Gitea 的具体操作从原有模块中解耦,整体架构方向正确。

建议项

  1. 运行时重复run-github-opencode.py 中的 detect_platform 和 Gitea 相关逻辑与 TypeScript 端的 platform.ts 存在本质重复。Python 和 TypeScript 虽无法共享代码,但相同的平台探测策略和 Gitea API 交互模式在两处独立维护,未来新增平台(如 GitLab)时需要同时修改两处。建议考虑将平台相关环境变量名称、URL 构建逻辑收敛到共享文档或 shell 辅助脚本中统一引用。

  2. comment.ts 沦为薄包装:提取后 comment.ts 仅做重新导出和简单委托,postPRComment/cleanupErrorComments 各 4-5 行。这一层间接性对调用方(index.ts)的实际价值有限,可考虑让 index.ts 直接调用 platform.ts,移除 comment.ts 中介层。

  3. 构建产物中的重命名dist/index.cjs 中出现 postPRComment2/cleanupErrorComments2。这是 comment.tsplatform.ts 导出同名函数被 bundler 重命名的结果,虽然不影响运行,但建议通过命名空间或统一导出路径消除。

  4. Python 端异常处理不一致run-github-opencode.py 中将 Exception 从 except 子句中移除(第 235/266 行),而 TypeScript 端仍然捕获一般异常。这两处对未预期错误的处理策略应保持一致。

阻塞项:无

@Svtter Svtter merged commit 1f0d591 into main May 27, 2026
2 of 3 checks passed
Svtter added a commit that referenced this pull request May 27, 2026
refactor: address review follow-up from PR #119
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.

Gitea + tea + opencode:AI Code Review 方案

1 participant