Skip to content

Commit ea74aab

Browse files
authored
Merge pull request #135 from EuniAI/fix-issue-133
Fix issue 133
2 parents 0a77239 + 487e691 commit ea74aab

5 files changed

Lines changed: 65 additions & 26 deletions

File tree

prometheus/app/api/routes/repository.py

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -15,32 +15,26 @@
1515
from prometheus.app.services.user_service import UserService
1616
from prometheus.configuration.config import settings
1717
from prometheus.exceptions.server_exception import ServerException
18+
from prometheus.utils.github_utils import is_repository_public
1819

1920
router = APIRouter()
2021

2122

22-
async def get_github_token(request: Request, github_token: str) -> str:
23-
"""Retrieve GitHub token from the request or user profile."""
23+
async def get_github_token(request: Request, github_token: str | None = None) -> str | None:
24+
"""Retrieve GitHub token from the request or user profile.
25+
26+
Returns:
27+
str | None: GitHub token if available, None for public repositories
28+
"""
2429
# If the token is provided in the request, use it directly
2530
if github_token:
2631
return github_token
27-
# If the token is not provided, fetch it from the user profile if logged in
28-
# Check if the user is authenticated
29-
if not settings.ENABLE_AUTHENTICATION:
30-
# If the user is not authenticated, raise an exception
31-
raise ServerException(
32-
code=400, message="GitHub token is required, please provide it or log in"
33-
)
34-
# If the user is authenticated, get the user service and fetch the token
35-
user_service: UserService = request.app.state.service["user_service"]
36-
user = await user_service.get_user_by_id(request.state.user_id)
37-
github_token = user.github_token if user else None
3832

39-
# If the token is still not available, raise an exception
40-
if not github_token:
41-
raise ServerException(
42-
code=400, message="Either provide a GitHub token or set it in your user profile"
43-
)
33+
# If the user is authenticated, get the user service and fetch the token
34+
if settings.ENABLE_AUTHENTICATION:
35+
user_service: UserService = request.app.state.service["user_service"]
36+
user = await user_service.get_user_by_id(request.state.user_id)
37+
github_token = user.github_token if user else None
4438
return github_token
4539

4640

@@ -86,17 +80,25 @@ async def upload_github_repository(
8680
message=f"You have reached the maximum number of repositories ({settings.DEFAULT_USER_REPOSITORY_LIMIT}). Please delete some repositories before uploading new ones.",
8781
)
8882

89-
# Get the GitHub token
83+
# Get the GitHub token (may be None for public repositories)
9084
github_token = await get_github_token(request, upload_repository_request.github_token)
9185

86+
# Check if the repository is public or private
87+
is_repository_public_ = await is_repository_public(upload_repository_request.https_url)
88+
if not is_repository_public_ and not github_token:
89+
raise ServerException(
90+
code=400,
91+
message="This appears to be a private repository. Please provide a GitHub token.",
92+
)
93+
9294
# Clone the repository
9395
try:
9496
saved_path = await repository_service.clone_github_repo(
9597
github_token, upload_repository_request.https_url, upload_repository_request.commit_id
9698
)
9799
except git.exc.GitCommandError:
98100
raise ServerException(
99-
code=400, message=f"Unable to clone {upload_repository_request.https_url}."
101+
code=400, message=f"Unable to clone {upload_repository_request.https_url}"
100102
)
101103

102104
# Build and save the knowledge graph from the cloned repository

prometheus/app/models/requests/repository.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ class UploadRepositoryRequest(BaseModel):
1414
)
1515
github_token: str | None = Field(
1616
default=None,
17-
description="Optional GitHub token for repository clone",
17+
description="GitHub token for private repository clone. Optional for public repositories.",
1818
max_length=100,
1919
)
2020

prometheus/app/services/repository_service.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ def get_new_playground_path(self) -> Path:
5858
return new_path
5959

6060
async def clone_github_repo(
61-
self, github_token: str, https_url: str, commit_id: Optional[str] = None
61+
self, github_token: str | None, https_url: str, commit_id: Optional[str] = None
6262
) -> Path:
6363
"""Clones a GitHub repository to the local workspace.
6464
@@ -67,7 +67,7 @@ async def clone_github_repo(
6767
the operation may be skipped.
6868
6969
Args:
70-
github_token: GitHub access token for authentication.
70+
github_token: GitHub access token for authentication. None for public repositories.
7171
https_url: HTTPS URL of the GitHub repository.
7272
commit_id: Optional specific commit to check out.
7373

prometheus/git/git_repository.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,19 +51,24 @@ def _set_default_branch(self):
5151
self.default_branch = self.repo.active_branch.name
5252

5353
async def from_clone_repository(
54-
self, https_url: str, github_access_token: str, target_directory: Path
54+
self, https_url: str, github_access_token: str | None, target_directory: Path
5555
):
5656
"""Clone a remote repository using HTTPS authentication.
5757
5858
Args:
5959
https_url: HTTPS URL of the remote repository.
60-
github_access_token: GitHub access token for authentication.
60+
github_access_token: GitHub access token for authentication. None for public repositories.
6161
target_directory: Directory where the repository will be cloned.
6262
6363
Returns:
6464
Repo: GitPython Repo object representing the cloned repository.
6565
"""
66-
https_url = https_url.replace("https://", f"https://x-access-token:{github_access_token}@")
66+
# Only modify the URL with token authentication if a token is provided
67+
if github_access_token:
68+
https_url = https_url.replace(
69+
"https://", f"https://x-access-token:{github_access_token}@"
70+
)
71+
6772
repo_name = https_url.split("/")[-1].split(".")[0]
6873
local_path = target_directory / repo_name
6974
if local_path.exists():

prometheus/utils/github_utils.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,35 @@ async def get_github_issue(repo: str, issue_number: int, github_token: str) -> D
5555
"state": issue_data["state"],
5656
"html_url": issue_data["html_url"],
5757
}
58+
59+
60+
async def is_repository_public(https_url: str) -> bool:
61+
"""
62+
Check if a GitHub repository is public by making an unauthenticated request.
63+
64+
Args:
65+
https_url: HTTPS URL of the GitHub repository
66+
67+
Returns:
68+
bool: True if the repository is public, False if private or not found
69+
"""
70+
# Extract owner and repo from HTTPS URL
71+
# Example: https://github.com/owner/repo.git -> owner/repo
72+
url_parts = https_url.replace("https://github.com/", "").replace(".git", "")
73+
owner, repo = url_parts.split("/")
74+
# Make unauthenticated request to check repository visibility
75+
async with httpx.AsyncClient() as client:
76+
response = await client.get(
77+
f"https://api.github.com/repos/{owner}/{repo}",
78+
headers={"Accept": "application/vnd.github.v3+json"},
79+
)
80+
81+
if response.status_code == 200:
82+
# Repository exists and is accessible without authentication (public)
83+
return True
84+
elif response.status_code == 404:
85+
# Repository not found or private (requires authentication)
86+
return False
87+
else:
88+
# Other error, assume private for safety
89+
return False

0 commit comments

Comments
 (0)