Skip to content

Commit 112f746

Browse files
committed
Create impacted pkg during advisory insertion in v2 base importer
Signed-off-by: Keshav Priyadarshi <git@keshav.space>
1 parent 58fff59 commit 112f746

File tree

5 files changed

+130
-229
lines changed

5 files changed

+130
-229
lines changed

vulnerabilities/pipelines/__init__.py

Lines changed: 5 additions & 215 deletions
Original file line numberDiff line numberDiff line change
@@ -15,29 +15,18 @@
1515
from traceback import format_exc as traceback_format_exc
1616
from typing import Iterable
1717
from typing import List
18-
from typing import Optional
1918

2019
from aboutcode.pipeline import LoopProgress
2120
from aboutcode.pipeline import PipelineDefinition
2221
from aboutcode.pipeline import humanize_time
23-
from fetchcode import package_versions
24-
from packageurl import PackageURL
2522

2623
from vulnerabilities.importer import AdvisoryData
27-
from vulnerabilities.importer import AffectedPackage
28-
from vulnerabilities.importer import UnMergeablePackageError
2924
from vulnerabilities.improver import MAX_CONFIDENCE
3025
from vulnerabilities.models import Advisory
31-
from vulnerabilities.models import PackageV2
3226
from vulnerabilities.models import PipelineRun
3327
from vulnerabilities.pipes.advisory import import_advisory
3428
from vulnerabilities.pipes.advisory import insert_advisory
3529
from vulnerabilities.pipes.advisory import insert_advisory_v2
36-
from vulnerabilities.utils import AffectedPackage as LegacyAffectedPackage
37-
from vulnerabilities.utils import classproperty
38-
from vulnerabilities.utils import get_affected_packages_by_patched_package
39-
from vulnerabilities.utils import nearest_patched_package
40-
from vulnerabilities.utils import resolve_version_range
4130

4231
module_logger = logging.getLogger(__name__)
4332

@@ -271,13 +260,15 @@ class VulnerableCodeBaseImporterPipelineV2(VulnerableCodePipeline):
271260
license_url = None
272261
spdx_license_expression = None
273262
repo_url = None
274-
advisory_confidence = MAX_CONFIDENCE
275263
ignorable_versions = []
276-
unfurl_version_ranges = False
277264

278265
@classmethod
279266
def steps(cls):
280-
return (cls.collect_and_store_advisories,)
267+
return (
268+
# Add step for downloading/cloning resource as required.
269+
cls.collect_and_store_advisories,
270+
# Add step for removing downloaded/cloned resource as required.
271+
)
281272

282273
def collect_advisories(self) -> Iterable[AdvisoryData]:
283274
"""
@@ -311,7 +302,6 @@ def collect_and_store_advisories(self):
311302
if _obj := insert_advisory_v2(
312303
advisory=advisory,
313304
pipeline_id=self.pipeline_id,
314-
get_advisory_packages=self.get_advisory_packages,
315305
logger=self.log,
316306
):
317307
collected_advisory_count += 1
@@ -323,203 +313,3 @@ def collect_and_store_advisories(self):
323313
continue
324314

325315
self.log(f"Successfully collected {collected_advisory_count:,d} advisories")
326-
327-
def get_advisory_packages(self, advisory_data: AdvisoryData) -> list:
328-
"""
329-
Return the list of packages for the given advisory.
330-
331-
Used by ``import_advisory`` to get the list of packages for the advisory.
332-
"""
333-
from vulnerabilities.improvers import default
334-
335-
affected_purls = []
336-
fixed_purls = []
337-
for affected_package in advisory_data.affected_packages:
338-
package_affected_purls, package_fixed_purls = default.get_exact_purls(
339-
affected_package=affected_package
340-
)
341-
affected_purls.extend(package_affected_purls)
342-
fixed_purls.extend(package_fixed_purls)
343-
344-
if self.unfurl_version_ranges:
345-
vulnerable_pvs, fixed_pvs = self.get_impacted_packages(
346-
affected_packages=advisory_data.affected_packages,
347-
advisory_date_published=advisory_data.date_published,
348-
)
349-
affected_purls.extend(vulnerable_pvs)
350-
fixed_purls.extend(fixed_pvs)
351-
352-
vulnerable_packages = []
353-
fixed_packages = []
354-
355-
for affected_purl in affected_purls:
356-
vulnerable_package, _ = PackageV2.objects.get_or_create_from_purl(purl=affected_purl)
357-
vulnerable_packages.append(vulnerable_package)
358-
359-
for fixed_purl in fixed_purls:
360-
fixed_package, _ = PackageV2.objects.get_or_create_from_purl(purl=fixed_purl)
361-
fixed_packages.append(fixed_package)
362-
363-
return vulnerable_packages, fixed_packages
364-
365-
def get_published_package_versions(
366-
self, package_url: PackageURL, until: Optional[datetime] = None
367-
) -> List[str]:
368-
"""
369-
Return a list of versions published before `until` for the `package_url`
370-
"""
371-
versions_before_until = []
372-
try:
373-
versions = package_versions.versions(str(package_url))
374-
for version in versions or []:
375-
if (
376-
version.release_date
377-
and version.release_date.tzinfo
378-
and until
379-
and until.tzinfo is None
380-
):
381-
until = until.replace(tzinfo=timezone.utc)
382-
if until and version.release_date and version.release_date > until:
383-
continue
384-
versions_before_until.append(version.value)
385-
386-
return versions_before_until
387-
except Exception as e:
388-
self.log(
389-
f"Failed to fetch versions for package {str(package_url)} {e!r}",
390-
level=logging.ERROR,
391-
)
392-
return []
393-
394-
def get_impacted_packages(self, affected_packages, advisory_date_published):
395-
"""
396-
Return a tuple of lists of affected and fixed PackageURLs
397-
"""
398-
if not affected_packages:
399-
return [], []
400-
401-
mergable = True
402-
403-
# TODO: We should never had the exception in first place
404-
try:
405-
purl, affected_version_ranges, fixed_versions = AffectedPackage.merge(affected_packages)
406-
except UnMergeablePackageError:
407-
self.log(f"Cannot merge with different purls {affected_packages!r}", logging.ERROR)
408-
mergable = False
409-
410-
if not mergable:
411-
vulnerable_packages = []
412-
fixed_packages = []
413-
for affected_package in affected_packages:
414-
purl = affected_package.package
415-
affected_version_range = affected_package.affected_version_range
416-
fixed_version = affected_package.fixed_version
417-
pkg_type = purl.type
418-
pkg_namespace = purl.namespace
419-
pkg_name = purl.name
420-
if not affected_version_range and fixed_version:
421-
fixed_packages.append(
422-
PackageURL(
423-
type=pkg_type,
424-
namespace=pkg_namespace,
425-
name=pkg_name,
426-
version=str(fixed_version),
427-
)
428-
)
429-
else:
430-
valid_versions = self.get_published_package_versions(
431-
package_url=purl, until=advisory_date_published
432-
)
433-
affected_pvs, fixed_pvs = self.resolve_package_versions(
434-
affected_version_range=affected_version_range,
435-
pkg_type=pkg_type,
436-
pkg_namespace=pkg_namespace,
437-
pkg_name=pkg_name,
438-
valid_versions=valid_versions,
439-
)
440-
vulnerable_packages.extend(affected_pvs)
441-
fixed_packages.extend(fixed_pvs)
442-
return vulnerable_packages, fixed_packages
443-
else:
444-
pkg_type = purl.type
445-
pkg_namespace = purl.namespace
446-
pkg_name = purl.name
447-
pkg_qualifiers = purl.qualifiers
448-
fixed_purls = [
449-
PackageURL(
450-
type=pkg_type,
451-
namespace=pkg_namespace,
452-
name=pkg_name,
453-
version=str(version),
454-
qualifiers=pkg_qualifiers,
455-
)
456-
for version in fixed_versions
457-
]
458-
if not affected_version_ranges:
459-
return [], fixed_purls
460-
else:
461-
valid_versions = self.get_published_package_versions(
462-
package_url=purl, until=advisory_date_published
463-
)
464-
vulnerable_packages = []
465-
fixed_packages = []
466-
for affected_version_range in affected_version_ranges:
467-
vulnerable_pvs, fixed_pvs = self.resolve_package_versions(
468-
affected_version_range=affected_version_range,
469-
pkg_type=pkg_type,
470-
pkg_namespace=pkg_namespace,
471-
pkg_name=pkg_name,
472-
valid_versions=valid_versions,
473-
)
474-
vulnerable_packages.extend(vulnerable_pvs)
475-
fixed_packages.extend(fixed_pvs)
476-
return vulnerable_packages, fixed_packages
477-
478-
def resolve_package_versions(
479-
self,
480-
affected_version_range,
481-
pkg_type,
482-
pkg_namespace,
483-
pkg_name,
484-
valid_versions,
485-
):
486-
"""
487-
Return a tuple of lists of ``affected_packages`` and ``fixed_packages`` PackageURL for the given `affected_version_range` and `valid_versions`.
488-
489-
``valid_versions`` are the valid version listed on the package registry for that package
490-
491-
"""
492-
aff_vers, unaff_vers = resolve_version_range(
493-
affected_version_range=affected_version_range,
494-
ignorable_versions=self.ignorable_versions,
495-
package_versions=valid_versions,
496-
)
497-
498-
affected_purls = list(
499-
self.expand_verion_range_to_purls(pkg_type, pkg_namespace, pkg_name, aff_vers)
500-
)
501-
502-
unaffected_purls = list(
503-
self.expand_verion_range_to_purls(pkg_type, pkg_namespace, pkg_name, unaff_vers)
504-
)
505-
506-
fixed_packages = []
507-
affected_packages = []
508-
509-
patched_packages = nearest_patched_package(
510-
vulnerable_packages=affected_purls, resolved_packages=unaffected_purls
511-
)
512-
513-
for (
514-
fixed_package,
515-
affected_purls,
516-
) in get_affected_packages_by_patched_package(patched_packages).items():
517-
if fixed_package:
518-
fixed_packages.append(fixed_package)
519-
affected_packages.extend(affected_purls)
520-
521-
return affected_packages, fixed_packages
522-
523-
def expand_verion_range_to_purls(self, pkg_type, pkg_namespace, pkg_name, versions):
524-
for version in versions:
525-
yield PackageURL(type=pkg_type, namespace=pkg_namespace, name=pkg_name, version=version)

vulnerabilities/pipes/advisory.py

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
from vulnerabilities.models import VulnerabilityRelatedReference
3636
from vulnerabilities.models import VulnerabilitySeverity
3737
from vulnerabilities.models import Weakness
38+
from vulnerabilities.pipes.univers_utils import get_exact_purls_v2
3839

3940

4041
def get_or_create_aliases(aliases: List) -> QuerySet:
@@ -43,9 +44,6 @@ def get_or_create_aliases(aliases: List) -> QuerySet:
4344
return Alias.objects.filter(alias__in=aliases)
4445

4546

46-
from django.db.models import Q
47-
48-
4947
def get_or_create_advisory_aliases(aliases: List[str]) -> List[AdvisoryAlias]:
5048
existing = AdvisoryAlias.objects.filter(alias__in=aliases)
5149
existing_aliases = {a.alias for a in existing}
@@ -139,9 +137,10 @@ def insert_advisory(advisory: AdvisoryData, pipeline_id: str, logger: Callable =
139137
def insert_advisory_v2(
140138
advisory: AdvisoryData,
141139
pipeline_id: str,
142-
get_advisory_packages: Callable,
143140
logger: Callable = None,
144141
):
142+
from vulnerabilities.models import ImpactedPackage
143+
from vulnerabilities.models import PackageV2
145144
from vulnerabilities.utils import compute_content_id
146145

147146
advisory_obj = None
@@ -150,7 +149,6 @@ def insert_advisory_v2(
150149
severities = get_or_create_advisory_severities(severities=advisory.severities)
151150
weaknesses = get_or_create_advisory_weaknesses(weaknesses=advisory.weaknesses)
152151
content_id = compute_content_id(advisory_data=advisory)
153-
affecting_packages, fixed_by_packages = get_advisory_packages(advisory_data=advisory)
154152
try:
155153
default_data = {
156154
"datasource_id": pipeline_id,
@@ -162,7 +160,7 @@ def insert_advisory_v2(
162160
"original_advisory_text": advisory.original_advisory_text,
163161
}
164162

165-
advisory_obj, _ = AdvisoryV2.objects.get_or_create(
163+
advisory_obj, created = AdvisoryV2.objects.get_or_create(
166164
unique_content_id=content_id,
167165
url=advisory.url,
168166
defaults=default_data,
@@ -172,8 +170,6 @@ def insert_advisory_v2(
172170
"references": references,
173171
"severities": severities,
174172
"weaknesses": weaknesses,
175-
"fixed_by_packages": fixed_by_packages,
176-
"affecting_packages": affecting_packages,
177173
}
178174

179175
for field_name, values in related_fields.items():
@@ -192,6 +188,29 @@ def insert_advisory_v2(
192188
level=logging.ERROR,
193189
)
194190

191+
if created:
192+
for affected_pkg in advisory.affected_packages:
193+
impact = ImpactedPackage.objects.create(
194+
advisory=advisory_obj,
195+
base_purl=str(affected_pkg.package),
196+
affecting_vers=str(affected_pkg.affected_version_range),
197+
fixed_vers=str(affected_pkg.fixed_version_range),
198+
)
199+
package_affected_purls, package_fixed_purls = get_exact_purls_v2(
200+
affected_package=affected_pkg,
201+
logger=logger,
202+
)
203+
affected_packages_v2 = [
204+
PackageV2.objects.get_or_create_from_purl(purl=purl)[0]
205+
for purl in package_affected_purls
206+
]
207+
fixed_packages_v2 = [
208+
PackageV2.objects.get_or_create_from_purl(purl=purl)[0]
209+
for purl in package_fixed_purls
210+
]
211+
impact.affecting_packages.add(*affected_packages_v2)
212+
impact.fixed_by_packages.add(*fixed_packages_v2)
213+
195214
return advisory_obj
196215

197216

0 commit comments

Comments
 (0)