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

Support user-provided base/head refs & non-PR workflows #200

Merged
merged 4 commits into from
Aug 18, 2022
Merged
Show file tree
Hide file tree
Changes from all 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
25 changes: 23 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# dependency-review-action

This action scans your pull requests for dependency changes and will raise an error if any new dependencies have existing vulnerabilities. The action is supported by an [API endpoint](https://docs.github.com/en/rest/reference/dependency-graph#dependency-review) that diffs the dependencies between any two revisions.
This action scans your pull requests for dependency changes, and will
raise an error if any vulnerabilities or invalid licenses are being introduced. The action is supported by an [API endpoint](https://docs.github.com/en/rest/reference/dependency-graph#dependency-review) that diffs the dependencies between any two revisions.

The action is available for all public repositories, as well as private repositories that have GitHub Advanced Security licensed.

<img width="854" alt="Screen Shot 2022-03-31 at 1 10 51 PM" src="https://user-images.githubusercontent.com/2161/161042286-b22d7dd3-13cb-458d-8744-ce70ed9bf562.png">


## Installation

**Please keep in mind that you need a [GitHub Advanced Security](https://docs.github.com/en/enterprise-cloud@latest/get-started/learning-about-github/about-github-advanced-security) license if you're running this action on private repositories.**
Expand Down Expand Up @@ -58,6 +58,7 @@ jobs:
```

## Configuration

You can pass additional options to the Dependency Review
Action using your workflow file. Here's an example workflow with
all the possible configurations:
Expand All @@ -79,6 +80,10 @@ jobs:
# Possible values: "critical", "high", "moderate", "low"
# fail-on-severity: critical
#
# Possible values: Any available git ref
# base-ref: ${{ github.event.pull_request.base.ref }}
# head-ref: ${{ github.event.pull_request.head.ref }}
#
# You can only include one of these two options: `allow-licenses` and `deny-licenses`. These options are not supported on GHES.
#
# Possible values: Any `spdx_id` value(s) from https://docs.github.com/en/rest/licenses
Expand All @@ -88,6 +93,11 @@ jobs:
# deny-licenses: LGPL-2.0, BSD-2-Clause
```

When the workflow with this action is caused by a `pull_request` or `pull_request_target` event,
the `base-ref` and `head-ref` values have the defaults as shown above. If the workflow is caused by
any other event, the `base-ref` and `head-ref` options must be
explicitly set in the configuration file.

### Vulnerability Severity

By default the action will fail on any pull request that contains a
Expand Down Expand Up @@ -134,6 +144,15 @@ to filter. A couple of examples:

**Important**

<<<<<<< HEAD
- The action will only accept one of the two parameters; an error will
be raised if you provide both.
- By default both parameters are empty (no license checking is
performed).
- 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**.
=======
* Checking for licenses is not supported on GHES.
* The action will only accept one of the two parameters; an error will
be raised if you provide both.
Expand All @@ -142,6 +161,7 @@ performed).
* 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**.
>>>>>>> main

## Blocking pull requests

Expand All @@ -159,4 +179,5 @@ We are grateful for any contributions made to this project.
Please read [CONTRIBUTING.MD](https://github.com/actions/dependency-review-action/blob/main/CONTRIBUTING.md) to get started.

## License

This project is released under the [MIT License](https://github.com/actions/dependency-review-action/blob/main/LICENSE).
37 changes: 34 additions & 3 deletions __tests__/config.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {expect, test, beforeEach} from '@jest/globals'
import {readConfig} from '../src/config'
import {getRefs} from '../src/git-refs'

// GitHub Action inputs come in the form of environment variables
// with an INPUT prefix (e.g. INPUT_FAIL-ON-SEVERITY)
Expand All @@ -10,9 +11,17 @@ function setInput(input: string, value: string) {
// We want a clean ENV before each test. We use `delete`
// since we want `undefined` values and not empty strings.
function clearInputs() {
delete process.env['INPUT_FAIL-ON-SEVERITY']
delete process.env['INPUT_ALLOW-LICENSES']
delete process.env['INPUT_DENY-LICENSES']
const allowedOptions = [
'FAIL-ON-SEVERITY',
'ALLOW-LICENSES',
'DENY-LICENSES',
'BASE-REF',
'HEAD-REF'
]

allowedOptions.forEach(option => {
delete process.env[`INPUT_${option.toUpperCase()}`]
})
}

beforeEach(() => {
Expand Down Expand Up @@ -51,3 +60,25 @@ test('it raises an error when given an unknown severity', async () => {
setInput('fail-on-severity', 'zombies')
expect(() => readConfig()).toThrow()
})

test('it uses the given refs when the event is not a pull request', async () => {
setInput('base-ref', 'a-custom-base-ref')
setInput('head-ref', 'a-custom-head-ref')

const refs = getRefs(readConfig(), {
payload: {},
eventName: 'workflow_dispatch'
})
expect(refs.base).toEqual('a-custom-base-ref')
expect(refs.head).toEqual('a-custom-head-ref')
})

test('it raises an error when no refs are provided and the event is not a pull request', async () => {
const options = readConfig()
expect(() =>
getRefs(options, {
payload: {},
eventName: 'workflow_dispatch'
})
).toThrow()
})
6 changes: 6 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ inputs:
description: Don't block PRs below this severity. Possible values are `low`, `moderate`, `high`, `critical`.
required: false
default: 'low'
base-ref:
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.
required: false
head-ref:
description: The head 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.
required: false
allow-licenses:
description: Comma-separated list of allowed licenses (e.g. "MIT, GPL 3.0, BSD 2 Clause")
required: false
Expand Down
68 changes: 57 additions & 11 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.

7 changes: 6 additions & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,14 @@ export function readConfig(): ConfigurationOptions {
throw new Error("Can't specify both allow_licenses and deny_licenses")
}

const base_ref = getOptionalInput('base-ref')
const head_ref = getOptionalInput('head-ref')

return {
fail_on_severity,
allow_licenses: allow_licenses?.split(',').map(x => x.trim()),
deny_licenses: deny_licenses?.split(',').map(x => x.trim())
deny_licenses: deny_licenses?.split(',').map(x => x.trim()),
base_ref,
head_ref
}
}
42 changes: 42 additions & 0 deletions src/git-refs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import {PullRequestSchema, ConfigurationOptions} from './schemas'

export function getRefs(
config: ConfigurationOptions,
context: {payload: {pull_request?: unknown}; eventName: string}
): {base: string; head: string} {
let base_ref = config.base_ref
let head_ref = config.head_ref

// If possible, source default base & head refs from the GitHub event.
// The base/head ref from the config take priority, if provided.
if (
context.eventName === 'pull_request' ||
context.eventName === 'pull_request_target'
) {
const pull_request = PullRequestSchema.parse(context.payload.pull_request)
base_ref = base_ref || pull_request.base.sha
head_ref = head_ref || pull_request.head.sha
}

if (!base_ref && !head_ref) {
throw new Error(
'Both a base ref and head ref must be provided, either via the `base_ref`/`head_ref` ' +
'config options, or by running a `pull_request`/`pull_request_target` workflow.'
)
} else if (!base_ref) {
throw new Error(
'A base ref must be provided, either via the `base_ref` config option, ' +
'or by running a `pull_request`/`pull_request_target` workflow.'
)
} else if (!head_ref) {
throw new Error(
'A head ref must be provided, either via the `head_ref` config option, ' +
'or by running a `pull_request`/`pull_request_target` workflow.'
)
}

return {
base: base_ref,
head: head_ref
}
}
19 changes: 6 additions & 13 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,24 @@ import * as dependencyGraph from './dependency-graph'
import * as github from '@actions/github'
import styles from 'ansi-styles'
import {RequestError} from '@octokit/request-error'
import {Change, PullRequestSchema, Severity} from './schemas'
import {Change, Severity} from './schemas'
import {readConfig} from '../src/config'
import {filterChangesBySeverity} from '../src/filter'
import {getDeniedLicenseChanges} from './licenses'
import {getRefs} from './git-refs'

async function run(): Promise<void> {
try {
if (github.context.eventName !== 'pull_request') {
throw new Error(
`This run was triggered by the "${github.context.eventName}" event, which is unsupported. Please ensure you are using the "pull_request" event for this workflow.`
)
}

const pull_request = PullRequestSchema.parse(
github.context.payload.pull_request
)
const config = readConfig()
const refs = getRefs(config, github.context)

const changes = await dependencyGraph.compare({
owner: github.context.repo.owner,
repo: github.context.repo.repo,
baseRef: pull_request.base.sha,
headRef: pull_request.head.sha
baseRef: refs.base,
headRef: refs.head
})

const config = readConfig()
const minSeverity = config.fail_on_severity
let failed = false

Expand Down
4 changes: 3 additions & 1 deletion src/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ export const ConfigurationOptionsSchema = z
.object({
fail_on_severity: z.enum(SEVERITIES).default('low'),
allow_licenses: z.array(z.string()).default([]),
deny_licenses: z.array(z.string()).default([])
deny_licenses: z.array(z.string()).default([]),
base_ref: z.string(),
head_ref: z.string()
})
.partial()
.refine(
Expand Down