mirror of
https://github.com/Sea-Haven-Industries/open-swe.git
synced 2026-10-02 22:43:27 +00:00
66 lines
2.3 KiB
Python
66 lines
2.3 KiB
Python
|
|
"""GitHub repository access checks for dashboard actions."""
|
||
|
|
|
||
|
|
from __future__ import annotations
|
||
|
|
|
||
|
|
import httpx
|
||
|
|
from fastapi import HTTPException
|
||
|
|
|
||
|
|
from .profiles import get_valid_access_token
|
||
|
|
from .review_styles import normalize_repo_full_name
|
||
|
|
|
||
|
|
|
||
|
|
def _raise_for_github_repo_status(status_code: int) -> None:
|
||
|
|
if status_code == 401:
|
||
|
|
raise HTTPException(401, "github token expired, re-login required")
|
||
|
|
if status_code == 404:
|
||
|
|
raise HTTPException(404, "repository not found")
|
||
|
|
if status_code == 403:
|
||
|
|
raise HTTPException(403, "no access to this private repository")
|
||
|
|
if status_code != 200:
|
||
|
|
raise HTTPException(502, f"github API error ({status_code})")
|
||
|
|
|
||
|
|
|
||
|
|
async def assert_repo_access(full_name: str, token: str) -> str:
|
||
|
|
full_name = normalize_repo_full_name(full_name)
|
||
|
|
headers = {
|
||
|
|
"Authorization": f"Bearer {token}",
|
||
|
|
"Accept": "application/vnd.github+json",
|
||
|
|
"X-GitHub-Api-Version": "2022-11-28",
|
||
|
|
}
|
||
|
|
owner, name = full_name.split("/", 1)
|
||
|
|
async with httpx.AsyncClient() as client:
|
||
|
|
response = await client.get(
|
||
|
|
f"https://api.github.com/repos/{owner}/{name}",
|
||
|
|
headers=headers,
|
||
|
|
)
|
||
|
|
_raise_for_github_repo_status(response.status_code)
|
||
|
|
return full_name
|
||
|
|
|
||
|
|
|
||
|
|
async def require_repo_access_for_user(login: str, full_name: str) -> str:
|
||
|
|
token = await get_valid_access_token(login)
|
||
|
|
if not token:
|
||
|
|
raise HTTPException(401, "github token unavailable, re-login required")
|
||
|
|
try:
|
||
|
|
await assert_repo_access(full_name, token)
|
||
|
|
except HTTPException as exc:
|
||
|
|
if exc.status_code != 401:
|
||
|
|
raise
|
||
|
|
token = await get_valid_access_token(login, force_refresh=True)
|
||
|
|
if not token:
|
||
|
|
raise HTTPException(401, "github token expired, re-login required") from exc
|
||
|
|
await assert_repo_access(full_name, token)
|
||
|
|
return token
|
||
|
|
|
||
|
|
|
||
|
|
async def repo_config_for_user(login: str, full_name: str | None) -> dict[str, str] | None:
|
||
|
|
if not isinstance(full_name, str) or not full_name.strip():
|
||
|
|
return None
|
||
|
|
try:
|
||
|
|
normalized = normalize_repo_full_name(full_name)
|
||
|
|
except ValueError as exc:
|
||
|
|
raise HTTPException(422, str(exc)) from exc
|
||
|
|
await require_repo_access_for_user(login, normalized)
|
||
|
|
owner, name = normalized.split("/", 1)
|
||
|
|
return {"owner": owner, "name": name}
|