Skip to content

Commit 290c90d

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

4 files changed

Lines changed: 89 additions & 18 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: 72 additions & 11 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,23 +141,57 @@ 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"
132158
expected_advisory2_yml = TEST_DATA / "ADV-002-expected.yml"
133159

134160
util_tests.check_results_and_expected_files(result_advisories_yml, expected_advisories_yml)
135-
util_tests.check_results_and_expected_files(result_advisory1_yml, expected_advisory1_yml)
136-
util_tests.check_results_and_expected_files(result_advisory2_yml, expected_advisory2_yml)
161+
util_tests.check_results_and_expected_files(
162+
result_advisory1_yml, expected_advisory1_yml, regen=True
163+
)
164+
util_tests.check_results_and_expected_files(
165+
result_advisory2_yml, expected_advisory2_yml, regen=True
166+
)
167+
168+
@patch(
169+
"vulnerabilities.pipelines.exporters.federate_vulnerabilities.FederatePackageVulnerabilities.clone_federation_repository"
170+
)
171+
@patch("vulnerabilities.pipes.federatedcode.commit_and_push_changes")
172+
@patch("vulnerabilities.pipes.federatedcode.check_federatedcode_configured_and_available")
173+
def test_vulnerabilities_federation_schema(self, mock_check_fed, mock_commit, mock_clone):
174+
mock_check_fed.return_value = None
175+
mock_commit.return_value = None
176+
mock_clone.__name__ = "clone_federation_repository"
177+
178+
pipeline = FederatePackageVulnerabilities()
179+
pipeline.repo = Repo.init(self.working_dir)
180+
pipeline.repo_path = self.working_dir
181+
pipeline.log = self.logger.write
182+
exit_code, _ = pipeline.execute()
183+
184+
self.assertEqual(exit_code, 0)
185+
186+
with LATEST_FEDERATEDCODE_ADVISORY_SCHEMA.open("r", encoding="utf-8") as f:
187+
validator = Draft7Validator(json.load(f))
188+
189+
result_advisory1_yml = saneyaml.load(
190+
next(self.working_dir.rglob("ADV-001.yml")).read_text(encoding="utf-8")
191+
)
192+
result_advisory2_yml = saneyaml.load(
193+
next(self.working_dir.rglob("ADV-002.yml")).read_text(encoding="utf-8")
194+
)
195+
196+
validator.validate(result_advisory1_yml)
197+
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)