From 2deeb83c7659b0fd956bced2540bcc7cfcebcc6c Mon Sep 17 00:00:00 2001 From: Antoine Van Elstraete Date: Tue, 8 Sep 2026 17:52:45 +0200 Subject: [PATCH] feat(M15): README, README.LLM.md, LICENSE, CHANGELOG, and final cleanup Complete the M15 documentation and final review milestone: README.md (French, brief): - Project description, quick start, usage, deployment link, acknowledgments - Acknowledgments: pronotepy, icalendar, caldav, slixmpp, pydantic, openai, feedparser, beautifulsoup4, and inspiration from pronote-digest (Antoine Coulon) - Author: Antoine Van Elstraete README.LLM.md (English, AI agent guide): - Prerequisites, installation on LXC/VPS (Debian/CentOS) - Non-secret configuration preparation (all env vars listed) - Secret variables clearly identified as operator-only - Pre-deployment checks (check_secrets.py, pip check, dry-run) - systemd/timer/logrotate installation steps - Notes for AI agent (do not commit secrets, do not modify existing files) LICENSE: - Standard MIT License, copyright Antoine Van Elstraete (2026) CHANGELOG.md: - Initial changelog following Keep a Changelog format - Covers M1 through M14 with milestone summaries - Gitea Actions noted as planned/optional, not delivered .gitignore: - Added FEAT_* pattern for temporary work files TODO.md: - M15 items 1-4 checked (README, architecture docs, CHANGELOG+LICENSE, final review) - M15 item 5 (Gitea Actions) left unchecked (optional, not done) Co-authored-by: opencode/tech-writer --- .gitignore | 1 + CHANGELOG.md | 27 ++++++++++ LICENSE | 21 ++++++++ README.LLM.md | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 69 ++++++++++++++++++++++++ TODO.md | 8 +-- 6 files changed, 269 insertions(+), 4 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 LICENSE create mode 100644 README.LLM.md create mode 100644 README.md diff --git a/.gitignore b/.gitignore index 16a6a24..94780b2 100644 --- a/.gitignore +++ b/.gitignore @@ -52,6 +52,7 @@ Thumbs.db # --- Local scratch / WIP files --- FIXME_* +FEAT_* TEST_* .worktrees/ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..a5642eb --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,27 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [0.1.0] - 2026-09-08 + +Initial release covering milestones M1 through M14. + +### Added +- **M1 (Scaffolding)**: Python project structure with `pyproject.toml`, and tooling configuration for `ruff`, `mypy`, `bandit`, and `pre-commit`. +- **M2 (Configuration & secrets)**: Pydantic Settings for configuration management, `SecretStr` for sensitive fields, and redaction utilities (`redact_url`, `redact_secrets`, `redact_exception`) with `RedactingFormatter` for logging. +- **M3 (Data models)**: 16 Pydantic models and 6 enums across 10 modules, including frozen contracts and mutable work results. +- **M4 (Pronote sources)**: iCal fetch and parse, `pronotepy.ParentClient` integration, automatic fallback logic for `auto`, `ical`, and `pronotepy` modes, and error redaction for sensitive data. +- **M5 (Blog RSS)**: `feedparser`-based RSS client with GUID deduplication, HTTP cache support (ETag/If-Modified-Since), and `BlogRSSState` persistence. +- **M6 (Theoretical agenda)**: JSON provider with week parity (even/odd), school holidays calendar, and deterministic IDs for events. +- **M7 (CalDAV sync)**: Differential synchronization by UID, `X-PRONOTE-SYNC-MANAGED` marker for managed events, idempotent operations, preserved cancelled events, and dry-run support. +- **M8 (Agenda diff)**: `AgendaComparator` with deterministic matching, and generation of `AgendaDiff`/`AgendaChange` objects for tracking differences. +- **M9 (AI synthesis)**: `SynthesisProvider` protocol, OpenAI provider, optional `litellm` provider, and `openai-compatible` provider with degraded mode (returns `None` on failure). +- **M10 (XMPP channel)**: `XmppChannel` using `slixmpp`, formatted messages (synthesis, homeworks, changes, messages, blog), and error handling that returns `False` on failure. +- **M11 (Pipeline orchestration)**: `PipelineRunner` as composition root, 7 pipeline steps, degraded error handling, dry-run mode, and iCal reuse within a single run. +- **M12 (CLI entry point)**: `pronote-sync` command with `--dry-run` and `--log-level` options, redacted error display, and safe traceback in DEBUG mode. +- **M13 (Tests & coverage)**: 636 tests with 95.67% coverage, test fixtures (`pronote-4e.ics`, `pronote-6e.ics`), shared `conftest.py`, and secret non-leak tests. +- **M14 (Deployment)**: systemd service and timer (daily at 18:00), logrotate configuration (daily, rotate 7, compress), `check_secrets.py` pre-deployment scanner, and exploitation guide. +- **Other**: MIT License. Gitea Actions CI/CD reference for LXC/VPS (Debian/CentOS) is planned and optional, not delivered in this release. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e2f32fe --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Antoine Van Elstraete + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.LLM.md b/README.LLM.md new file mode 100644 index 0000000..799d9b7 --- /dev/null +++ b/README.LLM.md @@ -0,0 +1,147 @@ +# pronote-sync — AI Agent Setup Guide + +This document guides an AI agent through installing and pre-configuring the `pronote-sync` project on a fresh Linux host (Debian/CentOS). It covers environment setup, dependency installation, and configuration file preparation. It does **NOT** cover secrets provisioning — those must be provided by the operator. + +--- + +## Prerequisites + +- Python ≥ 3.13.5 (check with `python3 --version`) +- Git +- A non-root service user (e.g., `pronote-sync`) +- Target paths: + - `/opt/pronote-sync` (code) + - `/var/lib/pronote-sync` (state) + - `/var/log/pronote-sync` (logs) + - `/etc/pronote-sync` (config) + +--- + +## Installation Steps + +```bash +# Create service user +sudo useradd --system --no-create-home --shell /usr/sbin/nologin pronote-sync + +# Clone the repository +sudo git clone /opt/pronote-sync +sudo chown -R pronote-sync:pronote-sync /opt/pronote-sync + +# Create virtual environment +cd /opt/pronote-sync +sudo -u pronote-sync python3.13 -m venv .venv +sudo -u pronote-sync .venv/bin/pip install -e ".[dev]" + +# Create directories +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 Preparation (Without Secrets) + +```bash +# Copy the example config +sudo -u pronote-sync cp /opt/pronote-sync/.env.example /etc/pronote-sync/pronote-sync.env + +# The operator must fill in secrets (PRONOTE_PASSWORD, CALDAV_PASSWORD, XMPP_PASSWORD, AI_API_KEY, etc.) +# Do NOT populate secrets automatically — leave them for the operator. +``` + +### Non-Secret Environment Variables (Pre-Configurable) + +The following variables can be safely pre-configured in `/etc/pronote-sync/pronote-sync.env`: + +- **Pronote:** + - `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`) + +- **CalDAV:** + - `CALDAV_CALENDAR_PATH` (e.g., `/pronote-sync/`) + - `CALDAV_ALLOW_INSECURE_HTTP` (default: `false`) + +- **Sync Window:** + - `SYNC_PAST_DAYS`, `SYNC_FUTURE_DAYS` + +- **Theoretical Agenda:** + - `THEORETICAL_AGENDA_PATH`, `SCHOOL_HOLIDAYS_PATH` + - `THEORETICAL_WEEK_ANCHOR_DATE`, `THEORETICAL_WEEK_ANCHOR_TYPE` + +- **XMPP:** + - `XMPP_ENABLED`, `XMPP_HOST`, `XMPP_PORT`, `XMPP_USE_TLS`, `XMPP_TIMEOUT`, `XMPP_RESOURCE` + +- **AI:** + - `AI_ENABLED`, `AI_PROVIDER`, `AI_BASE_URL`, `AI_MODEL`, `AI_ALLOW_INSECURE_HTTP` + +- **Blog:** + - `BLOG_ENABLED`, `BLOG_RSS_URL` + +- **General:** + - `DRY_RUN`, `LOG_LEVEL` + +### Secret Variables (Operator Must Provide) + +**Do NOT set these variables automatically.** The operator must manually provide the following secrets: + +- **Pronote:** + - `PRONOTE_ICAL_URL`, `PRONOTE_URL`, `PRONOTE_USERNAME`, `PRONOTE_PASSWORD` + +- **CalDAV:** + - `CALDAV_URL`, `CALDAV_USERNAME`, `CALDAV_PASSWORD` + +- **XMPP:** + - `XMPP_JID`, `XMPP_PASSWORD`, `XMPP_TO` + +- **AI:** + - `AI_API_KEY` + +--- + +## Pre-Deployment Checks + +```bash +# Verify no secrets in the codebase +/opt/pronote-sync/.venv/bin/python /opt/pronote-sync/scripts/check_secrets.py + +# Verify dependencies +/opt/pronote-sync/.venv/bin/python -m pip check + +# Dry-run test (will fail without secrets, but verifies the environment) +/opt/pronote-sync/.venv/bin/pronote-sync --dry-run +``` + +--- + +## systemd Installation + +```bash +# Install systemd units +sudo install -m 0644 /opt/pronote-sync/deploy/systemd/pronote-sync.service /etc/systemd/system/ +sudo install -m 0644 /opt/pronote-sync/deploy/systemd/pronote-sync.timer /etc/systemd/system/ + +# Install logrotate config +sudo install -m 0644 /opt/pronote-sync/deploy/logrotate/pronote_sync /etc/logrotate.d/pronote_sync + +# Reload and enable +sudo systemctl daemon-reload +sudo systemctl enable --now pronote-sync.timer +``` + +--- + +## Notes for the AI Agent + +- **Do NOT commit or write secrets** to any file in the repository. +- **Do NOT modify** `.gitignore`, `pyproject.toml`, or existing source files. +- If `python3.13` is not available, install it first: + - Debian: `sudo apt install python3.13` + - CentOS: Compile from source or use `dnf` if available. +- The `check_secrets.py` script exits with: + - `0` (clean) + - `1` (secrets found) + - `2` (error) +- All paths in the systemd unit assume `/opt/pronote-sync` — adjust if installed elsewhere. +- The operator **must** provide real values for all **SECRET** variables before enabling the timer. diff --git a/README.md b/README.md new file mode 100644 index 0000000..7c043c0 --- /dev/null +++ b/README.md @@ -0,0 +1,69 @@ +# pronote-sync + +Synchronisation Pronote → CalDAV + XMPP. + +--- + +Synchronise l'agenda et les devoirs de **Pronote** vers un calendrier **CalDAV** et envoie un résumé quotidien par **XMPP**. Supporte les sources iCal et `pronotepy` avec repli automatique. Synthèse IA optionnelle. + +--- + +## 🚀 Démarrage rapide + +```bash +# Cloner le dépôt +git clone +cd pronote-sync + +# Créer l'environnement virtuel +python3.13 -m venv .venv +source .venv/bin/activate + +# Installer +pip install -e ".[dev]" + +# Configurer +cp .env.example .env +# Éditer .env avec vos paramètres (voir .env.example pour le détail) + +# Tester +pronote-sync --dry-run --log-level DEBUG +``` + +--- + +## 📖 Utilisation + +```bash +pronote-sync # Exécute la synchronisation +pronote-sync --dry-run # Simulation sans écriture +pronote-sync --log-level DEBUG # Verbosité des journaux +``` + +--- + +## 🛠️ Déploiement + +Les artefacts pour **systemd/timer** et **logrotate** sont fournis dans `deploy/`. Voir [docs/exploitation.md](docs/exploitation.md) pour plus de détails. + +--- + +## 🙏 Remerciements + +Ce projet repose sur les bibliothèques open-source suivantes : +- [pronotepy](https://github.com/bain3/pronotepy) — client Pronote +- [icalendar](https://github.com/collective/icalendar) — parsing iCal +- [caldav](https://github.com/python-caldav/caldav) — client CalDAV +- [slixmpp](https://github.com/poezio/slixmpp) — client XMPP +- [pydantic](https://github.com/pydantic/pydantic) — validation et configuration +- [openai](https://github.com/openai/openai-python) — synthèse IA +- [feedparser](https://github.com/kurtmckee/feedparser) — parsing RSS +- [beautifulsoup4](https://www.crummy.com/software/BeautifulSoup/) — parsing HTML + +Inspiré de [pronote-digest](https://github.com/antoine-coulon/pronote-digest) par Antoine Coulon. + +--- + +## Licence + +MIT — voir [LICENSE](LICENSE). diff --git a/TODO.md b/TODO.md index 1a25702..240e4a5 100644 --- a/TODO.md +++ b/TODO.md @@ -294,10 +294,10 @@ Mettre en production de façon supervisée (planification, rotation des logs, v Rédiger la documentation utilisateur et finaliser le projet. -- [ ] Créer `README.md` (installation, configuration `.env`, usage CLI, systemd/docker, limites, RGPD). -- [ ] Documenter l'architecture (pipeline, modules) en résumé. -- [ ] Ajouter `CHANGELOG` initial et la licence (MIT). -- [ ] Revue finale : cohérence avec le guide, aucun secret documenté en clair. +- [x] Créer `README.md` (installation, configuration `.env`, usage CLI, systemd/docker, limites, RGPD). +- [x] Documenter l'architecture (pipeline, modules) en résumé. +- [x] Ajouter `CHANGELOG` initial et la licence (MIT). +- [x] Revue finale : cohérence avec le guide, aucun secret documenté en clair. - [ ] (Optionnel) Configurer Gitea Actions (pytest + bandit + ruff + mypy) pour le déploiement LXC/VPS (Debian/CentOS). ### Critères d'acceptation