Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exclude dependencies from license checks #423

Merged
merged 24 commits into from May 31, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
30 changes: 17 additions & 13 deletions README.md
Expand Up @@ -66,19 +66,22 @@ jobs:

Configure this action by either inlining these options in your workflow file, or by using an external configuration file. All configuration options are optional.

| Option | Usage | Possible values | Default value |
| ----------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ------------- |
| `fail-on-severity` | Defines the threshold for the level of severity. The action will fail on any pull requests that introduce vulnerabilities of the specified severity level or higher. | `low`, `moderate`, `high`, `critical` | `low` |
| `allow-licenses`* | Contains a list of allowed licenses. The action will fail on pull requests that introduce dependencies with licenses that do not match the list. | Any [SPDX-compliant identifier(s)](https://spdx.org/licenses/) | none |
| `deny-licenses`* | Contains a list of prohibited licenses. The action will fail on pull requests that introduce dependencies with licenses that match the list. | Any [SPDX-compliant identifier(s)](https://spdx.org/licenses/) | none |
| `fail-on-scopes`† | Contains a list of strings of the build environments you want to support. The action will fail on pull requests that introduce vulnerabilities in the scopes that match the list. | `runtime`, `development`, `unknown` | `runtime` |
| `allow-ghsas` | Contains a list of GitHub Advisory Database IDs that can be skipped during detection. | Any GHSAs from the [GitHub Advisory Database](https://github.com/advisories) | none |
| `license-check` | Enable or disable the license check performed by the action. | `true`, `false` | `true` |
| `vulnerability-check` | Enable or disable the vulnerability check performed by the action. | `true`, `false` | `true` |
| `base-ref`/`head-ref` | Provide custom git references for the git base/head when performing the comparison check. This is only used for event types other than `pull_request` and `pull_request_target`. | Any valid git ref(s) in your project | none |
| `comment-summary-in-pr` | Enable or disable reporting the review summary as a comment in the pull request. If enabled, you must give the workflow or job permission `pull-requests: write`. | `true`, `false` | `false` |

*not supported for use with GitHub Enterprise Server
| Option | Usage | Possible values | Default value |
| --------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ------------- |
| `fail-on-severity` | Defines the threshold for the level of severity. The action will fail on any pull requests that introduce vulnerabilities of the specified severity level or higher. | `low`, `moderate`, `high`, `critical` | `low` |
| `allow-licenses`\* | Contains a list of allowed licenses. The action will fail on pull requests that introduce dependencies with licenses that do not match the list. | Any [SPDX-compliant identifier(s)](https://spdx.org/licenses/) | none |
| `deny-licenses`\* | Contains a list of prohibited licenses. The action will fail on pull requests that introduce dependencies with licenses that match the list. | Any [SPDX-compliant identifier(s)](https://spdx.org/licenses/) | none |
| `fail-on-scopes`† | Contains a list of strings of the build environments you want to support. The action will fail on pull requests that introduce vulnerabilities in the scopes that match the list. | `runtime`, `development`, `unknown` | `runtime` |
| `allow-ghsas` | Contains a list of GitHub Advisory Database IDs that can be skipped during detection. | Any GHSAs from the [GitHub Advisory Database](https://github.com/advisories) | none |
| `license-check` | Enable or disable the license check performed by the action. | `true`, `false` | `true` |
| `vulnerability-check` | Enable or disable the vulnerability check performed by the action. | `true`, `false` | `true` |
| `allow-dependencies-licenses`\*\* | Containts excluded packages per ecosystem for the licenses checks. | `ecosystemName: pkgName1, pkgName2` | none |
theztefan marked this conversation as resolved.
Show resolved Hide resolved
| `base-ref`/`head-ref` | Provide custom git references for the git base/head when performing the comparison check. This is only used for event types other than `pull_request` and `pull_request_target`. | Any valid git ref(s) in your project | none |
| `comment-summary-in-pr` | Enable or disable reporting the review summary as a comment in the pull request. If enabled, you must give the workflow or job permission `pull-requests: write`. | `true`, `false` | `false` |

\*not supported for use with GitHub Enterprise Server

\*\*not supported for use with GitHub Enterprise Server and configuration must be provided in external configuration file

†will be supported with GitHub Enterprise Server 3.8

Expand Down Expand Up @@ -143,6 +146,7 @@ allow-licenses:
- Checking for licenses is not supported on Enterprise Server.
- The action will only accept one of the two `license` parameters; an error will be raised if you provide both.
- We don't have license information for all of your dependents. If we can't detect the license for a dependency **we will inform you, but the action won't fail**.
- The `allow-dependencies-licenses` option cannot be configured with inline configurations. It must be configured using the `config-file`.

## Blocking pull requests

Expand Down
54 changes: 49 additions & 5 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.

1 change: 1 addition & 0 deletions package-lock.json

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

4 changes: 4 additions & 0 deletions scripts/create_summary.ts
Expand Up @@ -22,6 +22,10 @@ const defaultConfig: ConfigurationOptions = {
allow_ghsas: [],
allow_licenses: ['MIT'],
deny_licenses: [],
allow_dependencies_licenses: {
npm: ['pkg1'],
pip: ['pkg2']
},
comment_summary_in_pr: true
}

Expand Down
16 changes: 15 additions & 1 deletion src/config.ts
Expand Up @@ -130,7 +130,8 @@ function parseConfigFile(configData: string): ConfigurationOptionsPartial {
'allow-licenses',
'deny-licenses',
'fail-on-scopes',
'allow-ghsas'
'allow-ghsas',
'allow-dependencies-licenses'
]

for (const key of Object.keys(data)) {
Expand All @@ -149,6 +150,19 @@ function parseConfigFile(configData: string): ConfigurationOptionsPartial {
validateLicenses(key, data[key])
}

// parse the allow-dependencies-licenses configs value
// per-ecosystem: ['pkg1', 'pkg2']
if (key === 'allow-dependencies-licenses') {
const val = data[key]
for (const ecosystem of Object.keys(val)) {
const pkgs = val[ecosystem]
if (typeof pkgs === 'string') {
val[ecosystem] = pkgs.split(',').map(x => x.trim())
}
}
data[key] = val
}

// get rid of the ugly dashes from the actions conventions
if (key.includes('-')) {
data[key.replace(/-/g, '_')] = data[key]
Expand Down
15 changes: 13 additions & 2 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, isDefined} from './utils'

/**
* Loops through a list of changes, filtering and returning the
Expand All @@ -24,11 +24,22 @@ export async function getInvalidLicenseChanges(
licenses: {
allow?: string[]
deny?: string[]
exception?: Record<string, string[]>
}
): Promise<InvalidLicenseChanges> {
const {allow, deny} = licenses
const {allow, deny, exception} = licenses
febuiles marked this conversation as resolved.
Show resolved Hide resolved

const groupedChanges = await groupChanges(changes)
// filter out changes that are part of exclusions list - config.allow_license_exceptions
groupedChanges.licensed = groupedChanges.licensed.filter(change => {
if (
isDefined(exception) &&
exception[change.ecosystem].includes(change.name)
) {
return false
}
return true
febuiles marked this conversation as resolved.
Show resolved Hide resolved
})
const licensedChanges: Changes = groupedChanges.licensed

const invalidLicenseChanges: InvalidLicenseChanges = {
Expand Down
3 changes: 2 additions & 1 deletion src/main.ts
Expand Up @@ -55,7 +55,8 @@ async function run(): Promise<void> {
filteredChanges,
{
allow: config.allow_licenses,
deny: config.deny_licenses
deny: config.deny_licenses,
exception: config.allow_dependencies_licenses
}
)

Expand Down
3 changes: 3 additions & 0 deletions src/schemas.ts
Expand Up @@ -40,6 +40,9 @@ export const ConfigurationOptionsSchema = z
fail_on_scopes: z.array(z.enum(SCOPES)).default(['runtime']),
allow_licenses: z.array(z.string()).optional(),
deny_licenses: z.array(z.string()).optional(),
allow_dependencies_licenses: z
.record(z.string(), z.array(z.string()))
.optional(),
allow_ghsas: z.array(z.string()).default([]),
license_check: z.boolean().default(true),
vulnerability_check: z.boolean().default(true),
Expand Down
11 changes: 11 additions & 0 deletions src/summary.ts
Expand Up @@ -143,6 +143,17 @@ export function addLicensesToSummary(
`<strong>Denied Licenses</strong>: ${config.deny_licenses.join(', ')}`
)
}
if (config.allow_dependencies_licenses) {
core.summary.addHeading('Allowed licensing exceptions', 3)

for (const [ecosystem, dependencies] of Object.entries(
config.allow_dependencies_licenses
)) {
core.summary.addRaw(
`<li> ${ecosystem}</strong>: ${dependencies.join(', ')} </li>`
)
}
}

core.debug(
`found ${invalidLicenseChanges.unlicensed.length} unknown licenses`
Expand Down
5 changes: 5 additions & 0 deletions src/utils.ts
Expand Up @@ -41,6 +41,11 @@ export function isSPDXValid(license: string): boolean {
}
}

// function to check if a value is not null or undefined
export function isDefined<T>(value: T | null | undefined): value is T {
return value !== null && value !== undefined
}

theztefan marked this conversation as resolved.
Show resolved Hide resolved
function isEnterprise(): boolean {
const serverUrl = new URL(
process.env['GITHUB_SERVER_URL'] ?? 'https://github.com'
Expand Down