Skip to content

Commit b87ebbd

Browse files
authored
Merge pull request #1482 from metacpan/haarg/cve-by-cve-id
index and fetch CVEs by CVE ID
2 parents c45ac0d + 74b9045 commit b87ebbd

7 files changed

Lines changed: 130 additions & 12 deletions

File tree

es/cve/mapping.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
"affected_versions": {
55
"type": "text"
66
},
7+
"cve_id": {
8+
"type": "keyword"
9+
},
710
"cpansa_id": {
811
"type": "keyword"
912
},

lib/MetaCPAN/Query/CVE.pm

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,45 @@ sub find_cves_by_cpansa {
2222
return +{ cve => [ map { $_->{_source} } @{ $res->{hits}{hits} } ] };
2323
}
2424

25+
sub find_cves_by_cpansa_or_cve_id {
26+
my ( $self, $id ) = @_;
27+
28+
my $query = +{
29+
bool => {
30+
should => [
31+
{ term => { cve_id => $id } },
32+
{ term => { cpansa_id => $id } },
33+
],
34+
},
35+
};
36+
37+
my $res = $self->es->search(
38+
es_doc_path('cve'),
39+
body => {
40+
query => $query,
41+
size => 999,
42+
},
43+
);
44+
45+
return +{ cve => [ map { $_->{_source} } @{ $res->{hits}{hits} } ] };
46+
}
47+
48+
sub find_cves_by_cve_id {
49+
my ( $self, $cve_id ) = @_;
50+
51+
my $query = +{ term => { cve_id => $cve_id } };
52+
53+
my $res = $self->es->search(
54+
es_doc_path('cve'),
55+
body => {
56+
query => $query,
57+
size => 999,
58+
}
59+
);
60+
61+
return +{ cve => [ map { $_->{_source} } @{ $res->{hits}{hits} } ] };
62+
}
63+
2564
sub find_cves_by_release {
2665
my ( $self, $author, $release ) = @_;
2766

lib/MetaCPAN/Script/CVE.pm

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,6 @@ has cve_url => (
2020
default => 'https://butterfly.cpansec.org/feed/cpansa.json',
2121
);
2222

23-
has cve_dev_url => (
24-
is => 'ro',
25-
isa => Uri,
26-
coerce => 1,
27-
default => 'https://butterfly.cpansec.org/feed/cpansa.json',
28-
);
29-
3023
has test => (
3124
is => 'ro',
3225
isa => Bool,
@@ -73,8 +66,10 @@ sub index_cve_data {
7366

7467
for my $dist ( sort keys %{$data} ) {
7568
for my $cpansa ( @{ $data->{$dist} } ) {
76-
if ( !$cpansa->{cpansa_id} ) {
77-
log_warn { sprintf( "Dist '%s' missing cpansa_id", $dist ) };
69+
if ( !$cpansa->{cpansa_id} && !$cpansa->{cve_id} ) {
70+
log_warn {
71+
sprintf( "Dist '%s' missing cpansa_id and cve_id", $dist )
72+
};
7873
next;
7974
}
8075

@@ -195,6 +190,7 @@ sub index_cve_data {
195190

196191
my $doc_data = {
197192
distribution => $dist,
193+
cve_id => $cpansa->{cve_id},
198194
cpansa_id => $cpansa->{cpansa_id},
199195
affected_versions => $cpansa->{affected_versions},
200196
cves => $cpansa->{cves},
@@ -210,8 +206,15 @@ sub index_cve_data {
210206
delete $doc_data->{$k} unless exists $valid_keys{$k};
211207
}
212208

209+
if ( $cpansa->{cve_id} && $cpansa->{cpansa_id} ) {
210+
211+
# if both exist, ensure an older record using cpansa_id as the
212+
# id is removed.
213+
$bulk->delete( { id => $cpansa->{cpansa_id} } );
214+
}
215+
213216
$bulk->update( {
214-
id => $cpansa->{cpansa_id},
217+
id => $cpansa->{cve_id} // $cpansa->{cpansa_id},
215218
doc => $doc_data,
216219
doc_as_upsert => true,
217220
} );
@@ -226,7 +229,7 @@ sub retrieve_cve_data {
226229

227230
return decode_json( path( $self->json_file )->slurp ) if $self->json_file;
228231

229-
my $url = $self->test ? $self->cve_dev_url : $self->cve_url;
232+
my $url = $self->cve_url;
230233

231234
log_info { 'Fetching data from ', $url };
232235
my $resp = $self->ua->get($url);

lib/MetaCPAN/Server/Controller/CVE.pm

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ with 'MetaCPAN::Server::Role::JSONP';
1212
sub get : Path('') : Args(1) {
1313
my ( $self, $c, $cpansa_id ) = @_;
1414
$c->stash_or_detach(
15-
$c->model('ESQuery')->cve->find_cves_by_cpansa($cpansa_id) );
15+
$c->model('ESQuery')->cve->find_cves_by_cpansa_or_cve_id($cpansa_id)
16+
);
1617
}
1718

1819
sub release : Path('release') : Args(2) {

t/00_setup.t

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ $server->index_cover;
4343
$server->index_river;
4444
$server->index_bus_factor;
4545
$server->index_tickets;
46+
$server->index_cves;
4647

4748
$server->prepare_user_test_data;
4849

t/lib/MetaCPAN/TestServer.pm

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use MetaCPAN::Script::Author ();
77
use MetaCPAN::Script::BusFactor ();
88
use MetaCPAN::Script::Cover ();
99
use MetaCPAN::Script::CPANTestersAPI ();
10+
use MetaCPAN::Script::CVE ();
1011
use MetaCPAN::Script::Favorite ();
1112
use MetaCPAN::Script::First ();
1213
use MetaCPAN::Script::Latest ();
@@ -270,6 +271,19 @@ sub index_bus_factor {
270271
);
271272
}
272273

274+
sub index_cves {
275+
my $self = shift;
276+
277+
local @ARGV = (
278+
'cve',
279+
'--cve_url',
280+
URI->new( 'file://' . testdata_dir()->child('cves.json') )->as_string,
281+
);
282+
283+
ok( MetaCPAN::Script::CVE->new_with_options( %{ $self->_config } )->run,
284+
'index cves', );
285+
}
286+
273287
sub prepare_user_test_data {
274288
my $self = shift;
275289
ok(

test-data/cves.json

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
{
2+
"Multiple-Releases": [
3+
{
4+
"affected_versions": [
5+
"<=1.1"
6+
],
7+
"cpansa_id": "CPANSA-Multiple-Releases-2025-54321",
8+
"cve": {},
9+
"cves": [],
10+
"description": "Description of 54321",
11+
"distribution": "Multiple-Releases",
12+
"references": [
13+
"https://metacpan.org/"
14+
],
15+
"reported": "2025-01-01",
16+
"severity": "medium",
17+
"title": "Title of 54321"
18+
},
19+
{
20+
"affected_versions": [
21+
">=1.2,<=1.5"
22+
],
23+
"cpansa_id": "CPANSA-Multiple-Releases-2025-54322",
24+
"cve": {},
25+
"cve_id": "CVE-2025-54322",
26+
"cves": [
27+
"CVE-2025-54322"
28+
],
29+
"description": "Description of 54322",
30+
"distribution": "Multiple-Releases",
31+
"references": [
32+
"https://metacpan.org/"
33+
],
34+
"reported": "2025-01-02",
35+
"severity": "medium",
36+
"title": "Title of 54322"
37+
},
38+
{
39+
"affected_versions": [
40+
">=1.7"
41+
],
42+
"cve": {},
43+
"cve_id": "CVE-2025-54323",
44+
"cves": [
45+
"CVE-2025-54323"
46+
],
47+
"description": "Description of 54323",
48+
"distribution": "Multiple-Releases",
49+
"references": [
50+
"https://metacpan.org/"
51+
],
52+
"reported": "2025-01-03",
53+
"severity": "medium",
54+
"title": "Title of 54323"
55+
}
56+
]
57+
}

0 commit comments

Comments
 (0)