Skip to content

Commit edf60bf

Browse files
committed
test: validate advisory federation against latest schema
Signed-off-by: Keshav Priyadarshi <git@keshav.space>
1 parent 58eb09f commit edf60bf

4 files changed

Lines changed: 83 additions & 16 deletions

File tree

docs/source/schemas/vulnerablecode-advisory.schema-0.1.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
}
5656
},
5757
"required": [
58-
"package"
58+
"purl"
5959
],
6060
"title": "Affected Package",
6161
"type": "object"
@@ -66,14 +66,14 @@
6666
"title": "Version Control Systems URL",
6767
"type": "string"
6868
},
69-
"commit_hash": {
69+
"commit": {
7070
"title": "Commit Hash",
7171
"type": "string"
7272
}
7373
},
7474
"required": [
7575
"vcs_url",
76-
"commit_hash"
76+
"commit"
7777
],
7878
"title": "Package Commit Patch",
7979
"type": "object"

vulnerabilities/pipes/export.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
from vulnerabilities.models import ImpactedPackageFixedBy
1616
from vulnerabilities.models import PackageV2
1717

18-
# Warning!
18+
# Note!
1919
# Any changes to the structure of the advisory exporter also require updating the advisory
2020
# schema documentation at `docs/source/advisory-schema.rst`.
2121

vulnerabilities/tests/pipelines/exporters/test_federate_vulnerabilities.py

Lines changed: 66 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,28 @@
88
#
99

1010

11+
import json
12+
import shutil
1113
import tempfile
1214
from datetime import datetime
1315
from datetime import timedelta
1416
from pathlib import Path
1517
from unittest.mock import patch
1618

19+
import saneyaml
1720
from django.test import TestCase
1821
from django.utils import timezone
1922
from git import Repo
23+
from jsonschema import Draft7Validator
2024
from packageurl import PackageURL
2125
from univers.version_range import VersionRange
2226

27+
from vulnerabilities import severity_systems
2328
from vulnerabilities.importer import AdvisoryDataV2
2429
from vulnerabilities.importer import AffectedPackageV2
2530
from vulnerabilities.importer import PackageCommitPatchData
31+
from vulnerabilities.importer import ReferenceV2
32+
from vulnerabilities.importer import VulnerabilitySeverity
2633
from vulnerabilities.pipelines import insert_advisory_v2
2734
from vulnerabilities.pipelines.exporters.federate_vulnerabilities import (
2835
FederatePackageVulnerabilities,
@@ -34,6 +41,14 @@
3441
Path(__file__).parent.parent.parent / "test_data" / "exporters" / "federate_vulnerabilities"
3542
)
3643

44+
LATEST_FEDERATEDCODE_ADVISORY_SCHEMA = (
45+
Path(__file__).parent.parent.parent.parent.parent
46+
/ "docs"
47+
/ "source"
48+
/ "schemas"
49+
/ "vulnerablecode-advisory.schema-0.1.json"
50+
)
51+
3752

3853
class TestFederatePackageVulnerabilities(TestCase):
3954
def setUp(self):
@@ -62,9 +77,15 @@ def setUp(self):
6277
advisory2 = AdvisoryDataV2(
6378
summary="Test advisory2",
6479
aliases=["CVE-2025-0002"],
65-
references=[],
66-
severities=[],
67-
weaknesses=[],
80+
references=[ReferenceV2(url="https://example.com/vuln1")],
81+
severities=[
82+
VulnerabilitySeverity(
83+
system=severity_systems.CVSSV3,
84+
scoring_elements="CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
85+
value="8.8",
86+
),
87+
],
88+
weaknesses=[707, 20],
6889
affected_packages=[
6990
AffectedPackageV2(
7091
package=PackageURL.from_string("pkg:npm/foobar"),
@@ -104,6 +125,12 @@ def setUp(self):
104125
a2._all_impacts_unfurled_successfully_at = cur
105126
a2.save()
106127

128+
self.working_dir = Path(tempfile.mkdtemp())
129+
130+
def tearDown(self):
131+
if self.working_dir:
132+
shutil.rmtree(self.working_dir)
133+
107134
@patch(
108135
"vulnerabilities.pipelines.exporters.federate_vulnerabilities.FederatePackageVulnerabilities.clone_federation_repository"
109136
)
@@ -114,18 +141,17 @@ def test_vulnerabilities_federation_v2(self, mock_check_fed, mock_commit, mock_c
114141
mock_commit.return_value = None
115142
mock_clone.__name__ = "clone_federation_repository"
116143

117-
working_dir = Path(tempfile.mkdtemp())
118144
pipeline = FederatePackageVulnerabilities()
119-
pipeline.repo = Repo.init(working_dir)
120-
pipeline.repo_path = working_dir
145+
pipeline.repo = Repo.init(self.working_dir)
146+
pipeline.repo_path = self.working_dir
121147
pipeline.log = self.logger.write
122148
exit_code, _ = pipeline.execute()
123149

124150
self.assertEqual(exit_code, 0)
125151

126-
result_advisories_yml = next(working_dir.rglob("1.2.4/advisories.yml"))
127-
result_advisory1_yml = next(working_dir.rglob("ADV-001.yml"))
128-
result_advisory2_yml = next(working_dir.rglob("ADV-002.yml"))
152+
result_advisories_yml = next(self.working_dir.rglob("1.2.4/advisories.yml"))
153+
result_advisory1_yml = next(self.working_dir.rglob("ADV-001.yml"))
154+
result_advisory2_yml = next(self.working_dir.rglob("ADV-002.yml"))
129155

130156
expected_advisories_yml = TEST_DATA / "1.2.4" / "advisories-expected.yml"
131157
expected_advisory1_yml = TEST_DATA / "ADV-001-expected.yml"
@@ -134,3 +160,34 @@ def test_vulnerabilities_federation_v2(self, mock_check_fed, mock_commit, mock_c
134160
util_tests.check_results_and_expected_files(result_advisories_yml, expected_advisories_yml)
135161
util_tests.check_results_and_expected_files(result_advisory1_yml, expected_advisory1_yml)
136162
util_tests.check_results_and_expected_files(result_advisory2_yml, expected_advisory2_yml)
163+
164+
@patch(
165+
"vulnerabilities.pipelines.exporters.federate_vulnerabilities.FederatePackageVulnerabilities.clone_federation_repository"
166+
)
167+
@patch("vulnerabilities.pipes.federatedcode.commit_and_push_changes")
168+
@patch("vulnerabilities.pipes.federatedcode.check_federatedcode_configured_and_available")
169+
def test_vulnerabilities_federation_schema(self, mock_check_fed, mock_commit, mock_clone):
170+
mock_check_fed.return_value = None
171+
mock_commit.return_value = None
172+
mock_clone.__name__ = "clone_federation_repository"
173+
174+
pipeline = FederatePackageVulnerabilities()
175+
pipeline.repo = Repo.init(self.working_dir)
176+
pipeline.repo_path = self.working_dir
177+
pipeline.log = self.logger.write
178+
exit_code, _ = pipeline.execute()
179+
180+
self.assertEqual(exit_code, 0)
181+
182+
with LATEST_FEDERATEDCODE_ADVISORY_SCHEMA.open("r", encoding="utf-8") as f:
183+
validator = Draft7Validator(json.load(f))
184+
185+
result_advisory1_yml = saneyaml.load(
186+
next(self.working_dir.rglob("ADV-001.yml")).read_text(encoding="utf-8")
187+
)
188+
result_advisory2_yml = saneyaml.load(
189+
next(self.working_dir.rglob("ADV-002.yml")).read_text(encoding="utf-8")
190+
)
191+
192+
validator.validate(result_advisory1_yml)
193+
validator.validate(result_advisory2_yml)

vulnerabilities/tests/test_data/exporters/federate_vulnerabilities/ADV-002-expected.yml

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@ impacted_packages:
1212
- vcs_url: https://foobar.vcs/
1313
commit: 982f801f
1414
introduced_in_commits: []
15-
severities: []
16-
weaknesses: []
17-
references: []
15+
severities:
16+
- score: '8.8'
17+
scoring_system: cvssv3
18+
scoring_elements: CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
19+
published_at:
20+
url:
21+
weaknesses:
22+
- CWE-707
23+
- CWE-20
24+
references:
25+
- url: https://example.com/vuln1
26+
reference_type:
27+
reference_id:

0 commit comments

Comments
 (0)