From b962d47c082e975f8ea2447b651a04e7a54f7e79 Mon Sep 17 00:00:00 2001 From: Frank Niessink Date: Mon, 13 Jan 2025 14:05:31 +0100 Subject: [PATCH] Allow for measuring the source up-to-dateness of Harbor JSON reports. Closes #10609. --- components/collector/.vulture_ignore_list.py | 4 +- .../src/source_collectors/__init__.py | 1 + .../src/source_collectors/harbor_json/base.py | 30 +++++++++++++++ .../harbor_json/security_warnings.py | 28 +------------- .../harbor_json/source_up_to_dateness.py | 17 +++++++++ .../source_collectors/harbor_json/base.py | 38 +++++++++++++++++++ .../harbor_json/test_security_warnings.py | 31 +-------------- .../harbor_json/test_source_up_to_dateness.py | 17 +++++++++ .../src/shared_data_model/metrics.py | 1 + .../src/shared_data_model/sources/harbor.py | 8 +++- docs/src/changelog.md | 1 + 11 files changed, 119 insertions(+), 57 deletions(-) create mode 100644 components/collector/src/source_collectors/harbor_json/base.py create mode 100644 components/collector/src/source_collectors/harbor_json/source_up_to_dateness.py create mode 100644 components/collector/tests/source_collectors/harbor_json/base.py create mode 100644 components/collector/tests/source_collectors/harbor_json/test_source_up_to_dateness.py diff --git a/components/collector/.vulture_ignore_list.py b/components/collector/.vulture_ignore_list.py index 40866159dc..d264b68aeb 100644 --- a/components/collector/.vulture_ignore_list.py +++ b/components/collector/.vulture_ignore_list.py @@ -68,7 +68,9 @@ GitLabUnusedJobs # unused class (src/source_collectors/gitlab/unused_jobs.py:11) scan_status # unused variable (src/source_collectors/harbor/security_warnings.py:58) HarborSecurityWarnings # unused class (src/source_collectors/harbor/security_warnings.py:62) -HarborJSONSecurityWarnings # unused class (src/source_collectors/harbor_json/security_warnings.py:36) +generated_at # unused variable (src/source_collectors/harbor_json/base.py:23) +HarborJSONSecurityWarnings # unused class (src/source_collectors/harbor_json/security_warnings.py:12) +HarborJSONSourceUpToDateness # unused class (src/source_collectors/harbor_json/source_up_to_dateness.py:13) JacocoSourceUpToDateness # unused class (src/source_collectors/jacoco/source_up_to_dateness.py:11) JacocoUncoveredBranches # unused class (src/source_collectors/jacoco/uncovered_branches.py:6) JacocoUncoveredLines # unused class (src/source_collectors/jacoco/uncovered_lines.py:6) diff --git a/components/collector/src/source_collectors/__init__.py b/components/collector/src/source_collectors/__init__.py index 0b5cd47544..d270dfafb0 100644 --- a/components/collector/src/source_collectors/__init__.py +++ b/components/collector/src/source_collectors/__init__.py @@ -60,6 +60,7 @@ from .gitlab.unused_jobs import GitLabUnusedJobs from .harbor.security_warnings import HarborSecurityWarnings from .harbor_json.security_warnings import HarborJSONSecurityWarnings +from .harbor_json.source_up_to_dateness import HarborJSONSourceUpToDateness from .jacoco.source_up_to_dateness import JacocoSourceUpToDateness from .jacoco.uncovered_branches import JacocoUncoveredBranches from .jacoco.uncovered_lines import JacocoUncoveredLines diff --git a/components/collector/src/source_collectors/harbor_json/base.py b/components/collector/src/source_collectors/harbor_json/base.py new file mode 100644 index 0000000000..9051a4f7c0 --- /dev/null +++ b/components/collector/src/source_collectors/harbor_json/base.py @@ -0,0 +1,30 @@ +"""Base classes for Harbor JSON collectors.""" + +from typing import Final, TypedDict + +REPORT_MIME_TYPE: Final = "application/vnd.security.vulnerability.report; version=1.1" + + +class HarborJSONVulnerability(TypedDict): + """A Harbor JSON vulnerability.""" + + id: str + package: str + version: str + fix_version: str + severity: str + description: str + links: list[str] + + +class HarborJSONVulnerabilityReport(TypedDict): + """A Harbor JSON vulnerability report.""" + + generated_at: str + vulnerabilities: list[HarborJSONVulnerability] + + +HarborJSON = TypedDict( + "HarborJSON", + {"application/vnd.security.vulnerability.report; version=1.1": HarborJSONVulnerabilityReport}, +) diff --git a/components/collector/src/source_collectors/harbor_json/security_warnings.py b/components/collector/src/source_collectors/harbor_json/security_warnings.py index 2050701ea0..9e03c49ec7 100644 --- a/components/collector/src/source_collectors/harbor_json/security_warnings.py +++ b/components/collector/src/source_collectors/harbor_json/security_warnings.py @@ -1,36 +1,12 @@ """Harbor JSON security warnings collector.""" -from typing import Final, TypedDict, cast +from typing import cast from base_collectors import JSONFileSourceCollector, SecurityWarningsSourceCollector from collector_utilities.type import JSON from model import Entities, Entity -REPORT_MIME_TYPE: Final = "application/vnd.security.vulnerability.report; version=1.1" - - -class Vulnerability(TypedDict): - """A Harbor JSON vulnerability.""" - - id: str - package: str - version: str - fix_version: str - severity: str - description: str - links: list[str] - - -class HarborJSONVulnerabilityReport(TypedDict): - """A Harbor JSON vulnerability report.""" - - vulnerabilities: list[Vulnerability] - - -HarborJSON = TypedDict( - "HarborJSON", - {"application/vnd.security.vulnerability.report; version=1.1": HarborJSONVulnerabilityReport}, -) +from .base import REPORT_MIME_TYPE, HarborJSON class HarborJSONSecurityWarnings(SecurityWarningsSourceCollector, JSONFileSourceCollector): diff --git a/components/collector/src/source_collectors/harbor_json/source_up_to_dateness.py b/components/collector/src/source_collectors/harbor_json/source_up_to_dateness.py new file mode 100644 index 0000000000..684d5c9bc7 --- /dev/null +++ b/components/collector/src/source_collectors/harbor_json/source_up_to_dateness.py @@ -0,0 +1,17 @@ +"""Harbor JSON source up-to-dateness collector.""" + +from datetime import datetime + +from base_collectors import JSONFileSourceCollector, TimePassedCollector +from collector_utilities.date_time import parse_datetime +from collector_utilities.type import Response + +from .base import REPORT_MIME_TYPE + + +class HarborJSONSourceUpToDateness(JSONFileSourceCollector, TimePassedCollector): + """Harbor JSON collector for source up-to-dateness.""" + + async def _parse_source_response_date_time(self, response: Response) -> datetime: + """Override to parse the date of the most recent analysis.""" + return parse_datetime((await response.json())[REPORT_MIME_TYPE]["generated_at"]) diff --git a/components/collector/tests/source_collectors/harbor_json/base.py b/components/collector/tests/source_collectors/harbor_json/base.py new file mode 100644 index 0000000000..07a1988c6f --- /dev/null +++ b/components/collector/tests/source_collectors/harbor_json/base.py @@ -0,0 +1,38 @@ +"""Base classes for Harbor JSON collector unit tests.""" + +from typing import ClassVar + +from source_collectors.harbor_json.base import HarborJSON + +from tests.source_collectors.source_collector_test_case import SourceCollectorTestCase + + +class HarborJSONCollectorTestCase(SourceCollectorTestCase): + """Base class for Harbor JSON collector unit tests.""" + + SOURCE_TYPE = "harbor_json" + VULNERABILITIES_JSON: ClassVar[HarborJSON] = { + "application/vnd.security.vulnerability.report; version=1.1": { + "generated_at": "2023-08-26T16:32:21.923910328Z", + "vulnerabilities": [ + { + "id": "CVE-2011-3374", + "package": "apt", + "version": "2.2.4", + "fix_version": "2.2.5", + "severity": "Low", + "description": "It was found that apt-key in apt, all versions, do not correctly validate ...", + "links": ["https://avd.aquasec.com/nvd/cve-2011-3374"], + }, + { + "id": "CVE-2020-22218", + "package": "libssh2-1", + "version": "1.9.0-2", + "fix_version": "", + "severity": "High", + "description": "An issue was discovered in function _libssh2_packet_add in libssh2 1.10.0 ...", + "links": ["https://avd.aquasec.com/nvd/cve-2020-22218"], + }, + ], + }, + } diff --git a/components/collector/tests/source_collectors/harbor_json/test_security_warnings.py b/components/collector/tests/source_collectors/harbor_json/test_security_warnings.py index e797655f91..b9442c2c68 100644 --- a/components/collector/tests/source_collectors/harbor_json/test_security_warnings.py +++ b/components/collector/tests/source_collectors/harbor_json/test_security_warnings.py @@ -2,40 +2,13 @@ from typing import ClassVar -from source_collectors.harbor_json.security_warnings import HarborJSON +from .base import HarborJSONCollectorTestCase -from tests.source_collectors.source_collector_test_case import SourceCollectorTestCase - -class HarborJSONSecurityWarningsTest(SourceCollectorTestCase): +class HarborJSONSecurityWarningsTest(HarborJSONCollectorTestCase): """Unit tests for the security warning metric.""" - SOURCE_TYPE = "harbor_json" METRIC_TYPE = "security_warnings" - VULNERABILITIES_JSON: ClassVar[HarborJSON] = { - "application/vnd.security.vulnerability.report; version=1.1": { - "vulnerabilities": [ - { - "id": "CVE-2011-3374", - "package": "apt", - "version": "2.2.4", - "fix_version": "2.2.5", - "severity": "Low", - "description": "It was found that apt-key in apt, all versions, do not correctly validate ...", - "links": ["https://avd.aquasec.com/nvd/cve-2011-3374"], - }, - { - "id": "CVE-2020-22218", - "package": "libssh2-1", - "version": "1.9.0-2", - "fix_version": "", - "severity": "High", - "description": "An issue was discovered in function _libssh2_packet_add in libssh2 1.10.0 ...", - "links": ["https://avd.aquasec.com/nvd/cve-2020-22218"], - }, - ], - }, - } EXPECTED_ENTITIES: ClassVar[list[dict[str, str]]] = [ { "key": "CVE-2011-3374@apt@2_2_4", diff --git a/components/collector/tests/source_collectors/harbor_json/test_source_up_to_dateness.py b/components/collector/tests/source_collectors/harbor_json/test_source_up_to_dateness.py new file mode 100644 index 0000000000..526b8ee037 --- /dev/null +++ b/components/collector/tests/source_collectors/harbor_json/test_source_up_to_dateness.py @@ -0,0 +1,17 @@ +"""Unit tests for the Harbor JSON source up-to-dateness collector.""" + +from collector_utilities.date_time import days_ago, parse_datetime + +from .base import HarborJSONCollectorTestCase + + +class HarborJSONSourceUpToDatenessTest(HarborJSONCollectorTestCase): + """Unit tests for the source up-to-dateness metric.""" + + METRIC_TYPE = "source_up_to_dateness" + + async def test_souce_up_to_dateness(self): + """Test the source up-to-dateness.""" + response = await self.collect(get_request_json_return_value=self.VULNERABILITIES_JSON) + expected_value = str(days_ago(parse_datetime("2023-08-26T16:32:21.923910328Z"))) + self.assert_measurement(response, value=expected_value) diff --git a/components/shared_code/src/shared_data_model/metrics.py b/components/shared_code/src/shared_data_model/metrics.py index 2598774166..8873bddc73 100644 --- a/components/shared_code/src/shared_data_model/metrics.py +++ b/components/shared_code/src/shared_data_model/metrics.py @@ -462,6 +462,7 @@ "dependency_track", "gatling", "gitlab", + "harbor_json", "jacoco", "jacoco_jenkins_plugin", "jenkins", diff --git a/components/shared_code/src/shared_data_model/sources/harbor.py b/components/shared_code/src/shared_data_model/sources/harbor.py index 38aea3d52d..2035ea781f 100644 --- a/components/shared_code/src/shared_data_model/sources/harbor.py +++ b/components/shared_code/src/shared_data_model/sources/harbor.py @@ -81,6 +81,8 @@ }, ) +ALL_HARBOR_JSON_METRICS = ["security_warnings", "source_up_to_dateness"] + HARBOR_JSON = Source( name="Harbor JSON", description=( @@ -91,7 +93,11 @@ parameters={ "severities": Severities(values=["unknown", "low", "medium", "high", "critical"]), "fix_availability": FixAvailability(), - **access_parameters(ALL_HARBOR_METRICS, source_type="Harbor vulnerability report", source_type_format="JSON"), + **access_parameters( + ALL_HARBOR_JSON_METRICS, + source_type="Harbor vulnerability report", + source_type_format="JSON", + ), }, entities={ "security_warnings": Entity( diff --git a/docs/src/changelog.md b/docs/src/changelog.md index cb13e5e8be..9709a0e6fb 100644 --- a/docs/src/changelog.md +++ b/docs/src/changelog.md @@ -23,6 +23,7 @@ If your currently installed *Quality-time* version is not the latest version, pl - When measuring missing metrics, make the subject type and the metric type of the missing metrics link to the reference documentation. Closes [#10528](https://github.com/ICTU/quality-time/issues/10528). - Allow for measuring the source up-to-dateness of Trivy JSON reports. Closes [#10608](https://github.com/ICTU/quality-time/issues/10608). +- Allow for measuring the source up-to-dateness of Harbor JSON reports. Closes [#10609](https://github.com/ICTU/quality-time/issues/10609). - Support version 4.1 of the OWASP Dependency-Check DTD (OWASP Dependency-Check version 12.0.0). Closes [#10645](https://github.com/ICTU/quality-time/issues/10645). ### Changed