refactor(config): migrer RSS et Pronote vers l'endpoint commun et durcir le contrat #64
+6
-3
@@ -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
@@ -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
@@ -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
@@ -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`
|
||||
|
||||
@@ -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`).
|
||||
|
||||
Reference in New Issue
Block a user