diff --git a/backend/app/schemas/test.py b/backend/app/schemas/test.py index 0d4e2a9..df7b276 100644 --- a/backend/app/schemas/test.py +++ b/backend/app/schemas/test.py @@ -175,16 +175,26 @@ class TestOut(BaseModel): @classmethod def model_validate(cls, obj, **kwargs): - """Override to populate technique and evidence fields from ORM relationships.""" + """Override to populate technique and evidence fields from ORM relationships. + + Evidences are only processed when the relationship was **explicitly loaded** + (via joinedload or prior access). Accessing ``obj.evidences`` blindly on a + session-expired ORM object triggers a lazy query that fails on mutation + endpoints that do not joinload the relationship. We inspect ``obj.__dict__`` + directly — SQLAlchemy stores loaded relationships there; if the key is absent + the relationship is unloaded and we leave the lists empty (the frontend + invalidates and refetches the detail endpoint, which *does* joinload). + """ if hasattr(obj, "technique") and obj.technique is not None: obj.__dict__["technique_mitre_id"] = obj.technique.mitre_id obj.__dict__["technique_name"] = obj.technique.name - # Split evidences by team and inject the backend-proxy download URL - if hasattr(obj, "evidences") and obj.evidences is not None: + # Only split evidences when they are already in memory (loaded via joinedload) + raw_evs = obj.__dict__.get("evidences") if hasattr(obj, "__dict__") else None + if raw_evs is not None: red_evs: list[EvidenceOut] = [] blue_evs: list[EvidenceOut] = [] - for ev in obj.evidences: + for ev in raw_evs: ev_out = EvidenceOut( id=ev.id, test_id=ev.test_id,