Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.root.io/llms.txt

Use this file to discover all available pages before exploring further.

The Root.io Gradle Plugin intercepts dependency resolution and transparently substitutes vulnerable dependencies with Root-patched versions from pkg.root.io/maven/. You declare the versions you know, and the plugin handles the rest—no changes to your dependency declarations required.

Root.io Gradle Plugin

View the source code, report issues, or contribute to the Root.io Gradle Plugin.

Prerequisites

Installation

The plugin is published to the Gradle Plugin Portal. Apply the plugin in build.gradle.kts:
plugins {
    id("io.root.patcher") version "0.2.0"
}
If your pluginManagement block explicitly lists repositories, make sure gradlePluginPortal() is included:
pluginManagement {
    repositories {
        gradlePluginPortal()
    }
}

Option 2: Root.io Maven Repository

Add the Root.io Gradle Plugin repository to settings.gradle.kts:
pluginManagement {
    repositories {
        maven {
            url = uri("https://pkg.root.io/gradle-plugins")
            credentials {
                username = "token"
                password = providers.environmentVariable("ROOTIO_API_KEY").get()
            }
        }
        gradlePluginPortal()
    }
}
Apply the plugin in build.gradle.kts:
plugins {
    id("io.root.patcher") version "0.2.0"
}

Option 3: Local Maven Repository

For testing or air-gapped environments:
cd rootio_gradle_plugin/
make publish-local
Then add mavenLocal() to your pluginManagement repositories:
pluginManagement {
    repositories {
        mavenLocal()
        gradlePluginPortal()
    }
}

Option 4: Private JFrog Artifactory

Publish and consume the plugin through your own JFrog Artifactory instance - useful when you need full control over the registry or want to keep builds air-gapped from the public internet.

Publishing

Set the following environment variables and run make publish:
export ARTIFACTORY_URL=https://your-instance.jfrog.io/artifactory/your-repo
export ARTIFACTORY_USER=your-username
export ARTIFACTORY_PASSWORD=your-api-key
make publish
This publishes both the plugin JAR and the Gradle plugin marker artifact (io.root.patcher:io.root.patcher.gradle.plugin) that Gradle requires for plugins {} block resolution.

Consuming

Add the Artifactory repository to pluginManagement in your settings.gradle.kts:
pluginManagement {
    repositories {
        maven {
            url = uri("https://your-instance.jfrog.io/artifactory/your-repo")
            credentials {
                username = providers.environmentVariable("JFROG_USERNAME").orNull
                password = providers.environmentVariable("JFROG_TOKEN").orNull
            }
        }
    }
}
Then apply the plugin as usual in build.gradle.kts:
plugins {
    id("io.root.patcher") version "0.2.0"
}

Using JFrog as a Proxy for pkg.root.io

If your organization routes all artifact traffic through an internal proxy, you can also point the plugin at your JFrog instance for resolving patched artifacts - instead of reaching pkg.root.io directly. In JFrog, create a remote Maven repository with the remote URL set to https://pkg.root.io/maven and configure your Root.io API key as the upstream password. JFrog will handle authentication to pkg.root.io on behalf of your builds - individual developers never need a Root.io API key. In your build.gradle.kts, override pkgUrl and supply JFrog credentials via pkgUsername/pkgPassword:
rootio {
    pkgUrl.set("https://your-instance.jfrog.io/artifactory/your-remote-repo")
    pkgUsername.set(providers.environmentVariable("JFROG_USERNAME").get())
    pkgPassword.set(providers.environmentVariable("JFROG_TOKEN").get())
}
pkgUsername/pkgPassword control only where patched artifacts are downloaded from, not where the plugin itself is resolved.

How It Works

When you run a build, the plugin will:
  1. Query Root.io API for patches on your declared dependencies
  2. Substitute patched versions if available
  3. Register pkg.root.io/maven/ as a Maven repository
  4. Cache results locally at .gradle/rootio-cache/

Configuration

Configure the plugin in build.gradle.kts:
rootio {
    apiKey.set("your-api-key-here")  // Optional if using env vars
    apiUrl.set("https://api.root.io")  // Default
    pkgUrl.set("https://pkg.root.io/maven")  // Default; override to use a proxy
    pkgUsername.set("...")  // Optional; overrides apiKey for pkg repo auth
    pkgPassword.set("...")  // Optional; overrides apiKey for pkg repo auth
    ttlHours.set(24)  // Cache TTL (0 = no cache)
    maxRetries.set(3)  // Max retry attempts
    retryBaseDelayMs.set(1000)  // Exponential backoff base
    allowInsecurePkgRepo.set(false)  // Allow HTTP (test only)
}

Configuration Properties

PropertyDefaultDescription
apiKey-Root.io API key (see API Key Resolution). Also used as a fallback password for the default pkg.root.io Maven repository when pkgUsername/pkgPassword are not set.
apiUrlhttps://api.root.ioRoot.io API base URL
pkgUrlhttps://pkg.root.io/mavenMaven repository URL from which patched artifacts are resolved. Override this when routing through a proxy (see Option 4).
pkgUsername-Username for the pkg Maven repository. When set together with pkgPassword, takes precedence over apiKey for repository authentication.
pkgPassword-Password for the pkg Maven repository. When set together with pkgUsername, takes precedence over apiKey for repository authentication.
ttlHours24Cache TTL in hours (0 disables caching)
maxRetries3Max retry attempts for transient API failures
retryBaseDelayMs1000Base delay (ms) for exponential backoff
allowInsecurePkgRepofalseAllow plain HTTP for package repo (test/local only)

API Key Resolution

The plugin resolves the API key in this order (highest priority first):
  1. Build script: rootio { apiKey.set("...") }
  2. Environment variable: export ROOTIO_API_KEY=...
  3. JVM system property: systemProp.ROOTIO_API_KEY=... in ~/.gradle/gradle.properties
  4. .env file: ROOTIO_API_KEY=... in project root
Keep your API key out of source control. Use environment variables or JVM system properties for CI/CD.

Multi-Project Setup

Apply the plugin once at the root and propagate to all subprojects:
// Root build.gradle.kts
plugins {
    id("io.root.patcher") version "0.2.0" apply false
}

subprojects {
    apply(plugin = "io.root.patcher")

    repositories {
        mavenCentral()
    }
}

// app/build.gradle.kts
dependencies {
    implementation("io.netty:netty-all:4.1.42.Final")
}

// lib/build.gradle.kts
dependencies {
    implementation("commons-beanutils:commons-beanutils:1.9.3")
}
Run the build:
export ROOTIO_API_KEY="your-api-key-here"
./gradlew build
All subprojects will automatically use Root-patched dependencies.

Caching

The plugin caches Root.io API responses locally at .gradle/rootio-cache/ to avoid repeated network calls. The cache is not used when:
  • The cached response is older than the TTL (default: 24 hours)
  • ttlHours.set(0) is configured (caching disabled)
  • A dependency is queried for the first time
  • The cache directory has been manually cleared
To clear the cache:
rm -rf .gradle/rootio-cache/

Detailed Flow

  1. Plugin applies to your project and creates the rootio {} configuration extension
  2. API key resolution happens in priority order (build script → env var → system property → .env)
  3. Root.io Maven repository is registered automatically with credentials
  4. Resolution hooks are installed on every resolvable configuration
  5. For each dependency, the plugin:
    • Checks the local cache (.gradle/rootio-cache/) for a valid entry
    • If cache miss, queries Root.io API (/v3/analyze/maven) for patches
    • Substitutes the dependency coordinates if a patch is available
    • Logs the patching decision
  6. Gradle resolves the patched version from pkg.root.io/maven/

Troubleshooting

IssueSolution
401 Unauthorized from Root.io APIVerify ROOTIO_API_KEY is set correctly (see API Key Resolution)
404 Not Found for patched artifactConfirm the patched version exists in pkg.root.io/maven/ (check Root.io dashboard)
Plugin not applying patchesCheck Gradle console output for [Root.io] log messages. Ensure plugin is applied before dependencies are declared.
Network timeoutsIncrease retryBaseDelayMs and maxRetries in the rootio {} block
Cache is staleDelete .gradle/rootio-cache/ or set ttlHours.set(0) to disable caching
ResolutionStrategy conflictsRoot.io plugin uses eachDependency hooks. Ensure no other plugins conflict with dependency resolution.
Multi-project builds not patching subprojectsVerify apply(plugin = "io.root.patcher") is in the subprojects {} block
If you encounter issues, check the Gradle build output for [Root.io] prefixed log messages. Run with --info or --debug for detailed output: ./gradlew build --info