feat(M1): échafaudage et outillage complétés

- .pre-commit-config.yaml : hooks ruff, mypy, bandit, detect-secrets, whitespace
- .secrets.baseline : baseline detect-secrets (faux positif GUIDE_DEV_PYTHON.md)
- pyproject.toml : migration clés ruff vers [tool.ruff.lint], exclusion guide du format
- pip install -e ".[dev]" : dépendances installées dans le venv
- pre-commit install : hook git installé
- TODO.md : items M1 cochés

Validations :
- ruff check . : PASS
- ruff format --check . : PASS
- mypy . : PASS (17 fichiers)
- pytest : PASS (0 test, infrastructure OK)
- bandit -r pronote_sync/ : PASS
- pre-commit run --all-files : 9 passed, 1 skipped, 0 failed
- import pronote_sync : OK

Co-authored-by: OpenCode/orchestrator <opencode-orchestrator@agents.invalid>
This commit is contained in:
2026-09-05 20:05:06 +02:00
parent 489fff874f
commit 03a4377f01
4 changed files with 216 additions and 8 deletions

60
.pre-commit-config.yaml Normal file
View File

@@ -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]

144
.secrets.baseline Normal file
View File

@@ -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"
}

16
TODO.md
View File

@@ -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). 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`). - [x] 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`). - [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`).
- [ ] 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] 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). - [x] 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`). - [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`).
- [ ] Ajouter la configuration pre-commit (ruff, mypy, bandit, detect-secrets, `trailing-whitespace`, `end-of-file`). - [x] 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]"`. - [x] Installer le projet en mode éditable : `pip install -e ".[dev]"`.
- [ ] Créer le commit initial (scaffold + `.gitignore`, sans aucun secret). - [x] Créer le commit initial (scaffold + `.gitignore`, sans aucun secret).
### Critères d'acceptation ### Critères d'acceptation
- Le package `pronote_sync` est importable sans erreur. - Le package `pronote_sync` est importable sans erreur.

View File

@@ -93,6 +93,10 @@ skips = ["B101"] # Ignorer les assertions (utilisées dans les tests)
[tool.ruff] [tool.ruff]
line-length = 100 line-length = 100
target-version = "py313" 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 = [ select = [
"E", # pycodestyle errors "E", # pycodestyle errors
"W", # pycodestyle warnings "W", # pycodestyle warnings