diff --git a/services/token-service/main.py b/services/token-service/main.py index 7832bf9..d403e4a 100644 --- a/services/token-service/main.py +++ b/services/token-service/main.py @@ -119,7 +119,7 @@ def get_github_handle_from_workspace_sa(service_account_email: str) -> str | Non Returns ------- str | None - GitHub handle if found, None otherwise. + GitHub handle (normalized to lowercase) if found, None otherwise. """ # For now, require github_handle to be passed in request body # In production, you could map this via metadata or workspace labels @@ -129,16 +129,22 @@ def get_github_handle_from_workspace_sa(service_account_email: str) -> str | Non logger.warning("github_handle not provided in request") return None + # Normalize GitHub handle to lowercase for case-insensitive matching + # GitHub handles are case-insensitive but case-preserving + github_handle_normalized = github_handle.lower() + # Verify this participant exists in Firestore try: - doc_ref = db.collection("participants").document(github_handle) + doc_ref = db.collection("participants").document(github_handle_normalized) doc = doc_ref.get() if not doc.exists: - logger.warning(f"Participant {github_handle} not found in Firestore") + logger.warning( + f"Participant {github_handle_normalized} not found in Firestore" + ) return None - return github_handle + return github_handle_normalized except Exception as e: logger.error(f"Failed to verify participant: {e}") diff --git a/src/aieng_platform_onboard/utils.py b/src/aieng_platform_onboard/utils.py index 1304960..d7b47ce 100644 --- a/src/aieng_platform_onboard/utils.py +++ b/src/aieng_platform_onboard/utils.py @@ -38,6 +38,26 @@ def get_console() -> Console: return console +def normalize_github_handle(github_handle: str) -> str: + """ + Normalize GitHub handle to lowercase for case-insensitive matching. + + GitHub handles are case-insensitive but case-preserving. This function + ensures consistent lookups in Firestore by normalizing to lowercase. + + Parameters + ---------- + github_handle : str + GitHub handle in any case. + + Returns + ------- + str + Normalized (lowercase) GitHub handle. + """ + return github_handle.lower() + + def get_github_user() -> str | None: """ Get GitHub username from environment variable. @@ -145,7 +165,8 @@ def fetch_token_from_service( # noqa: PLR0911 "Authorization": f"Bearer {id_token}", "Content-Type": "application/json", } - payload = {"github_handle": github_handle} + # Normalize GitHub handle for case-insensitive matching + payload = {"github_handle": normalize_github_handle(github_handle)} response = requests.post(url, json=payload, headers=headers, timeout=30) @@ -292,7 +313,9 @@ def get_participant_data( Participant data or None if not found. """ try: - doc_ref = db.collection("participants").document(github_handle) + # Normalize GitHub handle for case-insensitive matching + github_handle_normalized = normalize_github_handle(github_handle) + doc_ref = db.collection("participants").document(github_handle_normalized) doc = doc_ref.get() if not doc.exists: @@ -548,7 +571,9 @@ def check_onboarded_status( Tuple of (success, is_onboarded). """ try: - doc_ref = db.collection("participants").document(github_handle) + # Normalize GitHub handle for case-insensitive matching + github_handle_normalized = normalize_github_handle(github_handle) + doc_ref = db.collection("participants").document(github_handle_normalized) doc = doc_ref.get() if not doc.exists: @@ -633,7 +658,9 @@ def update_onboarded_status( Tuple of (success, error_message). """ try: - doc_ref = db.collection("participants").document(github_handle) + # Normalize GitHub handle for case-insensitive matching + github_handle_normalized = normalize_github_handle(github_handle) + doc_ref = db.collection("participants").document(github_handle_normalized) doc_ref.update( { "onboarded": True,