Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion linodecli/configuration/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,14 @@ def _check_full_access(base_url: str, token: str) -> bool:
verify=API_CA_PATH,
)

_handle_response_status(result, exit_on_error=True)
# IAM-enrolled users receive a 403 from /profile/grants since that
# endpoint is not accessible to them. Treat 403 as a valid response
# (i.e. not full access) rather than a fatal error.
_handle_response_status(
result,
exit_on_error=True,
status_validator=lambda status: status == 403,
)
Comment on lines +179 to +186
Copy link

Copilot AI Apr 28, 2026

Choose a reason for hiding this comment

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

Treating a 403 from /profile/grants as a non-fatal response makes _check_full_access return False for IAM-enrolled users. In CLIConfig.configure() this value gates the /account/users lookup, so IAM users will never be offered authorized_users selection even if they otherwise have the needed account permissions. If the intent is to still support configuring authorized users for IAM tokens, consider falling back to a different capability check (e.g. attempt /account/users with a status_validator for 401/403) or decouple the authorized-users prompt from _check_full_access when the grants endpoint is inaccessible.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@jriddle-linode Thoughts on this? I can't seem to reproduce the issue that requires this change but I might not be properly enrolled in IAM


return result.status_code == 204

Expand Down
39 changes: 39 additions & 0 deletions tests/unit/test_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
_default_text_input,
_default_thing_input,
)
from linodecli.configuration.auth import _check_full_access
Comment thread
mgwoj marked this conversation as resolved.
Outdated


class TestConfiguration:
Expand Down Expand Up @@ -676,3 +677,41 @@ def test_custom_config_path(self, monkeypatch, tmp_path):

for i, _ in enumerate(expected_configs):
assert expected_configs[i] == configs[i]


class TestCheckFullAccess:
"""
Unit tests for _check_full_access
"""

base_url = "https://linode-test.com"
test_token = "cli-dev-token"

def test_full_access_returns_true(self):
"""
204 No Content means the token has full (unrestricted) access.
"""
with requests_mock.Mocker() as m:
m.get(f"{self.base_url}/profile/grants", status_code=204)
assert _check_full_access(self.base_url, self.test_token) is True

def test_restricted_access_returns_false(self):
"""
200 with a grants body means the token has restricted access.
"""
with requests_mock.Mocker() as m:
m.get(
f"{self.base_url}/profile/grants",
status_code=200,
json={"linode": []},
)
assert _check_full_access(self.base_url, self.test_token) is False

def test_iam_user_403_returns_false(self):
"""
IAM-enrolled users receive a 403 from /profile/grants.
This should be treated as "not full access" rather than a fatal error.
"""
with requests_mock.Mocker() as m:
m.get(f"{self.base_url}/profile/grants", status_code=403)
assert _check_full_access(self.base_url, self.test_token) is False
Loading