Skip to content

Commit 8da5e51

Browse files
committed
SecurityAdvisories: skip duplicate GitHub advisories where package name and CVE matches
1 parent f383524 commit 8da5e51

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

src/SecurityAdvisory/GitHubSecurityAdvisoriesSource.php

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ public function getAdvisories(ConsoleIO $io): ?RemoteSecurityAdvisoryCollection
4444
{
4545
/** @var array<string, array<string, RemoteSecurityAdvisory>> $advisoryMap */
4646
$advisoryMap = [];
47+
/** @var array<string, array<string, true>> $foundPackageCves */
48+
$foundPackageCves = [];
4749
$hasNextPage = true;
4850
$after = '';
4951

@@ -95,6 +97,15 @@ public function getAdvisories(ConsoleIO $io): ?RemoteSecurityAdvisoryCollection
9597

9698
$packageName = strtolower($node['package']['name']);
9799

100+
// GitHub can have multiple advisories per CVE and package
101+
if ($cve !== null) {
102+
if (isset($foundPackageCves[$packageName][$cve])) {
103+
continue;
104+
}
105+
106+
$foundPackageCves[$packageName][$cve] = true;
107+
}
108+
98109
// GitHub adds spaces everywhere e.g. > 1.0, adjust to be able to match other advisories
99110
$versionRange = Preg::replace('#\s#', '', $node['vulnerableVersionRange']);
100111
if (isset($advisoryMap[$packageName][$remoteId])) {

tests/SecurityAdvisory/GitHubSecurityAdvisoriesSourceTest.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,38 @@ public function testWithPagination(): void
146146
$this->assertSame(Severity::MEDIUM, $advisories[1]->severity);
147147
}
148148

149+
public function testDuplicateCvePerPackage(): void
150+
{
151+
$responseFactory = function (string $method, string $url, array $options) {
152+
$this->assertSame('POST', $method);
153+
$this->assertSame('https://api.github.com/graphql', $url);
154+
$this->assertSame('{"query":"query{securityVulnerabilities(ecosystem:COMPOSER,first:100){nodes{advisory{summary,permalink,publishedAt,withdrawnAt,severity,identifiers{type,value},references{url}},vulnerableVersionRange,package{name}},pageInfo{hasNextPage,endCursor}}}"}', $options['body']);
155+
156+
return new MockResponse(json_encode($this->getGraphQLResultPageWithMultipleCvePerPackage()), ['http_code' => 200, 'response_headers' => ['Content-Type' => 'application/json; charset=utf-8']]);
157+
};
158+
$client = new MockHttpClient($responseFactory);
159+
160+
$source = new GitHubSecurityAdvisoriesSource($client, new NullLogger(), $this->providerManager, [], $this->doctrine);
161+
$package = $this->getPackage();
162+
$advisoryCollection = $source->getAdvisories(new BufferIO());
163+
164+
$this->assertNotNull($advisoryCollection);
165+
$this->assertSame(1, $client->getRequestsCount());
166+
167+
$advisories = $advisoryCollection->getAdvisoriesForPackageName($package->getName());
168+
$this->assertCount(1, $advisories);
169+
170+
$this->assertSame('GHSA-h58v-c6rf-abcd', $advisories[0]->id);
171+
$this->assertSame('Insert tag injection', $advisories[0]->title);
172+
$this->assertSame('vendor/package', $advisories[0]->packageName);
173+
$this->assertSame('=4.10.0', $advisories[0]->affectedVersions);
174+
$this->assertSame('https://github.com/advisories/GHSA-h58v-c6rf-abcd', $advisories[0]->link);
175+
$this->assertSame('CVE-2020-25768', $advisories[0]->cve);
176+
$this->assertSame('2021-07-01T17:00:04+0000', $advisories[0]->date->format(\DateTimeInterface::ISO8601));
177+
$this->assertNull($advisories[0]->composerRepository);
178+
$this->assertSame(Severity::MEDIUM, $advisories[0]->severity);
179+
}
180+
149181
private function getPackage(): Package
150182
{
151183
$package = new Package();
@@ -191,6 +223,24 @@ private function getGraphQLResultSecondPage(): array
191223
];
192224
}
193225

226+
private function getGraphQLResultPageWithMultipleCvePerPackage(): array
227+
{
228+
return [
229+
'data' => [
230+
'securityVulnerabilities' => [
231+
'nodes' => [
232+
$this->graphQlPackageNode('GHSA-h58v-c6rf-abcd', 'vendor/package', '= 4.10.0', 'CVE-2020-25768', 'Insert tag injection', '2021-07-01T17:00:04Z'),
233+
$this->graphQlPackageNode('GHSA-f7wm-x4gw-abcd', 'vendor/package', '= 4.10.0', 'CVE-2020-25768', 'Insert tag injection in forms', '2020-09-24T16:23:54Z'),
234+
],
235+
'pageInfo' => [
236+
'hasNextPage' => false,
237+
'endCursor' => 'Y3Vyc29yOnYyOpK5MjAxOS0xMi0xN1QyMDozNTozMSswMTowMM0LWQ==',
238+
],
239+
],
240+
],
241+
];
242+
}
243+
194244
private function graphQlPackageNode(string $advisoryId, string $packageName, string $range, string $cve, string $summary, string $publishedAt): array
195245
{
196246
return [

0 commit comments

Comments
 (0)