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
+6 -3
View File
@@ -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
+2 -2
View File
@@ -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"
}
+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. |
+6 -3
View File
@@ -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`
+5 -1
View File
@@ -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`).