📄 SKILL.md 🔒 c01cf621…8e87bd08 Se connecter pour télécharger ← Retour
---
name: detecteur-panic-points
description: Détecteur de points de panique (.unwrap(), .expect(, panic!(, unreachable!(, todo!(, unimplemented!() en dehors du code de test, dans du code source Rust. Bibliothèque standard uniquement, zéro dépendance, zéro appel réseau.
theme: securite-souverainete
langages_cibles: rust
---

# detecteur-panic-points

## Objectif

Scanner un dossier de code source Rust et détecter les six constructions
qui font paniquer le programme si elles sont atteintes en dehors du code de
test : `.unwrap()`, `.expect(`, `panic!(`, `unreachable!(`, `todo!(`,
`unimplemented!(`. Un panic sur un chemin non testé peut faire tomber un
thread entier — sur un serveur asynchrone, cela peut interrompre toutes les
requêtes en cours sur ce thread, pas seulement celle qui a déclenché le
panic.

## Pourquoi ce skill existe

Cette règle est déjà une règle absolue du projet qui a produit ce skill
(voir `feedback_regles_codage_fondamentales` : "jamais unwrap/expect/panic
en dehors des tests, toujours un match exhaustif avec log + variant
d'erreur nommé"). Ce skill formalise cette règle en un outil réutilisable
et vérifiable, plutôt que de compter uniquement sur la relecture manuelle.

## Pourquoi Rust (et pas un autre langage) ?

Même famille de raisons que les 2 autres skills Rust du projet
(`linter-temps-constant`, `detecteur-async-bloquant`) : c'est le langage du
code analysé, un binaire compilé scanne un gros répertoire `src/` en une
fraction de seconde, et la stdlib suffit entièrement.

**Exclusion du code de test — la partie la plus délicate de ce skill** :
une détection naïve ligne par ligne signalerait massivement du code de
test légitime (`.unwrap()` sur un `Option` de fixture est un idiome Rust
courant et acceptable en test, puisqu'un panic de test = un test qui
échoue, pas un incident de production). `reperer_zones_test()` retrouve le
corps de tout module `#[cfg(test)] mod { ... }` et de toute fonction
`#[test]`/`#[tokio::test]` isolée, via la même technique de suivi de
profondeur d'accolades/parenthèses caractère par caractère que
`detecteur-async-bloquant` — avec la même exclusion des chaînes de
caractères (normales et brutes `r#"..."#`) et des commentaires, condition
nécessaire pour qu'un exemple de code cité dans une chaîne de test ne soit
jamais confondu avec du vrai code.

## Garanties de conception (non négociables)

- **Zéro dépendance tierce**, **zéro appel réseau**.
- **Contenu scanné traité comme donnée inerte**, jamais exécuté ni interprété.
- **Fonctions cœur 100% pures et testées isolément** : `construire_masque_code`,
  `trouver_prochaine_occurrence`, `trouver_fin_bloc`, `reperer_zones_test`,
  `detecter_points_panique` ne font aucune I/O — testables sur de simples
  chaînes de caractères.
- **Exemption ligne par ligne** via le marqueur `panic-ok` en commentaire,
  pour les rares cas où le panic est réellement le comportement voulu et
  justifié (ex. une invariant interne prouvée hors d'atteinte par construction).
- **`eprintln!` au lieu de `tracing`** : même raison que les 2 autres
  skills Rust — outil CLI ponctuel, pas un serveur long-running.

## Conformité aux règles du projet (verify_rules_rust.sh)

```bash
bash ../../outils/verify_rules_rust.sh --src src
```

**Résultat au 2026-07-28 : 17 violations (§2, §14, §18) + 2 avertissements
(§5), tous vérifiés un par un et confirmés faux positifs à 100%** — même
situation, pour la même raison structurelle, que `detecteur-async-bloquant`
avant lui : ce scanner textuel sans AST ne distingue pas une chaîne de
caractères d'un vrai appel de code. Ici concrètement :

- Les 2 premières violations §2 pointent le tableau `MOTIFS_PANIQUE`
  lui-même (`".unwrap()"`, `".expect("`) — une donnée de configuration
  (le catalogue de motifs recherchés), jamais un appel réel.
- Toutes les violations restantes (§2, §14, §18) pointent des lignes à
  l'intérieur du module `#[cfg(test)] mod tests` — soit des chaînes de
  caractères utilisées comme fixtures (extraits de code Rust fictif passés
  en entrée à `detecter_points_panique()` pour vérifier qu'elle les détecte
  correctement), soit des `assert_eq!`/`assert!` comparant à ces mêmes
  chaînes littérales. Zéro occurrence réelle de `.unwrap()`/`.expect()`/
  `panic!()`/`unreachable!()`/`todo!()`/`unimplemented!()`/`.await` sans
  match en dehors de ces chaînes — vérifié explicitement par grep restreint
  à la portion du fichier précédant `#[cfg(test)]`.
- Les 2 avertissements §5 (`None => false` dans `est_rs`) sont identiques,
  ligne pour ligne, au cas déjà documenté deux fois dans les 2 autres
  skills Rust du projet (fonction `iter_fichiers_rust` reprise à l'identique).

## Mode d'emploi

**Compiler :**

```bash
cargo build --release
```

**Lancer :**

```bash
./target/release/detecteur-panic-points <dossier_cible>
```

**Tests unitaires** (13 tests, aucun réseau, aucune I/O disque réelle) :

```bash
cargo test
```

**Résultat réel obtenu lors de la validation de ce skill** (dossier `src/`
d'un projet Rust d'environ 657 fichiers, ~1 seconde) : le détail exact
n'est pas reproduit ici (code source d'un tiers), mais l'exécution confirme
que le mécanisme d'exclusion du code de test fonctionne comme prévu — la
quasi-totalité des occurrences des 6 motifs surveillés sur ce dépôt se
trouvent dans des modules `#[cfg(test)]`/fonctions `#[test]`, cohérent avec
un projet qui applique déjà strictement sa propre règle "jamais unwrap en
production" (voir `feedback_regles_codage_fondamentales`) — le nombre de
signalements réels en dehors du code de test est resté marginal.

**Prérequis :** Rust stable (testé avec rustc 1.93, édition 2024). Aucune
dépendance à installer.

## Limites connues (honnêteté de l'outil, pas de sur-promesse)

- **Pas un AST complet** : comme démontré par les faux positifs de
  `verify_rules_rust.sh` documentés ci-dessus sur ce skill lui-même, un
  texte qui *ressemble* à un point de panique (dans une chaîne de
  caractères, un commentaire non préfixé par `//` en début de ligne
  visible) peut en théorie produire un faux positif symétrique dans ce
  skill — aucun cas de ce type observé lors de la validation sur un dépôt
  réel.
- **Fonctions `#[test]` imbriquées dans un autre bloc que `#[cfg(test)] mod`**
  (rare, ex. un `#[test]` au niveau module racine sans wrapper) sont bien
  couvertes par la recherche `#[test]`/`#[tokio::test]` isolée — mais un
  autre framework de test avec un attribut différent (`#[rstest]`,
  `#[proptest]`...) ne serait pas reconnu comme zone de test.
- Ne détecte pas l'indexation de tableau/slice qui panique hors limites
  (`arr[i]`) — trop ambigu à distinguer d'un accès légitime sans analyse de
  type réelle, volontairement hors périmètre de cette version.
- Ne remplace pas une revue de sécurité humaine ni `cargo clippy` (qui a
  ses propres lints `unwrap_used`/`expect_used`, désactivés dans ce projet
  — voir `feedback_clippy_inadaptation`) — outil de dégrossissage rapide et
  reproductible, pas une preuve d'absence de panic.
7.0 Ko BLAKE3 : c01cf621…8e87bd08