fix(config): valider l'alias CalDAV legacy et retirer file:// de fetch_ical
Supprime le contournement model_construct : l'alias CALDAV_URL est désormais validé comme le champ canonique (userinfo, host et port rejetés). Retire le support file:// de fetch_ical et corrige l'exemple résiduel du guide. Ajoute les tests négatifs de l'alias legacy et adapte le test de sécurité CalDAV au contrat durci. Refs #63
This commit is contained in:
@@ -244,13 +244,12 @@ class CalDAVSettings(BaseSettings):
|
||||
def _migrate_legacy_url(cls, data: object) -> object:
|
||||
"""Migre ``url`` vers l'endpoint commun avec un avertissement.
|
||||
|
||||
L'alias historique ``CALDAV_URL`` conserve ses sémantiques passées
|
||||
pendant la transition : lorsqu'il embarque des identifiants
|
||||
(``user:pass@hôte``), l'endpoint est construit sans revalidation pour
|
||||
ne pas casser une configuration existante, alors que le contrat
|
||||
canonique ``CALDAV_ENDPOINT__URL`` refuse désormais les credentials
|
||||
embarqués. La politique de transport (HTTPS, ou HTTP loopback
|
||||
uniquement avec ``allow_insecure_http``) reste appliquée ensuite.
|
||||
L'alias historique ``CALDAV_URL`` est migré via le chemin de validation
|
||||
canonique : il est donc soumis exactement aux mêmes règles que
|
||||
``CALDAV_ENDPOINT__URL`` (schémas réseau uniquement, hôte obligatoire,
|
||||
port valide, credentials embarqués refusés). La politique de transport
|
||||
(HTTPS, ou HTTP loopback uniquement avec ``allow_insecure_http``) reste
|
||||
appliquée ensuite.
|
||||
|
||||
:param data: Données brutes du modèle.
|
||||
:return: Données complétées avec ``endpoint`` si nécessaire.
|
||||
@@ -265,20 +264,7 @@ class CalDAVSettings(BaseSettings):
|
||||
stacklevel=2,
|
||||
)
|
||||
if migrated_data.get("endpoint") is None:
|
||||
legacy_url = migrated_data["url"]
|
||||
raw_url = (
|
||||
legacy_url.get_secret_value()
|
||||
if isinstance(legacy_url, SecretStr)
|
||||
else str(legacy_url)
|
||||
)
|
||||
parsed = urlparse(raw_url)
|
||||
if parsed.username is not None or parsed.password is not None:
|
||||
# Alias obsolète : grandfathered, on préserve l'URL telle quelle.
|
||||
migrated_data["endpoint"] = ExternalEndpoint.model_construct(
|
||||
url=legacy_url if isinstance(legacy_url, SecretStr) else SecretStr(legacy_url)
|
||||
)
|
||||
else:
|
||||
migrated_data["endpoint"] = {"url": legacy_url}
|
||||
migrated_data["endpoint"] = {"url": migrated_data["url"]}
|
||||
return migrated_data
|
||||
|
||||
@model_validator(mode="after")
|
||||
|
||||
Reference in New Issue
Block a user