Pruebas de seguridad mejoradas para proyectos de Gradle basados en Git mediante archivos de bloqueo
Antonio Gomes
7 de diciembre de 2020
0 minutos de lecturaDurante el último año, hemos trabajado arduamente para mejorar las pruebas de los proyectos de Gradle importados desde repositorios de Git, con el objetivo de hacerlas más confiables, precisas y escalables.
Entendimos que analizar un manifiesto de Gradle en lugar de un archivo de bloqueo de Gradle sería una batalla interminable que siempre perderíamos. Intentar interpretar el modelo de complejidad de Gradle analizando un archivo build.gradle es un enfoque no determinista que depende de muchas suposiciones. No siempre se tendrían en cuenta las configuraciones que fuerzan estrictamente una versión determinada o una versión máxima de una o varias dependencias, ni aquellas cuyas versiones se definen en otros archivos. Además, este enfoque nunca declarará explícitamente qué resolverá y usará Gradle en distintos contextos de configuración, como las fases de compilación, prueba o ejecución. Todo esto puede generar resultados imprecisos o incompletos.
Por eso, distintas herramientas de dependencias recurren al bloqueo de dependencias para ayudar a los desarrolladores a lograr compilaciones reproducibles. Algunos ejemplos son npm (package-lock.json), yarn (yarn.lock), RubyGems (Gemfile.lock) y ahora también Gradle con gradle.lockfile.
Cómo generar un archivo de bloqueo de Gradle
Así se ve un archivo gradle.lockfile típico:

No contiene una estructura de árbol o de grafo; en cambio, cumple su función al incluir todas las dependencias directas y transitivas que se usan, e indicar sus versiones y las configuraciones a las que pertenecen.
Para generar un archivo de bloqueo en tu proyecto único o monorepositorio (que contiene distintos subproyectos), edita el archivo build.gradle con las siguientes instrucciones:

Como puedes ver, le pedimos a Gradle que active dependencyLocking para todas las configuraciones disponibles, por ejemplo, annotationProcessor, compilación, ejecución, etc.
Una vez que agregamos el código, Gradle podrá entender lo que queremos hacer.
En este ejemplo, tenemos una sola configuración, pero normalmente podemos tener varias y terminar con varios archivos de bloqueo, uno por configuración. Para tener una única fuente de verdad, veamos cómo generar un solo archivo de bloqueo por proyecto.
Cómo generar un solo archivo de bloqueo
Con una vista previa de una función de Gradle 7.0, que ya está disponible para usuarios de Gradle 6.0 o posterior, podemos generar un solo gradle.lockfile por proyecto que contenga todos los distintos estados de bloqueo de las diferentes configuraciones. Este enfoque de un solo archivo de bloqueo será el predeterminado a partir de Gradle 7.0.

Una vez definida esta regla, el siguiente paso es ejecutar en la terminal el comando gradle resolveAndLockAll --write-locks, que generará el siguiente archivo de bloqueo:

En lo anterior, podemos ver que:
cada línea sigue representando una sola dependencia en la notación GAV
group:artifact:version.cada dependencia tiene una lista de las configuraciones a las que pertenece.
la última línea,
empty, contiene la lista de configuraciones disponibles que no tienen dependencias.
Cómo el archivo de bloqueo de Gradle te facilita la vida
El bloqueo de dependencias puede evitar errores inesperados causados por una dependencia transitiva que no puedes controlar cuando usas versiones dinámicas de dependencias (por ejemplo, 1.+ o [1.0,2.0). Este es un caso común que puede ocurrir en cualquier momento sin que te des cuenta.
Aquí tenemos un pequeño archivo build.gradle en el que declaramos una dependencia con una versión dinámica:

Al ejecutar el comando gradle -q dependencies, el resultado no es 2.11 ni 2.14. Como podemos ver en la imagen a continuación, Gradle resolvió las dependencias a la versión 2.13.

Ahora, al verificar las dependencias disponibles en el archivo de bloqueo, podemos confirmar que el resultado del comando coincide con el estado del archivo de bloqueo de la aplicación de nuestro ejemplo.

¡Es hora de ver los resultados!
Aquí tenemos un caso en el que no pudimos analizar el archivo build.gradle, que contenía dependencias con versiones dinámicas. Comparemos los resultados usando un gradle.lockfile.

Como podemos ver, los resultados al usar el archivo gradle.lockfile son mucho mejores: pudimos identificar 24 dependencias frente a 0 en el caso anterior, incluidas las directas y transitivas, y reportar un total de 33 problemas.

Si quieres profundizar en el bloqueo de dependencias en Gradle, consulta la documentación oficial.
¡Esperamos que te guste esta función de Snyk! ¿Todavía no tienes una cuenta de Snyk? Regístrate gratis.
Empieza con Capture the Flag
Aprende a resolver desafíos de Capture the Flag viendo nuestro taller virtual introductorio a pedido.


