From c89113ba360426932d4ea47312c2493a1705347c Mon Sep 17 00:00:00 2001 From: OpenCode Date: Sun, 13 Sep 2026 15:33:29 +0200 Subject: [PATCH] docs: aligner la documentation sur le contrat ExternalEndpoint MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .env.example | 9 ++++++--- .secrets.baseline | 4 ++-- GUIDE_DEV_PYTHON.md | 30 +++++++++++++++++++++++++----- README.LLM.md | 9 ++++++--- docs/pronote-auth.md | 6 +++++- 5 files changed, 44 insertions(+), 14 deletions(-) diff --git a/.env.example b/.env.example index 2b008e0..10f53ed 100644 --- a/.env.example +++ b/.env.example @@ -1,7 +1,8 @@ # --- Pronote --- +# Endpoints externes : HTTPS uniquement (pas de fichier local file://). PRONOTE_ICAL_ENDPOINT__URL=https://college.ent/pronote/ical/Edt_Jean.ics?icalsecurise=REPLACE_ME&version=2024 PRONOTE_ENDPOINT__URL=https://college.ent/pronote/parent.html -# Anciens noms temporairement supportés avec un avertissement : PRONOTE_ICAL_URL, PRONOTE_URL +# Anciens noms (alias obsolètes encore supportés avec un DeprecationWarning) : PRONOTE_ICAL_URL, PRONOTE_URL PRONOTE_ACCOUNT_TYPE=parent PRONOTE_USERNAME=parent.dupont PRONOTE_PASSWORD=your_secure_password @@ -30,8 +31,9 @@ PRONOTE_AUTH_MODE=password # --- CalDAV --- # Endpoint commun (URL potentiellement sensible, masquée dans les journaux) +# HTTPS uniquement ; HTTP n'est toléré que pour localhost avec CALDAV_ALLOW_INSECURE_HTTP=true. CALDAV_ENDPOINT__URL=https://caldav.example.com/calendars/user/pronote/ -# Ancien nom temporairement supporté avec un avertissement de dépréciation : CALDAV_URL +# Ancien nom (alias obsolète encore supporté avec un DeprecationWarning) : CALDAV_URL CALDAV_USERNAME=user@example.com CALDAV_PASSWORD=your_caldav_password CALDAV_CALENDAR_PATH=/pronote-sync/ @@ -94,9 +96,10 @@ AI_BASE_URL=https://api.openai.com/v1 # AI_ALLOW_INSECURE_HTTP=true # --- Blog --- +# Endpoint externe : HTTPS uniquement (pas de fichier local file://). BLOG_ENABLED=false BLOG_ENDPOINT__URL=https://blogpeda.ac-bordeaux.fr/cjeliote/?feed=rss2 -# Ancien nom temporairement supporté avec un avertissement de dépréciation : BLOG_RSS_URL +# Ancien nom (alias obsolète encore supporté avec un DeprecationWarning) : BLOG_RSS_URL # --- Divers --- DRY_RUN=false diff --git a/.secrets.baseline b/.secrets.baseline index 1dc0a7f..aed4d4b 100644 --- a/.secrets.baseline +++ b/.secrets.baseline @@ -140,7 +140,7 @@ "filename": "GUIDE_DEV_PYTHON.md", "hashed_secret": "90bd1b48e958257948487b90bee080ba5ed00caa", "is_verified": false, - "line_number": 5188 + "line_number": 5198 } ], "tests/unit/test_caldav_gateway.py": [ @@ -185,5 +185,5 @@ } ] }, - "generated_at": "2026-09-13T09:54:04Z" + "generated_at": "2026-09-13T13:32:54Z" } diff --git a/GUIDE_DEV_PYTHON.md b/GUIDE_DEV_PYTHON.md index 16876b7..9c1f2cd 100644 --- a/GUIDE_DEV_PYTHON.md +++ b/GUIDE_DEV_PYTHON.md @@ -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. | diff --git a/README.LLM.md b/README.LLM.md index 0fba1d1..f0ba1cc 100644 --- a/README.LLM.md +++ b/README.LLM.md @@ -58,6 +58,7 @@ The following variables can be safely pre-configured in `/etc/pronote-sync/prono - `PRONOTE_ACCOUNT_TYPE` (default: `parent`) - `PRONOTE_ENT` (ENT slug, e.g., `lyceeconnecte`) - `PRONOTE_AGENDA_SOURCE`, `PRONOTE_HOMEWORK_SOURCE`, `PRONOTE_MESSAGES_SOURCE` (`auto`, `ical`, or `pronotepy`) + - `PRONOTE_ENDPOINT__URL` (API Pronote endpoint) and `PRONOTE_ICAL_ENDPOINT__URL` (iCal feed endpoint). The old names `PRONOTE_URL` and `PRONOTE_ICAL_URL` are deprecated aliases that still work with a `DeprecationWarning`. - **CalDAV:** - `CALDAV_CALENDAR_PATH` (e.g., `/pronote-sync/`) @@ -78,7 +79,7 @@ The following variables can be safely pre-configured in `/etc/pronote-sync/prono - `AI_ENABLED`, `AI_PROVIDER`, `AI_BASE_URL`, `AI_MODEL`, `AI_ALLOW_INSECURE_HTTP` — la validation structurelle de `AI_BASE_URL` s'applique à tous les providers (HTTPS sauf `AI_ALLOW_INSECURE_HTTP=true`, pas de credentials ni de paramètres sensibles dans l'URL, pas de `/v1` automatique) ; seul `openai-compatible` exige `AI_BASE_URL` et `AI_MODEL`. - **Blog:** - - `BLOG_ENABLED`, `BLOG_RSS_URL` + - `BLOG_ENABLED`, `BLOG_ENDPOINT__URL`. The old name `BLOG_RSS_URL` is a deprecated alias that still works with a `DeprecationWarning`. - **General:** - `DRY_RUN`, `LOG_LEVEL` @@ -88,10 +89,12 @@ The following variables can be safely pre-configured in `/etc/pronote-sync/prono **Do NOT set these variables automatically.** The operator must manually provide the following secrets: - **Pronote:** - - `PRONOTE_ICAL_URL`, `PRONOTE_URL`, `PRONOTE_USERNAME`, `PRONOTE_PASSWORD` + - `PRONOTE_ICAL_ENDPOINT__URL`, `PRONOTE_ENDPOINT__URL`, `PRONOTE_USERNAME`, `PRONOTE_PASSWORD` + - The old names `PRONOTE_ICAL_URL` and `PRONOTE_URL` are deprecated aliases that still work with a `DeprecationWarning`. - **CalDAV:** - - `CALDAV_URL`, `CALDAV_USERNAME`, `CALDAV_PASSWORD` + - `CALDAV_ENDPOINT__URL`, `CALDAV_USERNAME`, `CALDAV_PASSWORD` + - The old name `CALDAV_URL` is a deprecated alias that still works with a `DeprecationWarning`. - **XMPP:** - `XMPP_JID`, `XMPP_PASSWORD`, `XMPP_TO` diff --git a/docs/pronote-auth.md b/docs/pronote-auth.md index 93c395b..3bbbaa4 100644 --- a/docs/pronote-auth.md +++ b/docs/pronote-auth.md @@ -95,6 +95,8 @@ https://{etablissement}.index-education.net/pronote/ical/Edt_{prenom}.ics?icalse ### Intégration dans `pronote-sync` - **Paramètre** : `PRONOTE_ICAL_ENDPOINT__URL` (ex. `.env.example` ligne 2). + L'ancien nom `PRONOTE_ICAL_URL` reste accepté comme **alias obsolète** (émission d'un + `DeprecationWarning`). Seul HTTPS est accepté ; `file://` est refusé. - **Comportement** : - Prioritaire en mode `PRONOTE_AGENDA_SOURCE=auto`. - Si l'URL est invalide ou expire, repli automatique vers `pronotepy` (si `PRONOTE_AGENDA_SOURCE=auto`). @@ -126,7 +128,9 @@ Connexion via le protocole propriétaire de Pronote (JSON sur HTTPS), avec **chi ### Intégration dans `pronote-sync` - **Paramètres** : - - `PRONOTE_ENDPOINT__URL` (ex. `.env.example` ligne 3). + - `PRONOTE_ENDPOINT__URL` (ex. `.env.example` ligne 3). L'ancien nom `PRONOTE_URL` reste + accepté comme **alias obsolète** (émission d'un `DeprecationWarning`). Seul HTTPS est + accepté ; `file://` est refusé. - `PRONOTE_USERNAME`, `PRONOTE_PASSWORD`. - `PRONOTE_ENT` (slug dans `_ENT_NAMES`). - `PRONOTE_ACCOUNT_TYPE` (ex. `parent`).