Pruebas de mutación para la era de la agencia
CYBERSECURITY ANÁLISIS DESTACADO

Pruebas de mutación para la era de la agencia

FUENTE

The Trail of Bits Blog

DATE

READ

9 min de lectura

La cobertura del código, una métrica de prueba de software comúnmente utilizada, puede ser engañosa, ya que mide la ejecución en lugar de la verificación, lo que puede ocultar funciones críticas que no se han probado. …

El análisis de cobertura es una de las métricas de calidad más peligrosas en las pruebas de software. Muchos desarrolladores no se dan cuenta de que el análisis de cobertura funciona por omisión: mide la ejecución, no la verificación. Los conjuntos de pruebas con alta cobertura pueden ocultar el hecho de que las funcionalidades críticas no se han probado, a medida que el software evoluciona con el tiempo. Lo vimos cuando las pruebas de mutación revelaron una vulnerabilidad grave del protocolo Arkis, que había pasado desapercibida debido a las métricas de cobertura, y que habría permitido a los atacantes drenar fondos. Hoy, estamos anunciando MuTON y mewt, dos nuevas herramientas de pruebas de mutación optimizadas para su uso con agentes, junto con una habilidad de optimización de configuración para ayudar a los agentes a configurar campañas de forma eficiente. MuTON proporciona un soporte de primera clase para los lenguajes del blockchain TON (FunC, Tolk y Tact), mientras que mewt es el núcleo sin ambigüedades que también admite Solidity, Rust, Go y más. El objetivo de las pruebas de mutación es introducir sistemáticamente errores (mutantes) y comprobar si sus pruebas los detectan, señalando los puntos críticos donde el código no está suficientemente probado. Sin embargo, las herramientas de pruebas de mutación históricamente han sido lentas y específicas de cada lenguaje. MuTON y mewt están diseñadas para cambiar esto. Para entenderlo, ayuda primero comprender lo que están reemplazando. La era de las expresiones regulares. Las pruebas de mutación se remontan a la década de 1970, pero durante mucho tiempo, esta técnica rara vez se adoptó en el espacio blockchain como una medida de calidad del software. Los frameworks de pruebas están estrechamente acoplados a los lenguajes objetivo, lo que dificulta la compatibilidad con nuevos lenguajes. Universalmutator cambió esto con su motor de expresiones regulares. Después de añadir soporte para Solidity en un commit del 10 de marzo de 2018, la herramienta ganó rápidamente tracción en el espacio blockchain. Colaboramos con el equipo de universalmutator para avanzar en las pruebas de contratos inteligentes y destacamos la herramienta en nuestra publicación de blog de 2019. A pesar (o quizás debido a) su enfoque elegante y su código base compacto, universalmutator generó un número impresionante de mutantes, lo que permitió a los desarrolladores evaluar la cobertura de las pruebas de forma más exhaustiva que las herramientas más simples. Vyper y otras funcionalidades de soporte de lenguajes siguieron, consolidando a universalmutator como la herramienta de pruebas de mutación líder para blockchain. Sin embargo, las expresiones regulares tienen límites fundamentales. Los patrones basados en líneas no pueden mutar declaraciones multi-línea, una laguna crítica que se reconoció en el documento original. Más problemático: sin priorización de mutantes, la herramienta desperdicia tiempo en mutaciones redundantes. Cuando comentar una línea no provoca fallos, universalmutator aún genera y prueba todas las posibles variaciones de esa línea, lo que prolonga drásticamente el tiempo de ejecución de la campaña. Imprimir los resultados en stdout añade aún más fricción a los humanos y agentes de IA que revisan las campañas. Las mejoras posteriores (incluida una transición a comby en 2024 para un mejor manejo sintáctico) abordaron algunos puntos débiles, pero las limitaciones restantes llevaron al desarrollo de alternativas más enfocadas. Entre 2019 y 2023, surgieron varias herramientas para abordar estos problemas, incluida nuestra solución slither-mutate. Cada una adoptó un enfoque diferente para los problemas centrales de comprensión del lenguaje, escalabilidad y calidad de las pruebas. slither-mutate: Velocidad a través de la priorización. Lanzamos slither-mutate en agosto de 2022, después de que Vishnuram, nuestro equipo de invierno, lo hiciera posible. Dado que Slither ya analizaba el AST de Solidity y proporcionaba una API de Python, se allanó el camino para generar mutaciones sintácticamente válidas e implementar un ciclo más limpio de “prueba-alterar-restaurar” (las herramientas anteriores ensuciaban los repositorios con archivos mutados). La innovación clave de la herramienta fue la priorización de mutantes: los mutantes de alta gravedad reemplazan las declaraciones con “revert” (exponiendo los caminos de código no ejecutados), los mutantes de gravedad media comentan líneas (revelando efectos secundarios no verificados), y los mutantes de baja gravedad realizan cambios sutiles, como intercambiar operadores. La herramienta omite los mutantes de baja gravedad cuando los mutantes de mayor gravedad ya indican una cobertura insuficiente en la misma línea, lo que reduce drásticamente el tiempo de ejecución de la campaña, que es el mayor obstáculo para la adopción generalizada de las pruebas de mutación. A finales de 2022, estábamos desplegando slither-mutate en la mayoría de las auditorías de Solidity. Permanecían dos limitaciones. En primer lugar, el estrecho acoplamiento a Solidity significaba que no había forma de soportar fácilmente otros lenguajes de blockchain. En segundo lugar, el problema de enviar resultados a stdout persistía, pero añadir una base de datos a Slither creaba una fricción inaceptable para el amplio grupo de usuarios de Slither. Introduciendo MuTON y mewt: La era de Tree-sitter. MuTON, nuestra nueva herramienta de pruebas de mutación, proporciona un soporte de primera clase para los tres lenguajes del blockchain TON: Tolk, Tact y FunC. Estamos agradecidos a la Fundación TON por apoyar su desarrollo. MuTON se basa en mewt, un núcleo sin ambigüedades de pruebas de mutación que también admite Solidity, Rust y más. MuTON logra una comprensión del lenguaje comparable a slither-mutate al admitir múltiples lenguajes utilizando Tree-sitter como su analizador. Tree-sitter proporciona el resaltado de sintaxis en los editores modernos, construyendo un árbol de sintaxis concreto que distingue las palabras clave del lenguaje de los comentarios. Esto permite a MuTON apuntar a expresiones como las sentencias “if” de forma estructurada, gestionando las sentencias multi-línea con elegancia. Tradicionalmente, integrar gramáticas Tree-sitter para el nuevo soporte de lenguajes requiere órdenes de magnitud más de tiempo que escribir reglas de expresiones regulares, pero los agentes de IA combinados con habilidades a medida invierten este cálculo, proporcionando el poder de Tree-sitter con la facilidad de extensión de las expresiones regulares. MuTON almacena todos los mutantes y los resultados de las pruebas en una base de datos SQLite, una mejora de calidad de vida que se hizo evidente al usar slither-mutate, pero no era factible retroceder. Los resultados persisten a través de las sesiones; las campañas se pueden pausar y reanudar sin perder progreso. Si accidentalmente cierras tu terminal durante una campaña de 24 horas, tu trabajo sobrevivirá. El almacenamiento persistente también permite la filtración y el formato flexibles: imprime solo los mutantes no detectados en archivos específicos, o traduce los resultados a SARIF para una mejor revisión. Esta flexibilidad ayuda a los humanos y a los agentes de IA a explorar los resultados, a triagear los hallazgos, y a buscar errores. El futuro de las pruebas de mutación. MuTON aborda muchos puntos débiles históricos, pero quedan importantes obstáculos. Tres desafíos separan las pruebas de mutación de la adopción generalizada: configurar campañas con tiempos de ejecución razonables, triagear los resultados para distinguir entre la señal y el ruido, y generar pruebas que codifiquen los requisitos en lugar de accidentes. Los agentes de IA, equipados con habilidades especializadas, prometen transformar cada uno de estos obstáculos en tareas rutinarias. Optimización del rendimiento. El rendimiento sigue siendo el mayor obstáculo para las pruebas de mutación. Si tu conjunto de pruebas tarda cinco minutos y tienes 1000 mutantes, eso significa 83 horas de tiempo de ejecución inevitable. Las herramientas de pruebas de mutación no pueden arreglar pruebas lentas, pero una configuración inteligente puede reducir drásticamente el tiempo desperdiciado. MuTON ya te proporciona opciones potentes para ajustar las campañas: apuntar a componentes críticos en lugar de todo, utilizar campañas de dos fases que ejecutan pruebas dirigidas primero y luego re-prueban los mutantes no detectados con el conjunto completo, configurar comandos de prueba por objetivo para que las mutaciones en el código de autenticación solo desencadenen pruebas de autenticación, o restringir a mutantes de alta y media gravedad cuando el tiempo es limitado. Estas herramientas funcionan hoy y proporcionan mejoras reales de velocidad. Pero la decisión se ramifica sin fin: ¿deberías dividir por componentes o por gravedad? ¿Dos fases o pruebas dirigidas? ¿Qué tiempo de espera debe tener la recompilación incremental? Hemos lanzado una habilidad de optimización de la configuración para guiar a los agentes de IA a través de estas decisiones, midiendo tu conjunto de pruebas, estimando tiempos de ejecución, y proponiendo configuraciones óptimas adaptadas a la estructura de tu proyecto. Pruébalo ahora: está disponible en nuestro repositorio público de habilidades y hace que el proceso sea fácil. Triage de resultados. No todos los mutantes no detectados importan. Los mutantes que cambian “x > 0” a “x != 0” son operaciones sin sentido cuando x es un entero sin signo. Un mutador perfecto no generaría tales mutantes en primer lugar, pero eso requeriría una comprensión del lenguaje más profunda que Tree-sitter proporciona. Tradicionalmente, el triage manual requiere pasar cientos de resultados, revisar los tipos y comprender el contexto para extraer información útil. MuTON y la filtración flexible ya facilitan esto. Filtra por tipo de mutación o archivos específicos para resaltar los resultados de alto valor. Más importante aún, estas opciones de filtrado hacen que el triage asistido por IA sea eficiente en tokens de la misma manera que las herramientas anteriores que simplemente imprimían los resultados en stdout nunca pudieron. Incluso hoy en día, pedirle a un agente que revise los resultados de mutantes filtrados y resuma los verdaderos positivos requiere el 80% de los esfuerzos por el 1% de trabajo manual. Estamos desarrollando una habilidad de triage que guía sistemáticamente a los agentes a través del análisis de los resultados, identificando patrones como mutantes no detectados agrupados (una fuerte indicación de un error) en comparación con mutaciones de operadores aisladas en funciones de utilidad (probablemente falsos positivos o de baja prioridad). La habilidad ayudará a los agentes a señalar las áreas de alto riesgo y a explicar por qué ciertas mutaciones importan, convirtiendo los resultados brutos en información de seguridad útil. El potencial y el peligro de la generación de pruebas impulsada por mutación. A primera vista, usar las pruebas de mutación para guiar a los agentes de IA en la escritura de pruebas parece una solución elegante: muta, encuentra escapes, genera pruebas para capturarlos, repite hasta que la cobertura esté completa. Pero este enfoque ingenuo conlleva un peligro sutil: un agente sin filtro no sabe si está codificando un comportamiento correcto o propagando errores en tu conjunto de pruebas. Cuando las pruebas de mutación revelan que cambiar “prioridad >= 2” a “prioridad > 2” altera el comportamiento, ¿debería el agente escribir una prueba que afirme que “prioridad == 2” desencadene una acción? Quizás. O tal vez eso es un error, y ahora has corrompido tus pruebas con la misma lógica incorrecta, dando falsa confianza mientras doblas tu carga de mantenimiento. El verdadero desafío no es generar pruebas que simplemente capturen los mutantes; es generar pruebas que codifiquen los requisitos en lugar de accidentes. Creemos que la solución radica en construir agentes que sean escépticos, que detengan y hagan preguntas cuando encuentran patrones sospechosos o ambiguos, y que exijan validación externa antes de cristalizar el comportamiento en pruebas. Es un problema sutil que equilibra las fortalezas de la IA con la limitada atención de los desarrolladores, pero estamos trabajando en ello. Mantente atento.