Skip to content

Commit f1c8401

Browse files
committed
resolve merge conflicts
2 parents ef8ebf0 + 1f7c838 commit f1c8401

17 files changed

+7010
-336
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,12 @@ Start by specifying that you will be using an external configuration file:
129129
config-file: './.github/dependency-review-config.yml'
130130
```
131131

132-
And then create the file in the path you just specified:
132+
And then create the file in the path you just specified. Please note
133+
that the **option names in external files use underscores instead of dashes**:
133134

134135
```yaml
135-
fail-on-severity: 'critical'
136-
allow-licenses:
136+
fail_on_severity: 'critical'
137+
allow_licenses:
137138
- 'GPL-3.0'
138139
- 'BSD-3-Clause'
139140
- 'MIT'

__tests__/config.test.ts

Lines changed: 1 addition & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -2,35 +2,7 @@ import {expect, test, beforeEach} from '@jest/globals'
22
import {readConfig} from '../src/config'
33
import {getRefs} from '../src/git-refs'
44
import * as Utils from '../src/utils'
5-
6-
// GitHub Action inputs come in the form of environment variables
7-
// with an INPUT prefix (e.g. INPUT_FAIL-ON-SEVERITY)
8-
function setInput(input: string, value: string): void {
9-
process.env[`INPUT_${input.toUpperCase()}`] = value
10-
}
11-
12-
// We want a clean ENV before each test. We use `delete`
13-
// since we want `undefined` values and not empty strings.
14-
function clearInputs(): void {
15-
const allowedOptions = [
16-
'FAIL-ON-SEVERITY',
17-
'FAIL-ON-SCOPES',
18-
'ALLOW-LICENSES',
19-
'DENY-LICENSES',
20-
'ALLOW-GHSAS',
21-
'LICENSE-CHECK',
22-
'VULNERABILITY-CHECK',
23-
'CONFIG-FILE',
24-
'BASE-REF',
25-
'HEAD-REF',
26-
'COMMENT-SUMMARY-IN-PR'
27-
]
28-
29-
// eslint-disable-next-line github/array-foreach
30-
allowedOptions.forEach(option => {
31-
delete process.env[`INPUT_${option.toUpperCase()}`]
32-
})
33-
}
5+
import {setInput, clearInputs} from './test-helpers'
346

357
beforeAll(() => {
368
jest.spyOn(Utils, 'isSPDXValid').mockReturnValue(true)
@@ -105,60 +77,6 @@ test('it raises an error when no refs are provided and the event is not a pull r
10577
).toThrow()
10678
})
10779

108-
test('it reads an external config file', async () => {
109-
setInput('config-file', './__tests__/fixtures/config-allow-sample.yml')
110-
111-
const config = await readConfig()
112-
expect(config.fail_on_severity).toEqual('critical')
113-
expect(config.allow_licenses).toEqual(['BSD', 'GPL 2'])
114-
})
115-
116-
test('raises an error when the config file was not found', async () => {
117-
setInput('config-file', 'fixtures/i-dont-exist')
118-
await expect(readConfig()).rejects.toThrow(/Unable to fetch/)
119-
})
120-
121-
test('it parses options from both sources', async () => {
122-
setInput('config-file', './__tests__/fixtures/config-allow-sample.yml')
123-
124-
let config = await readConfig()
125-
expect(config.fail_on_severity).toEqual('critical')
126-
127-
setInput('base-ref', 'a-custom-base-ref')
128-
config = await readConfig()
129-
expect(config.base_ref).toEqual('a-custom-base-ref')
130-
})
131-
132-
test('in case of conflicts, the inline config is the source of truth', async () => {
133-
setInput('fail-on-severity', 'low')
134-
setInput('config-file', './__tests__/fixtures/config-allow-sample.yml') // this will set fail-on-severity to 'critical'
135-
136-
const config = await readConfig()
137-
expect(config.fail_on_severity).toEqual('low')
138-
})
139-
140-
test('it uses the default values when loading external files', async () => {
141-
setInput('config-file', './__tests__/fixtures/no-licenses-config.yml')
142-
let config = await readConfig()
143-
expect(config.allow_licenses).toEqual(undefined)
144-
expect(config.deny_licenses).toEqual(undefined)
145-
146-
setInput('config-file', './__tests__/fixtures/license-config-sample.yml')
147-
config = await readConfig()
148-
expect(config.fail_on_severity).toEqual('low')
149-
})
150-
151-
test('it accepts an external configuration filename', async () => {
152-
setInput('config-file', './__tests__/fixtures/no-licenses-config.yml')
153-
const config = await readConfig()
154-
expect(config.fail_on_severity).toEqual('critical')
155-
})
156-
157-
test('it raises an error when given an unknown severity in an external config file', async () => {
158-
setInput('config-file', './__tests__/fixtures/invalid-severity-config.yml')
159-
await expect(readConfig()).rejects.toThrow()
160-
})
161-
16280
test('it defaults to runtime scope', async () => {
16381
const config = await readConfig()
16482
expect(config.fail_on_scopes).toEqual(['runtime'])
@@ -234,16 +152,6 @@ test('it is not possible to disable both checks', async () => {
234152
)
235153
})
236154

237-
test('it supports comma-separated lists', async () => {
238-
setInput(
239-
'config-file',
240-
'./__tests__/fixtures/inline-license-config-sample.yml'
241-
)
242-
const config = await readConfig()
243-
244-
expect(config.allow_licenses).toEqual(['MIT', 'GPL-2.0-only'])
245-
})
246-
247155
describe('licenses that are not valid SPDX licenses', () => {
248156
beforeAll(() => {
249157
jest.spyOn(Utils, 'isSPDXValid').mockReturnValue(false)

__tests__/external-config.test.ts

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import {expect, test, beforeEach} from '@jest/globals'
2+
import {readConfig} from '../src/config'
3+
import * as Utils from '../src/utils'
4+
import {setInput, clearInputs} from './test-helpers'
5+
6+
const externalConfig = `fail_on_severity: 'high'
7+
allow_licenses: ['GPL-2.0-only']
8+
`
9+
const mockOctokit = {
10+
rest: {
11+
repos: {
12+
getContent: jest.fn().mockReturnValue({data: externalConfig})
13+
}
14+
}
15+
}
16+
17+
jest.mock('octokit', () => {
18+
return {
19+
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
20+
Octokit: class {
21+
constructor() {
22+
return mockOctokit
23+
}
24+
}
25+
}
26+
})
27+
28+
beforeAll(() => {
29+
jest.spyOn(Utils, 'isSPDXValid').mockReturnValue(true)
30+
})
31+
32+
beforeEach(() => {
33+
clearInputs()
34+
})
35+
36+
test('it reads an external config file', async () => {
37+
setInput('config-file', './__tests__/fixtures/config-allow-sample.yml')
38+
39+
const config = await readConfig()
40+
expect(config.fail_on_severity).toEqual('critical')
41+
expect(config.allow_licenses).toEqual(['BSD', 'GPL 2'])
42+
})
43+
44+
test('raises an error when the config file was not found', async () => {
45+
setInput('config-file', 'fixtures/i-dont-exist')
46+
await expect(readConfig()).rejects.toThrow(/Unable to fetch/)
47+
})
48+
49+
test('it parses options from both sources', async () => {
50+
setInput('config-file', './__tests__/fixtures/config-allow-sample.yml')
51+
52+
let config = await readConfig()
53+
expect(config.fail_on_severity).toEqual('critical')
54+
55+
setInput('base-ref', 'a-custom-base-ref')
56+
config = await readConfig()
57+
expect(config.base_ref).toEqual('a-custom-base-ref')
58+
})
59+
60+
test('in case of conflicts, the inline config is the source of truth', async () => {
61+
setInput('fail-on-severity', 'low')
62+
setInput('config-file', './__tests__/fixtures/config-allow-sample.yml') // this will set fail-on-severity to 'critical'
63+
64+
const config = await readConfig()
65+
expect(config.fail_on_severity).toEqual('low')
66+
})
67+
68+
test('it uses the default values when loading external files', async () => {
69+
setInput('config-file', './__tests__/fixtures/no-licenses-config.yml')
70+
let config = await readConfig()
71+
expect(config.allow_licenses).toEqual(undefined)
72+
expect(config.deny_licenses).toEqual(undefined)
73+
74+
setInput('config-file', './__tests__/fixtures/license-config-sample.yml')
75+
config = await readConfig()
76+
expect(config.fail_on_severity).toEqual('low')
77+
})
78+
79+
test('it accepts an external configuration filename', async () => {
80+
setInput('config-file', './__tests__/fixtures/no-licenses-config.yml')
81+
const config = await readConfig()
82+
expect(config.fail_on_severity).toEqual('critical')
83+
})
84+
85+
test('it raises an error when given an unknown severity in an external config file', async () => {
86+
setInput('config-file', './__tests__/fixtures/invalid-severity-config.yml')
87+
await expect(readConfig()).rejects.toThrow()
88+
})
89+
90+
test('it supports comma-separated lists', async () => {
91+
setInput(
92+
'config-file',
93+
'./__tests__/fixtures/inline-license-config-sample.yml'
94+
)
95+
const config = await readConfig()
96+
97+
expect(config.allow_licenses).toEqual(['MIT', 'GPL-2.0-only'])
98+
})
99+
100+
test('it reads a config file hosted in another repo', async () => {
101+
setInput(
102+
'config-file',
103+
'future-funk/anyone-cualkiera/external-config.yml@main'
104+
)
105+
setInput('external-repo-token', 'gh_viptoken')
106+
107+
const config = await readConfig()
108+
109+
expect(config.fail_on_severity).toEqual('high')
110+
expect(config.allow_licenses).toEqual(['GPL-2.0-only'])
111+
})
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
allow-licenses: MIT, GPL-2.0-only
1+
allow-licenses: "MIT, GPL-2.0-only"
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
fail-on-severity: 'so many zombies'
2-
deny-licenses:
1+
fail_on_severity: 'so many zombies'
2+
deny_licenses:
33
- MIT

__tests__/summary.test.ts

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,45 @@ const defaultConfig: ConfigurationOptions = {
2727
comment_summary_in_pr: true
2828
}
2929

30+
const changesWithEmptyManifests: Changes = [
31+
{
32+
change_type: 'added',
33+
manifest: '',
34+
ecosystem: 'unknown',
35+
name: 'castore',
36+
version: '0.1.17',
37+
package_url: 'pkg:hex/[email protected]',
38+
license: null,
39+
source_repository_url: null,
40+
scope: 'runtime',
41+
vulnerabilities: []
42+
},
43+
{
44+
change_type: 'added',
45+
manifest: '',
46+
ecosystem: 'unknown',
47+
name: 'connection',
48+
version: '1.1.0',
49+
package_url: 'pkg:hex/[email protected]',
50+
license: null,
51+
source_repository_url: null,
52+
scope: 'runtime',
53+
vulnerabilities: []
54+
},
55+
{
56+
change_type: 'added',
57+
manifest: 'python/dist-info/METADATA',
58+
ecosystem: 'pip',
59+
name: 'pygments',
60+
version: '2.6.1',
61+
package_url: 'pkg:pypi/[email protected]',
62+
license: 'BSD-2-Clause',
63+
source_repository_url: 'https://github.com/pygments/pygments',
64+
scope: 'runtime',
65+
vulnerabilities: []
66+
}
67+
]
68+
3069
test('prints headline as h1', () => {
3170
summary.addSummaryToSummary(
3271
emptyChanges,
@@ -65,6 +104,22 @@ test('only includes "No license issues found"-message if "vulnerability_check" i
65104
expect(text).toContain('✅ No license issues found.')
66105
})
67106

107+
test('groups dependencies with empty manifest paths together', () => {
108+
summary.addSummaryToSummary(
109+
changesWithEmptyManifests,
110+
emptyInvalidLicenseChanges,
111+
defaultConfig
112+
)
113+
summary.addScannedDependencies(changesWithEmptyManifests)
114+
const text = core.summary.stringify()
115+
116+
expect(text).toContain('<summary>Unnamed Manifest</summary>')
117+
expect(text).toContain('castore')
118+
expect(text).toContain('connection')
119+
expect(text).toContain('<summary>python/dist-info/METADATA</summary>')
120+
expect(text).toContain('pygments')
121+
})
122+
68123
test('does not include status section if nothing was found', () => {
69124
summary.addSummaryToSummary(
70125
emptyChanges,

__tests__/test-helpers.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// GitHub Action inputs come in the form of environment variables
2+
// with an INPUT prefix (e.g. INPUT_FAIL-ON-SEVERITY)
3+
export function setInput(input: string, value: string): void {
4+
process.env[`INPUT_${input.toUpperCase()}`] = value
5+
}
6+
7+
// We want a clean ENV before each test. We use `delete`
8+
// since we want `undefined` values and not empty strings.
9+
export function clearInputs(): void {
10+
const allowedOptions = [
11+
'FAIL-ON-SEVERITY',
12+
'FAIL-ON-SCOPES',
13+
'ALLOW-LICENSES',
14+
'DENY-LICENSES',
15+
'ALLOW-GHSAS',
16+
'LICENSE-CHECK',
17+
'VULNERABILITY-CHECK',
18+
'CONFIG-FILE',
19+
'BASE-REF',
20+
'HEAD-REF',
21+
'COMMENT-SUMMARY-IN-PR'
22+
]
23+
24+
// eslint-disable-next-line github/array-foreach
25+
allowedOptions.forEach(option => {
26+
delete process.env[`INPUT_${option.toUpperCase()}`]
27+
})
28+
}

action.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# Avoid using default values for options here since they will
2+
# end up overriding external configurations.
13
name: 'Dependency Review'
24
description: 'Prevent the introduction of dependencies with known vulnerabilities'
35
author: 'GitHub'
@@ -9,11 +11,9 @@ inputs:
911
fail-on-severity:
1012
description: Don't block PRs below this severity. Possible values are `low`, `moderate`, `high`, `critical`.
1113
required: false
12-
default: 'low'
1314
fail-on-scopes:
1415
description: Dependency scopes to block PRs on. Comma-separated list. Possible values are 'unknown', 'runtime', and 'development' (e.g. "runtime, development")
1516
required: false
16-
default: 'runtime'
1717
base-ref:
1818
description: The base git ref to be used for this check. Has a default value when the workflow event is `pull_request` or `pull_request_target`. Must be provided otherwise.
1919
required: false

0 commit comments

Comments
 (0)