8000 Merge pull request #927 from dangoor/dangoor/multilicense · actions/dependency-review-action@8477905 · GitHub
[go: up one dir, main page]

Skip to content

Commit 8477905

Browse files
authored
Merge pull request #927 from dangoor/dangoor/multilicense
Handle complex licenses (e.g. X AND Y)
2 parents 5a5d4df + 2013ccc commit 8477905

File tree

10 files changed

+257
-169
lines changed

10 files changed

+257
-169
lines changed

__tests__/licenses.test.ts

Lines changed: 43 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const npmChange: Change = {
2121
}
2222
]
2323
}
24+
2425
const rubyChange: Change = {
2526
change_type: 'added',
2627
manifest: 'Gemfile.lock',
@@ -73,6 +74,32 @@ const pipChange: Change = {
7374
]
7475
}
7576

77+
const complexLicenseChange: Change = {
78+
change_type: 'added',
79+
manifest: 'requirements.txt',
80+
ecosystem: 'pip',
81+
name: 'package-1',
82+
version: '1.1.1',
83+
package_url: 'pkg:pypi/package-1@1.1.1',
84+
license: 'MIT AND Apache-2.0',
85+
source_repository_url: 'github.com/some-repo',
86+
scope: 'runtime',
87+
vulnerabilities: [
88+
{
89+
severity: 'moderate',
90+
advisory_ghsa_id: 'second-random_string',
91+
advisory_summary: 'not so dangerous',
92+
advisory_url: 'github.com/future-funk'
93+
},
94+
{
95+
severity: 'low',
96+
advisory_ghsa_id: 'third-random_string',
97+
advisory_summary: 'dont page me',
98+
advisory_url: 'github.com/future-funk'
99+
}
100+
]
101+
}
102+
76103
jest.mock('@actions/core')
77104

78105
const mockOctokit = {
@@ -100,130 +127,55 @@ beforeEach(async () => {
100127
jest.resetModules()
101128
})
102129

103-
test('it should handle SPDX expressions in allow-list that matches a single license project', async () => {
104-
const change: Change = getChangeWithLicense('MIT')
105-
const changes: Changes = [change]
106-
107-
const {forbidden} = await getInvalidLicenseChanges(changes, {
108-
allow: ['EPL-1.0 OR MIT']
109-
})
110-
111-
expect(forbidden).toStrictEqual([])
112-
})
113-
114-
test('it should handle SPDX expressions in allow-list with operators and a valid triple licensed project', async () => {
115-
const change: Change = getChangeWithLicense(
116-
'EPL-1.0 AND LGPL-2.1 AND LGPL-2.1-only'
117-
)
118-
const changes: Changes = [change]
119-
120-
const {forbidden} = await getInvalidLicenseChanges(changes, {
121-
allow: ['EPL-1.0 AND LGPL-2.1 AND LGPL-2.1-only']
122-
})
123-
124-
expect(forbidden).toStrictEqual([])
125-
})
126-
127-
test('it should handle a valid triple licensed project that does not have a match in the allow-list', async () => {
128-
const change = getChangeWithLicense('EPL-1.0 AND LGPL-2.1 AND LGPL-2.1-only')
129-
const changes: Changes = [change]
130-
131-
const {forbidden} = await getInvalidLicenseChanges(changes, {
132-
allow: ['EPL-1.0', 'LGPL-2.1', 'LGPL-2.1-only']
133-
})
134-
135-
expect(forbidden[0]).toBe(change)
136-
expect(forbidden.length).toEqual(1)
137-
})
138-
139-
test('it should handle license with OR SPDX expression and only match on one license in the allow-list', async () => {
140-
const change = getChangeWithLicense('EPL-1.0 OR LGPL-2.1')
141-
const changes: Changes = [change]
142-
143-
for (const allowedLicense of ['EPL-1.0', 'LGPL-2.1']) {
144-
const {forbidden} = await getInvalidLicenseChanges(changes, {
145-
allow: [allowedLicense]
146-
})
147-
148-
expect(forbidden).toStrictEqual([])
149-
}
150-
})
151-
152-
test('it should handle SPDX expressions in allow-list with operators when license matches', async () => {
153-
const changes: Changes = [
154-
npmChange // MIT license
155-
]
156-
157-
const {forbidden} = await getInvalidLicenseChanges(changes, {
158-
allow: ['MIT OR Apache-2.0', 'MIT', 'BSD-3-Clause']
159-
})
160-
161-
expect(forbidden).toStrictEqual([])
162-
})
163-
164-
test('it should handle SPDX expressions in allow-list with operators when license does not match', async () => {
130+
test('it adds license outside the allow list to forbidden changes', async () => {
165131
const changes: Changes = [
166-
npmChange // MIT license
132+
npmChange, // MIT license
133+
rubyChange // BSD license
167134
]
168135

169136
const {forbidden} = await getInvalidLicenseChanges(changes, {
170-
allow: ['MIT AND Apache-2.0', 'BSD-3-Clause']
137+
allow: ['BSD-3-Clause']
171138
})
172139

173140
expect(forbidden[0]).toBe(npmChange)
174141
expect(forbidden.length).toEqual(1)
175142
})
176143

177-
test('it should handle SPDX expressions in deny-list with operators when license matches deny list entry', async () => {
144+
test('it adds license inside the deny list to forbidden changes', async () => {
178145
const changes: Changes = [
179-
npmChange // MIT license
146+
npmChange, // MIT license
147+
rubyChange // BSD license
180148
]
181149

182150
const {forbidden} = await getInvalidLicenseChanges(changes, {
183-
deny: ['MIT OR Apache-2.0', 'BSD-3-Clause']
151+
deny: ['BSD-3-Clause']
184152
})
185153

186-
expect(forbidden[0]).toBe(npmChange)
154+
expect(forbidden[0]).toBe(rubyChange)
187155
expect(forbidden.length).toEqual(1)
188156
})
189157

190-
test('it should handle SPDX expressions in deny-list with operators when license does not match any deny list entry', async () => {
158+
test('it handles allowed complex licenses', async () => {
191159
const changes: Changes = [
192-
npmChange // MIT license
160+
complexLicenseChange // MIT AND Apache-2.0 license
193161
]
194162

195163
const {forbidden} = await getInvalidLicenseChanges(changes, {
196-
deny: ['MIT AND Apache-2.0', 'BSD-3-Clause']
164+
allow: ['MIT', 'Apache-2.0']
197165
})
198166

199-
expect(forbidden).toStrictEqual([])
167+
expect(forbidden.length).toEqual(0)
200168
})
201169

202-
test('it adds license outside the allow list to forbidden changes', async () => {
170+
test('it handles complex licenses not all on the allow list', async () => {
203171
const changes: Changes = [
204-
npmChange, // MIT license
205-
rubyChange // BSD license
206-
]
207-
208-
const {forbidden} = await getInvalidLicenseChanges(changes, {
209-
allow: ['BSD-3-Clause']
210-
})
211-
212-
expect(forbidden[0]).toBe(npmChange)
213-
expect(forbidden.length).toEqual(1)
214-
})
215-
216-
test('it adds license inside the deny list to forbidden changes', async () => {
217-
const changes: Changes = [
218-
npmChange, // MIT license
219-
rubyChange // BSD license
172+
complexLicenseChange // MIT AND Apache-2.0 license
220173
]
221174

222175
const {forbidden} = await getInvalidLicenseChanges(changes, {
223-
deny: ['BSD-3-Clause']
176+
allow: ['MIT']
224177
})
225178

226-
expect(forbidden[0]).toBe(rubyChange)
227179
expect(forbidden.length).toEqual(1)
228180
})
229181

@@ -362,25 +314,3 @@ describe('GH License API fallback', () => {
362314
expect(unlicensed.length).toEqual(0)
363315
})
364316
})
365-
366-
function getChangeWithLicense(license: string): Change {
367-
return {
368-
manifest: 'pom.xml',
369-
change_type: 'added',
370-
ecosystem: 'maven',
371-
name: 'dummy-library',
372-
version: '1.0.0',
373-
package_url: 'pkg:org.something:sdummy-library@1.0.0',
374-
license,
375-
source_repository_url: 'github.com/some-repo',
376-
scope: 'runtime',
377-
vulnerabilities: [
378-
{
379-
severity: 'critical',
380-
advisory_ghsa_id: 'first-random_string',
381-
advisory_summary: 'very dangerous',
382-
advisory_url: 'github.com/future-funk'
383-
}
384-
]
385-
}
386-
}

__tests__/spdx.test.ts

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -145,77 +145,77 @@ describe('satisfies', () => {
145145
const units = [
146146
{
147147
candidate: 'MIT',
148-
constraint: 'MIT',
148+
allowList: ['MIT'],
149149
expected: true
150150
},
151151
{
152152
candidate: 'Apache-2.0',
153-
constraint: 'MIT',
153+
allowList: ['MIT'],
154154
expected: false
155155
},
156156
{
157157
candidate: 'MIT OR Apache-2.0',
158-
constraint: 'MIT',
158+
allowList: ['MIT'],
159159
expected: true
160160
},
161161
{
162162
candidate: 'MIT OR Apache-2.0',
163-
constraint: 'Apache-2.0',
163+
allowList: ['Apache-2.0'],
164164
expected: true
165165
},
166166
{
167167
candidate: 'MIT OR Apache-2.0',
168-
constraint: 'BSD-3-Clause',
168+
allowList: ['BSD-3-Clause'],
169169
expected: false
170170
},
171171
{
172172
candidate: 'MIT OR Apache-2.0',
173-
constraint: 'Apache-2.0 OR BSD-3-Clause',
173+
allowList: ['Apache-2.0', 'BSD-3-Clause'],
174174
expected: true
175175
},
176176
{
177177
candidate: 'MIT AND Apache-2.0',
178-
constraint: 'MIT AND Apache-2.0',
178+
allowList: ['MIT', 'Apache-2.0'],
179179
expected: true
180180
},
181181
{
182182
candidate: 'MIT OR Apache-2.0',
183-
constraint: 'MIT AND Apache-2.0',
184-
expected: false
183+
allowList: ['MIT', 'Apache-2.0'],
184+
expected: true
185185
},
186186
{
187187
candidate: 'ISC OR (MIT AND Apache-2.0)',
188-
constraint: 'MIT AND Apache-2.0',
188+
allowList: ['MIT', 'Apache-2.0'],
189189
expected: true
190190
},
191191

192192
// missing params, case sensitivity, syntax problems,
193193
// or unknown licenses will return 'false'
194194
{
195195
candidate: 'MIT',
196-
constraint: 'MiT',
196+
allowList: ['MiT'],
197197
expected: false
198198
},
199199
{
200200
candidate: 'MIT AND (ISC OR',
201-
constraint: 'MIT',
201+
allowList: ['MIT'],
202202
expected: false
203203
},
204204
{
205205
candidate: 'MIT OR ISC OR Apache-2.0',
206-
constraint: '',
206+
allowList: [],
207207
expected: false
208208
},
209209
{
210210
candidate: '',
211-
constraint: '(BSD-3-Clause AND ISC) OR MIT',
211+
allowList: ['BSD-3-Clause', 'ISC', 'MIT'],
212212
expected: false
213213
}
214214
]
215215

216216
for (const unit of units) {
217-
const got: boolean = spdx.satisfies(unit.candidate, unit.constraint)
218-
test(`should return ${unit.expected} for ("${unit.candidate}", "${unit.constraint}")`, () => {
217+
const got: boolean = spdx.satisfies(unit.candidate, unit.allowList)
218+
test(`should return ${unit.expected} for ("${unit.candidate}", "${unit.allowList}")`, () => {
219219
expect(got).toBe(unit.expected)
220220
})
221221
}

0 commit comments

Comments
 (0)
0