Prhub

#2877 fix(ci): mint the command-App token with pull-requests: write for label commands

原始 PR 作者 guapisolo 合并时间 2026-09-02 14:33 文件变更 5 提交数 3 评论 1 代码增减 +46 / -5

执行摘要

修复 CI 命令应用令牌权限,解决标签命令的 HTTP 403 错误。

标签命令在处理拉取请求时,使用问题 API 添加标签需要 pull-requests: write 权限。之前的令牌只请求了 pull-requests: read,导致 GitHub API 返回 403 错误,阻止了标签添加和后续 CI 启动。PR body 中明确指出:'POST /repos/radixark/miles/issues/{n}/labels for an issue that is a pull request' 需要 pull_requests 范围的写权限。

该 PR 值得精读,因为它修复了阻塞性的 CI 问题,并展示了良好的工程实践:在修复权限的同时增强错误诊断能力。设计决策如在错误消息中包含权限信息,有助于未来快速调试权限相关问题。

讨论亮点

无实质性技术讨论;仅有一个来自 claude[bot] 的自动化评论,说明手动代码审查配置,未涉及设计或实现细节。

实现拆解

变更分为四个核心步骤:

  1. 权限配置调整:修改 .github/workflows/comment-ci-command.yml,将 permission-pull-requests: read 更改为 write,并添加注释说明标签命令在 PR 上需要写权限。这直接修复了令牌铸造错误。
  2. 错误处理增强:在 .github/workflows/scripts/comment_ci_command.py 的 GitHubAPI._request 方法中,改进 HTTP 错误处理,构造包含请求方法、路径和 GitHub 接受权限头的详细错误消息,避免仅报告 'HTTP 403'。
  3. 测试覆盖补充:在 tests/ci/test/test_comment_ci_command.py 中新增两个测试函数 test_http_error_names_the_request_and_accepted_permissions 和 test_http_error_without_accepted_permissions_still_names_the_request,验证错误消息格式;同时更新现有工作流测试以断言新权限行的存在(如 \n permission-pull-requests: write\n)。
  4. 文档同步更新:更新 docs/ci/01-label.md 和 docs/ci/05-command-identity.md,说明新权限要求、安装批准需求,以及缓解措施(固定处理代码和作业作用域令牌)。

所有变更都围绕 CI 基础设施,没有涉及核心源码逻辑。

文件 模块 状态 重要度
tests/ci/test/test_comment_ci_command.py CI 命令测试 modified 6.47
.github/workflows/scripts/comment_ci_command.py CI 工作流脚本 modified 4.19
.github/workflows/comment-ci-command.yml CI 工作流 modified 3.21
docs/ci/01-label.md CI 文档 modified 1.52
docs/ci/05-command-identity.md CI 文档 modified 1.52

关键符号

test_http_error_names_the_request_and_accepted_permissions test_http_error_without_accepted_permissions_still_names_the_request

关键源码片段

tests/ci/test/test_comment_ci_command.py test-coverage

测试文件是本次变更的核心验证部分,新增测试覆盖错误消息和权限断言,确保修复有效性。

# 新增测试:验证 HTTP 错误消息包含请求方法、路径和接受权限头
def test_http_error_names_the_request_and_accepted_permissions(monkeypatch):
    def urlopen(_request, *, timeout):
        # 模拟 GitHub API 返回 403 错误,附带接受权限头
        raise urllib.error.HTTPError(
            "url", 403, "forbidden", {"X-Accepted-GitHub-Permissions": "pull_requests=write"}, None
        )
​
    monkeypatch.setattr(HANDLER.urllib.request, "urlopen", urlopen)
    with pytest.raises(HANDLER.CommentCommandError) as excinfo:
        HANDLER.GitHubAPI("secret-token").add_label(123, "run-ci-short")
    message = str(excinfo.value)
    # 断言错误消息包含方法、路径和权限信息
    assert message == (
        "GitHub API returned HTTP 403 for POST /repos/radixark/miles/issues/123/labels; "
        "accepted permissions: pull_requests=write"
    )
    # 确保令牌不在消息中泄露
    assert "secret-token" not in message
​
# 新增测试:验证错误消息在无接受权限头时仍包含请求信息
def test_http_error_without_accepted_permissions_still_names_the_request(monkeypatch):
    def urlopen(_request, *, timeout):
        raise urllib.error.HTTPError("url", 404, "missing", {}, None)
​
    monkeypatch.setattr(HANDLER.urllib.request, "urlopen", urlopen)
    with pytest.raises(HANDLER.CommentCommandError) as excinfo:
        HANDLER.GitHubAPI("secret-token").get_permission("actor")
    # 断言错误消息包含方法和路径,但不包含权限头
    assert str(excinfo.value) == (
        "GitHub API returned HTTP 404 for GET /repos/radixark/miles/collaborators/actor/permission"
    )
.github/workflows/scripts/comment_ci_command.py infrastructure

脚本中的错误处理改进是本次修复的关键部分,使权限错误更易诊断。

# 在 GitHubAPI._request 方法中,改进 HTTP 错误处理
def _request(self, path, *, method="GET", payload=None, expected_statuses=None, ...):
    ...
    try:
        response = self.urllib.request.urlopen(request, timeout=15)
        ...
    except urllib.error.HTTPError as error:
        # 原错误消息仅为 'GitHub API returned HTTP {error.code}'
        # 改进后包含方法和路径,以及可选的接受权限头,便于调试
        detail = f"GitHub API returned HTTP {error.code} for {method} {path}"
        # GitHub 的 X-Accepted-GitHub-Permissions 头指示了该调用所需的安装权限
        accepted = error.headers.get("X-Accepted-GitHub-Permissions")
        if accepted:
            detail = f"{detail}; accepted permissions: {accepted}"
        # 抛出详细的错误消息,但不包含令牌
        raise CommentCommandError(detail) from error
    except urllib.error.URLError as error:
        ...

评论区精华

CI 命令应用令牌权限修复 other

无实际技术讨论;自动化机器人评论说明手动审查配置。

结论:PR 直接合并,无未解决疑虑。 · 已关闭

风险与影响

风险较低,但需注意:

  • 兼容性风险:如果 GitHub 应用安装未更新权限(Pull requests: write),令牌铸造可能失败。但 PR body 提到 App 已持有该权限,因此无失败窗口。
  • 回归风险:错误消息格式变更可能影响依赖旧消息的监控或日志解析,但测试已覆盖新格式。
  • 安全风险:错误消息现在包含请求路径和权限头,但不包含令牌,符合安全实践。

影响范围限于 CI 命令网关的标签命令功能,修复后标签操作将正常工作,允许后续 CI 工作流启动。影响程度为中等,因为 CI 流程的稳定性得到提升,但变更不涉及训练或推理核心路径。

CI 权限修复 错误消息改进 文档同步更新

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论