Fix GraphQL URL configuration for GitHub Enterprise Server (#10725)

Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
Rohit Malhotra 2025-08-30 18:06:00 -04:00 committed by GitHub
parent c648b6f74f
commit 9d6afa09b6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 96 additions and 1 deletions

View File

@ -42,6 +42,7 @@ class GitHubService(
"""
BASE_URL = 'https://api.github.com'
GRAPHQL_URL = 'https://api.github.com/graphql'
token: SecretStr = SecretStr('')
refresh = False
@ -62,6 +63,7 @@ class GitHubService(
if base_domain and base_domain != 'github.com':
self.BASE_URL = f'https://{base_domain}/api/v3'
self.GRAPHQL_URL = f'https://{base_domain}/api/graphql'
self.external_auth_id = external_auth_id
self.external_auth_token = external_auth_token

View File

@ -18,9 +18,11 @@ class GitHubMixinBase(BaseGitService):
"""
BASE_URL: str
GRAPHQL_URL: str
token: SecretStr
refresh: bool
external_auth_id: str | None
base_domain: str | None
async def _get_github_headers(self) -> dict:
"""Retrieve the GH Token from settings store to construct the headers."""
@ -86,8 +88,9 @@ class GitHubMixinBase(BaseGitService):
try:
async with httpx.AsyncClient() as client:
github_headers = await self._get_github_headers()
response = await client.post(
f'{self.BASE_URL}/graphql',
self.GRAPHQL_URL,
headers=github_headers,
json={'query': query, 'variables': variables},
)

View File

@ -340,3 +340,93 @@ async def test_github_get_user_organizations_error_handling():
# Should return empty list on error
assert orgs == []
@pytest.mark.asyncio
async def test_github_service_base_url_configuration():
"""Test that BASE_URL is correctly configured based on base_domain."""
# Test default GitHub.com configuration
service = GitHubService(user_id=None, token=SecretStr('test-token'))
assert service.BASE_URL == 'https://api.github.com'
# Test GitHub Enterprise Server configuration
service = GitHubService(
user_id=None, token=SecretStr('test-token'), base_domain='github.enterprise.com'
)
assert service.BASE_URL == 'https://github.enterprise.com/api/v3'
# Test that github.com base_domain doesn't change the URL
service = GitHubService(
user_id=None, token=SecretStr('test-token'), base_domain='github.com'
)
assert service.BASE_URL == 'https://api.github.com'
@pytest.mark.asyncio
async def test_github_service_graphql_url_enterprise_server():
"""Test that GraphQL URL is correctly constructed for GitHub Enterprise Server."""
# Mock httpx.AsyncClient for testing GraphQL calls
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {'data': {'viewer': {'login': 'test-user'}}}
mock_response.raise_for_status = Mock()
mock_client = AsyncMock()
mock_client.post.return_value = mock_response
mock_client.__aenter__.return_value = mock_client
mock_client.__aexit__.return_value = None
with patch('httpx.AsyncClient', return_value=mock_client):
# Test GitHub Enterprise Server
service = GitHubService(
user_id=None,
token=SecretStr('test-token'),
base_domain='github.enterprise.com',
)
query = 'query { viewer { login } }'
variables = {}
await service.execute_graphql_query(query, variables)
# Verify the GraphQL request was made to the CORRECT URL
# For GitHub Enterprise Server, it should be /api/graphql, not /api/v3/graphql
mock_client.post.assert_called_once()
call_args = mock_client.post.call_args
actual_url = call_args[0][0] # First positional argument is the URL
# After the fix, GraphQL URL should be correctly constructed for GitHub Enterprise Server
# The URL should be /api/graphql, not /api/v3/graphql
assert actual_url == 'https://github.enterprise.com/api/graphql'
@pytest.mark.asyncio
async def test_github_service_graphql_url_github_com():
"""Test that GraphQL URL is correctly constructed for GitHub.com."""
# Mock httpx.AsyncClient for testing GraphQL calls
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {'data': {'viewer': {'login': 'test-user'}}}
mock_response.raise_for_status = Mock()
mock_client = AsyncMock()
mock_client.post.return_value = mock_response
mock_client.__aenter__.return_value = mock_client
mock_client.__aexit__.return_value = None
with patch('httpx.AsyncClient', return_value=mock_client):
# Test GitHub.com (should work correctly)
service = GitHubService(user_id=None, token=SecretStr('test-token'))
query = 'query { viewer { login } }'
variables = {}
await service.execute_graphql_query(query, variables)
# Verify the GraphQL request was made to the correct URL for GitHub.com
mock_client.post.assert_called_once()
call_args = mock_client.post.call_args
actual_url = call_args[0][0] # First positional argument is the URL
# This should be correct for GitHub.com
assert actual_url == 'https://api.github.com/graphql'