docs: aligner la documentation sur le contrat ExternalEndpoint

Documente le schéma *_ENDPOINT__URL unique, le statut déprécié des anciens noms et le refus de file:// et des credentials embarqués dans README.LLM.md, .env.example, GUIDE_DEV_PYTHON.md et docs/pronote-auth.md.

Refs #63
This commit is contained in:
2026-09-13 15:33:29 +02:00
parent 177286b528
commit c89113ba36
5 changed files with 44 additions and 14 deletions
+25 -5
View File
@@ -283,6 +283,12 @@ Le projet utilise **`pydantic-settings`** pour valider et charger la configurati
> `CALDAV_ENDPOINT__URL` pour la nouvelle configuration.
> `PRONOTE_URL` et `PRONOTE_ICAL_URL` restent temporairement acceptés avec un avertissement de
> dépréciation ; utiliser respectivement `PRONOTE_ENDPOINT__URL` et `PRONOTE_ICAL_ENDPOINT__URL`.
>
> **Contrat des endpoints externes** : le schéma `file://` n'est **pas** supporté en production.
> Seul HTTPS est accepté (plus HTTP uniquement pour un hôte loopback CalDAV lorsque
> `CALDAV_ALLOW_INSECURE_HTTP=true`). Les credentials embarqués (`user:pass@hôte`) sont refusés
> par les endpoints canoniques `*_ENDPOINT__URL`. Les fixtures locales ne doivent pas passer par
> ces variables.
Les variables Pronote sont obligatoires selon les sources activées :
@@ -1314,8 +1320,12 @@ from pronote_sync.models.blog import BlogArticle
@pytest.fixture
def mock_blog_rss_client():
"""Retourne un client RSS mocké pour les tests."""
client = BlogRSSClient(rss_url="file://tests/fixtures/blog_rss.xml")
"""Retourne un client RSS mocké pour les tests.
``requests.get`` est mocké : aucune requête réseau réelle n'est émise.
Le schéma ``file://`` n'est pas supporté par ``BlogRSSClient``.
"""
client = BlogRSSClient(rss_url="https://example.com/blog/feed")
return client
@@ -1362,7 +1372,7 @@ def test_blog_deduplication(tmp_path):
assert "https://blogpeda.ac-bordeaux.fr/cjeliote/?p=1625" in state.get_known_guids()
# Simuler une nouvelle récupération : seul le nouvel article doit être retourné
client = BlogRSSClient(rss_url="file://tests/fixtures/blog_rss.xml")
client = BlogRSSClient(rss_url="https://example.com/blog/feed") # requête mockée
result = client.fetch_and_parse(known_guids=state.get_known_guids())
# Seul l'article avec p=1626 doit être retourné (car p=1625 est déjà connu)
@@ -5728,7 +5738,17 @@ def check_secrets_in_code():
(["grep", "-r", "icalsecurise=", "src/", "tests/", "--include=*.py"], "Tokens iCal dans le code"),
(["grep", "-r", "password\s*=", "src/", "tests/", "--include=*.py"], "Mots de passe en clair"),
(["grep", "-r", "api_key\s*=", "src/", "tests/", "--include=*.py"], "Clés API en clair"),
(["grep", "-r", "PRONOTE_ICAL_URL.*=", "src/", "tests/", "--include=*.py"], "URLs iCal en clair"),
(
[
"grep",
"-r",
"PRONOTE_ICAL_ENDPOINT__URL.*=",
"src/",
"tests/",
"--include=*.py",
],
"URLs iCal en clair",
),
]
all_ok = True
@@ -5964,7 +5984,7 @@ Exemple de ligne cron (exécution tous les jours à 18h) :
| **Commande** | **Description** |
|---------------------------------------|-----------------------------------------------------------------------------------------------------|
| `python -m pronote_sync.cli.main --dry-run --log-level DEBUG` | Exécute le pipeline en mode dry-run avec des logs détaillés. |
| `python -c "from pronote_sync.sources.pronote.ical import fetch_ical; print(fetch_ical('file://tests/fixtures/pronote-4e.ics'))"` | Teste le parsing d'un fichier iCal local. |
| `python -c "from pronote_sync.sources.pronote.ical import fetch_ical; print(fetch_ical('https://college.ent/pronote/ical/Edt.ics?icalsecurise=TOKEN'))"` | Teste la récupération d'un flux iCal HTTPS (remplacer `TOKEN`). |
| `python -c "from pronote_sync.config.settings import settings; print(settings)"` | Affiche la configuration chargée. |
| `python -c "import caldav; print(caldav.__version__)"` | Vérifie la version de la bibliothèque CalDAV. |
| `python -c "import slixmpp; print(slixmpp.__version__)"` | Vérifie la version de la bibliothèque XMPP. |