Testes de segurança aprimorados para projetos Gradle baseados em Git usando arquivos de lock
Antonio Gomes
7 de dezembro de 2020
0 minutos de leituraNo último ano, trabalhamos bastante para tornar os testes de segurança de projetos Gradle importados de repositórios Git mais confiáveis, precisos e escaláveis.
Entendemos que analisar um manifesto do Gradle, em vez de um arquivo de lock do Gradle, seria uma batalha sem fim que nunca venceríamos. Tentar interpretar o modelo de complexidade do Gradle analisando um arquivo build.gradle é uma abordagem não determinística, que depende de muitas suposições. Configurações que forçam estritamente uma versão específica ou uma versão máxima de uma ou mais dependências, ou cujas versões são definidas em outros arquivos, nem sempre seriam consideradas. Além disso, essa abordagem nunca declarará explicitamente o que o Gradle resolverá e usará em diferentes contextos de configuração, como nas fases de compilação, teste ou execução. Tudo isso pode levar a resultados imprecisos ou incompletos.
Por isso, diferentes ferramentas de dependências usam o bloqueio de dependências para ajudar desenvolvedores a obter compilações reproduzíveis. Alguns exemplos são npm (package-lock.json), yarn (yarn.lock), RubyGems (Gemfile.lock) e, agora, também o Gradle com gradle.lockfile.
Como gerar um arquivo de lock do Gradle
Este é um exemplo típico de arquivo gradle.lockfile:

Ele não contém uma estrutura em árvore ou em grafo. Em vez disso, faz seu trabalho incluindo todas as dependências diretas e transitivas em uso, e especificando as versões e as configurações às quais elas pertencem.
Para gerar um arquivo de lock em um projeto único ou em um monorepo (com diferentes subprojetos), edite o arquivo build.gradle com as instruções a seguir:

Como você pode ver, estamos pedindo ao Gradle para ativar dependencyLocking considerando todas as configurações disponíveis, como annotationProcessor, compilação, execução etc.
Depois de adicionar o código, o Gradle entenderá o que queremos fazer.
Neste exemplo, temos uma única configuração, mas normalmente podemos ter várias configurações e acabar com vários arquivos de lock, um por configuração. Para ter uma única fonte da verdade, veja como gerar um único arquivo de lock por projeto.
Gerar um único arquivo de lock
Com uma prévia de recurso do Gradle 7.0, já disponível para quem usa o Gradle 6.0 ou superior, podemos gerar um único gradle.lockfile por projeto, contendo todos os diferentes estados de lock para cada configuração. Essa abordagem com um único arquivo de lock será o padrão a partir do Gradle 7.0.

Depois de definir essa regra, o próximo passo é executar no terminal o comando gradle resolveAndLockAll --write-locks, que gerará o arquivo de lock abaixo:

Como podemos ver acima:
cada linha ainda representa uma única dependência na notação GAV
group:artifact:version.cada dependência tem uma lista das configurações às quais pertence.
a última linha,
empty, contém a lista das configurações disponíveis que não têm dependências.
Como o arquivo de lock do Gradle facilita sua vida
O bloqueio de dependências pode evitar erros inesperados causados por uma dependência transitiva sobre a qual você não tem controle quando usa versões dinâmicas de dependências (por exemplo, 1.+ ou [1.0,2.0). Esse cenário é comum e pode acontecer a qualquer momento sem que você perceba.
Aqui temos um pequeno arquivo build.gradle que declara uma dependência com uma versão dinâmica:

Ao executar o comando gradle -q dependencies, o resultado não é 2.11 nem 2.14. Como podemos ver na imagem abaixo, o Gradle resolveu as dependências para a versão 2.13.

Agora, ao verificar as dependências disponíveis no arquivo de lock, podemos confirmar que o resultado do comando corresponde ao estado do arquivo de lock da aplicação deste exemplo.

Agora é hora de ver os resultados!
Neste caso, não conseguimos analisar o arquivo build.gradle, que continha dependências com versões dinâmicas. Vamos comparar os resultados usando um gradle.lockfile.

Como podemos ver, os resultados com o gradle.lockfile são muito melhores: conseguimos identificar 24 dependências, contra 0 no caso anterior, incluindo dependências diretas e transitivas, e reportar um total de 33 problemas!

Se quiser saber mais sobre o bloqueio de dependências no Gradle, consulte a documentação oficial.
Esperamos que você goste desse recurso do Snyk! Ainda não tem uma conta Snyk? Cadastre-se gratuitamente.
Comece a participar de desafios de Capture the Flag
Aprenda a resolver desafios de Capture the Flag assistindo sob demanda ao nosso workshop virtual introdutório.
