fix(jira): use model_validator(after) for jira_token_set + timeout on test
Some checks failed
Aegis CI / lint-and-test (push) Has been cancelled

FastAPI uses __pydantic_validator__.validate_python() which bypasses
model_validate() overrides. Switch to @model_validator(mode='after')
which the Pydantic Rust core always calls, so jira_token_set is now
correctly derived from the excluded jira_api_token field.

Also add a 10s timeout to the jira-test endpoint and better error
messages (the Atlassian library's "Expecting value" JSON error was
ambiguous).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
kitos
2026-05-26 17:36:35 +02:00
parent 513a7b488b
commit 48a936d426
2 changed files with 32 additions and 14 deletions

View File

@@ -4,7 +4,7 @@ import re
import uuid
from datetime import datetime
from pydantic import BaseModel, ConfigDict, EmailStr, field_validator
from pydantic import BaseModel, ConfigDict, EmailStr, Field, field_validator, model_validator
# ── Username policy ─────────────────────────────────────────────────
@@ -148,15 +148,20 @@ class UserOut(BaseModel):
notification_preferences: dict | None = None
jira_account_id: str | None = None
jira_email: str | None = None
# Never return the raw tokenjust indicate whether it is configured.
# Read from ORM but NEVER exposed in responses — used only to derive jira_token_set.
jira_api_token: str | None = Field(default=None, exclude=True)
# True when the user has a personal Atlassian token stored.
jira_token_set: bool = False
model_config = ConfigDict(from_attributes=True)
@classmethod
def model_validate(cls, obj, *args, **kwargs): # type: ignore[override]
instance = super().model_validate(obj, *args, **kwargs)
# Derive jira_token_set from the ORM object without exposing the value
if hasattr(obj, "jira_api_token"):
instance.jira_token_set = bool(obj.jira_api_token)
return instance
@model_validator(mode="after")
def _derive_jira_token_set(self) -> "UserOut":
"""Set jira_token_set from the (excluded) jira_api_token field.
Uses @model_validator(mode='after') so Pydantic's Rust core calls it
during FastAPI response serialisation — model_validate() overrides are
bypassed by FastAPI's __pydantic_validator__.validate_python() path.
"""
self.jira_token_set = bool(self.jira_api_token)
return self