mirror of
https://github.com/Matysh/houseplan-card
synced 2026-07-31 08:28:31 +00:00
v1.45.4: review of v1.45.3 — R5-1, R5-2
R5-1: the backend signs each path independently and answers successfully with whatever it managed, skipping (and logging) the rest. The card read any successful call as 'the batch is done', cleared the backoff for every path in it, then wrote only the urls that came back — so a path the backend kept skipping was asked for again on every render, the exact amplification the backoff was added to stop. A path now counts as signed only when the answer carries a url for it; the others back off individually, keys that were not requested are ignored, and onUpdate fires only when a new signature landed. R5-2: docs/STATUS.md still described main as holding releases up to v1.40.1 and quoted test counts several releases old, while the version line beside them was kept current — a handoff reader got a wrong branch model and less coverage than exists. Branch roles are now accurate, and the counts are gone rather than corrected: scripts/inventory.mjs (npm run inventory) prints them from the tree, so there is nothing left to drift. Tests: three unit cases for empty/partial/foreign-key answers, verified to fail against a v1.45.3 checkout; a backend test pinning the partial-success contract by making async_sign_path raise for one path of two. Docs: CHANGELOG.md + CHANGELOG.ru.md + TESTING.md + STATUS.md.
This commit is contained in:
@@ -504,3 +504,44 @@ async def test_content_signed_path_opens_without_a_bearer_header(
|
||||
)
|
||||
resp2 = await client.receive_json()
|
||||
assert resp2["success"] and resp2["result"]["urls"] == {}
|
||||
|
||||
|
||||
async def test_signing_one_path_may_fail_without_failing_the_request(
|
||||
hass: HomeAssistant, hass_ws_client: WebSocketGenerator, monkeypatch
|
||||
) -> None:
|
||||
"""review R5-1: pin the contract the card now codes against.
|
||||
|
||||
One unsignable path must NOT fail the whole call — a single bad url would
|
||||
otherwise block the signatures of every other file in the batch. The answer
|
||||
is a partial map, and the card treats a path missing from it as a failure
|
||||
for that path (backing off) rather than as success.
|
||||
"""
|
||||
from custom_components.houseplan import websocket_api as wsapi
|
||||
from custom_components.houseplan.const import CONTENT_URL
|
||||
|
||||
await _setup(hass)
|
||||
good = f"{CONTENT_URL}/plans/_/good.png"
|
||||
bad = f"{CONTENT_URL}/plans/_/bad.png"
|
||||
|
||||
real = wsapi.async_sign_path if hasattr(wsapi, "async_sign_path") else None
|
||||
assert real is None # imported inside the handler, so patch the source module
|
||||
|
||||
import homeassistant.components.http.auth as ha_auth
|
||||
|
||||
original = ha_auth.async_sign_path
|
||||
|
||||
def _sign(hass_, *args, **kwargs):
|
||||
path = next((a for a in args if isinstance(a, str) and a.startswith("/")), "")
|
||||
if path == bad:
|
||||
raise ValueError("cannot sign this one")
|
||||
return original(hass_, *args, **kwargs)
|
||||
|
||||
monkeypatch.setattr(ha_auth, "async_sign_path", _sign)
|
||||
|
||||
client = await hass_ws_client(hass)
|
||||
await client.send_json_auto_id({"type": "houseplan/content/sign", "paths": [good, bad]})
|
||||
resp = await client.receive_json()
|
||||
assert resp["success"], "one bad path must not fail the batch"
|
||||
urls = resp["result"]["urls"]
|
||||
assert good in urls and "authSig=" in urls[good]
|
||||
assert bad not in urls, "an unsignable path is absent, never an unsigned url"
|
||||
|
||||
Reference in New Issue
Block a user