Outils d'analyse statique de code pour développeurs Rust

La boĂ®te Ă  outils du dĂ©veloppeur Rust : les meilleurs outils d'analyse de code statique

Le compilateur de Rust est le relecteur de code le plus dogmatique que la plupart des développeurs auront jamais à utiliser. Son système de propriété, son vérificateur d'emprunts et son application stricte de la durée de vie des ressources éliminent des catégories entières de bogues qui affectent les bases de code C et C++. Cependant, un compilateur qui prévient les erreurs de mémoire ne constitue pas un système de qualité complet. Les bogues logiques, les chaînes de dépendances non sécurisées, les utilisations abusives de blocs non sécurisés, les anti-modèles de performance et les dérives de style persistent. rustcLes équipes qui déploient à grande échelle un code Rust fiable combinent le compilateur avec un ensemble d'outils d'analyse statique multicouches, chacun couvrant une partie différente de la surface de qualité.

Choisir la mauvaise combinaison d'outils fait perdre du temps Ă  l'intĂ©gration continue et gĂ©nère du bruit que les dĂ©veloppeurs finissent par ignorer. Choisir la bonne combinaison, c'est faire en sorte que la rigueur du compilateur soit perçue comme un minimum plutĂ´t qu'un maximum. Les outils prĂ©sentĂ©s dans ce guide sont organisĂ©s selon leur fonction, et non par ordre alphabĂ©tique, afin que les Ă©quipes puissent construire une pile technologique couvrant les trois niveaux de qualitĂ© : analyse statique et bonnes pratiques, sĂ©curitĂ© des dĂ©pendances et vĂ©rification approfondie du code critique ou sensible Ă  la sĂ©curitĂ©.

SMART TS XL

Maintenir la qualité dans le développement Rust moderne est un défi, même avec les solides garanties de sécurité du langage. SMART TS XL est conçu pour aider les équipes à créer des logiciels fiables, maintenables et sécurisés, en offrant des capacités d'analyse statique approfondies, adaptées aux fonctionnalités uniques de Rust. Il prend en charge les workflows d'ingénierie professionnels en détectant les problèmes en amont, en garantissant la cohérence et en réduisant les efforts de révision manuelle.

Analyse statique des trois couches de rouille

Comprendre quel outil utiliser et où permet d'éviter l'erreur fréquente d'utiliser un vérificateur formel là où un linter suffirait, ou de se fier à un linter alors qu'un scanner de sécurité est nécessaire. Tout projet Rust mature devrait couvrir ces trois niveaux.

Niveau 1 : L’analyse statique du code et le contrĂ´le de style dĂ©tectent les violations idiomatiques, les erreurs courantes et les problèmes de maintenabilitĂ©. Outils : Clippy, rustfmt, rust-analyzer.

Couche 2 : Audits de sĂ©curitĂ© des dĂ©pendances et de la chaĂ®ne d’approvisionnement des caisses tierces afin de dĂ©tecter les vulnĂ©rabilitĂ©s connues et les violations de politiques. Outils : cargo-audit, cargo-deny, cargo-auditable.

Couche 3 : La vĂ©rification approfondie dĂ©tecte les problèmes de sĂ©curitĂ© mĂ©moire dans le code non sĂ©curisĂ© et les comportements indĂ©finis, et prouve formellement les propriĂ©tĂ©s des fonctions critiques. Outils : Miri, Kani, MIRAI, Rudra, Creusot, Prusti.

Le tableau ci-dessous associe chaque outil principal Ă  sa couche, son coĂ»t, son adĂ©quation Ă  l'intĂ©gration continue et son principal cas d'utilisation :

OutilCouchePrixCI adaptéCas d'utilisation principal
ClippyPeluchageLibre / OSSOuiLinting idiomatique, style, bugs courants
rustfmtPeluchageLibre / OSSOuiApplication du formatage du code
analyseur de rouillePeluches / DXLibre / OSSPartielDiagnostic IDE, analyse en ligne
audit de fretSécurité des dépendancesLibre / OSSOuiCVE connues dans les caisses
refus de cargaisonSécurité des dépendancesLibre / OSSOuiLicence, duplicatas, avis
cargaison auditableSécurité des dépendancesLibre / OSSOuiIncorporer les données de dépendance dans les binaires
MiriVérification approfondieLibre / OSSSélectifComportement indéfini dans du code non sécurisé
KaniVérification approfondieLibre / OSSSélectifVérification formelle, vérification de modèles
MIRAIVérification approfondieLibre / OSSSélectifInterprétation abstraite, analyse de la contamination
RudraVérification approfondieLibre / OSSRechercheFailles de sécurité mémoire dans Rust non sécurisé
SemgrepNameTransversalNiveau gratuit + niveau payantOuiModèles de sécurité personnalisés, multilingue
SonarCloudTransversalNiveau gratuit + niveau payantOuiContrôle qualité continu, tableaux de bord

Couche 1 : Analyse statique du code, style et expĂ©rience du dĂ©veloppeur

Clippy

Clippy est le point de dĂ©part incontournable pour l'analyse statique en Rust. IntĂ©grĂ© Ă  la chaĂ®ne d'outils officielle de Rust, il propose plus de 700 lints couvrant la correction, les performances, le style, la complexitĂ© et les restrictions. C'est l'outil que la plupart des Ă©quipes Rust utilisent quotidiennement, et Ă  juste titre : il dĂ©tecte les vĂ©ritables bogues, et non de simples prĂ©fĂ©rences stylistiques.

bash

# Run all lints including pedantic and nursery groups
cargo clippy -- -W clippy::all -W clippy::pedantic

# Fail CI on any warning
cargo clippy -- -D warnings

# Check specific lint group
cargo clippy -- -W clippy::correctness -W clippy::suspicious

Il est important de bien comprendre les catĂ©gories de lint de Clippy :

CatégoriesCe qu'il attrape
correctnessCode presque certainement erroné (toujours nier)
suspiciousCode probablement erroné ou très surprenant
styleDes modèles non idiomatiques avec une nette amélioration
complexityConstructions inutilement complexes
performanceCode qui compile mais s'exécute plus lentement que prévu
pedanticDirectives strictes, subjectives (activation sélective)
restrictionRègles que vous pourriez vouloir appliquer dans des contextes spécifiques
nurseryLes nouvelles peluches peuvent produire des faux positifs.

vĂ©rification de cargaison vs clippy: cargo check Il valide la conformitĂ© des types et la compilation sans gĂ©nĂ©rer de binaire. Il est rapide et adaptĂ© Ă  la vĂ©rification de la construction. cargo clippy fonctionne cargo check plus toutes les analyses de lint. Pour l'intĂ©gration continue, exĂ©cutez cargo check pour un retour d'information rapide sur la compilation et cargo clippy -- -D warnings en tant que contrĂ´le qualitĂ© distinct. Ils ne sont pas interchangeables : cargo check ne dĂ©tectera pas les problèmes idiomatiques, et cargo clippy est plus lent.

Configuration de Clippy via clippy.toml ou les attributs en ligne permettent aux Ă©quipes de contrĂ´ler le bruit :

TomL

# clippy.toml
avoid-breaking-exported-api = false
msrv = "1.70"

rouille

// Suppress a lint for one function with documented reason
#[allow(clippy::too_many_arguments)]
fn complex_setup(...) { ... }

Clippy ne prend pas en charge : l’analyse approfondie des flux de donnĂ©es entre les modules, l’analyse des vulnĂ©rabilitĂ©s de sĂ©curitĂ© dans les dĂ©pendances, la preuve formelle de conformitĂ© ni les règles personnalisĂ©es propres Ă  l’organisation. Ces fonctionnalitĂ©s nĂ©cessitent des outils situĂ©s dans les autres couches.

rustfmt

rustfmt impose un formatage cohĂ©rent dans l'ensemble du code source en utilisant cargo fmtL’ rustfmt.toml Le fichier de configuration dĂ©finit les règles de style Ă  l'Ă©chelle du projet. Dans l'intĂ©gration continue, cargo fmt -- --check se termine avec un code d'erreur diffĂ©rent de zĂ©ro si un fichier quelconque doit ĂŞtre reformatĂ©, ce qui en fait un contrĂ´le qualitĂ© simple sans surcharge de configuration :

bash

# Check formatting without modifying files (CI mode)
cargo fmt -- --check

# Apply formatting (developer mode)
cargo fmt

Intégration de rust-analyzer et de l'IDE

rust-analyzer est l'implémentation du protocole LSP (Language Server Protocol) pour Rust. Il offre des diagnostics en temps réel, la complétion automatique, la navigation vers la définition et l'affichage des avertissements Clippy directement dans tout éditeur compatible LSP. Il remplace le serveur de langage RLS (Rust Language Server), désormais obsolète, et devrait être le seul serveur de langage utilisé dans les nouveaux projets.

Du point de vue de l'analyse statique, rust-analyzer affiche les lints de Clippy directement dans le code au fur et Ă  mesure que les dĂ©veloppeurs tapent, fournissant un retour immĂ©diat sur les problèmes de style et de correction dès leur apparition, sans nĂ©cessiter d'exĂ©cution sĂ©parĂ©e dans le terminal :

json

// VS Code settings.json: enable Clippy via rust-analyzer
{
  "rust-analyzer.check.command": "clippy",
  "rust-analyzer.check.extraArgs": [
    "--", "-W", "clippy::all", "-W", "clippy::pedantic"
  ]
}

rust-analyzer fournit également des indications contextuelles pour les types inférés, les durées de vie des emprunts et les noms des paramètres, ce qui est utile pour examiner du code inconnu sans avoir à consulter les définitions.

Couche 2 : Dépendance et sécurité de la chaîne d'approvisionnement

audit de fret

Les contrôles d'audit de cargaison Cargo.lock Ce fichier est comparé à la base de données de sécurité RustSec afin d'identifier les vulnérabilités CVE connues dans les dépendances directes et transitives. Il s'agit de l'outil de sécurité des dépendances minimal que tout projet Rust devrait exécuter en intégration continue.

bash

# Install
cargo install cargo-audit

# Run audit
cargo audit

# Ignore a specific advisory (document the reason in comments)
cargo audit --ignore RUSTSEC-2024-0001

# JSON output for pipeline integration
cargo audit --json | jq '.vulnerabilities'

cargo-audit ne couvre que les avis de sécurité connus et publiés. Il ne peut pas détecter les vulnérabilités dans votre propre code, les problèmes non encore répertoriés dans la base de données RustSec, ni les violations de politiques telles que les licences non désirées.

refus de cargaison

cargo-deny étend la gestion des dépendances au-delà des CVE connues pour inclure la conformité des licences, la détection des crates dupliqués et les politiques d'autorisation/d'interdiction personnalisées. C'est l'outil le plus complet pour les organisations soumises à des exigences de conformité.

TomL

# deny.toml
[advisories]
vulnerability = "deny"
unmaintained = "warn"

[licenses]
allow = ["MIT", "Apache-2.0", "ISC", "BSD-2-Clause", "BSD-3-Clause"]
deny = ["GPL-2.0"]
copyleft = "warn"

[bans]
multiple-versions = "warn"

bash

cargo install cargo-deny
cargo deny check

cargaison auditable

cargo-auditable intègre l'arbre de dépendances complet dans les binaires Rust compilés sous forme de métadonnées structurées dans une section dédiée de l'éditeur de liens. Cela permet d'auditer les binaires déployés sans accéder au code source, ce qui est précieux pour les analyses de sécurité post-déploiement et la transparence de la chaîne d'approvisionnement.

bash

cargo install cargo-auditable
cargo auditable build --release
# The binary now contains auditable dependency metadata
# Audit a binary directly:
cargo audit bin ./target/release/my-service

Couche 3 : Vérification approfondie

Les outils de cette couche nécessitent une configuration plus poussée, une expertise plus pointue et des temps d'analyse plus longs. Ils ne conviennent pas à toutes les fonctions de tous les codes sources. Ils sont indispensables pour le code non sécurisé, les implémentations cryptographiques, la logique d'analyse syntaxique traitant des entrées non fiables et tout code dont la correction doit être prouvée plutôt que testée.

Miri : Détection de comportements indéfinis

Miri est un interprĂ©teur pour la reprĂ©sentation intermĂ©diaire de niveau moyen (MIR) de Rust qui exĂ©cute le code d'une manière qui dĂ©tecte les comportements indĂ©finis autorisĂ©s par le compilateur mais qui violent les garanties de sĂ©curitĂ© de Rust : accès mĂ©moire hors limites dans les blocs non sĂ©curisĂ©s, utilisation après libĂ©ration, dĂ©rĂ©fĂ©rencements de pointeurs mal alignĂ©s, conflits de donnĂ©es dans le code non sĂ©curisĂ© multithread et violations du modèle d'alias de Rust.

bash

# Install Miri (requires nightly)
rustup +nightly component add miri

# Run tests under Miri
cargo +nightly miri test

# Enable strict aliasing validation
MIRIFLAGS="-Zmiri-strict-provenance" cargo +nightly miri test

Ce que Miri détecte: comportement indéfini dans unsafe Blocages, violations d'accès mémoire, utilisation après libération, accès mal alignés, dépassement d'entier dans les versions de débogage, conflits de données dans le code concurrent non sécurisé.

Ce que Miri ne couvre pas : les erreurs logiques dans le code sĂ»r qui n’impliquent pas de comportement indĂ©fini, les vulnĂ©rabilitĂ©s liĂ©es aux dĂ©pendances, les problèmes de style de code ou les problèmes de performance.

IntĂ©gration CIMiri fonctionne 10 Ă  50 fois plus lentement que cargo testExĂ©cutez-le de manière sĂ©lective sur les modules contenant unsafe code, ou selon une planification nocturne plutĂ´t qu'Ă  chaque commit :

yaml

- name: Miri on unsafe modules
  run: |
    rustup +nightly component add miri
    cargo +nightly miri test --package my-unsafe-crate

Kani : Vérification de modèles et vérification formelle

Kani, développé par Amazon Web Services, est un vérificateur de modèles qui vérifie formellement les propriétés du code Rust en explorant exhaustivement les chemins d'exécution jusqu'à une limite définie. Alors que Miri exécute des cas de test concrets et détecte des bogues précis, Kani prouve ou réfute la validité des propriétés pour toutes les entrées comprises dans son périmètre d'analyse.

Kani nĂ©cessite l'Ă©criture de cadres de vĂ©rification : des fonctions qui dĂ©finissent l'espace d'entrĂ©e et les propriĂ©tĂ©s Ă  vĂ©rifier :

rouille

#[cfg(kani)]
mod verification {
    use super::*;

    #[kani::proof]
    fn verify_add_no_overflow() {
        let a: u32 = kani::any();
        let b: u32 = kani::any();
        if a.checked_add(b).is_some() {
            let result = safe_add(a, b);
            assert!(result == a + b);
        }
    }
}

bash

cargo install --locked kani-verifier
cargo kani setup
cargo kani

Idéal pour : les fonctions critiques pour la sécurité, les implémentations de protocoles, les opérations arithmétiques dans le code financier ou cryptographique, et toute fonction pour laquelle il est nécessaire de prouver, et non seulement de tester, une propriété de correction.

MIRAI : Interprétation abstraite et analyse de la contamination

MIRAI, développé par Facebook Research, utilise l'interprétation abstraite pour analyser le MIR de Rust. Il effectue une analyse interprocédurale qui suit le flux des valeurs lors des appels de fonctions, détectant ainsi les paniques potentielles, les violations de contrat et la propagation de la contamination dans le code.

rouille

use mirai_annotations::*;

fn divide(a: i32, b: i32) -> i32 {
    precondition!(b != 0);  // MIRAI verifies all callers satisfy this
    a / b
}

MIRAI nécessite un compilateur Rust nocturne et sa configuration est complexe, ce qui le rend plus approprié aux équipes disposant de capacités d'ingénierie de sécurité dédiées ou d'exigences de qualité axées sur la recherche.

Rudra : SĂ©curitĂ© de la mĂ©moire dans le code de bibliothèque non sĂ©curisĂ©

Rudra effectue une analyse complète du programme, couvrant l'ensemble des crates, afin de dĂ©tecter les failles de sĂ©curitĂ© mĂ©moire spĂ©cifiques au modèle de propriĂ©tĂ© de Rust : violations de sĂ©curitĂ© des traits Send/Sync, problèmes de durĂ©e de vie de niveau supĂ©rieur permettant une extension de durĂ©e de vie non sĂ©curisĂ©e, et problèmes de gestion des paniques dans le code non sĂ©curisĂ©. DĂ©veloppĂ© initialement par des chercheurs, Rudra fonctionne comme un plugin de compilateur et nĂ©cessite une version nightly spĂ©cifique. Il est recommandĂ© de l'exĂ©cuter rĂ©gulièrement pour les crates de bibliothèque contenant des Ă©lĂ©ments internes non sĂ©curisĂ©s, plutĂ´t qu'Ă  chaque commit.

Creusot et Prusti : Vérification déductive

Creusot et Prusti sont des outils de vérification déductive qui prouvent les propriétés mathématiques des programmes Rust. Ils requièrent des spécifications formelles (préconditions, postconditions, invariants de boucle) et utilisent des démonstrateurs de théorèmes automatisés pour vérifier les implémentations par rapport à ces spécifications. Ils ciblent un sous-ensemble restreint de code Rust sûr et nécessitent une expertise en méthodes formelles. Ils conviennent aux secteurs réglementés, au développement de bibliothèques cryptographiques ou à tout contexte où la preuve mathématique de la correction est une exigence contractuelle ou réglementaire.

Outils supplémentaires à inclure

Semgrep pour les modèles de sécurité personnalisés

Semgrep propose une analyse statique basée sur des modèles, fonctionnant simultanément sur plusieurs langages. Pour Rust, elle permet aux équipes de définir des règles personnalisées appliquant les politiques de sécurité de l'organisation et les modèles spécifiques au code source, ce que Clippy ne peut pas exprimer.

yaml

# Custom rule: flag .unwrap() in production paths
rules:
  - id: no-unwrap-in-production
    pattern: $X.unwrap()
    message: "Use proper error handling instead of .unwrap()"
    languages: [rust]
    severity: WARNING

Semgrep fournit également un registre de règles géré contenant des règles de sécurité Rust maintenues par la communauté.

SonarCloud / SonarQube pour les contrôles qualité continus

SonarCloud propose une analyse continue de la qualité du code grâce à un tableau de bord, un suivi des tendances et l'annotation des demandes de fusion. Sa prise en charge de Rust couvre les schémas de bogues courants, les points faibles en matière de sécurité et les anomalies de code. Pour les équipes d'entreprise utilisant déjà SonarCloud pour d'autres langages, l'ajout de Rust au même pipeline offre une visibilité unifiée sur la qualité de l'ensemble de la pile technologique.

Création d'un pipeline CI/CD à plusieurs niveaux

Le flux de travail GitHub Actions suivant reprĂ©sente un point de dĂ©part pratique pour les Ă©quipes qui souhaitent une couverture de qualitĂ© complète de Rust sans sur-ingĂ©nierie :

yaml

# .github/workflows/quality.yml
name: Code Quality and Security

on: [push, pull_request]

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable
        with:
          components: clippy, rustfmt

      - name: Check formatting
        run: cargo fmt -- --check

      - name: Clippy (treat warnings as errors)
        run: cargo clippy -- -D warnings

  security:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable

      - name: Install security tools
        run: |
          cargo install cargo-audit
          cargo install cargo-deny

      - name: Dependency audit
        run: cargo audit --deny warnings

      - name: License and policy check
        run: cargo deny check

  verify:
    runs-on: ubuntu-latest
    # Scheduled or manually triggered, not on every push
    if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@nightly
        with:
          components: miri

      - name: Miri on unsafe modules
        run: cargo +nightly miri test --package my-unsafe-crate

Quel outil utiliser ? Guide de décision

Nouveau projet Rust : Clippy + rustfmt + cargo-audit. Configurable en moins de cinq minutes, ce système dĂ©tecte la plupart des problèmes de qualitĂ© et de sĂ©curitĂ© rencontrĂ©s par les Ă©quipes.

Service de production avec dépendances externes : Ajouter cargo-deny pour la conformité des licences et l'application des politiques de la chaîne d'approvisionnement au-delà des CVE.

Bibliothèque contenant des Ă©lĂ©ments internes non sĂ©curisĂ©s : ajoutez Miri Ă  votre suite de tests pour les modules contenant du code non sĂ©curisĂ©. ExĂ©cutez Rudra de manière planifiĂ©e.

Code critique pour la sĂ©curitĂ© ou cryptographique : Élaborez des cadres de vĂ©rification Kani pour les fonctions les plus critiques. Envisagez Creusot ou Prusti si l’équipe possède une expertise en mĂ©thodes formelles.

Organisation axĂ©e sur la sĂ©curitĂ© : ajoutez Semgrep avec des règles personnalisĂ©es pour les politiques de sĂ©curitĂ© organisationnelles, ainsi qu’une auditabilitĂ© Cargo dans les versions de production.

VisibilitĂ© continue pour une Ă©quipe plus nombreuse : SonarCloud pour le suivi des tendances, la dĂ©coration des demandes de fusion et les contrĂ´les qualitĂ©, en complĂ©ment des outils open source.

environnement d'entreprise polyglotte lĂ  oĂą Rust interagit avec COBOL, Java ou d'autres langages hĂ©ritĂ©s : les outils Rust monolingue ne peuvent pas voir au-delĂ  de la frontière du langage. SMART TS XL fournit l'analyse interlinguistique qui couvre l'ensemble du système.

Quand l'analyse statique de Rust rencontre les systèmes d'entreprise

Rust est de plus en plus utilisé pour les nouveaux services au sein des organisations qui exécutent également COBOL, Java, PL/I ou RPG sur des systèmes mainframe ou des plateformes existantes. Dans ces environnements, l'analyse statique s'étend bien au-delà des capacités des outils spécifiques à Rust. Un microservice Rust peut appeler un programme COBOL, écrire dans une base de données partagée ou consommer des événements générés par un système de traitement par lots existant. L'analyse de la qualité et des dépendances, essentielle pour un architecte d'entreprise, porte simultanément sur l'ensemble de ces systèmes.

SMART TS XL comble cette lacune en fournissant une analyse des dépendances interlangages pour l'ensemble du portefeuille d'applications. Là où Clippy et cargo-audit ne détectent que Rust, SMART TS XL Il cartographie la manière dont un service Rust dépend des structures de données partagées, des programmes existants et des API d'entreprise, et évalue l'impact de toute modification de ces dépendances. C'est ce qui en fait l'outil de prédilection pour analyse d’impact et planification de la modernisation du patrimoine dans des environnements où Rust n'est qu'un langage parmi d'autres.

Pour les équipes qui adoptent Rust progressivement au sein d'une base de code d'entreprise plus vaste, SMART TS XL's analyse de code statique offre la visibilité structurelle nécessaire pour comprendre comment les composants Rust s'intègrent au système global avant d'apporter des modifications susceptibles d'affecter des composants écrits dans d'autres langages. Comme examiné dans le contexte de graphes de dépendance et risque applicatifCartographier l'ensemble de la structure des dépendances avant d'étendre un système est ce qui distingue les changements qui se déroulent sans accroc de ceux qui produisent des défaillances dans des composants que personne n'a pensé à tester.

L'approche par couches est essentielle.

L'analyse statique en Rust ne se résume pas au choix d'un seul outil. C'est une approche progressive qui part des fonctionnalités offertes par le compilateur et s'étend en fonction du profil de risque du code. Clippy et rustfmt constituent la base. cargo-audit est indispensable pour tout projet avec des dépendances externes. Miri est nécessaire pour tout projet contenant du code non sécurisé. Kani et les outils de vérification formelle sont destinés aux fonctions où toute erreur est inacceptable.

Les Ă©quipes qui maĂ®trisent cette approche intègrent l'analyse statique au cycle de dĂ©veloppement : Clippy directement dans l'Ă©diteur, cargo-audit Ă  chaque exĂ©cution d'intĂ©gration continue et Miri exĂ©cutĂ© quotidiennement pour dĂ©tecter les erreurs que les tests seuls ne peuvent pas dĂ©celer. Le rĂ©sultat ne se limite pas Ă  la rĂ©duction des bogues ; il renforce la confiance dans le code source, permettant aux Ă©quipes d'apporter rapidement des modifications, sachant que les couches d'analyse entre le dĂ©veloppement et la production fonctionnent correctement.