pmescan 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. pmescan-0.1.0/.gitignore +25 -0
  2. pmescan-0.1.0/01-VISION.md +62 -0
  3. pmescan-0.1.0/02-UTILISATION.md +89 -0
  4. pmescan-0.1.0/03-CONCEPTION.md +184 -0
  5. pmescan-0.1.0/04-ETAPES.md +75 -0
  6. pmescan-0.1.0/CONTRIBUTING.md +108 -0
  7. pmescan-0.1.0/LICENSE +21 -0
  8. pmescan-0.1.0/PKG-INFO +268 -0
  9. pmescan-0.1.0/README-mode-agressif.md +101 -0
  10. pmescan-0.1.0/README.md +234 -0
  11. pmescan-0.1.0/pmescan/__init__.py +6 -0
  12. pmescan-0.1.0/pmescan/autorisation.py +70 -0
  13. pmescan-0.1.0/pmescan/checks/__init__.py +1 -0
  14. pmescan-0.1.0/pmescan/checks/base.py +21 -0
  15. pmescan-0.1.0/pmescan/checks/cms.py +460 -0
  16. pmescan-0.1.0/pmescan/checks/dns_mail.py +176 -0
  17. pmescan-0.1.0/pmescan/checks/entetes.py +158 -0
  18. pmescan-0.1.0/pmescan/checks/exposes.py +118 -0
  19. pmescan-0.1.0/pmescan/checks/ports.py +170 -0
  20. pmescan-0.1.0/pmescan/checks/tls.py +252 -0
  21. pmescan-0.1.0/pmescan/cli.py +243 -0
  22. pmescan-0.1.0/pmescan/domaine.py +84 -0
  23. pmescan-0.1.0/pmescan/i18n/__init__.py +19 -0
  24. pmescan-0.1.0/pmescan/i18n/fr.yaml +607 -0
  25. pmescan-0.1.0/pmescan/modele.py +45 -0
  26. pmescan-0.1.0/pmescan/notation.py +34 -0
  27. pmescan-0.1.0/pmescan/rapport/__init__.py +5 -0
  28. pmescan-0.1.0/pmescan/rapport/generateur.py +164 -0
  29. pmescan-0.1.0/pmescan/rapport/modele.html +257 -0
  30. pmescan-0.1.0/pmescan/scanner.py +78 -0
  31. pmescan-0.1.0/pyproject.toml +79 -0
  32. pmescan-0.1.0/tests/__init__.py +0 -0
  33. pmescan-0.1.0/tests/conftest.py +171 -0
  34. pmescan-0.1.0/tests/fixtures/entetes_non_securises.json +10 -0
  35. pmescan-0.1.0/tests/fixtures/entetes_securises.json +15 -0
  36. pmescan-0.1.0/tests/test_autorisation.py +174 -0
  37. pmescan-0.1.0/tests/test_cli.py +576 -0
  38. pmescan-0.1.0/tests/test_cms.py +686 -0
  39. pmescan-0.1.0/tests/test_dns_mail.py +231 -0
  40. pmescan-0.1.0/tests/test_domaine.py +188 -0
  41. pmescan-0.1.0/tests/test_entetes.py +119 -0
  42. pmescan-0.1.0/tests/test_exposes.py +161 -0
  43. pmescan-0.1.0/tests/test_i18n.py +367 -0
  44. pmescan-0.1.0/tests/test_notation.py +68 -0
  45. pmescan-0.1.0/tests/test_ports.py +378 -0
  46. pmescan-0.1.0/tests/test_rapport.py +246 -0
  47. pmescan-0.1.0/tests/test_scanner.py +228 -0
  48. pmescan-0.1.0/tests/test_tls.py +216 -0
@@ -0,0 +1,25 @@
1
+ # Environnements Python
2
+ .venv/
3
+ venv/
4
+ __pycache__/
5
+ *.py[cod]
6
+
7
+ # Build / distribution
8
+ build/
9
+ dist/
10
+ *.egg-info/
11
+
12
+ # Tests / outils
13
+ .pytest_cache/
14
+ .mypy_cache/
15
+ .ruff_cache/
16
+
17
+ # Rapports générés
18
+ *.pdf
19
+ consent.log
20
+
21
+ # Éditeurs / OS
22
+ .vscode/
23
+ .idea/
24
+ .DS_Store
25
+ Thumbs.db
@@ -0,0 +1,62 @@
1
+ # 01 — Vision : à quoi sert le projet
2
+
3
+ ## Nom
4
+
5
+ **pmescan** — Scanner de sécurité pour PME francophones.
6
+
7
+ ## Le problème
8
+
9
+ Les petites et moyennes entreprises (PME), en particulier au Sénégal et en Afrique
10
+ francophone, ont presque toutes une présence en ligne : site vitrine, boutique
11
+ WordPress, adresse e-mail professionnelle. Mais :
12
+
13
+ - Elles n'ont **pas d'équipe sécurité** ni de budget pour un audit à 2 000 €.
14
+ - Les outils existants (Mozilla Observatory, Nuclei, SSL Labs) sont **en anglais**,
15
+ **techniques**, et crachent une sortie **illisible pour un gérant**.
16
+ - Résultat : un certificat TLS expiré, un WordPress non à jour, une base de données
17
+ MySQL exposée sur Internet, ou l'absence de DMARC passent inaperçus — jusqu'à
18
+ l'incident (site piraté, usurpation d'e-mail, fuite de données clients).
19
+
20
+ ## La solution
21
+
22
+ Un outil **gratuit et open source** qui scanne un site web et produit un **rapport
23
+ PDF en français clair**, compréhensible par un dirigeant non technique. Chaque faille
24
+ est traduite en **risque métier** et accompagnée d'une **action priorisée**.
25
+
26
+ Exemple de traduction :
27
+
28
+ | Au lieu de… | pmescan dit… |
29
+ |---|---|
30
+ | `DMARC record not found` | « N'importe qui peut envoyer des e-mails en se faisant passer pour votre entreprise. » |
31
+ | `TLS 1.0 enabled` | « Votre site utilise un chiffrement obsolète qu'un attaquant peut casser. » |
32
+ | `Port 3306 open` | « Votre base de données est accessible depuis Internet. À fermer en urgence. » |
33
+
34
+ ## Pour qui
35
+
36
+ 1. **Gérants de PME** — veulent savoir en 30 secondes si leur site est à risque.
37
+ 2. **Agences web et prestataires** — veulent un rapport en marque blanche pour leurs clients.
38
+ 3. **Freelances sécurité / étudiants** — veulent un outil pédagogique et un point de départ.
39
+
40
+ ## Ce que le projet n'est pas
41
+
42
+ - Ce n'est **pas un outil de piratage**. Le mode par défaut ne fait que lire des
43
+ informations publiques.
44
+ - Ce n'est **pas un pentest complet**. Il repère les failles courantes, pas les 0-day.
45
+ - Ce n'est **pas** un remplaçant d'un expert pour les gros systèmes critiques.
46
+
47
+ ## Objectif de différenciation
48
+
49
+ Là où les concurrents s'arrêtent à la donnée technique brute, pmescan ajoute trois
50
+ choses qu'aucun ne réunit :
51
+
52
+ 1. **Langue** : tout en français (et plus tard wolof, anglais).
53
+ 2. **Vulgarisation** : risque métier + qui corrige + effort estimé.
54
+ 3. **Ancrage local** : références à la loi sénégalaise 2008-12 sur les données
55
+ personnelles et à la CDP, pour crédibiliser le rapport auprès des dirigeants.
56
+
57
+ ## Mesure du succès (version 1)
58
+
59
+ - Un gérant comprend son rapport **sans aide**.
60
+ - Un scan passif complet s'exécute en **moins de 60 secondes**.
61
+ - Le README montre la valeur en **30 secondes** (démo + exemple de PDF).
62
+ - Publié sur **PyPI**, installable en une commande.
@@ -0,0 +1,89 @@
1
+ # 02 — Utilisation : comment le projet s'utilise
2
+
3
+ ## Installation
4
+
5
+ Depuis les sources (pmescan n'est pas encore publié sur PyPI) :
6
+
7
+ ```bash
8
+ python -m venv .venv
9
+ .venv/bin/pip install . # Windows : .venv\Scripts\pip install .
10
+ ```
11
+
12
+ Une fois publié : `pip install pmescan`. Pour le rapport PDF, il faut en plus les
13
+ bibliothèques système de WeasyPrint (voir le README).
14
+
15
+ ## Les trois modes
16
+
17
+ | Mode | Commande | Ce qu'il fait | Autorisation |
18
+ |---|---|---|---|
19
+ | **Passif** | *(défaut)* | Lit seulement ce que le site publie : TLS, en-têtes, DNS/e-mail, page d'accueil pour le CMS. | Non |
20
+ | **Actif** | `--mode actif --jai-l-autorisation` | Ajoute les fichiers exposés, les fichiers de version du CMS et le test des ports. | Oui |
21
+ | **Agressif** | `--mode agressif --jai-l-autorisation` | Réservé à de futures vérifications. Équivaut aujourd'hui au mode actif. | Oui |
22
+
23
+ > ⚠️ Les modes actif et agressif ne s'utilisent que sur une cible dont vous êtes
24
+ > propriétaire, ou pour laquelle vous avez une autorisation écrite. Voir
25
+ > `README-mode-agressif.md`.
26
+
27
+ ## Commandes de base
28
+
29
+ ```bash
30
+ # Scan passif, résultat dans le terminal
31
+ pmescan scan exemple.sn
32
+
33
+ # Rapport PDF en français
34
+ pmescan scan exemple.sn --pdf
35
+
36
+ # Préciser le fichier PDF
37
+ pmescan scan exemple.sn --pdf --sortie rapport-client.pdf
38
+
39
+ # Sortie JSON (intégration, script)
40
+ pmescan scan exemple.sn --json
41
+
42
+ # Mode actif (fichiers exposés, ports…) : autorisation obligatoire
43
+ pmescan scan exemple.sn --mode actif --jai-l-autorisation
44
+
45
+ # Vérifier aussi les failles connues du CMS (contacte osv.dev)
46
+ pmescan scan exemple.sn --verifier-cve
47
+ ```
48
+
49
+ ## Ce que voit l'utilisateur
50
+
51
+ Le terminal affiche une ligne par vérification, `[OK]` ou `[PROBLEME]`, avec
52
+ l'identifiant et la gravité, puis la note globale :
53
+
54
+ ```
55
+ [PROBLEME] dmarc_absent (elevee)
56
+ [OK] cms_detecte (info)
57
+ Note globale : D (47/100)
58
+ ```
59
+
60
+ Les explications en français se trouvent dans le rapport PDF.
61
+
62
+ ## Contenu du rapport PDF
63
+
64
+ - **Page 1** : note globale (A à F), résumé en 3 phrases, les 3 actions les plus urgentes.
65
+ - **Fiches** : une par problème, avec :
66
+ - le risque expliqué simplement ;
67
+ - la gravité (critique, élevée, moyenne ou faible) ;
68
+ - qui doit corriger (hébergeur, développeur ou gérant) ;
69
+ - l'effort estimé.
70
+ - **Annexe technique** : identifiants et preuves brutes pour le prestataire.
71
+ - **Rappel légal** : loi sénégalaise 2008-12 et CDP.
72
+
73
+ ## Cas d'usage typiques
74
+
75
+ 1. **Un gérant** lance `pmescan scan monsite.sn --pdf`, lit les 3 actions urgentes et
76
+ les transmet à son hébergeur.
77
+ 2. **Une agence web** scanne chaque mois les sites de ses clients, en mode actif avec
78
+ leur autorisation écrite, et leur remet le PDF.
79
+ 3. **Une intégration continue** lance `pmescan scan monsite.sn --json`. Le pipeline
80
+ échoue si le code de sortie vaut 1, c'est-à-dire s'il y a un problème critique.
81
+
82
+ ## Codes de sortie (pour les scripts)
83
+
84
+ | Code | Signification |
85
+ |---|---|
86
+ | `0` | Scan terminé, aucun problème critique. |
87
+ | `1` | Scan terminé, au moins un problème critique. |
88
+ | `2` | Erreur : option ou domaine invalide, PDF impossible à générer, erreur imprévue ou interruption. |
89
+ | `3` | Refus : mode actif ou agressif sans `--jai-l-autorisation`. |
@@ -0,0 +1,184 @@
1
+ # 03 — Conception : comment on va le créer
2
+
3
+ ## Principe directeur
4
+
5
+ - **Code en français** : noms de variables, fonctions, classes, commentaires.
6
+ - **Modulaire** : chaque vérification (« check ») est indépendante et renvoie le même
7
+ type d'objet `Resultat`.
8
+ - **Textes séparés du code** : les explications vulgarisées vivent dans des fichiers
9
+ YAML, pas dans le code. Un non-développeur peut les améliorer, et on ajoute une
10
+ langue sans toucher au code.
11
+ - **Sans dépendance lourde** : pas besoin d'installer `nmap` ; le scan de ports se fait
12
+ en Python via `asyncio`.
13
+
14
+ ## Langage et bibliothèques
15
+
16
+ | Besoin | Choix | Pourquoi |
17
+ |---|---|---|
18
+ | Langage | Python 3.11+ | Lisible, riche en libs sécurité, facile à contribuer. |
19
+ | CLI | `typer` | Interface en ligne de commande propre et typée. |
20
+ | TLS | `sslyze` | Analyse fine des certificats et protocoles. |
21
+ | HTTP | `httpx` | Client HTTP moderne, async. |
22
+ | DNS / e-mail | `dnspython` | Requêtes SPF, DMARC, DKIM, MX, DNSSEC. |
23
+ | CVE | API OSV / NVD | Comparer versions CMS aux failles connues. |
24
+ | Ports | `asyncio` (natif) | Connexion TCP sans dépendance externe. |
25
+ | Rapport PDF | `jinja2` + `weasyprint` | HTML → PDF, mise en page soignée. |
26
+ | Tests | `pytest` | Standard Python. |
27
+ | Qualité | `ruff` + `mypy` | Lint et typage. |
28
+
29
+ ## Arborescence du projet
30
+
31
+ ```
32
+ pmescan/
33
+ ├── pyproject.toml # métadonnées + dépendances (packaging PyPI)
34
+ ├── README.md
35
+ ├── README-mode-agressif.md
36
+ ├── LICENSE # MIT
37
+ ├── CONTRIBUTING.md
38
+ ├── pmescan/
39
+ │ ├── __init__.py
40
+ │ ├── cli.py # point d'entrée Typer
41
+ │ ├── modele.py # classes Resultat, Gravite, Cible
42
+ │ ├── scanner.py # orchestre les checks selon le mode
43
+ │ ├── checks/
44
+ │ │ ├── __init__.py
45
+ │ │ ├── base.py # classe abstraite Verification
46
+ │ │ ├── tls.py
47
+ │ │ ├── entetes.py # en-têtes HTTP
48
+ │ │ ├── dns_mail.py
49
+ │ │ ├── cms.py
50
+ │ │ ├── ports.py
51
+ │ │ └── exposes.py # fichiers sensibles exposés
52
+ │ ├── notation.py # pondération → note A–F
53
+ │ ├── i18n/
54
+ │ │ └── fr.yaml # textes vulgarisés par problème
55
+ │ └── rapport/
56
+ │ ├── modele.html # gabarit Jinja2
57
+ │ └── generateur.py # rendu WeasyPrint → PDF
58
+ └── tests/
59
+ ├── test_tls.py
60
+ ├── test_entetes.py
61
+ ├── test_dns_mail.py
62
+ ├── test_notation.py
63
+ └── fixtures/ # réponses enregistrées pour tests hors-ligne
64
+ ```
65
+
66
+ ## Modèle de données (cœur du système)
67
+
68
+ ```python
69
+ # pmescan/modele.py
70
+ from dataclasses import dataclass, field
71
+ from enum import Enum
72
+
73
+
74
+ class Gravite(str, Enum):
75
+ CRITIQUE = "critique"
76
+ ELEVEE = "elevee"
77
+ MOYENNE = "moyenne"
78
+ FAIBLE = "faible"
79
+ INFO = "info"
80
+
81
+
82
+ @dataclass
83
+ class Resultat:
84
+ """Un problème (ou une absence de problème) trouvé par une vérification."""
85
+ identifiant: str # ex. "tls_expire", "dmarc_absent"
86
+ gravite: Gravite
87
+ reussi: bool # True = aucun problème sur ce point
88
+ preuve: str = "" # donnée technique brute (ex. date d'expiration)
89
+ details: dict = field(default_factory=dict)
90
+
91
+
92
+ @dataclass
93
+ class Cible:
94
+ domaine: str
95
+ ip: str | None = None
96
+ mode: str = "passif" # "passif" | "actif" | "agressif"
97
+ ```
98
+
99
+ ## Contrat d'une vérification
100
+
101
+ Chaque check hérite de `Verification` et implémente `executer()`. Il renvoie une liste
102
+ de `Resultat`. Il ne connaît ni la notation ni le rapport : il fait une seule chose.
103
+
104
+ ```python
105
+ # pmescan/checks/base.py
106
+ from abc import ABC, abstractmethod
107
+ from pmescan.modele import Cible, Resultat
108
+
109
+
110
+ class Verification(ABC):
111
+ """Classe mère de toutes les vérifications."""
112
+
113
+ nom: str = "verification"
114
+ niveau_minimum: str = "passif" # mode minimal qui active ce check
115
+
116
+ @abstractmethod
117
+ async def executer(self, cible: Cible) -> list[Resultat]:
118
+ """Analyse la cible et renvoie la liste des problèmes trouvés."""
119
+ ...
120
+ ```
121
+
122
+ ## Séparation texte / code (i18n)
123
+
124
+ Le code produit un `identifiant` (`dmarc_absent`). Le fichier YAML donne la version
125
+ humaine. Pour ajouter le wolof, on copie `fr.yaml` en `wo.yaml`.
126
+
127
+ ```yaml
128
+ # pmescan/i18n/fr.yaml
129
+ dmarc_absent:
130
+ titre: "Aucune protection contre l'usurpation d'e-mail"
131
+ risque: >
132
+ N'importe qui peut envoyer des e-mails en se faisant passer pour votre
133
+ entreprise. Vos clients peuvent recevoir de fausses factures à votre nom.
134
+ qui_corrige: "hebergeur"
135
+ effort: "1 h"
136
+ action: "Ajouter un enregistrement DMARC dans votre zone DNS."
137
+ ```
138
+
139
+ ## Notation (note A–F)
140
+
141
+ Chaque `Resultat` non réussi retire des points selon sa gravité. La somme donne un
142
+ score sur 100, converti en lettre.
143
+
144
+ ```python
145
+ # pmescan/notation.py
146
+ PENALITES = {
147
+ "critique": 40,
148
+ "elevee": 20,
149
+ "moyenne": 10,
150
+ "faible": 3,
151
+ "info": 0,
152
+ }
153
+
154
+ def calculer_note(resultats: list[Resultat]) -> tuple[int, str]:
155
+ score = 100
156
+ for r in resultats:
157
+ if not r.reussi:
158
+ score -= PENALITES[r.gravite.value]
159
+ score = max(0, score)
160
+ lettre = (
161
+ "A" if score >= 90 else
162
+ "B" if score >= 75 else
163
+ "C" if score >= 60 else
164
+ "D" if score >= 40 else
165
+ "E" if score >= 20 else "F"
166
+ )
167
+ return score, lettre
168
+ ```
169
+
170
+ ## Sécurité et éthique intégrées dès la conception
171
+
172
+ - Le mode passif est le mode par défaut. Les modes actif et agressif exigent le flag
173
+ `--jai-l-autorisation` : sans lui, la CLI refuse avant toute requête, avec le code 3.
174
+ - Chaque scan intrusif autorisé est noté dans un journal local (`~/.pmescan/consent.log`).
175
+ - Défense en profondeur : `scanner()` n'exécute une vérification intrusive que si
176
+ `Cible.autorisation` vaut True. Les checks intrusifs (`ports`, `exposes`) et les
177
+ sondes de chemins du check `cms` vérifient aussi ce champ eux-mêmes. Même un appel
178
+ Python direct ne lance donc aucune requête intrusive sans autorisation explicite.
179
+ - La charge sur la cible est bornée : 20 connexions simultanées au plus, 2 s par
180
+ tentative, une seule tentative par port.
181
+ - Aucune donnée envoyée à un tiers : tout le scan et le rapport restent locaux. La seule
182
+ exception est la vérification CVE optionnelle via OSV, désactivée par défaut et activable
183
+ avec `--verifier-cve`, qui envoie uniquement le nom et la version du CMS détecté à l'API
184
+ publique osv.dev.
@@ -0,0 +1,75 @@
1
+ # 04 — Étapes à suivre pour créer le projet
2
+
3
+ Plan de construction en 4 semaines pour une version 1 publiable. Chaque étape se
4
+ termine par quelque chose qui marche et qui est testé.
5
+
6
+ ## Étape 0 — Mise en place (jour 1)
7
+
8
+ 1. Créer le dépôt Git et la structure de dossiers (voir `03-CONCEPTION.md`).
9
+ 2. Écrire `pyproject.toml` (dépendances, point d'entrée `pmescan`).
10
+ 3. Mettre en place l'environnement : `python -m venv .venv`, `pip install -e .`.
11
+ 4. Configurer `ruff`, `mypy`, `pytest`.
12
+ 5. Ajouter `LICENSE` (MIT) et un `README.md` minimal.
13
+
14
+ **Fini quand** : `pmescan --version` s'affiche.
15
+
16
+ ## Étape 1 — Noyau + TLS + en-têtes (semaine 1)
17
+
18
+ 1. Écrire `modele.py` (classes `Resultat`, `Gravite`, `Cible`).
19
+ 2. Écrire `checks/base.py` (classe `Verification`).
20
+ 3. Écrire `scanner.py` (orchestre les checks selon le mode).
21
+ 4. Écrire `checks/tls.py` (expiration, TLS 1.0/1.1, chiffrements faibles, redirection).
22
+ 5. Écrire `checks/entetes.py` (HSTS, CSP, X-Frame-Options, cookies, fuite de version).
23
+ 6. Écrire `cli.py` avec sortie JSON (`--json`).
24
+ 7. Écrire les tests `test_tls.py` et `test_entetes.py` avec des fixtures hors-ligne.
25
+
26
+ **Fini quand** : `pmescan scan exemple.com --json` renvoie les résultats TLS et en-têtes.
27
+
28
+ ## Étape 2 — DNS/e-mail + fichiers exposés + notation (semaine 2)
29
+
30
+ 1. Écrire `checks/dns_mail.py` (SPF, DMARC, DKIM, MX, DNSSEC).
31
+ 2. Écrire `checks/exposes.py` (`/.git/`, `/.env`, `backup.zip`, listing de répertoires).
32
+ 3. Écrire `notation.py` (score + note A–F).
33
+ 4. Écrire `i18n/fr.yaml` avec les textes des problèmes déjà détectés.
34
+ 5. Tests : `test_dns_mail.py`, `test_notation.py`.
35
+
36
+ **Fini quand** : `pmescan scan exemple.com --json` renvoie une note globale A–F.
37
+
38
+ ## Étape 3 — Rapport PDF en français (semaine 3)
39
+
40
+ 1. Écrire `rapport/modele.html` (gabarit Jinja2 : page de garde, fiches, annexe).
41
+ 2. Écrire `rapport/generateur.py` (WeasyPrint → PDF).
42
+ 3. Brancher `--pdf` et `--sortie` dans `cli.py`.
43
+ 4. Ajouter l'encadré légal (loi 2008-12, CDP).
44
+ 5. Soigner la mise en page (couleurs par gravité, note en gros sur la page 1).
45
+
46
+ **Fini quand** : `pmescan scan exemple.com --pdf` produit un PDF lisible par un non-technicien.
47
+
48
+ ## Étape 4 — CMS + ports + publication (semaine 4)
49
+
50
+ 1. Écrire `checks/cms.py` (WordPress/Joomla/Drupal/PrestaShop + API OSV pour les CVE).
51
+ 2. Écrire `checks/ports.py` (~30 ports critiques via `asyncio`, mode actif).
52
+ 3. Ajouter la garde `--jai-l-autorisation` (modes actif et agressif) et le journal de
53
+ consentement, puis aligner `README-mode-agressif.md` sur ce comportement.
54
+ 4. Finaliser le `README.md` (exemple de sortie, options, codes de sortie). Un exemple de
55
+ PDF et un GIF de démo restent à ajouter.
56
+ 5. Publier sur **PyPI** (`python -m build`, `twine upload`).
57
+ 6. Écrire `CONTRIBUTING.md`.
58
+
59
+ **Fini quand** : `pip install pmescan` fonctionne pour tout le monde.
60
+
61
+ ## Après la version 1 (idées)
62
+
63
+ - Interface web (FastAPI) pour scanner sans ligne de commande.
64
+ - Scans planifiés avec alerte e-mail si la note baisse.
65
+ - Mode multi-sites pour les agences.
66
+ - Traduction wolof et anglais (`wo.yaml`, `en.yaml`).
67
+ - Rapport en marque blanche (logo de l'agence).
68
+
69
+ ## Règle de qualité à chaque étape
70
+
71
+ Rien n'est « fini » tant que :
72
+ - les tests passent (`pytest`) ;
73
+ - `ruff` et `mypy` ne signalent aucune erreur ;
74
+ - la fonctionnalité est documentée dans le README ;
75
+ - le code est en français et lisible.
@@ -0,0 +1,108 @@
1
+ # Contribuer à pmescan
2
+
3
+ Merci de votre intérêt ! Toutes les contributions comptent, même sans écrire de code :
4
+ - une explication plus claire dans `fr.yaml` ;
5
+ - une traduction ;
6
+ - un faux positif signalé ;
7
+ - une version de CMS à mettre à jour.
8
+
9
+ ## Installer l'environnement de développement
10
+
11
+ ```bash
12
+ git clone <url-du-depot> pmescan
13
+ cd pmescan
14
+ python -m venv .venv
15
+ .venv/bin/pip install -e ".[dev]" # Windows : .venv\Scripts\pip install -e ".[dev]"
16
+ ```
17
+
18
+ ## Avant chaque proposition (pull request)
19
+
20
+ Les trois commandes suivantes doivent passer sans erreur :
21
+
22
+ ```bash
23
+ python -m pytest -q
24
+ python -m ruff check pmescan tests
25
+ python -m mypy pmescan
26
+ ```
27
+
28
+ Sous Windows, remplacez `python` par `.venv\Scripts\python.exe`.
29
+
30
+ Un test est ignoré si WeasyPrint ou ses bibliothèques système (Pango, GTK) sont absents.
31
+ C'est normal.
32
+
33
+ ## Règles du projet
34
+
35
+ 1. **Tout en français.**
36
+ - Les noms de variables, de fonctions et de classes, les commentaires et les messages
37
+ de commit sont en français.
38
+ - Seuls les noms imposés par une bibliothèque restent en anglais (`status_code`,
39
+ `wait_closed`, …).
40
+ 2. **Aucun texte destiné à l'utilisateur dans le code.**
41
+ - Un check produit un `Resultat` qui porte un `identifiant` stable, par exemple
42
+ `dmarc_absent`.
43
+ - L'explication en français se trouve dans `pmescan/i18n/fr.yaml`. Chaque entrée a
44
+ cinq clés : `titre`, `risque`, `qui_corrige` (`hebergeur`, `developpeur` ou
45
+ `gerant`), `effort` et `action`.
46
+ 3. **Écrire pour un gérant, pas pour un expert.**
47
+ - Le champ `risque` explique la conséquence concrète, sans jargon : par exemple
48
+ « essais de mots de passe en masse » plutôt que « force brute ».
49
+ - Le texte n'exagère pas : on écrit « peut permettre » plutôt que « permet ».
50
+ 4. **Tests 100 % hors ligne.** Aucun test ne doit toucher le réseau :
51
+ - les appels HTTP passent par `respx` ;
52
+ - le DNS est simulé (`dns.asyncresolver.resolve`, `VerificationPorts._resoudre`) ;
53
+ - sslyze est remplacé par les faux objets de `tests/conftest.py` ;
54
+ - les connexions TCP passent par `faux_open_connection`.
55
+ 5. **Aucune exception ne doit faire planter le scan.**
56
+ - Un check gère lui-même ses erreurs réseau.
57
+ - L'orchestrateur (`scanner.py`) sert de filet de sécurité : il transforme une
58
+ exception imprévue en `<check>_erreur_interne`.
59
+ 6. **Respecter les modes.**
60
+ - Toute requête qui va au-delà de la simple lecture de ce que le site publie est
61
+ réservée au mode `actif` : chemins sensibles, fichiers de version, connexions TCP.
62
+ - Le mode `passif` ne doit jamais faire ce type de requête.
63
+ - Une requête intrusive exige **aussi** `cible.autorisation`. `scanner()` ignore les
64
+ vérifications de niveau actif quand `Cible.autorisation` vaut False. C'est la
65
+ valeur par défaut, y compris lorsqu'on appelle pmescan depuis Python.
66
+ - Une nouvelle sonde intrusive placée dans un check passif doit tester
67
+ `cible.autorisation` elle-même, comme le fait `cms.py`.
68
+ 7. **Pas de faux positif.**
69
+ - Dans le doute, un check ne signale rien, ou signale en `INFO`, ce qui ne retire
70
+ aucun point.
71
+ - Un problème signalé à tort coûte la confiance du gérant.
72
+
73
+ ## Ajouter une vérification
74
+
75
+ 1. Créez `pmescan/checks/<nom>.py`, avec une classe qui hérite de `Verification` et
76
+ déclare `nom`, `niveau_minimum` (`"passif"` ou `"actif"`) et `async def executer(self, cible)`.
77
+ 2. Ajoutez-la à `VERIFICATIONS` dans `pmescan/scanner.py`.
78
+ 3. Ajoutez une entrée dans `fr.yaml` pour **chaque** identifiant non réussi.
79
+ 4. Écrivez `tests/test_<nom>.py`, qui couvre le cas « problème », le cas « tout va
80
+ bien » et les erreurs réseau.
81
+ 5. Ajoutez un scénario « problème » dans `_SCENARIOS_PAR_NOM` de `tests/test_i18n.py`.
82
+ C'est obligatoire : sans ce scénario, le test échoue. Ce garde-fou assure que tout
83
+ identifiant émis a bien son texte en français.
84
+
85
+ ## Ajouter une langue
86
+
87
+ Copiez `pmescan/i18n/fr.yaml` en `<code>.yaml` (par exemple `wo.yaml` pour le wolof) et
88
+ traduisez les valeurs. Les **clés** ne changent pas. Une relecture par une personne de
89
+ langue maternelle est très appréciée.
90
+
91
+ ## Mettre à jour les versions de CMS
92
+
93
+ La table `BRANCHES_MAINTENUES` de `pmescan/checks/cms.py` est tenue à la main. Pour la
94
+ corriger :
95
+ - indiquez dans la pull request la source officielle (calendrier de support du CMS) ;
96
+ - mettez à jour la date du commentaire.
97
+
98
+ ## Signaler une faille de sécurité dans pmescan
99
+
100
+ Ne publiez pas les détails dans une issue publique. Utilisez le signalement privé de
101
+ vulnérabilité de la plateforme qui héberge le dépôt, ou ouvrez une issue qui demande
102
+ seulement un canal de contact privé.
103
+
104
+ ## Éthique
105
+
106
+ pmescan est un outil défensif. Une contribution qui ajoute une capacité offensive
107
+ (exploitation de faille, essais de mots de passe, contournement de protections) ou qui
108
+ affaiblit la garde d'autorisation des modes intrusifs sera refusée.
pmescan-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 pmescan et ses contributeurs
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.