mirror of
https://github.com/Matysh/houseplan-card
synced 2026-07-31 08:28:31 +00:00
test: HA-harness expectations follow the authenticated content URLs (audit B1)
- upload/plan_set tests asserted the old public /houseplan_files/... paths and only run in CI, so the B1 change surfaced there - +test for the fail-closed admin check (audit B2/T4: the authorization boundary had zero coverage)
This commit is contained in:
@@ -31,7 +31,8 @@ async def test_upload_ok(hass: HomeAssistant, hass_client: ClientSessionGenerato
|
|||||||
resp = await client.post("/api/houseplan/upload", data=fd)
|
resp = await client.post("/api/houseplan/upload", data=fd)
|
||||||
assert resp.status == 200
|
assert resp.status == 200
|
||||||
body = await resp.json()
|
body = await resp.json()
|
||||||
assert body["ok"] and body["url"].startswith("/houseplan_files/files/m1/manual.pdf?v=")
|
# audit B1: uploads now return the AUTHENTICATED content URL
|
||||||
|
assert body["ok"] and body["url"].startswith("/api/houseplan/content/files/m1/manual.pdf?v=")
|
||||||
|
|
||||||
|
|
||||||
async def test_upload_bad_ext(hass: HomeAssistant, hass_client: ClientSessionGenerator) -> None:
|
async def test_upload_bad_ext(hass: HomeAssistant, hass_client: ClientSessionGenerator) -> None:
|
||||||
@@ -57,4 +58,4 @@ async def test_upload_traversal_sanitized(hass: HomeAssistant, hass_client: Clie
|
|||||||
# no path segment may be exactly ".." (dots inside a name are harmless)
|
# no path segment may be exactly ".." (dots inside a name are harmless)
|
||||||
path = body["url"].split("?", 1)[0]
|
path = body["url"].split("?", 1)[0]
|
||||||
assert all(seg != ".." for seg in path.split("/"))
|
assert all(seg != ".." for seg in path.split("/"))
|
||||||
assert path.startswith("/houseplan_files/files/")
|
assert path.startswith("/api/houseplan/content/files/")
|
||||||
|
|||||||
@@ -99,4 +99,29 @@ async def test_plan_set_validates(hass: HomeAssistant, hass_ws_client: WebSocket
|
|||||||
{"type": "houseplan/plan/set", "space_id": "s1", "ext": "png", "data": "aGVsbG8="}
|
{"type": "houseplan/plan/set", "space_id": "s1", "ext": "png", "data": "aGVsbG8="}
|
||||||
)
|
)
|
||||||
resp = await client.receive_json()
|
resp = await client.receive_json()
|
||||||
assert resp["success"] and resp["result"]["url"].startswith("/houseplan_files/plans/s1.png?v=")
|
assert resp["success"] and resp["result"]["url"].startswith("/api/houseplan/content/plans/_/s1.png?v=")
|
||||||
|
|
||||||
|
|
||||||
|
async def test_admin_check_fails_closed(hass, hass_ws_client):
|
||||||
|
"""audit B2/T4: with no config entry the policy is unknown — deny writes.
|
||||||
|
|
||||||
|
This used to allow them: plan uploads slipped through during a reload.
|
||||||
|
"""
|
||||||
|
from custom_components.houseplan import websocket_api as wsapi
|
||||||
|
|
||||||
|
class _User:
|
||||||
|
is_admin = False
|
||||||
|
|
||||||
|
class _Conn:
|
||||||
|
user = _User()
|
||||||
|
|
||||||
|
# no entry at all → non-admin must be refused
|
||||||
|
assert wsapi._check_write(hass, _Conn()) is False
|
||||||
|
|
||||||
|
class _Admin:
|
||||||
|
is_admin = True
|
||||||
|
|
||||||
|
class _AdminConn:
|
||||||
|
user = _Admin()
|
||||||
|
|
||||||
|
assert wsapi._check_write(hass, _AdminConn()) is True
|
||||||
|
|||||||
Reference in New Issue
Block a user