|
| 1 | +import base64 |
| 2 | +import json |
1 | 3 | from os import path |
2 | 4 | from unittest import TestCase |
| 5 | +from unittest.mock import MagicMock, patch |
3 | 6 |
|
4 | 7 | from application.core.models import Product |
5 | 8 | from application.core.types import Severity |
|
8 | 11 |
|
9 | 12 |
|
10 | 13 | class TestCycloneDXParser(TestCase): |
| 14 | + def test_grype_observations_kept_when_sbom_attestation_resolves(self): |
| 15 | + # The scan report (Grype) and the attested SBOM (Trivy) use different bom-refs for the same |
| 16 | + # package. When the cosign attestation lookup succeeds, the SBOM components must be *merged* |
| 17 | + # with the scan components, not replace them. Otherwise the vulnerabilities reference refs |
| 18 | + # that only exist in the scan report, no component is found, and every observation is |
| 19 | + # silently dropped. |
| 20 | + attested_sbom = { |
| 21 | + "bomFormat": "CycloneDX", |
| 22 | + "metadata": {"component": {"bom-ref": "sbom-only-ref", "type": "container", "name": "x"}}, |
| 23 | + "components": [ |
| 24 | + { |
| 25 | + "bom-ref": "sbom-only-ref", |
| 26 | + "type": "library", |
| 27 | + "name": "sbom-only-package", |
| 28 | + "version": "1.0.0", |
| 29 | + "purl": "pkg:generic/sbom-only-package@1.0.0", |
| 30 | + } |
| 31 | + ], |
| 32 | + "dependencies": [], |
| 33 | + } |
| 34 | + payload = base64.b64encode(json.dumps({"predicate": attested_sbom}).encode()).decode() |
| 35 | + cosign_result = MagicMock(returncode=0, stdout=json.dumps({"payload": payload}).encode()) |
| 36 | + |
| 37 | + with open(path.dirname(__file__) + "/files/grype.json") as testfile: |
| 38 | + parser, parser_instance, data = detect_parser(testfile) |
| 39 | + |
| 40 | + with patch( |
| 41 | + "application.import_observations.parsers.cyclone_dx.parser.subprocess.run", |
| 42 | + return_value=cosign_result, |
| 43 | + ): |
| 44 | + observations, scanner = parser_instance.get_observations(data, Product(name="product"), None) |
| 45 | + |
| 46 | + self.assertEqual("grype / 0.59.1", scanner) |
| 47 | + self.assertEqual(8, len(observations)) |
| 48 | + |
11 | 49 | def test_grype_no_bom_link(self): |
12 | 50 | with open(path.dirname(__file__) + "/files/grype.json") as testfile: |
13 | 51 | parser, parser_instance, data = detect_parser(testfile) |
|
0 commit comments