Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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 @@ -131,6 +131,7 @@ All configuration options are optional.
| `show-openssf-scorecard` | When set to `true`, the action will output information about all the known OpenSSF Scorecard scores for the dependencies changed in this pull request. | `true`, `false` | `true` |
| `warn-on-openssf-scorecard-level` | When `show-openssf-scorecard-levels` is set to `true`, this option lets you configure the threshold for when a score is considered too low and gets a :warning: warning in the CI. | Any positive integer | 3 |
| `show-patched-versions`\* | When set to `true`, the vulnerability summary table will include an additional column showing the first patched version for each vulnerability. This requires additional API calls to fetch advisory data. | `true`, `false` | `false` |
| `show-fixes-in-summary` | When set to `true`, the summary will include a "🎉 Issues Fixed" section showing vulnerabilities resolved by the PR. | `true`, `false` | `false` |

> [!NOTE]
>
Expand Down
181 changes: 180 additions & 1 deletion __tests__/summary.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ const defaultConfig: ConfigurationOptions = {
warn_only: false,
warn_on_openssf_scorecard_level: 3,
show_openssf_scorecard: false,
show_patched_versions: false
show_patched_versions: false,
show_fixes_in_summary: false
}

const changesWithEmptyManifests: Changes = [
Expand Down Expand Up @@ -876,3 +877,181 @@ test('addChangeVulnerabilitiesToSummary() - completes all tasks even with varyin
expect(completedAdvisories.size).toBe(20)
expect(mockOctokitRequest).toHaveBeenCalledTimes(20)
})

test('addSummaryToSummary() - shows three-section layout when show_fixes_in_summary is true and fixes exist', () => {
const config = {...defaultConfig, show_fixes_in_summary: true}
const vulnerabilities = [createTestChange({name: 'lodash'})]
const fixedVulns = [
createTestChange({
name: 'some-package',
version: '1.0.0',
change_type: 'removed',
vulnerabilities: [
{
severity: 'high',
advisory_ghsa_id: 'GHSA-1234-abcd',
advisory_summary: 'Insecure Temporary File',
advisory_url: 'https://github.com/advisories/GHSA-1234-abcd'
}
]
})
]

summary.addSummaryToSummary(
vulnerabilities,
emptyInvalidLicenseChanges,
emptyChanges,
emptyScorecard,
config,
fixedVulns
)

const text = core.summary.stringify()
expect(text).toContain('Action Needed')
expect(text).toContain('Issues Fixed')
expect(text).toContain('Checks Passed')
expect(text).not.toContain('The following issues were found:')
})

test('addSummaryToSummary() - shows fixed vuln details in Issues Fixed section', () => {
const config = {...defaultConfig, show_fixes_in_summary: true}
const fixedVulns = [
createTestChange({
name: 'other-package',
version: '2.0.0',
change_type: 'removed',
vulnerabilities: [
{
severity: 'critical',
advisory_ghsa_id: 'GHSA-5678-efgh',
advisory_summary: 'CVE-2022-XXXX',
advisory_url: 'https://github.com/advisories/GHSA-5678-efgh'
}
]
})
]

summary.addSummaryToSummary(
emptyChanges,
emptyInvalidLicenseChanges,
emptyChanges,
emptyScorecard,
config,
fixedVulns
)

const text = core.summary.stringify()
expect(text).toContain('CVE-2022-XXXX')
expect(text).toContain('other-package@2.0.0')
expect(text).toContain('critical severity')
})

test('addSummaryToSummary() - does not show three-section layout when show_fixes_in_summary is false', () => {
const config = {...defaultConfig, show_fixes_in_summary: false}
const vulnerabilities = [createTestChange({name: 'lodash'})]
const fixedVulns = [
createTestChange({
name: 'some-package',
change_type: 'removed'
})
]

summary.addSummaryToSummary(
vulnerabilities,
emptyInvalidLicenseChanges,
emptyChanges,
emptyScorecard,
config,
fixedVulns
)

const text = core.summary.stringify()
expect(text).toContain('The following issues were found:')
expect(text).not.toContain('Issues Fixed')
expect(text).not.toContain('Action Needed')
})

test('addSummaryToSummary() - does not show three-section layout when there are no fixed vulns', () => {
const config = {...defaultConfig, show_fixes_in_summary: true}
const vulnerabilities = [createTestChange({name: 'lodash'})]

summary.addSummaryToSummary(
vulnerabilities,
emptyInvalidLicenseChanges,
emptyChanges,
emptyScorecard,
config,
[] // no fixed vulns
)

const text = core.summary.stringify()
expect(text).toContain('The following issues were found:')
expect(text).not.toContain('Issues Fixed')
})

test('addSummaryToSummary() - shows only Issues Fixed and Checks Passed when no action needed but fixes exist', () => {
const config = {...defaultConfig, show_fixes_in_summary: true}
const fixedVulns = [
createTestChange({
name: 'fixed-package',
version: '1.0.0',
change_type: 'removed',
vulnerabilities: [
{
severity: 'moderate',
advisory_ghsa_id: 'GHSA-abcd-1234',
advisory_summary: 'Some advisory',
advisory_url: 'https://github.com/advisories/GHSA-abcd-1234'
}
]
})
]

summary.addSummaryToSummary(
emptyChanges,
emptyInvalidLicenseChanges,
emptyChanges,
emptyScorecard,
config,
fixedVulns
)

const text = core.summary.stringify()
expect(text).toContain('Issues Fixed')
expect(text).toContain('Checks Passed')
expect(text).not.toContain('Action Needed')
expect(text).not.toContain('The following issues were found:')
})

test('addFixedVulnerabilitiesToSummary() - does nothing when no fixed vulns', () => {
summary.addFixedVulnerabilitiesToSummary([])
const text = core.summary.stringify()
expect(text).toEqual('')
})

test('addFixedVulnerabilitiesToSummary() - renders fixed vulnerabilities table', () => {
const fixedVulns = [
createTestChange({
name: 'some-package',
version: '1.0.0',
change_type: 'removed',
source_repository_url: 'https://github.com/some/package',
vulnerabilities: [
{
severity: 'high',
advisory_ghsa_id: 'GHSA-1234-abcd',
advisory_summary: 'Insecure Temporary File',
advisory_url: 'https://github.com/advisories/GHSA-1234-abcd'
}
]
})
]

summary.addFixedVulnerabilitiesToSummary(fixedVulns)

const text = core.summary.stringify()
expect(text).toContain('<h2>Fixed Vulnerabilities</h2>')
expect(text).toContain('some-package')
expect(text).toContain('Insecure Temporary File')
expect(text).toContain('high')
})
3 changes: 3 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ inputs:
show-patched-versions:
description: When set to `true`, the vulnerability summary table will include a column showing the first patched version for each vulnerability.
required: false
show-fixes-in-summary:
description: When set to `true`, the summary will include a "🎉 Issues Fixed" section showing vulnerabilities resolved by the PR.
required: false
outputs:
comment-content:
description: Prepared dependency report comment
Expand Down
4 changes: 3 additions & 1 deletion src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ function readInlineConfig(): ConfigurationOptionsPartial {
'warn-on-openssf-scorecard-level'
)
const show_patched_versions = getOptionalBoolean('show-patched-versions')
const show_fixes_in_summary = getOptionalBoolean('show-fixes-in-summary')

validateLicenses('allow-licenses', allow_licenses)
validateLicenses('deny-licenses', deny_licenses)
Expand All @@ -76,7 +77,8 @@ function readInlineConfig(): ConfigurationOptionsPartial {
warn_only,
show_openssf_scorecard,
warn_on_openssf_scorecard_level,
show_patched_versions
show_patched_versions,
show_fixes_in_summary
}

return Object.fromEntries(
Expand Down
14 changes: 13 additions & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,14 @@ async function run(): Promise<void> {
filteredChanges
)

const fixedVulns: Changes = config.show_fixes_in_summary
? filteredChanges.filter(
change =>
change.change_type === 'removed' &&
change.vulnerabilities.length > 0
)
: []

const invalidLicenseChanges = await getInvalidLicenseChanges(
filteredChanges,
{
Expand Down Expand Up @@ -197,7 +205,8 @@ async function run(): Promise<void> {
invalidLicenseChanges,
deniedChanges,
scorecard,
config
config,
fixedVulns
)

if (snapshot_warnings) {
Expand Down Expand Up @@ -237,6 +246,9 @@ async function run(): Promise<void> {
printScorecardBlock(scorecard, config)
createScorecardWarnings(scorecard, config)
}
if (config.show_fixes_in_summary) {
summary.addFixedVulnerabilitiesToSummary(fixedVulns)
}

core.setOutput('dependency-changes', JSON.stringify(changes))
summary.addScannedFiles(changes)
Expand Down
1 change: 1 addition & 0 deletions src/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ export const ConfigurationOptionsSchema = z
show_openssf_scorecard: z.boolean().optional().default(true),
warn_on_openssf_scorecard_level: z.number().default(3),
show_patched_versions: z.boolean().default(false),
show_fixes_in_summary: z.boolean().default(false),
comment_summary_in_pr: z
.union([
z.preprocess(
Expand Down
Loading