Skip to content

Commit

Permalink
refactor: No longer use full-result, just look up what we need
Browse files Browse the repository at this point in the history
  • Loading branch information
rottebds committed Feb 16, 2022
1 parent 9edd03b commit 85020c5
Show file tree
Hide file tree
Showing 8 changed files with 192 additions and 286 deletions.
203 changes: 140 additions & 63 deletions dist/index.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index.js.map

Large diffs are not rendered by default.

31 changes: 0 additions & 31 deletions src/blackduck-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,37 +69,6 @@ export interface IRapidScanLicense {
}
}

export interface IRapidScanFullResults {
componentName: string
versionName: string
componentIdentifier: string
violatingPolicies: {
policyName: string
description: string
policySeverity: string
}[]
policyViolationVulnerabilities: IRapidScanVulnerability[]
policyViolationLicenses: {
name: string
}[]
allVulnerabilities: {
name: string
description: string
vulnSeverity: string
overallScore: number
_meta: {
href: string
}
}[]
allLicenses: {
name: string
licenseFamilyName: string
_meta: {
href: string
}
}[]
}

export class BlackduckApiService {
blackduckUrl: string
blackduckApiToken: string
Expand Down
85 changes: 42 additions & 43 deletions src/detect/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,48 @@ import { warning } from '@actions/core'
import { BlackduckApiService, IComponentVersion, IComponentVulnerability, IRapidScanLicense, IRapidScanResults, IRapidScanVulnerability, IRecommendedVersion, IUpgradeGuidance } from '../blackduck-api'
import { BLACKDUCK_API_TOKEN, BLACKDUCK_URL } from '../inputs'

export async function createRapidScanReport(policyViolations: IRapidScanResults[], blackduckApiService?: BlackduckApiService): Promise<IComponentReport[]> {
const rapidScanReport: IComponentReport[] = []

if (blackduckApiService === undefined) {
blackduckApiService = new BlackduckApiService(BLACKDUCK_URL, BLACKDUCK_API_TOKEN)
}

const bearerToken = await blackduckApiService.getBearerToken()

for (const policyViolation of policyViolations) {
const componentIdentifier = policyViolation.componentIdentifier
const componentVersionResponse = await blackduckApiService.getComponentsMatching(bearerToken, componentIdentifier)
const componentVersion = componentVersionResponse?.result?.items[0]

let upgradeGuidance = undefined
let vulnerabilities = undefined
if (componentVersion !== undefined) {
upgradeGuidance = await blackduckApiService
.getUpgradeGuidanceFor(bearerToken, componentVersion)
.then(response => {
if (response.result === null) {
warning(`Could not get upgrade guidance for ${componentIdentifier}: The upgrade guidance result was empty`)
return undefined
}

return response.result
})
.catch(reason => {
warning(`Could not get upgrade guidance for ${componentIdentifier}: ${reason}`)
return undefined
})

const vulnerabilityResponse = await blackduckApiService.getComponentVulnerabilties(bearerToken, componentVersion)
vulnerabilities = vulnerabilityResponse?.result?.items
}

const componentReport = createComponentReport(policyViolation, componentVersion, upgradeGuidance, vulnerabilities)
rapidScanReport.push(componentReport)
}

return rapidScanReport
}
export interface IComponentReport {
violatedPolicies: IPolicyReport[]
name: string
Expand Down Expand Up @@ -109,46 +151,3 @@ export function createUpgradeReport(recommendedVersion?: IRecommendedVersion): I
vulnerabilityCount: Object.values(recommendedVersion.vulnerabilityRisk).reduce((accumulatedValues, value) => accumulatedValues + value, 0)
}
}

export async function createRapidScanReport(policyViolations: IRapidScanResults[], blackduckApiService?: BlackduckApiService): Promise<IComponentReport[]> {
const rapidScanReport: IComponentReport[] = []

if (blackduckApiService === undefined) {
blackduckApiService = new BlackduckApiService(BLACKDUCK_URL, BLACKDUCK_API_TOKEN)
}

const bearerToken = await blackduckApiService.getBearerToken()

for (const policyViolation of policyViolations) {
const componentIdentifier = policyViolation.componentIdentifier
const componentVersionResponse = await blackduckApiService.getComponentsMatching(bearerToken, componentIdentifier)
const componentVersion = componentVersionResponse?.result?.items[0]

let upgradeGuidance = undefined
let vulnerabilities = undefined
if (componentVersion !== undefined) {
upgradeGuidance = await blackduckApiService
.getUpgradeGuidanceFor(bearerToken, componentVersion)
.then(response => {
if (response.result === null) {
warning(`Could not get upgrade guidance for ${componentIdentifier}: The upgrade guidance result was empty`)
return undefined
}

return response.result
})
.catch(reason => {
warning(`Could not get upgrade guidance for ${componentIdentifier}: ${reason}`)
return undefined
})

const vulnerabilityResponse = await blackduckApiService.getComponentVulnerabilties(bearerToken, componentVersion)
vulnerabilities = vulnerabilityResponse?.result?.items
}

const componentReport = createComponentReport(policyViolation, componentVersion, upgradeGuidance, vulnerabilities)
rapidScanReport.push(componentReport)
}

return rapidScanReport
}
77 changes: 7 additions & 70 deletions src/detect/reporting.ts
Original file line number Diff line number Diff line change
@@ -1,56 +1,25 @@
import { warning } from '@actions/core'
import { IRestResponse } from 'typed-rest-client'
import { BlackduckApiService, cleanUrl, IBlackduckItemArray, IComponentVersion, IRapidScanFullResults, IRapidScanResults, IUpgradeGuidance } from '../blackduck-api'
import { BLACKDUCK_API_TOKEN, BLACKDUCK_URL } from '../inputs'
import { IComponentReport } from './report'
import { IRapidScanResults } from '../blackduck-api'
import { createRapidScanReport, IComponentReport } from './report'

export const TABLE_HEADER = '| Policies Violated | Dependency | License(s) | Vulnerabilities | Short Term Recommended Upgrade | Long Term Recommended Upgrade |\r\n' + '|-|-|-|-|-|-|\r\n'

export async function createRapidScanReport(policyViolations: IRapidScanResults[], policyCheckWillFail: boolean): Promise<string> {
export async function createRapidScanReportString(policyViolations: IRapidScanResults[], policyCheckWillFail: boolean): Promise<string> {
let message = ''
if (policyViolations.length == 0) {
message = message.concat('# :white_check_mark: None of your dependencies violate policy!')
} else {
const violationSymbol = policyCheckWillFail ? ':x:' : ':warning:'
message = message.concat(`# ${violationSymbol} Found dependencies violating policy!\r\n`)
message = message.concat(`# ${violationSymbol} Found dependencies violating policy!\r\n\r\n`)

const blackduckApiService = new BlackduckApiService(BLACKDUCK_URL, BLACKDUCK_API_TOKEN)
const bearerToken = await blackduckApiService.getBearerToken()
const fullResultsResponse: IRestResponse<IBlackduckItemArray<IRapidScanFullResults>> = await blackduckApiService.get(bearerToken, policyViolations[0]._meta.href + '/full-result')
const fullResults = fullResultsResponse?.result?.items
if (fullResults === undefined || fullResults.length == 0) {
return Promise.reject(`Could not retrieve Black Duck RAPID scan results from ${policyViolations[0]._meta.href + '/full-result'}, response was ${fullResultsResponse.statusCode}`)
}

message = message.concat('\r\n')

const reportTable = await createTable(blackduckApiService, bearerToken, fullResults)
const componentReports = await createRapidScanReport(policyViolations)
const tableBody = componentReports.map(componentReport => createComponentRow(componentReport)).join('\r\n')
const reportTable = TABLE_HEADER.concat(tableBody)
message = message.concat(reportTable)
}

return message
}

export async function createTable(blackduckApiService: BlackduckApiService, bearerToken: string, fullResults: IRapidScanFullResults[]): Promise<string> {
let table = TABLE_HEADER

for (const violation of fullResults) {
if (violation.violatingPolicies.length > 0) {
const componentVersionResponse = await blackduckApiService.getComponentsMatching(bearerToken, violation.componentIdentifier)
const componentVersion = componentVersionResponse?.result?.items[0]

let upgradeGuidance = null
if (componentVersion !== undefined) {
const upgradeGuidanceResponse = await blackduckApiService.getUpgradeGuidanceFor(bearerToken, componentVersion).catch(reason => warning(`Could not get upgrade guidance for ${violation.componentIdentifier}: ${reason}`))
upgradeGuidance = upgradeGuidanceResponse?.result
}
table = table.concat(`${createComponentRowFromFullResults(componentVersion, upgradeGuidance, violation)}\r\n`)
}
}

return table
}

function createComponentRow(component: IComponentReport): string {
const violatedPolicies = component.violatedPolicies.map(policy => `${policy.name} ${policy.severity === 'UNSPECIFIED' ? '' : `(${policy.severity})`}`).join('<br/>')
const componentInViolation = component?.href ? `[${component.name}](${component.href})` : component.name
Expand All @@ -61,35 +30,3 @@ function createComponentRow(component: IComponentReport): string {

return `| ${violatedPolicies} | ${componentInViolation} | ${componentLicenses} | ${vulnerabilities} | ${shortTermString} | ${longTermString} |`
}

function createComponentRowFromFullResults(componentVersion: IComponentVersion | undefined, upgradeGuidance: IUpgradeGuidance | null | undefined, violation: IRapidScanFullResults): string {
const violatingLicenseNames = violation.policyViolationLicenses.map(license => license.name)
const violatingVulnerabilityNames = violation.policyViolationVulnerabilities.map(vulnerability => vulnerability.name)

const violatedPolicies = violation.violatingPolicies.map(policy => `${policy.policyName} ${policy.policySeverity === 'UNSPECIFIED' ? '' : `(${policy.policySeverity})`}`).join('<br/>')
let componentInViolation = `${violation.componentName} ${violation.versionName}`
if (componentVersion?.version !== undefined) {
componentInViolation = `[${violation.componentName} ${violation.versionName}](${componentVersion?.version})`
}
const componentLicenses = violation.allLicenses.map(license => `${violatingLicenseNames.includes(license.name) ? ':x: &nbsp; ' : ''}[${license.name}](${license._meta.href}/text)`).join('<br/>')
const vulnerabilities = violation.allVulnerabilities.map(vulnerability => `${violatingVulnerabilityNames.includes(vulnerability.name) ? ':x: &nbsp; ' : ''}[${vulnerability.name}](${cleanUrl(BLACKDUCK_URL)}/api/vulnerabilities/${vulnerability.name}) (${vulnerability.vulnSeverity}: CVSS ${vulnerability.overallScore})`).join('<br/>')

if (upgradeGuidance === undefined || upgradeGuidance === null) {
return `| ${violatedPolicies} | ${componentInViolation} | ${componentLicenses} | ${vulnerabilities} | | | `
}

let shortTermString = ''
let longTermString = ''
const shortTerm = upgradeGuidance?.shortTerm
if (shortTerm !== undefined) {
const vulnerabilitiesAfterUpgrade = Object.values(shortTerm.vulnerabilityRisk).reduce((accumulatedValues, value) => accumulatedValues + value, 0)
shortTermString = `[${shortTerm.versionName}](${shortTerm.version}) (${vulnerabilitiesAfterUpgrade} known vulnerabilities)`
}
const longTerm = upgradeGuidance?.longTerm
if (longTerm !== undefined) {
const vulnerabilitiesAfterUpgrade = Object.values(longTerm.vulnerabilityRisk).reduce((accumulatedValues, value) => accumulatedValues + value, 0)
longTermString = `[${longTerm.versionName}](${longTerm.version}) (${vulnerabilitiesAfterUpgrade} known vulnerabilities)`
}

return `| ${violatedPolicies} | ${componentInViolation} | ${componentLicenses} | ${vulnerabilities} | ${shortTermString} | ${longTermString} |`
}
4 changes: 2 additions & 2 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { POLICY_SEVERITY, SUCCESS } from './detect/exit-codes'
import { TOOL_NAME, findOrDownloadDetect, runDetect } from './detect/detect-manager'
import { isPullRequest } from './github/github-context'
import { BLACKDUCK_API_TOKEN, BLACKDUCK_URL, DETECT_TRUST_CERT, DETECT_VERSION, FAIL_ON_ALL_POLICY_SEVERITIES, OUTPUT_PATH_OVERRIDE, SCAN_MODE } from './inputs'
import { createRapidScanReport } from './detect/reporting'
import { createRapidScanReportString } from './detect/reporting'
import { uploadArtifact } from './github/upload-artifacts'
import { CHECK_NAME } from './application-constants'

Expand Down Expand Up @@ -101,7 +101,7 @@ export async function runWithPolicyCheck(blackduckPolicyCheck: GitHubCheck): Pro
debug(`Policy Violations Present: ${hasPolicyViolations}`)

const failureConditionsMet = detectExitCode === POLICY_SEVERITY || FAIL_ON_ALL_POLICY_SEVERITIES
const rapidScanReport = await createRapidScanReport(policyViolations, hasPolicyViolations && failureConditionsMet)
const rapidScanReport = await createRapidScanReportString(policyViolations, hasPolicyViolations && failureConditionsMet)

if (isPullRequest()) {
info('This is a pull request, commenting...')
Expand Down
58 changes: 0 additions & 58 deletions tests/resources/fullResultsWithoutPolicyViolations.json

This file was deleted.

18 changes: 0 additions & 18 deletions tests/unit/reporting.test.ts

This file was deleted.

0 comments on commit 85020c5

Please sign in to comment.