Quick guide to safelisting repository artifacts in Gradle 
Tags: gradle, android, jcenter, maven
Published: 2021-03-20 13:50:10

###The background

The typical `build.gradle` files list repositories in a way similar to this:
```Kotlin
repositories {
   google()
   mavenCentral()
}
```
This is a quick way to specify that dependencies we're using should be grabbed from one of the repositories above.


This approach has a few potential issues:
* Security, e.g: if a malicious actor placed a dependency impersonating the one we need, the script could download it and we wouldn't know. 
* Slowness: the script doesn't know the exact coordinates of each dependency and would be searching in each repository starting from the top one.

###A better way

A few years ago, Gradle added a functionality that allows to specify where each of the dependencies is precisely located.
These APIs include: `includeModule`, `includeGroup`, `includeGroupByRegex`.

The good news is that we can gradually migrate to these APIs and make the dependency resolution more secure and faster straight away.

###1st approach
The easiest way is to replace each repository with a set of `includeGroupByRegex` entries.

Let's imagine that our project is using Retrofit and OkHttp.

**Step 1:** Remove `mavenCentral()` from the repositories section.

**Step 2:** Force refresh dependencies in one of the following ways:
* sync the project,
* execute `./gradlew --refresh-dependencies`,
* run the app/tests,
* remove `.m2` & `.gradle/caches` folders from the machine

In Android Studio, we will see errors similar to these:
``` Shell
   > Could not find com.squareup.okhttp3:okhttp:3.12.1.
     Required by:
         project :app
   > Could not find com.squareup.okhttp3:okhttp-urlconnection:.
     Required by:
         project :app
   > Could not find com.squareup.retrofit2:retrofit:2.9.0.
```

**Step 3:** Notice that all these missing files have the same group id: `com.squareup`

**Step 4:** In place of `mavenCentral()`, add the below and refresh dependenices again (see step 2): 

```Kotlin
   mavenCentral {
      content {
         includeGroupByRegex("com.squareup.*")
      }
  }
```
**Step 5:** Continue the same way till every dependency has been safe-listed. Do the same for `google()`. 

We could stop at this stage. The dependency resolution is safer and faster.


###Going a bit further with `includeGroup`

`includeGroup` is a more precise version of `includeGroupByRegex`. 
 
Let's remove `includeGroupByRegex("com.squareup.*")` and inspect the errors again. We can see the group names. Let's use them and replace:
```Kotlin 
includeGroupByRegex("com.squareup.*")
```
with 
``` Kotlin
 includeGroup("com.squareup.retrofit2")
 includeGroup("com.squareup.okhttp3")
```

Repeat that for every `includeGroupByRegex`.

The dependency resolution is yet safer and faster. We could stop here. 


###An ultimate version - using: `includeModule`

Now, start removing each `includeGroup` one by one and inspect the errors again. The groups and modules names shown in the error console are all we need to use `includeModule()`. Let's use these and replace:
```Kotlin 
includeGroup("com.squareup.retrofit2")
```
with 
``` Kotlin
includeModule("com.squareup.retrofit2", "retrofit")
includeModule("com.squareup.retrofit2", "converter-gson")
includeModule("com.squareup.retrofit2", "retrofit-mock")
```

Repeat that for every `includeGroup`.
The resulting build script files will be quite large but we'll have full control over the repositories and what gets included in the app.

###Conclusion

We can migrate at our own pace. We can either jump right into using `includeModule` or gradually transition from general repositories to `includeGroupByRegex` to `includeGroup` and then finally `includeModule`.

We can also use a mix of the `include`s above. 

As long as we replace general repositories with a set of `include`s - our dependency resolution will be faster and safer. And we will know exactly what goes into our apps. 

Further reading:
* https://docs.gradle.org/5.1.1/userguide/declaring_repositories.html
* https://commonsware.com/blog/2021/02/20/using-repository-safelist-gradle.html
* https://jebware.com/blog/?p=573