From 87d59ccb5cbf9cee91b4b1d5ebb4984b9fd3b67c Mon Sep 17 00:00:00 2001 From: Matteo Benedetto Date: Sun, 16 Aug 2026 19:21:01 +0200 Subject: [PATCH] feat: validazione expires_at ISO 8601 (422 con messaggio chiaro, niente fallback silenzioso) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - field_validator Pydantic su MemoryIn.expires_at - verificato sul server: valida OK, invalida → 422 (istanza di test) --- gateway/main.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/gateway/main.py b/gateway/main.py index ec69a48..584ae65 100644 --- a/gateway/main.py +++ b/gateway/main.py @@ -33,7 +33,7 @@ from typing import Any, Literal, Optional import httpx import uvicorn from fastapi import Depends, FastAPI, Header, HTTPException, Request -from pydantic import BaseModel, Field +from pydantic import BaseModel, Field, field_validator from qdrant_client import QdrantClient from qdrant_client.http import models as qm @@ -135,6 +135,18 @@ class MemoryIn(BaseModel): supersedes_id: Optional[str] = None supersede_reason: Optional[str] = Field(default=None, max_length=512) + @field_validator("expires_at") + @classmethod + def _validate_expires_at(cls, v: Optional[str]) -> Optional[str]: + """Valida il formato ISO 8601: invalida → 422 (niente fallback silenzioso).""" + if v is None: + return v + try: + datetime.fromisoformat(v.replace("Z", "+00:00")) + except ValueError: + raise ValueError("expires_at deve essere una data ISO 8601 valida (es. 2026-09-01T00:00:00Z)") + return v + class SearchIn(BaseModel): query: str = Field(min_length=1, max_length=512)