Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ Dependency review action can create [outputs](https://docs.github.com/en/actions
- `vulnerable-changes` holds information about dependency changes with vulnerable dependencies in a JSON format.
- `invalid-license-changes` holds information about invalid or non-compliant license dependency changes in a JSON format.
- `denied-changes` holds information about denied dependency changes in a JSON format.
- `resolved-vulnerabilities` holds information about vulnerabilities that have been resolved by removing or upgrading packages in a JSON format.

> [!NOTE]
> Action outputs are unicode strings [with a 1MB size limit](https://docs.github.com/en/actions/creating-actions/metadata-syntax-for-github-actions#outputs-for-docker-container-and-javascript-actions).
Expand Down
122 changes: 122 additions & 0 deletions __tests__/resolved-vulnerabilities.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import {test, expect} from '@jest/globals'
import {getResolvedVulnerabilities} from '../src/resolved-vulnerabilities'
import {Changes, Change} from '../src/schemas'

const vulnerableRemovedChange: Change = {
change_type: 'removed',
manifest: 'package.json',
ecosystem: 'npm',
name: 'lodash',
version: '4.17.20',
package_url: 'pkg:npm/lodash@4.17.20',
license: 'MIT',
source_repository_url: 'https://github.com/lodash/lodash',
scope: 'runtime',
vulnerabilities: [
{
severity: 'high',
advisory_ghsa_id: 'GHSA-35jh-r3h4-6jhm',
advisory_summary: 'lodash Prototype Pollution vulnerability',
advisory_url: 'https://github.com/advisories/GHSA-35jh-r3h4-6jhm'
},
{
severity: 'critical',
advisory_ghsa_id: 'GHSA-p6mc-m468-83gw',
advisory_summary: 'lodash Command Injection via template',
advisory_url: 'https://github.com/advisories/GHSA-p6mc-m468-83gw'
}
]
}

const nonVulnerableRemovedChange: Change = {
change_type: 'removed',
manifest: 'package.json',
ecosystem: 'npm',
name: 'express',
version: '4.18.0',
package_url: 'pkg:npm/express@4.18.0',
license: 'MIT',
source_repository_url: 'https://github.com/expressjs/express',
scope: 'runtime',
vulnerabilities: []
}

const addedChange: Change = {
change_type: 'added',
manifest: 'package.json',
ecosystem: 'npm',
name: 'react',
version: '18.0.0',
package_url: 'pkg:npm/react@18.0.0',
license: 'MIT',
source_repository_url: 'https://github.com/facebook/react',
scope: 'runtime',
vulnerabilities: [
{
severity: 'moderate',
advisory_ghsa_id: 'GHSA-test-1234',
advisory_summary: 'Test vulnerability',
advisory_url: 'https://github.com/advisories/GHSA-test-1234'
}
]
}

test('extracts resolved vulnerabilities from removed packages', () => {
const changes: Changes = [
vulnerableRemovedChange,
nonVulnerableRemovedChange,
addedChange
]

const resolvedVulns = getResolvedVulnerabilities(changes)

expect(resolvedVulns).toHaveLength(2)

expect(resolvedVulns[0]).toEqual({
severity: 'high',
advisory_ghsa_id: 'GHSA-35jh-r3h4-6jhm',
advisory_summary: 'lodash Prototype Pollution vulnerability',
advisory_url: 'https://github.com/advisories/GHSA-35jh-r3h4-6jhm',
package_name: 'lodash',
package_version: '4.17.20',
package_url: 'pkg:npm/lodash@4.17.20',
manifest: 'package.json',
ecosystem: 'npm'
})

expect(resolvedVulns[1]).toEqual({
severity: 'critical',
advisory_ghsa_id: 'GHSA-p6mc-m468-83gw',
advisory_summary: 'lodash Command Injection via template',
advisory_url: 'https://github.com/advisories/GHSA-p6mc-m468-83gw',
package_name: 'lodash',
package_version: '4.17.20',
package_url: 'pkg:npm/lodash@4.17.20',
manifest: 'package.json',
ecosystem: 'npm'
})
})

test('returns empty array when no removed packages have vulnerabilities', () => {
const changes: Changes = [nonVulnerableRemovedChange, addedChange]

const resolvedVulns = getResolvedVulnerabilities(changes)

expect(resolvedVulns).toHaveLength(0)
})

test('ignores added packages with vulnerabilities', () => {
const changes: Changes = [addedChange]

const resolvedVulns = getResolvedVulnerabilities(changes)

expect(resolvedVulns).toHaveLength(0)
})

test('handles empty changes array', () => {
const changes: Changes = []

const resolvedVulns = getResolvedVulnerabilities(changes)

expect(resolvedVulns).toHaveLength(0)
})
15 changes: 14 additions & 1 deletion __tests__/summary.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {expect, jest, test} from '@jest/globals'
import {Changes, ConfigurationOptions, Scorecard} from '../src/schemas'
import {Changes, ConfigurationOptions, Scorecard, ResolvedVulnerabilities} from '../src/schemas'
import * as summary from '../src/summary'
import * as core from '@actions/core'
import {createTestChange} from './fixtures/create-test-change'
Expand All @@ -19,6 +19,7 @@ const emptyInvalidLicenseChanges = {
const emptyScorecard: Scorecard = {
dependencies: []
}
const emptyResolvedVulnerabilities: ResolvedVulnerabilities = []
const defaultConfig: ConfigurationOptions = {
vulnerability_check: true,
license_check: true,
Expand Down Expand Up @@ -102,6 +103,7 @@ test('prints headline as h1', () => {
emptyInvalidLicenseChanges,
emptyChanges,
scorecard,
emptyResolvedVulnerabilities,
defaultConfig
)
const text = core.summary.stringify()
Expand All @@ -115,6 +117,7 @@ test('does not add deprecation warning for deny-licenses option if not set', ()
emptyInvalidLicenseChanges,
emptyChanges,
scorecard,
emptyResolvedVulnerabilities,
defaultConfig
)
const text = core.summary.stringify()
Expand All @@ -130,6 +133,7 @@ test('adds deprecation warning for deny-licenses option if set', () => {
emptyInvalidLicenseChanges,
emptyChanges,
scorecard,
emptyResolvedVulnerabilities,
config
)
const text = core.summary.stringify()
Expand All @@ -155,6 +159,7 @@ test('returns minimal summary formatted for posting as a PR comment', () => {
emptyInvalidLicenseChanges,
emptyChanges,
scorecard,
emptyResolvedVulnerabilities,
defaultConfig
)

Expand All @@ -181,6 +186,7 @@ test('only includes "No vulnerabilities or license issues found"-message if both
emptyInvalidLicenseChanges,
emptyChanges,
emptyScorecard,
emptyResolvedVulnerabilities,
defaultConfig
)
const text = core.summary.stringify()
Expand All @@ -195,6 +201,7 @@ test('only includes "No vulnerabilities found"-message if "license_check" is set
emptyInvalidLicenseChanges,
emptyChanges,
emptyScorecard,
emptyResolvedVulnerabilities,
config
)
const text = core.summary.stringify()
Expand All @@ -209,6 +216,7 @@ test('only includes "No license issues found"-message if "vulnerability_check" i
emptyInvalidLicenseChanges,
emptyChanges,
emptyScorecard,
emptyResolvedVulnerabilities,
config
)
const text = core.summary.stringify()
Expand All @@ -222,6 +230,7 @@ test('groups dependencies with empty manifest paths together', () => {
emptyInvalidLicenseChanges,
emptyChanges,
emptyScorecard,
emptyResolvedVulnerabilities,
defaultConfig
)
summary.addScannedFiles(changesWithEmptyManifests)
Expand All @@ -236,6 +245,7 @@ test('does not include status section if nothing was found', () => {
emptyInvalidLicenseChanges,
emptyChanges,
emptyScorecard,
emptyResolvedVulnerabilities,
defaultConfig
)
const text = core.summary.stringify()
Expand All @@ -259,6 +269,7 @@ test('includes count and status icons for all findings', () => {
licenseIssues,
emptyChanges,
emptyScorecard,
emptyResolvedVulnerabilities,
defaultConfig
)

Expand All @@ -279,6 +290,7 @@ test('uses checkmarks for license issues if only vulnerabilities were found', ()
emptyInvalidLicenseChanges,
emptyChanges,
emptyScorecard,
emptyResolvedVulnerabilities,
defaultConfig
)

Expand All @@ -303,6 +315,7 @@ test('uses checkmarks for vulnerabilities if only license issues were found', ()
licenseIssues,
emptyChanges,
emptyScorecard,
emptyResolvedVulnerabilities,
defaultConfig
)

Expand Down
Loading