App-token:推分支建 PR 改走 GitHub App installation token
- github_app:纯标准库 RS256 签 App JWT(PKCS#1/PKCS#8), 换 installation token(现换现用、不缓存),按仓库名查安装 记录,任一步失败回落 None - pr:app_token 路径 push 走 credential helper(token 只进 子进程环境),建 PR 走 REST API(读 default_branch 当 base); 不传 token 时 gh 路径不变 - server:/pr 端点按项目 repo_url 解析仓库名、现换 token, 响应加 auth_via=app|pat,换失败回落 PAT 不报错 - 测试:JWT/换 token/解析 9 个、pr App 路径 6 个、端点级 App 与 PAT 回落 2 个
This commit is contained in:
1 parent
ee4b01c8f6
commit
25d9b3d938
7 files changed
+1060
-20
No files matched your search
+37
-4
@@ -59,7 +59,8 @@ from cloud.db import PostgresIntegrityError as _PgIntegrityError
|
||||
from cloud.db import PostgresOperationalError as _PgOperationalError
|
||||
from cloud.kb import KBStore
|
||||
from cloud.memory import MemoryStore
|
||||
from cloud.pr import PrSkipped, PrStepError, create_task_pr
|
||||
from cloud.pr import (PrSkipped, PrStepError, create_task_pr,
|
||||
parse_git_remote_owner_repo)
|
||||
from cloud.workers import (
|
||||
heartbeat_worker as _registry_heartbeat,
|
||||
list_workers as _registry_list,
|
||||
@@ -100,6 +101,7 @@ from cloud.github_app import (
|
||||
record_installation_repos,
|
||||
remove_installation,
|
||||
remove_installation_repos,
|
||||
resolve_app_token,
|
||||
save_app_config,
|
||||
set_fix_review_task_id,
|
||||
)
|
||||
@@ -1505,6 +1507,11 @@ class CloudControlPlaneHandler(BaseHTTPRequestHandler):
|
||||
pr_skipped 与 reason,任务状态保持 merged 不变;push/pr
|
||||
创建失败时返回 502 并写清哪一步失败,任务同样保持 merged。
|
||||
成功时把 pr_url/pr_number 写回任务并记审计 pr_created。
|
||||
App-token:项目 repo_url 能解析出 github.com 仓库名且
|
||||
库里有该仓库的 App 安装记录时,现换 installation token
|
||||
走 App 路径(响应里 auth_via=app),否则走原来的 gh +
|
||||
PAT 路径(auth_via=pat);换 token 任一步失败都回落
|
||||
PAT,不因此报错。token 只在本次请求内存里出现。
|
||||
"""
|
||||
row = self._fetch_task(task_id)
|
||||
if row is None:
|
||||
@@ -1525,16 +1532,39 @@ class CloudControlPlaneHandler(BaseHTTPRequestHandler):
|
||||
conn = self._db()
|
||||
try:
|
||||
prow = conn.execute(
|
||||
"SELECT auto_pr FROM projects WHERE id = ?",
|
||||
"SELECT auto_pr, repo_url FROM projects WHERE id = ?",
|
||||
(task["project_id"],)).fetchone()
|
||||
finally:
|
||||
conn.close()
|
||||
auto_pr = 0
|
||||
repo_url = None
|
||||
if prow is not None:
|
||||
try:
|
||||
auto_pr = prow["auto_pr"] or 0
|
||||
except (KeyError, IndexError, TypeError):
|
||||
auto_pr = 0
|
||||
try:
|
||||
repo_url = prow["repo_url"]
|
||||
except (KeyError, IndexError, TypeError):
|
||||
repo_url = None
|
||||
app_token = None
|
||||
auth_via = "pat"
|
||||
repo_full_name = None
|
||||
if repo_url:
|
||||
parsed = parse_git_remote_owner_repo(repo_url)
|
||||
if parsed:
|
||||
repo_full_name = "%s/%s" % parsed
|
||||
if repo_full_name:
|
||||
conn = self._db()
|
||||
try:
|
||||
app_token = resolve_app_token(
|
||||
conn, repo_full_name,
|
||||
http_client=getattr(
|
||||
self.server, "pr_app_token_client", None))
|
||||
finally:
|
||||
conn.close()
|
||||
if app_token:
|
||||
auth_via = "app"
|
||||
try:
|
||||
result = create_task_pr(
|
||||
task_id, auto_pr,
|
||||
@@ -1542,7 +1572,9 @@ class CloudControlPlaneHandler(BaseHTTPRequestHandler):
|
||||
self.server, "host_worktrees_dir", None),
|
||||
git_runner=getattr(self.server, "pr_git_runner", None),
|
||||
gh_runner=getattr(self.server, "pr_gh_runner", None),
|
||||
gh_which=getattr(self.server, "pr_gh_which", None))
|
||||
gh_which=getattr(self.server, "pr_gh_which", None),
|
||||
app_token=app_token,
|
||||
github_api=getattr(self.server, "pr_github_api", None))
|
||||
except PrSkipped as exc:
|
||||
self._send_json(200, {
|
||||
"task_id": task_id, "status": task["status"],
|
||||
@@ -1575,7 +1607,8 @@ class CloudControlPlaneHandler(BaseHTTPRequestHandler):
|
||||
result["pr_url"])
|
||||
self._send_json(200, dict(task, pr_url=result["pr_url"],
|
||||
pr_number=result["pr_number"],
|
||||
branch=result["branch"]))
|
||||
branch=result["branch"],
|
||||
auth_via=auth_via))
|
||||
|
||||
def _heartbeat_task(self, user_id, task_id):
|
||||
row = self._fetch_task(task_id)
|
||||
|
||||
Reference in new issue
Block a user