fix: use GitHub App installation token for PR creation instead of user token (#1149)

* fix: use GitHub App installation token for PR creation instead of user token

* fix: move installation token fetch after no-changes check to avoid unnecessary API call
This commit is contained in:
Aran Yogesh 2026-03-30 12:47:57 -07:00 • committed by GitHub
parent 7d1004ad66
commit 86307affe4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 34 additions and 26 deletions

View file

@ -36,6 +36,7 @@ from ..utils.github import (
git_has_unpushed_commits,
git_push,
)
from ..utils.github_app import get_github_app_installation_token
from ..utils.github_token import get_github_token
from ..utils.sandbox_paths import aresolve_repo_dir
from ..utils.sandbox_state import get_sandbox_backend
@ -98,6 +99,11 @@ async def open_pr_if_needed(
pr_body = add_pr_collaboration_note(pr_body, user_identity)
commit_message = add_user_coauthor_trailer(commit_message, user_identity)
installation_token = await get_github_app_installation_token()
if not installation_token:
logger.error("Failed to get GitHub App installation token for thread %s", thread_id)
return None
if not thread_id:
raise ValueError("No thread_id found in config")
@ -154,23 +160,22 @@ async def open_pr_if_needed(
await asyncio.to_thread(git_add_all, sandbox_backend, repo_dir)
await asyncio.to_thread(git_commit, sandbox_backend, repo_dir, commit_message)
if github_token:
await asyncio.to_thread(
git_push, sandbox_backend, repo_dir, target_branch, github_token
)
await asyncio.to_thread(
git_push, sandbox_backend, repo_dir, target_branch, installation_token
)
base_branch = await get_github_default_branch(repo_owner, repo_name, github_token)
logger.info("Using base branch: %s", base_branch)
base_branch = await get_github_default_branch(repo_owner, repo_name, installation_token)
logger.info("Using base branch: %s", base_branch)
await create_github_pr(
repo_owner=repo_owner,
repo_name=repo_name,
github_token=github_token,
title=pr_title,
head_branch=target_branch,
base_branch=base_branch,
body=pr_body,
)
await create_github_pr(
repo_owner=repo_owner,
repo_name=repo_name,
github_token=installation_token,
title=pr_title,
head_branch=target_branch,
base_branch=base_branch,
body=pr_body,
)
logger.info("After-agent middleware completed successfully")

View file

@ -24,6 +24,7 @@ from ..utils.github import (
git_has_unpushed_commits,
git_push,
)
from ..utils.github_app import get_github_app_installation_token
from ..utils.github_token import get_github_token
from ..utils.sandbox_paths import resolve_repo_dir
from ..utils.sandbox_state import get_sandbox_backend_sync
@ -149,6 +150,14 @@ def commit_and_open_pr(
if not (has_uncommitted_changes or has_unpushed_commits):
return {"success": False, "error": "No changes detected", "pr_url": None}
installation_token = asyncio.run(get_github_app_installation_token())
if not installation_token:
return {
"success": False,
"error": "Failed to get GitHub App installation token",
"pr_url": None,
}
metadata = config.get("metadata", {})
branch_name = metadata.get("branch_name")
current_branch = git_current_branch(sandbox_backend, repo_dir)
@ -188,15 +197,7 @@ def commit_and_open_pr(
"pr_url": None,
}
if not github_token:
logger.error("commit_and_open_pr missing GitHub token for thread %s", thread_id)
return {
"success": False,
"error": "Missing GitHub token",
"pr_url": None,
}
push_result = git_push(sandbox_backend, repo_dir, target_branch, github_token)
push_result = git_push(sandbox_backend, repo_dir, target_branch, installation_token)
if push_result.exit_code != 0:
return {
"success": False,
@ -204,12 +205,14 @@ def commit_and_open_pr(
"pr_url": None,
}
base_branch = asyncio.run(get_github_default_branch(repo_owner, repo_name, github_token))
base_branch = asyncio.run(
get_github_default_branch(repo_owner, repo_name, installation_token)
)
pr_url, _pr_number, pr_existing = asyncio.run(
create_github_pr(
repo_owner=repo_owner,
repo_name=repo_name,
github_token=github_token,
github_token=installation_token,
title=title,
head_branch=target_branch,
base_branch=base_branch,