Skip to content

Commit 30d61ca

Browse files
committed
Use advisory alias relation in pipelines and importer
Signed-off-by: Keshav Priyadarshi <git@keshav.space>
1 parent 927833f commit 30d61ca

File tree

4 files changed

+41
-36
lines changed

4 files changed

+41
-36
lines changed

vulnerabilities/import_runner.py

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
from django.core.exceptions import ValidationError
1717
from django.db import transaction
18+
from django.db.models.query import QuerySet
1819

1920
from vulnerabilities.importer import AdvisoryData
2021
from vulnerabilities.importer import Importer
@@ -96,12 +97,14 @@ def process_advisories(
9697
Insert advisories into the database
9798
Return the number of inserted advisories.
9899
"""
100+
from vulnerabilities.pipes.advisory import get_or_create_aliases
101+
99102
count = 0
100103
advisories = []
101104
for data in advisory_datas:
102105
try:
106+
aliases = get_or_create_aliases(aliases=data.aliases)
103107
obj, created = Advisory.objects.get_or_create(
104-
aliases=data.aliases,
105108
summary=data.summary,
106109
affected_packages=[pkg.to_dict() for pkg in data.affected_packages],
107110
references=[ref.to_dict() for ref in data.references],
@@ -113,6 +116,7 @@ def process_advisories(
113116
},
114117
url=data.url,
115118
)
119+
obj.aliases.add(*aliases)
116120
if not obj.date_imported:
117121
advisories.append(obj)
118122
except Exception as e:
@@ -148,6 +152,8 @@ def process_inferences(inferences: List[Inference], advisory: Advisory, improver
148152
erroneous. Also, the atomic transaction for every advisory and its
149153
inferences makes sure that date_imported of advisory is consistent.
150154
"""
155+
from vulnerabilities.pipes.advisory import get_or_create_aliases
156+
151157
inferences_processed_count = 0
152158

153159
if not inferences:
@@ -157,9 +163,10 @@ def process_inferences(inferences: List[Inference], advisory: Advisory, improver
157163
logger.info(f"Improving advisory id: {advisory.id}")
158164

159165
for inference in inferences:
166+
aliases = get_or_create_aliases(inference.aliases)
160167
vulnerability = get_or_create_vulnerability_and_aliases(
161168
vulnerability_id=inference.vulnerability_id,
162-
aliases=inference.aliases,
169+
aliases=aliases,
163170
summary=inference.summary,
164171
advisory=advisory,
165172
)
@@ -265,14 +272,13 @@ def create_valid_vulnerability_reference(url, reference_id=None):
265272

266273

267274
def get_or_create_vulnerability_and_aliases(
268-
aliases: List[str], vulnerability_id=None, summary=None, advisory=None
275+
aliases: QuerySet, vulnerability_id=None, summary=None, advisory=None
269276
):
270277
"""
271278
Get or create vulnerabilitiy and aliases such that all existing and new
272279
aliases point to the same vulnerability
273280
"""
274-
aliases = set(alias.strip() for alias in aliases if alias and alias.strip())
275-
new_alias_names, existing_vulns = get_vulns_for_aliases_and_get_new_aliases(aliases)
281+
new_aliases, existing_vulns = get_vulns_for_aliases_and_get_new_aliases(aliases)
276282

277283
# All aliases must point to the same vulnerability
278284
vulnerability = None
@@ -310,11 +316,11 @@ def get_or_create_vulnerability_and_aliases(
310316
# f"Inconsistent summary for {vulnerability.vulnerability_id}. "
311317
# f"Existing: {vulnerability.summary!r}, provided: {summary!r}"
312318
# )
313-
associate_vulnerability_with_aliases(vulnerability=vulnerability, aliases=new_alias_names)
319+
associate_vulnerability_with_aliases(vulnerability=vulnerability, aliases=new_aliases)
314320
else:
315321
try:
316322
vulnerability = create_vulnerability_and_add_aliases(
317-
aliases=new_alias_names, summary=summary
323+
aliases=new_aliases, summary=summary
318324
)
319325
importer_name = get_importer_name(advisory)
320326
VulnerabilityChangeLog.log_import(
@@ -324,24 +330,22 @@ def get_or_create_vulnerability_and_aliases(
324330
)
325331
except Exception as e:
326332
logger.error(
327-
f"Cannot create vulnerability with summary {summary!r} and {new_alias_names!r} {e!r}.\n{traceback_format_exc()}."
333+
f"Cannot create vulnerability with summary {summary!r} and {new_aliases!r} {e!r}.\n{traceback_format_exc()}."
328334
)
329335
return
330336

331337
return vulnerability
332338

333339

334-
def get_vulns_for_aliases_and_get_new_aliases(aliases):
340+
def get_vulns_for_aliases_and_get_new_aliases(aliases: QuerySet):
335341
"""
336342
Return ``new_aliases`` that are not in the database and
337343
``existing_vulns`` that point to the given ``aliases``.
338344
"""
339-
new_aliases = set(aliases)
340-
existing_vulns = set()
341-
for alias in Alias.objects.filter(alias__in=aliases):
342-
existing_vulns.add(alias.vulnerability)
343-
new_aliases.remove(alias.alias)
344-
return new_aliases, existing_vulns
345+
new_aliases = aliases.filter(vulnerability__isnull=True)
346+
existing_vulns = [alias.vulnerability for alias in aliases.filter(vulnerability__isnull=False)]
347+
348+
return new_aliases, list(set(existing_vulns))
345349

346350

347351
@transaction.atomic
@@ -360,7 +364,5 @@ def create_vulnerability_and_add_aliases(aliases, summary):
360364

361365

362366
def associate_vulnerability_with_aliases(aliases, vulnerability):
363-
for alias_name in aliases:
364-
alias = Alias(alias=alias_name, vulnerability=vulnerability)
365-
alias.save()
366-
logger.info(f"New alias for {vulnerability!r}: {alias_name}")
367+
aliases.update(vulnerability=vulnerability)
368+
logger.info(f"New alias for {vulnerability!r}: {aliases}")

vulnerabilities/improvers/vulnerability_status.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,7 @@ class VulnerabilityStatusImprover(Improver):
3737

3838
@property
3939
def interesting_advisories(self) -> QuerySet:
40-
return (
41-
Advisory.objects.filter(Q(created_by=NVDImporterPipeline.pipeline_id))
42-
.distinct("aliases")
43-
.paginated()
44-
)
40+
return Advisory.objects.filter(Q(created_by=NVDImporterPipeline.pipeline_id)).paginated()
4541

4642
def get_inferences(self, advisory_data: AdvisoryData) -> Iterable[Inference]:
4743
"""

vulnerabilities/pipelines/add_cvss31_to_CVEs.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
from vulnerabilities import severity_systems
1414
from vulnerabilities.models import Advisory
15+
from vulnerabilities.models import Alias
1516
from vulnerabilities.models import VulnerabilitySeverity
1617
from vulnerabilities.pipelines import VulnerableCodePipeline
1718

@@ -48,7 +49,6 @@ def process_cve_advisory_mapping(self):
4849
results = []
4950

5051
for severity in progress.iter(nvd_severities.paginated(per_page=batch_size)):
51-
print(severity.url)
5252
cve_pattern = re.compile(r"(CVE-\d{4}-\d{4,7})").search
5353
cve_match = cve_pattern(severity.url)
5454
if cve_match:
@@ -57,12 +57,10 @@ def process_cve_advisory_mapping(self):
5757
self.log(f"Could not find CVE ID in URL: {severity.url}")
5858
continue
5959

60-
matching_advisories = Advisory.objects.filter(
61-
aliases=[cve_id],
62-
created_by="nvd_importer",
63-
)
60+
if matching_alias := Alias.objects.get(alias=cve_id):
61+
matching_advisories = matching_alias.advisories.filter(created_by="nvd_importer")
6462

65-
for advisory in matching_advisories:
63+
for advisory in matching_advisories or []:
6664
for reference in advisory.references:
6765
for sev in reference.get("severities", []):
6866
if sev.get("system") == "cvssv3.1":
@@ -76,7 +74,6 @@ def process_cve_advisory_mapping(self):
7674
)
7775

7876
if results:
79-
print(results)
8077
self._process_batch(results)
8178

8279
self.log(f"Completed processing CVE to Advisory mappings")

vulnerabilities/pipes/advisory.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@
1212
from datetime import timezone
1313
from traceback import format_exc as traceback_format_exc
1414
from typing import Callable
15+
from typing import List
1516

1617
from django.db import transaction
1718

1819
from vulnerabilities.importer import AdvisoryData
1920
from vulnerabilities.improver import MAX_CONFIDENCE
2021
from vulnerabilities.models import Advisory
2122
from vulnerabilities.models import AffectedByPackageRelatedVulnerability
23+
from vulnerabilities.models import Alias
2224
from vulnerabilities.models import FixingPackageRelatedVulnerability
2325
from vulnerabilities.models import Package
2426
from vulnerabilities.models import VulnerabilityReference
@@ -27,11 +29,17 @@
2729
from vulnerabilities.models import Weakness
2830

2931

32+
def get_or_create_aliases(aliases: List) -> List:
33+
for alias in aliases:
34+
Alias.objects.get_or_create(alias=alias)
35+
return Alias.objects.filter(alias__in=aliases)
36+
37+
3038
def insert_advisory(advisory: AdvisoryData, pipeline_id: str, logger: Callable = None):
31-
obj = None
39+
advisory_obj = None
40+
aliases = get_or_create_aliases(aliases=advisory.aliases)
3241
try:
33-
obj, _ = Advisory.objects.get_or_create(
34-
aliases=advisory.aliases,
42+
advisory_obj, _ = Advisory.objects.get_or_create(
3543
summary=advisory.summary,
3644
affected_packages=[pkg.to_dict() for pkg in advisory.affected_packages],
3745
references=[ref.to_dict() for ref in advisory.references],
@@ -43,14 +51,15 @@ def insert_advisory(advisory: AdvisoryData, pipeline_id: str, logger: Callable =
4351
"date_collected": datetime.now(timezone.utc),
4452
},
4553
)
54+
advisory_obj.aliases.add(*aliases)
4655
except Exception as e:
4756
if logger:
4857
logger(
4958
f"Error while processing {advisory!r} with aliases {advisory.aliases!r}: {e!r} \n {traceback_format_exc()}",
5059
level=logging.ERROR,
5160
)
5261

53-
return obj
62+
return advisory_obj
5463

5564

5665
@transaction.atomic
@@ -82,9 +91,10 @@ def import_advisory(
8291
affected_purls.extend(package_affected_purls)
8392
fixed_purls.extend(package_fixed_purls)
8493

94+
aliases = get_or_create_aliases(advisory_data.aliases)
8595
vulnerability = import_runner.get_or_create_vulnerability_and_aliases(
8696
vulnerability_id=None,
87-
aliases=advisory_data.aliases,
97+
aliases=aliases,
8898
summary=advisory_data.summary,
8999
advisory=advisory,
90100
)

0 commit comments

Comments
 (0)