fix: remove keycloak_auth cookie requirement for webhook secrets endpoint (#12525)

Co-authored-by: openhands <openhands@all-hands.dev>
This commit is contained in:
Tim O'Farrell
2026-01-21 09:17:19 -07:00
committed by GitHub
parent 650bf8c0c0
commit 8ea4813936
3 changed files with 7 additions and 15 deletions

View File

@@ -163,6 +163,7 @@ class SetAuthCookieMiddleware:
'/oauth/device/authorize',
'/oauth/device/token',
'/api/v1/web-client/config',
'/api/v1/webhooks/secrets',
)
if path in ignore_paths:
return False

View File

@@ -114,7 +114,6 @@ class LiveStatusAppConversationService(AppConversationServiceBase):
openhands_provider_base_url: str | None
access_token_hard_timeout: timedelta | None
app_mode: str | None = None
keycloak_auth_cookie: str | None = None
tavily_api_key: str | None = None
async def search_app_conversations(
@@ -602,10 +601,6 @@ class LiveStatusAppConversationService(AppConversationServiceBase):
)
headers = {'X-Access-Token': access_token}
# Include keycloak_auth cookie in headers if app_mode is SaaS
if self.app_mode == 'saas' and self.keycloak_auth_cookie:
headers['Cookie'] = f'keycloak_auth={self.keycloak_auth_cookie}'
secrets[secret_name] = LookupSecret(
url=self.web_url + '/api/v1/webhooks/secrets',
headers=headers,
@@ -1400,17 +1395,14 @@ class LiveStatusAppConversationServiceInjector(AppConversationServiceInjector):
if isinstance(sandbox_service, DockerSandboxService):
web_url = f'http://host.docker.internal:{sandbox_service.host_port}'
# Get app_mode and keycloak_auth cookie for SaaS mode
# Get app_mode for SaaS mode
app_mode = None
keycloak_auth_cookie = None
try:
from openhands.server.shared import server_config
app_mode = (
server_config.app_mode.value if server_config.app_mode else None
)
if request and server_config.app_mode == AppMode.SAAS:
keycloak_auth_cookie = request.cookies.get('keycloak_auth')
except (ImportError, AttributeError):
# If server_config is not available (e.g., in tests), continue without it
pass
@@ -1440,6 +1432,5 @@ class LiveStatusAppConversationServiceInjector(AppConversationServiceInjector):
openhands_provider_base_url=config.openhands_provider_base_url,
access_token_hard_timeout=access_token_hard_timeout,
app_mode=app_mode,
keycloak_auth_cookie=keycloak_auth_cookie,
tavily_api_key=tavily_api_key,
)

View File

@@ -75,7 +75,6 @@ class TestLiveStatusAppConversationService:
openhands_provider_base_url='https://provider.example.com',
access_token_hard_timeout=None,
app_mode='test',
keycloak_auth_cookie=None,
)
# Mock user info
@@ -150,10 +149,9 @@ class TestLiveStatusAppConversationService:
@pytest.mark.asyncio
async def test_setup_secrets_for_git_providers_with_saas_mode(self):
"""Test _setup_secrets_for_git_providers with SaaS mode (includes keycloak cookie)."""
"""Test _setup_secrets_for_git_providers with SaaS mode uses LookupSecret with X-Access-Token."""
# Arrange
self.service.app_mode = 'saas'
self.service.keycloak_auth_cookie = 'test_cookie'
base_secrets = {}
self.mock_user_context.get_secrets.return_value = base_secrets
self.mock_jwt_service.create_jws_token.return_value = 'test_access_token'
@@ -173,8 +171,10 @@ class TestLiveStatusAppConversationService:
assert 'GITLAB_TOKEN' in result
lookup_secret = result['GITLAB_TOKEN']
assert isinstance(lookup_secret, LookupSecret)
assert 'Cookie' in lookup_secret.headers
assert lookup_secret.headers['Cookie'] == 'keycloak_auth=test_cookie'
assert 'X-Access-Token' in lookup_secret.headers
assert lookup_secret.headers['X-Access-Token'] == 'test_access_token'
# Verify no cookie is included (authentication is via X-Access-Token only)
assert 'Cookie' not in lookup_secret.headers
# Verify description is included
assert lookup_secret.description == 'GITLAB authentication token'