Block devices with sub-components from becoming sub-components via forged edit

This commit is contained in:
2026-06-10 12:29:18 -05:00
parent 2a103f52a5
commit a9835fee1e
2 changed files with 16 additions and 0 deletions
+3
View File
@@ -889,6 +889,9 @@ def create_app(config_object="config"):
if new_parent.id == device_id: if new_parent.id == device_id:
flash("A device cannot be its own parent.", "error") flash("A device cannot be its own parent.", "error")
return redirect(url_for("device_detail", device_id=device_id)) return redirect(url_for("device_detail", device_id=device_id))
if device.has_children():
flash("A device with sub-components cannot itself become a sub-component.", "error")
return redirect(url_for("device_detail", device_id=device_id))
if new_parent.is_subcomponent(): if new_parent.is_subcomponent():
flash("Cannot nest sub-components more than one level deep.", "error") flash("Cannot nest sub-components more than one level deep.", "error")
return redirect(url_for("device_detail", device_id=device_id)) return redirect(url_for("device_detail", device_id=device_id))
+13
View File
@@ -999,6 +999,19 @@ def test_add_subcomponent(client):
assert b"Remote" in resp.data assert b"Remote" in resp.data
def test_device_with_children_cannot_become_subcomponent(client):
_setup_rc_car(client)
# Garage is parent-eligible (top-level, 0 slots, no size)
client.post("/device/add", data={"name": "Garage", "battery_slots": "0", "battery_size": ""})
resp = client.post("/device/1/edit",
data={"name": "RC Car Set", "battery_slots": "0", "parent_id": "4"},
follow_redirects=True)
assert b"cannot itself become a sub-component" in resp.data
data = _json.loads(client.get("/export/all.json").data)
devs = {d["name"]: d for d in data["devices"]}
assert devs["RC Car Set"]["parent_id"] is None
def test_subcomponent_prevents_deep_nesting(client): def test_subcomponent_prevents_deep_nesting(client):
_setup_rc_car(client) _setup_rc_car(client)
# id=2 is "Remote", which already has parent_id=1 # id=2 is "Remote", which already has parent_id=1