Corrections issues de la revue indépendante des PR #59/#60/#61 (ticket #16, centralisation du contrat des endpoints externes).
Constat bloquant : le schéma file:// est accepté par la configuration de production (Pronote iCal, Blog RSS) alors qu'aucun client ne le consomme réellement. BlogRSSClient.fetch_and_parse appelle inconditionnellement requests.get() (pronote_sync/sources/blog/rss.py), donc un BLOG_ENDPOINT__URL=file://… passe la validation puis dégrade silencieusement. Les tests ne le détectent pas car ils mockent requests.get avec une URL file:// factice. Cela contrevient au critère du ticket #16 : « conserver la possibilité de tests locaux injectés sans transformer ces facilités de test en comportement implicite de production ».
Constats complémentaires : matrice de tests de contrat incomplète ; hide_input_in_errors absent de PronoteSettings/CalDAVSettings/BlogSettings ; README.LLM.md documente encore les anciens noms de variables.
Périmètre (liste fermée)
P0 — bloquant
Retirer le schéma file du contrat ExternalEndpoint pour les trois connecteurs (CalDAV, Pronote iCal, Blog RSS). Seuls https (et http en loopback explicite via allow_insecure_http) restent acceptés. Aucune lecture de fichier local n'est ajoutée en production.
Réécrire les fixtures de test qui utilisent file:// (Blog RSS, test_fallback.py) avec une URL https:// factice interceptée par mock HTTP (responses), sans accès réseau.
Ajouter hide_input_in_errors=True aux SettingsConfigDict de PronoteSettings, CalDAVSettings, BlogSettings (parité avec XmppSettings et ExternalEndpoint).
Matrice de tests paramétrée exhaustive du contrat, partagée par les trois connecteurs : précédence canonique/alias avec DeprecationWarning, loopback HTTP accepté/refusé selon allow_insecure_http, extra='forbid', frozen=True, userinfo rejeté, query params sensibles rejetés/expurgés, file:// rejeté.
P1 — documentation
5. README.LLM.md : retirer BLOG_RSS_URL, PRONOTE_URL, PRONOTE_ICAL_URL, CALDAV_URL et documenter le schéma *_ENDPOINT__URL + statut des alias dépréciés.
6. Aligner .env.example, GUIDE_DEV_PYTHON.md et docs/pronote-auth.md sur le même contrat.
Hors périmètre
Toute évolution du protocole des connecteurs (parsing métier, format iCal/RSS, logique de fallback).
Mécanisme de lecture de fichier local en production.
Modification de l'endpoint XMPP.
Modification des correctifs sécurité #53/#54/#58 déjà dans main (seule leur préservation est requise).
Critères d'acceptation
Aucune configuration de production n'accepte file:// (les trois connecteurs).
rg 'file://' tests/ ne retourne plus de dépendance à ce schéma.
La matrice de tests de contrat est paramétrée et couvre les cas listés au point 4.
README.LLM.md et les guides ne contredisent plus le contrat unique.
pytest --cov, ruff check ., mypy ., bandit -r pronote_sync/ passent sur la branche.
## Contexte
Corrections issues de la revue indépendante des PR #59/#60/#61 (ticket #16, centralisation du contrat des endpoints externes).
Constat bloquant : le schéma `file://` est accepté par la configuration de production (Pronote iCal, Blog RSS) alors qu'aucun client ne le consomme réellement. `BlogRSSClient.fetch_and_parse` appelle inconditionnellement `requests.get()` (`pronote_sync/sources/blog/rss.py`), donc un `BLOG_ENDPOINT__URL=file://…` passe la validation puis dégrade silencieusement. Les tests ne le détectent pas car ils mockent `requests.get` avec une URL `file://` factice. Cela contrevient au critère du ticket #16 : « conserver la possibilité de tests locaux injectés sans transformer ces facilités de test en comportement implicite de production ».
Constats complémentaires : matrice de tests de contrat incomplète ; `hide_input_in_errors` absent de `PronoteSettings`/`CalDAVSettings`/`BlogSettings` ; `README.LLM.md` documente encore les anciens noms de variables.
## Périmètre (liste fermée)
**P0 — bloquant**
1. Retirer le schéma `file` du contrat `ExternalEndpoint` pour les trois connecteurs (CalDAV, Pronote iCal, Blog RSS). Seuls `https` (et `http` en loopback explicite via `allow_insecure_http`) restent acceptés. Aucune lecture de fichier local n'est ajoutée en production.
2. Réécrire les fixtures de test qui utilisent `file://` (Blog RSS, `test_fallback.py`) avec une URL `https://` factice interceptée par mock HTTP (`responses`), sans accès réseau.
3. Ajouter `hide_input_in_errors=True` aux `SettingsConfigDict` de `PronoteSettings`, `CalDAVSettings`, `BlogSettings` (parité avec `XmppSettings` et `ExternalEndpoint`).
4. Matrice de tests paramétrée exhaustive du contrat, partagée par les trois connecteurs : précédence canonique/alias avec `DeprecationWarning`, loopback HTTP accepté/refusé selon `allow_insecure_http`, `extra='forbid'`, `frozen=True`, userinfo rejeté, query params sensibles rejetés/expurgés, `file://` rejeté.
**P1 — documentation**
5. `README.LLM.md` : retirer `BLOG_RSS_URL`, `PRONOTE_URL`, `PRONOTE_ICAL_URL`, `CALDAV_URL` et documenter le schéma `*_ENDPOINT__URL` + statut des alias dépréciés.
6. Aligner `.env.example`, `GUIDE_DEV_PYTHON.md` et `docs/pronote-auth.md` sur le même contrat.
## Hors périmètre
- Toute évolution du protocole des connecteurs (parsing métier, format iCal/RSS, logique de fallback).
- Mécanisme de lecture de fichier local en production.
- Modification de l'endpoint XMPP.
- Modification des correctifs sécurité #53/#54/#58 déjà dans `main` (seule leur préservation est requise).
## Critères d'acceptation
- Aucune configuration de production n'accepte `file://` (les trois connecteurs).
- `rg 'file://' tests/` ne retourne plus de dépendance à ce schéma.
- La matrice de tests de contrat est paramétrée et couvre les cas listés au point 4.
- `README.LLM.md` et les guides ne contredisent plus le contrat unique.
- `pytest --cov`, `ruff check .`, `mypy .`, `bandit -r pronote_sync/` passent sur la branche.
## Références
- Ticket parent : #16
- PR concernées : #59, #60, #61
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Contexte
Corrections issues de la revue indépendante des PR #59/#60/#61 (ticket #16, centralisation du contrat des endpoints externes).
Constat bloquant : le schéma
file://est accepté par la configuration de production (Pronote iCal, Blog RSS) alors qu'aucun client ne le consomme réellement.BlogRSSClient.fetch_and_parseappelle inconditionnellementrequests.get()(pronote_sync/sources/blog/rss.py), donc unBLOG_ENDPOINT__URL=file://…passe la validation puis dégrade silencieusement. Les tests ne le détectent pas car ils mockentrequests.getavec une URLfile://factice. Cela contrevient au critère du ticket #16 : « conserver la possibilité de tests locaux injectés sans transformer ces facilités de test en comportement implicite de production ».Constats complémentaires : matrice de tests de contrat incomplète ;
hide_input_in_errorsabsent dePronoteSettings/CalDAVSettings/BlogSettings;README.LLM.mddocumente encore les anciens noms de variables.Périmètre (liste fermée)
P0 — bloquant
filedu contratExternalEndpointpour les trois connecteurs (CalDAV, Pronote iCal, Blog RSS). Seulshttps(ethttpen loopback explicite viaallow_insecure_http) restent acceptés. Aucune lecture de fichier local n'est ajoutée en production.file://(Blog RSS,test_fallback.py) avec une URLhttps://factice interceptée par mock HTTP (responses), sans accès réseau.hide_input_in_errors=TrueauxSettingsConfigDictdePronoteSettings,CalDAVSettings,BlogSettings(parité avecXmppSettingsetExternalEndpoint).DeprecationWarning, loopback HTTP accepté/refusé selonallow_insecure_http,extra='forbid',frozen=True, userinfo rejeté, query params sensibles rejetés/expurgés,file://rejeté.P1 — documentation
5.
README.LLM.md: retirerBLOG_RSS_URL,PRONOTE_URL,PRONOTE_ICAL_URL,CALDAV_URLet documenter le schéma*_ENDPOINT__URL+ statut des alias dépréciés.6. Aligner
.env.example,GUIDE_DEV_PYTHON.mdetdocs/pronote-auth.mdsur le même contrat.Hors périmètre
main(seule leur préservation est requise).Critères d'acceptation
file://(les trois connecteurs).rg 'file://' tests/ne retourne plus de dépendance à ce schéma.README.LLM.mdet les guides ne contredisent plus le contrat unique.pytest --cov,ruff check .,mypy .,bandit -r pronote_sync/passent sur la branche.Références