32 KiB
Usage
- Selecting a Java distribution
- Installing custom Java package type
- Installing custom Java architecture
- Installing custom Java distribution from local file
- Testing against different Java distributions
- Testing against different platforms
- Publishing using Apache Maven
- Publishing using Gradle
- Hosted Tool Cache
- Modifying Maven Toolchains
- Java-version file
- Self-signed certificates and internal CAs (GitHub Enterprise)
See action.yml for more details on task inputs.
Selecting a Java distribution
Inputs java-version and distribution are mandatory and needs to be provided. See Supported distributions for a list of available options.
Eclipse Temurin
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '21'
- run: java --version
Adopt
NOTE: Adopt OpenJDK got moved to Eclipse Temurin and won't be updated anymore. It is highly recommended to migrate workflows from adopt to temurin to keep receiving software and security updates. See more details in the Good-bye AdoptOpenJDK post.
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'adopt-hotspot'
java-version: '11'
- run: java --version
Zulu
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'zulu'
java-version: '21'
java-package: jdk # optional (jdk, jre, jdk+fx or jre+fx) - defaults to jdk
- run: java --version
Liberica
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'liberica'
java-version: '21'
java-package: jdk # optional (jdk, jre, jdk+fx or jre+fx) - defaults to jdk
- run: java --version
Microsoft
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'microsoft'
java-version: '21'
- run: java --version
Using Microsoft distribution on GHES
setup-java comes pre-installed on the appliance with GHES if Actions is enabled. When dynamically downloading the Microsoft Build of OpenJDK distribution, setup-java makes a request to actions/setup-java to get available versions on github.com (outside of the appliance). These calls to actions/setup-java are made via unauthenticated requests, which are limited to 60 requests per hour per IP. If more requests are made within the time frame, then you will start to see rate-limit errors during downloading that looks like: ##[error]API rate limit exceeded for....
To get a higher rate limit, you can generate a personal access token on github.com and pass it as the token input for the action:
uses: actions/setup-java@v5
with:
token: ${{ secrets.GH_DOTCOM_TOKEN }}
distribution: 'microsoft'
java-version: '21'
If the runner is not able to access github.com, any Java versions requested during a workflow run must come from the runner's tool cache. See "Setting up the tool cache on self-hosted runners without internet access" for more information.
Amazon Corretto
NOTE: Amazon Corretto only supports the major version specification.
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'corretto'
java-version: '21'
- run: java --version
Oracle
NOTE: Oracle Java SE Development Kit is only available for version 17 and later.
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'oracle'
java-version: '21'
- run: java --version
Alibaba Dragonwell
NOTE: Alibaba Dragonwell only provides jdk.
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'dragonwell'
java-version: '8'
- run: java --version
SapMachine
NOTE: An OpenJDK release maintained and supported by SAP
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'sapmachine'
java-version: '21'
- run: java --version
GraalVM
NOTE: Oracle GraalVM is only available for JDK 17 and later.
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'graalvm'
java-version: '21'
- run: |
java --version
native-image --version
GraalVM Community
NOTE: GraalVM Community is available for stable JDK 17 and later releases.
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'graalvm-community'
java-version: '21'
- run: |
java --version
native-image --version
JetBrains
NOTE: JetBrains is only available for LTS versions on 11 or later (11, 17, 21, etc.).
Not all minor LTS versions are guaranteed to be available, since JetBrains considers what to ship IntelliJ IDEA with, most commonly on JDK 11.
For example, 11.0.24 is not available but 11.0.16 is.
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'jetbrains'
java-version: '11'
- run: java --version
The JetBrains installer uses the GitHub API to fetch the latest version. If you believe your project is going to be running into rate limits, you can provide a
GitHub token to the action to increase the rate limit. Set the GITHUB_TOKEN environment variable to the value of your GitHub token in the workflow file.
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'jetbrains'
java-version: '17'
java-package: 'jdk' # optional (jdk, jre, jdk+jcef, jre+jcef, jdk+ft, or jre+ft) - defaults to jdk
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: java --version
You can specify your package type (as shown in the releases page) in the java-package parameter.
The available package types are:
jdk- JBRSDKjre- JBR (Vanilla)jdk+jcef- JBRSDK with JCEFjre+jcef- JBR with JCEFjdk+ft- JBRSDK (FreeType)jre+ft- JBR (FreeType)
Installing custom Java package type
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: '<distribution>'
java-version: '11'
java-package: jdk # optional (jdk or jre) - defaults to jdk
- run: java --version
JavaFX Maven project
For JavaFX projects that use Maven, use jdk+fx (or jre+fx) as the java-package value together with a distribution that supports it (e.g. zulu or liberica). Then include the javafx-maven-plugin in your pom.xml as described in the Getting Started with JavaFX guide.
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'zulu'
java-version: '21'
java-package: jdk+fx
cache: maven
- name: Build with Maven
run: mvn --no-transfer-progress compile
To run the JavaFX application in CI:
- name: Run with Maven
run: mvn --no-transfer-progress javafx:run
Installing custom Java architecture
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: '<distribution>'
java-version: '11'
architecture: x86 # optional - default value derived from the runner machine
- run: java --version
Installing Java from local file
If your use-case requires a custom distribution or a version that is not provided by setup-java, you can download it manually and setup-java will take care of the installation and caching on the VM:
Note
This approach also lets you use builds that setup-java does not provide directly, such as Early Access (EA) or other unreleased JDK builds (for example, an upcoming feature release or a Loom/Valhalla preview build). Download the desired archive in a prior step and point
jdkFileat it; setup-java will extract, install, and cache it just like a supported distribution. When targeting multiple architectures, select the correct binary per architecture in your workflow (for example, with a build matrix).
steps:
- run: |
download_url="https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.10%2B9/OpenJDK11U-jdk_x64_linux_hotspot_11.0.10_9.tar.gz"
wget -O $RUNNER_TEMP/java_package.tar.gz $download_url
- uses: actions/setup-java@v5
with:
distribution: 'jdkfile'
jdkFile: ${{ runner.temp }}/java_package.tar.gz
java-version: '11.0.0'
architecture: x64
- run: java --version
For example, to use an Early Access build from jdk.java.net, download the archive for your runner OS/architecture and install it via distribution: 'jdkfile' (example below assumes Linux x64):
steps:
- run: |
download_url="https://download.java.net/java/early_access/jdk25/36/GPL/openjdk-25-ea+36_linux-x64_bin.tar.gz"
wget -O $RUNNER_TEMP/java_package.tar.gz $download_url
- uses: actions/setup-java@v5
with:
distribution: 'jdkfile'
jdkFile: ${{ runner.temp }}/java_package.tar.gz
java-version: '25.0.0-ea.36'
architecture: x64
- run: java --version
If your use-case requires a custom distribution (in the example, alpine-linux is used) or a version that is not provided by setup-java and you want to always install the latest version during runtime, then you can use the following code to auto-download the latest JDK, determine the semver needed for setup-java, and setup-java will take care of the installation and caching on the VM:
steps:
- name: fetch latest temurin JDK
id: fetch_latest_jdk
run: |
major_version={{ env.JAVA_VERSION }} # Example 16 or 21 or 22
cd $RUNNER_TEMP
response=$(curl -s "https://api.github.com/repos/adoptium/temurin${major_version}-binaries/releases")
latest_jdk_download_url=$(echo "$response" | jq -r '.[0].assets[] | select(.name | contains("jdk_x64_alpine-linux") and endswith(".tar.gz")) | .browser_download_url')
curl -Ls "$latest_jdk_download_url" -o java_package.tar.gz
latest_jdk_json_url=$(jdk_download_url "$response" | jq -r '.[0].assets[] | select(.name | contains("jdk_x64_alpine-linux") and endswith(".tar.gz.json")) | .browser_download_url')
latest_semver_version=$(curl -sL $latest_jdk_json_url | jq -r 'version.semver')
echo "java_version=$latest_semver_version" >> "$GITHUB_OUTPUT"
- uses: actions/setup-java@v5
with:
distribution: 'jdkfile'
jdkFile: ${{ runner.temp }}/java_package.tar.gz
java-version: {{ steps.fetch_latest_jdk.outputs.java_version }}
architecture: x64
- run: java --version
Testing against different Java distributions
NOTE: The different distributors can provide discrepant list of available versions / supported configurations. Please refer to the official documentation to see the list of supported versions.
jobs:
build:
runs-on: ubuntu-20.04
strategy:
matrix:
distribution: [ 'zulu', 'temurin' ]
java: [ '8', '11' ]
name: Java ${{ matrix.Java }} (${{ matrix.distribution }}) sample
steps:
- uses: actions/checkout@v6
- name: Setup java
uses: actions/setup-java@v5
with:
distribution: ${{ matrix.distribution }}
java-version: ${{ matrix.java }}
- run: java --version
Testing against different platforms
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
java: [ '8', '11' ]
os: [ 'ubuntu-latest', 'macos-latest', 'windows-latest' ]
name: Java ${{ matrix.Java }} (${{ matrix.os }}) sample
steps:
- uses: actions/checkout@v6
- name: Setup java
uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: ${{ matrix.java }}
- run: java --version
Publishing using Apache Maven
Yaml example:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up JDK 11
uses: actions/setup-java@v5
with:
distribution: '<distribution>'
java-version: '11'
- name: Build with Maven
run: mvn -B package --file pom.xml
- name: Publish to GitHub Packages Apache Maven
run: mvn deploy
env:
GITHUB_TOKEN: ${{ github.token }} # GITHUB_TOKEN is the default env for the password
- name: Set up Apache Maven Central
uses: actions/setup-java@v5
with: # running setup-java again overwrites the settings.xml
distribution: 'temurin'
java-version: '11'
server-id: maven # Value of the distributionManagement/repository/id field of the pom.xml
server-username: MAVEN_USERNAME # env variable for username in deploy
server-password: MAVEN_CENTRAL_TOKEN # env variable for token in deploy
gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import
gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase
- name: Publish to Apache Maven Central
run: mvn deploy
env:
MAVEN_USERNAME: maven_username123
MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }}
MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }}
The two settings.xml files created from the above example look like the following.
settings.xml file created for the first deploy to GitHub Packages
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
<interactiveMode>false</interactiveMode>
<servers>
<server>
<id>github</id>
<username>${env.GITHUB_ACTOR}</username>
<password>${env.GITHUB_TOKEN}</password>
</server>
<server>
<id>gpg.passphrase</id>
<passphrase>${env.GPG_PASSPHRASE}</passphrase>
</server>
</servers>
</settings>
settings.xml file created for the second deploy to Apache Maven Central
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 https://maven.apache.org/xsd/settings-1.0.0.xsd">
<interactiveMode>false</interactiveMode>
<servers>
<server>
<id>maven</id>
<username>${env.MAVEN_USERNAME}</username>
<password>${env.MAVEN_CENTRAL_TOKEN}</password>
</server>
<server>
<id>gpg.passphrase</id>
<passphrase>${env.MAVEN_GPG_PASSPHRASE}</passphrase>
</server>
</servers>
</settings>
NOTE: The settings.xml file is created in the Actions $HOME/.m2 directory. If you have an existing settings.xml file at that location, it will be overwritten. See below for using the settings-path to change your settings.xml file location.
If you don't want to overwrite the settings.xml file, you can set overwrite-settings: false
Extra setup for pom.xml:
The Maven GPG Plugin configuration in the pom.xml file should contain the following structure to avoid possible issues like Inappropriate ioctl for device or gpg: signing failed: No such file or directory:
<configuration>
<!-- Prevent gpg from using pinentry programs -->
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
</configuration>
GPG 2.1 requires --pinentry-mode to be set to loopback in order to pick up the gpg.passphrase value defined in Maven settings.xml.
GPG
If gpg-private-key input is provided, the private key will be written to a file in the runner's temp directory, the private key file will be imported into the GPG keychain, and then the file will be promptly removed before proceeding with the rest of the setup process. A cleanup step will remove the imported private key from the GPG keychain after the job completes regardless of the job status. This ensures that the private key is no longer accessible on self-hosted runners and cannot "leak" between jobs (hosted runners are always clean instances).
GPG key should be exported by: gpg --armor --export-secret-keys YOUR_ID
See the help docs on Publishing a Package for more information on the pom.xml file.
NOTE: If the error that states, gpg: Sorry, no terminal at all requested - can't get input is encountered, please update the version of maven-gpg-plugin to 1.6 or higher.
Apache Maven with a settings path
When using an Actions self-hosted runner with multiple shared runners the default $HOME directory can be shared by a number runners at the same time which could overwrite existing settings file. Setting the settings-path variable allows you to choose a unique location for your settings file.
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up JDK 11 for Shared Runner
uses: actions/setup-java@v5
with:
distribution: '<distribution>'
java-version: '11'
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
settings-path: ${{ github.workspace }} # location for the settings.xml file
- name: Build with Maven
run: mvn -B package --file pom.xml
- name: Publish to GitHub Packages Apache Maven
run: mvn deploy -s $GITHUB_WORKSPACE/settings.xml
env:
GITHUB_TOKEN: ${{ github.token }}
Publishing using Gradle
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up JDK 11
uses: actions/setup-java@v5
with:
distribution: '<distribution>'
java-version: '11'
- name: Build with Gradle
run: gradle build
- name: Publish to GitHub Packages
run: gradle publish
env:
USERNAME: ${{ github.actor }}
PASSWORD: ${{ secrets.GITHUB_TOKEN }}
NOTE: The USERNAME and PASSWORD need to correspond to the credentials environment variables used in the publishing section of your build.gradle.
See the help docs on Publishing a Package with Gradle for more information on the build.gradle configuration file.
Hosted Tool Cache
GitHub Hosted Runners have a tool cache that comes with some Java versions pre-installed. This tool cache helps speed up runs and tool setup by not requiring any new downloads. There is an environment variable called RUNNER_TOOL_CACHE on each runner that describes the location of this tools cache and this is where you can find the pre-installed versions of Java. setup-java works by taking a specific version of Java in this tool cache and adding it to PATH if the version, architecture and distribution match.
Currently, LTS versions of Eclipse Temurin (temurin) are cached on the GitHub Hosted Runners.
The tools cache gets updated on a weekly basis. For information regarding locally cached versions of Java on GitHub hosted runners, check out GitHub Actions Virtual Environments.
Modifying Maven Toolchains
The setup-java action generates a basic Maven Toolchains declaration for specified Java versions by either creating a minimal toolchains file or extending an existing declaration with the additional JDKs.
Installing Multiple JDKs With Toolchains
Subsequent calls to setup-java with distinct distribution and version parameters will continue to extend the toolchains declaration and make all specified Java versions available.
steps:
- uses: actions/setup-java@v5
with:
distribution: '<distribution>'
java-version: |
8
11
- uses: actions/setup-java@v5
with:
distribution: '<distribution>'
java-version: '15'
The result is a Toolchain with entries for JDKs 8, 11 and 15. You can even combine this with custom JDKs of arbitrary versions:
- run: |
download_url="https://example.com/java/jdk/6u45-b06/jdk-6u45-linux-x64.tar.gz"
wget -O $RUNNER_TEMP/java_package.tar.gz $download_url
- uses: actions/setup-java@v5
with:
distribution: 'jdkfile'
jdkFile: ${{ runner.temp }}/java_package.tar.gz
java-version: '1.6'
architecture: x64
This will generate a Toolchains entry with the following values: version: 1.6, vendor: jdkfile, id: Oracle_1.6.
Modifying The Toolchain Vendor For JDKs
Each JDK provider will receive a default vendor using the distribution input value but this can be overridden with the mvn-toolchain-vendor parameter as follows.
- run: |
download_url="https://example.com/java/jdk/6u45-b06/jdk-6u45-linux-x64.tar.gz"
wget -O $RUNNER_TEMP/java_package.tar.gz $download_url
- uses: actions/setup-java@v5
with:
distribution: 'jdkfile'
jdkFile: ${{ runner.temp }}/java_package.tar.gz
java-version: '1.6'
architecture: x64
mvn-toolchain-vendor: 'Oracle'
This will generate a Toolchains entry with the following values: version: 1.6, vendor: Oracle, id: Oracle_1.6.
In case you install multiple versions of Java at once with multi-line java-version input setting the mvn-toolchain-vendor still only accepts one value and will use this value for installed JDKs as expected when installing multiple versions of the same distribution.
steps:
- uses: actions/setup-java@v5
with:
distribution: '<distribution>'
java-version: |
8
11
mvn-toolchain-vendor: Eclipse Temurin
Modifying The Toolchain ID For JDKs
Each JDK provider will receive a default id based on the combination of distribution and java-version in the format of distribution_java-version (e.g. temurin_11) but this can be overridden with the mvn-toolchain-id parameter as follows.
steps:
- uses: actions/checkout@v6
- uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '11'
mvn-toolchain-id: 'some_other_id'
- run: java --version
In case you install multiple versions of Java at once you can use the same syntax as used in java-versions. Please note that you have to declare an ID for all Java versions that will be installed or the mvn-toolchain-id instruction will be skipped wholesale due to mapping ambiguities.
steps:
- uses: actions/setup-java@v5
with:
distribution: '<distribution>'
java-version: |
8
11
mvn-toolchain-id: |
something_else
something_other
Java version file
If the java-version-file input is specified, the action will extract the version from the file and install it.
Supported files are .java-version, .tool-versions and .sdkmanrc.
- In
.java-versionfile, only the version should be specified (e.g., 17.0.7). The.java-versionfile recognizes all variants of the version description according to jenv. - In
.tool-versionsfile, java version should be preceded by the java keyword (e.g., java 17.0.7). The.tool-versionsfile supports version specifications in accordance with asdf standards, adhering to Semantic Versioning (semver). - In
.sdkmanrcfile, java version should be preceded by thejava=prefix (e.g., java=17.0.7-tem) and include the distribution. The.sdkmanrcfile supports version specifications in accordance with file format, see Sdkman! documentation for more information.
If both java-version and java-version-file inputs are provided, the java-version input will be used.
Example step using Sdkman!:
- name: Setup java
uses: actions/setup-java@v5
with:
java-version-file: '.sdkmanrc'
distribution: 'temurin'
Example .sdkmanrc:
java=17.0.7-tem
Valid entry options (does not apply to .sdkmanrc):
major versions: 8, 11, 16, 17, 21
more specific versions: 8.0.282+8, 8.0.232, 11.0, 11.0.4, 17.0
early access (EA) versions: 15-ea, 15.0.0-ea
versions with specified distribution: openjdk64-11.0.2
LTS versions : temurin-21.0.5+11.0.LTS
If the file contains multiple versions, only the first one will be recognized.
NOTE: For the tool-version file, ensure that you use standard semantic versioning (semver) formats, as non-standard formats (such as jetbrains-21b212.1) may not be parsed correctly. Additionally, for complex version strings containing multiple version-like segments (for example, java semeru-openj9-11.0.15+10_openj9-0.32.0), the extraction logic may incorrectly capture the last segment (0.32.0) instead of the main version (11.0.15+10).
Self-signed certificates and internal CAs (GitHub Enterprise)
When setup-java dynamically downloads a JDK, it makes HTTPS requests both to fetch the available version metadata and to download the JDK archive. If your runners sit behind a TLS-inspecting corporate proxy, or you are on GitHub Enterprise Server (GHES) with an internal certificate authority, those requests can fail with an error such as:
Error: self signed certificate in certificate chain
This happens because the certificate presented to the runner is signed by an internal or self-signed CA that is not part of the runner's default trust store. The download itself is fine — the runner simply cannot verify the certificate chain.
Recommended fix: trust your internal CA
The secure way to resolve this is to make the runner trust your organization's CA, which keeps TLS verification fully enabled. setup-java runs on Node.js, which honors the NODE_EXTRA_CA_CERTS environment variable. Point it at your CA bundle (in PEM format) before the actions/setup-java step:
steps:
# The CA bundle is already present on the runner image in this example.
# Alternatively, write it from a secret in a previous step.
- name: Trust the internal CA
run: echo "NODE_EXTRA_CA_CERTS=/etc/ssl/certs/internal-ca.pem" >> "$GITHUB_ENV"
- uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '21'
If you keep the certificate in a secret rather than on the runner image, write it to disk first:
steps:
- name: Write and trust the internal CA
run: |
echo "${{ secrets.INTERNAL_CA_PEM }}" > "${RUNNER_TEMP}/internal-ca.pem"
echo "NODE_EXTRA_CA_CERTS=${RUNNER_TEMP}/internal-ca.pem" >> "$GITHUB_ENV"
- uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '21'
For self-hosted runners, you can instead install your CA into the operating system's trust store (for example, update-ca-certificates on Debian/Ubuntu or update-ca-trust on RHEL). This makes the certificate trusted for all tooling on the runner, not just setup-java.
GitHub Enterprise customers
On GitHub Enterprise Server, traffic from your runners frequently passes through an organization-managed proxy or terminates TLS at an appliance using a certificate from an internal CA. If your workflows hit the error above, set NODE_EXTRA_CA_CERTS to your enterprise CA bundle (or bake the CA into your self-hosted runner image) as shown above. Coordinate with your platform team to obtain the correct PEM bundle for your appliance and proxy chain.
Security warning: do not disable certificate verification
Do not work around this error by disabling TLS verification (for example, by setting NODE_TLS_REJECT_UNAUTHORIZED=0). setup-java does not verify a pinned checksum or signature of the downloaded archive, so TLS is effectively the only integrity guarantee on the JDK download. Disabling verification would expose your workflow to a man-in-the-middle attacker who could serve a tampered JDK — which then becomes the java used by the rest of your pipeline, with access to your secrets and credentials. Always extend trust to your CA instead of turning verification off.
Trusting an internal CA inside the installed JDK
The guidance above makes the runner trust your CA so that the JDK can be downloaded. That is a separate layer from making the installed JDK trust your CA at application runtime. If your build steps (Maven/Gradle dependency resolution, integration tests, HTTPS calls from your app, etc.) connect to internal services that present a certificate from your internal CA, the JDK will reject them with errors such as:
PKIX path building failed: unable to find valid certification path to requested target
The JDK keeps its own trust store — a keystore named cacerts under $JAVA_HOME/lib/security/cacerts — which is independent of the operating system and Node trust stores. After setup-java has run (so that JAVA_HOME points at the freshly installed JDK), import your CA into that keystore with keytool:
steps:
- uses: actions/setup-java@v5
with:
distribution: 'temurin'
java-version: '21'
- name: Import internal CA into the JDK trust store
shell: bash
run: |
# Write the CA from a secret (or reference a file already on the runner)
echo "${{ secrets.INTERNAL_CA_PEM }}" > "${RUNNER_TEMP}/internal-ca.pem"
keytool -importcert -noprompt \
-alias internal-ca \
-file "${RUNNER_TEMP}/internal-ca.pem" \
-keystore "${JAVA_HOME}/lib/security/cacerts" \
-storepass changeit
Notes and caveats:
- The default keystore password for
cacertsischangeitunless your distribution overrides it. - On hosted runners the change applies only to the current job's JDK and is discarded when the job ends, so include the import step in every job that needs it.
- On self-hosted runners, importing into a tool-cache JDK persists for as long as that cached version remains on the runner; if you want it to survive JDK reinstalls, pre-seed the CA into your runner image or re-run the import step each time.
- Prefer giving the certificate a stable, descriptive
-aliasso re-runs are idempotent (re-importing the same alias will fail; addkeytool -delete -alias internal-ca ...first if you re-run within a long-lived runner).
This documents the post-install workflow; there is no dedicated action input for supplying a custom cacerts file.