dependabot / dependabot-core

🤖 Dependabot's core logic for creating update PRs.
https://docs.github.com/en/code-security/dependabot
MIT License
4.72k stars 1.02k forks source link

Fully Featured Gradle Support with the Gradle Tooling API #1164

Open JLLeitschuh opened 5 years ago

JLLeitschuh commented 5 years ago

Foreward I'm not intimately familiar with how Dependabot works so please excuse me if I wildly misrepresent something about Dependabot.

Problem

Currently, Dependabot is attempting to parse build.gradle files as text files instead of fully understanding the complexities of Gradle Builds.

This is because the dependencies declared in a build.gradle file doesn't tell the full story.

Additionally, since Gradle now supports the Gradle Kotlin DSL, there are now build.gradle.kts files. On top of that, users can also change the name of their build files so that they call the files my-project.gradle.kts and Gradle will handle that fine.

This current methodology completely misses any dependencies added by plugins, transitive dependencies, and dependencies added using Gradle in abnormal but valid ways.

Fundamentally this issue arises because unlike NPM and Yarn, where dependency declaration files are static, Gradle & Maven both require code execution to fully resolve the dependency graph.

Solution

Gradle offers something called the Gradle Tooling API. This tooling API is already in use in IntelliJ, Eclipse, and the Gradle Test Kit.

The Tooling API exposes the entire dependency graph for the repositories build in a way that can be transformed into a format Dependabot can understand.

The Tooling API executes the Gradle Build and can be used to extract metadata about the build for consumption by external tools.

Risks

There are certain risks that are taken on by moving forward with this plan.

Security

In order to use the Tooling API, Dependabot will be required to execute the user's code in their repository. Fundamentally, this introduces untrusted code execution into the same environment where Dependabot is being executed. I don't know what the security model of Dependabot's execution is, but if executing user code is a non-starter, using the Tooling API won't work.

Performance

Sometimes developers have really, really weird builds. Sometimes they also have really slow builds. Calling the ToolingAPI will bring the Dependabot execution time from being predictable with respect to the number of files being parsed, to a non-deterministic amount of execution time.

Enviromental

Certain versions of Gradle only work with certain versions of the JVM. Certain builds only work with certain versions of the JVM. Implementing this feature will require maintainers of repositories to explicitly declare what version of the JVM their build depends upon.

Rewards

Keeping the Java Ecosystem Safe.

Using the GitHub search functionality for filename:gradle-wrapper.jar returns 2.55 million results. Additionally, Gradle is the official build tool for the Android Ecosystem.

Having good tooling support around Gradle from GitHub and Dependabot would protect developers, corperations, and Android users around the world.

JLLeitschuh commented 5 years ago

Gradle also has a Dependency Lock File, although it's not enabled by default and many projects still don't take advantage of it.

https://docs.gradle.org/current/userguide/dependency_locking.html

sschuberth commented 5 years ago

Maybe there's a way for Dependabot to leverage (code from) the OSS Review Toolkit's analyzer, which already uses the Gradle Tooling API to determine dependencies (and it supports several other package managers, too).

JLLeitschuh commented 5 years ago

Would this issue be more appropriate if it had been opened against the Dependabot Feedback Repo?

If it is, feel free to move this issue there.

https://github.com/dependabot/feedback

greysteil commented 5 years ago

Nope, here is the right place for it, I've just been super busy with the GitHub announcement (sorry).

I'm super 👍 on thus, but making the switch is going to require some serious work on our side.

On the risks above:

Basically I think the above is entirely do-able, but to do it needs someone who has (or wants to acquire) deep knowledge of Gradle. I can't be that person myself.

We haven't done any formal planning of what the team will look like on Dependabot going forward, wether we're hiring, etc., but it was always my intention to eventually have someone dedicated to Maven and Gradle support. If we can't do that internally I'll make sure it's as easy as possible for someone from the community to do it (but I'll push for us to do it internally).

JLLeitschuh commented 5 years ago

Hi @greysteil,

I've just been super busy with the GitHub announcement (sorry).

Don't worry about it. Congratulations by the way! This is awesome news!

We don't do this at file fetching time, and need to use regex parsing to figure out which dependent files to pull down (we don't clone your repo either, so that doing that code evaluation won't leak it).

So, it sounds like you only want dependabot to check out the minimum number of files required to actually do the evaluation correct? This sounds like it's fraught with peril as it can be difficult to statically determine what files are relevant for a Gradle build's execution.

A potential workaround would be to allow the user to specify additional custom files that they need dependabot to check out in order for the build to operate successfully.

but it was always my intention to eventually have someone dedicated to Maven and Gradle support. If we can't do that internally I'll make sure it's as easy as possible for someone from the community to do it (but I'll push for us to do it internally).

I'm about to become a formal member of the Gradle team myself. There is a general interest in exploring how we can improve the software supply chain security of the JVM ecosystem. Although I can't commit any time to this project yet, I'm interested in trying to accrue the information we need to make a ballpark estimate of what kind of time/resources would be required to pull this off.


As an aside, what mechanism/project drives the GitHub dependency graph (dependabot example) feature? I feel like adding proper Gradle support to that is an important first step in proper dependency security vulnerability detection that dependabot needs in order to even consider offering 'update' support.

Would this discussion need to be with an internal GitHub team if we wanted to integrate this feature at that level?

greysteil commented 5 years ago

So, it sounds like you only want dependabot to check out the minimum number of files required to actually do the evaluation correct? This sounds like it's fraught with peril

Yep, fraught with difficulty! For now we think the safest way to ensure nothing can be stolen when executing unsafe code is to have nothing worth stealing accessible to that code, though.

I'm interested in trying to accrue the information we need to make a ballpark estimate of what kind of time/resources would be required to pull this off.

Let's talk! Things are hectic at the moment as myself and the Dependabot team integrate with GitHub, but once things settle I'd love to chat.

As an aside, what mechanism/project drives the GitHub dependency graph

It's not Dependabot yet, but we think we have a big role to play there, and support for Gradle is high up the list of priorities for dependency graph. We should definitely chat about that one too - let me get back to you.

JLLeitschuh commented 5 years ago

For now we think the safest way to ensure nothing can be stolen when executing unsafe code is to have nothing worth stealing accessible to that code, though.

Sounds like a very sane security model.

What's the downside of just checking out the entire repository and allowing dependabot to operate with the whole codebase? Is there a concern about the size of the repository that is being checked out? I understand that you don't want to checkout a python repository and try to parse it as a Gradle project because that's a waste of CPU cycles.

Things are hectic at the moment as myself and the Dependabot team integrate with GitHub, but once things settle I'd love to chat.

I don't formally start with Gradle until June 17th. But we can have discussions as you become available.

You can also find me and the rest of the Gradle team in the Gradle Community Slack Channel here: https://is.gd/xPCSJh

Looking forward to chatting more about this soon!

greysteil commented 5 years ago

What's the downside of just checking out the entire repository and allowing dependabot to operate with the whole codebase?

Just that that would require us to have to whole codebase in the insecure environment, and we wouldn't want folks to be able to steal it. That's us being super cautious, though - CI has exactly the same issues and obviously clones the whole repo...

Looking forward to chatting more about this soon!

Yes! I've joined the community channel so I'm always available there, and will get in touch once things settle at GitHub. Feel free to use me as your point of contact for finding the right person at GitHub on anything / everything, too, and I'll do my best.

JLLeitschuh commented 5 years ago

Some additional details from one of our internal discussion threads. Thanks to @melix who I'm quoting from below:

Gradle source files are code. Dependencies can be added in very different ways (build scripts, plugins, ...) and there's no pattern how to add them (you can add extension methods to declare dependencies, you can rely on ext.something for the version number, ....)

Then even if you had a way to do [reliable parsing], you'd get a wrong answer. Whatever is declared is not what is resolved. So it's not because you declare a dependency on org:foo:1.0 that you don't have a vulnerability; you could actually resolve to org:foo:1.1 which is vulnerable. Or you could bring org:bar:1.3 which would also be vulnerable. This is why such tools should always rely on the resolution result instead of what's declared in the code.


TL;DR: The only correct way to get the true dependency information out of a Gradle build is to use the resolution results. The easiest way to do this is to utilize the Gradle Tooling API.

CC: @jhutchings1

apapia commented 5 years ago

One alternative to consider is supporting updates to lock files using this feature: https://docs.gradle.org/current/userguide/dependency_locking.html

The lockfiles are already "resolved" and in a machine readable format so they would be easier to update automatically without necessary needing to use the Gradle Tooling API. There may be limitations to this approach but I think it would be a lot easier to implement. Generally if you want to keep your dependencies up-to-date using dynamic versions + dependency locking has been a really effective strategy.

JLLeitschuh commented 5 years ago

@apapia Unfortunately, this would only work for newer versions of Gradle, and we'd have to start enabling dependency locking by default.

Currently, there are over 2 million Gradle projects on GitHub (that are public) we wouldn't want to leave those projects behind when implementing this feature.

msridhar commented 5 years ago

One question here. Using the Gradle Tooling API seems like a great way to accurately detect dependencies for a Gradle project. But when a dependency is out of date, there is still the problem of generating a pull request to update the dependency. AFAIK, the Tooling API would not help with that, and it seems that it could be quite a challenge. Is there a plan for robustly generating pull requests to update Gradle dependencies?

JLLeitschuh commented 5 years ago

Unfortunately, I don't believe that we (Gradle) have a good solution for this right now. I do believe it's a problem we need to figure out how to resolve.

mnonnenmacher commented 5 years ago

The Gradle Versions Plugin could help with detecting newer versions. I believe you could apply it through the Tooling API on the fly.

ben-manes commented 4 years ago

Maybe you can evangelize to the Gradle team to make this a built in task (like Maven's version plugin)? They are too comfortable having a plugin, which was fun to write in a weekend for Gradle 1.x, but I certainly thought they'd have bundled it by now.

dotCipher commented 3 years ago

Looks like this might have been solved from https://github.com/dependabot/dependabot-core/pull/2680 ?

sschuberth commented 3 years ago

No, #2680 "just" implements static parsing of .kts files via regexes. But this issue is about using a (build script language agnostic) way of actually semantically understanding the build logic and getting the dependencies, taking into account things like version conflict resolution etc. which you do not get when just parsing build files. If you need correctness on that level, I recommend to take a look at ORT's analyzer (disclaimer, I'm the founder of the ORT project).

dotCipher commented 3 years ago

Fair, there are many ways to describe versions outside of the build.gradle.kts file for a dependency, so it wouldn't be trivial to do

JLLeitschuh commented 3 years ago

Fair, there are many ways to describe versions outside of the build.gradle.kts file for a dependency, so it wouldn't be trivial to do

This is very true. We, Gradle, have some active internal discussions going on around this and are working towards solutions to make improvements in this area.

huehnerlady commented 3 years ago

is there an update on this?

dinomite commented 3 years ago

I'm interested in putting some effort into this—are there tips on where to start or even groundwork-laying that would be helpful?

sschuberth commented 3 years ago

See my comment above, @dinomite. You might want to start with looking at existing similar solutions, like the ORT analyzer, and in particular our init.gradle that we inject into a build for getting its dependencies. Also, you might want to have a look at Gradle plugins that determine outdated dependencies, like https://github.com/ben-manes/gradle-versions-plugin or https://github.com/jmfayard/refreshVersions.

yogurtearl commented 3 years ago

https://github.com/autonomousapps/dependency-analysis-android-gradle-plugin is also a good reference.

simondean commented 3 years ago

Hi. I don't know if it'll help but here's a static analyser I wrote for Gradle build scripts.

https://github.com/kronicle-tech/kronicle/tree/main/service/src/main/java/tech/kronicle/service/scanners/gradle

It's part of a new open source project called Kronicle at the moment but it could be fairly easy to extract it into an independent Java library. It doesn't really have any hard dependencies on the codebase it's part of.

Here's a couple of examples of the output of the code:

Those are webpages displaying the dependency information for a couple of codebases. You can see the same thing in JSON form here:

I found writing a static analyser is a lot more complex than using something like Gradle Tooling API but it does have advantages like not having use a secure sandbox due to execution of arbitrary code in Gradle plugins and Gradle build scripts when loading a Gradle codebase "for real" with something like Gradle Tooling API.

At the moment, this code supports build.gradle files (Groovy) but not build.gradle.kts files (Kotlin script).

The analyser has to specifically support/detect codebases that use the Spring Dependency plugin, Spring Boot plugin, Micronaut Application plugin or Micronaut Library plugin, as those Gradle plugins change the dependency behaviour of Gradle (e.g. implicitly adding a BOM/platform dependency to a codebase).

jurre commented 3 years ago

Hi. I don't know if it'll help but here's a static analyser I wrote for Gradle build scripts.

https://github.com/kronicle-tech/kronicle/tree/main/service/src/main/java/tech/kronicle/service/scanners/gradle

This looks super promising, thanks for sharing that @simondean!

JLLeitschuh commented 3 years ago

Hi Everyone,

After several years of discussion on this issue I'm actively working on a POC for this feature that will hopefully become the fully implemented solution. There are two parts:

  1. The extraction of dependencies (covered in this issue) which I'm actively discussing with GitHub. As discussed at GitHub Universe by Grey Barker, the goal here is to enable support for Dependabot to extract dependencies in a standardized format.
  2. Improving how Dependabot and similar tools can tell Gradle to update dependencies. IE. Communicating to Gradle "hey this version of a dependency has a vulnerability, please don't use it".

The proposal below discusses part 2 of this problem.

Note: Because of how Gradle's Google Drive infrastructure is setup, you'll need to request access to the document to read it, unfortunately, I can't just make the doc public. I'll give access to anyone who requests it as soon as I see the request.

bcmedeiros commented 2 years ago

I like the idea of the constraints.xml, but I think its current form does not cover something that is very common when there is a patch release, which is the patch being applied to many branches. E.g a library could be currently on version 4.1.3, and when a security issue is fixed, it's realeased on 4.1.4, but they also backport it to 3.5.6 and 2.2.3, for example. When that happens, we have multiple "good versions". We would need something like this:

<?xml version="1.0"?>
<constraints>
    <constraint>
        <group>junit</group>
        <name>junit</name>
        <inRange>[4.0,5.0[</inRange>
        <lowest-known-safe>4.13</lowest-known-safe>
        <rejected>
            <reject>[4.7,4.13]</reject>
        </rejected>
        <because>CVE-2020-15250: TemporaryFolder on unix-like systems does not limit access to created files</because>
    </constraint>
    <constraint>
        <group>junit</group>
        <name>junit</name>
        <inRange>[0,4.0[</inRange>
        <lowest-known-safe>3.2.2</lowest-known-safe>
        <rejected>
            <reject>[0,3.2.1]</reject>
        </rejected>
        <because>CVE-2020-15250: TemporaryFolder on unix-like systems does not limit access to created files</because>
    </constraint>
</constraints>
yogurtearl commented 2 years ago

Why XML for the constraints file? Gradle metadata is JSON, Version catalogs are TOML... seems surprising to make the the constraints file would be XML... can we use TOML or JSON? or some other file format that is already gradle native?

JLLeitschuh commented 2 years ago

When that happens, we have multiple "good versions".

I agree this is indeed a problem. Currently it's "out of scope" and will require manual intervention to update your build by hand. This is a case of, supporting the majority use-case is better than nothing at all. There are likely several variations of this same problem and trying to decide what is "correct" in each of these cases most likely requires a build maintainer to make an informed decision.

The suggestion we offer to tooling authors looking to modify this constraints file would be that they should look at the safe versions and pick the lowest safe version above all existing dependency requests that are not vulnerable.

As an example: Project A depends upon JUnit 3.9, Project B depends upon JUnit 4.12, Project C depends upon 4.13.2. A vulnerability is discovered in [4.7,4.13]. The added constraint should reject [4.7,4.13] and suggest 4.13.1. As such, Project A and Project B would both be updated to 4.13.1 and Project C would stay on 4.13.2. If the build author really doesn't want to update Project A, they can step in and make the modifications to the build themselves instead of accepting the Dependabot PR.

Unfortunately, due to the current limitations of the Gradle dependency engine and the constraints infrastructure, the highest version available will always be picked. There may be ways to improve this user experience in the future, but at least for the first pass implementation, this is the way we plan to support it.

yogurtearl commented 2 years ago

Another related use case:

I would like to have automation to be able to "bisect" versions of each component to figure out what is the highest version (not on the denylist) where the tests/CI build still passes.

I.e. have a bot that tries to build with highest version and if that doesn't work tries with current plus one, and then binary searches for the highest version where the build/tests still pass.

Should I file a separate issue for that?

JLLeitschuh commented 2 years ago

JLLeitschuh closed this now

Oops 😆

Why XML for the constraints file?

TOML was chosen for the version catalog feature because it needed to be modified by the end user manually. We wanted a friendly language for this use case. On the other hand, the Gradle Verification Metadata is using XML. This is because this file is both written and read by Gradle, it's not really designed to be modified by hand very often. Similarly, this constraints file will be mostly interacted with by automated tooling. In theory, we could also publish a small stand-alone application to make writing additional constraints to this file easier. At the end of the day, this file needs to be easy for someone to review in a PR, but not necessarily something we envisioned end-users modify much on their own.

At the end of the day, I don't particularly care what format the file takes. If someone has a really compelling use-case for another format, please feel free to provide it. The only major downside I see for XML is that most parsers are vulnerable to the External Entity Processing (XXE) vulnerability by default. Other than that, I'm impartial.

JLLeitschuh commented 2 years ago

I would like to have automation to be able to "bisect" versions of each component to figure out what is the highest version (not on the denylist) where the tests/CI build still passes.

Sounds like a valid use case, and something this file could support as a place to put these "bisect" versions you'd like to tests. However, it sounds like it's potentially outside the scope of this feature proposal in Gradle and how Dependabot interacts with it IMHO.

yogurtearl commented 2 years ago

as another data point, Gradle Module Metadata is JSON. :)

Would be nice to have a consistent approach and design guidelines in gradle for to choosing XML, TOML, JSON, etc. for this and future features of gradle.

Would be nice to have to deal with fewer file formats in general when interacting with gradle builds. All apps tend to have a JSON parser for some purpose already, while more recent app might not otherwise have a need for XML support.

Kotlin Serialization supports JSON, but not XML out of the box, so dealing with JSON in a multiplatform kotlin project would be better supported.

melix commented 2 years ago

There are reasons for the different file formats, depending on whether they are intended to be consumed by humans or machines, or whether they are intended to be modified at all. You can read about the rationale for choosing TOML for the catalog here.

JLLeitschuh commented 2 years ago

I've gotten a lot of feedback requesting that this feature support JSON instead of XML. As such, I've drafted up a JSON schema proposal for this file. I'd like to do some testing and ensure that I can still get reasonable (ie. user friendly and actionable) error messages out of the schema validator before committing to it. Currently, the XML parser I wrote was based upon the SAX parse that @melix developed for Dependency Verification, which produces very clear error messages when the file is malformed. I'm hoping I can get similarly user-friendly error messages with this implementation as well.

https://github.com/gradle/gradle-dependency-constrain/pull/1/files#diff-1a57b02c313c3a4348c2018e4d7a034eca54377ce7fb67b95d2c27d3f1f65b16

cw-alexcroteau commented 2 years ago

I know that the Gradle dependency constraint file is still a WIP, but would it be worth it to start working on integration with dependabot-core? I think that we could start implementing the support for dependency constraints based on the currently-open PR for dependency-constraints-schema.json even if it is not final, and keep up with it. I don't think that major structural changes will happen from know on, and there is quite a bit of work to be done to support it.

I'd be glad to start working on this, except if there is a private initiative currently ongoing by the core team. I have an interest in having Gradle support for dependabot in terms of security updates, so if I can help to make things go forward I'll do it.

JLLeitschuh commented 2 years ago

I'd say go for it. Even a spike that does discovery work to figure out if Dependabot has the right information to generate this file would be valuable. If you are able to capture what you learn and can determine what's missing in Dependabot currently, thst would be super useful.

ben-manes commented 2 years ago

Part 1 involves getting the dependency information out of Gradle in a format that GitHub can understand. That is out of scope for this document.

@JLLeitschuh can you provide details if "Part 1" has been thought through? I am excited to see a richer ecosystem emerge, especially if the next generation of tooling will subsumes the gradle-versions-plugin.

JLLeitschuh commented 2 years ago

@JLLeitschuh can you provide details if "Part 1" has been thought through? I am excited to see a richer ecosystem emerge, especially if the next generation of tooling will subsumes the gradle-versions-plugin.

So, currently, the plan is to build some tooling that will extract the dependencies from a Gradle Build using an init-script plugin will automatically added when a build leverages the gradle/gradle-build-action. GitHub is planning on adding a new API where, similar to CodeQL scanning, a build that has just been built can upload a dependency graph report. This will allow the GitHub Dependency Graph to become aware of dependencies that it wasn't previously aware of. The GitHub Dependency Graph is currently how Dependabot security alerts are generated. As such, as soon as this information is provided to GitHub and fed into the Dependency Graph infrastructure, Dependabot alerts that hadn't been previously generated because Gradle builds couldn't be understood by GitHub now will be.

I've asked @reiddraper if I can share the full details of the plan here with the rest of you all, including the currently proposed specification for the payload that tools like Gradle and others will be able to send to GitHub.

I'm currently in a time crunch trying to get Part 2 in a solid state, and I'm working on Part 1 when Part 2 is stalled on other work. I'll post a link to the GitHub repository for Part 1 when I have a little bit more working.

Currently, the API to send the Dependency Graph Report to doesn't exist at GitHub, so currently the file is just written to disk.

Also, before people jump on the topic: allowing multiple Dependency Graph Reports to be uploaded for a single commit has been discussed. This is indeed the plan. As such, if you have different dependencies for, as an example, MacOS and Linux, both of those dependencies will be reflected in the GitHub dependency graph.

JLLeitschuh commented 2 years ago

@reiddraper gave me approval to share the proposed specification document here. For those curious, feel free to take a look: https://docs.google.com/document/d/1TjxJJwgPavw-TFzK3110iH-CWstgdcVdb2JYiRy2GVs/edit?usp=sharing

ben-manes commented 2 years ago

Do you foresee including packages like Gradle’s version and embedded platform tools such as pmd or jacoco? These are not project configuration dependencies in the normal sense, but equally important to maintain up to date.

JLLeitschuh commented 2 years ago

Do you foresee including packages like Gradle’s version and embedded platform tools such as pmd or jacoco? These are not project configuration dependencies in the normal sense, but equally important to maintain up to date.

Yes, similar to build scans, all configurations that are resolved during the build will be set to GitHub. Similarly, the dependency-constraints.json will impact all resolve dependencies when implemented as a core feature in Gradle.

florianmutter commented 1 year ago

Is there an update on this?

nsoft commented 1 year ago

My $0.02 : Break this in two. Get the useful notifications of dependency issues out there. Make a second project out of generating pull requests. The first bit should be possible via parsing gradle dependencies (or api equivalent) for runtime/provided configs. WRT security and dependencies, knowing the problem exists is substantially more than half the battle.

ben-manes commented 1 year ago

@nsoft as a workaround, I use gradle-dependency-submission to push the dependency graph into Github, which parse the dependencies task as you suggested. This allows for security alerts and perhaps version alerts but I don't use that (since it cannot update the build files). I use (and wrote) the gradle-versions-plugin so I am used to that flow, and others have written extensions like gradle-update-checker for a github action and notification. Just an fyi if helpful until there is native support by gradle/github.

bcmedeiros commented 1 year ago

Break this in two.

@nsoft they know that, but I'm pretty sure that is some non-public reason for this delay.

Notifying flawed dependencies is clearly the best value/cost ratio, yet for some reason it seems it's not going this way.

pioterj commented 1 year ago

The Gradle Build Tool team is working on this now. See the related issue on our public roadmap: https://github.com/gradle/build-tool-roadmap/issues/42 cc @bigdaz

jeffwidman commented 1 year ago

@pioterj @bigdaz if there's anything we can do to help, please let us know.

My email is in my profile if you want to have a call about ways to have a clean interface between native Gradle and Dependabot. The general topic of interfaces between Dependabot and native helpers is something we've spent some time thinking about.

And we're very interested in leveraging native Gradle... so many ways it'd be better than our current approach of re-implementing Gradle in Ruby, but poorly.

JLLeitschuh commented 1 year ago

if there's anything we can do to help, please let us know.

Source for the dependency extractor Gradle plugin can be found here:

If you're willing to work with a beta plugin in your build, you can give it a try, but the API is unstable, and it may break your build.

Eventually, it should end up as a native feature built into the https://github.com/gradle/gradle-build-action GitHub action. Once support has been added, as long as your build has the GitHub action, you will get support automatically. I have no idea what the timeline on that will be though.

JLLeitschuh commented 1 year ago

Anyone who is interested in giving the plugin a try, it's currently in a pre-release state:

https://github.com/gradle/github-dependency-graph-gradle-plugin/releases/tag/v0.0.2

You can find it on the Gradle Plugin Portal here:

https://plugins.gradle.org/plugin/org.gradle.github-dependency-graph-gradle-plugin

Two things: