diff --git a/.github/actions/init-integ-test/action.yml b/.github/actions/init-integ-test/action.yml index d8dc5da..b1838d9 100644 --- a/.github/actions/init-integ-test/action.yml +++ b/.github/actions/init-integ-test/action.yml @@ -9,6 +9,11 @@ runs: distribution: 'temurin' java-version: 11 + - name: Configure environment + shell: bash + run: | + echo "ALLOWED_GRADLE_WRAPPER_CHECKSUMS=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" >> "$GITHUB_ENV" + # Downloads a 'dist' directory artifact that was uploaded in an earlier 'build-dist' step - name: Download dist if: ${{ env.SKIP_DIST != 'true' && !env.ACT }} diff --git a/.github/workflows/integ-test-wrapper-validation.yml b/.github/workflows/integ-test-wrapper-validation.yml index 199f358..25d29f5 100644 --- a/.github/workflows/integ-test-wrapper-validation.yml +++ b/.github/workflows/integ-test-wrapper-validation.yml @@ -29,8 +29,8 @@ jobs: - name: Run wrapper-validation-action id: setup-gradle uses: ./setup-gradle - with: - validate-wrappers: true + env: + ALLOWED_GRADLE_WRAPPER_CHECKSUMS: '' continue-on-error: true - name: Check failure diff --git a/dependency-submission/action.yml b/dependency-submission/action.yml index f80489d..32b178c 100644 --- a/dependency-submission/action.yml +++ b/dependency-submission/action.yml @@ -172,6 +172,21 @@ inputs: description: The Develocity short-lived access tokens expiry in hours. Default is 2 hours. required: false + # Wrapper validation configuration + validate-wrappers: + description: | + When 'true' the action will automatically validate all wrapper jars found in the repository. + If the wrapper checksums are not valid, the action will fail. + required: false + default: false + + allow-snapshot-wrappers: + description: | + When 'true', wrapper validation will include the checksums of snapshot wrapper jars. + Use this if you are running with nightly or snapshot versions of the Gradle wrapper. + required: false + default: false + # DEPRECATED ACTION INPUTS # EXPERIMENTAL ACTION INPUTS diff --git a/docs/setup-gradle.md b/docs/setup-gradle.md index 98d3ba6..b705ae1 100644 --- a/docs/setup-gradle.md +++ b/docs/setup-gradle.md @@ -515,14 +515,30 @@ Since Gradle applies init scripts in alphabetical order, one way to ensure this ## Gradle Wrapper validation -Instead of using the [wrapper-validation action](./wrapper-validation.md) separately, you can enable -wrapper validation directly in your Setup Gradle step. +By default, this action will perform the same wrapper validation as is performed by the dedicated +[wrapper-validation action](./wrapper-validation.md). +This means that invalid wrapper jars will be automatically detected when using `setup-gradle`. + +If you do not want wrapper-validation to occur automatically, you can disable it: + +```yaml + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v3 + with: + validate-wrappers: false +``` + +If your repository uses snapshot versions of the Gradle wrapper, such as nightly builds, then you'll need to +explicitly allow snapshot wrappers in wrapper validation. +These are not allowed by default. + ```yaml - name: Setup Gradle uses: gradle/actions/setup-gradle@v3 with: validate-wrappers: true + allow-snapshot-wrappers: true ``` If you need more advanced configuration, then you're advised to continue using a separate workflow step diff --git a/docs/wrapper-validation.md b/docs/wrapper-validation.md index 21e6dfc..66f42a2 100644 --- a/docs/wrapper-validation.md +++ b/docs/wrapper-validation.md @@ -4,6 +4,9 @@ This action validates the checksums of _all_ [Gradle Wrapper](https://docs.gradl The action should be run in the root of the repository, as it will recursively search for any files named `gradle-wrapper.jar`. +The `setup-gradle` action will perform wrapper validation on each execution. If you are using `setup-gradle` in your +workflows, it is unlikely that you will need to use this action. + ## The Gradle Wrapper Problem in Open Source The `gradle-wrapper.jar` is a binary blob of executable code that is checked into nearly diff --git a/setup-gradle/action.yml b/setup-gradle/action.yml index 8794397..134eca7 100644 --- a/setup-gradle/action.yml +++ b/setup-gradle/action.yml @@ -190,9 +190,16 @@ inputs: # Wrapper validation configuration validate-wrappers: description: | - When 'true', the action will perform the 'wrapper-validation' action automatically. + When 'true' (the default) the action will automatically validate all wrapper jars found in the repository. If the wrapper checksums are not valid, the action will fail. required: false + default: true + + allow-snapshot-wrappers: + description: | + When 'true', wrapper validation will include the checksums of snapshot wrapper jars. + Use this if you are running with nightly or snapshot versions of the Gradle wrapper. + required: false default: false # DEPRECATED ACTION INPUTS diff --git a/sources/src/actions/setup-gradle/main.ts b/sources/src/actions/setup-gradle/main.ts index 75289a7..b7a20f0 100644 --- a/sources/src/actions/setup-gradle/main.ts +++ b/sources/src/actions/setup-gradle/main.ts @@ -6,7 +6,7 @@ import { CacheConfig, DependencyGraphConfig, GradleExecutionConfig, - doValidateWrappers, + WrapperValidationConfig, getActionId, setActionId } from '../../configuration' @@ -26,10 +26,7 @@ export async function run(): Promise { setActionId('gradle/actions/setup-gradle') - // Check for invalid wrapper JARs if requested - if (doValidateWrappers()) { - await setupGradle.checkNoInvalidWrapperJars() - } + await setupGradle.validateWrappers(new WrapperValidationConfig()) // Configure Gradle environment (Gradle User Home) await setupGradle.setup(new CacheConfig(), new BuildScanConfig()) diff --git a/sources/src/configuration.ts b/sources/src/configuration.ts index 6f30dfd..a354a2e 100644 --- a/sources/src/configuration.ts +++ b/sources/src/configuration.ts @@ -357,8 +357,14 @@ export class GradleExecutionConfig { } } -export function doValidateWrappers(): boolean { - return getBooleanInput('validate-wrappers') +export class WrapperValidationConfig { + doValidateWrappers(): boolean { + return getBooleanInput('validate-wrappers') + } + + allowSnapshotWrappers(): boolean { + return getBooleanInput('allow-snapshot-wrappers') + } } // Internal parameters diff --git a/sources/src/setup-gradle.ts b/sources/src/setup-gradle.ts index 8b788e5..792151e 100644 --- a/sources/src/setup-gradle.ts +++ b/sources/src/setup-gradle.ts @@ -10,7 +10,13 @@ import * as buildScan from './develocity/build-scan' import {loadBuildResults, markBuildResultsProcessed} from './build-results' import {CacheListener, generateCachingReport} from './caching/cache-reporting' import {DaemonController} from './daemon-controller' -import {BuildScanConfig, CacheConfig, SummaryConfig, getWorkspaceDirectory} from './configuration' +import { + BuildScanConfig, + CacheConfig, + SummaryConfig, + WrapperValidationConfig, + getWorkspaceDirectory +} from './configuration' import {findInvalidWrapperJars} from './wrapper-validation/validate' import {JobFailure} from './errors' @@ -117,9 +123,16 @@ async function determineUserHome(): Promise { return userHome } -export async function checkNoInvalidWrapperJars(rootDir = getWorkspaceDirectory()): Promise { +export async function validateWrappers( + config: WrapperValidationConfig, + rootDir = getWorkspaceDirectory() +): Promise { + if (!config.doValidateWrappers()) { + return // Wrapper validation is disabled + } + const allowedChecksums = process.env['ALLOWED_GRADLE_WRAPPER_CHECKSUMS']?.split(',') || [] - const result = await findInvalidWrapperJars(rootDir, 1, false, allowedChecksums) + const result = await findInvalidWrapperJars(rootDir, 0, config.allowSnapshotWrappers(), allowedChecksums) if (result.isValid()) { core.info(result.toDisplayString()) } else { diff --git a/sources/src/wrapper-validation/checksums.ts b/sources/src/wrapper-validation/checksums.ts index 6a04af8..2748508 100644 --- a/sources/src/wrapper-validation/checksums.ts +++ b/sources/src/wrapper-validation/checksums.ts @@ -55,15 +55,15 @@ export async function fetchUnknownChecksums( // eslint-disable-next-line @typescript-eslint/no-explicit-any (entry: any) => entry.wrapperChecksumUrl as string ) - console.log(`Fetching checksums for ${checksumUrls.length} versions`) if (allowSnapshots) { await addDistributionSnapshotChecksums(checksumUrls) } - console.log(`Fetching checksums for ${checksumUrls.length} versions after snapshot check`) - const checksums = await Promise.all(checksumUrls.map(async (url: string) => { - // console.log(`Fetching checksum from ${url}`) - return httpGetText(url) - })) + const checksums = await Promise.all( + checksumUrls.map(async (url: string) => { + // console.log(`Fetching checksum from ${url}`) + return httpGetText(url) + }) + ) return new Set(checksums) } @@ -83,10 +83,10 @@ export async function addDistributionSnapshotChecksums(checksumUrls: string[]): // // Extract all wrapper checksum from the index page. These end in -wrapper.jar.sha256 // // Load the HTML into cheerio - const $ = cheerio.load(indexPage); + const $ = cheerio.load(indexPage) // // Find all links ending with '-wrapper.jar.sha256' - const wrapperChecksumLinks = $('a[href$="-wrapper.jar.sha256"]'); + const wrapperChecksumLinks = $('a[href$="-wrapper.jar.sha256"]') // build the absolute URL for each wrapper checksum wrapperChecksumLinks.each((index, element) => {