Herramientas del ecosistema Rust: clippy avanzado, cargo-audit, flamegraph y miri

El ecosistema de herramientas de Rust va mucho más allá del compilador y Cargo. clippy con sus lints avanzados, cargo-audit para vulnerabilidades conocidas, cargo-flamegraph para perfilar CPU, miri para detectar comportamiento indefinido y cargo-deny para política de dependencias forman juntos un pipeline de calidad que pocos lenguajes pueden igualar.

clippy avanzado: pedantic, nursery y allow selectivo

clippy incluye grupos de lints con distintos niveles de agresividad. El grupo clippy::pedantic activa advertencias útiles pero que pueden generar falsos positivos; clippy::nursery añade lints experimentales. Puedes silenciar lints individuales con #[allow] donde el aviso no es aplicable.

// Activar grupos completos desde la línea de comandos:
// cargo clippy -- -W clippy::pedantic -W clippy::nursery

// O en código (afecta a todo el crate):
#![warn(clippy::pedantic)]
#![warn(clippy::nursery)]
#![allow(clippy::module_name_repetitions)] // silenciar un lint concreto

// Lints útiles de pedantic:
fn suma_positivos(v: &[i32]) -> i32 {
    // clippy::pedantic sugiere usar filter_map en lugar de filter+map
    v.iter().filter(|&&x| x > 0).sum()
    // Sugerencia: v.iter().filter(|&&x| x > 0).sum()
}

// #[allow] localizado solo donde hace falta:
#[allow(clippy::cast_possible_truncation)]
fn truncar_a_u8(n: u32) -> u8 {
    n as u8 // clippy lo marcaría sin el allow
}

// clippy::nursery: redundant_clone, cognitive_complexity...
fn procesar(datos: Vec<String>) -> Vec<String> {
    datos.into_iter()
         .filter(|s| !s.is_empty())
         .map(|s| s.to_uppercase())
         .collect()
}

cargo-audit: vulnerabilidades RUSTSEC

cargo-audit compara tu Cargo.lock con la base de datos de vulnerabilidades de RustSec y avisa si alguna dependencia tiene CVEs conocidos. Es el paso más básico de seguridad en un pipeline CI.

// Instalación y uso:
// cargo install cargo-audit
// cargo audit

// Ejemplo de salida cuando hay un advisory:
// error[RUSTSEC-2023-0072]: Potential deadlock in a specific pattern
//    --> Cargo.lock:...
//
// Para ignorar un advisory concreto (con justificación documentada):
// En .cargo/audit.toml:
// [ignore]
// RUSTSEC-2023-0072 = "No usamos la API afectada (ver issue #42)"

// En CI, falla el pipeline con:
// cargo audit --deny warnings

cargo-flamegraph: perfilado de CPU

cargo-flamegraph genera un flamegraph SVG interactivo a partir de muestras de perf (Linux) o DTrace (macOS). Permite identificar visualmente qué funciones consumen más tiempo de CPU sin tocar el código fuente.

// Instalación:
// cargo install flamegraph

// Configurar símbolos de debug manteniendo optimizaciones (Cargo.toml):
// [profile.release]
// debug = true

// Generar flamegraph de un binario:
// cargo flamegraph --bin mi-binario

// O de un benchmark criterion:
// cargo flamegraph --bench mi_bench -- --bench

// El SVG generado muestra la pila de llamadas.
// Las barras más anchas son las funciones que más tiempo consumen.
// Haz clic en cualquier función para hacer zoom.

// Para perfilar con perf directamente (más control):
// perf record -g --call-graph dwarf cargo run --release
// perf script | stackcollapse-perf.pl | flamegraph.pl > out.svg

miri: detectar comportamiento indefinido

miri es un intérprete de MIR (la representación intermedia de Rust) que ejecuta el programa simulando la memoria y detecta comportamiento indefinido, accesos fuera de bounds, uso de memoria no inicializada y violaciones del modelo de aliasing de Rust.

// Instalación (requiere nightly):
// rustup +nightly component add miri
// cargo +nightly miri test

// Ejemplo: miri detecta esto como UB aunque clippy no lo marque
unsafe fn sumar_raw(ptr: *const i32, n: usize) -> i32 {
    let mut suma = 0;
    for i in 0..n {
        suma += *ptr.add(i); // miri verifica que todos los accesos son válidos
    }
    suma
}

// miri también detecta:
// - Data races en código unsafe con hilos
// - Aliasing inválido (&mut y & al mismo dato)
// - Fugas de memoria en código unsafe
// - Acceso a memoria liberada (use-after-free)

fn main() {
    let datos = [1i32, 2, 3, 4, 5];
    let suma = unsafe { sumar_raw(datos.as_ptr(), datos.len()) };
    println!("Suma: {suma}"); // miri: OK si los índices son correctos
}

cargo-deny y cargo-udeps

cargo-deny aplica políticas sobre las dependencias del workspace: prohíbe licencias incompatibles, fuentes no permitidas y advisories de seguridad. cargo-udeps detecta dependencias declaradas en Cargo.toml que no se usan en el código.

// cargo-deny: configurar en deny.toml
// [licenses]
// allow = ["MIT", "Apache-2.0", "BSD-2-Clause", "BSD-3-Clause"]
// deny = ["GPL-3.0"]
//
// [advisories]
// db-path = "~/.cargo/advisory-db"
// db-urls = ["https://github.com/rustsec/advisory-db"]
// vulnerability = "deny"
//
// Ejecutar:
// cargo deny check

// cargo-udeps: encontrar dependencias no usadas
// cargo install cargo-udeps
// cargo +nightly udeps

// Resultado típico:
// unused dependencies:
// `mi-crate v0.1.0`
// ??? dependencies
//     ??? "rand" (unused)

Integra todas estas herramientas en un script de CI que ejecute: cargo clippy -- -D warnings, cargo audit --deny warnings, cargo deny check, y cargo test. Con este pipeline básico capturas la mayoría de errores de calidad y seguridad antes de que lleguen a producción, sin necesitar herramientas externas ni configuración compleja.

COMPARTE ESTE ARTÍCULO

COMPARTIR EN FACEBOOK
COMPARTIR EN TWITTER
COMPARTIR EN LINKEDIN
COMPARTIR EN WHATSAPP