いけむランド

はてダからやってきました

build.gradle のクソデカ化と戦っている

Log4Shell みたいなことが起きた時に慌てるのは嫌だなということで、去年の年末以降は dependency-check や trivy のレポートとにらめっこしてる。 (実際には 0-day は防げないため、直接は関係しないが、芽を摘んでおくことは良いことであるはず。)

github.com

github.com

しかし、対応すればするほど build.gradle がクソデカになっていくのがなかなか悩ましい。(これは他の言語のビルドファイルでも同じかもしれない。)

当たり前だがライブラリを使えば、その可能性は高まる。

yamory.io

↑の記事にもある通り、依存先が古くて駄目というのはよくある。

+ com.example:library-a:1.2.3 <- 設計や実装が完成してしまっているため、更新されることがもうない
    + com.example:library-b:2.3.4 <- ↑が更新されないため pom が古いままで脆弱性が出てる

一番良い方法は library-a のメンテナに更新してもらうことであるが、library-a の開発がアクティブでない場合は残念ながら期待できないであろう。 そのため、使用するライブラリの開発がアクティブかどうかは選定における重要な要素の一つである。

メンテナによる対応が期待できない場合は手元の build.gradlelibrary-b を「直接使わないのだが」明示するしかない。 そして、そういうことを繰り返すことで build.gradle がクソデカになっていく...。

逆に不要なライブラリであれば、削るという対策もできる場合がある。 実際に不要なものが入っていることはそうそうないが、たまに記述ミスか何かで入ってるのを見かけることはある。

+ com.example:library-a:1.2.3
    + com.example:library-a-test:1.2.3
        + junit:junit

たとえば、開発者がテスト用のサブプロジェクトをうっかり依存を入れ込むと↑のようなことになる。 ちなみに junit は 4.x 系列だと最新じゃないとほぼヒットする (= Vulnerability がある) ため、だいたい気付ける。

mvnrepository.com

こういう場合は exclude すれば OK である。

docs.gradle.org

dependencies {
    implementation('com.example:library-a:1.2.3') {
        exclude module: 'library-a-test'
        exclude module: 'junit'
    }
}

↑のような依存の場合は library-a-test だけ exclude しても junit は残るため、推移先すべてを指定しないと駆逐できない。(つまり、成果物に入ってしまう。)

また、別のライブラリが library-a に依存している場合は、そちら経由で library-a-test 以下が成果物に入ってしまう。

そのため、すべての依存から library-a-testjunit を exclude するような書き方をするのが最善と思われる。

gradle.monochromeroad.com

configurations {
    implementation.exclude module: 'library-test-a'
    implementation.exclude module: 'junit'
}

こういうことをやって、少しずつ脆弱性のあるライブラリを成果物から取り除いていくことで安心して眠れるようになりたい。