Skip to content

Commit 8a81708

Browse files
authored
Merge pull request #672 from Hritik14/example
Add example importer and improver
2 parents 57c3cc9 + cbf411e commit 8a81708

2 files changed

Lines changed: 220 additions & 0 deletions

File tree

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
from datetime import datetime
2+
from datetime import timezone
3+
from typing import Iterable
4+
5+
import requests
6+
from django.db.models.query import QuerySet
7+
from packageurl import PackageURL
8+
from univers.version_range import NginxVersionRange
9+
from univers.versions import SemverVersion
10+
11+
from vulnerabilities.importer import AdvisoryData
12+
from vulnerabilities.importer import AffectedPackage
13+
from vulnerabilities.importer import Importer
14+
from vulnerabilities.importer import Reference
15+
from vulnerabilities.importer import VulnerabilitySeverity
16+
from vulnerabilities.improver import MAX_CONFIDENCE
17+
from vulnerabilities.improver import Improver
18+
from vulnerabilities.improver import Inference
19+
from vulnerabilities.models import Advisory
20+
from vulnerabilities.severity_systems import SCORING_SYSTEMS
21+
22+
23+
class ExampleImporter(Importer):
24+
25+
spdx_license_expression = "BSD-2-Clause"
26+
27+
def advisory_data(self) -> Iterable[AdvisoryData]:
28+
raw_data = fetch_advisory_data()
29+
for data in raw_data:
30+
yield parse_advisory_data(data)
31+
32+
33+
def fetch_advisory_data():
34+
return [
35+
{
36+
"id": "CVE-2021-230171337",
37+
"summary": "1-byte memory overwrite in resolver",
38+
"advisory_severity": "medium",
39+
"vulnerable": "0.6.18-1.20.0",
40+
"fixed": "1.20.1",
41+
"reference": "http://mailman.nginx.org/pipermail/nginx-announce/2021/000300.html",
42+
"published_on": "14-02-2021 UTC",
43+
},
44+
{
45+
"id": "CVE-2021-12341337",
46+
"summary": "Dummy advisory",
47+
"advisory_severity": "high",
48+
"vulnerable": "0.6.18-1.20.0",
49+
"fixed": "1.20.1",
50+
"reference": "http://example.com/cve-2021-1234",
51+
"published_on": "06-10-2021 UTC",
52+
},
53+
]
54+
55+
56+
def parse_advisory_data(raw_data) -> AdvisoryData:
57+
purl = PackageURL(type="example", name="dummy_package")
58+
affected_version_range = NginxVersionRange.from_native(raw_data["vulnerable"])
59+
fixed_version = SemverVersion(raw_data["fixed"])
60+
affected_package = AffectedPackage(
61+
package=purl, affected_version_range=affected_version_range, fixed_version=fixed_version
62+
)
63+
severity = VulnerabilitySeverity(
64+
system=SCORING_SYSTEMS["generic_textual"], value=raw_data["advisory_severity"]
65+
)
66+
references = [Reference(url=raw_data["reference"], severities=[severity])]
67+
date_published = datetime.strptime(raw_data["published_on"], "%d-%m-%Y %Z").replace(
68+
tzinfo=timezone.utc
69+
)
70+
71+
return AdvisoryData(
72+
aliases=[raw_data["id"]],
73+
summary=raw_data["summary"],
74+
affected_packages=[affected_package],
75+
references=references,
76+
date_published=date_published,
77+
)
78+
79+
80+
class ExampleAliasImprover(Improver):
81+
@property
82+
def interesting_advisories(self) -> QuerySet:
83+
return Advisory.objects.filter(created_by=ExampleImporter.qualified_name)
84+
85+
def get_inferences(self, advisory_data) -> Iterable[Inference]:
86+
for alias in advisory_data.aliases:
87+
new_aliases = fetch_additional_aliases(alias)
88+
aliases = new_aliases + [alias]
89+
yield Inference(aliases=aliases, confidence=MAX_CONFIDENCE)
90+
91+
92+
def fetch_additional_aliases(alias):
93+
alias_map = {
94+
"CVE-2021-230171337": ["PYSEC-1337", "CERTIN-1337"],
95+
"CVE-2021-12341337": ["ANONSEC-1337", "CERTDES-1337"],
96+
}
97+
return alias_map.get(alias)
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
import datetime
2+
import os
3+
from unittest.mock import patch
4+
5+
from django.test import TestCase
6+
from packageurl import PackageURL
7+
from univers.version_constraint import VersionConstraint
8+
from univers.version_range import NginxVersionRange
9+
from univers.versions import SemverVersion
10+
11+
from vulnerabilities import models
12+
from vulnerabilities.import_runner import ImportRunner
13+
from vulnerabilities.importer import AdvisoryData
14+
from vulnerabilities.importer import AffectedPackage
15+
from vulnerabilities.importer import Reference
16+
from vulnerabilities.importer import ScoringSystem
17+
from vulnerabilities.importer import VulnerabilitySeverity
18+
from vulnerabilities.improve_runner import ImproveRunner
19+
from vulnerabilities.improvers.default import DefaultImprover
20+
from vulnerabilities.tests.example_importer_improver import ExampleAliasImprover
21+
from vulnerabilities.tests.example_importer_improver import ExampleImporter
22+
from vulnerabilities.tests.example_importer_improver import parse_advisory_data
23+
24+
25+
def mock_fetch_advisory_data():
26+
return [
27+
{
28+
"id": "CVE-2021-12341337",
29+
"summary": "Dummy advisory",
30+
"advisory_severity": "high",
31+
"vulnerable": "0.6.18-1.20.0",
32+
"fixed": "1.20.1",
33+
"reference": "http://example.com/cve-2021-1234",
34+
"published_on": "06-10-2021 UTC",
35+
}
36+
]
37+
38+
39+
def mock_fetch_additional_aliases(alias):
40+
alias_map = {
41+
"CVE-2021-12341337": ["ANONSEC-1337", "CERTDES-1337"],
42+
}
43+
return alias_map.get(alias)
44+
45+
46+
@patch(
47+
"vulnerabilities.tests.example_importer_improver.fetch_advisory_data", mock_fetch_advisory_data
48+
)
49+
@patch(
50+
"vulnerabilities.tests.example_importer_improver.fetch_additional_aliases",
51+
mock_fetch_additional_aliases,
52+
)
53+
class TestExampleImporter(TestCase):
54+
def test_parse_advisory_data(self):
55+
raw_data = mock_fetch_advisory_data()[0]
56+
expected = AdvisoryData(
57+
aliases=["CVE-2021-12341337"],
58+
summary="Dummy advisory",
59+
affected_packages=[
60+
AffectedPackage(
61+
package=PackageURL(
62+
type="example",
63+
namespace=None,
64+
name="dummy_package",
65+
version=None,
66+
qualifiers={},
67+
subpath=None,
68+
),
69+
affected_version_range=NginxVersionRange(
70+
constraints=(
71+
VersionConstraint(
72+
comparator=">=", version=SemverVersion(string="0.6.18")
73+
),
74+
VersionConstraint(
75+
comparator="<=", version=SemverVersion(string="1.20.0")
76+
),
77+
)
78+
),
79+
fixed_version=SemverVersion(string="1.20.1"),
80+
)
81+
],
82+
references=[
83+
Reference(
84+
reference_id="",
85+
url="http://example.com/cve-2021-1234",
86+
severities=[
87+
VulnerabilitySeverity(
88+
system=ScoringSystem(
89+
identifier="generic_textual",
90+
name="Generic textual severity rating",
91+
url="",
92+
notes="Severity for unknown scoring systems. Contains generic textual values like High, Low etc",
93+
),
94+
value="high",
95+
)
96+
],
97+
)
98+
],
99+
date_published=datetime.datetime(2021, 10, 6, 0, 0, tzinfo=datetime.timezone.utc),
100+
)
101+
actual = parse_advisory_data(raw_data)
102+
assert actual == expected
103+
104+
def test_import_framework_using_example_importer(self):
105+
raw_datas = mock_fetch_advisory_data()
106+
ImportRunner(ExampleImporter).run()
107+
108+
for raw_data in raw_datas:
109+
assert models.Advisory.objects.get(aliases__contains=raw_data["id"])
110+
111+
def test_improve_framework_using_example_improver(self):
112+
ImportRunner(ExampleImporter).run()
113+
ImproveRunner(DefaultImprover).run()
114+
ImproveRunner(ExampleAliasImprover).run()
115+
raw_datas = mock_fetch_advisory_data()
116+
117+
assert models.Package.objects.count() == 3
118+
assert models.PackageRelatedVulnerability.objects.filter(fix=True).count() == 1
119+
assert models.PackageRelatedVulnerability.objects.filter(fix=False).count() == 2
120+
assert models.VulnerabilitySeverity.objects.count() == 1
121+
assert models.VulnerabilityReference.objects.count() == 1
122+
for raw_data in raw_datas:
123+
assert models.Vulnerability.objects.get(summary=raw_data["summary"])

0 commit comments

Comments
 (0)