Enable wrapper validation by default

- Add 'allow-snapshot-wrappers' input parameter
- Default 'validate-wrappers' to 'true'

Fixes #12
This commit is contained in:
daz 2024-07-31 20:38:10 -06:00
parent 7179909719
commit b644be617f
No known key found for this signature in database
10 changed files with 85 additions and 23 deletions

View File

@ -9,6 +9,11 @@ runs:
distribution: 'temurin' distribution: 'temurin'
java-version: 11 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 # Downloads a 'dist' directory artifact that was uploaded in an earlier 'build-dist' step
- name: Download dist - name: Download dist
if: ${{ env.SKIP_DIST != 'true' && !env.ACT }} if: ${{ env.SKIP_DIST != 'true' && !env.ACT }}

View File

@ -29,8 +29,8 @@ jobs:
- name: Run wrapper-validation-action - name: Run wrapper-validation-action
id: setup-gradle id: setup-gradle
uses: ./setup-gradle uses: ./setup-gradle
with: env:
validate-wrappers: true ALLOWED_GRADLE_WRAPPER_CHECKSUMS: ''
continue-on-error: true continue-on-error: true
- name: Check failure - name: Check failure

View File

@ -172,6 +172,21 @@ inputs:
description: The Develocity short-lived access tokens expiry in hours. Default is 2 hours. description: The Develocity short-lived access tokens expiry in hours. Default is 2 hours.
required: false 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 # DEPRECATED ACTION INPUTS
# EXPERIMENTAL ACTION INPUTS # EXPERIMENTAL ACTION INPUTS

View File

@ -515,14 +515,30 @@ Since Gradle applies init scripts in alphabetical order, one way to ensure this
## Gradle Wrapper validation ## Gradle Wrapper validation
Instead of using the [wrapper-validation action](./wrapper-validation.md) separately, you can enable By default, this action will perform the same wrapper validation as is performed by the dedicated
wrapper validation directly in your Setup Gradle step. [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 ```yaml
- name: Setup Gradle - name: Setup Gradle
uses: gradle/actions/setup-gradle@v3 uses: gradle/actions/setup-gradle@v3
with: with:
validate-wrappers: true validate-wrappers: true
allow-snapshot-wrappers: true
``` ```
If you need more advanced configuration, then you're advised to continue using a separate workflow step If you need more advanced configuration, then you're advised to continue using a separate workflow step

View File

@ -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 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 Problem in Open Source
The `gradle-wrapper.jar` is a binary blob of executable code that is checked into nearly The `gradle-wrapper.jar` is a binary blob of executable code that is checked into nearly

View File

@ -190,9 +190,16 @@ inputs:
# Wrapper validation configuration # Wrapper validation configuration
validate-wrappers: validate-wrappers:
description: | 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. If the wrapper checksums are not valid, the action will fail.
required: false 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 default: false
# DEPRECATED ACTION INPUTS # DEPRECATED ACTION INPUTS

View File

@ -6,7 +6,7 @@ import {
CacheConfig, CacheConfig,
DependencyGraphConfig, DependencyGraphConfig,
GradleExecutionConfig, GradleExecutionConfig,
doValidateWrappers, WrapperValidationConfig,
getActionId, getActionId,
setActionId setActionId
} from '../../configuration' } from '../../configuration'
@ -26,10 +26,7 @@ export async function run(): Promise<void> {
setActionId('gradle/actions/setup-gradle') setActionId('gradle/actions/setup-gradle')
// Check for invalid wrapper JARs if requested await setupGradle.validateWrappers(new WrapperValidationConfig())
if (doValidateWrappers()) {
await setupGradle.checkNoInvalidWrapperJars()
}
// Configure Gradle environment (Gradle User Home) // Configure Gradle environment (Gradle User Home)
await setupGradle.setup(new CacheConfig(), new BuildScanConfig()) await setupGradle.setup(new CacheConfig(), new BuildScanConfig())

View File

@ -357,10 +357,16 @@ export class GradleExecutionConfig {
} }
} }
export function doValidateWrappers(): boolean { export class WrapperValidationConfig {
doValidateWrappers(): boolean {
return getBooleanInput('validate-wrappers') return getBooleanInput('validate-wrappers')
} }
allowSnapshotWrappers(): boolean {
return getBooleanInput('allow-snapshot-wrappers')
}
}
// Internal parameters // Internal parameters
export function getJobMatrix(): string { export function getJobMatrix(): string {
return core.getInput('workflow-job-context') return core.getInput('workflow-job-context')

View File

@ -10,7 +10,13 @@ import * as buildScan from './develocity/build-scan'
import {loadBuildResults, markBuildResultsProcessed} from './build-results' import {loadBuildResults, markBuildResultsProcessed} from './build-results'
import {CacheListener, generateCachingReport} from './caching/cache-reporting' import {CacheListener, generateCachingReport} from './caching/cache-reporting'
import {DaemonController} from './daemon-controller' 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 {findInvalidWrapperJars} from './wrapper-validation/validate'
import {JobFailure} from './errors' import {JobFailure} from './errors'
@ -117,9 +123,16 @@ async function determineUserHome(): Promise<string> {
return userHome return userHome
} }
export async function checkNoInvalidWrapperJars(rootDir = getWorkspaceDirectory()): Promise<void> { export async function validateWrappers(
config: WrapperValidationConfig,
rootDir = getWorkspaceDirectory()
): Promise<void> {
if (!config.doValidateWrappers()) {
return // Wrapper validation is disabled
}
const allowedChecksums = process.env['ALLOWED_GRADLE_WRAPPER_CHECKSUMS']?.split(',') || [] 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()) { if (result.isValid()) {
core.info(result.toDisplayString()) core.info(result.toDisplayString())
} else { } else {

View File

@ -55,15 +55,15 @@ export async function fetchUnknownChecksums(
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
(entry: any) => entry.wrapperChecksumUrl as string (entry: any) => entry.wrapperChecksumUrl as string
) )
console.log(`Fetching checksums for ${checksumUrls.length} versions`)
if (allowSnapshots) { if (allowSnapshots) {
await addDistributionSnapshotChecksums(checksumUrls) await addDistributionSnapshotChecksums(checksumUrls)
} }
console.log(`Fetching checksums for ${checksumUrls.length} versions after snapshot check`) const checksums = await Promise.all(
const checksums = await Promise.all(checksumUrls.map(async (url: string) => { checksumUrls.map(async (url: string) => {
// console.log(`Fetching checksum from ${url}`) // console.log(`Fetching checksum from ${url}`)
return httpGetText(url) return httpGetText(url)
})) })
)
return new Set(checksums) 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 // // Extract all wrapper checksum from the index page. These end in -wrapper.jar.sha256
// // Load the HTML into cheerio // // Load the HTML into cheerio
const $ = cheerio.load(indexPage); const $ = cheerio.load(indexPage)
// // Find all links ending with '-wrapper.jar.sha256' // // 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 // build the absolute URL for each wrapper checksum
wrapperChecksumLinks.each((index, element) => { wrapperChecksumLinks.each((index, element) => {