mjolnir-qa 1.0.9 → 2.0.0
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.
- package/CHANGELOG.md +194 -0
- package/README.ar.md +434 -478
- package/README.bn.md +434 -491
- package/README.br.md +434 -520
- package/README.bs.md +431 -500
- package/README.da.md +433 -509
- package/README.de.md +432 -522
- package/README.es.md +428 -517
- package/README.fr.md +426 -520
- package/README.gr.md +433 -517
- package/README.he.md +433 -475
- package/README.it.md +436 -525
- package/README.ja.md +436 -506
- package/README.ko.md +434 -494
- package/README.md +416 -426
- package/README.no.md +435 -509
- package/README.pl.md +433 -511
- package/README.ru.md +434 -515
- package/README.th.md +434 -484
- package/README.tr.md +427 -504
- package/README.uk.md +433 -505
- package/README.vi.md +436 -494
- package/README.zh.md +433 -462
- package/README.zht.md +433 -462
- package/dist/cli.d.mts +590 -111
- package/dist/cli.mjs +9937 -8951
- package/dist/mcp/stdio.mjs +1904 -816
- package/dist/rolldown-runtime-8H4AJuhK.mjs +14 -0
- package/package.json +6 -4
package/README.fr.md
CHANGED
|
@@ -1,404 +1,431 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
|
|
3
|
-
<img src="assets/readme/
|
|
3
|
+
<img src="assets/readme/hero.svg" alt="Mjölnir. Les tests vous disent ce qui a réussi. Mjölnir vous dit à quoi vous pouvez vous fier." width="100%" />
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
<br />
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
exactement où la confiance se brise.
|
|
7
|
+
Mjölnir trouve les tests qui ne peuvent pas échouer et les pipelines qui ne peuvent pas passer au rouge,<br />
|
|
8
|
+
puis évalue jusqu'où le résultat mérite confiance, avec la preuve de chaque point.
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
[](https://github.com/Sergey-Bar/Mjolnir/actions/workflows/ci.yml)
|
|
13
|
-
[](LICENSE)
|
|
14
|
-
[](https://nodejs.org)
|
|
15
|
-
|
|
16
|
-
[English](README.md) | [简体中文](README.zh.md) | [繁體中文](README.zht.md) | [한국어](README.ko.md) | [Deutsch](README.de.md) | [Español](README.es.md) | Français | [Italiano](README.it.md) | [Dansk](README.da.md) | [日本語](README.ja.md) | [Polski](README.pl.md) | [Русский](README.ru.md) | [Norsk](README.no.md) | [Português (Brasil)](README.br.md) | [ไทย](README.th.md) | [Türkçe](README.tr.md) | [Українська](README.uk.md) | [বাংলা](README.bn.md) | [Ελληνικά](README.gr.md) | [Tiếng Việt](README.vi.md) | [עברית](README.he.md) | [العربية](README.ar.md) | [Bosanski](README.bs.md)
|
|
10
|
+
<br />
|
|
17
11
|
|
|
18
|
-
|
|
12
|
+
[](https://www.npmjs.com/package/mjolnir-qa)
|
|
13
|
+
[](https://www.npmjs.com/package/mjolnir-qa)
|
|
14
|
+
[](https://github.com/Sergey-Bar/Mjolnir/actions/workflows/ci.yml)
|
|
15
|
+
[](https://codecov.io/gh/Sergey-Bar/Mjolnir)
|
|
16
|
+
[](https://scorecard.dev/viewer/?uri=github.com/Sergey-Bar/Mjolnir)
|
|
17
|
+
[](LICENSE)
|
|
18
|
+
[](https://nodejs.org)
|
|
19
19
|
|
|
20
20
|
```bash
|
|
21
21
|
npx mjolnir-qa@latest
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
[Le voir à l'œuvre](#le-voir-à-lœuvre) · [Démarrage rapide](#démarrage-rapide) · [Ce qu'il trouve](#ce-que-mjölnir-trouve) · [Score](#le-score-de-fiabilité) · [Preuves](#le-modèle-de-preuves) · [Forensique](#forensique-dexécution) · [CI](#intégrité-de-la-ci) · [Agents](#agents-ia) · [Sécurité](#confiance-et-sécurité) · [Limites](#ce-que-mjölnir-ne-peut-pas-vous-dire) · [Docs](#documentation)
|
|
25
|
+
|
|
26
|
+
<details>
|
|
27
|
+
<summary>Lire dans une autre langue — 22 traductions</summary>
|
|
28
|
+
|
|
29
|
+
[English](README.md) | [简体中文](README.zh.md) | [繁體中文](README.zht.md) | [한국어](README.ko.md) | [Deutsch](README.de.md) | [Español](README.es.md) | Français | [Italiano](README.it.md) | [Dansk](README.da.md) | [日本語](README.ja.md) | [Polski](README.pl.md) | [Русский](README.ru.md) | [Norsk](README.no.md) | [Português (Brasil)](README.br.md) | [ไทย](README.th.md) | [Türkçe](README.tr.md) | [Українська](README.uk.md) | [বাংলা](README.bn.md) | [Ελληνικά](README.gr.md) | [Tiếng Việt](README.vi.md) | [עברית](README.he.md) | [العربية](README.ar.md) | [Bosanski](README.bs.md)
|
|
30
|
+
|
|
31
|
+
> 🤖 Machine-assisted translation. The [English README](README.md) is canonical. Last synced: 2026-09-15.
|
|
32
|
+
|
|
33
|
+
<!-- Source hash: 3541b09e8d04 -->
|
|
25
34
|
|
|
26
|
-
|
|
27
|
-
[Démarrage rapide](#-démarrage-rapide) ·
|
|
28
|
-
[Ce qu'il vérifie](#-ce-que-mjölnir-vérifie) ·
|
|
29
|
-
[Scoring](#comment-le-score-fonctionne) ·
|
|
30
|
-
[CI](#-intégration-ci) · [Configuration](#configuration) ·
|
|
31
|
-
[Documentation](#-documentation)
|
|
35
|
+
</details>
|
|
32
36
|
|
|
33
37
|
</div>
|
|
34
38
|
|
|
35
|
-
|
|
39
|
+
<br />
|
|
40
|
+
|
|
41
|
+
## Une coche verte est une affirmation, pas une preuve
|
|
42
|
+
|
|
43
|
+
Une coche verte signifie que le pipeline n'a pas échoué. Elle ne signifie pas que les tests ont tourné, ni qu'ils auraient pu échouer. Chacun de ces cas passe au vert :
|
|
44
|
+
|
|
45
|
+
- un `.only` commité qui a exécuté 3 tests au lieu de 900
|
|
46
|
+
- `continue-on-error: true` sur le job censé servir de barrière
|
|
47
|
+
- `|| true` après la commande de test
|
|
48
|
+
- un test qui n'affirme rien, ou dont le corps est vide
|
|
49
|
+
- un wrapper de relance qui transforme un vrai échec en réussite chanceuse
|
|
50
|
+
- un rapport que le workflow téléverse mais n'a jamais généré
|
|
51
|
+
- un sleep fixe qui maintient une condition de concurrence
|
|
52
|
+
|
|
53
|
+
Aucun ne fait passer le pipeline au rouge, et chacun semble délibéré en revue. C'est pour cela qu'ils survivent. Voici Mjölnir lisant un cas réel :
|
|
54
|
+
|
|
55
|
+
<p align="center">
|
|
56
|
+
<img src="assets/readme/scan.svg" alt="Le workflow CI du dépôt de démonstration, lu ligne par ligne. Mjölnir signale chaque constat à la ligne rapportée, avec sa règle, ce qui ne va pas, son niveau de preuve et son taux de faux positifs mesuré." width="800" />
|
|
57
|
+
</p>
|
|
58
|
+
|
|
59
|
+
<sub>Chaque constat que le scan de démonstration a rapporté pour ce workflow, à la ligne rapportée. Généré par `npm run docs:readme-brand` à partir de [`demo-report.json`](assets/readme/demo-report.json) et verrouillé contre toute dérive en CI.</sub>
|
|
60
|
+
|
|
61
|
+
**Mode strict.** Les détections les plus agressives — `.only`, `continue-on-error`, tests vides, abus de retry — vivent dans le niveau quarantaine. Elles ne tournent qu'avec `--strict` et sont limitées à la sévérité `info` : elles signalent, ne bloquent jamais. Le scan par défaut (`npx mjolnir-qa@latest` sans `--strict`) ne couvre que les règles core et extended. Ajoutez `--strict` quand vous voulez aussi la couche consultative.
|
|
62
|
+
|
|
63
|
+
Mjölnir lit la suite, les workflows CI et, si vous en avez un, le rapport d'une exécution réelle. Il n'exécute pas vos tests, n'installe pas vos dépendances et n'exécute pas le code qu'il analyse. Et quand il n'a pas de preuve, il le dit au lieu d'inventer de la confiance :
|
|
64
|
+
|
|
65
|
+
| Situation | Ce que Mjölnir rapporte |
|
|
66
|
+
| ------------------------------------------------------ | --------------------------------------------------------------- |
|
|
67
|
+
| Aucune déclaration de test trouvée | Score `null`, affiché comme **UNKNOWN**. Jamais un 100 inventé. |
|
|
68
|
+
| Aucune baseline ni révision comparable | **UNKNOWN**, avec la raison indiquée. Jamais un 0 supposé. |
|
|
69
|
+
| Scan interrompu (budget de temps, fichiers illisibles) | **PARTIAL**, sortie `2`. Jamais présenté comme propre. |
|
|
70
|
+
|
|
71
|
+
<p align="center">
|
|
72
|
+
<img src="assets/readme/how-it-works.svg" alt="Comment fonctionne Mjölnir. Il lit la suite de tests et le pipeline CI de manière statique, ainsi que le rapport d'une exécution réelle quand il y en a un. Il pondère chaque constat par son niveau de preuve et son niveau de confiance, où seule une exécution réelle peut atteindre L3 à L5, et produit des constats, un score de fiabilité et une barrière CI aux codes de sortie figés. Dans la boucle d'agent, l'IA écrit le correctif et Mjölnir relance le scan pour le prouver." width="880" />
|
|
73
|
+
</p>
|
|
74
|
+
|
|
75
|
+
<sub>Composé pour cette page et affiché à 1:1. Généré par `npm run docs:readme-brand` et verrouillé contre toute dérive en CI ; le score, les décomptes et l'ID de règle proviennent de [`script.demo.json`](assets/video/script.demo.json), de [`demo-report.json`](assets/readme/demo-report.json) et du registre des règles, jamais saisis à la main. La même image en affiche : [`architecture.svg`](assets/readme/architecture.svg).</sub>
|
|
76
|
+
|
|
77
|
+
<br />
|
|
78
|
+
|
|
79
|
+
## Le voir à l'œuvre
|
|
80
|
+
|
|
81
|
+
Un vrai scan de [`examples/demo-repo`](examples/demo-repo), une petite suite Playwright avec un workflow CI. Voici où sont partis ses points :
|
|
82
|
+
|
|
83
|
+
<p align="center">
|
|
84
|
+
<img src="assets/readme/terminal-hero.svg" alt="Le détail des déductions de Mjölnir : WORTHINESS 75/100 NEEDS WORK, le score par catégorie, l'encadré des déductions par sévérité et une liste FIX THIS FIRST" width="520" />
|
|
85
|
+
</p>
|
|
86
|
+
|
|
87
|
+
<sub>Généré par `npm run docs:hero` à partir d'un vrai scan et verrouillé contre toute dérive en CI. Le rapport `--verbose` complet du même scan est [`demo.svg`](assets/readme/demo.svg) (`npm run docs:demo`).</sub>
|
|
88
|
+
|
|
89
|
+
<details>
|
|
90
|
+
<summary><strong>Le regarder</strong> — un scan, le correctif qu'il affiche et le nouveau scan qui le prouve</summary>
|
|
36
91
|
|
|
37
|
-
|
|
92
|
+
<br />
|
|
38
93
|
|
|
39
94
|
<p align="center">
|
|
40
|
-
<
|
|
95
|
+
<a href="assets/video/mjolnir-demo.mp4">
|
|
96
|
+
<img src="assets/video/mjolnir-demo-poster.png" alt="Une image de l'enregistrement de démonstration : npx mjolnir-qa@latest analysant le dépôt de démonstration dans une fenêtre de terminal" width="900" />
|
|
97
|
+
</a>
|
|
41
98
|
</p>
|
|
42
99
|
|
|
43
|
-
<sub>
|
|
44
|
-
rendue par le vrai reporter — rien de rogné. Régénérée par
|
|
45
|
-
`npm run docs:demo` ;
|
|
46
|
-
[`tests/demo-asset-reproducibility.spec.ts`](tests/demo-asset-reproducibility.spec.ts)
|
|
47
|
-
fait échouer la CI si elle dérive de ce que l'outil imprime.</sub>
|
|
100
|
+
<sub>Rendu image par image à partir d'un vrai scan par `npm run docs:video` ; jamais enregistré à l'écran. Sélectionnez l'image pour ouvrir [`mjolnir-demo.mp4`](assets/video/mjolnir-demo.mp4).</sub>
|
|
48
101
|
|
|
49
|
-
|
|
102
|
+
</details>
|
|
103
|
+
|
|
104
|
+
### Un constat, de près
|
|
50
105
|
|
|
51
|
-
|
|
52
|
-
workflow CI et un fichier de test Python — quatre langages/formats,
|
|
53
|
-
une seule passe.
|
|
54
|
-
2. Il a trouvé des preuves qui affaiblissent la confiance dans la suite
|
|
55
|
-
— un `continue-on-error` qui masque un job, un `|| true` qui avale un
|
|
56
|
-
code de sortie, des sleeps en dur, un sélecteur fragile, des URLs de
|
|
57
|
-
staging codées en dur, une attente `networkidle`.
|
|
58
|
-
3. Il en a fait un constat concret avec un ID de règle, un emplacement
|
|
59
|
-
et un correctif — et un score unique sur lequel gate une PR.
|
|
106
|
+
Chaque constat répond à quatre questions : où il se trouve, à quel point Mjölnir est sûr, à quelle fréquence la règle se trompe, et comment le corriger.
|
|
60
107
|
|
|
61
|
-
|
|
108
|
+
<p align="center">
|
|
109
|
+
<img src="assets/readme/finding-anatomy.svg" alt="Le premier constat du scan de démonstration, exactement tel que le terminal l'affiche, avec ses quatre parties repérées : où, à quel point c'est sûr, à quelle fréquence la règle se trompe, et le correctif." width="100%" />
|
|
110
|
+
</p>
|
|
62
111
|
|
|
63
|
-
|
|
64
|
-
et vous obtenez :
|
|
112
|
+
`mjolnir explain QA-CI-001` affiche tout le dossier de confiance d'une règle, y compris son taux de faux positifs mesuré et le niveau que ce taux lui a valu :
|
|
65
113
|
|
|
66
114
|
```text
|
|
67
|
-
|
|
115
|
+
▍ QA-CI-001 — continue-on-error masks a failing verification gate
|
|
68
116
|
|
|
69
117
|
Severity: error
|
|
70
118
|
Confidence: high
|
|
119
|
+
Tier: quarantine
|
|
71
120
|
Evidence: E2
|
|
72
|
-
|
|
121
|
+
QA impact: False-green risk (FALSE-GREEN)
|
|
122
|
+
Measured FP: 11% (19 hand-classified corpus verdicts)
|
|
123
|
+
FP risk: low (author estimate)
|
|
124
|
+
Languages: yaml
|
|
125
|
+
Frameworks: github-actions, azure-pipelines
|
|
73
126
|
|
|
74
127
|
WHAT WAS FOUND (real detector output, not a mockup)
|
|
75
128
|
Job `security-scan` runs a verification gate under `continue-on-error: true`.
|
|
76
129
|
|
|
77
130
|
WHY IT MATTERS
|
|
78
|
-
This job can fail every day and CI will still show green. The checkmark
|
|
79
|
-
|
|
131
|
+
This job can fail every day and CI will still show green. The checkmark on
|
|
132
|
+
this workflow cannot be trusted.
|
|
80
133
|
|
|
81
134
|
HOW TO FIX
|
|
82
135
|
Remove continue-on-error, or scope it to individual non-blocking steps only.
|
|
83
|
-
```
|
|
84
136
|
|
|
85
|
-
|
|
86
|
-
où votre CI affiche quelque chose comme réussi alors que ça ne l'est
|
|
87
|
-
pas.
|
|
137
|
+
Example from this rule's own must-fire fixture: QA-CI-001/must-fire/masked.yml
|
|
88
138
|
|
|
89
|
-
|
|
139
|
+
WHAT WOULD CHANGE THE VERDICT
|
|
140
|
+
- a run report next to the scan target (mjolnir.report.json or test-results/)
|
|
141
|
+
corroborating this file lifts its findings to L3–L5
|
|
142
|
+
- a documented suppression (mjolnir.config.json) lowers the finding count
|
|
143
|
+
without claiming correctness
|
|
144
|
+
- quarantine findings run only under --strict and are advisory (E0) — they can
|
|
145
|
+
never gate CI
|
|
90
146
|
|
|
91
|
-
|
|
147
|
+
NEXT ACTION
|
|
148
|
+
Fix the first occurrence, then re-run: `mjolnir --scope changed`. Every
|
|
149
|
+
occurrence of this rule is listed in the scan output.
|
|
92
150
|
|
|
93
|
-
|
|
94
|
-
|
|
151
|
+
HOW TO VERIFY THE FIX
|
|
152
|
+
Re-run `mjolnir` on the changed file(s) — this finding should no longer
|
|
153
|
+
appear. `mjolnir --scope changed` scopes the check to just what you touched.
|
|
95
154
|
|
|
96
|
-
|
|
97
|
-
npx mjolnir-qa@latest
|
|
155
|
+
Docs: mjolnir rules --md (full catalog, this rule included)
|
|
98
156
|
```
|
|
99
157
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
158
|
+
Voilà l'unité de valeur : un endroit où la CI rapporte une réussite qu'elle n'a pas méritée.
|
|
159
|
+
|
|
160
|
+
<br />
|
|
161
|
+
|
|
162
|
+
## Démarrage rapide
|
|
103
163
|
|
|
104
164
|
```bash
|
|
105
|
-
npx mjolnir-qa@latest
|
|
165
|
+
npx mjolnir-qa@latest
|
|
106
166
|
```
|
|
107
167
|
|
|
108
|
-
|
|
109
|
-
et c'est fini. Tout le reste est optionnel.
|
|
168
|
+
Il analyse le répertoire courant et affiche le Trust Report : ce qu'il a trouvé, jusqu'où vous pouvez vous y fier, pourquoi, et quoi faire ensuite. Il sort avec `0` quand rien n'a été trouvé au niveau de la barrière ou au-dessus.
|
|
110
169
|
|
|
111
|
-
|
|
112
|
-
| ----------------------------------- | ---------------------------------------------------------------------- |
|
|
113
|
-
| `mjolnir` | Scan complet du dépôt + score de fiabilité |
|
|
114
|
-
| `mjolnir --scope changed` | Uniquement ce que votre branche a introduit — la forme CI |
|
|
115
|
-
| `mjolnir ci install` | Génère le workflow de PR consultatif |
|
|
116
|
-
| `mjolnir explain QA-CI-001` | Quoi / pourquoi / correctif + taux de FP mesuré d'une règle |
|
|
117
|
-
| `mjolnir rules --unmeasured` | Les règles qui tournent sur hypothèse, pas sur mesure |
|
|
118
|
-
| `mjolnir --json` / `--format sarif` | Lisible par machine / GitHub Code Scanning |
|
|
119
|
-
| `mjolnir --strict` | Exécute aussi les règles du tier quarantaine (risque de FP plus élevé) |
|
|
170
|
+
En CI, n'analysez que ce que la branche a introduit, pour qu'une suite historique ne noie pas votre première pull request :
|
|
120
171
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
| Commande | Ce qu'elle fait |
|
|
125
|
-
| ----------------------------------- | -------------------------------------------------------------- |
|
|
126
|
-
| `mjolnir forensics ./test-results/` | Vraies données d'exécution → verdicts `TRUE-FLAKE`, `FLAKY.md` |
|
|
127
|
-
| `mjolnir triage ./test-results/` | Proposition de quarantaine issue de l'historique d'exécution |
|
|
128
|
-
| `mjolnir pw-report ./test-results/` | Synthèse de run Playwright — retries / flakes / plus lents |
|
|
129
|
-
| `mjolnir doctor:playwright` | Scan profond Playwright uniquement + Selector Health Score |
|
|
172
|
+
```bash
|
|
173
|
+
npx mjolnir-qa@latest --scope changed
|
|
174
|
+
```
|
|
130
175
|
|
|
131
|
-
|
|
176
|
+
`mjolnir ci install` l'écrit sous forme de workflow GitHub Actions, en utilisant l'[action](https://github.com/Sergey-Bar/Mjolnir#readme) épinglée sur le tag majeur `v1` (ou un simple `npx` avec `--no-action`). Il reste consultatif jusqu'à ce que vous décidiez qu'il doit bloquer.
|
|
177
|
+
|
|
178
|
+
| Commande | Ce qu'elle fait |
|
|
179
|
+
| ----------------------------------- | ----------------------------------------------------------------------- |
|
|
180
|
+
| `mjolnir` | Trust Report : verdict, confiance, prochaine action |
|
|
181
|
+
| `mjolnir --scope changed` | Uniquement ce que votre branche a introduit (la forme CI) |
|
|
182
|
+
| `mjolnir ci install` | Génère le workflow de PR consultatif (basé sur l'action) |
|
|
183
|
+
| `mjolnir explain QA-CI-001` | Quoi, pourquoi et correctif, plus le taux de FP mesuré |
|
|
184
|
+
| `mjolnir why src/a.spec.ts:42` | Pourquoi cette ligne précise a été signalée. Ne bloque jamais. |
|
|
185
|
+
| `mjolnir forensics ./test-results/` | Preuves d'exécution tirées d'une exécution réelle |
|
|
186
|
+
| `mjolnir trust-report` | Trust Artifact autonome (md + json) |
|
|
187
|
+
| `mjolnir handoff` | Plan de remédiation pour un agent de code |
|
|
188
|
+
| `mjolnir --json` / `--format sarif` | Sortie lisible par machine, GitHub Code Scanning |
|
|
189
|
+
| `mjolnir --format codequality` | Rapport GitLab Code Quality (artefact du widget de MR) |
|
|
190
|
+
| `mjolnir --strict` | Exécute aussi les règles du niveau quarantine (risque de FP plus élevé) |
|
|
132
191
|
|
|
133
192
|
<details>
|
|
134
|
-
<summary><strong>
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
|
139
|
-
|
|
|
140
|
-
| `mjolnir
|
|
141
|
-
| `mjolnir
|
|
142
|
-
| `mjolnir
|
|
143
|
-
| `mjolnir
|
|
144
|
-
| `mjolnir
|
|
145
|
-
| `mjolnir
|
|
146
|
-
| `mjolnir
|
|
147
|
-
| `mjolnir
|
|
148
|
-
| `mjolnir
|
|
193
|
+
<summary><strong>Toutes les autres commandes</strong> — tri des tests instables, rapports, gouvernance</summary>
|
|
194
|
+
|
|
195
|
+
<br />
|
|
196
|
+
|
|
197
|
+
| Commande | Ce qu'elle fait |
|
|
198
|
+
| ----------------------------------- | -------------------------------------------------------------------------------- |
|
|
199
|
+
| `mjolnir --classic` | La bannière de score d'avant le Trust Report |
|
|
200
|
+
| `mjolnir explain verdict` | Pourquoi le verdict du scan enregistré est ce qu'il est |
|
|
201
|
+
| `mjolnir triage ./test-results/` | Tri guidé. Chaque ligne se termine par une prochaine action. |
|
|
202
|
+
| `mjolnir pw-report ./test-results/` | Résumé d'exécution Playwright : relances, tests instables, les plus lents |
|
|
203
|
+
| `mjolnir doctor:playwright` | Scan approfondi dédié à Playwright plus Selector Health Score |
|
|
204
|
+
| `mjolnir fix --dry-run` / `fix` | Correctifs automatiques sûrs, chacun re-scanné pour prouver qu'il s'est appliqué |
|
|
205
|
+
| `mjolnir baseline` / `diff` | Photographie les constats, puis ne rapporte que les nouveaux ou les aggravés |
|
|
206
|
+
| `mjolnir impact --since <ref>` | Ce qu'un commit a introduit et résolu |
|
|
207
|
+
| `mjolnir summary` | Annotations CI et résumé d'étape à partir d'un rapport |
|
|
208
|
+
| `mjolnir pr-comment` | Un commentaire de PR ciblé, en Markdown |
|
|
209
|
+
| `mjolnir debt` | Registre de la dette de tests avec un modèle de coût |
|
|
210
|
+
| `mjolnir handover` | Carte d'intégration de la suite pour un nouvel ingénieur QA |
|
|
211
|
+
| `mjolnir init` | Détecte les frameworks, affiche une checklist d'installation |
|
|
212
|
+
| `mjolnir suppressions` | Liste les constats supprimés, pour la gouvernance |
|
|
213
|
+
| `mjolnir rules --unmeasured` | Les règles qui reposent sur une hypothèse, pas sur une mesure |
|
|
214
|
+
| `mjolnir rules --md` | Catalogue complet des règles (JSON ou Markdown) |
|
|
215
|
+
| `mjolnir doctor` | Auto-audit de la base de règles de Mjölnir |
|
|
216
|
+
| `mjolnir create-rule <ID>` | Crée le squelette d'une nouvelle règle et de ses fixtures |
|
|
217
|
+
| `mjolnir stats` | Compteurs locaux cumulés des correctifs observés |
|
|
218
|
+
| `mjolnir badge` | JSON d'endpoint shields.io et extrait |
|
|
219
|
+
| `mjolnir --cache` | Re-scans incrémentaux via un cache local des verdicts |
|
|
220
|
+
| `mjolnir --format mermaid` | Diagramme d'architecture de tests pour un commentaire de PR |
|
|
221
|
+
|
|
222
|
+
`mjolnir help <command>` affiche l'usage, des exemples et la prochaine étape pour chacune d'elles.
|
|
149
223
|
|
|
150
224
|
</details>
|
|
151
225
|
|
|
152
|
-
|
|
153
|
-
`npm i -g mjolnir-qa`. Requiert Node.js ≥ 22.18. Fonctionne sous
|
|
154
|
-
Windows, macOS et Linux.
|
|
155
|
-
|
|
156
|
-
---
|
|
157
|
-
|
|
158
|
-
## 👥 À qui ça s'adresse ?
|
|
159
|
-
|
|
160
|
-
- **QA / SDET** propriétaires d'une suite e2e ou d'intégration qui ont
|
|
161
|
-
besoin de la preuve que la suite mérite vraiment la coche verte
|
|
162
|
-
qu'elle produit.
|
|
163
|
-
- **Équipes Plateforme / DevEx** responsables de l'intégrité CI et des
|
|
164
|
-
release gates — celles et ceux pour qui un `continue-on-error` ne
|
|
165
|
-
doit jamais repeindre en vert une pipeline rouge en silence.
|
|
166
|
-
- **Mainteneurs OSS** qui veulent un gate de vérification bon marché,
|
|
167
|
-
toujours actif, qui tourne en local et en CI sans aucun appel réseau.
|
|
226
|
+
Nécessite **Node.js ≥ 22.18** sous Windows, macOS ou Linux. Vous préférez une installation globale ? `npm i -g mjolnir-qa`. Ce minimum vient de la chaîne de build (tsdown le cible et le pipeline de publication fait des tests de fumée dessus) ; les dépendances d'exécution n'en demandent pas davantage.
|
|
168
227
|
|
|
169
|
-
|
|
228
|
+
<br />
|
|
170
229
|
|
|
171
|
-
##
|
|
230
|
+
## Ce que Mjölnir trouve
|
|
172
231
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
| 🎭 | **Selector Health Score** — note vos locators Playwright, pas seulement votre taux de réussite |
|
|
177
|
-
| 🔬 | **Forensique d'exécution** — lit de vraies données de run Playwright/JUnit pour détecter `TRUE-FLAKE`, pas seulement des suppositions statiques |
|
|
178
|
-
| 🚨 | **Règles d'intégrité CI** — attrape `continue-on-error`, `\|\| true` et autres astuces à faux vert |
|
|
179
|
-
| 🐍 | **Les quatre bindings Playwright** — TypeScript, Python, Java, C#/.NET — plus pytest, JUnit/TestNG et workflows CI |
|
|
180
|
-
| 🔒 | **Local-first** — zéro appel réseau pendant le scan, zéro télémétrie, s'exécute en secondes |
|
|
181
|
-
|
|
182
|
-
### Les règles
|
|
183
|
-
|
|
184
|
-
Chaque règle est livrée avec des fixtures must-fire **et** must-not-fire.
|
|
185
|
-
Une règle qui se déclenche sur sa propre fixture négative ne peut pas
|
|
186
|
-
sortir — c'est le pare-feu anti faux positifs.
|
|
187
|
-
|
|
188
|
-
<details>
|
|
189
|
-
<summary><strong>Hygiène des tests</strong></summary>
|
|
190
|
-
|
|
191
|
-
| ID | Règle | Severity |
|
|
192
|
-
| ----------- | ----------------------------------------------------- | -------- |
|
|
193
|
-
| QA-TEST-001 | Test focalisé commité (`.only`, `fit`) | error |
|
|
194
|
-
| QA-TEST-002 | Test sauté sans justification | error |
|
|
195
|
-
| QA-TEST-002 | Test sauté avec justification tracée | warning |
|
|
196
|
-
| QA-TEST-003 | Test sans assertion | error |
|
|
197
|
-
| QA-TEST-004 | Sleep en dur (`waitForTimeout`, `sleep()`, `delay()`) | warning |
|
|
198
|
-
| QA-TEST-006 | Abus de retry masquant l'instabilité | warning |
|
|
199
|
-
| QA-TEST-010 | Corps de test vide | error |
|
|
200
|
-
|
|
201
|
-
</details>
|
|
232
|
+
<p align="center">
|
|
233
|
+
<img src="assets/readme/stack.svg" alt="Fonctionne avec votre stack : les langages, frameworks de test et systèmes CI couverts par ses règles, d'après le registre des règles." width="100%" />
|
|
234
|
+
</p>
|
|
202
235
|
|
|
203
|
-
|
|
204
|
-
<summary><strong>Qualité des tests</strong></summary>
|
|
236
|
+
**79 règles** en quatre familles — hygiène des tests, qualité des tests, Playwright et intégrité de la CI — pour TypeScript et JavaScript, Python, Java, C# et le YAML de GitHub Actions. Elles couvrent Playwright dans ses quatre bindings, ainsi que pytest, JUnit, TestNG, NUnit, xUnit, MSTest, Jest, Vitest et Mocha, avec une couverture de départ pour Cypress et Selenium. Neuf d'entre elles, pour donner une idée :
|
|
205
237
|
|
|
206
|
-
| ID | Règle
|
|
207
|
-
| ------------ |
|
|
208
|
-
| QA-
|
|
209
|
-
| QA-
|
|
210
|
-
| QA-
|
|
238
|
+
| ID | Règle | Sévérité | Niveau |
|
|
239
|
+
| ------------ | ---------------------------------------------------------------------- | -------- | ---------- |
|
|
240
|
+
| QA-CI-001 | `continue-on-error` masque une barrière de vérification en échec | error | quarantine |
|
|
241
|
+
| QA-CI-009 | Code de sortie des tests non propagé (`\|` sans pipefail, chaînes `;`) | error | extended |
|
|
242
|
+
| QA-TEST-001 | Test ciblé commité (`.only`, `fit`) | error | quarantine |
|
|
243
|
+
| QA-TEST-003 | Test sans assertion | error | quarantine |
|
|
244
|
+
| QA-TQUAL-009 | Assertion de promesse sans await | error | quarantine |
|
|
245
|
+
| QA-PW-002 | Assertion de locator sans await | error | core |
|
|
246
|
+
| QA-PW-004 | Sélecteurs CSS/XPath fragiles | warning | quarantine |
|
|
247
|
+
| QA-PY-002 | Test ignoré (`skip`, `xfail` non strict) | warning | core |
|
|
248
|
+
| QA-CS-103 | Méthode de test sans assertion | error | core |
|
|
211
249
|
|
|
212
|
-
|
|
250
|
+
Le catalogue complet est généré depuis le registre, jamais maintenu à la main : `mjolnir rules --md`, [`docs/rules/`](docs/rules/), ou le [guide de ce qu'il vérifie](https://sergey-bar.github.io/Mjolnir/guide/what-it-checks).
|
|
213
251
|
|
|
214
252
|
<details>
|
|
215
|
-
<summary><strong>
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
|
222
|
-
|
|
|
253
|
+
<summary><strong>Toutes les règles citées dans ce README</strong>, dans un seul tableau</summary>
|
|
254
|
+
|
|
255
|
+
<br />
|
|
256
|
+
|
|
257
|
+
> Les règles `quarantine` ne tournent que sous `--strict` et ne bloquent jamais (elles sont plafonnées à info). La sévérité indiquée est celle définie par l'auteur.
|
|
258
|
+
|
|
259
|
+
| ID | Famille | Règle | Sévérité | Niveau |
|
|
260
|
+
| ------------ | ---------- | ------------------------------------------------------------ | -------- | ---------- |
|
|
261
|
+
| QA-TEST-001 | Hygiène | Test ciblé commité (`.only`, `fit`) | error | quarantine |
|
|
262
|
+
| QA-TEST-002 | Hygiène | Test ignoré. Passe à `error` sans raison suivie. | warning | quarantine |
|
|
263
|
+
| QA-TEST-003 | Hygiène | Test sans assertion | error | quarantine |
|
|
264
|
+
| QA-TEST-004 | Hygiène | Sleep fixe (`waitForTimeout`, `sleep()`, `delay()`) | warning | extended |
|
|
265
|
+
| QA-TEST-006 | Hygiène | Abus de relances masquant l'instabilité | warning | quarantine |
|
|
266
|
+
| QA-TEST-010 | Hygiène | Corps de test vide | error | quarantine |
|
|
267
|
+
| QA-TQUAL-002 | Qualité | Assertion tautologique | error | quarantine |
|
|
268
|
+
| QA-TQUAL-009 | Qualité | Assertion de promesse sans await | error | quarantine |
|
|
269
|
+
| QA-TQUAL-011 | Qualité | Tests commentés | warning | extended |
|
|
270
|
+
| QA-PW-002 | Playwright | Assertion de locator sans await | error | core |
|
|
271
|
+
| QA-PW-003 | Playwright | `page.pause()` / `test.only()` commité | error | core |
|
|
272
|
+
| QA-PW-004 | Playwright | Sélecteurs CSS/XPath fragiles | warning | quarantine |
|
|
273
|
+
| QA-PW-123 | Playwright | URL d'environnement codées en dur | warning | quarantine |
|
|
274
|
+
| QA-PW-140 | Playwright | Capture d'écran sans `maxDiffPixelRatio` | warning | core |
|
|
275
|
+
| QA-CI-001 | CI | `continue-on-error` masque une barrière en échec | error | quarantine |
|
|
276
|
+
| QA-CI-002 | CI | `\|\| true` avale les codes de sortie | error | extended |
|
|
277
|
+
| QA-CI-005 | CI | Rapport consommé mais jamais généré | error | quarantine |
|
|
278
|
+
| QA-CI-007 | CI | Wrappers de relance autour des tests | warning | extended |
|
|
279
|
+
| QA-CI-008 | CI | Étape toujours réussie qui masque les échecs | error | quarantine |
|
|
280
|
+
| QA-CI-009 | CI | Code de sortie non propagé (`\|` sans pipefail, chaînes `;`) | error | extended |
|
|
281
|
+
| QA-CI-010 | CI | Tests ignorés là où ils doivent bloquer | error | quarantine |
|
|
282
|
+
| QA-PY-002 | Python | Test ignoré (`skip`, `xfail` non strict) | warning | core |
|
|
283
|
+
| QA-PY-003 | Python | Fonction de test sans assertion | error | quarantine |
|
|
284
|
+
| QA-PY-005 | Python | `time.sleep()` dans les tests | warning | extended |
|
|
285
|
+
| QA-PY-012 | Python | Assertion tautologique | error | quarantine |
|
|
286
|
+
| QA-JV-101 | Java | Test désactivé (`@Disabled`) | warning | core |
|
|
287
|
+
| QA-JV-102 | Java | Sleep fixe (`Thread.sleep()`) | warning | extended |
|
|
288
|
+
| QA-JV-103 | Java | Méthode de test sans assertion | error | extended |
|
|
289
|
+
| QA-JV-105 | Java | Sleep fixe via `waitForTimeout()` de Playwright | warning | core |
|
|
290
|
+
| QA-JV-106 | Java | Sélecteur fragile au lieu d'un locator par rôle | warning | quarantine |
|
|
291
|
+
| QA-CS-101 | C# | Test ignoré (`[Ignore]`, `[Fact(Skip=)]`) | warning | core |
|
|
292
|
+
| QA-CS-102 | C# | Sleep fixe (`Thread.Sleep` / `Task.Delay`) | warning | core |
|
|
293
|
+
| QA-CS-103 | C# | Méthode de test sans assertion | error | core |
|
|
294
|
+
| QA-CS-105 | C# | Sleep fixe via `WaitForTimeoutAsync()` | warning | extended |
|
|
295
|
+
| QA-CS-106 | C# | Sélecteur fragile au lieu d'un locator par rôle | warning | quarantine |
|
|
296
|
+
|
|
297
|
+
Python fournit aussi QA-PY-001…012 (hygiène pytest) et QA-PY-101…108 (Playwright pour Python). Cypress et Selenium disposent de jeux de départ de trois règles chacun.
|
|
223
298
|
|
|
224
299
|
</details>
|
|
225
300
|
|
|
226
|
-
|
|
227
|
-
<summary><strong>Intégrité CI</strong></summary>
|
|
228
|
-
|
|
229
|
-
| ID | Règle | Severity |
|
|
230
|
-
| --------- | -------------------------------------------------------------------- | -------- |
|
|
231
|
-
| QA-CI-001 | `continue-on-error` masque les échecs | error |
|
|
232
|
-
| QA-CI-002 | `\|\| true` avale les codes de sortie | error |
|
|
233
|
-
| QA-CI-005 | Rapport consommé mais jamais généré | error |
|
|
234
|
-
| QA-CI-007 | Wrappers de retry autour des tests | warning |
|
|
235
|
-
| QA-CI-008 | Step toujours réussi masquant les échecs | error |
|
|
236
|
-
| QA-CI-009 | Code de sortie du test non propagé (`\|` sans pipefail, chaînes `;`) | error |
|
|
237
|
-
| QA-CI-010 | Tests sautés là où ils doivent bloquer (gardes skip-on-PR) | error |
|
|
301
|
+
Chaque règle est livrée avec une fixture must-fire **et** une fixture must-not-fire, et une règle qui se déclenche sur sa propre fixture négative ne peut pas être livrée. C'est le pare-feu anti-faux-positifs ; `mjolnir doctor` l'applique dans la CI de ce dépôt.
|
|
238
302
|
|
|
239
|
-
|
|
303
|
+
### Selector Health Score
|
|
240
304
|
|
|
241
|
-
|
|
242
|
-
<summary><strong>Python / pytest 🐍</strong></summary>
|
|
305
|
+
`mjolnir doctor:playwright` note chaque locator selon la façon dont il trouve un élément : comme le ferait un utilisateur (rôle, libellé, texte), par un contrat explicite (`data-testid`), ou par un accident structurel (chaînes CSS, XPath). Chaque fichier reçoit un score de 0 à 100 :
|
|
243
306
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
| QA-PY-002 | Test sauté (`skip`, `xfail` non strict) | warning |
|
|
247
|
-
| QA-PY-003 | Fonction de test sans assertion | error |
|
|
248
|
-
| QA-PY-005 | `time.sleep()` dans les tests | warning |
|
|
249
|
-
| QA-PY-012 | Assertion tautologique | error |
|
|
307
|
+
```text
|
|
308
|
+
▍ SELECTOR HEALTH
|
|
250
309
|
|
|
251
|
-
|
|
310
|
+
e2e/login.spec.ts
|
|
311
|
+
[█████████████░░░░░░░] 65 / 100
|
|
312
|
+
role/text: 1 · testid: 0 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
|
|
252
313
|
|
|
253
|
-
|
|
314
|
+
e2e/checkout.spec.ts
|
|
315
|
+
[█████████████████░░░] 86 / 100
|
|
316
|
+
role/text: 3 · testid: 1 · plain-css: 0 · css-chains: 1 ⚠ · xpath: 0
|
|
317
|
+
```
|
|
254
318
|
|
|
255
|
-
|
|
256
|
-
<summary><strong>Java / JUnit · TestNG ☕</strong></summary>
|
|
319
|
+
Cela mesure la **robustesse, pas l'exactitude**. `.btn.btn-primary > div:nth-child(2)` passe aujourd'hui et continue de passer jusqu'à ce que quelqu'un touche au balisage. Un score bas n'affirme jamais que le test est cassé, seulement qu'il dépend d'un balisage que personne n'a promis de conserver.
|
|
257
320
|
|
|
258
|
-
|
|
259
|
-
| --------- | ------------------------------------------- | -------- |
|
|
260
|
-
| QA-JV-101 | Test désactivé (`@Disabled`) | warning |
|
|
261
|
-
| QA-JV-102 | Sleep en dur (`Thread.sleep()`) | warning |
|
|
262
|
-
| QA-JV-103 | Méthode de test sans assertion | error |
|
|
263
|
-
| QA-JV-105 | Sleep en dur Playwright `waitForTimeout()` | warning |
|
|
264
|
-
| QA-JV-106 | Sélecteur fragile au lieu d'un role locator | warning |
|
|
321
|
+
<br />
|
|
265
322
|
|
|
266
|
-
|
|
323
|
+
## Le score de fiabilité
|
|
267
324
|
|
|
268
|
-
<
|
|
269
|
-
<
|
|
325
|
+
<p align="center">
|
|
326
|
+
<img src="assets/readme/score-gauge.svg" alt="L'échelle de fiabilité de 0 à 100, avec un marqueur qui parcourt chaque score : UNWORTHY sous 50, NEEDS WORK de 50 à 79, WORTHY de 80 à 99, FORGED à 100" width="720" />
|
|
327
|
+
</p>
|
|
270
328
|
|
|
271
|
-
|
|
272
|
-
| --------- | -------------------------------------------- | -------- |
|
|
273
|
-
| QA-CS-101 | Test sauté (`[Ignore]`, `[Fact(Skip=)]`) | warning |
|
|
274
|
-
| QA-CS-102 | Sleep en dur (`Thread.Sleep` / `Task.Delay`) | warning |
|
|
275
|
-
| QA-CS-103 | Méthode de test sans assertion | error |
|
|
276
|
-
| QA-CS-105 | Sleep en dur `WaitForTimeoutAsync()` | warning |
|
|
277
|
-
| QA-CS-106 | Sélecteur fragile au lieu d'un role locator | warning |
|
|
329
|
+
<sub>Chaque score de 0 à 100, placé par le vrai `deriveScoreState`. Généré par `npm run docs:gauge` et verrouillé contre toute dérive en CI.</sub>
|
|
278
330
|
|
|
279
|
-
|
|
331
|
+
| Score | Verdict |
|
|
332
|
+
| --------- | ------------------------------------------------ |
|
|
333
|
+
| `0 – 49` | **UNWORTHY** |
|
|
334
|
+
| `50 – 79` | **NEEDS WORK** |
|
|
335
|
+
| `80 – 99` | **WORTHY** |
|
|
336
|
+
| `100` | **FORGED** |
|
|
337
|
+
| `null` | **UNKNOWN** : aucune déclaration de test trouvée |
|
|
280
338
|
|
|
281
|
-
|
|
282
|
-
> confidence, son risque de faux positif et sa disponibilité d'autofix —
|
|
283
|
-
> est généré depuis le registre :
|
|
284
|
-
>
|
|
285
|
-
> ```bash
|
|
286
|
-
> mjolnir rules --md
|
|
287
|
-
> ```
|
|
288
|
-
>
|
|
289
|
-
> Les pages par règle vivent sous [`docs/rules/`](docs/rules/).
|
|
339
|
+
**Comment il est calculé.** La sévérité fixe une déduction de base (`error −8`, `warning −3`, `info −1`) et le niveau de preuve la réduit : E2 compte en entier, E1 à moitié (arrondi à l'inférieur), E0 pas du tout. Le total est normalisé par l'exposition de la suite, c'est-à-dire en déductions par déclaration de test plutôt que par fichier. Le terminal affiche les mêmes nombres réduits que ceux utilisés par le score ; il n'y a pas de second modèle caché. Détails : [docs/SCORING.md](docs/SCORING.md) et le [guide du score](https://sergey-bar.github.io/Mjolnir/guide/scoring).
|
|
290
340
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
**78 des 99 règles portent un taux de faux positifs mesuré sur du vrai
|
|
294
|
-
code OSS** (≥ 10 constats classés à la main chacun ; voir
|
|
295
|
-
[docs/FP-AUDIT.md](docs/FP-AUDIT.md)). Les 21 autres sortent sur
|
|
296
|
-
l'estimation de l'auteur. Chaque pied de scan vous dit combien des
|
|
297
|
-
règles _déclenchées_ sont mesurées ; `mjolnir rules --unmeasured` liste
|
|
298
|
-
celles qui ne le sont pas ; la page `mjolnir explain` de chaque règle
|
|
299
|
-
énonce son statut. Nous publions le taux même quand il est laid —
|
|
300
|
-
grandir ce chiffre est le travail continu du projet.
|
|
341
|
+
**Ce que 100 ne veut pas dire.** Cela ne veut pas dire que le logiciel est correct, que la suite est suffisante ou que le produit est exempt de défauts. Cela veut dire une seule chose : **aucune des règles évaluées par Mjölnir n'a produit de déduction avec ce scan et ce modèle de preuves.**
|
|
301
342
|
|
|
302
|
-
|
|
343
|
+
<br />
|
|
303
344
|
|
|
304
|
-
|
|
305
|
-
son taux de faux positifs **mesuré** :
|
|
345
|
+
## Le modèle de preuves
|
|
306
346
|
|
|
307
|
-
|
|
308
|
-
| ------------ | ------------------------------------------------ | :-------------: | :--------: |
|
|
309
|
-
| `core` | ≤ 10 % de FP mesuré | ✅ | ✅ |
|
|
310
|
-
| `extended` | ≤ 30 % de FP mesuré | ✅ | ✅ |
|
|
311
|
-
| `quarantine` | au-dessus de 30 %, ou pas encore mesuré (n < 10) | ❌ | ✅ |
|
|
347
|
+
Chaque constat porte deux étiquettes : à quel point Mjölnir est sûr, et jusqu'où le constat a été vérifié. C'est la différence entre un outil qui signale des motifs et un outil sur lequel on peut conditionner une release.
|
|
312
348
|
|
|
313
|
-
|
|
314
|
-
| --------------- | --------------- | ---------------------------------------------------------- |
|
|
315
|
-
| TypeScript / JS | AST compilateur | la plus large, la plus mesurée — surtout `core`/`extended` |
|
|
316
|
-
| Python / pytest | Couche regex | large, auditée sur corpus — surtout `core`/`extended` |
|
|
317
|
-
| Java | Couche regex | plus récent — surtout `extended`/`quarantine` |
|
|
318
|
-
| C# / .NET | Couche regex | plus récent — surtout `extended`/`quarantine` |
|
|
349
|
+
**À quel point c'est sûr — le niveau de preuve.**
|
|
319
350
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
351
|
+
| Niveau | Nom | Signifie | Déduction |
|
|
352
|
+
| ------ | ------------------- | -------------------------------------------------------------- | --------- |
|
|
353
|
+
| **E2** | Preuve déterministe | Le défaut est présent dans le code tel qu'il est écrit | Totale |
|
|
354
|
+
| **E1** | Preuve par motif | Un motif fortement lié au défaut a correspondu | Moitié |
|
|
355
|
+
| **E0** | Observation | Bon à savoir. Pas une affirmation que quelque chose ne va pas. | Nulle |
|
|
324
356
|
|
|
325
|
-
|
|
357
|
+
La confiance dans une détection n'est pas la force de la preuve. Une règle peut être certaine d'avoir trouvé ce qu'elle cherchait tout en regardant une heuristique. Les constats E1 sont là pour être lus et jugés, jamais appliqués aveuglément, et cette limite est inscrite sur le constat dans le terminal, le JSON et le passage de relais à l'agent.
|
|
326
358
|
|
|
327
|
-
|
|
359
|
+
**Jusqu'où c'est vérifié — le niveau de confiance.** La plupart des constats viennent de la lecture de votre code. Donnez à Mjölnir le rapport d'une vraie exécution de tests et il pourra confirmer que le code a bien tourné.
|
|
328
360
|
|
|
329
361
|
<p align="center">
|
|
330
|
-
<img src="assets/readme/
|
|
362
|
+
<img src="assets/readme/trust-ladder.svg" alt="L'échelle de confiance de L0 à L5. L0 à L2 viennent de la lecture du code ; L3 à L5 exigent le rapport d'une exécution réelle, marqué par une rupture dans l'échelle." width="100%" />
|
|
331
363
|
</p>
|
|
332
364
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
365
|
+
| Niveau | En clair | Ce qu'il faut |
|
|
366
|
+
| ------ | --------------------- | --------------------------------------------------------------------- |
|
|
367
|
+
| **L0** | Noté | Lire le code |
|
|
368
|
+
| **L1** | Ressemble au problème | Lire le code : un motif a correspondu |
|
|
369
|
+
| **L2** | Prouvé dans le code | Lire le code : le défaut est structurel |
|
|
370
|
+
| **L3** | Le fichier a tourné | Un rapport d'exécution montre que le fichier du constat a été exécuté |
|
|
371
|
+
| **L4** | Le test a tourné | Un rapport d'exécution montre que le test du constat a été exécuté |
|
|
372
|
+
| **L5** | L'exécution concorde | Le résultat même de l'exécution confirme la classe de défaut |
|
|
337
373
|
|
|
338
|
-
|
|
339
|
-
normalisé par l'exposition de la suite (déductions par déclaration de
|
|
340
|
-
test). Les déductions pondérées par la preuve signifient que les
|
|
341
|
-
signaux faibles coûtent moins cher. Le terminal affiche les mêmes
|
|
342
|
-
chiffres actualisés que ceux du score — pas de boîte noire. Méthode
|
|
343
|
-
complète : [docs/SCORING.md](docs/SCORING.md).
|
|
374
|
+
Un scan statique s'arrête à L2. Seul le rapport d'une exécution réelle (Playwright JSON, Jest ou Vitest JSON, JUnit XML) peut élever un constat à L3 ou plus, si bien qu'un constat qu'on n'a jamais vu tourner ne peut jamais prétendre l'avoir fait. Définitions : [docs/TERMINOLOGY.md](docs/TERMINOLOGY.md).
|
|
344
375
|
|
|
345
|
-
|
|
376
|
+
### Quelle part est mesurée
|
|
346
377
|
|
|
347
|
-
|
|
348
|
-
| ------- | ---------------- |
|
|
349
|
-
| ≥ 80 | ✓ **WORTHY** |
|
|
350
|
-
| 50 – 79 | ⚠ **NEEDS WORK** |
|
|
351
|
-
| < 50 | ✖ **UNWORTHY** |
|
|
378
|
+
**74 règles sur 79 ont un taux de faux positifs mesuré sur du vrai code OSS** (au moins 10 constats classés à la main chacune ; voir [docs/FP-AUDIT.md](docs/FP-AUDIT.md)). Les 5 autres reposent sur l'estimation de l'auteur et le disent, règle par règle, dans `mjolnir explain`. `mjolnir rules --unmeasured` les liste, et le pied de chaque scan indique combien des règles qui se sont réellement _déclenchées_ sont mesurées.
|
|
352
379
|
|
|
353
|
-
|
|
354
|
-
du constat dans le score :
|
|
380
|
+
Les taux restent publics quand ils sont mauvais. QA-TEST-001 (un `.only` commité) obtient un mauvais audit sur des dépôts réels et se trouve en quarantine pour cette raison. Le chiffre actuel de chaque règle, QA-PW-141 comprise, figure dans l'audit.
|
|
355
381
|
|
|
356
|
-
|
|
357
|
-
| ------ | ------------------- | --------------------- | --------------------------------------------------------- |
|
|
358
|
-
| E2 | Défaut déterministe | Déduction pleine | `.only` commité — structurellement prouvable |
|
|
359
|
-
| E1 | Motif heuristique | Déduction moitié | `sleep()` détecté par regex — signal fort, pas une preuve |
|
|
360
|
-
| E0 | Observation | Zéro (info seulement) | Rapporté mais ne gate jamais la CI ni ne déduit |
|
|
382
|
+
### Niveaux de confiance des règles
|
|
361
383
|
|
|
362
|
-
|
|
363
|
-
ce système : les constats E2 sont une preuve structurelle ; les
|
|
364
|
-
constats E1 sont des avertissements correctement positionnés, pas des
|
|
365
|
-
preuves formelles.
|
|
384
|
+
Les niveaux suivent le taux de faux positifs mesuré, pas une opinion :
|
|
366
385
|
|
|
367
|
-
|
|
368
|
-
|
|
386
|
+
| Niveau | FP mesuré | Comportement |
|
|
387
|
+
| -------------- | ------------------------------ | -------------------------------------------------------- |
|
|
388
|
+
| **core** | ≤ 10% | Rapport par défaut, bloque |
|
|
389
|
+
| **extended** | ≤ 30% | Rapport par défaut, confiance moindre |
|
|
390
|
+
| **quarantine** | > 30% ou explicitement déclaré | Uniquement `--strict`, plafonné à info, ne bloque jamais |
|
|
391
|
+
| _non mesurée_ | n < 10 | Ne peut être promue en core avant d'être mesurée |
|
|
369
392
|
|
|
370
|
-
|
|
393
|
+
Les bandes de FP ne peuvent que rétrograder un niveau — elles ne promeuvent jamais une règle hors de `quarantine` si elle y a été explicitement déclarée. Une règle explicitement mise en quarantine y reste quelle que soit son taux de FP mesuré.
|
|
371
394
|
|
|
372
|
-
|
|
395
|
+
Promotion, rétrogradation et maturité par langage : [cycle de vie des règles](https://sergey-bar.github.io/Mjolnir/reference/rule-lifecycle).
|
|
373
396
|
|
|
374
|
-
|
|
375
|
-
locators :
|
|
397
|
+
### Pourquoi ce n'est pas un linter
|
|
376
398
|
|
|
377
|
-
|
|
378
|
-
▚ SELECTOR HEALTH — e2e/checkout.spec.ts
|
|
399
|
+
Les linters vous disent si le code suit des règles. Mjölnir vous dit si votre vérification mérite confiance.
|
|
379
400
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
401
|
+
| | Linters (ESLint, SonarQube) | Outils de couverture | Revue de code par IA | **Mjölnir** |
|
|
402
|
+
| ---------------------------------------------------------------- | :-------------------------: | :------------------: | :------------------: | :--------------: |
|
|
403
|
+
| Note le **système de vérification**, pas le code produit | Non | Non | Non | Oui |
|
|
404
|
+
| Intégrité des workflows CI (`continue-on-error`, `\|\| true`) | Non | Non | seulement le diff | Oui |
|
|
405
|
+
| Note la robustesse des locators Playwright (Selector Health) | Non | Non | Non | Oui |
|
|
406
|
+
| Lit de vraies données d'exécution pour les verdicts `TRUE-FLAKE` | Non | Non | Non | Oui |
|
|
407
|
+
| Publie un taux de faux positifs mesuré par règle | Non | Non | Non | Oui |
|
|
408
|
+
| Signale les tests sans assertion | Oui\* | Non | parfois | Oui |
|
|
409
|
+
| Détecte les sleeps fixes (`waitForTimeout`, `time.sleep`) | Oui\* | Non | parfois | Oui |
|
|
410
|
+
| Déterministe (même entrée, même sortie) | Oui | Oui | Non | Oui |
|
|
411
|
+
| Coût par scan | gratuit | gratuit | tokens | **zéro** (local) |
|
|
412
|
+
|
|
413
|
+
<sub>\*Couvert par `eslint-plugin-jest` et `eslint-plugin-playwright` (`expect-expect`, `no-wait-for-timeout`) ainsi que par les propres règles d'assertion de SonarQube. Les colonnes décrivent le comportement par défaut pour la vérification de suites de tests ; les plugins, les offres payantes et les règles personnalisées changent certaines réponses. C'est un résumé de positionnement, pas un benchmark.</sub>
|
|
383
414
|
|
|
384
|
-
|
|
385
|
-
chaînes de classes CSS et le XPath effondrent le score — ils cassent à
|
|
386
|
-
chaque refonte du DOM sans vous dire quel comportement a régressé.
|
|
415
|
+
Utilisez aussi la revue par IA. Elle saisit les nuances, l'intention et les défauts de conception qu'aucun motif ne peut trouver. Mjölnir détecte ce que la revue par IA laisse passer parce que cela semble intentionnel : un `.only` commité, un code de sortie avalé, un `continue-on-error` sur un job de tests. Cela demande un scan, pas un raisonnement.
|
|
387
416
|
|
|
388
|
-
|
|
417
|
+
<br />
|
|
389
418
|
|
|
390
|
-
##
|
|
419
|
+
## Forensique d'exécution
|
|
391
420
|
|
|
392
|
-
|
|
393
|
-
**vraies données d'exécution** — rapports JSON Playwright et XML JUnit
|
|
394
|
-
de n'importe quel runner :
|
|
421
|
+
L'analyse statique raisonne sur du code qui n'a jamais tourné. La forensique lit ce qui s'est réellement passé : Playwright JSON, Jest JSON, Vitest JSON et JUnit XML de n'importe quel runner.
|
|
395
422
|
|
|
396
423
|
```bash
|
|
397
424
|
mjolnir forensics ./test-results/
|
|
398
425
|
```
|
|
399
426
|
|
|
400
427
|
```text
|
|
401
|
-
|
|
428
|
+
▍ FLAKINESS LEADERBOARD
|
|
402
429
|
|
|
403
430
|
3 tests · 1 failed · 1 flaky · 1 retried
|
|
404
431
|
|
|
@@ -408,305 +435,184 @@ FAILING declines an expired card (e2e/checkout.spec.ts)
|
|
|
408
435
|
████░░░░░░░░░░░░░░░░ 1.1s · 1 attempt
|
|
409
436
|
```
|
|
410
437
|
|
|
411
|
-
|
|
412
|
-
qui passe — c'est un test chanceux. Il est marqué `TRUE-FLAKE` quel que
|
|
413
|
-
soit le vert final de la coche.
|
|
438
|
+
`TRUE-FLAKE` ne signifie pas que le test a été relancé. Cela signifie que le test **a échoué au moins une tentative puis a terminé au vert** : une réussite chanceuse, signalée quoi que dise la coche finale. `mjolnir triage` transforme cet historique en proposition de quarantaine, et `mjolnir pw-report` résume une exécution. Ce sont ces mêmes rapports d'exécution qui élèvent les constats aux niveaux de confiance L3 et au-delà.
|
|
414
439
|
|
|
415
|
-
|
|
440
|
+
<br />
|
|
416
441
|
|
|
417
|
-
##
|
|
442
|
+
## Intégrité de la CI
|
|
418
443
|
|
|
419
|
-
|
|
420
|
-
votre vérification peut être crue.
|
|
444
|
+
Un test peut réussir alors que le pipeline qui l'entoure ne peut pas échouer. Mjölnir lit aussi les workflows : `continue-on-error`, `|| true`, les codes de sortie jamais propagés, les étapes toujours réussies, les rapports consommés mais jamais générés, et les barrières ignorées sur les événements qui devraient bloquer. Chaque constat nomme le job, l'étape et la ligne, et porte son propre niveau de preuve.
|
|
421
445
|
|
|
422
|
-
|
|
423
|
-
| ------------------------------------------------------------- | :----------------: | :----------------: | :------------: | :---------: |
|
|
424
|
-
| Intégrité des workflows CI (`continue-on-error`, `\|\| true`) | ❌ | ❌ | rarement | ✅ |
|
|
425
|
-
| Multi-langage (TS, Python, Java, C#) depuis un seul outil | ❌ | ❌ | ❌ | ✅ |
|
|
426
|
-
| Note la résilience des locators Playwright (Selector Health) | ❌ | ❌ | rarement | ✅ |
|
|
427
|
-
| Signale les tests sans vraies assertions | ✅ (plugin)\* | ❌ | parfois | ✅ |
|
|
428
|
-
| Détecte les sleeps en dur (`waitForTimeout`, `time.sleep`) | ✅ (plugin)\* | ❌ | parfois | ✅ |
|
|
429
|
-
| Tourne en secondes, zéro appel réseau pendant le scan | ✅ | ✅ | — | ✅ |
|
|
446
|
+
Générez le workflow de PR, consultatif par défaut :
|
|
430
447
|
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
448
|
+
```bash
|
|
449
|
+
mjolnir ci install
|
|
450
|
+
```
|
|
434
451
|
|
|
435
|
-
|
|
436
|
-
statique :
|
|
452
|
+
Ou ajoutez l'action du Marketplace à un workflow existant :
|
|
437
453
|
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
454
|
+
```yaml
|
|
455
|
+
- uses: Sergey-Bar/Mjolnir@v1
|
|
456
|
+
with:
|
|
457
|
+
scope: changed
|
|
458
|
+
fail-on: error
|
|
459
|
+
```
|
|
443
460
|
|
|
444
|
-
|
|
445
|
-
d'instabilité autonome avec des étiquettes de verdict.
|
|
461
|
+
Épinglez `@v1` pour suivre la ligne majeure, ou un tag exact (`@v0.5.32`) pour une barrière reproductible. [docs/DISTRIBUTION-KIT.md](docs/DISTRIBUTION-KIT.md) couvre le Marketplace, Smithery et les registres MCP.
|
|
446
462
|
|
|
447
|
-
|
|
463
|
+
Pour envoyer les constats dans GitHub Code Scanning, téléversez le SARIF (nécessite `security-events: write` au niveau du workflow ou du job) :
|
|
448
464
|
|
|
449
|
-
|
|
465
|
+
```yaml
|
|
466
|
+
- run: npx mjolnir-qa@latest --format sarif > mjolnir.sarif
|
|
467
|
+
continue-on-error: true
|
|
468
|
+
- uses: github/codeql-action/upload-sarif@v3
|
|
469
|
+
if: ${{ !cancelled() }}
|
|
470
|
+
with:
|
|
471
|
+
sarif_file: mjolnir.sarif
|
|
472
|
+
```
|
|
450
473
|
|
|
451
|
-
|
|
452
|
-
changement de test suspect dans un diff ; elle ne prouve pas que le
|
|
453
|
-
système de vérification dans son ensemble est digne de confiance — et
|
|
454
|
-
elle ne voit que le diff que vous lui montrez.
|
|
474
|
+
Sur GitLab, `--format codequality` écrit le rapport Code Quality que lisent le widget de MR et les annotations du diff ([docs/GITLAB-CI.md](docs/GITLAB-CI.md)). Configuration de l'éditeur et du pipeline : [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md).
|
|
455
475
|
|
|
456
|
-
|
|
457
|
-
| ------------------------------------------- | :------------------------------------: | :---------------------------------: |
|
|
458
|
-
| Coût par scan | Tokens (évolue avec la taille du diff) | **Zéro** (local, installé) |
|
|
459
|
-
| Voit toute la suite + toutes les configs CI | Seulement le diff de PR montré | **Tout, à chaque fois** |
|
|
460
|
-
| Déterministe (même entrée → même sortie) | ❌ (non déterministe) | **✅** |
|
|
461
|
-
| Détecte des motifs dormants depuis des mois | Seulement s'il est dans le contexte | **✅** (scanne tous les fichiers) |
|
|
462
|
-
| Se souvient des constats entre les runs | ❌ (aucune mémoire entre sessions) | **✅** (baseline + diff) |
|
|
463
|
-
| Tourne sans déclencheur humain | Nécessite une PR ou un prompt | **✅** (hook CI, quelques secondes) |
|
|
476
|
+
### Attribution sur le périmètre modifié
|
|
464
477
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
« intentionnels » — un `.only` commité, un code de sortie avalé, un
|
|
469
|
-
`continue-on-error` sur un job de test. Ce ne sont pas des bugs qui
|
|
470
|
-
demandent du raisonnement ; ce sont des faits qui demandent un scan.
|
|
478
|
+
```bash
|
|
479
|
+
npx mjolnir-qa@latest --scope changed
|
|
480
|
+
```
|
|
471
481
|
|
|
472
|
-
|
|
482
|
+
Les constats sont attribués aux lignes ajoutées par votre branche, mesurées par rapport à la **merge-base**. Le périmètre est le même ensemble de fichiers qu'un scan complet découvre (specs TS/JS et configurations d'adaptateurs, `test_*.py`, `*Test.java`, `*Tests.cs`, `.github/workflows/*.yml`), plus les modifications non commitées et non suivies, si bien que cela fonctionne avant le commit. La base est résolue selon `main → master → origin/main → origin/master → origin/HEAD` ; remplacez-la avec `--base <ref>`.
|
|
473
483
|
|
|
474
|
-
|
|
484
|
+
Quand la merge-base ne peut pas être résolue (un clone superficiel, un HEAD détaché, une cible hors de git), les constats se replient sur une attribution au fichier entier **et le rapport le dit.** Un repli silencieux serait exactement le type de défaut que cet outil existe pour détecter.
|
|
475
485
|
|
|
476
|
-
|
|
477
|
-
bloquant :
|
|
486
|
+
<br />
|
|
478
487
|
|
|
479
|
-
|
|
480
|
-
mjolnir ci install
|
|
481
|
-
```
|
|
488
|
+
## Agents IA
|
|
482
489
|
|
|
483
|
-
|
|
490
|
+
Les constats ne valent quelque chose que si quelque chose agit dessus.
|
|
484
491
|
|
|
485
|
-
```
|
|
486
|
-
|
|
487
|
-
- uses: github/codeql-action/upload-sarif@v3
|
|
488
|
-
with:
|
|
489
|
-
sarif_file: mjolnir.sarif
|
|
492
|
+
```text
|
|
493
|
+
SCAN → EVIDENCE → HANDOFF → AGENT → RE-SCAN → PROOF
|
|
490
494
|
```
|
|
491
495
|
|
|
492
|
-
|
|
493
|
-
[docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md).
|
|
496
|
+
**L'IA écrit le correctif. Mjölnir le vérifie.** La preuve vient du nouveau scan, jamais du propre compte rendu de réussite de l'agent.
|
|
494
497
|
|
|
495
|
-
|
|
498
|
+
| Commande | Ce que reçoit l'agent |
|
|
499
|
+
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
500
|
+
| `mjolnir mcp` | Un serveur [MCP](https://modelcontextprotocol.io) sur stdio. `scan`, `explain` et `diff` deviennent des outils appelables. |
|
|
501
|
+
| `mjolnir handoff` | Un rapport `--json` enregistré devient un plan Markdown déterministe : ce qui a été détecté, la limite de preuve de chaque constat, ce qui ne doit **pas** changer, comment vérifier. |
|
|
502
|
+
| `mjolnir install` | Écrit dans les surfaces d'agent que votre dépôt possède déjà (`.claude/`, `.cursor/`, `.kilo/`, `AGENTS.md`) pour que l'agent relance le scan avant d'affirmer qu'il a terminé. |
|
|
496
503
|
|
|
497
|
-
|
|
498
|
-
branche par rapport à la base de fusion avec `main`. Il couvre les
|
|
499
|
-
fichiers de tests (`*.spec.*`, `*.test.*`) plus les fichiers de
|
|
500
|
-
workflow GitHub et les configurations Playwright du diff. Quand la base
|
|
501
|
-
de fusion ne peut pas être résolue — clone superficiel, HEAD détaché,
|
|
502
|
-
cible non-git, branche par défaut différente — il dégrade honnêtement :
|
|
503
|
-
les constats retombent sur une attribution au fichier entier, et le
|
|
504
|
-
rapport le dit. Remplacez la ref de base avec `--base <ref>`.
|
|
504
|
+
Ajoutez-le à un client qui fournit sa propre CLI :
|
|
505
505
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
Mjölnir est zéro-config. Un `mjolnir.config.json` optionnel (ou
|
|
511
|
-
`.mjolnir.json`) à la racine du dépôt ajuste sévérité, gating et
|
|
512
|
-
périmètre — il ne change jamais la sémantique de détection.
|
|
506
|
+
```bash
|
|
507
|
+
claude mcp add mjolnir -- npx -y mjolnir-qa@latest mcp
|
|
508
|
+
```
|
|
513
509
|
|
|
514
|
-
|
|
515
|
-
| ------------------- | ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
516
|
-
| `exclude` | `string[]` | Globs d'ignore supplémentaires (sous-ensemble gitignore), au-dessus des valeurs par défaut intégrées |
|
|
517
|
-
| `gate` | `"advisory" \| "error" \| "warning"` | Quelles sévérités sortent avec un code non nul (défaut `error` ; `advisory` ne bloque jamais) |
|
|
518
|
-
| `severityOverrides` | `{ "<RULE-ID>": severity }` | Re-classe les constats d'une règle pour votre dépôt |
|
|
519
|
-
| `ignore` | `IgnoreEntry[]` | Supprime des constats — **`reason` est obligatoire** ; les entrées expirent après 90 jours (une date `expires` explicite, ou la date de dernière modification du fichier de config pour les entrées sans) |
|
|
520
|
-
| `plugins` | `string[]` | Paquets de règles tiers (voir [Modèle de confiance](#modèle-de-confiance)) |
|
|
510
|
+
Ou à tout client qui accepte un bloc `mcpServers` :
|
|
521
511
|
|
|
522
512
|
```json
|
|
523
513
|
{
|
|
524
|
-
"
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
"ignore": [
|
|
528
|
-
{
|
|
529
|
-
"ruleId": "QA-TEST-004",
|
|
530
|
-
"files": ["e2e/legacy-login.spec.ts"],
|
|
531
|
-
"reason": "Third-party widget needs a settle delay; tracked in JIRA-4821",
|
|
532
|
-
"expires": "2026-12-31"
|
|
533
|
-
}
|
|
534
|
-
]
|
|
514
|
+
"mcpServers": {
|
|
515
|
+
"mjolnir": { "command": "npx", "args": ["-y", "mjolnir-qa@latest", "mcp"] }
|
|
516
|
+
}
|
|
535
517
|
}
|
|
536
518
|
```
|
|
537
519
|
|
|
538
|
-
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
-
|
|
547
|
-
[docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md).
|
|
520
|
+
**Le garde-fou compte plus que la commodité.** Chaque constat d'un passage de relais porte sa limite. **E2** dit _déterministe : vérifiez l'emplacement et appliquez le correctif_. **E1** dit _CONFIRMATION REQUISE : l'observation seule ne prouve pas le défaut_. Un agent qui corrige un E1 aveuglément, supprime une règle ou modifie une règle pour faire monter le score fait exactement ce que cet outil existe pour détecter ; le passage de relais le dit donc dans le prompt, à côté du constat.
|
|
521
|
+
|
|
522
|
+
<br />
|
|
523
|
+
|
|
524
|
+
## Confiance et sécurité
|
|
525
|
+
|
|
526
|
+
**Local d'abord, zéro télémétrie.** Aucune API capable d'accéder au réseau (`fetch`, `http`, `https`, `net`, `dns`, `dgram`, WebSocket) n'existe nulle part dans `src/`, et [`privacy-network-isolation.spec.ts`](tests/contract/privacy-network-isolation.spec.ts) fait échouer le build si l'une d'elles apparaît. Il interdit aussi `eval` et `new Function`. Analyser du code non fiable ne l'exécute jamais : l'analyse statique lit du texte source, et la forensique analyse des fichiers de rapport déjà présents sur le disque.
|
|
527
|
+
|
|
528
|
+
Deux réserves : `npx` lui-même télécharge le paquet avant que quoi que ce soit ne tourne, et la garantie couvre `src/`, pas les plugins tiers.
|
|
548
529
|
|
|
549
|
-
Les
|
|
550
|
-
`mjolnir suppressions`, qui liste ce qui est actuellement supprimé et
|
|
551
|
-
quand chaque entrée expire.
|
|
530
|
+
**Les plugins ne sont pas isolés dans un bac à sable.** Les plugins JS (`mjolnir-rules/*.mjs`, ou les paquets npm listés sous `"plugins"`) tournent avec tous les privilèges de Node, le même modèle de confiance que les plugins ESLint ou Vitest. Les charger est un choix explicite **par scan** : sans `--enable-plugins` (ou `MJOLNIR_ENABLE_PLUGINS=1`), leurs sources ne sont jamais chargées, et un avis sur stderr liste ce qui a été ignoré. Les manifestes de règles JSON n'exécutent aucun code, et les préfixes d'ID des règles core sont réservés pour qu'un plugin ne puisse pas se faire passer pour l'une d'elles. Signalez les vulnérabilités via [SECURITY.md](SECURITY.md).
|
|
552
531
|
|
|
553
|
-
|
|
532
|
+
**Il s'analyse lui-même.** Un moteur de confiance de vérification n'a aucune légitimité s'il n'est pas lui-même vérifiable. Chaque exécution de la CI analyse ce dépôt avec le build produit par cette même exécution. La barrière échoue sur tout constat de sévérité error, ainsi que sur un scan **partiel** ou une **règle qui plante**, parce qu'un auto-scan tronqué qui ne rapporte rien est exactement le faux vert que ce projet existe pour détecter. `mjolnir doctor` ré-audite la base de règles dans la même exécution (pare-feu des fixtures, honnêteté des niveaux, plafond du niveau core), et une vérification INCONCLUSIVE échoue exactement comme une vérification en échec. Les deux rapports sont téléversés comme artefacts de build.
|
|
554
533
|
|
|
555
|
-
|
|
534
|
+
### Codes de sortie et contrat machine
|
|
556
535
|
|
|
557
|
-
Figés
|
|
536
|
+
Figés, pour que vous puissiez bâtir de la logique CI dessus :
|
|
558
537
|
|
|
559
538
|
| Code de sortie | Signification |
|
|
560
539
|
| -------------- | ------------------------------------------------------------------------------ |
|
|
561
|
-
| `0` | Propre
|
|
562
|
-
| `1` | Constats au
|
|
563
|
-
| `2` | Scan partiel (budget de temps atteint, fichiers illisibles)
|
|
564
|
-
| `10` | Erreur d'
|
|
540
|
+
| `0` | Propre : aucun constat au niveau de la barrière ou au-dessus |
|
|
541
|
+
| `1` | Constats au niveau de la barrière ou au-dessus |
|
|
542
|
+
| `2` | Scan partiel (budget de temps atteint, fichiers illisibles). Ne bloque jamais. |
|
|
543
|
+
| `10` | Erreur d'utilisation (option invalide, cible manquante) |
|
|
565
544
|
| `20` | Erreur interne |
|
|
566
545
|
|
|
567
|
-
|
|
568
|
-
(`QA-<FAMILY>-NNN`) sont immuables une fois livrés et jamais
|
|
569
|
-
réutilisés.
|
|
570
|
-
|
|
571
|
-
---
|
|
572
|
-
|
|
573
|
-
## Modèle de confiance
|
|
574
|
-
|
|
575
|
-
- **Local-first** — zéro appel réseau pendant le scan. Jamais. Zéro
|
|
576
|
-
télémétrie.
|
|
577
|
-
- **Pas de fausse preuve** — nous préférons dire « inconnu » que
|
|
578
|
-
« vérifié ». Un dépôt vide obtient `score: null`, jamais un faux 100.
|
|
579
|
-
- **Honnêteté partielle** — si l'analyse a été interrompue, la sortie le
|
|
580
|
-
dit. Jamais « complete » quand ça ne l'est pas.
|
|
581
|
-
- **Pare-feu FP** — la détection tourne sur une vue du code sans
|
|
582
|
-
commentaires ni chaînes (les règles TypeScript utilisent l'AST du
|
|
583
|
-
compilateur) : un motif dans un commentaire de prose ou une chaîne
|
|
584
|
-
d'exemple de doc est de la documentation, pas un constat.
|
|
585
|
-
- **Mesuré, pas affirmé** — seules les règles avec un taux de faux
|
|
586
|
-
positifs issu de vrai code OSS sortent dans les tiers vedettes (voir
|
|
587
|
-
[Quelle part est mesurée](#quelle-part-est-mesurée)) ; le pied de scan
|
|
588
|
-
et `mjolnir rules --unmeasured` vous disent lesquels.
|
|
589
|
-
- **Confiance plugins & porte d'exécution** — les plugins sont des paquets npm déclarés
|
|
590
|
-
sous `"plugins"` ; les modules JS vivent dans `mjolnir-rules/*.mjs`.
|
|
591
|
-
Il n'y a **pas de sandbox** : le code d'un plugin
|
|
592
|
-
tourne avec tous les privilèges Node, le même modèle de confiance que
|
|
593
|
-
les plugins ESLint ou Vitest. Pour cette raison, l'exécution de code est
|
|
594
|
-
**opt-in à chaque scan** : passez `--enable-plugins` (ou définissez
|
|
595
|
-
`MJOLNIR_ENABLE_PLUGINS=1`), sinon les sources ne sont PAS chargées — une
|
|
596
|
-
notification stderr bruyante liste exactement ce qui a été ignoré.
|
|
597
|
-
Scanner du code non fiable ne l'exécute jamais. Les manifestes de règles
|
|
598
|
-
JSON (`mjolnir-rules/*.json`) ne sont pas concernés : ils déclarent des
|
|
599
|
-
motifs regex et n'exécutent aucun code par conception. Les préfixes
|
|
600
|
-
d'ID de règles core sont
|
|
601
|
-
réservés et refusés aux plugins et règles externes pour empêcher
|
|
602
|
-
l'usurpation.
|
|
603
|
-
- **Règles externes locales au workspace** (par dossier, zéro réseau) —
|
|
604
|
-
un répertoire `mjolnir-rules/` à côté de la cible du scan charge des
|
|
605
|
-
règles personnalisées : des fichiers JSON déclarent des motifs regex
|
|
606
|
-
(aucun code exécuté), les modules `.mjs`/`.js` exportent `rules`
|
|
607
|
-
(confiance Node complète, comme les plugins). Les règles externes
|
|
608
|
-
portent les mêmes métadonnées de confiance que core ; elles ne
|
|
609
|
-
peuvent jamais sortir dans le tier core (core exige un taux de FP
|
|
610
|
-
mesuré depuis le sidecar corpus — un `tier: "core"` déclaré est
|
|
611
|
-
borné à `extended`), obéissent aux caps de tier et sont vérifiées
|
|
612
|
-
contre la dérive : `mjolnir rules --md --external` rend le catalogue
|
|
613
|
-
depuis les fichiers chargés (provenance `external`), et le générateur
|
|
614
|
-
de matrice accepte `--external <root>`.
|
|
615
|
-
|
|
616
|
-
---
|
|
617
|
-
|
|
618
|
-
## 🏗️ Architecture
|
|
546
|
+
`2` est volontairement distinct de `0` : un scan qui n'a pas terminé n'a pas « rien trouvé ». Il n'a pas fini de chercher.
|
|
619
547
|
|
|
620
|
-
|
|
621
|
-
<summary>Déplier l'arbre</summary>
|
|
548
|
+
Tout ce qu'une machine consomme (résultats des outils MCP, `--json`, SARIF 2.1) provient d'un unique résultat canonique sous un schéma versionné et **uniquement additif** (`schemaVersion: 1`, `contractVersion: 1`), si bien qu'aucun consommateur n'a à reconstruire le sens à partir du texte affiché. Voir [le contrat machine](docs/machine-contract.md). Les ID de règle (`QA-<FAMILY>-NNN`) sont immuables une fois publiés et ne sont jamais réutilisés.
|
|
622
549
|
|
|
623
|
-
|
|
624
|
-
mjolnir/
|
|
625
|
-
├── src/
|
|
626
|
-
│ ├── engine/ # LanguageAdapter interface + rule runner
|
|
627
|
-
│ ├── adapters/ # typescript · python · java · csharp · github-actions
|
|
628
|
-
│ ├── rules/ # rules across 8 families + the measured-FP table
|
|
629
|
-
│ ├── playwright/ # Selector Health Score engine
|
|
630
|
-
│ ├── discovery/ # workspace, frameworks, ignore resolution
|
|
631
|
-
│ ├── scope/ # git merge-base changed-scope engine
|
|
632
|
-
│ ├── scorer/ # transparent deduction table + prioritization
|
|
633
|
-
│ ├── reporter/ # terminal · JSON · SARIF 2.1 · Mermaid
|
|
634
|
-
│ ├── forensics/ # run-data ingestion · flake verdicts · triage
|
|
635
|
-
│ ├── config/ # mjolnir.config.json + suppressions
|
|
636
|
-
│ ├── plugins/ # third-party rule loading (no sandbox)
|
|
637
|
-
│ └── commands/ # every subcommand
|
|
638
|
-
└── tests/
|
|
639
|
-
├── fixtures/ # must-fire / must-not-fire per rule
|
|
640
|
-
└── golden/ # frozen score regression locks
|
|
641
|
-
```
|
|
550
|
+
<br />
|
|
642
551
|
|
|
643
|
-
|
|
552
|
+
## Ce que Mjölnir ne peut pas vous dire
|
|
644
553
|
|
|
645
|
-
- **
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
- **
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
-
|
|
652
|
-
|
|
653
|
-
le pipeline de scan synchrone.
|
|
554
|
+
- **Il n'exécute pas vos tests.** Un scan propre n'est pas une suite qui passe.
|
|
555
|
+
- **Il ne peut pas vous dire qu'une assertion est _fausse_.** `expect(total).toBe(41)` a l'air saine. Mjölnir trouve les tests qui _ne peuvent pas échouer_ et les pipelines qui _ne peuvent pas passer au rouge_, pas les tests qui vérifient la mauvaise chose.
|
|
556
|
+
- **Il ne prouve pas l'exactitude métier.** Rien ici ne dit que votre produit fait ce que l'exigence demandait.
|
|
557
|
+
- **Un 100 n'est pas la preuve d'une bonne suite.** Savoir si votre suite couvre votre risque réel est une autre question, et cet outil n'y répond pas.
|
|
558
|
+
- **5 règles sur 79 reposent sur une estimation**, pas sur un taux mesuré. Chacune le dit sur son propre constat.
|
|
559
|
+
- **E1 n'est pas E2.** Les constats heuristiques méritent d'être lus, pas d'être appliqués aveuglément.
|
|
560
|
+
- **Un dépôt vide obtient `null`, jamais 100.**
|
|
561
|
+
- **Un fichier nommé `*.spec.ts` sans déclaration de test ne compte pas comme couverture.** Un dépôt dont les seuls fichiers spec contiennent des imports ou des types (zéro appel `it`/`test`) obtient `null`, pas 100.
|
|
654
562
|
|
|
655
|
-
|
|
563
|
+
<br />
|
|
656
564
|
|
|
657
|
-
##
|
|
565
|
+
## Documentation
|
|
658
566
|
|
|
659
|
-
|
|
660
|
-
| ------------------------------------------------------ | -------------------------------------------------- |
|
|
661
|
-
| [docs/SCORING.md](docs/SCORING.md) | Normalisation du score + pondération par la preuve |
|
|
662
|
-
| [docs/FP-AUDIT.md](docs/FP-AUDIT.md) | Taux de faux positifs mesurés + méthode |
|
|
663
|
-
| [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md) | États des règles, suppression, dépréciation |
|
|
664
|
-
| [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md) | Sortie SARIF + configuration éditeur/CI |
|
|
665
|
-
| [docs/rules/](docs/rules/) | Catalogue généré par règle |
|
|
666
|
-
| [CONTRIBUTING.md](CONTRIBUTING.md) | Setup dev + workflow de contribution |
|
|
667
|
-
| [CHANGELOG.md](CHANGELOG.md) | Historique des versions |
|
|
668
|
-
| [SECURITY.md](SECURITY.md) | Signalement de vulnérabilités |
|
|
567
|
+
Le site de documentation complet se trouve sur <https://sergey-bar.github.io/Mjolnir/>.
|
|
669
568
|
|
|
670
|
-
|
|
569
|
+
| Document | Contenu |
|
|
570
|
+
| ------------------------------------------------------ | ----------------------------------------------------------- |
|
|
571
|
+
| [docs/SCORING.md](docs/SCORING.md) | Normalisation du score et pondération des preuves |
|
|
572
|
+
| [docs/TERMINOLOGY.md](docs/TERMINOLOGY.md) | Vocabulaire canonique : un mot par concept |
|
|
573
|
+
| [docs/FP-AUDIT.md](docs/FP-AUDIT.md) | Taux de faux positifs mesurés et méthode |
|
|
574
|
+
| [docs/RULE-LIFECYCLE.md](docs/RULE-LIFECYCLE.md) | États des règles, niveaux, suppression, dépréciation |
|
|
575
|
+
| [docs/VERSIONING.md](docs/VERSIONING.md) | Politique semver, surfaces figées, cycle de dépréciation |
|
|
576
|
+
| [docs/machine-contract.md](docs/machine-contract.md) | Le résultat canonique lisible par machine |
|
|
577
|
+
| [docs/SARIF-INTEGRATION.md](docs/SARIF-INTEGRATION.md) | Sortie SARIF et configuration de l'éditeur ou de la CI |
|
|
578
|
+
| [docs/GITLAB-CI.md](docs/GITLAB-CI.md) | GitLab : rapport Code Quality, recette de MR, barrière |
|
|
579
|
+
| [docs/rules/](docs/rules/) | Catalogue généré par règle |
|
|
580
|
+
| [CONTRIBUTING.md](CONTRIBUTING.md) | Environnement de développement et processus de contribution |
|
|
581
|
+
| [SUPPORT.md](SUPPORT.md) | Où poser des questions, signaler et obtenir de l'aide |
|
|
582
|
+
| [SECURITY.md](SECURITY.md) | Signalement des vulnérabilités |
|
|
583
|
+
| [CHANGELOG.md](CHANGELOG.md) | Historique des versions |
|
|
671
584
|
|
|
672
|
-
|
|
585
|
+
### Statut
|
|
673
586
|
|
|
674
|
-
**
|
|
675
|
-
des contrats figés. TypeScript et Python ont la couverture mesurée la
|
|
676
|
-
plus large ; Java et C# sont plus récents — lisez-les via la
|
|
677
|
-
[table des tiers](#tiers-de-règles-et-maturité-par-langage).
|
|
587
|
+
**Version 1.** Le schéma JSON et les codes de sortie sont des contrats figés. TypeScript et Python ont la couverture mesurée la plus large. Java et C# sont plus récents ; lisez-les à travers le [tableau de maturité](https://sergey-bar.github.io/Mjolnir/reference/rule-lifecycle). La suite, sans dates inventées : [la feuille de route publique](https://sergey-bar.github.io/Mjolnir/reference/roadmap).
|
|
678
588
|
|
|
679
|
-
|
|
589
|
+
### Contribuer
|
|
680
590
|
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
Les nouvelles règles sont la première contribution la plus simple —
|
|
684
|
-
une commande scaffolde la règle plus ses fixtures must-fire **et**
|
|
685
|
-
must-not-fire (la règle générée échoue volontairement à ses fixtures
|
|
686
|
-
tant que vous n'implémentez pas une vraie détection — un stub ne peut
|
|
687
|
-
pas sortir) :
|
|
591
|
+
Les nouvelles règles sont la première contribution la plus facile. Une commande crée le squelette de la règle avec ses fixtures must-fire **et** must-not-fire. La règle générée échoue volontairement sur ses propres fixtures tant qu'une vraie détection n'est pas écrite, parce qu'un stub livré est une règle que personne n'a mesurée :
|
|
688
592
|
|
|
689
593
|
```bash
|
|
690
594
|
mjolnir create-rule QA-PW-140 --title "Screenshot without diff bound"
|
|
691
595
|
```
|
|
692
596
|
|
|
693
|
-
|
|
694
|
-
lois anti-dérive / pare-feu à fixtures sont dans
|
|
695
|
-
[CONTRIBUTING.md](CONTRIBUTING.md).
|
|
597
|
+
L'environnement de développement, les commandes des barrières permanentes et les lois anti-creep et du pare-feu des fixtures se trouvent dans [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
696
598
|
|
|
697
|
-
|
|
599
|
+
<br />
|
|
698
600
|
|
|
699
601
|
<div align="center">
|
|
700
602
|
|
|
701
|
-
|
|
702
|
-
confiance.**
|
|
603
|
+
<img src="assets/readme/closing.svg" alt="Lancez-le sur votre dépôt." width="100%" />
|
|
703
604
|
|
|
704
605
|
```bash
|
|
705
606
|
npx mjolnir-qa@latest
|
|
706
607
|
```
|
|
707
608
|
|
|
708
|
-
|
|
609
|
+
[Lire le guide](https://sergey-bar.github.io/Mjolnir/guide/getting-started) · [Site de documentation](https://sergey-bar.github.io/Mjolnir/) · [npm](https://www.npmjs.com/package/mjolnir-qa)
|
|
610
|
+
|
|
611
|
+
<br />
|
|
612
|
+
|
|
613
|
+
Ne demandez pas si les tests ont réussi.<br />
|
|
614
|
+
Demandez si les preuves montrent qu'ils méritent la confiance.
|
|
709
615
|
|
|
710
|
-
|
|
616
|
+
<sub>Créé par [Sergey Bar](https://www.linkedin.com/in/sergeybar/) · Licence MIT</sub>
|
|
711
617
|
|
|
712
618
|
</div>
|