Skip to content

🎨 Palette: Add friendly API pre-flight check#121

Merged
abhimehro merged 2 commits intomainfrom
palette-ux-api-check-14442985379801282171
Jan 22, 2026
Merged

🎨 Palette: Add friendly API pre-flight check#121
abhimehro merged 2 commits intomainfrom
palette-ux-api-check-14442985379801282171

Conversation

@google-labs-jules
Copy link

Added a pre-flight check to validate API credentials before starting the sync process. This improves UX by providing clear, actionable error messages for authentication failures instead of a screen full of generic errors.


PR created automatically by Jules for task 14442985379801282171 started by @abhimehro

Added a `check_api_access` function that runs before the main sync process.
This validates credentials (Token/Profile ID) and provides specific, actionable
error messages for 401, 403, and 404 responses, preventing cascade failures
and helping users debug configuration issues faster.

- Validates Token and Profile ID validity immediately
- Returns helpful "Check your token at URL" messages
- Avoids retrying on permanent Auth errors
@google-labs-jules
Copy link
Author

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@trunk-io
Copy link

trunk-io bot commented Jan 21, 2026

😎 Merged manually by Abhi Mehrotra (@abhimehro) - details.

**Action:** Use `\033[K` for dynamic CLI updates and favor visual bars for waits > 5 seconds.

## 2024-05-24 - Fail Fast & Friendly
**Learning:** In CLI tools involving APIs, cascade failures (hundreds of "Failed to X") caused by basic auth issues (401/403) are overwhelming and confusing. A dedicated "Pre-flight Check" that validates credentials *before* attempting the main workload allows for specific, actionable error messages (e.g. "Check your token at [URL]") instead of generic HTTP errors.

Check notice

Code scanning / Remark-lint (reported by Codacy)

Warn when references to undefined definitions are found. Note

[no-undefined-references] Found reference to undefined definition
**Action:** Use `\033[K` for dynamic CLI updates and favor visual bars for waits > 5 seconds.

## 2024-05-24 - Fail Fast & Friendly
**Learning:** In CLI tools involving APIs, cascade failures (hundreds of "Failed to X") caused by basic auth issues (401/403) are overwhelming and confusing. A dedicated "Pre-flight Check" that validates credentials *before* attempting the main workload allows for specific, actionable error messages (e.g. "Check your token at [URL]") instead of generic HTTP errors.

Check notice

Code scanning / Remark-lint (reported by Codacy)

Warn when shortcut reference links are used. Note

[no-shortcut-reference-link] Use the trailing [] on reference links
resp = client.get(url)
resp.raise_for_status()
return True
except httpx.HTTPStatusError as e:

Check warning

Code scanning / Pylint (reported by Codacy)

Variable name "e" doesn't conform to snake_case naming style Warning

Variable name "e" doesn't conform to snake_case naming style
except httpx.HTTPStatusError as e:
code = e.response.status_code
if code == 401:
log.critical(f"{Colors.FAIL}❌ Authentication Failed: The API Token is invalid.{Colors.ENDC}")

Check warning

Code scanning / Pylint (reported by Codacy)

Line too long (105/100) Warning

Line too long (105/100)
code = e.response.status_code
if code == 401:
log.critical(f"{Colors.FAIL}❌ Authentication Failed: The API Token is invalid.{Colors.ENDC}")
log.critical(f"{Colors.FAIL} Please check your token at: https://controld.com/account/manage-account{Colors.ENDC}")

Check warning

Code scanning / Pylint (reported by Codacy)

Line too long (129/100) Warning

Line too long (129/100)
log.critical(f"{Colors.FAIL}❌ Authentication Failed: The API Token is invalid.{Colors.ENDC}")
log.critical(f"{Colors.FAIL} Please check your token at: https://controld.com/account/manage-account{Colors.ENDC}")
elif code == 403:
log.critical(f"{Colors.FAIL}🚫 Access Denied: Token lacks permission for Profile {profile_id}.{Colors.ENDC}")

Check warning

Code scanning / Pylint (reported by Codacy)

Line too long (120/100) Warning

Line too long (120/100)
elif code == 403:
log.critical(f"{Colors.FAIL}🚫 Access Denied: Token lacks permission for Profile {profile_id}.{Colors.ENDC}")
elif code == 404:
log.critical(f"{Colors.FAIL}🔍 Profile Not Found: The ID '{profile_id}' does not exist.{Colors.ENDC}")

Check warning

Code scanning / Pylint (reported by Codacy)

Line too long (113/100) Warning

Line too long (113/100)
log.critical(f"{Colors.FAIL}🚫 Access Denied: Token lacks permission for Profile {profile_id}.{Colors.ENDC}")
elif code == 404:
log.critical(f"{Colors.FAIL}🔍 Profile Not Found: The ID '{profile_id}' does not exist.{Colors.ENDC}")
log.critical(f"{Colors.FAIL} Please verify the Profile ID from your Control D Dashboard URL.{Colors.ENDC}")

Check warning

Code scanning / Pylint (reported by Codacy)

Line too long (121/100) Warning

Line too long (121/100)
else:
log.error(f"API Access Check Failed ({code}): {e}")
return False
except httpx.RequestError as e:

Check warning

Code scanning / Pylint (reported by Codacy)

Variable name "e" doesn't conform to snake_case naming style Warning

Variable name "e" doesn't conform to snake_case naming style
except httpx.HTTPStatusError as e:
code = e.response.status_code
if code == 401:
log.critical(f"{Colors.FAIL}❌ Authentication Failed: The API Token is invalid.{Colors.ENDC}")

Check warning

Code scanning / Prospector (reported by Codacy)

Use lazy % formatting in logging functions (logging-fstring-interpolation) Warning

Use lazy % formatting in logging functions (logging-fstring-interpolation)
code = e.response.status_code
if code == 401:
log.critical(f"{Colors.FAIL}❌ Authentication Failed: The API Token is invalid.{Colors.ENDC}")
log.critical(f"{Colors.FAIL} Please check your token at: https://controld.com/account/manage-account{Colors.ENDC}")

Check warning

Code scanning / Prospector (reported by Codacy)

Use lazy % formatting in logging functions (logging-fstring-interpolation) Warning

Use lazy % formatting in logging functions (logging-fstring-interpolation)
log.critical(f"{Colors.FAIL}❌ Authentication Failed: The API Token is invalid.{Colors.ENDC}")
log.critical(f"{Colors.FAIL} Please check your token at: https://controld.com/account/manage-account{Colors.ENDC}")
elif code == 403:
log.critical(f"{Colors.FAIL}🚫 Access Denied: Token lacks permission for Profile {profile_id}.{Colors.ENDC}")

Check warning

Code scanning / Prospector (reported by Codacy)

Use lazy % formatting in logging functions (logging-fstring-interpolation) Warning

Use lazy % formatting in logging functions (logging-fstring-interpolation)
elif code == 403:
log.critical(f"{Colors.FAIL}🚫 Access Denied: Token lacks permission for Profile {profile_id}.{Colors.ENDC}")
elif code == 404:
log.critical(f"{Colors.FAIL}🔍 Profile Not Found: The ID '{profile_id}' does not exist.{Colors.ENDC}")

Check warning

Code scanning / Prospector (reported by Codacy)

Use lazy % formatting in logging functions (logging-fstring-interpolation) Warning

Use lazy % formatting in logging functions (logging-fstring-interpolation)
log.critical(f"{Colors.FAIL}🚫 Access Denied: Token lacks permission for Profile {profile_id}.{Colors.ENDC}")
elif code == 404:
log.critical(f"{Colors.FAIL}🔍 Profile Not Found: The ID '{profile_id}' does not exist.{Colors.ENDC}")
log.critical(f"{Colors.FAIL} Please verify the Profile ID from your Control D Dashboard URL.{Colors.ENDC}")

Check warning

Code scanning / Prospector (reported by Codacy)

Use lazy % formatting in logging functions (logging-fstring-interpolation) Warning

Use lazy % formatting in logging functions (logging-fstring-interpolation)
log.critical(f"{Colors.FAIL}🔍 Profile Not Found: The ID '{profile_id}' does not exist.{Colors.ENDC}")
log.critical(f"{Colors.FAIL} Please verify the Profile ID from your Control D Dashboard URL.{Colors.ENDC}")
else:
log.error(f"API Access Check Failed ({code}): {e}")

Check warning

Code scanning / Prospector (reported by Codacy)

Use lazy % formatting in logging functions (logging-fstring-interpolation) Warning

Use lazy % formatting in logging functions (logging-fstring-interpolation)
log.error(f"API Access Check Failed ({code}): {e}")
return False
except httpx.RequestError as e:
log.error(f"Network Error during access check: {e}")

Check warning

Code scanning / Prospector (reported by Codacy)

Use lazy % formatting in logging functions (logging-fstring-interpolation) Warning

Use lazy % formatting in logging functions (logging-fstring-interpolation)
resp = client.get(url)
resp.raise_for_status()
return True
except httpx.HTTPStatusError as e:

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Variable name "e" doesn't conform to snake_case naming style Warning

Variable name "e" doesn't conform to snake_case naming style
except httpx.HTTPStatusError as e:
code = e.response.status_code
if code == 401:
log.critical(f"{Colors.FAIL}❌ Authentication Failed: The API Token is invalid.{Colors.ENDC}")

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Line too long (105/100) Warning

Line too long (105/100)
code = e.response.status_code
if code == 401:
log.critical(f"{Colors.FAIL}❌ Authentication Failed: The API Token is invalid.{Colors.ENDC}")
log.critical(f"{Colors.FAIL} Please check your token at: https://controld.com/account/manage-account{Colors.ENDC}")

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Line too long (129/100) Warning

Line too long (129/100)
log.critical(f"{Colors.FAIL}❌ Authentication Failed: The API Token is invalid.{Colors.ENDC}")
log.critical(f"{Colors.FAIL} Please check your token at: https://controld.com/account/manage-account{Colors.ENDC}")
elif code == 403:
log.critical(f"{Colors.FAIL}🚫 Access Denied: Token lacks permission for Profile {profile_id}.{Colors.ENDC}")

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Line too long (120/100) Warning

Line too long (120/100)
elif code == 403:
log.critical(f"{Colors.FAIL}🚫 Access Denied: Token lacks permission for Profile {profile_id}.{Colors.ENDC}")
elif code == 404:
log.critical(f"{Colors.FAIL}🔍 Profile Not Found: The ID '{profile_id}' does not exist.{Colors.ENDC}")

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Line too long (113/100) Warning

Line too long (113/100)
log.critical(f"{Colors.FAIL}❌ Authentication Failed: The API Token is invalid.{Colors.ENDC}")
log.critical(f"{Colors.FAIL} Please check your token at: https://controld.com/account/manage-account{Colors.ENDC}")
elif code == 403:
log.critical(f"{Colors.FAIL}🚫 Access Denied: Token lacks permission for Profile {profile_id}.{Colors.ENDC}")

Check notice

Code scanning / Pylintpython3 (reported by Codacy)

Use lazy % formatting in logging functions Note

Use lazy % formatting in logging functions
elif code == 403:
log.critical(f"{Colors.FAIL}🚫 Access Denied: Token lacks permission for Profile {profile_id}.{Colors.ENDC}")
elif code == 404:
log.critical(f"{Colors.FAIL}🔍 Profile Not Found: The ID '{profile_id}' does not exist.{Colors.ENDC}")

Check notice

Code scanning / Pylintpython3 (reported by Codacy)

Use lazy % formatting in logging functions Note

Use lazy % formatting in logging functions
log.critical(f"{Colors.FAIL}🚫 Access Denied: Token lacks permission for Profile {profile_id}.{Colors.ENDC}")
elif code == 404:
log.critical(f"{Colors.FAIL}🔍 Profile Not Found: The ID '{profile_id}' does not exist.{Colors.ENDC}")
log.critical(f"{Colors.FAIL} Please verify the Profile ID from your Control D Dashboard URL.{Colors.ENDC}")

Check notice

Code scanning / Pylintpython3 (reported by Codacy)

Use lazy % formatting in logging functions Note

Use lazy % formatting in logging functions
log.critical(f"{Colors.FAIL}🔍 Profile Not Found: The ID '{profile_id}' does not exist.{Colors.ENDC}")
log.critical(f"{Colors.FAIL} Please verify the Profile ID from your Control D Dashboard URL.{Colors.ENDC}")
else:
log.error(f"API Access Check Failed ({code}): {e}")

Check notice

Code scanning / Pylintpython3 (reported by Codacy)

Use lazy % formatting in logging functions Note

Use lazy % formatting in logging functions
log.error(f"API Access Check Failed ({code}): {e}")
return False
except httpx.RequestError as e:
log.error(f"Network Error during access check: {e}")

Check notice

Code scanning / Pylintpython3 (reported by Codacy)

Use lazy % formatting in logging functions Note

Use lazy % formatting in logging functions
@abhimehro abhimehro marked this pull request as ready for review January 22, 2026 10:07
Copilot AI review requested due to automatic review settings January 22, 2026 10:07
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a pre-flight API validation check to improve user experience when authentication or authorization fails. Instead of receiving a cascade of generic HTTP errors during the sync process, users now get clear, actionable error messages upfront.

Changes:

  • Added check_api_access() function to validate API credentials and profile access before starting the sync
  • Integrated the pre-flight check into sync_profile() to fail fast with helpful error messages
  • Documented the "Fail Fast & Friendly" pattern in palette.md for future reference

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
main.py Added pre-flight API check function and integrated it at the start of the sync workflow to validate credentials before heavy processing
.Jules/palette.md Documented the learning about failing fast with friendly error messages for API authentication issues

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +345 to +372
def check_api_access(client: httpx.Client, profile_id: str) -> bool:
"""
Verifies API access and Profile existence before starting heavy work.
Returns True if access is good, False otherwise (with helpful logs).
"""
url = f"{API_BASE}/{profile_id}/groups"
try:
# We use a raw request here to avoid the automatic retries of _retry_request
# for auth errors, which are permanent.
resp = client.get(url)
resp.raise_for_status()
return True
except httpx.HTTPStatusError as e:
code = e.response.status_code
if code == 401:
log.critical(f"{Colors.FAIL}❌ Authentication Failed: The API Token is invalid.{Colors.ENDC}")
log.critical(f"{Colors.FAIL} Please check your token at: https://controld.com/account/manage-account{Colors.ENDC}")
elif code == 403:
log.critical(f"{Colors.FAIL}🚫 Access Denied: Token lacks permission for Profile {profile_id}.{Colors.ENDC}")
elif code == 404:
log.critical(f"{Colors.FAIL}🔍 Profile Not Found: The ID '{profile_id}' does not exist.{Colors.ENDC}")
log.critical(f"{Colors.FAIL} Please verify the Profile ID from your Control D Dashboard URL.{Colors.ENDC}")
else:
log.error(f"API Access Check Failed ({code}): {e}")
return False
except httpx.RequestError as e:
log.error(f"Network Error during access check: {e}")
return False
Copy link

Copilot AI Jan 22, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new check_api_access function lacks test coverage. Since the repository has comprehensive test coverage for similar functions (e.g., get_all_existing_rules, push_rules), this function should also have tests to validate the different error scenarios (401, 403, 404) and success case.

Copilot uses AI. Check for mistakes.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @google-lab-jules, please open a new pull request to apply any changes based on the suggestions in this thread. Thanks!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi! I don't see any specific suggestions in this thread. Could you please clarify what changes you'd like me to make? I'm happy to address them!

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Of course! The suggestions were the following: "The new check_api_access function lacks test coverage. Since the repository has comprehensive test coverage for similar functions (e.g., get_all_existing_rules, push_rules), this function should also have tests to validate the different error scenarios (401, 403, 404) and success case." Let me know if this provides proper clarification, but it seems the task would be to potentially add tests to validate the different error scenarios (401, 403, 404). I appreciate your help, @google-lab-jules!

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the clarification! I've added comprehensive tests for check_api_access covering 401, 403, 404, generic HTTP errors, and network errors.

Added unit tests for the `check_api_access` function in `test_main.py`.
The tests cover:
- Success case (returns True)
- 401 Unauthorized (returns False, logs critical)
- 403 Forbidden (returns False, logs critical)
- 404 Not Found (returns False, logs critical)
- Generic HTTP 500 Error (returns False, logs error)
- Network/Request Exception (returns False, logs error)

This ensures the new pre-flight check logic is robust and handles all
expected failure modes correctly.
def test_check_api_access_success(monkeypatch):
m = reload_main_with_env(monkeypatch)
mock_client = MagicMock()
mock_client.get.return_value.raise_for_status.return_value = None

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
mock_client = MagicMock()
mock_client.get.return_value.raise_for_status.return_value = None

assert m.check_api_access(mock_client, "valid_profile") is True

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.

# Simulate 401 response
mock_response = MagicMock()
mock_response.status_code = 401

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.

def test_check_api_access_403(monkeypatch):
m = reload_main_with_env(monkeypatch)
mock_client = MagicMock()

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
def test_check_api_access_403(monkeypatch):
m = reload_main_with_env(monkeypatch)
mock_client = MagicMock()

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
mock_client = MagicMock()

# Simulate 500 response
mock_response = MagicMock()

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.

# Simulate 500 response
mock_response = MagicMock()
mock_response.status_code = 500

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
m = reload_main_with_env(monkeypatch)
mock_client = MagicMock()

# Simulate network error

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
mock_client = MagicMock()

# Simulate network error
error = httpx.RequestError("Network failure", request=MagicMock())

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.

# Simulate network error
error = httpx.RequestError("Network failure", request=MagicMock())
mock_client.get.side_effect = error

Check notice

Code scanning / Bandit

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
assert m.check_api_access(mock_client, "invalid_token") is False
assert mock_log.critical.call_count >= 1
# Check for authentication failed message
args = str(mock_log.critical.call_args_list)

Check warning

Code scanning / Pylint (reported by Codacy)

Missing function docstring Warning test

Missing function docstring
m = reload_main_with_env(monkeypatch)
mock_client = MagicMock()

# Simulate 403 response

Check warning

Code scanning / Pylint (reported by Codacy)

Missing function docstring Warning test

Missing function docstring
mock_client = MagicMock()

# Simulate 403 response
mock_response = MagicMock()

Check warning

Code scanning / Pylint (reported by Codacy)

Variable name "m" doesn't conform to snake_case naming style Warning test

Variable name "m" doesn't conform to snake_case naming style
# Simulate 404 response
mock_response = MagicMock()
mock_response.status_code = 404
error = httpx.HTTPStatusError("404 Not Found", request=MagicMock(), response=mock_response)

Check warning

Code scanning / Pylint (reported by Codacy)

Missing function docstring Warning test

Missing function docstring
mock_response = MagicMock()
mock_response.status_code = 404
error = httpx.HTTPStatusError("404 Not Found", request=MagicMock(), response=mock_response)
mock_client.get.return_value.raise_for_status.side_effect = error

Check warning

Code scanning / Pylint (reported by Codacy)

Variable name "m" doesn't conform to snake_case naming style Warning test

Variable name "m" doesn't conform to snake_case naming style
mock_response = MagicMock()
mock_response.status_code = 500
error = httpx.HTTPStatusError("500 Server Error", request=MagicMock(), response=mock_response)
mock_client.get.return_value.raise_for_status.side_effect = error

Check warning

Code scanning / Pylint (reported by Codacy)

Variable name "m" doesn't conform to snake_case naming style Warning test

Variable name "m" doesn't conform to snake_case naming style
# Simulate network error
error = httpx.RequestError("Network failure", request=MagicMock())
mock_client.get.side_effect = error

Check warning

Code scanning / Pylint (reported by Codacy)

Missing function docstring Warning test

Missing function docstring
error = httpx.RequestError("Network failure", request=MagicMock())
mock_client.get.side_effect = error

mock_log = MagicMock()

Check warning

Code scanning / Pylint (reported by Codacy)

Variable name "m" doesn't conform to snake_case naming style Warning test

Variable name "m" doesn't conform to snake_case naming style
test_main.py Outdated

Check warning

Code scanning / Pylint (reported by Codacy)

Missing function docstring Warning test

Missing function docstring
test_main.py Outdated

Check warning

Code scanning / Pylint (reported by Codacy)

Variable name "m" doesn't conform to snake_case naming style Warning test

Variable name "m" doesn't conform to snake_case naming style
test_main.py Outdated

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Variable name "m" doesn't conform to snake_case naming style Warning test

Variable name "m" doesn't conform to snake_case naming style
test_main.py Outdated

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Missing function or method docstring Warning test

Missing function or method docstring
error = httpx.RequestError("Network failure", request=MagicMock())
mock_client.get.side_effect = error

mock_log = MagicMock()

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Variable name "m" doesn't conform to snake_case naming style Warning test

Variable name "m" doesn't conform to snake_case naming style
# Simulate network error
error = httpx.RequestError("Network failure", request=MagicMock())
mock_client.get.side_effect = error

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Missing function or method docstring Warning test

Missing function or method docstring
mock_response = MagicMock()
mock_response.status_code = 500
error = httpx.HTTPStatusError("500 Server Error", request=MagicMock(), response=mock_response)
mock_client.get.return_value.raise_for_status.side_effect = error

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Variable name "m" doesn't conform to snake_case naming style Warning test

Variable name "m" doesn't conform to snake_case naming style
mock_response = MagicMock()
mock_response.status_code = 404
error = httpx.HTTPStatusError("404 Not Found", request=MagicMock(), response=mock_response)
mock_client.get.return_value.raise_for_status.side_effect = error

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Variable name "m" doesn't conform to snake_case naming style Warning test

Variable name "m" doesn't conform to snake_case naming style
# Simulate 404 response
mock_response = MagicMock()
mock_response.status_code = 404
error = httpx.HTTPStatusError("404 Not Found", request=MagicMock(), response=mock_response)

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Missing function or method docstring Warning test

Missing function or method docstring
m = reload_main_with_env(monkeypatch)
mock_client = MagicMock()

# Simulate 403 response

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Missing function or method docstring Warning test

Missing function or method docstring
assert mock_log.critical.call_count >= 1
# Check for authentication failed message
args = str(mock_log.critical.call_args_list)
assert "Authentication Failed" in args

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Variable name "m" doesn't conform to snake_case naming style Warning test

Variable name "m" doesn't conform to snake_case naming style
assert m.check_api_access(mock_client, "invalid_token") is False
assert mock_log.critical.call_count >= 1
# Check for authentication failed message
args = str(mock_log.critical.call_args_list)

Check warning

Code scanning / Pylintpython3 (reported by Codacy)

Missing function or method docstring Warning test

Missing function or method docstring

# Mock log to verify output
mock_log = MagicMock()
monkeypatch.setattr(m, "log", mock_log)

Check notice

Code scanning / Bandit (reported by Codacy)

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
# Mock log to verify output
mock_log = MagicMock()
monkeypatch.setattr(m, "log", mock_log)

Check notice

Code scanning / Bandit (reported by Codacy)

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.

def test_check_api_access_403(monkeypatch):
m = reload_main_with_env(monkeypatch)
mock_client = MagicMock()

Check notice

Code scanning / Bandit (reported by Codacy)

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
assert "Access Denied" in str(mock_log.critical.call_args)

def test_check_api_access_404(monkeypatch):
m = reload_main_with_env(monkeypatch)

Check notice

Code scanning / Bandit (reported by Codacy)

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.

def test_check_api_access_404(monkeypatch):
m = reload_main_with_env(monkeypatch)
mock_client = MagicMock()

Check notice

Code scanning / Bandit (reported by Codacy)

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
m = reload_main_with_env(monkeypatch)
mock_client = MagicMock()

# Simulate network error

Check notice

Code scanning / Bandit (reported by Codacy)

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
mock_client = MagicMock()

# Simulate network error
error = httpx.RequestError("Network failure", request=MagicMock())

Check notice

Code scanning / Bandit (reported by Codacy)

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
test_main.py Outdated

Check notice

Code scanning / Bandit (reported by Codacy)

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
test_main.py Outdated

Check notice

Code scanning / Bandit (reported by Codacy)

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
test_main.py Outdated

Check notice

Code scanning / Bandit (reported by Codacy)

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code. Note test

Use of assert detected. The enclosed code will be removed when compiling to optimised byte code.
@abhimehro abhimehro merged commit 5c2deea into main Jan 22, 2026
18 checks passed
@abhimehro abhimehro deleted the palette-ux-api-check-14442985379801282171 branch January 22, 2026 11:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants