* docs: add Home Assistant 0.4.0 hardening roadmap * fix: protect media credentials and resume state * feat: authenticate RelayTV API operations * fix: make targeting and media state reliable * test: add Home Assistant integration CI * fix: validate API credentials during setup * release: prepare HACS 0.4.0 * fix: align pytest dependency pin * fix: close URL sanitizer gaps and correct player state reporting Sync the sensitive-query-key list with the RelayTV server (adds auth, exp, jwt, X-Emby-Token, X-Jellyfin-Token), filter query credentials from relative URLs instead of returning them verbatim, and preserve brackets around IPv6 literal hosts. Also report volume on RelayTV's 0-100 scale unconditionally (a raw 1 is 1%, not full volume) and give the coordinator its own position_updated_at stamp — the base DataUpdateCoordinator has no last_update_success_time, so media_position_updated_at silently fell back to now() on every read and the seek bar never extrapolated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
29 lines
959 B
Python
29 lines
959 B
Python
"""Tests for RelayTV config-entry setup."""
|
|
|
|
import pytest
|
|
|
|
from homeassistant.exceptions import ConfigEntryAuthFailed
|
|
from pytest_homeassistant_custom_component.common import MockConfigEntry
|
|
|
|
from custom_components.relaytv import async_setup_entry
|
|
from custom_components.relaytv.const import CONF_API_TOKEN, CONF_BASE_URL, DOMAIN
|
|
|
|
|
|
async def test_setup_rejects_invalid_write_credentials(hass, aioclient_mock) -> None:
|
|
base_url = "http://relaytv.local:8787"
|
|
entry = MockConfigEntry(
|
|
domain=DOMAIN,
|
|
title="Living Room",
|
|
data={CONF_BASE_URL: base_url, "name": "Living Room", CONF_API_TOKEN: "wrong"},
|
|
)
|
|
entry.add_to_hass(hass)
|
|
aioclient_mock.get(f"{base_url}/status", json={"state": "idle"})
|
|
aioclient_mock.post(
|
|
f"{base_url}/auth/check",
|
|
status=401,
|
|
json={"detail": "api token required"},
|
|
)
|
|
|
|
with pytest.raises(ConfigEntryAuthFailed):
|
|
await async_setup_entry(hass, entry)
|