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:
2026-09-13 15:46:07 +02:00
parent c89113ba36
commit 5a3e251ad6
6 changed files with 89 additions and 76 deletions
+19 -12
View File
@@ -1632,11 +1632,14 @@ from ..models.agenda import RawCalendarData
def fetch_ical(url: str, timeout: int = 20) -> str:
"""
Récupère le flux iCal depuis une URL Pronote.
Récupère le flux iCal depuis une URL Pronote (HTTPS uniquement).
Inspiré de src/sources/pronote/fetch.ts.
Le schéma ``file://`` n'est **pas** supporté : les fixtures locales sont
injectées via un mock HTTP (``responses``) dans les tests.
Args:
url: URL du flux iCal (peut être file:// pour les tests).
url: URL HTTPS du flux iCal (avec token ``icalsecurise``).
timeout: Timeout en secondes (défaut: 20s).
Returns:
@@ -1651,16 +1654,7 @@ def fetch_ical(url: str, timeout: int = 20) -> str:
"user-agent": "pronote-sync",
}
# Gestion des URLs file:// pour les tests
if url.startswith("file://"):
import pathlib
file_path = pathlib.Path(url.replace("file://", ""))
content = file_path.read_text(encoding="utf-8")
if "BEGIN:VCALENDAR" not in content:
raise ValueError(f"Fichier iCal invalide: {redact_url(url)}")
return content
# Récupération HTTP
# Récupération HTTP (aucun accès fichier local)
try:
response = requests.get(
url,
@@ -1686,6 +1680,19 @@ def fetch_ical(url: str, timeout: int = 20) -> str:
return content
# Test unitaire réseau mocké (aucun accès fichier)
@responses.activate
def test_fetch_ical_https() -> None:
responses.add(
responses.GET,
"https://pronote.example.test/ical.ics",
body="BEGIN:VCALENDAR\nVERSION:2.0\nEND:VCALENDAR",
status=200,
)
content = fetch_ical("https://pronote.example.test/ical.ics")
assert content.startswith("BEGIN:VCALENDAR")
def get_calendar_name(raw_ical: str) -> str | None:
"""
Extrait le nom du calendrier depuis X-WR-CALNAME.