For the complete documentation index, see llms.txt.

Migrating a Java project to Chainguard Libraries

How to migrate an existing Java project to pull dependencies from Chainguard Libraries
  10 min read

Chainguard Libraries for Java provides a curated repository of packages rebuilt from upstream sources and scanned for malware. Because Chainguard Libraries uses the standard Maven repository format, switching an existing project requires only a repository configuration change — no changes to your application code or dependency versions.

This guide walks through migrating an existing Java project to Chainguard Libraries, covering the two most common setups:

  • Direct access — your build tool connects directly to libraries.cgr.dev. This option is faster for initial evaluation and smaller-scale setups.
  • Repository manager — your build tool connects to a repository manager (Cloudsmith, Google Artifact Registry, JFrog Artifactory, or Sonatype Nexus), which proxies requests to Chainguard Libraries.

Prerequisites

Before you begin, you need:

Create an entitlement

You must have an entitlement to Chainguard Libraries for Java with upstream fallback enabled.

To create an entitlement to Chainguard Libraries for Java and enable upstream fallback, which includes a default 7-day cooldown, run the following command:

chainctl libraries entitlements create --ecosystems=JAVA --policy=CHAINGUARD_AND_UPSTREAM

Alternatively, you can create an entitlement in the Chainguard Console: while viewing the Java ecosystem page, follow the prompts to create an access token.

You can also configure cooldown policies after you create the entitlement. For example, to create and enforce a policy that disables the cooldown:

chainctl libraries policy create --name=java-disable-cooldown --cooldown-days=0
chainctl libraries policy enable --policy=java-disable-cooldown --ecosystem=JAVA --mode=ENFORCE

It can take up to 30 minutes for the fallback and cooldown policies to take effect. Learn more about cooldown and other policies in the Chainguard Libraries Access documentation.

Note: If you choose to manage your own fallback to upstream repositories, see the following docs pages for more information: Build configuration for direct access instructions or Global configuration for repo manager instructions. Note that configuring a public fallback bypasses the protections provided by Chainguard.

Step 1: Confirm your baseline build

Before making any changes, confirm your project builds cleanly against Maven Central.

cd your-project
./mvnw install

All dependencies should download from Central and tests should pass. This gives you a baseline to compare against after migration.

Step 2: Generate a pull token

You must be an Owner or have the libraries.java.pull_token_creator permission to create a pull token. You can create a pull token in the Chainguard Console, or via chainctl.

The following command creates the token and populates environment variables directly. Make sure to replace example.org with your own Chainguard org name:

eval $(chainctl auth pull-token --parent=example.org --repository=java --name=my-java-token --output=env)

This results in values for the CHAINGUARD_JAVA_IDENTITY_ID and CHAINGUARD_JAVA_TOKEN variables. The token is named my-java-token, with a default expiration of 30 days. To configure the expiration, use the --ttl flag.

Learn more about command options in the chainctl documentation.

When configuring direct access, note that environment variables do not persist between terminal sessions. You must re-export them each time you open a new terminal, or add them to your shell profile. Learn more about pull tokens in the Access documentation.

Do not commit credentials to version control

The Gradle build.gradle file and the Maven pom.xml are typically committed to a repository — always use environment variables for credentials rather than hardcoding token values directly in the file. Maven credentials live in ~/.m2/settings.xml, which is outside the project directory and not committed by default, but take care not to add it to your repository. Store tokens as CI secrets referenced via environment variables instead. If you accidentally commit credentials, delete the exposed token.

For more secure credential management, consider using a secrets manager such as 1Password CLI or Bitwarden, which can dynamically inject environment variables at runtime without storing token values in shell profiles or env files.

Verify your setup

Run the following command for a connectivity and authentication check:

curl -u "$CHAINGUARD_JAVA_IDENTITY_ID:$CHAINGUARD_JAVA_TOKEN" \
  https://libraries.cgr.dev/java/

The command returns an HTML page listing repository directories. If credentials are invalid or expired, the command returns a 403 error instead of the directory listing.

Step 3: Configure repository access

The https://libraries.cgr.dev/java/ endpoint is also the Chainguard Repository endpoint for Java. By default, it serves only Chainguard-built artifacts. When upstream fallback is enabled for your organization, the same endpoint can also serve requested versions from Maven Central under Chainguard security controls.

Direct access

Maven repository and credentials configuration lives in a settings.xml file. For a project-local setup, place this file in the .mvn folder of your project and pass -s .mvn/settings.xml when running Maven commands.

First, create a .mvn directory if it doesn’t already exist:

mkdir -p .mvn

Next, create a .mvn/settings.xml file with the following content. This configuration sets the Chainguard remediated repository as the first source, followed by the standard Chainguard repository, with Maven Central set as invalid to avoid accidental unintended fallback to the public repository:

<settings>
  <servers>
    <server>
      <id>chainguard-remediated</id>
      <username>${env.CHAINGUARD_JAVA_IDENTITY_ID}</username>
      <password>${env.CHAINGUARD_JAVA_TOKEN}</password>
    </server>
    <server>
      <id>chainguard</id>
      <username>${env.CHAINGUARD_JAVA_IDENTITY_ID}</username>
      <password>${env.CHAINGUARD_JAVA_TOKEN}</password>
    </server>
  </servers>

  <profiles>
    <profile>
      <id>chainguard</id>
      <repositories>
        <repository>
          <id>chainguard-remediated</id>
          <url>https://libraries.cgr.dev/java-remediated/</url>
          <releases><enabled>true</enabled></releases>
          <snapshots><enabled>false</enabled></snapshots>
        </repository>
        <repository>
          <id>chainguard</id>
          <url>https://libraries.cgr.dev/java/</url>
          <releases><enabled>true</enabled></releases>
          <snapshots><enabled>false</enabled></snapshots>
        </repository>
        <repository>
          <id>central</id>
          <url>https://invalid</url>
          <releases><enabled>true</enabled></releases>
          <snapshots><enabled>false</enabled></snapshots>
        </repository>
      </repositories>

      <pluginRepositories>
        <pluginRepository>
          <id>chainguard-remediated</id>
          <url>https://libraries.cgr.dev/java-remediated/</url>
          <releases><enabled>true</enabled></releases>
          <snapshots><enabled>false</enabled></snapshots>
        </pluginRepository>
        <pluginRepository>
          <id>chainguard</id>
          <url>https://libraries.cgr.dev/java/</url>
          <releases><enabled>true</enabled></releases>
          <snapshots><enabled>false</enabled></snapshots>
        </pluginRepository>
        <pluginRepository>
          <id>central</id>
          <url>https://invalid</url>
          <releases><enabled>true</enabled></releases>
          <snapshots><enabled>false</enabled></snapshots>
        </pluginRepository>
      </pluginRepositories>

    </profile>
  </profiles>
  <activeProfiles>
    <activeProfile>chainguard</activeProfile>
  </activeProfiles>
</settings>

Repository manager

If your organization uses a repository manager, configure it to use Chainguard Libraries as an upstream source first. Follow the global configuration documentation for your repository manager.

Once configured, point your build tool at your repository manager URL. In this setup, the credentials your build tool uses are your repository manager credentials — not a Chainguard pull token.

Create or update ~/.m2/settings.xml to point Maven at your repository manager and override Central with invalid URLs. See example settings files in Chainguard’s demo repository on GitHub for different repository managers.

Use a configuration similar to the following. Make sure to update the credentials in the server section to use your repository manager account credentials, using environment variables when possible. This example uses environment variables for Artifactory credentials:

<settings>

  <mirrors>
    <mirror>
      <!-- Set the identifier for the server credentials for repository manager access
      must match server name in "servers" -->
      <id>example</id>
      <!-- Send all requests to the repository manager URL -->
      <mirrorOf>*</mirrorOf>
      <!-- Ordered repository group with
        - java-remediated
        - java
        - Maven central
        - anything else needed, including internal repos
      -->
      <!--<url>https://repo.example.com:8443/repository/java-all/</url>-->
      <url>http://localhost:8081/repository/java-all/</url>
    </mirror>
  </mirrors>

  <!-- Activate repo manager and override central repo from Maven itself with invalid URLs -->
  <activeProfiles>
    <activeProfile>repo-manager</activeProfile>
  </activeProfiles>
  <profiles>
    <profile>
      <id>repo-manager</id>
      <repositories>
        <repository>
          <id>central</id>
          <url>http://central</url>
          <releases>
            <enabled>true</enabled>
          </releases>
          <snapshots>
            <enabled>true</enabled>
          </snapshots>
        </repository>
      </repositories>
      <pluginRepositories>
        <pluginRepository>
          <id>central</id>
          <url>http://central</url>
          <releases>
            <enabled>true</enabled>
          </releases>
          <snapshots>
            <enabled>true</enabled>
          </snapshots>
        </pluginRepository>
      </pluginRepositories>
    </profile>
  </profiles>

  <servers>
    <server>
      <id>repo-manager</id>
      <username>${env.ARTIFACTORY_USERNAME}</username>
      <password>{env.ARTIFACTORY_PASSWORD}</password>
    </server>
  </servers>
</settings>

Replace https://repo.example.com/java-all/ with your repo manager’s virtual repository URL, and update the username and password.

Step 4: Refresh dependencies

To force re-resolution from Chainguard, you can clear local caches or clear only relevant artifacts.

Remove local cache:

rm -rf ~/.m2/repository

Remove specific artifact:

rm -rf ~/.m2/repository/<group>/<artifact>

Step 5: Build the project

Run a full build and capture the output.

cd your-project
./mvnw install 2>&1 | tee /tmp/mvn-output.txt

To check which repositories served completed downloads:

grep "Downloaded from" /tmp/mvn-output.txt

All downloads should come from chainguard or chainguard-remediated.

Look for lines beginning with Downloaded from chainguard: or Downloaded from chainguard-remediated: to confirm artifacts are being served by Chainguard.

If all artifacts download from Central, your credentials may be invalid or expired. Regenerate your pull token, re-export the pull token credentials as environment variables, then clear the cache and rebuild.

Step 6: Verify artifacts

To check whether a specific artifact was built by Chainguard, use chainctl libraries verify /full/path/to/artifact.jar. Verify artifacts immediately after a clean build, before any repackaging.

To list all downloaded JARs:

find ~/.m2/repository -name "*.jar"

Pick any JAR from the output to verify. For example:

chainctl libraries verify \
  ~/.m2/repository/org/apache/commons/commons-lang3/3.13.0/commons-lang3-3.13.0.jar

A checksum mismatch means the artifact came from Central rather than Chainguard. This can happen if the artifact was cached from a previous build. To resolve, delete the specific artifact and re-download it:

rm ~/.m2/repository/org/apache/commons/commons-lang3/3.13.0/commons-lang3-3.13.0.jar
./mvnw dependency:get -Dartifact=org.apache.commons:commons-lang3:3.13.0

Then run chainctl libraries verify again.

A successfully verified artifact produces output similar to:

Artifact: /path/to/artifact.jar
Verification Coverage: 100.00%

Last updated: 2026-07-02 00:00