Skip to content

Commit

Permalink
Bypass purls (mostly) for deny checks
Browse files Browse the repository at this point in the history
  • Loading branch information
juxtin committed Apr 26, 2024
1 parent 7e773b1 commit 1e3e4d6
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 41 deletions.
122 changes: 102 additions & 20 deletions dist/index.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

10 changes: 9 additions & 1 deletion src/config.ts
Expand Up @@ -233,7 +233,7 @@ function validatePURL(allow_dependencies_licenses: string[] | undefined): void {
return
}
const invalid_purls = allow_dependencies_licenses.filter(
purl => !PackageURL.fromString(purl)
purl => !isPURLValid(purl)
)

if (invalid_purls.length > 0) {
Expand All @@ -243,3 +243,11 @@ function validatePURL(allow_dependencies_licenses: string[] | undefined): void {
}
return
}

const isPURLValid = (purl: string): boolean => {
try {
return PackageURL.fromString(purl) !== null
} catch (error) {
return false
}
}
47 changes: 33 additions & 14 deletions src/deny.ts
@@ -1,6 +1,7 @@
import * as core from '@actions/core'
import {Change} from './schemas'
import {PackageURL} from 'packageurl-js'
import {parsePURL} from './utils'

export async function getDeniedChanges(
changes: Change[],
Expand All @@ -11,29 +12,19 @@ export async function getDeniedChanges(

let hasDeniedPackage = false
for (const change of changes) {
let changedPackage: PackageURL
try {
changedPackage = PackageURL.fromString(change.package_url)
} catch (error) {
core.error(`Error parsing package URL '${change.package_url}': ${error}`)
continue
}

for (const denied of deniedPackages) {
if (
(!denied.version || changedPackage.version === denied.version) &&
changedPackage.name === denied.name
(!denied.version || change.version === denied.version) &&
change.name === denied.name
) {
changesDenied.push(change)
hasDeniedPackage = true
}
}

for (const denied of deniedGroups) {
if (
changedPackage.namespace &&
changedPackage.namespace === denied.namespace
) {
const namespace = getNamespace(change)
if (namespace && namespace === denied.namespace) {
changesDenied.push(change)
hasDeniedPackage = true
}
Expand All @@ -48,3 +39,31 @@ export async function getDeniedChanges(

return changesDenied
}

// getNamespace returns the namespace associated with the given change.
// it tries to get this from the package_url member, but that won't exist
// for all changes, so as a fallback it may create a new purl based on the
// ecosystem and name associated with the change, then extract the namespace
// from that.
// returns '' if there is no namespace.
export const getNamespace = (change: Change): string => {
let purl_str: string
if (change.package_url) {
purl_str = change.package_url
} else {
purl_str = `pkg:${change.ecosystem}/${change.name}`
}

try {
const purl = parsePURL(purl_str)
const namespace = purl.namespace
if (namespace === undefined || namespace === null) {
return ''
} else {
return namespace
}
} catch (e) {
core.error(`Error parsing purl '${purl_str}': ${e}`)
return ''
}
}
6 changes: 2 additions & 4 deletions src/licenses.ts
@@ -1,6 +1,6 @@
import spdxSatisfies from 'spdx-satisfies'
import {Change, Changes} from './schemas'
import {isSPDXValid, octokitClient} from './utils'
import {isSPDXValid, octokitClient, parsePURL} from './utils'
import {PackageURL} from 'packageurl-js'

/**
Expand Down Expand Up @@ -45,9 +45,7 @@ export async function getInvalidLicenseChanges(
return true
}

const changeAsPackageURL = PackageURL.fromString(
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
// If it does, we want to filter it out and therefore return false
Expand Down
29 changes: 28 additions & 1 deletion src/utils.ts
Expand Up @@ -80,10 +80,37 @@ export const parsePURL = (purlString: string): PackageURL => {
) {
//packageurl-js does not support empty names, so will manually override it for deny-groups
//https://github.com/package-url/packageurl-js/blob/master/src/package-url.js#L216
const purl = PackageURL.fromString(`${purlString}TEMP_NAME`)
const fixedPurlString = addTempName(purlString)
const purl = parsePURL(fixedPurlString)
purl.name = ''
return purl
} else if ((error as Error).message === `version must be percent-encoded`) {
core.error(
`Version must be percent-encoded. Removing version from purl: '${purlString}.`
)
const fixedPurlString = removeVersion(purlString)
const purl = PackageURL.fromString(fixedPurlString)
purl.version = ''
return purl
}
core.error(`Error parsing purl: ${purlString}`)
throw error
}
}

export const removeVersion = (purlString: string): string => {
const idx = purlString.lastIndexOf('@')
let noVersion = purlString.substring(0, idx)
// Sometimes these errors are actually caused by a final `/`, so let's discard that as well.
if (noVersion.endsWith('/')) {
noVersion = noVersion.substring(0, noVersion.length - 1)
}
return noVersion
}

export const addTempName = (purlString: string): string => {
if (purlString.endsWith('/')) {
return `${purlString}TEMP_NAME`
}
return `${purlString}/TEMP_NAME`
}

0 comments on commit 1e3e4d6

Please sign in to comment.