From 1f0a388ca404c29c97a04b5daf3a8b7e60efe4eb Mon Sep 17 00:00:00 2001 From: Mike Penz Date: Thu, 25 Jan 2024 08:51:04 +0000 Subject: [PATCH] - introduce new configuration to enable checksum validation only for detected versions - version is detected from `gradle-wrapper.properties` - checksum is only fetched for these particular versions - FIX https://github.com/gradle/wrapper-validation-action/issues/96 While not specifically targeted, this also - RESOLVES https://github.com/gradle/wrapper-validation-action/issues/142 May enable https://github.com/gradle/wrapper-validation-action/issues/35 --- src/checksums.ts | 8 +++++-- src/find.ts | 61 ++++++++++++++++++++++++++++++++++++++++++++++++ src/main.ts | 3 ++- src/validate.ts | 15 ++++++++++-- 4 files changed, 82 insertions(+), 5 deletions(-) diff --git a/src/checksums.ts b/src/checksums.ts index b82810e2..0797f22a 100644 --- a/src/checksums.ts +++ b/src/checksums.ts @@ -7,7 +7,9 @@ const httpc = new httpm.HttpClient( ) export async function fetchValidChecksums( - allowSnapshots: boolean + allowSnapshots: boolean, + detectVersions: boolean, + detectedVersions: string[] ): Promise { const all = await httpGetJsonArray('https://services.gradle.org/versions/all') const withChecksum = all.filter( @@ -18,7 +20,9 @@ export async function fetchValidChecksums( ) const allowed = withChecksum.filter( // eslint-disable-next-line @typescript-eslint/no-explicit-any - (entry: any) => allowSnapshots || !entry.snapshot + (entry: any) => + (allowSnapshots || !entry.snapshot) && + (!detectVersions || detectedVersions.includes(entry.version)) ) const checksumUrls = allowed.map( // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/src/find.ts b/src/find.ts index 66f14b9e..f9f14214 100644 --- a/src/find.ts +++ b/src/find.ts @@ -1,9 +1,13 @@ import * as util from 'util' import * as path from 'path' import * as fs from 'fs' +import * as readline from 'readline' import unhomoglyph from 'unhomoglyph' +import events from 'events' +import * as core from '@actions/core' const readdir = util.promisify(fs.readdir) +const versionRegex = new RegExp(/\/gradle-(.+)-/) export async function findWrapperJars(baseDir: string): Promise { const files = await recursivelyListFiles(baseDir) @@ -13,6 +17,63 @@ export async function findWrapperJars(baseDir: string): Promise { .sort((a, b) => a.localeCompare(b)) } +export async function detectVersions(wrapperJars: string[]): Promise { + return ( + await Promise.all( + wrapperJars.map(async wrapperJar => await findWrapperVersion(wrapperJar)) + ) + ).filter(version => version !== undefined) as string[] +} + +async function findWrapperVersion( + wrapperJar: string +): Promise { + const jar = path.parse(wrapperJar) + const properties = path.resolve(jar.dir, 'gradle-wrapper.properties') + + if (fs.existsSync(properties)) { + try { + const lineReader = readline.createInterface({ + input: fs.createReadStream(properties) + }) + + let distributionUrl = '' + lineReader.on('line', function (line) { + if (line.startsWith('distributionUrl=')) { + distributionUrl = line + lineReader.close() + } + }) + + await events.once(lineReader, 'close') + + if (distributionUrl) { + const matchedVersion = distributionUrl.match(versionRegex) + if (matchedVersion && matchedVersion.length >= 1) { + return matchedVersion[1] + } else { + core.debug( + `Could not parse version from distributionUrl in gradle-wrapper.properties file: ${properties}` + ) + } + } else { + core.debug( + `Could not identify valid distributionUrl in gradle-wrapper.properties file: ${properties}` + ) + } + } catch (error) { + core.warning( + `Failed to retrieve version from gradle-wrapper.properties file: ${properties} due to ${error}` + ) + } + } else { + core.debug( + `No gradle-wrapper.properties file existed alongside ${wrapperJar}` + ) + } + return undefined +} + async function recursivelyListFiles(baseDir: string): Promise { const childrenNames = await readdir(baseDir) const childrenPaths = await Promise.all( diff --git a/src/main.ts b/src/main.ts index 98096e4e..ef079eb0 100644 --- a/src/main.ts +++ b/src/main.ts @@ -9,7 +9,8 @@ export async function run(): Promise { path.resolve('.'), +core.getInput('min-wrapper-count'), core.getInput('allow-snapshots') === 'true', - core.getInput('allow-checksums').split(',') + core.getInput('allow-checksums').split(','), + core.getInput('detect-version') === 'true' ) if (result.isValid()) { core.info(result.toDisplayString()) diff --git a/src/validate.ts b/src/validate.ts index f10a771a..0798faad 100644 --- a/src/validate.ts +++ b/src/validate.ts @@ -6,7 +6,8 @@ export async function findInvalidWrapperJars( gitRepoRoot: string, minWrapperCount: number, allowSnapshots: boolean, - allowChecksums: string[] + allowChecksums: string[], + detectVersions: boolean ): Promise { const wrapperJars = await find.findWrapperJars(gitRepoRoot) const result = new ValidationResult([], []) @@ -16,7 +17,17 @@ export async function findInvalidWrapperJars( ) } if (wrapperJars.length > 0) { - const validChecksums = await checksums.fetchValidChecksums(allowSnapshots) + let detectedVersions: string[] + if (detectVersions) { + detectedVersions = await find.detectVersions(wrapperJars) + } else { + detectedVersions = [] + } + const validChecksums = await checksums.fetchValidChecksums( + allowSnapshots, + detectVersions, + detectedVersions + ) validChecksums.push(...allowChecksums) for (const wrapperJar of wrapperJars) { const sha = await hash.sha256File(wrapperJar)