-
Notifications
You must be signed in to change notification settings - Fork 109
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
17 changed files
with
7,010 additions
and
336 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
import {expect, test, beforeEach} from '@jest/globals' | ||
import {readConfig} from '../src/config' | ||
import * as Utils from '../src/utils' | ||
import {setInput, clearInputs} from './test-helpers' | ||
|
||
const externalConfig = `fail_on_severity: 'high' | ||
allow_licenses: ['GPL-2.0-only'] | ||
` | ||
const mockOctokit = { | ||
rest: { | ||
repos: { | ||
getContent: jest.fn().mockReturnValue({data: externalConfig}) | ||
} | ||
} | ||
} | ||
|
||
jest.mock('octokit', () => { | ||
return { | ||
// eslint-disable-next-line @typescript-eslint/no-extraneous-class | ||
Octokit: class { | ||
constructor() { | ||
return mockOctokit | ||
} | ||
} | ||
} | ||
}) | ||
|
||
beforeAll(() => { | ||
jest.spyOn(Utils, 'isSPDXValid').mockReturnValue(true) | ||
}) | ||
|
||
beforeEach(() => { | ||
clearInputs() | ||
}) | ||
|
||
test('it reads an external config file', async () => { | ||
setInput('config-file', './__tests__/fixtures/config-allow-sample.yml') | ||
|
||
const config = await readConfig() | ||
expect(config.fail_on_severity).toEqual('critical') | ||
expect(config.allow_licenses).toEqual(['BSD', 'GPL 2']) | ||
}) | ||
|
||
test('raises an error when the config file was not found', async () => { | ||
setInput('config-file', 'fixtures/i-dont-exist') | ||
await expect(readConfig()).rejects.toThrow(/Unable to fetch/) | ||
}) | ||
|
||
test('it parses options from both sources', async () => { | ||
setInput('config-file', './__tests__/fixtures/config-allow-sample.yml') | ||
|
||
let config = await readConfig() | ||
expect(config.fail_on_severity).toEqual('critical') | ||
|
||
setInput('base-ref', 'a-custom-base-ref') | ||
config = await readConfig() | ||
expect(config.base_ref).toEqual('a-custom-base-ref') | ||
}) | ||
|
||
test('in case of conflicts, the inline config is the source of truth', async () => { | ||
setInput('fail-on-severity', 'low') | ||
setInput('config-file', './__tests__/fixtures/config-allow-sample.yml') // this will set fail-on-severity to 'critical' | ||
|
||
const config = await readConfig() | ||
expect(config.fail_on_severity).toEqual('low') | ||
}) | ||
|
||
test('it uses the default values when loading external files', async () => { | ||
setInput('config-file', './__tests__/fixtures/no-licenses-config.yml') | ||
let config = await readConfig() | ||
expect(config.allow_licenses).toEqual(undefined) | ||
expect(config.deny_licenses).toEqual(undefined) | ||
|
||
setInput('config-file', './__tests__/fixtures/license-config-sample.yml') | ||
config = await readConfig() | ||
expect(config.fail_on_severity).toEqual('low') | ||
}) | ||
|
||
test('it accepts an external configuration filename', async () => { | ||
setInput('config-file', './__tests__/fixtures/no-licenses-config.yml') | ||
const config = await readConfig() | ||
expect(config.fail_on_severity).toEqual('critical') | ||
}) | ||
|
||
test('it raises an error when given an unknown severity in an external config file', async () => { | ||
setInput('config-file', './__tests__/fixtures/invalid-severity-config.yml') | ||
await expect(readConfig()).rejects.toThrow() | ||
}) | ||
|
||
test('it supports comma-separated lists', async () => { | ||
setInput( | ||
'config-file', | ||
'./__tests__/fixtures/inline-license-config-sample.yml' | ||
) | ||
const config = await readConfig() | ||
|
||
expect(config.allow_licenses).toEqual(['MIT', 'GPL-2.0-only']) | ||
}) | ||
|
||
test('it reads a config file hosted in another repo', async () => { | ||
setInput( | ||
'config-file', | ||
'future-funk/anyone-cualkiera/external-config.yml@main' | ||
) | ||
setInput('external-repo-token', 'gh_viptoken') | ||
|
||
const config = await readConfig() | ||
|
||
expect(config.fail_on_severity).toEqual('high') | ||
expect(config.allow_licenses).toEqual(['GPL-2.0-only']) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
allow-licenses: MIT, GPL-2.0-only | ||
allow-licenses: "MIT, GPL-2.0-only" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
fail-on-severity: 'so many zombies' | ||
deny-licenses: | ||
fail_on_severity: 'so many zombies' | ||
deny_licenses: | ||
- MIT |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,45 @@ const defaultConfig: ConfigurationOptions = { | |
comment_summary_in_pr: true | ||
} | ||
|
||
const changesWithEmptyManifests: Changes = [ | ||
{ | ||
change_type: 'added', | ||
manifest: '', | ||
ecosystem: 'unknown', | ||
name: 'castore', | ||
version: '0.1.17', | ||
package_url: 'pkg:hex/[email protected]', | ||
license: null, | ||
source_repository_url: null, | ||
scope: 'runtime', | ||
vulnerabilities: [] | ||
}, | ||
{ | ||
change_type: 'added', | ||
manifest: '', | ||
ecosystem: 'unknown', | ||
name: 'connection', | ||
version: '1.1.0', | ||
package_url: 'pkg:hex/[email protected]', | ||
license: null, | ||
source_repository_url: null, | ||
scope: 'runtime', | ||
vulnerabilities: [] | ||
}, | ||
{ | ||
change_type: 'added', | ||
manifest: 'python/dist-info/METADATA', | ||
ecosystem: 'pip', | ||
name: 'pygments', | ||
version: '2.6.1', | ||
package_url: 'pkg:pypi/[email protected]', | ||
license: 'BSD-2-Clause', | ||
source_repository_url: 'https://github.com/pygments/pygments', | ||
scope: 'runtime', | ||
vulnerabilities: [] | ||
} | ||
] | ||
|
||
test('prints headline as h1', () => { | ||
summary.addSummaryToSummary( | ||
emptyChanges, | ||
|
@@ -65,6 +104,22 @@ test('only includes "No license issues found"-message if "vulnerability_check" i | |
expect(text).toContain('✅ No license issues found.') | ||
}) | ||
|
||
test('groups dependencies with empty manifest paths together', () => { | ||
summary.addSummaryToSummary( | ||
changesWithEmptyManifests, | ||
emptyInvalidLicenseChanges, | ||
defaultConfig | ||
) | ||
summary.addScannedDependencies(changesWithEmptyManifests) | ||
const text = core.summary.stringify() | ||
|
||
expect(text).toContain('<summary>Unnamed Manifest</summary>') | ||
expect(text).toContain('castore') | ||
expect(text).toContain('connection') | ||
expect(text).toContain('<summary>python/dist-info/METADATA</summary>') | ||
expect(text).toContain('pygments') | ||
}) | ||
|
||
test('does not include status section if nothing was found', () => { | ||
summary.addSummaryToSummary( | ||
emptyChanges, | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
// GitHub Action inputs come in the form of environment variables | ||
// with an INPUT prefix (e.g. INPUT_FAIL-ON-SEVERITY) | ||
export function setInput(input: string, value: string): void { | ||
process.env[`INPUT_${input.toUpperCase()}`] = value | ||
} | ||
|
||
// We want a clean ENV before each test. We use `delete` | ||
// since we want `undefined` values and not empty strings. | ||
export function clearInputs(): void { | ||
const allowedOptions = [ | ||
'FAIL-ON-SEVERITY', | ||
'FAIL-ON-SCOPES', | ||
'ALLOW-LICENSES', | ||
'DENY-LICENSES', | ||
'ALLOW-GHSAS', | ||
'LICENSE-CHECK', | ||
'VULNERABILITY-CHECK', | ||
'CONFIG-FILE', | ||
'BASE-REF', | ||
'HEAD-REF', | ||
'COMMENT-SUMMARY-IN-PR' | ||
] | ||
|
||
// eslint-disable-next-line github/array-foreach | ||
allowedOptions.forEach(option => { | ||
delete process.env[`INPUT_${option.toUpperCase()}`] | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.