Reject coerced consequence-preview inputs
Declare child_id as StrictInt and is_present as StrictBool on the consequence request model so a JSON true is not accepted as child id 1 and a numeric or string status is not coerced to a bool (NQ-201-1). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
+3
-2
@@ -681,12 +681,13 @@ class AdminPresenceOverrideConsequenceRequest(BaseModel):
|
|||||||
``is_present`` bool are enforced by the SAME
|
``is_present`` bool are enforced by the SAME
|
||||||
:class:`~nestquest_core.presence.PresenceOverride` constructor the
|
:class:`~nestquest_core.presence.PresenceOverride` constructor the
|
||||||
create route's core path builds; this model only guards the SHAPE.
|
create route's core path builds; this model only guards the SHAPE.
|
||||||
|
Strict fields: a JSON ``true`` is not child id 1, nor ``1`` a bool.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
child_id: int
|
child_id: StrictInt
|
||||||
start_date: str
|
start_date: str
|
||||||
end_date: str
|
end_date: str
|
||||||
is_present: bool
|
is_present: StrictBool
|
||||||
|
|
||||||
|
|
||||||
class AdminPresenceOverrideConsequenceResponse(BaseModel):
|
class AdminPresenceOverrideConsequenceResponse(BaseModel):
|
||||||
|
|||||||
@@ -371,6 +371,42 @@ async def test_malformed_range_or_status_is_422(
|
|||||||
assert response.status_code == 422
|
assert response.status_code == 422
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"overrides",
|
||||||
|
[
|
||||||
|
{"child_id": True},
|
||||||
|
{"child_id": False},
|
||||||
|
{"child_id": "1"},
|
||||||
|
{"child_id": 1.0},
|
||||||
|
{"is_present": 1},
|
||||||
|
{"is_present": 0},
|
||||||
|
{"is_present": "true"},
|
||||||
|
{"is_present": "false"},
|
||||||
|
],
|
||||||
|
)
|
||||||
|
async def test_coercible_child_id_or_status_is_422(
|
||||||
|
custody: SimpleNamespace, overrides: dict[str, object]
|
||||||
|
) -> None:
|
||||||
|
"""Strict fields: a bool id or a numeric/string status is rejected.
|
||||||
|
|
||||||
|
The fixture child's id is 1, so a coerced ``true`` would otherwise
|
||||||
|
target it and return 200. Nothing is stored and nothing removed.
|
||||||
|
"""
|
||||||
|
assert custody.child_id == 1
|
||||||
|
database = custody.database
|
||||||
|
before = await _open_future_keys(database, custody.child_id)
|
||||||
|
body = {**_body(custody.child_id, 0, 14), **overrides}
|
||||||
|
response = await custody.client.post(
|
||||||
|
CONSEQUENCE_URL, json=body, headers=_admin_headers()
|
||||||
|
)
|
||||||
|
assert response.status_code == 422
|
||||||
|
assert await _open_future_keys(database, custody.child_id) == before
|
||||||
|
overrides_stored = await _dao_presence.PresenceOverridesDao(
|
||||||
|
database
|
||||||
|
).list_by_child_and_range(custody.child_id, "2000-01-01", "2100-01-01")
|
||||||
|
assert overrides_stored == []
|
||||||
|
|
||||||
|
|
||||||
# --- authentication: the router's ONE require_admin --------------------------
|
# --- authentication: the router's ONE require_admin --------------------------
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user