Merge pull request #181 from tspascoal/add-summary

Show vulnerabities and license information on the job summary.
This commit is contained in:
Federico Builes
2022-08-18 16:14:27 +02:00
committed by GitHub
5 changed files with 14347 additions and 14021 deletions

View File

@@ -5,8 +5,14 @@ raise an error if any vulnerabilities or invalid licenses are being introduced.
The action is available for all public repositories, as well as private repositories that have GitHub Advanced Security licensed.
You can see the results on the job logs
<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">
or on the job summary
<img src="https://user-images.githubusercontent.com/7847935/182871416-50332bbb-b279-4621-a136-ca72a4314301.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.**
@@ -144,15 +150,6 @@ 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.
@@ -161,7 +158,6 @@ 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

28156
dist/index.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/index.js.map generated vendored

File diff suppressed because one or more lines are too long

View File

@@ -7,8 +7,10 @@ import {Change, Severity} from './schemas'
import {readConfig} from '../src/config'
import {filterChangesBySeverity} from '../src/filter'
import {getDeniedLicenseChanges} from './licenses'
import * as summary from './summary'
import {getRefs} from './git-refs'
async function run(): Promise<void> {
try {
const config = readConfig()
@@ -29,27 +31,32 @@ async function run(): Promise<void> {
deny: config.deny_licenses
}
const filteredChanges = filterChangesBySeverity(
const addedChanges = filterChangesBySeverity(
minSeverity as Severity,
changes
)
for (const change of filteredChanges) {
if (
).filter(
change =>
change.change_type === 'added' &&
change.vulnerabilities !== undefined &&
change.vulnerabilities.length > 0
) {
printChangeVulnerabilities(change)
failed = true
}
}
)
const [licenseErrors, unknownLicenses] = getDeniedLicenseChanges(
changes,
licenses
)
summary.addSummaryToSummary(addedChanges, licenseErrors, unknownLicenses)
if (addedChanges.length > 0) {
for (const change of addedChanges) {
printChangeVulnerabilities(change)
}
failed = true
}
summary.addChangeVulnerabilitiesToSummary(addedChanges, minSeverity || '')
if (licenseErrors.length > 0) {
printLicensesError(licenseErrors)
core.setFailed('Dependency review detected incompatible licenses.')
@@ -57,6 +64,8 @@ async function run(): Promise<void> {
printNullLicenses(unknownLicenses)
summary.addLicensesToSummary(licenseErrors, unknownLicenses, config)
if (failed) {
core.setFailed('Dependency review detected vulnerable packages.')
} else {
@@ -80,6 +89,8 @@ async function run(): Promise<void> {
core.setFailed('Unexpected fatal error')
}
}
} finally {
await core.summary.write()
}
}

163
src/summary.ts Normal file
View File

@@ -0,0 +1,163 @@
import * as core from '@actions/core'
import {ConfigurationOptions, Change, Changes} from './schemas'
import {SummaryTableRow} from '@actions/core/lib/summary'
export function addSummaryToSummary(
addedPackages: Changes,
licenseErrors: Change[],
unknownLicenses: Change[]
): void {
core.summary
.addHeading('Dependency Review')
.addRaw(
`We found ${addedPackages.length} vulnerable package(s), ${licenseErrors.length} package(s) with incompatible licenses, and ${unknownLicenses.length} package(s) with unknown licenses.`
)
}
export function addChangeVulnerabilitiesToSummary(
addedPackages: Changes,
severity: string
): void {
const rows: SummaryTableRow[] = []
const manifests = getManifests(addedPackages)
core.summary
.addHeading('Vulnerabilities')
.addQuote(
`Vulnerabilites were filtered by mininum severity <strong>${severity}</strong>.`
)
if (addedPackages.length === 0) {
core.summary.addQuote('No vulnerabilities found in added packages.')
return
}
for (const manifest of manifests) {
for (const change of addedPackages.filter(
pkg => pkg.manifest === manifest
)) {
let previous_package = ''
let previous_version = ''
for (const vuln of change.vulnerabilities) {
const sameAsPrevious =
previous_package === change.name &&
previous_version === change.version
if (!sameAsPrevious) {
rows.push([
renderUrl(change.source_repository_url, change.name),
change.version,
renderUrl(vuln.advisory_url, vuln.advisory_summary),
vuln.severity
])
} else {
rows.push([
{data: '', colspan: '2'},
renderUrl(vuln.advisory_url, vuln.advisory_summary),
vuln.severity
])
}
previous_package = change.name
previous_version = change.version
}
}
core.summary.addHeading(`<em>${manifest}</em>`, 3).addTable([
[
{data: 'Name', header: true},
{data: 'Version', header: true},
{data: 'Vulnerability', header: true},
{data: 'Severity', header: true}
],
...rows
])
}
}
export function addLicensesToSummary(
licenseErrors: Change[],
unknownLicenses: Change[],
config: ConfigurationOptions
): void {
core.summary.addHeading('Licenses')
if (config.allow_licenses && config.allow_licenses.length > 0) {
core.summary.addQuote(
`<strong>Allowed Licenses</strong>: ${config.allow_licenses.join(', ')}`
)
}
if (config.deny_licenses && config.deny_licenses.length > 0) {
core.summary.addQuote(
`<strong>Denied Licenses</strong>: ${config.deny_licenses.join(', ')}`
)
}
if (licenseErrors.length === 0 && unknownLicenses.length === 0) {
core.summary.addQuote('No license violations detected.')
return
}
if (licenseErrors.length > 0) {
const rows: SummaryTableRow[] = []
const manifests = getManifests(licenseErrors)
core.summary.addHeading('Incompatible Licenses', 3).addSeparator()
for (const manifest of manifests) {
core.summary.addHeading(`<em>${manifest}</em>`, 4)
for (const change of licenseErrors.filter(
pkg => pkg.manifest === manifest
)) {
rows.push([
renderUrl(change.source_repository_url, change.name),
change.version,
change.license || ''
])
}
core.summary.addTable([['Package', 'Version', 'License'], ...rows])
}
} else {
core.summary.addQuote('No license violations detected.')
}
core.debug(`found ${unknownLicenses.length} unknown licenses`)
if (unknownLicenses.length > 0) {
const rows: SummaryTableRow[] = []
const manifests = getManifests(unknownLicenses)
core.debug(
`found ${manifests.entries.length} manifests for unknown licenses`
)
core.summary.addHeading('Unknown Licenses', 3).addSeparator()
for (const manifest of manifests) {
core.summary.addHeading(`<em>${manifest}</em>`, 4)
for (const change of unknownLicenses.filter(
pkg => pkg.manifest === manifest
)) {
rows.push([
renderUrl(change.source_repository_url, change.name),
change.version
])
}
core.summary.addTable([['Package', 'Version'], ...rows])
}
}
}
function getManifests(changes: Changes): Set<string> {
return new Set(changes.flatMap(c => c.manifest))
}
function renderUrl(url: string | null, text: string): string {
if (url) {
return `<a href="${url}">${text}</a>`
} else {
return text
}
}