diff --git a/lib/platform/common.ts b/lib/platform/common.ts index 4f937f8c6f8b9ab339bd071a2a18cea345c8ee53..dc3a8cdf0289ade92a17b94aed7d6d847e82148e 100644 --- a/lib/platform/common.ts +++ b/lib/platform/common.ts @@ -6,6 +6,14 @@ import { export type VulnerabilityAlert = _VulnerabilityAlert; +type VulnerabilityKey = string; +type VulnerabilityRangeKey = string; +type VulnerabilityPatch = string; +export type AggregatedVulnerabilities = Record< + VulnerabilityKey, + Record<VulnerabilityRangeKey, VulnerabilityPatch> +>; + export interface PlatformParams { endpoint?: string; token?: string; diff --git a/lib/platform/github/index.spec.ts b/lib/platform/github/index.spec.ts index da6a76f3b0e8f9dfd08b9f2f57112258ea2e27e2..9e77b4aa21962690f71fb9516c294cdfaf4a150d 100644 --- a/lib/platform/github/index.spec.ts +++ b/lib/platform/github/index.spec.ts @@ -8,7 +8,7 @@ import { } from '../../constants/error-messages'; import { BranchStatus, PrState } from '../../types'; import * as _git from '../../util/git'; -import { Platform } from '../common'; +import { Platform, VulnerabilityAlert } from '../common'; const githubApiHost = 'https://api.github.com'; @@ -1939,23 +1939,35 @@ describe('platform/github', () => { expect(httpMock.getTrace()).toMatchSnapshot(); }); it('returns array if found', async () => { - // prettier-ignore - httpMock.scope(githubApiHost).post('/graphql').reply(200, { - "data": { - "repository": { - "vulnerabilityAlerts": { - "edges": [{ - "node": { - "externalIdentifier": "CVE-2018-1000136", - "externalReference": "https://nvd.nist.gov/vuln/detail/CVE-2018-1000136", - "affectedRange": ">= 1.8, < 1.8.3", "fixedIn": "1.8.3", - "id": "MDI4OlJlcG9zaXRvcnlWdWxuZXJhYmlsaXR5QWxlcnQ1MzE3NDk4MQ==", "packageName": "electron" - } - }] - } - } - } - }); + httpMock + .scope(githubApiHost) + .post('/graphql') + .reply(200, { + data: { + repository: { + vulnerabilityAlerts: { + edges: [ + { + node: { + securityAdvisory: { severity: 'HIGH', references: [] }, + securityVulnerability: { + package: { + ecosystem: 'NPM', + name: 'left-pad', + range: '0.0.2', + }, + vulnerableVersionRange: '0.0.2', + firstPatchedVersion: { identifier: '0.0.3' }, + }, + vulnerableManifestFilename: 'foo', + vulnerableManifestPath: 'bar', + } as VulnerabilityAlert, + }, + ], + }, + }, + }, + }); const res = await github.getVulnerabilityAlerts(); expect(res).toHaveLength(1); expect(httpMock.getTrace()).toMatchSnapshot(); diff --git a/lib/platform/github/index.ts b/lib/platform/github/index.ts index cc110fa87e0b26eca87aff204258c1e1a37cab65..301c5f1ed3913fcb5c2f310d6fe3b04ec6be303f 100644 --- a/lib/platform/github/index.ts +++ b/lib/platform/github/index.ts @@ -26,6 +26,7 @@ import * as githubHttp from '../../util/http/github'; import { sanitize } from '../../util/sanitize'; import { ensureTrailingSlash } from '../../util/url'; import { + AggregatedVulnerabilities, BranchStatusConfig, CreatePRConfig, EnsureCommentConfig, @@ -1629,8 +1630,24 @@ export async function getVulnerabilityAlerts(): Promise<VulnerabilityAlert[]> { }); if (vulnerabilityAlerts?.length) { alerts = vulnerabilityAlerts.map((edge) => edge.node); + const shortAlerts: AggregatedVulnerabilities = {}; if (alerts.length) { - logger.debug({ alerts }, 'Found GitHub vulnerability alerts'); + logger.trace({ alerts }, 'GitHub vulnerability details'); + for (const alert of alerts) { + const { + package: { name, ecosystem }, + vulnerableVersionRange, + firstPatchedVersion, + } = alert.securityVulnerability; + const patch = firstPatchedVersion?.identifier; + + const key = `${ecosystem.toLowerCase()}/${name}`; + const range = vulnerableVersionRange; + const elem = shortAlerts[key] || {}; + elem[range] = patch || null; + shortAlerts[key] = elem; + } + logger.debug({ alerts: shortAlerts }, 'GitHub vulnerability details'); } } else { logger.debug('Cannot read vulnerability alerts');