fix(server): reject inverted period_start/period_end in CameraRecord
A misbehaving or clock-broken device could submit period_end <= period_start, polluting the camera_records table with zero-length or inverted windows that corrupt downstream hourly analytics. Add a Pydantic model_validator so the request is rejected at the API boundary instead of silently persisting bad ranges. Found via adversarial review (run 2026-05-01-191359, both reviewers). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,7 @@ import sqlite3
|
|||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
from fastapi import Depends
|
from fastapi import Depends
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field, model_validator
|
||||||
|
|
||||||
|
|
||||||
class CameraRecord(BaseModel):
|
class CameraRecord(BaseModel):
|
||||||
@@ -20,6 +20,12 @@ class CameraRecord(BaseModel):
|
|||||||
entries: int = Field(ge=0)
|
entries: int = Field(ge=0)
|
||||||
exits: int = Field(ge=0)
|
exits: int = Field(ge=0)
|
||||||
|
|
||||||
|
@model_validator(mode="after")
|
||||||
|
def _period_order(self):
|
||||||
|
if self.period_end <= self.period_start:
|
||||||
|
raise ValueError("period_end must be strictly greater than period_start")
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
class CameraEventsRequest(BaseModel):
|
class CameraEventsRequest(BaseModel):
|
||||||
location_id: str
|
location_id: str
|
||||||
|
|||||||
@@ -98,3 +98,15 @@ def test_negative_counts_rejected():
|
|||||||
with pytest.raises(ValidationError):
|
with pytest.raises(ValidationError):
|
||||||
CameraRecord(period_start=1712000000, period_end=1712003600,
|
CameraRecord(period_start=1712000000, period_end=1712003600,
|
||||||
entries=-1, exits=0)
|
entries=-1, exits=0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_inverted_period_rejected():
|
||||||
|
"""Pydantic should reject period_end <= period_start."""
|
||||||
|
from pydantic import ValidationError
|
||||||
|
from server.camera_endpoint import CameraRecord
|
||||||
|
with pytest.raises(ValidationError):
|
||||||
|
CameraRecord(period_start=1712003600, period_end=1712003600,
|
||||||
|
entries=0, exits=0)
|
||||||
|
with pytest.raises(ValidationError):
|
||||||
|
CameraRecord(period_start=1712003600, period_end=1712000000,
|
||||||
|
entries=0, exits=0)
|
||||||
|
|||||||
Reference in New Issue
Block a user