Skip to content

Commit 8b59296

Browse files
authored
Merge pull request #1044 from TG1999/migrate/xen
Migrate xen importer
2 parents 594c442 + 94c2c8c commit 8b59296

File tree

6 files changed

+168
-56
lines changed

6 files changed

+168
-56
lines changed

vulnerabilities/importers/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from vulnerabilities.importers import retiredotnet
3232
from vulnerabilities.importers import suse_scores
3333
from vulnerabilities.importers import ubuntu
34+
from vulnerabilities.importers import xen
3435

3536
IMPORTERS_REGISTRY = [
3637
nginx.NginxImporter,
@@ -57,6 +58,7 @@
5758
suse_scores.SUSESeverityScoreImporter,
5859
elixir_security.ElixirSecurityImporter,
5960
apache_tomcat.ApacheTomcatImporter,
61+
xen.XenImporter,
6062
]
6163

6264
IMPORTERS_REGISTRY = {x.qualified_name: x for x in IMPORTERS_REGISTRY}

vulnerabilities/importers/xen.py

Lines changed: 67 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -7,66 +7,77 @@
77
# See https://aboutcode.org for more information about nexB OSS projects.
88
#
99

10-
import json
11-
12-
import requests
13-
1410
from vulnerabilities.importer import AdvisoryData
1511
from vulnerabilities.importer import Importer
16-
from vulnerabilities.importer import Reference
17-
from vulnerabilities.utils import create_etag
12+
from vulnerabilities.references import XsaReference
13+
from vulnerabilities.utils import fetch_response
1814
from vulnerabilities.utils import is_cve
1915

2016

2117
class XenImporter(Importer):
22-
# CONFIG_CLASS = XenDBConfiguration
23-
24-
def updated_advisories(self):
25-
advisories = []
26-
if create_etag(data_src=self, url=self.config.db_url, etag_key="etag"):
27-
advisories.extend(self.to_advisories(fetch(self.config.db_url)))
28-
29-
return self.batch_advisories(advisories)
30-
31-
def create_etag(self, url):
32-
etag = requests.head(url).headers.get("etag")
33-
if not etag:
34-
return True
35-
36-
elif url in self.config.etags:
37-
if self.config.etags[url] == etag:
38-
return False
39-
40-
self.config.etags[url] = etag
41-
return True
42-
43-
@staticmethod
44-
def to_advisories(xen_db):
45-
advisories = []
46-
for xsa in xen_db[0]["xsas"]:
47-
reference = get_xen_references(xsa["xsa"])
48-
title = xsa.get("title", [""])
49-
for cve in xsa.get("cve", [""]):
50-
if not is_cve(cve):
51-
cve = ""
52-
53-
advisories.append(
54-
AdvisoryData(
55-
vulnerability_id=cve,
56-
summary=title,
57-
references=[reference],
58-
)
59-
)
60-
return advisories
61-
62-
63-
def get_xen_references(xsa_id):
64-
return Reference(
65-
reference_id="XSA-" + xsa_id,
66-
url="https://xenbits.xen.org/xsa/advisory-{}.html".format(xsa_id),
67-
)
68-
6918

70-
def fetch(url):
71-
response = requests.get(url).content
72-
return json.loads(response)
19+
url = "https://xenbits.xen.org/xsa/xsa.json"
20+
spdx_license_expression = "LicenseRef-scancode-other-permissive"
21+
notice = """
22+
From: George Dunlap <[email protected]>
23+
Date: Wed, Jan 25, 2023 at 4:57 PM
24+
Subject: Re: Usage of Xen Security Data in VulnerableCode
25+
To: Tushar Goel <[email protected]>
26+
27+
28+
On Thu, Jan 19, 2023 at 1:10 PM Tushar Goel <[email protected]> wrote:
29+
>
30+
> Hi Andrew,
31+
>
32+
> > Maybe we want to make it CC-BY-4 to require people to reference back to
33+
> > the canonical upstream ?
34+
> Thanks for your response, can we have a more declarative statement on
35+
> the license from your end
36+
> and also can you please provide your acknowledgement over the usage of
37+
> Xen security data in vulnerablecode.
38+
39+
40+
Hey Tushar,
41+
Informally, the Xen Project Security Team is happy for you to include the data from xsa.json in your open-source vulnerability database. As a courtesy we'd request that it be documented where the information came from. (I think if the data includes links to then advisories on our website, that will suffice.)
42+
Formally, we're not copyright lawyers; but we don't think there's anything copyright-able in the xsa.json: There is no editorial or creative control in the generation of that file; it's just a collection of facts which you could re-generate by scanning all the advisories. (In fact that's exactly how the file is created; i.e., the collection of advisory texts is our "source of truth".)
43+
We do have "Officially license all advisory text as CC-BY-4" on our to-do list; if you'd be more comfortable with an official license for xsa.json as well, we can add that to the list.
44+
45+
-George
46+
"""
47+
48+
def advisory_data(self):
49+
data = fetch_response(self.url).json()
50+
# The data looks like this
51+
# [
52+
# {
53+
# "xsas": [
54+
# {
55+
# "cve": [
56+
# "CVE-2012-5510"
57+
# ],
58+
# "title": "XSA-1: Xen security advisory",
59+
# }
60+
# ]
61+
# }
62+
# ]
63+
if not data:
64+
return []
65+
xsas = data[0]["xsas"]
66+
for xsa in xsas:
67+
yield from self.to_advisories(xsa)
68+
69+
def to_advisories(self, xsa):
70+
xsa_id = xsa.get("xsa")
71+
references = []
72+
if xsa_id:
73+
references.append(XsaReference.from_number(number=xsa_id))
74+
title = xsa.get("title")
75+
for cve in xsa.get("cve") or []:
76+
# TODO: https://github.com/nexB/vulnerablecode/issues/981
77+
if not is_cve(cve):
78+
continue
79+
yield AdvisoryData(
80+
aliases=[cve],
81+
summary=title,
82+
references=references,
83+
)

vulnerabilities/references.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ def from_id(cls, xsa_id):
2828
url=f"https://xenbits.xen.org/xsa/advisory-{numid}.html",
2929
)
3030

31+
@classmethod
32+
def from_number(cls, number):
33+
"""
34+
Return a new XsaReference from an XSA number.
35+
"""
36+
return cls(
37+
reference_id=f"XSA-{number}",
38+
url=f"https://xenbits.xen.org/xsa/advisory-{number}.html",
39+
)
40+
3141

3242
class ZbxReference(Reference):
3343
"""
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[
2+
{
3+
"aliases": [
4+
"CVE-2012-5510"
5+
],
6+
"summary": "Grant table version switch list corruption vulnerability",
7+
"affected_packages": [],
8+
"references": [
9+
{
10+
"reference_id": "XSA-26",
11+
"url": "https://xenbits.xen.org/xsa/advisory-26.html",
12+
"severities": []
13+
}
14+
],
15+
"date_published": null,
16+
"weaknesses": []
17+
}
18+
]
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{
2+
"cve": [
3+
"CVE-2012-5510"
4+
],
5+
"files": [
6+
{
7+
"name": "xsa26-4.1.patch",
8+
"project": "xen",
9+
"upstream": "Xen",
10+
"versions": [
11+
[
12+
"4.1.x"
13+
]
14+
]
15+
},
16+
{
17+
"name": "xsa26-4.2.patch",
18+
"project": "xen",
19+
"upstream": "Xen",
20+
"versions": [
21+
[
22+
"4.2.x"
23+
]
24+
]
25+
},
26+
{
27+
"name": "xsa26-unstable.patch",
28+
"project": "xen",
29+
"upstream": "Xen",
30+
"versions": [
31+
[
32+
"xen-unstable"
33+
]
34+
]
35+
}
36+
],
37+
"public_time": "2012-12-03 17:51",
38+
"title": "Grant table version switch list corruption vulnerability",
39+
"version": 3,
40+
"version_time": "2012-12-03 17:51",
41+
"xsa": "26"
42+
}

vulnerabilities/tests/test_xen.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#
2+
# Copyright (c) nexB Inc. and others. All rights reserved.
3+
# VulnerableCode is a trademark of nexB Inc.
4+
# SPDX-License-Identifier: Apache-2.0
5+
# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
6+
# See https://github.com/nexB/vulnerablecode for support or download.
7+
# See https://aboutcode.org for more information about nexB OSS projects.
8+
#
9+
10+
import json
11+
import os
12+
13+
from vulnerabilities.importers.xen import XenImporter
14+
from vulnerabilities.tests import util_tests
15+
16+
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
17+
TEST_DATA = os.path.join(
18+
BASE_DIR,
19+
"test_data",
20+
)
21+
22+
23+
def test_xen_to_advisories():
24+
with open(os.path.join(TEST_DATA, "xen_data.json")) as f:
25+
raw_data = json.load(f)
26+
advisories = XenImporter().to_advisories(raw_data)
27+
result = [data.to_dict() for data in advisories]
28+
expected_file = os.path.join(TEST_DATA, f"parse-advisory-xen-expected.json")
29+
util_tests.check_results_against_json(result, expected_file)

0 commit comments

Comments
 (0)