Skip to content

Commit 1717f51

Browse files
authored
Merge pull request #731 from TG1999/fix_severity_model
Fix severity model
2 parents b585b16 + f5222a1 commit 1717f51

9 files changed

Lines changed: 221 additions & 8 deletions

vulnerabilities/improve_runner.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ def process_inferences(inferences: List[Inference], advisory: Advisory, improver
7272

7373
for severity in ref.severities:
7474
_vs, updated = models.VulnerabilitySeverity.objects.update_or_create(
75-
vulnerability=vuln,
7675
scoring_system=severity.system.identifier,
7776
reference=reference,
7877
defaults={"value": str(severity.value)},
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Copyright (c) nexB Inc. and others. All rights reserved.
2+
# http://nexb.com and https://github.com/nexB/vulnerablecode/
3+
# The VulnerableCode software is licensed under the Apache License version 2.0.
4+
# Data generated with VulnerableCode require an acknowledgment.
5+
#
6+
# You may not use this software except in compliance with the License.
7+
# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
8+
# Unless required by applicable law or agreed to in writing, software distributed
9+
# under the License is distributed on an 'AS IS' BASIS, WITHOUT WARRANTIES OR
10+
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
# specific language governing permissions and limitations under the License.
12+
#
13+
# When you publish or redistribute any data created with VulnerableCode or any VulnerableCode
14+
# derivative work, you must accompany this data with the following acknowledgment:
15+
#
16+
# Generated with VulnerableCode and provided on an 'AS IS' BASIS, WITHOUT WARRANTIES
17+
# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
18+
# VulnerableCode should be considered or used as legal advice. Consult an Attorney
19+
# for any legal advice.
20+
# VulnerableCode is a free software code scanning tool from nexB Inc. and others.
21+
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
22+
23+
from django.db import migrations
24+
from django.db.models import Count
25+
from django.db.models import Max
26+
27+
28+
class Migration(migrations.Migration):
29+
30+
dependencies = [
31+
("vulnerabilities", "0013_auto_20220503_0941"),
32+
]
33+
34+
def remove_duplicate_rows(apps, schema_editor):
35+
"""
36+
Find all duplicate rows and remove all of them except the latest one.
37+
"""
38+
unique_fields = [
39+
"reference",
40+
"scoring_system",
41+
"value",
42+
]
43+
Severities = apps.get_model("vulnerabilities", "VulnerabilitySeverity")
44+
# Get all duplicates according to the unique_fields
45+
duplicates = (
46+
Severities.objects.values(*unique_fields)
47+
.order_by()
48+
.annotate(max_id=Max("id"), count_id=Count("id"))
49+
.filter(count_id__gt=1)
50+
)
51+
for duplicate in duplicates:
52+
unique_fields_data = {
53+
uniqe_field: duplicate[uniqe_field] for uniqe_field in unique_fields
54+
}
55+
# Get all rows with the same unique_fields_data
56+
# exclude the latest one
57+
# and delete rest of them
58+
(
59+
Severities.objects.filter(**unique_fields_data)
60+
.exclude(id=duplicate["max_id"])
61+
.delete()
62+
)
63+
64+
# sepecifying migrations.RunPython.noop as reverse_code
65+
operations = [migrations.RunPython(remove_duplicate_rows, migrations.RunPython.noop)]
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Generated by Django 4.0.4 on 2022-05-16 15:07
2+
3+
from django.db import migrations
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('vulnerabilities', '0014_remove_duplicate_severities'),
10+
]
11+
12+
operations = [
13+
migrations.AlterUniqueTogether(
14+
name='vulnerabilityseverity',
15+
unique_together={('reference', 'scoring_system', 'value')},
16+
),
17+
migrations.RemoveField(
18+
model_name='vulnerabilityseverity',
19+
name='vulnerability',
20+
),
21+
]

vulnerabilities/models.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,6 @@ def update_or_create(self):
300300

301301
class VulnerabilitySeverity(models.Model):
302302

303-
vulnerability = models.ForeignKey(Vulnerability, on_delete=models.CASCADE)
304303
reference = models.ForeignKey(VulnerabilityReference, on_delete=models.CASCADE)
305304

306305
scoring_system_choices = tuple(
@@ -322,7 +321,6 @@ class VulnerabilitySeverity(models.Model):
322321

323322
class Meta:
324323
unique_together = (
325-
"vulnerability",
326324
"reference",
327325
"scoring_system",
328326
"value",
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# Copyright (c) nexB Inc. and others. All rights reserved.
2+
# http://nexb.com and https://github.com/nexB/vulnerablecode/
3+
# The VulnerableCode software is licensed under the Apache License version 2.0.
4+
# Data generated with VulnerableCode require an acknowledgment.
5+
#
6+
# You may not use this software except in compliance with the License.
7+
# You may obtain a copy of the License at: http://apache.org/licenses/LICENSE-2.0
8+
# Unless required by applicable law or agreed to in writing, software distributed
9+
# under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
10+
# CONDITIONS OF ANY KIND, either express or implied. See the License for the
11+
# specific language governing permissions and limitations under the License.
12+
#
13+
# When you publish or redistribute any data created with VulnerableCode or any VulnerableCode
14+
# derivative work, you must accompany this data with the following acknowledgment:
15+
#
16+
# Generated with VulnerableCode and provided on an "AS IS" BASIS, WITHOUT WARRANTIES
17+
# OR CONDITIONS OF ANY KIND, either express or implied. No content created from
18+
# VulnerableCode should be considered or used as legal advice. Consult an Attorney
19+
# for any legal advice.
20+
# VulnerableCode is a free software tool from nexB Inc. and others.
21+
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
22+
23+
from django.apps import apps
24+
from django.db import connection
25+
from django.db.migrations.executor import MigrationExecutor
26+
from django.test import TestCase
27+
28+
from vulnerabilities import severity_systems
29+
from vulnerabilities.models import VulnerabilityReference
30+
from vulnerabilities.models import VulnerabilitySeverity
31+
32+
33+
class TestMigrations(TestCase):
34+
@property
35+
def app(self):
36+
return apps.get_containing_app_config(type(self).__module__).name
37+
38+
migrate_from = None
39+
migrate_to = None
40+
41+
def setUp(self):
42+
assert (
43+
self.migrate_from and self.migrate_to
44+
), "TestCase '{}' must define migrate_from and migrate_to properties".format(
45+
type(self).__name__
46+
)
47+
self.migrate_from = [(self.app, self.migrate_from)]
48+
self.migrate_to = [(self.app, self.migrate_to)]
49+
executor = MigrationExecutor(connection)
50+
old_apps = executor.loader.project_state(self.migrate_from).apps
51+
52+
# # Reverse to the original migration
53+
executor.migrate(self.migrate_from)
54+
55+
self.setUpBeforeMigration(old_apps)
56+
57+
# Run the migration to test
58+
executor = MigrationExecutor(connection)
59+
executor.loader.build_graph() # reload.
60+
executor.migrate(self.migrate_to)
61+
62+
self.apps = executor.loader.project_state(self.migrate_to).apps
63+
64+
def setUpBeforeMigration(self, apps):
65+
pass
66+
67+
68+
class DuplicateSeverityTestCase(TestMigrations):
69+
70+
migrate_from = "0013_auto_20220503_0941"
71+
migrate_to = "0014_remove_duplicate_severities"
72+
73+
def setUpBeforeMigration(self, apps):
74+
# using get_model to avoid circular import
75+
VulnerabilityReference = apps.get_model("vulnerabilities", "VulnerabilityReference")
76+
Severities = apps.get_model("vulnerabilities", "VulnerabilitySeverity")
77+
Vulnerability = apps.get_model("vulnerabilities", "Vulnerability")
78+
79+
reference = VulnerabilityReference.objects.create(
80+
reference_id="CVE-TEST", url="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-TEST"
81+
)
82+
self.reference = reference
83+
vulnerability1 = Vulnerability(vulnerability_id=1, summary="test-1")
84+
vulnerability1.save()
85+
vulnerability2 = Vulnerability(vulnerability_id=2, summary="test-2")
86+
vulnerability2.save()
87+
vulnerability3 = Vulnerability(vulnerability_id=3, summary="test-3")
88+
vulnerability3.save()
89+
Severities.objects.update_or_create(
90+
vulnerability=vulnerability1,
91+
scoring_system=severity_systems.REDHAT_AGGREGATE.identifier,
92+
reference=reference,
93+
defaults={"value": str("TEST")},
94+
)
95+
Severities.objects.update_or_create(
96+
vulnerability=vulnerability2,
97+
scoring_system=severity_systems.REDHAT_AGGREGATE.identifier,
98+
reference=reference,
99+
defaults={"value": str("TEST")},
100+
)
101+
Severities.objects.update_or_create(
102+
vulnerability=vulnerability3,
103+
scoring_system=severity_systems.REDHAT_AGGREGATE.identifier,
104+
reference=reference,
105+
defaults={"value": str("TEST")},
106+
)
107+
108+
def test_remove_duplicate_rows(self):
109+
VulnerabilitySeverity = self.apps.get_model("vulnerabilities", "VulnerabilitySeverity")
110+
assert len(VulnerabilitySeverity.objects.filter(reference=self.reference.id)) == 1
111+
112+
113+
class DropVulnerabilityFromSeverityTestCase(TestMigrations):
114+
115+
migrate_from = "0014_remove_duplicate_severities"
116+
migrate_to = "0015_alter_vulnerabilityseverity_unique_together_and_more"
117+
118+
def test_dropping_vulnerability_from_severity(self):
119+
# using get_model to avoid circular import
120+
VulnerabilityReference = self.apps.get_model("vulnerabilities", "VulnerabilityReference")
121+
VulnerabilitySeverity = self.apps.get_model("vulnerabilities", "VulnerabilitySeverity")
122+
123+
reference = VulnerabilityReference.objects.create(
124+
reference_id="CVE-TEST", url="https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-TEST"
125+
)
126+
VulnerabilitySeverity.objects.update_or_create(
127+
scoring_system=severity_systems.REDHAT_AGGREGATE.identifier,
128+
reference=reference,
129+
defaults={"value": str("TEST")},
130+
)

vulnerabilities/tests/test_fix_api.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
# Visit https://github.com/nexB/vulnerablecode/ for support and download.
2222

2323
from django.test import TestCase
24+
from django.utils.http import int_to_base36
2425
from rest_framework import status
2526

2627
from vulnerabilities.models import Package
@@ -31,7 +32,7 @@
3132

3233
class APITestCaseVulnerability(TestCase):
3334
def setUp(self):
34-
for i in range(0, 10):
35+
for i in range(0, 200):
3536
Vulnerability.objects.create(
3637
summary=str(i),
3738
)
@@ -43,15 +44,15 @@ def test_api_status(self):
4344

4445
def test_api_response(self):
4546
response = self.client.get("/api/vulnerabilities/", format="json").data
46-
self.assertEqual(response["count"], 11)
47+
self.assertEqual(response["count"], 201)
4748

4849
def test_api_with_single_vulnerability(self):
4950
response = self.client.get(
5051
f"/api/vulnerabilities/{self.vulnerability.id}", format="json"
5152
).data
5253
assert response == {
5354
"url": f"http://testserver/api/vulnerabilities/{self.vulnerability.id}",
54-
"vulnerability_id": "VULCOID-Y",
55+
"vulnerability_id": f"VULCOID-{int_to_base36(self.vulnerability.id).upper()}",
5556
"summary": "test",
5657
"aliases": [],
5758
"fixed_packages": [],

vulnerabilities/tests/test_redhat_importer.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,6 @@ def test_redhat_importer(bugzilla, rhsa, fetcher):
6666
json.load(open(rhsa_1437)),
6767
json.load(open(rhsa_1439)),
6868
]
69-
print(fetcher.return_value)
7069
expected_file = os.path.join(TEST_DATA, f"redhat-expected.json")
7170
imported_data = list(redhat_importer.advisory_data())
7271
result = [data.to_dict() for data in imported_data]

vulnerabilities/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ def get_affected_packages_by_patched_package(
295295

296296

297297
# This code has been vendored from scancode.
298-
# https://github.com/nexB/scancode-toolkit/blob/develop/src/packagedcode/utils.py#L111
298+
# https://github.com/nexB/scancode-toolkit/blob/aba31126dcb3ab57f2b885090f7145f69b67351a/src/packagedcode/utils.py#L111
299299
def build_description(summary, description):
300300
"""
301301
Return a description string from a summary and description

0 commit comments

Comments
 (0)