update licenses pkg and tests

This commit is contained in:
Eli Reisman
2024-06-05 23:38:18 -07:00
parent 3fc792b939
commit dfbe08e4d2
4 changed files with 62 additions and 42 deletions
+29 -30
View File
@@ -1,7 +1,6 @@
import {expect, jest, test} from '@jest/globals' import {expect, jest, test} from '@jest/globals'
import {Change, Changes} from '../src/schemas' import {Change, Changes} from '../src/schemas'
import {getInvalidLicenseChanges} from '../src/licenses'
let getInvalidLicenseChanges: Function
const npmChange: Change = { const npmChange: Change = {
manifest: 'package.json', manifest: 'package.json',
@@ -30,7 +29,7 @@ const rubyChange: Change = {
name: 'actionsomething', name: 'actionsomething',
version: '3.2.0', version: '3.2.0',
package_url: 'pkg:gem/[email protected]', package_url: 'pkg:gem/[email protected]',
license: 'BSD', license: 'BSD-3-Clause',
source_repository_url: 'github.com/some-repo', source_repository_url: 'github.com/some-repo',
scope: 'runtime', scope: 'runtime',
vulnerabilities: [ vulnerabilities: [
@@ -100,29 +99,32 @@ jest.mock('octokit', () => {
beforeEach(async () => { beforeEach(async () => {
jest.resetModules() jest.resetModules()
jest.doMock('spdx-satisfies', () => {
// mock spdx-satisfies return value
// true for BSD, false for all others
return jest.fn((license: string, _: string): boolean => license === 'BSD')
})
// eslint-disable-next-line @typescript-eslint/no-require-imports
;({getInvalidLicenseChanges} = require('../src/licenses'))
}) })
test('it adds license outside the allow list to forbidden changes', async () => { test('it adds license outside the allow list to forbidden changes', async () => {
const changes: Changes = [npmChange, rubyChange] const changes: Changes = [
npmChange, // MIT license
rubyChange // BSD license
]
const {forbidden} = await getInvalidLicenseChanges(changes, { const {forbidden} = await getInvalidLicenseChanges(changes, {
allow: ['BSD'] allow: ['BSD-3-Clause']
}) })
expect(forbidden[0]).toBe(npmChange) expect(forbidden[0]).toBe(npmChange)
expect(forbidden.length).toEqual(1) expect(forbidden.length).toEqual(1)
}) })
test('it adds license inside the deny list to forbidden changes', async () => { test('it adds license inside the deny list to forbidden changes', async () => {
const changes: Changes = [npmChange, rubyChange] const changes: Changes = [
npmChange, // MIT license
rubyChange // BSD license
]
const {forbidden} = await getInvalidLicenseChanges(changes, { const {forbidden} = await getInvalidLicenseChanges(changes, {
deny: ['BSD'] deny: ['BSD-3-Clause']
}) })
expect(forbidden[0]).toBe(rubyChange) expect(forbidden[0]).toBe(rubyChange)
expect(forbidden.length).toEqual(1) expect(forbidden.length).toEqual(1)
}) })
@@ -133,7 +135,7 @@ test('it does not add license outside the allow list to forbidden changes if it
{...rubyChange, change_type: 'removed'} {...rubyChange, change_type: 'removed'}
] ]
const {forbidden} = await getInvalidLicenseChanges(changes, { const {forbidden} = await getInvalidLicenseChanges(changes, {
allow: ['BSD'] allow: ['BSD-3-Clause']
}) })
expect(forbidden).toStrictEqual([]) expect(forbidden).toStrictEqual([])
}) })
@@ -144,7 +146,7 @@ test('it does not add license inside the deny list to forbidden changes if it is
{...rubyChange, change_type: 'removed'} {...rubyChange, change_type: 'removed'}
] ]
const {forbidden} = await getInvalidLicenseChanges(changes, { const {forbidden} = await getInvalidLicenseChanges(changes, {
deny: ['BSD'] deny: ['BSD-3-Clause']
}) })
expect(forbidden).toStrictEqual([]) expect(forbidden).toStrictEqual([])
}) })
@@ -156,23 +158,18 @@ test('it adds license outside the allow list to forbidden changes if it is in bo
{...rubyChange, change_type: 'removed'} {...rubyChange, change_type: 'removed'}
] ]
const {forbidden} = await getInvalidLicenseChanges(changes, { const {forbidden} = await getInvalidLicenseChanges(changes, {
allow: ['BSD'] allow: ['BSD-3-Clause']
}) })
expect(forbidden).toStrictEqual([npmChange]) expect(forbidden).toStrictEqual([npmChange])
}) })
test('it adds all licenses to unresolved if it is unable to determine the validity', async () => { test('it adds all licenses to unresolved if it is unable to determine the validity', async () => {
jest.resetModules() // reset module set in before const changes: Changes = [
jest.doMock('spdx-satisfies', () => { {...npmChange, license: 'Foo'},
return jest.fn((_first: string, _second: string) => { {...rubyChange, license: 'Bar'}
throw new Error('Some Error') ]
})
})
// eslint-disable-next-line @typescript-eslint/no-require-imports
;({getInvalidLicenseChanges} = require('../src/licenses'))
const changes: Changes = [npmChange, rubyChange]
const invalidLicenses = await getInvalidLicenseChanges(changes, { const invalidLicenses = await getInvalidLicenseChanges(changes, {
allow: ['BSD'] allow: ['Apache-2.0']
}) })
expect(invalidLicenses.forbidden.length).toEqual(0) expect(invalidLicenses.forbidden.length).toEqual(0)
expect(invalidLicenses.unlicensed.length).toEqual(0) expect(invalidLicenses.unlicensed.length).toEqual(0)
@@ -182,7 +179,7 @@ test('it adds all licenses to unresolved if it is unable to determine the validi
test('it does not filter out changes that are on the exclusions list', async () => { test('it does not filter out changes that are on the exclusions list', async () => {
const changes: Changes = [pipChange, npmChange, rubyChange] const changes: Changes = [pipChange, npmChange, rubyChange]
const licensesConfig = { const licensesConfig = {
allow: ['BSD'], allow: ['BSD-3-Clause'],
licenseExclusions: ['pkg:pypi/[email protected]', 'pkg:npm/[email protected]'] licenseExclusions: ['pkg:pypi/[email protected]', 'pkg:npm/[email protected]']
} }
const invalidLicenses = await getInvalidLicenseChanges( const invalidLicenses = await getInvalidLicenseChanges(
@@ -198,7 +195,7 @@ test('it does not fail when the packages dont have a valid PURL', async () => {
const changes: Changes = [emptyPurlChange, npmChange, rubyChange] const changes: Changes = [emptyPurlChange, npmChange, rubyChange]
const licensesConfig = { const licensesConfig = {
allow: ['BSD'], allow: ['BSD-3-Clause'],
licenseExclusions: ['pkg:pypi/[email protected]', 'pkg:npm/[email protected]'] licenseExclusions: ['pkg:pypi/[email protected]', 'pkg:npm/[email protected]']
} }
@@ -212,16 +209,18 @@ test('it does not fail when the packages dont have a valid PURL', async () => {
test('it does filters out changes if they are not on the exclusions list', async () => { test('it does filters out changes if they are not on the exclusions list', async () => {
const changes: Changes = [pipChange, npmChange, rubyChange] const changes: Changes = [pipChange, npmChange, rubyChange]
const licensesConfig = { const licensesConfig = {
allow: ['BSD'], allow: ['BSD-3-Clause'],
licenseExclusions: [ licenseExclusions: [
'pkg:pypi/[email protected]', 'pkg:pypi/[email protected]',
'pkg:npm/[email protected]' 'pkg:npm/[email protected]'
] ]
} }
const invalidLicenses = await getInvalidLicenseChanges( const invalidLicenses = await getInvalidLicenseChanges(
changes, changes,
licensesConfig licensesConfig
) )
expect(invalidLicenses.forbidden.length).toEqual(2) expect(invalidLicenses.forbidden.length).toEqual(2)
expect(invalidLicenses.forbidden[0]).toBe(pipChange) expect(invalidLicenses.forbidden[0]).toBe(pipChange)
expect(invalidLicenses.forbidden[1]).toBe(npmChange) expect(invalidLicenses.forbidden[1]).toBe(npmChange)
+7 -12
View File
@@ -1,8 +1,7 @@
import spdxSatisfies from 'spdx-satisfies'
import {Change, Changes} from './schemas' import {Change, Changes} from './schemas'
import {octokitClient} from './utils' import {octokitClient} from './utils'
import {parsePURL} from './purl' import {parsePURL} from './purl'
import {isValid} from './spdx' import * as spdx from './spdx'
/** /**
* Loops through a list of changes, filtering and returning the * Loops through a list of changes, filtering and returning the
@@ -48,7 +47,7 @@ export async function getInvalidLicenseChanges(
const changeAsPackageURL = parsePURL(encodeURI(change.package_url)) const changeAsPackageURL = parsePURL(encodeURI(change.package_url))
// We want to find if the licenseExclussion list contains the PackageURL of the Change // We want to find if the licenseExclusion list contains the PackageURL of the Change
// If it does, we want to filter it out and therefore return false // If it does, we want to filter it out and therefore return false
// If it doesn't, we want to keep it and therefore return true // If it doesn't, we want to keep it and therefore return true
if ( if (
@@ -88,15 +87,11 @@ export async function getInvalidLicenseChanges(
} else if (validityCache.get(license) === undefined) { } else if (validityCache.get(license) === undefined) {
try { try {
if (allow !== undefined) { if (allow !== undefined) {
const found = allow.find(spdxExpression => const found = spdx.satisfiesAny(license, allow)
spdxSatisfies(license, spdxExpression) validityCache.set(license, found)
)
validityCache.set(license, found !== undefined)
} else if (deny !== undefined) { } else if (deny !== undefined) {
const found = deny.find(spdxExpression => const found = spdx.satisfiesAny(license, deny)
spdxSatisfies(license, spdxExpression) validityCache.set(license, !found)
)
validityCache.set(license, found === undefined)
} }
} catch (err) { } catch (err) {
invalidLicenseChanges.unresolved.push(change) invalidLicenseChanges.unresolved.push(change)
@@ -166,7 +161,7 @@ const setGHLicenses = async (changes: Change[]): Promise<Change[]> => {
// Currently Dependency Graph licenses are truncated to 255 characters // Currently Dependency Graph licenses are truncated to 255 characters
// This possibly makes them invalid spdx ids // This possibly makes them invalid spdx ids
const truncatedDGLicense = (license: string): boolean => const truncatedDGLicense = (license: string): boolean =>
license.length === 255 && !isValid(license) license.length === 255 && !spdx.isValid(license)
async function groupChanges( async function groupChanges(
changes: Changes changes: Changes
+14
View File
@@ -8,6 +8,20 @@ export function satisfies(
return spdx.satisfies(candidateExpr, constraintExpr) return spdx.satisfies(candidateExpr, constraintExpr)
} }
export function satisfiesAny(
candidateExpr: string,
licenses: string[]
): boolean {
return spdx.satisfiesAny(candidateExpr, licenses)
}
export function satisfiesAll(
candidateExpr: string,
licenses: string[]
): boolean {
return spdx.satisfiesAll(candidateExpr, licenses)
}
// can be a single license or an SPDX expression // can be a single license or an SPDX expression
export function isValid(spdxExpr: string): boolean { export function isValid(spdxExpr: string): boolean {
try { try {
+12
View File
@@ -3,4 +3,16 @@ declare module '@onebeyond/spdx-license-satisfies' {
candidateExpr: string, candidateExpr: string,
constraintExpr: string constraintExpr: string
): boolean ): boolean
export function satisfiesAny(
candidateExpr: string,
licenses: string[]
): boolean
export function satisfiesAll(
candidateExpr: string,
licenses: string[]
): boolean
export function isValid(candidateExpr: string): boolean
} }