Skip to content

Commit

Permalink
Add migrations files #95
Browse files Browse the repository at this point in the history
Signed-off-by: tdruez <tdruez@nexb.com>
  • Loading branch information
tdruez committed Sep 4, 2024
1 parent c97c73d commit ec4f5d4
Show file tree
Hide file tree
Showing 18 changed files with 202 additions and 32 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Generated by Django 5.0.6 on 2024-09-04 08:17

from django.db import migrations


class Migration(migrations.Migration):

dependencies = [
('component_catalog', '0007_vulnerability_fixed_packages_count_and_more'),
]

operations = [
migrations.RemoveField(
model_name='package',
name='affected_by_vulnerabilities',
),
migrations.RemoveField(
model_name='component',
name='affected_by_vulnerabilities',
),
migrations.DeleteModel(
name='Vulnerability',
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Generated by Django 5.0.6 on 2024-09-04 08:17

import django.db.models.deletion
import uuid
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('component_catalog', '0008_remove_package_affected_by_vulnerabilities_and_more'),
('dje', '0004_dataspace_vulnerabilities_updated_at'),
('vulnerabilities', '0001_initial'),
]

operations = [
migrations.CreateModel(
name='ComponentAffectedByVulnerability',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('uuid', models.UUIDField(default=uuid.uuid4, editable=False, verbose_name='UUID')),
('component', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='component_catalog.component')),
('dataspace', models.ForeignKey(editable=False, help_text='A Dataspace is an independent, exclusive set of DejaCode data, which can be either nexB master reference data or installation-specific data.', on_delete=django.db.models.deletion.PROTECT, to='dje.dataspace')),
('vulnerability', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='vulnerabilities.vulnerability')),
],
options={
'unique_together': {('component', 'vulnerability'), ('dataspace', 'uuid')},
},
),
migrations.AddField(
model_name='component',
name='affected_by_vulnerabilities',
field=models.ManyToManyField(help_text='Vulnerabilities affecting this object.', related_name='affected_%(class)ss', through='component_catalog.ComponentAffectedByVulnerability', to='vulnerabilities.vulnerability'),
),
migrations.CreateModel(
name='PackageAffectedByVulnerability',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('uuid', models.UUIDField(default=uuid.uuid4, editable=False, verbose_name='UUID')),
('dataspace', models.ForeignKey(editable=False, help_text='A Dataspace is an independent, exclusive set of DejaCode data, which can be either nexB master reference data or installation-specific data.', on_delete=django.db.models.deletion.PROTECT, to='dje.dataspace')),
('package', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='component_catalog.package')),
('vulnerability', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='vulnerabilities.vulnerability')),
],
options={
'unique_together': {('dataspace', 'uuid'), ('package', 'vulnerability')},
},
),
migrations.AddField(
model_name='package',
name='affected_by_vulnerabilities',
field=models.ManyToManyField(help_text='Vulnerabilities affecting this object.', related_name='affected_%(class)ss', through='component_catalog.PackageAffectedByVulnerability', to='vulnerabilities.vulnerability'),
),
]
50 changes: 47 additions & 3 deletions component_catalog/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@
from license_library.models import LicenseChoice
from policy.models import SetPolicyFromLicenseMixin
from policy.models import UsagePolicyMixin
from vulnerabilities.models import VulnerabilityMixin
from vulnerabilities.models import AffectedByVulnerabilityMixin
from workflow.models import RequestMixin

logger = logging.getLogger("dje")
Expand Down Expand Up @@ -889,7 +889,7 @@ class Component(
HolderMixin,
KeywordsMixin,
CPEMixin,
VulnerabilityMixin,
AffectedByVulnerabilityMixin,
LicenseFieldsMixin,
ParentChildModelMixin,
BaseComponentMixin,
Expand Down Expand Up @@ -1226,6 +1226,13 @@ class Component(
through="ComponentAssignedPackage",
)

affected_by_vulnerabilities = models.ManyToManyField(
to="vulnerabilities.Vulnerability",
through="ComponentAffectedByVulnerability",
related_name="affected_%(class)ss",
help_text=_("Vulnerabilities affecting this object."),
)

objects = DataspacedManager.from_queryset(ComponentQuerySet)()

class Meta(BaseComponentMixin.Meta):
Expand Down Expand Up @@ -1693,7 +1700,7 @@ class Package(
HolderMixin,
KeywordsMixin,
CPEMixin,
VulnerabilityMixin,
AffectedByVulnerabilityMixin,
URLFieldsMixin,
HashFieldsMixin,
PackageURLMixin,
Expand Down Expand Up @@ -1834,6 +1841,12 @@ class Package(
to="license_library.License",
through="PackageAssignedLicense",
)
affected_by_vulnerabilities = models.ManyToManyField(
to="vulnerabilities.Vulnerability",
through="PackageAffectedByVulnerability",
related_name="affected_%(class)ss",
help_text=_("Vulnerabilities affecting this object."),
)

objects = DataspacedManager.from_queryset(PackageQuerySet)()

Expand Down Expand Up @@ -2489,6 +2502,37 @@ def __str__(self):
return f"{self.package} is under {self.license}."


# TODO: Review cascade
class PackageAffectedByVulnerability(DataspacedModel):
package = models.ForeignKey(
to="component_catalog.Package",
on_delete=models.CASCADE,
)

vulnerability = models.ForeignKey(
to="vulnerabilities.Vulnerability",
on_delete=models.PROTECT,
)

class Meta:
unique_together = (("package", "vulnerability"), ("dataspace", "uuid"))


class ComponentAffectedByVulnerability(DataspacedModel):
component = models.ForeignKey(
to="component_catalog.Component",
on_delete=models.CASCADE,
)

vulnerability = models.ForeignKey(
to="vulnerabilities.Vulnerability",
on_delete=models.PROTECT,
)

class Meta:
unique_together = (("component", "vulnerability"), ("dataspace", "uuid"))


class ComponentAssignedPackage(DataspacedModel):
component = models.ForeignKey(
to="component_catalog.Component",
Expand Down
18 changes: 1 addition & 17 deletions component_catalog/tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from component_catalog.models import Component
from component_catalog.models import Package
from dje.tests import make_string
from vulnerabilities.models import Vulnerability
from vulnerabilities.tests import make_vulnerability


def make_package(dataspace, package_url=None, is_vulnerable=False, **data):
Expand Down Expand Up @@ -42,19 +42,3 @@ def make_component(dataspace, is_vulnerable=False, **data):
make_vulnerability(dataspace, affecting=component)

return component


def make_vulnerability(dataspace, affecting=None, **data):
"""Create a vulnerability for test purposes."""
if "vulnerability_id" not in data:
data["vulnerability_id"] = f"VCID-0000-{make_string(4)}"

vulnerability = Vulnerability.objects.create(
dataspace=dataspace,
**data,
)

if affecting:
vulnerability.add_affected(affecting)

return vulnerability
2 changes: 1 addition & 1 deletion component_catalog/tests/test_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
from component_catalog.models import ComponentType
from component_catalog.tests import make_component
from component_catalog.tests import make_package
from component_catalog.tests import make_vulnerability
from dje.models import Dataspace
from dje.tests import create_superuser
from dje.tests import create_user
from license_library.models import License
from organization.models import Owner
from policy.models import UsagePolicy
from vulnerabilities.tests import make_vulnerability


class ComponentFilterSetTest(TestCase):
Expand Down
2 changes: 1 addition & 1 deletion component_catalog/tests/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
from component_catalog.models import Subcomponent
from component_catalog.tests import make_component
from component_catalog.tests import make_package
from component_catalog.tests import make_vulnerability
from dejacode_toolkit import download
from dejacode_toolkit.download import DataCollectionException
from dejacode_toolkit.download import collect_package_data
Expand All @@ -59,6 +58,7 @@
from organization.models import Owner
from product_portfolio.tests import make_product
from vulnerabilities.models import Vulnerability
from vulnerabilities.tests import make_vulnerability


class ComponentCatalogModelsTestCase(TestCase):
Expand Down
2 changes: 1 addition & 1 deletion component_catalog/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
from component_catalog.models import Subcomponent
from component_catalog.tests import make_component
from component_catalog.tests import make_package
from component_catalog.tests import make_vulnerability
from component_catalog.views import ComponentAddView
from component_catalog.views import ComponentListView
from component_catalog.views import PackageTabScanView
Expand Down Expand Up @@ -72,6 +71,7 @@
from product_portfolio.models import ProductPackage
from product_portfolio.models import ProductRelationStatus
from vulnerabilities.models import Vulnerability
from vulnerabilities.tests import make_vulnerability
from workflow.models import Request
from workflow.models import RequestTemplate

Expand Down
3 changes: 0 additions & 3 deletions component_catalog/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
from django.core import signing
from django.core.validators import EMPTY_VALUES
from django.db.models import Count
from django.db.models import F
from django.db.models import Prefetch
from django.http import FileResponse
from django.http import Http404
Expand Down Expand Up @@ -53,7 +52,6 @@

from component_catalog.filters import ComponentFilterSet
from component_catalog.filters import PackageFilterSet
from component_catalog.filters import VulnerabilityFilterSet
from component_catalog.forms import AddMultipleToComponentForm
from component_catalog.forms import AddToComponentForm
from component_catalog.forms import AddToProductAdminForm
Expand Down Expand Up @@ -108,7 +106,6 @@
from policy.models import UsagePolicy
from product_portfolio.models import ProductComponent
from product_portfolio.models import ProductPackage
from vulnerabilities.models import Vulnerability

License = apps.get_model("license_library", "License")

Expand Down
2 changes: 1 addition & 1 deletion dje/tests/test_outputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
from cyclonedx.model import bom as cyclonedx_bom

from component_catalog.tests import make_package
from component_catalog.tests import make_vulnerability
from dejacode import __version__ as dejacode_version
from dje import outputs
from dje.models import Dataspace
from dje.tests import create_superuser
from dje.tests import create_user
from product_portfolio.models import Product
from product_portfolio.tests import make_product_package
from vulnerabilities.tests import make_vulnerability


class OutputsTestCase(TestCase):
Expand Down
2 changes: 1 addition & 1 deletion product_portfolio/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
from component_catalog.models import ComponentKeyword
from component_catalog.models import Package
from component_catalog.tests import make_package
from component_catalog.tests import make_vulnerability
from dejacode_toolkit import scancodeio
from dje.models import Dataspace
from dje.models import History
Expand Down Expand Up @@ -60,6 +59,7 @@
from product_portfolio.tests import make_product
from product_portfolio.tests import make_product_package
from product_portfolio.views import ManageComponentGridView
from vulnerabilities.tests import make_vulnerability
from workflow.models import Request
from workflow.models import RequestTemplate

Expand Down
41 changes: 41 additions & 0 deletions vulnerabilities/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Generated by Django 5.0.6 on 2024-09-04 08:13

import django.db.models.deletion
import dje.fields
import uuid
from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = [
('dje', '0004_dataspace_vulnerabilities_updated_at'),
]

operations = [
migrations.CreateModel(
name='Vulnerability',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('uuid', models.UUIDField(default=uuid.uuid4, editable=False, verbose_name='UUID')),
('created_date', models.DateTimeField(auto_now_add=True, db_index=True, help_text='The date and time the object was created.')),
('last_modified_date', models.DateTimeField(auto_now=True, db_index=True, help_text='The date and time the object was last modified.')),
('vulnerability_id', models.CharField(help_text="A unique identifier for the vulnerability, prefixed with 'VCID-'. For example, 'VCID-2024-0001'.", max_length=20)),
('summary', models.TextField(blank=True, help_text='A brief summary of the vulnerability, outlining its nature and impact.')),
('aliases', dje.fields.JSONListField(blank=True, default=list, help_text="A list of aliases for this vulnerability, such as CVE identifiers (e.g., 'CVE-2017-1000136').")),
('references', dje.fields.JSONListField(blank=True, default=list, help_text='A list of references for this vulnerability. Each reference includes a URL, an optional reference ID, scores, and the URL for further details. ')),
('fixed_packages', dje.fields.JSONListField(blank=True, default=list, help_text='A list of packages that are not affected by this vulnerability.')),
('fixed_packages_count', models.GeneratedField(db_persist=True, expression=models.Func(models.F('fixed_packages'), function='jsonb_array_length'), output_field=models.IntegerField())),
('min_score', models.FloatField(blank=True, help_text='The minimum score of the range.', null=True)),
('max_score', models.FloatField(blank=True, help_text='The maximum score of the range.', null=True)),
('dataspace', models.ForeignKey(editable=False, help_text='A Dataspace is an independent, exclusive set of DejaCode data, which can be either nexB master reference data or installation-specific data.', on_delete=django.db.models.deletion.PROTECT, to='dje.dataspace')),
],
options={
'verbose_name_plural': 'Vulnerabilities',
'indexes': [models.Index(fields=['vulnerability_id'], name='vulnerabili_vulnera_92f044_idx')],
'unique_together': {('dataspace', 'uuid'), ('dataspace', 'vulnerability_id')},
},
),
]
2 changes: 1 addition & 1 deletion vulnerabilities/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,7 @@ def as_cyclonedx(self, affected_instances):
)


class VulnerabilityMixin(models.Model):
class AffectedByVulnerabilityMixin(models.Model):
"""Add the `vulnerability` many to many field."""

affected_by_vulnerabilities = models.ManyToManyField(
Expand Down
26 changes: 26 additions & 0 deletions vulnerabilities/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#
# Copyright (c) nexB Inc. and others. All rights reserved.
# DejaCode is a trademark of nexB Inc.
# SPDX-License-Identifier: AGPL-3.0-only
# See https://github.com/aboutcode-org/dejacode for support or download.
# See https://aboutcode.org for more information about AboutCode FOSS projects.
#

from dje.tests import make_string
from vulnerabilities.models import Vulnerability


def make_vulnerability(dataspace, affecting=None, **data):
"""Create a vulnerability for test purposes."""
if "vulnerability_id" not in data:
data["vulnerability_id"] = f"VCID-0000-{make_string(4)}"

vulnerability = Vulnerability.objects.create(
dataspace=dataspace,
**data,
)

if affecting:
vulnerability.add_affected(affecting)

return vulnerability
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
from vulnerabilities.fetch import fetch_from_vulnerablecode


class VulnerabilitiesTestCase(TestCase):
data = Path(__file__).parent / "testfiles"
class VulnerabilitiesFetchTestCase(TestCase):
data = Path(__file__).parent / "data"

def setUp(self):
self.dataspace = Dataspace.objects.create(name="nexB")
Expand Down
Loading

0 comments on commit ec4f5d4

Please sign in to comment.