Compléter la section mise à jour avec git pull et pip install

2026-09-08 18:08:13 +02:00
parent ef562083fe
commit 7d5e677680
2 changed files with 119 additions and 231 deletions

@@ -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`.

@@ -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`). ## Installation
## 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` :
```bash ```bash
# OpenRouter (HTTPS) # Créer le compte de service
AI_PROVIDER=openai-compatible sudo useradd --system --no-create-home --shell /usr/sbin/nologin pronote-sync
AI_BASE_URL=https://openrouter.ai/api/v1
AI_MODEL=fournisseur/modele
AI_API_KEY=your-openrouter-key
AI_ALLOW_INSECURE_HTTP=false
# Ollama local (HTTP) # Cloner le dépôt
AI_PROVIDER=openai-compatible sudo git clone https://git.antoineve.me/AntoineVe/college-infos /opt/pronote-sync
AI_BASE_URL=http://127.0.0.1:11434/v1 sudo chown -R pronote-sync:pronote-sync /opt/pronote-sync
AI_MODEL=modele-local
AI_API_KEY=local-not-required # Créer l'environnement virtuel
AI_ALLOW_INSECURE_HTTP=true 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 ## Configuration
| 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 :
```bash ```bash
cp .env.example .env sudo -u pronote-sync cp /opt/pronote-sync/.env.example /etc/pronote-sync/pronote-sync.env
# Éditer .env avec vos paramètres
``` ```
> **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. 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`.