diff --git a/D%C3%A9ploiement.md b/D%C3%A9ploiement.md deleted file mode 100644 index e7a3b6e..0000000 --- a/D%C3%A9ploiement.md +++ /dev/null @@ -1,123 +0,0 @@ -# Déploiement - -## Prérequis - -- Python ≥ 3.13.5 -- Git -- Un compte de service non-root (ex: `pronote-sync`) -- Chemins cibles : - - `/opt/pronote-sync` (code) - - `/var/lib/pronote-sync` (état) - - `/var/log/pronote-sync` (logs) - - `/etc/pronote-sync` (configuration) - -## Installation - -```bash -# Créer le compte de service -sudo useradd --system --no-create-home --shell /usr/sbin/nologin pronote-sync - -# Cloner le dépôt -sudo git clone https://git.antoineve.me/AntoineVe/college-infos /opt/pronote-sync -sudo chown -R pronote-sync:pronote-sync /opt/pronote-sync - -# Créer l'environnement virtuel -cd /opt/pronote-sync -sudo -u pronote-sync python3.13 -m venv .venv -sudo -u pronote-sync .venv/bin/pip install -e ".[dev]" - -# Créer les répertoires -sudo install -d -m 0700 -o pronote-sync -g pronote-sync /etc/pronote-sync -sudo install -d -m 0750 -o pronote-sync -g pronote-sync /var/lib/pronote-sync -sudo install -d -m 0750 -o pronote-sync -g pronote-sync /var/log/pronote-sync -``` - -## Configuration - -```bash -sudo -u pronote-sync cp /opt/pronote-sync/.env.example /etc/pronote-sync/pronote-sync.env -``` - -L'opérateur doit renseigner les secrets (`PRONOTE_PASSWORD`, `CALDAV_PASSWORD`, `XMPP_PASSWORD`, `AI_API_KEY`) dans ce fichier. - -Ne jamais placer de secret dans une unité systemd, une commande shell ou un journal. Voir [Sécurité](Sécurité). - -## Contrôles pré-déploiement - -```bash -.venv/bin/python scripts/check_secrets.py -.venv/bin/python -m pip check -.venv/bin/pronote-sync --dry-run -``` - -- `check_secrets.py` : - - Sort avec le code **0** (propre), **1** (secrets détectés), **2** (erreur). - - Inspecte les fichiers textuels, en excluant `.env`, les environnements virtuels, les répertoires générés, `tests/` et `GUIDE_DEV_PYTHON.md`. - - Utilisez `--staged` pour vérifier uniquement les fichiers indexés par Git avant un commit. -- `pip check` : Vérifie la cohérence des dépendances. -- `--dry-run` : Valide le pipeline sans écrire dans CalDAV/XMPP. - -## Installation systemd - -Les fichiers fournis dans `deploy/systemd/` sont : - -- `pronote-sync.service` (oneshot, exécute la synchronisation) -- `pronote-sync.timer` (quotidien à 18:00, avec `Persistent=true`) - -Le service utilise les protections suivantes : `NoNewPrivileges`, `PrivateTmp`, `ProtectHome`, `ProtectSystem=strict`, `ReadWritePaths` pour l'état et les logs. - -```bash -sudo install -m 0644 deploy/systemd/pronote-sync.service /etc/systemd/system/ -sudo install -m 0644 deploy/systemd/pronote-sync.timer /etc/systemd/system/ -sudo systemctl daemon-reload -sudo systemctl enable --now pronote-sync.timer -systemctl list-timers pronote-sync.timer -``` - -Adaptez `User`, `Group`, `WorkingDirectory`, `EnvironmentFile`, les chemins dans `ExecStartPre`, `ExecStart`, `StateDirectory`, `LogsDirectory` et `ReadWritePaths` avant l'installation. - -## Test manuel - -```bash -sudo systemctl start pronote-sync.service -sudo systemctl status pronote-sync.service -``` - -Une exécution en échec laisse le service en état **failed** : configurez une supervision pour alerter sur cet état. - -## Journaux - -```bash -sudo tail -f /var/log/pronote-sync/pronote-sync.log -sudo journalctl -u pronote-sync.service --since today -sudo journalctl -u pronote-sync.service -f -systemctl status pronote-sync.timer -``` - -## Rotation des journaux - -La configuration `deploy/logrotate/pronote_sync` applique : - -- Rotation quotidienne -- 7 archives conservées -- Compression avec `delaycompress` -- Création du fichier avec le mode `0640` pour le compte de service - -```bash -sudo install -m 0644 deploy/logrotate/pronote_sync /etc/logrotate.d/pronote_sync -sudo logrotate --debug /etc/logrotate.d/pronote_sync -``` - -## Mise à jour - -```bash -.venv/bin/python scripts/check_secrets.py -.venv/bin/python -m pip check -.venv/bin/pronote-sync --dry-run -sudo systemctl daemon-reload -sudo systemctl restart pronote-sync.timer -sudo systemctl start pronote-sync.service -journalctl -u pronote-sync.service -n 100 --no-pager -``` - -Voir aussi : [Configuration](Configuration) pour les variables d'environnement, [Sécurité](Sécurité) pour la gestion des secrets et `check_secrets`. \ No newline at end of file diff --git a/unnamed.md b/unnamed.md index 156efae..9838be3 100644 --- a/unnamed.md +++ b/unnamed.md @@ -1,121 +1,132 @@ -# Configuration +# Déploiement -Configuration via `pydantic-settings` depuis les variables d'environnement ou un fichier `.env`. Copiez `.env.example` vers `.env` pour démarrer. Les secrets utilisent `SecretStr` et sont masqués dans les logs. +## Prérequis -## Principe +- Python ≥ 3.13.5 +- Git +- Un compte de service non-root (ex: `pronote-sync`) +- Chemins cibles : + - `/opt/pronote-sync` (code) + - `/var/lib/pronote-sync` (état) + - `/var/log/pronote-sync` (logs) + - `/etc/pronote-sync` (configuration) -Les paramètres sont chargés automatiquement depuis les variables d'environnement ou un fichier `.env` à la racine du projet. Le fichier `.env` n'est **jamais** versionné (couvert par `.gitignore`). - -## Variables Pronote - -| Variable | Description | Valeur par défaut | Type | -|----------|-------------|--------------------|------| -| `PRONOTE_ICAL_URL` | URL du flux iCal Pronote (contient `icalsecurise`) | obligatoire si source `ical` | SecretStr | -| `PRONOTE_URL` | URL de la page Pronote pour `pronotepy` | obligatoire si source `pronotepy` | str | -| `PRONOTE_ACCOUNT_TYPE` | Type de compte Pronote | `parent` | str | -| `PRONOTE_USERNAME` | Identifiant Pronote | obligatoire si source `pronotepy` | str | -| `PRONOTE_PASSWORD` | Mot de passe Pronote | obligatoire si source `pronotepy` | SecretStr | -| `PRONOTE_ENT` | Slug ENT (résolu vers `pronotepy.ent`) | optionnel | str | -| `PRONOTE_AGENDA_SOURCE` | Source pour l'agenda | `auto` | Literal["auto", "ical", "pronotepy"] | -| `PRONOTE_HOMEWORK_SOURCE` | Source pour les devoirs | `auto` | Literal["auto", "ical", "pronotepy"] | -| `PRONOTE_MESSAGES_SOURCE` | Source pour les messages | `pronotepy` | Literal["pronotepy"] | - -> **Note** : `PRONOTE_URL` et `PRONOTE_ICAL_URL` sont deux contrats distincts. L'un ne doit **jamais** être déduit de l'autre. - -## Variables CalDAV - -| Variable | Description | Valeur par défaut | Type | -|----------|-------------|--------------------|------| -| `CALDAV_URL` | URL du serveur CalDAV | obligatoire | SecretStr | -| `CALDAV_USERNAME` | Identifiant CalDAV | obligatoire | str | -| `CALDAV_PASSWORD` | Mot de passe CalDAV | obligatoire | SecretStr | -| `CALDAV_CALENDAR_PATH` | Chemin du calendrier sur le serveur | `/pronote-sync/` | str | -| `CALDAV_ALLOW_INSECURE_HTTP` | Autoriser HTTP non sécurisé (localhost uniquement) | `false` | bool | - -## Fenêtre de synchronisation - -| Variable | Description | Valeur par défaut | Type | -|----------|-------------|--------------------|------| -| `SYNC_PAST_DAYS` | Nombre de jours dans le passé à synchroniser | `7` | int | -| `SYNC_FUTURE_DAYS` | Nombre de jours dans le futur à synchroniser | `30` | int | - -## Agenda théorique - -| Variable | Description | Valeur par défaut | Type | -|----------|-------------|--------------------|------| -| `THEORETICAL_AGENDA_PATH` | Chemin vers le fichier JSON de l'agenda théorique | `None` | str \| None | -| `SCHOOL_HOLIDAYS_PATH` | Chemin vers le fichier JSON des vacances scolaires | `None` | str \| None | -| `THEORETICAL_WEEK_ANCHOR_DATE` | Date de référence pour la parité des semaines | `None` | date \| None | -| `THEORETICAL_WEEK_ANCHOR_TYPE` | Parité de la semaine de référence | `None` | Literal["even", "odd"] \| None | - -## Variables XMPP - -| Variable | Description | Valeur par défaut | Type | -|----------|-------------|--------------------|------| -| `XMPP_ENABLED` | Activer la notification XMPP | `false` | bool | -| `XMPP_JID` | Identifiant XMPP (ex: `user@example.com`) | obligatoire si activé | str | -| `XMPP_PASSWORD` | Mot de passe XMPP | obligatoire si activé | SecretStr | -| `XMPP_HOST` | Hôte XMPP | `""` | str | -| `XMPP_PORT` | Port XMPP | `5222` | int | -| `XMPP_TO` | Destinataire XMPP | obligatoire si activé | str | -| `XMPP_RESOURCE` | Ressource XMPP | `pronote-sync` | str | -| `XMPP_USE_TLS` | Utiliser TLS pour la connexion | `true` | bool | -| `XMPP_TIMEOUT` | Délai d'attente en secondes | `30` | int | - -## Variables IA - -| Variable | Description | Valeur par défaut | Type | -|----------|-------------|--------------------|------| -| `AI_ENABLED` | Activer la synthèse IA | `false` | bool | -| `AI_PROVIDER` | Fournisseur IA | `openai` | Literal["openai", "litellm", "openai-compatible"] | -| `AI_BASE_URL` | URL de base de l'API IA | `None` | str \| None | -| `AI_API_KEY` | Clé API IA | `None` | SecretStr | -| `AI_MODEL` | Modèle IA | `None` | str \| None | -| `AI_ALLOW_INSECURE_HTTP` | Autoriser HTTP non sécurisé pour `openai-compatible` | `false` | bool | - -> **Note** : Le fournisseur `openai-compatible` réutilise `OpenAISynthesisProvider` avec un `base_url` personnalisé. `AI_BASE_URL` et `AI_MODEL` sont requis pour ce fournisseur. L'URL doit utiliser `https` sauf si `AI_ALLOW_INSECURE_HTTP=true`. Les identifiants dans l'URL sont rejetés. Les paramètres sensibles dans la *query string* sont rejetés. Aucune manipulation automatique de `/v1` n'est effectuée. En cas de configuration invalide, la factory retourne `None` avec un avertissement (mode dégradé). - -Exemples de configuration pour `openai-compatible` : +## Installation ```bash -# OpenRouter (HTTPS) -AI_PROVIDER=openai-compatible -AI_BASE_URL=https://openrouter.ai/api/v1 -AI_MODEL=fournisseur/modele -AI_API_KEY=your-openrouter-key -AI_ALLOW_INSECURE_HTTP=false +# Créer le compte de service +sudo useradd --system --no-create-home --shell /usr/sbin/nologin pronote-sync -# Ollama local (HTTP) -AI_PROVIDER=openai-compatible -AI_BASE_URL=http://127.0.0.1:11434/v1 -AI_MODEL=modele-local -AI_API_KEY=local-not-required -AI_ALLOW_INSECURE_HTTP=true +# Cloner le dépôt +sudo git clone https://git.antoineve.me/AntoineVe/college-infos /opt/pronote-sync +sudo chown -R pronote-sync:pronote-sync /opt/pronote-sync + +# Créer l'environnement virtuel +cd /opt/pronote-sync +sudo -u pronote-sync python3.13 -m venv .venv +sudo -u pronote-sync .venv/bin/pip install -e ".[dev]" + +# Créer les répertoires +sudo install -d -m 0700 -o pronote-sync -g pronote-sync /etc/pronote-sync +sudo install -d -m 0750 -o pronote-sync -g pronote-sync /var/lib/pronote-sync +sudo install -d -m 0750 -o pronote-sync -g pronote-sync /var/log/pronote-sync ``` -## Variables Blog - -| Variable | Description | Valeur par défaut | Type | -|----------|-------------|--------------------|------| -| `BLOG_ENABLED` | Activer la synchronisation du blog | `false` | bool | -| `BLOG_RSS_URL` | URL du flux RSS du blog | `https://blogpeda.ac-bordeaux.fr/cjeliote/?feed=rss2` | str | - -## Divers - -| Variable | Description | Valeur par défaut | Type | -|----------|-------------|--------------------|------| -| `DRY_RUN` | Mode simulation (pas d'écriture) | `false` | bool | -| `LOG_LEVEL` | Niveau de log | `INFO` | str | - -## Fichier .env - -Pour créer votre fichier de configuration : +## Configuration ```bash -cp .env.example .env -# Éditer .env avec vos paramètres +sudo -u pronote-sync cp /opt/pronote-sync/.env.example /etc/pronote-sync/pronote-sync.env ``` -> **Rappel** : Le fichier `.env` n'est **jamais** versionné. Utilisez `.env.example` comme modèle. +L'opérateur doit renseigner les secrets (`PRONOTE_PASSWORD`, `CALDAV_PASSWORD`, `XMPP_PASSWORD`, `AI_API_KEY`) dans ce fichier. -Voir aussi : [Sécurité](Sécurité) pour la gestion des secrets, [Déploiement](Déploiement) pour la configuration en production. \ No newline at end of file +Ne jamais placer de secret dans une unité systemd, une commande shell ou un journal. Voir [Sécurité](Sécurité). + +## Contrôles pré-déploiement + +```bash +.venv/bin/python scripts/check_secrets.py +.venv/bin/python -m pip check +.venv/bin/pronote-sync --dry-run +``` + +- `check_secrets.py` : + - Sort avec le code **0** (propre), **1** (secrets détectés), **2** (erreur). + - Inspecte les fichiers textuels, en excluant `.env`, les environnements virtuels, les répertoires générés, `tests/` et `GUIDE_DEV_PYTHON.md`. + - Utilisez `--staged` pour vérifier uniquement les fichiers indexés par Git avant un commit. +- `pip check` : Vérifie la cohérence des dépendances. +- `--dry-run` : Valide le pipeline sans écrire dans CalDAV/XMPP. + +## Installation systemd + +Les fichiers fournis dans `deploy/systemd/` sont : + +- `pronote-sync.service` (oneshot, exécute la synchronisation) +- `pronote-sync.timer` (quotidien à 18:00, avec `Persistent=true`) + +Le service utilise les protections suivantes : `NoNewPrivileges`, `PrivateTmp`, `ProtectHome`, `ProtectSystem=strict`, `ReadWritePaths` pour l'état et les logs. + +```bash +sudo install -m 0644 deploy/systemd/pronote-sync.service /etc/systemd/system/ +sudo install -m 0644 deploy/systemd/pronote-sync.timer /etc/systemd/system/ +sudo systemctl daemon-reload +sudo systemctl enable --now pronote-sync.timer +systemctl list-timers pronote-sync.timer +``` + +Adaptez `User`, `Group`, `WorkingDirectory`, `EnvironmentFile`, les chemins dans `ExecStartPre`, `ExecStart`, `StateDirectory`, `LogsDirectory` et `ReadWritePaths` avant l'installation. + +## Test manuel + +```bash +sudo systemctl start pronote-sync.service +sudo systemctl status pronote-sync.service +``` + +Une exécution en échec laisse le service en état **failed** : configurez une supervision pour alerter sur cet état. + +## Journaux + +```bash +sudo tail -f /var/log/pronote-sync/pronote-sync.log +sudo journalctl -u pronote-sync.service --since today +sudo journalctl -u pronote-sync.service -f +systemctl status pronote-sync.timer +``` + +## Rotation des journaux + +La configuration `deploy/logrotate/pronote_sync` applique : + +- Rotation quotidienne +- 7 archives conservées +- Compression avec `delaycompress` +- Création du fichier avec le mode `0640` pour le compte de service + +```bash +sudo install -m 0644 deploy/logrotate/pronote_sync /etc/logrotate.d/pronote_sync +sudo logrotate --debug /etc/logrotate.d/pronote_sync +``` + +## Mise à jour + +```bash +# Récupérer la nouvelle version du code +sudo -u pronote-sync git -C /opt/pronote-sync pull --ff-only + +# Mettre à jour les dépendances +sudo -u pronote-sync /opt/pronote-sync/.venv/bin/pip install -e ".[dev]" + +# Contrôles pré-redémarrage +sudo -u pronote-sync /opt/pronote-sync/.venv/bin/python scripts/check_secrets.py +sudo -u pronote-sync /opt/pronote-sync/.venv/bin/python -m pip check +sudo -u pronote-sync /opt/pronote-sync/.venv/bin/pronote-sync --dry-run + +# Recharger et redémarrer +sudo systemctl daemon-reload +sudo systemctl restart pronote-sync.timer +sudo systemctl start pronote-sync.service +journalctl -u pronote-sync.service -n 100 --no-pager +``` + +Voir aussi : [Configuration](Configuration) pour les variables d'environnement, [Sécurité](Sécurité) pour la gestion des secrets et `check_secrets`. \ No newline at end of file