Merge branch 'master' into feat/JLL/homoglyph_detector

* master:
  Add :
  Build
  Rework output
  Let finding wrapper jars be predictable
  Ignore IDEA files
This commit is contained in:
Jonathan Leitschuh 2020-01-15 11:57:46 -05:00
commit 9f4cacc32b
No known key found for this signature in database
GPG key ID: 3501A7427721B061
6 changed files with 173 additions and 48 deletions

2
.gitignore vendored
View file

@ -99,3 +99,5 @@ __tests__/runner/*
lib/**/* lib/**/*
.idea .idea
*.iml

View file

@ -1,26 +1,71 @@
import * as path from 'path' import * as path from 'path'
import * as validate from '../src/validate' import * as validate from '../src/validate'
test('validates wrapper jars', async () => { const baseDir = path.resolve('.')
const invalidWrapperJars = await validate.findInvalidWrapperJars(
path.resolve('.'), test('succeeds if all found wrapper jars are valid', async () => {
3, const result = await validate.findInvalidWrapperJars(baseDir, 3, false, [
false, 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
[] ])
expect(result.isValid()).toBe(true)
expect(result.toDisplayString()).toBe(
'✓ Found known Gradle Wrapper JAR files:\n' +
' e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 __tests__/data/invalid/gradle-wrapper.jar\n' +
' e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 __tests__/data/invalid/gradlе-wrapper.jar\n' + // homoglyph
' 3888c76faa032ea8394b8a54e04ce2227ab1f4be64f65d450f8509fe112d38ce __tests__/data/valid/gradle-wrapper.jar'
) )
expect(invalidWrapperJars.length).toBe(2) })
expect(invalidWrapperJars[0]).toEqual(
new validate.InvalidWrapperJar( test('fails if invalid wrapper jars are found', async () => {
const result = await validate.findInvalidWrapperJars(baseDir, 3, false, [])
expect(result.isValid()).toBe(false)
expect(result.valid).toEqual([
new validate.WrapperJar(
'__tests__/data/valid/gradle-wrapper.jar',
'3888c76faa032ea8394b8a54e04ce2227ab1f4be64f65d450f8509fe112d38ce'
)
])
expect(result.invalid).toEqual([
new validate.WrapperJar(
'__tests__/data/invalid/gradle-wrapper.jar', '__tests__/data/invalid/gradle-wrapper.jar',
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855' 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
),
new validate.WrapperJar(
'__tests__/data/invalid/gradlе-wrapper.jar', // homoglyph
'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
) )
])
expect(result.toDisplayString()).toBe(
'✗ Found unknown Gradle Wrapper JAR files:\n' +
' e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 __tests__/data/invalid/gradle-wrapper.jar\n' +
' e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 __tests__/data/invalid/gradlе-wrapper.jar\n' + // homoglyph
'✓ Found known Gradle Wrapper JAR files:\n' +
' 3888c76faa032ea8394b8a54e04ce2227ab1f4be64f65d450f8509fe112d38ce __tests__/data/valid/gradle-wrapper.jar'
) )
}) })
test('fails if not enough wrapper jars are found', async () => { test('fails if not enough wrapper jars are found', async () => {
await expect( const result = await validate.findInvalidWrapperJars(baseDir, 4, false, [])
validate.findInvalidWrapperJars(path.resolve('.'), 4, false, [])
).rejects.toThrowError( expect(result.isValid()).toBe(false)
expect(result.errors).toEqual([
'Expected to find at least 4 Gradle Wrapper JARs but got only 3' 'Expected to find at least 4 Gradle Wrapper JARs but got only 3'
])
expect(result.toDisplayString()).toBe(
'✗ Found unknown Gradle Wrapper JAR files:\n' +
' e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 __tests__/data/invalid/gradle-wrapper.jar\n' +
' e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 __tests__/data/invalid/gradlе-wrapper.jar\n' + // homoglyph
'✗ Other validation errors:\n' +
' Expected to find at least 4 Gradle Wrapper JARs but got only 3\n' +
'✓ Found known Gradle Wrapper JAR files:\n' +
' 3888c76faa032ea8394b8a54e04ce2227ab1f4be64f65d450f8509fe112d38ce __tests__/data/valid/gradle-wrapper.jar'
) )
}) })

66
dist/index.js vendored
View file

@ -340,13 +340,12 @@ const validate = __importStar(__webpack_require__(474));
function run() { function run() {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
try { try {
const minWrapperCount = +core.getInput('min-wrapper-count'); const result = yield validate.findInvalidWrapperJars(path.resolve('.'), +core.getInput('min-wrapper-count'), core.getInput('allow-snapshots') === 'true', core.getInput('allow-checksums').split(','));
const allowSnapshots = core.getInput('allow-snapshots') === 'true'; if (result.isValid()) {
const allowChecksums = core.getInput('allow-checksums').split(','); core.info(result.toDisplayString());
const invalidWrapperJars = yield validate.findInvalidWrapperJars(path.resolve('.'), minWrapperCount, allowSnapshots, allowChecksums); }
if (invalidWrapperJars.length > 0) { else {
const list = invalidWrapperJars.map(invalid => `${invalid.checksum} ${invalid.path}`); core.setFailed(result.toDisplayString());
core.setFailed(`Found unknown Gradle Wrapper JAR files\n${list.join('\n- ')}`);
} }
} }
catch (error) { catch (error) {
@ -976,32 +975,68 @@ const hash = __importStar(__webpack_require__(652));
function findInvalidWrapperJars(gitRepoRoot, minWrapperCount, allowSnapshots, allowChecksums) { function findInvalidWrapperJars(gitRepoRoot, minWrapperCount, allowSnapshots, allowChecksums) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const wrapperJars = yield find.findWrapperJars(gitRepoRoot); const wrapperJars = yield find.findWrapperJars(gitRepoRoot);
const result = new ValidationResult([], []);
if (wrapperJars.length < minWrapperCount) { if (wrapperJars.length < minWrapperCount) {
throw new Error(`Expected to find at least ${minWrapperCount} Gradle Wrapper JARs but got only ${wrapperJars.length}`); result.errors.push(`Expected to find at least ${minWrapperCount} Gradle Wrapper JARs but got only ${wrapperJars.length}`);
} }
if (wrapperJars.length > 0) { if (wrapperJars.length > 0) {
const validChecksums = yield checksums.fetchValidChecksums(allowSnapshots); const validChecksums = yield checksums.fetchValidChecksums(allowSnapshots);
validChecksums.push(...allowChecksums); validChecksums.push(...allowChecksums);
const invalidWrapperJars = [];
for (const wrapperJar of wrapperJars) { for (const wrapperJar of wrapperJars) {
const sha = yield hash.sha256File(wrapperJar); const sha = yield hash.sha256File(wrapperJar);
if (!validChecksums.includes(sha)) { if (!validChecksums.includes(sha)) {
invalidWrapperJars.push(new InvalidWrapperJar(wrapperJar, sha)); result.invalid.push(new WrapperJar(wrapperJar, sha));
}
else {
result.valid.push(new WrapperJar(wrapperJar, sha));
} }
} }
return invalidWrapperJars;
} }
return []; return result;
}); });
} }
exports.findInvalidWrapperJars = findInvalidWrapperJars; exports.findInvalidWrapperJars = findInvalidWrapperJars;
class InvalidWrapperJar { class ValidationResult {
constructor(valid, invalid) {
this.errors = [];
this.valid = valid;
this.invalid = invalid;
}
isValid() {
return this.invalid.length === 0 && this.errors.length === 0;
}
toDisplayString() {
let displayString = '';
if (this.invalid.length > 0) {
displayString += `✗ Found unknown Gradle Wrapper JAR files:\n${ValidationResult.toDisplayList(this.invalid)}`;
}
if (this.errors.length > 0) {
if (displayString.length > 0)
displayString += '\n';
displayString += `✗ Other validation errors:\n ${this.errors.join(`\n `)}`;
}
if (this.valid.length > 0) {
if (displayString.length > 0)
displayString += '\n';
displayString += `✓ Found known Gradle Wrapper JAR files:\n${ValidationResult.toDisplayList(this.valid)}`;
}
return displayString;
}
static toDisplayList(wrapperJars) {
return ` ${wrapperJars.map(wj => wj.toDisplayString()).join(`\n `)}`;
}
}
exports.ValidationResult = ValidationResult;
class WrapperJar {
constructor(path, checksum) { constructor(path, checksum) {
this.path = path; this.path = path;
this.checksum = checksum; this.checksum = checksum;
} }
toDisplayString() {
return `${this.checksum} ${this.path}`;
}
} }
exports.InvalidWrapperJar = InvalidWrapperJar; exports.WrapperJar = WrapperJar;
/***/ }), /***/ }),
@ -1069,7 +1104,8 @@ function findWrapperJars(baseDir) {
const files = yield recursivelyListFiles(baseDir); const files = yield recursivelyListFiles(baseDir);
return files return files
.filter(file => unhomoglyph_1.default(file).endsWith('gradle-wrapper.jar')) .filter(file => unhomoglyph_1.default(file).endsWith('gradle-wrapper.jar'))
.map(wrapperJar => path.relative(baseDir, wrapperJar)); .map(wrapperJar => path.relative(baseDir, wrapperJar))
.sort((a, b) => a.localeCompare(b));
}); });
} }
exports.findWrapperJars = findWrapperJars; exports.findWrapperJars = findWrapperJars;

View file

@ -10,6 +10,7 @@ export async function findWrapperJars(baseDir: string): Promise<string[]> {
return files return files
.filter(file => unhomoglyph(file).endsWith('gradle-wrapper.jar')) .filter(file => unhomoglyph(file).endsWith('gradle-wrapper.jar'))
.map(wrapperJar => path.relative(baseDir, wrapperJar)) .map(wrapperJar => path.relative(baseDir, wrapperJar))
.sort((a, b) => a.localeCompare(b))
} }
async function recursivelyListFiles(baseDir: string): Promise<string[]> { async function recursivelyListFiles(baseDir: string): Promise<string[]> {

View file

@ -5,22 +5,16 @@ import * as validate from './validate'
export async function run(): Promise<void> { export async function run(): Promise<void> {
try { try {
const minWrapperCount = +core.getInput('min-wrapper-count') const result = await validate.findInvalidWrapperJars(
const allowSnapshots = core.getInput('allow-snapshots') === 'true'
const allowChecksums = core.getInput('allow-checksums').split(',')
const invalidWrapperJars = await validate.findInvalidWrapperJars(
path.resolve('.'), path.resolve('.'),
minWrapperCount, +core.getInput('min-wrapper-count'),
allowSnapshots, core.getInput('allow-snapshots') === 'true',
allowChecksums core.getInput('allow-checksums').split(',')
) )
if (invalidWrapperJars.length > 0) { if (result.isValid()) {
const list = invalidWrapperJars.map( core.info(result.toDisplayString())
invalid => `${invalid.checksum} ${invalid.path}` } else {
) core.setFailed(result.toDisplayString())
core.setFailed(
`Found unknown Gradle Wrapper JAR files\n${list.join('\n- ')}`
)
} }
} catch (error) { } catch (error) {
core.setFailed(error.message) core.setFailed(error.message)

View file

@ -7,33 +7,80 @@ export async function findInvalidWrapperJars(
minWrapperCount: number, minWrapperCount: number,
allowSnapshots: boolean, allowSnapshots: boolean,
allowChecksums: string[] allowChecksums: string[]
): Promise<InvalidWrapperJar[]> { ): Promise<ValidationResult> {
const wrapperJars = await find.findWrapperJars(gitRepoRoot) const wrapperJars = await find.findWrapperJars(gitRepoRoot)
const result = new ValidationResult([], [])
if (wrapperJars.length < minWrapperCount) { if (wrapperJars.length < minWrapperCount) {
throw new Error( result.errors.push(
`Expected to find at least ${minWrapperCount} Gradle Wrapper JARs but got only ${wrapperJars.length}` `Expected to find at least ${minWrapperCount} Gradle Wrapper JARs but got only ${wrapperJars.length}`
) )
} }
if (wrapperJars.length > 0) { if (wrapperJars.length > 0) {
const validChecksums = await checksums.fetchValidChecksums(allowSnapshots) const validChecksums = await checksums.fetchValidChecksums(allowSnapshots)
validChecksums.push(...allowChecksums) validChecksums.push(...allowChecksums)
const invalidWrapperJars: InvalidWrapperJar[] = []
for (const wrapperJar of wrapperJars) { for (const wrapperJar of wrapperJars) {
const sha = await hash.sha256File(wrapperJar) const sha = await hash.sha256File(wrapperJar)
if (!validChecksums.includes(sha)) { if (!validChecksums.includes(sha)) {
invalidWrapperJars.push(new InvalidWrapperJar(wrapperJar, sha)) result.invalid.push(new WrapperJar(wrapperJar, sha))
} else {
result.valid.push(new WrapperJar(wrapperJar, sha))
} }
} }
return invalidWrapperJars
} }
return [] return result
} }
export class InvalidWrapperJar { export class ValidationResult {
valid: WrapperJar[]
invalid: WrapperJar[]
errors: string[] = []
constructor(valid: WrapperJar[], invalid: WrapperJar[]) {
this.valid = valid
this.invalid = invalid
}
isValid(): boolean {
return this.invalid.length === 0 && this.errors.length === 0
}
toDisplayString(): string {
let displayString = ''
if (this.invalid.length > 0) {
displayString += `✗ Found unknown Gradle Wrapper JAR files:\n${ValidationResult.toDisplayList(
this.invalid
)}`
}
if (this.errors.length > 0) {
if (displayString.length > 0) displayString += '\n'
displayString += `✗ Other validation errors:\n ${this.errors.join(
`\n `
)}`
}
if (this.valid.length > 0) {
if (displayString.length > 0) displayString += '\n'
displayString += `✓ Found known Gradle Wrapper JAR files:\n${ValidationResult.toDisplayList(
this.valid
)}`
}
return displayString
}
private static toDisplayList(wrapperJars: WrapperJar[]): string {
return ` ${wrapperJars.map(wj => wj.toDisplayString()).join(`\n `)}`
}
}
export class WrapperJar {
path: string path: string
checksum: string checksum: string
constructor(path: string, checksum: string) { constructor(path: string, checksum: string) {
this.path = path this.path = path
this.checksum = checksum this.checksum = checksum
} }
toDisplayString(): string {
return `${this.checksum} ${this.path}`
}
} }