mirror of
https://github.com/home-assistant/supervisor.git
synced 2026-02-14 23:19:37 +00:00
Tighten list_users() to trust Core's auth/list contract
Core's config/auth/list WS command always returns a list, never None. Replace the silent `if not raw: return []` (which also swallowed empty lists) with an assert, remove the dead AuthListUsersNoneResponseError exception class, and document the HomeAssistantWSError contract in the docstring. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -620,18 +620,6 @@ class AuthListUsersError(AuthError, APIUnknownSupervisorError):
|
||||
message_template = "Can't request listing users on Home Assistant"
|
||||
|
||||
|
||||
class AuthListUsersNoneResponseError(AuthError, APIInternalServerError):
|
||||
"""Auth error if listing users returned invalid None response."""
|
||||
|
||||
error_key = "auth_list_users_none_response_error"
|
||||
message_template = "Home Assistant returned invalid response of `{none}` instead of a list of users. Check Home Assistant logs for details (check with `{logs_command}`)"
|
||||
extra_fields = {"none": "None", "logs_command": "ha core logs"}
|
||||
|
||||
def __init__(self, logger: Callable[..., None] | None = None) -> None:
|
||||
"""Initialize exception."""
|
||||
super().__init__(None, logger)
|
||||
|
||||
|
||||
class AuthInvalidNonStringValueError(AuthError, APIUnauthorized):
|
||||
"""Auth error if something besides a string provided as username or password."""
|
||||
|
||||
|
||||
@@ -568,10 +568,12 @@ class HomeAssistant(FileConfiguration, CoreSysAttributes):
|
||||
self._data[attr] = data[attr]
|
||||
|
||||
async def list_users(self) -> list[HomeAssistantUser]:
|
||||
"""Fetch list of all users from Home Assistant Core via WebSocket."""
|
||||
"""Fetch list of all users from Home Assistant Core via WebSocket.
|
||||
|
||||
Raises HomeAssistantWSError on WebSocket connection/communication failure.
|
||||
"""
|
||||
raw: list[dict[str, Any]] | None = await self.websocket.async_send_command(
|
||||
{ATTR_TYPE: "config/auth/list"}
|
||||
)
|
||||
if not raw:
|
||||
return []
|
||||
assert raw is not None
|
||||
return [HomeAssistantUser.from_dict(data) for data in raw]
|
||||
|
||||
@@ -189,18 +189,6 @@ async def test_list_users_ws_error(
|
||||
assert "Can't request listing users on Home Assistant: fail" in caplog.text
|
||||
|
||||
|
||||
async def test_list_users_none_response(
|
||||
api_client: TestClient,
|
||||
ha_ws_client: AsyncMock,
|
||||
):
|
||||
"""Test None response from WS returns empty user list."""
|
||||
ha_ws_client.async_send_command.return_value = None
|
||||
resp = await api_client.get("/auth/list")
|
||||
assert resp.status == 200
|
||||
result = await resp.json()
|
||||
assert result["data"]["users"] == []
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("field", "api_client"),
|
||||
[("username", TEST_ADDON_SLUG), ("user", TEST_ADDON_SLUG)],
|
||||
|
||||
@@ -59,9 +59,10 @@ async def test_load(
|
||||
|
||||
|
||||
async def test_list_users_none(coresys: CoreSys, ha_ws_client: AsyncMock):
|
||||
"""Test list users returning none does not fail."""
|
||||
"""Test list users asserts on unexpected None response from Core."""
|
||||
ha_ws_client.async_send_command.return_value = None
|
||||
assert await coresys.homeassistant.list_users() == []
|
||||
with pytest.raises(AssertionError):
|
||||
await coresys.homeassistant.list_users()
|
||||
|
||||
|
||||
async def test_write_pulse_error(coresys: CoreSys, caplog: pytest.LogCaptureFixture):
|
||||
|
||||
Reference in New Issue
Block a user