diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..e461b4b --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,60 @@ +# Hooks pre-commit pour pronote-sync +# Installation : pre-commit install +# Exécution manuelle : pre-commit run --all-files +default_language_version: + python: python3 + +repos: + # Outils du venv (ruff, mypy, bandit) — exécutés dans l'environnement géré par pre-commit + - repo: local + hooks: + - id: ruff-check + name: ruff check + entry: ruff check + language: python + additional_dependencies: ["ruff>=0.4.0"] + types: [python] + + - id: ruff-format + name: ruff format + entry: ruff format + language: python + additional_dependencies: ["ruff>=0.4.0"] + types: [python] + + - id: mypy + name: mypy + entry: mypy + language: python + additional_dependencies: ["mypy>=1.10.0"] + types: [python] + pass_filenames: true + + - id: bandit + name: bandit + entry: bandit + args: [-c, pyproject.toml, -r] + language: python + additional_dependencies: ["bandit>=1.7.0"] + types: [python] + + # Hooks standard de pre-commit + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: trailing-whitespace + exclude: 'GUIDE_DEV_PYTHON\.md' + - id: end-of-file-fixer + exclude: 'GUIDE_DEV_PYTHON\.md' + - id: check-yaml + - id: check-added-large-files + args: [--maxkb=500] + exclude: 'GUIDE_DEV_PYTHON\.md' + - id: check-merge-conflict + + # Détection de secrets + - repo: https://github.com/Yelp/detect-secrets + rev: v1.5.0 + hooks: + - id: detect-secrets + args: [--baseline, .secrets.baseline] diff --git a/.secrets.baseline b/.secrets.baseline new file mode 100644 index 0000000..81af743 --- /dev/null +++ b/.secrets.baseline @@ -0,0 +1,144 @@ +{ + "version": "1.5.0", + "plugins_used": [ + { + "name": "ArtifactoryDetector" + }, + { + "name": "AWSKeyDetector" + }, + { + "name": "AzureStorageKeyDetector" + }, + { + "name": "Base64HighEntropyString", + "limit": 4.5 + }, + { + "name": "BasicAuthDetector" + }, + { + "name": "CloudantDetector" + }, + { + "name": "DiscordBotTokenDetector" + }, + { + "name": "GitHubTokenDetector" + }, + { + "name": "GitLabTokenDetector" + }, + { + "name": "HexHighEntropyString", + "limit": 3.0 + }, + { + "name": "IbmCloudIamDetector" + }, + { + "name": "IbmCosHmacDetector" + }, + { + "name": "IPPublicDetector" + }, + { + "name": "JwtTokenDetector" + }, + { + "name": "KeywordDetector", + "keyword_exclude": "" + }, + { + "name": "MailchimpDetector" + }, + { + "name": "NpmDetector" + }, + { + "name": "OpenAIDetector" + }, + { + "name": "PrivateKeyDetector" + }, + { + "name": "PypiTokenDetector" + }, + { + "name": "SendGridDetector" + }, + { + "name": "SlackDetector" + }, + { + "name": "SoftlayerDetector" + }, + { + "name": "SquareOAuthDetector" + }, + { + "name": "StripeDetector" + }, + { + "name": "TelegramBotTokenDetector" + }, + { + "name": "TwilioKeyDetector" + } + ], + "filters_used": [ + { + "path": "detect_secrets.filters.allowlist.is_line_allowlisted" + }, + { + "path": "detect_secrets.filters.common.is_ignored_due_to_verification_policies", + "min_level": 2 + }, + { + "path": "detect_secrets.filters.heuristic.is_indirect_reference" + }, + { + "path": "detect_secrets.filters.heuristic.is_likely_id_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_lock_file" + }, + { + "path": "detect_secrets.filters.heuristic.is_not_alphanumeric_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_potential_uuid" + }, + { + "path": "detect_secrets.filters.heuristic.is_prefixed_with_dollar_sign" + }, + { + "path": "detect_secrets.filters.heuristic.is_sequential_string" + }, + { + "path": "detect_secrets.filters.heuristic.is_swagger_file" + }, + { + "path": "detect_secrets.filters.heuristic.is_templated_secret" + }, + { + "path": "detect_secrets.filters.regex.should_exclude_file", + "pattern": [ + "\\.venv/.*", + "\\.git/.*" + ] + } + ], + "results": { + "GUIDE_DEV_PYTHON.md": [ + { + "type": "Hex High Entropy String", + "filename": "GUIDE_DEV_PYTHON.md", + "hashed_secret": "90bd1b48e958257948487b90bee080ba5ed00caa", + "is_verified": false, + "line_number": 5073 + } + ] + }, + "generated_at": "2026-09-05T17:53:24Z" +} diff --git a/TODO.md b/TODO.md index 290ab5d..7c9b2e3 100644 --- a/TODO.md +++ b/TODO.md @@ -10,14 +10,14 @@ Mettre en place le dépôt, l'environnement, l'arborescence du package et la chaîne d'outils (lint/type/test/pré-commit). -- [ ] Créer l'environnement virtuel Python (≥ 3.13.5) et l'activer (`python -m venv venv`). -- [ ] Créer `pyproject.toml` d'après l'Annexe C (projet `pronote-sync`, `requires-python = ">=3.13.5"`, dépendances, extras `dev` et `ai-litellm`, script console `pronote-sync`). -- [ ] Configurer ruff (`line-length = 100`, `target-version = "py313"`, règles E/W/F/I/B/C4/UP), mypy (`strict`), bandit et coverage (`fail_under = 90`) dans `pyproject.toml`. -- [ ] Créer `.gitignore` (venv, `__pycache__`, `.env`, `.blog_rss_state.json`, `.coverage`, artefacts `.ics` temporaires). -- [ ] Créer l'arborescence `pronote_sync/` avec `__init__.py` dans chaque package (`config`, `models`, `sources/pronote`, `sources/blog`, `sources/theoretical`, `sync`, `synthesis`, `channels`, `pipeline/steps`, `cli`, `utils`, `tests`). -- [ ] Ajouter la configuration pre-commit (ruff, mypy, bandit, detect-secrets, `trailing-whitespace`, `end-of-file`). -- [ ] Installer le projet en mode éditable : `pip install -e ".[dev]"`. -- [ ] Créer le commit initial (scaffold + `.gitignore`, sans aucun secret). +- [x] Créer l'environnement virtuel Python (≥ 3.13.5) et l'activer (`python -m venv venv`). +- [x] Créer `pyproject.toml` d'après l'Annexe C (projet `pronote-sync`, `requires-python = ">=3.13.5"`, dépendances, extras `dev` et `ai-litellm`, script console `pronote-sync`). +- [x] Configurer ruff (`line-length = 100`, `target-version = "py313"`, règles E/W/F/I/B/C4/UP), mypy (`strict`), bandit et coverage (`fail_under = 90`) dans `pyproject.toml`. +- [x] Créer `.gitignore` (venv, `__pycache__`, `.env`, `.blog_rss_state.json`, `.coverage`, artefacts `.ics` temporaires). +- [x] Créer l'arborescence `pronote_sync/` avec `__init__.py` dans chaque package (`config`, `models`, `sources/pronote`, `sources/blog`, `sources/theoretical`, `sync`, `synthesis`, `channels`, `pipeline/steps`, `cli`, `utils`, `tests`). +- [x] Ajouter la configuration pre-commit (ruff, mypy, bandit, detect-secrets, `trailing-whitespace`, `end-of-file`). +- [x] Installer le projet en mode éditable : `pip install -e ".[dev]"`. +- [x] Créer le commit initial (scaffold + `.gitignore`, sans aucun secret). ### Critères d'acceptation - Le package `pronote_sync` est importable sans erreur. diff --git a/pyproject.toml b/pyproject.toml index c4873d7..32e4735 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -93,6 +93,10 @@ skips = ["B101"] # Ignorer les assertions (utilisées dans les tests) [tool.ruff] line-length = 100 target-version = "py313" +# Exclure la documentation markdown (ruff format ne doit pas toucher aux blocs de code Python inclus) +extend-exclude = ["GUIDE_DEV_PYTHON.md"] + +[tool.ruff.lint] select = [ "E", # pycodestyle errors "W", # pycodestyle warnings