Repository: JackPlowman/repo_standards_validator
Issue category: Security Vulnerability

Fix private vulnerability disclosure incorrect value



Functions to edit:
validator/__main__.py:main
validator/repository_checks.py:check_repository
validator/repository_checks.py:check_repository_security_details
Functions added: validator/repository_checks.py:get_private_vulnerability_disclosures

Patch:
diff --git a/poetry.lock b/poetry.lock
index 4c114dc..aec2415 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -938,31 +938,31 @@ jinja2 = ["ruamel.yaml.jinja2 (>=0.2)"]
 
 [[package]]
 name = "ruff"
-version = "0.9.3"
+version = "0.9.5"
 description = "An extremely fast Python linter and code formatter, written in Rust."
 optional = true
 python-versions = ">=3.7"
 groups = ["main"]
 markers = "extra == \"dev\""
 files = [
-    {file = "ruff-0.9.3-py3-none-linux_armv6l.whl", hash = "sha256:7f39b879064c7d9670197d91124a75d118d00b0990586549949aae80cdc16624"},
-    {file = "ruff-0.9.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a187171e7c09efa4b4cc30ee5d0d55a8d6c5311b3e1b74ac5cb96cc89bafc43c"},
-    {file = "ruff-0.9.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c59ab92f8e92d6725b7ded9d4a31be3ef42688a115c6d3da9457a5bda140e2b4"},
-    {file = "ruff-0.9.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2dc153c25e715be41bb228bc651c1e9b1a88d5c6e5ed0194fa0dfea02b026439"},
-    {file = "ruff-0.9.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:646909a1e25e0dc28fbc529eab8eb7bb583079628e8cbe738192853dbbe43af5"},
-    {file = "ruff-0.9.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a5a46e09355695fbdbb30ed9889d6cf1c61b77b700a9fafc21b41f097bfbba4"},
-    {file = "ruff-0.9.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c4bb09d2bbb394e3730d0918c00276e79b2de70ec2a5231cd4ebb51a57df9ba1"},
-    {file = "ruff-0.9.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:96a87ec31dc1044d8c2da2ebbed1c456d9b561e7d087734336518181b26b3aa5"},
-    {file = "ruff-0.9.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9bb7554aca6f842645022fe2d301c264e6925baa708b392867b7a62645304df4"},
-    {file = "ruff-0.9.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cabc332b7075a914ecea912cd1f3d4370489c8018f2c945a30bcc934e3bc06a6"},
-    {file = "ruff-0.9.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:33866c3cc2a575cbd546f2cd02bdd466fed65118e4365ee538a3deffd6fcb730"},
-    {file = "ruff-0.9.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:006e5de2621304c8810bcd2ee101587712fa93b4f955ed0985907a36c427e0c2"},
-    {file = "ruff-0.9.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ba6eea4459dbd6b1be4e6bfc766079fb9b8dd2e5a35aff6baee4d9b1514ea519"},
-    {file = "ruff-0.9.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:90230a6b8055ad47d3325e9ee8f8a9ae7e273078a66401ac66df68943ced029b"},
-    {file = "ruff-0.9.3-py3-none-win32.whl", hash = "sha256:eabe5eb2c19a42f4808c03b82bd313fc84d4e395133fb3fc1b1516170a31213c"},
-    {file = "ruff-0.9.3-py3-none-win_amd64.whl", hash = "sha256:040ceb7f20791dfa0e78b4230ee9dce23da3b64dd5848e40e3bf3ab76468dcf4"},
-    {file = "ruff-0.9.3-py3-none-win_arm64.whl", hash = "sha256:800d773f6d4d33b0a3c60e2c6ae8f4c202ea2de056365acfa519aa48acf28e0b"},
-    {file = "ruff-0.9.3.tar.gz", hash = "sha256:8293f89985a090ebc3ed1064df31f3b4b56320cdfcec8b60d3295bddb955c22a"},
+    {file = "ruff-0.9.5-py3-none-linux_armv6l.whl", hash = "sha256:d466d2abc05f39018d53f681fa1c0ffe9570e6d73cde1b65d23bb557c846f442"},
+    {file = "ruff-0.9.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:38840dbcef63948657fa7605ca363194d2fe8c26ce8f9ae12eee7f098c85ac8a"},
+    {file = "ruff-0.9.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d56ba06da53536b575fbd2b56517f6f95774ff7be0f62c80b9e67430391eeb36"},
+    {file = "ruff-0.9.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4f7cb2a01da08244c50b20ccfaeb5972e4228c3c3a1989d3ece2bc4b1f996001"},
+    {file = "ruff-0.9.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:96d5c76358419bc63a671caac70c18732d4fd0341646ecd01641ddda5c39ca0b"},
+    {file = "ruff-0.9.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:deb8304636ed394211f3a6d46c0e7d9535b016f53adaa8340139859b2359a070"},
+    {file = "ruff-0.9.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:df455000bf59e62b3e8c7ba5ed88a4a2bc64896f900f311dc23ff2dc38156440"},
+    {file = "ruff-0.9.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de92170dfa50c32a2b8206a647949590e752aca8100a0f6b8cefa02ae29dce80"},
+    {file = "ruff-0.9.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d28532d73b1f3f627ba88e1456f50748b37f3a345d2be76e4c653bec6c3e393"},
+    {file = "ruff-0.9.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c746d7d1df64f31d90503ece5cc34d7007c06751a7a3bbeee10e5f2463d52d2"},
+    {file = "ruff-0.9.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:11417521d6f2d121fda376f0d2169fb529976c544d653d1d6044f4c5562516ee"},
+    {file = "ruff-0.9.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:5b9d71c3879eb32de700f2f6fac3d46566f644a91d3130119a6378f9312a38e1"},
+    {file = "ruff-0.9.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:2e36c61145e70febcb78483903c43444c6b9d40f6d2f800b5552fec6e4a7bb9a"},
+    {file = "ruff-0.9.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:2f71d09aeba026c922aa7aa19a08d7bd27c867aedb2f74285a2639644c1c12f5"},
+    {file = "ruff-0.9.5-py3-none-win32.whl", hash = "sha256:134f958d52aa6fdec3b294b8ebe2320a950d10c041473c4316d2e7d7c2544723"},
+    {file = "ruff-0.9.5-py3-none-win_amd64.whl", hash = "sha256:78cc6067f6d80b6745b67498fb84e87d32c6fc34992b52bffefbdae3442967d6"},
+    {file = "ruff-0.9.5-py3-none-win_arm64.whl", hash = "sha256:18a29f1a005bddb229e580795627d297dfa99f16b30c7039e73278cf6b5f9fa9"},
+    {file = "ruff-0.9.5.tar.gz", hash = "sha256:11aecd7a633932875ab3cb05a484c99970b9d52606ce9ea912b690b02653d56c"},
 ]
 
 [[package]]
@@ -1122,28 +1122,28 @@ files = [
 
 [[package]]
 name = "zizmor"
-version = "1.2.2"
+version = "1.3.0"
 description = "Static analysis for GitHub Actions"
 optional = true
 python-versions = ">=3.9"
 groups = ["main"]
 markers = "extra == \"dev\""
 files = [
-    {file = "zizmor-1.2.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d7eca7e6c15153b7067342f732837ce36786f145e96f12b87de470086edb59fa"},
-    {file = "zizmor-1.2.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:84a0eeab3a8db963fd69d371951f47557a94e809e6642e7bcfea219a85abfa7e"},
-    {file = "zizmor-1.2.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2c1a9de80ace20a8de6e13aa10976132974fc938d86595234cb8068336b99257"},
-    {file = "zizmor-1.2.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e178d19c86b10f3c8f83a473a41d9a1a5298c8cc56d438de5a6290a84464bc6d"},
-    {file = "zizmor-1.2.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:da086f8cd175c9bed2b1c0b438dbfbaaca4a0bd5b9b6b44ed748640f9a385555"},
-    {file = "zizmor-1.2.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b94aee9a49a4ceeba565ece03218b8083db63570aabba5deeb6714a55bd0f9ad"},
-    {file = "zizmor-1.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fcedb04e6445be4a64eef8bd25b47c0ce5426d4ec7577e8faaf41a4b596a79be"},
-    {file = "zizmor-1.2.2-py3-none-manylinux_2_24_aarch64.whl", hash = "sha256:139f07f6c52af97a47a2e90d0d205d5066e808f8f6ff0e87558dc124d200b591"},
-    {file = "zizmor-1.2.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:15b24f2aafe8cf560de79f4a0065f26456f30d3957afe63b716c230a06a7c864"},
-    {file = "zizmor-1.2.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:6a6a202c27d97d90b3dd622cd7e802e3420ed952e54efe6e581801d93cc3af64"},
-    {file = "zizmor-1.2.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6a50cf1fdf10ba1f0122d35a1821a75e7b13a85da222f5d31971b2900cc50fc0"},
-    {file = "zizmor-1.2.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:2639d934260d299afd5fe476d326e62fb395a8c2312031865a56b2fe6501d295"},
-    {file = "zizmor-1.2.2-py3-none-win32.whl", hash = "sha256:21d72d1664372628151b6d0dd8c041a0b65359b9e8edd2e9659ad422578d55f6"},
-    {file = "zizmor-1.2.2-py3-none-win_amd64.whl", hash = "sha256:383c14bcb6ea69acb37ffbd2b57e2b86722d41e3ca31fbb0add80d79aca48da5"},
-    {file = "zizmor-1.2.2.tar.gz", hash = "sha256:17b14d30806895f337930e5db8c89314521e5395a41809cd7bbed8b93fc65997"},
+    {file = "zizmor-1.3.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:a30f7da86caee6c4dc12ac8b9946e824c8717d4b5f939a371c21ae827e972841"},
+    {file = "zizmor-1.3.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a6f4c02457fa53e780f5542db45e58db7293c7ce8439cedd17ceaa5a0481618b"},
+    {file = "zizmor-1.3.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:20bba9366147f4594743090102df07ac919de59872af3c4b5016414cf759e454"},
+    {file = "zizmor-1.3.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:081c386c9f14ae831aa45c4c3f75ab1848e24f6cae6ecd30e42fcc2c6fe550f7"},
+    {file = "zizmor-1.3.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7be14dd3981f7f29b0ced4dfdede80a27631b5fdbca2d74aea325234a9892f1d"},
+    {file = "zizmor-1.3.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f88a3e617b3c25d381a701329ee8900d090fc0f42281fbe0c56b1ae2b40e34de"},
+    {file = "zizmor-1.3.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9392bd39b19886a8c01ae39f230542013efd20a1bb38f6aef7072eb7bff8301b"},
+    {file = "zizmor-1.3.0-py3-none-manylinux_2_24_aarch64.whl", hash = "sha256:8bdcd92b1685d7f0054f89cb9cc659ce7a099b9b6f780b5e9a1325a305541ce4"},
+    {file = "zizmor-1.3.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f0c50ec5c2fb95f2e6c48660948d49d535289a96566b9373aa8aa6a9dc0ef17a"},
+    {file = "zizmor-1.3.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:99f93ce552bb4d34e8dc0abf03364633b33f441c690a4df99101f6fee12d1acc"},
+    {file = "zizmor-1.3.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:488fe8ceffb551d3a4a14aef3943a8e7c4f3d9458c0995ee5651a79f2ecac060"},
+    {file = "zizmor-1.3.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e0f48a1413955827d89252046fadce1cf100f237d529a63e4354812e3d6d209e"},
+    {file = "zizmor-1.3.0-py3-none-win32.whl", hash = "sha256:5783368fe5c9414a1c3e95c0c2811fba0d970060d609cc88a2cb050a7ba61b3a"},
+    {file = "zizmor-1.3.0-py3-none-win_amd64.whl", hash = "sha256:c5e90804a35b9c951d5afb98c726f984d343f1bc6b03eccad98471633234275a"},
+    {file = "zizmor-1.3.0.tar.gz", hash = "sha256:00c02fca187a7579a3faf26789f791d30ff92fdff2ec26b1ef5fe7443e42db4e"},
 ]
 
 [extras]
@@ -1152,4 +1152,4 @@ dev = ["check-jsonschema", "pytest", "pytest-cov", "ruff", "vulture", "zizmor"]
 [metadata]
 lock-version = "2.1"
 python-versions = ">=3.13"
-content-hash = "125e1aee4bb752ca958db1b39c76ffd09ea5cd95e3c660f6ba2c85beaa69e933"
+content-hash = "5c319970a4853bb0f882dc3a8b7d1624c06d4c6fa6ae2ccfad0a1b3d8f8fbea8"
diff --git a/pyproject.toml b/pyproject.toml
index ec1f3db..a495452 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -6,15 +6,16 @@ dependencies = [
   "structlog==24.4.0",
   "pygithub==2.5.0",
   "GitPython==3.1.44",
+  "requests==2.32.3",
 ]
 
 [project.optional-dependencies]
 dev = [
   "pytest==8.3.4",
   "pytest-cov==6.0.0",
-  "ruff==0.9.3",
+  "ruff==0.9.5",
   "vulture==2.14",
-  "zizmor==1.2.2",
+  "zizmor==1.3.0",
   "check-jsonschema==0.31.0",
 ]
 
diff --git a/validator/__main__.py b/validator/__main__.py
index cfa3060..491e431 100644
--- a/validator/__main__.py
+++ b/validator/__main__.py
@@ -28,7 +28,7 @@ def main() -> None:
     total_repositories = repositories.totalCount
     for index, repository in enumerate(repositories, 1):
         clone_repository(repository.name, repository.clone_url)
-        analysed_repository = check_repository(repository)
+        analysed_repository = check_repository(configuration, repository)
         raw_analysed_repositories.append(asdict(analysed_repository))
         logger.info(
             "Repository analysed",
diff --git a/validator/repository_checks.py b/validator/repository_checks.py
index 3967f0d..6efa32b 100644
--- a/validator/repository_checks.py
+++ b/validator/repository_checks.py
@@ -1,6 +1,8 @@
 from github import Repository as GitHubRepositoryType
+from requests import RequestException, get
 from structlog import get_logger, stdlib
 
+from .configuration import Configuration
 from .custom_types import Repository as AnalysedRepository
 from .custom_types import (
     RepositoryDetails,
@@ -12,10 +14,13 @@
 logger: stdlib.BoundLogger = get_logger()
 
 
-def check_repository(repository: GitHubRepositoryType) -> AnalysedRepository:
+def check_repository(
+    configuration: Configuration, repository: GitHubRepositoryType
+) -> AnalysedRepository:
     """Check the repository for the required settings.
 
     Args:
+        configuration (Configuration): The configuration to use.
         repository (GitHubRepositoryType): The repository to check.
 
     Returns:
@@ -23,7 +28,9 @@ def check_repository(repository: GitHubRepositoryType) -> AnalysedRepository:
     """
     logger.info("Checking repository", repository=repository.full_name)
     repository_details = check_repository_details(repository)
-    repository_security_details = check_repository_security_details(repository)
+    repository_security_details = check_repository_security_details(
+        configuration, repository
+    )
     repository_key_files = check_repository_has_key_files(repository)
     logger.debug(
         "Repository checked",
@@ -68,11 +75,13 @@ def check_repository_details(repository: GitHubRepositoryType) -> RepositoryDeta
 
 
 def check_repository_security_details(
+    configuration: Configuration,
     repository: GitHubRepositoryType,
 ) -> RepositorySecurityDetails:
     """Check the repository for the required security details.
 
     Args:
+        configuration (Configuration): The configuration to use.
         repository (GitHubRepositoryType): The repository to check.
 
     Returns:
@@ -85,7 +94,9 @@ def check_repository_security_details(
     dependabot_security_updates = (
         repository.security_and_analysis.dependabot_security_updates.status
     )
-    private_vulnerability_disclosures = repository.get_vulnerability_alert()
+    private_vulnerability_disclosures = get_private_vulnerability_disclosures(
+        configuration, repository
+    )
     code_scanning_alerts = get_code_scanning_alerts(repository)
     return RepositorySecurityDetails(
         secret_scanning_push_protection=status_to_bool(secret_scanning_push_protection),
@@ -147,3 +158,36 @@ def get_code_scanning_alerts(repository: GitHubRepositoryType) -> int:
             "Could not fetch code scanning alerts", repository=repository.full_name
         )
         return 0
+
+
+def get_private_vulnerability_disclosures(
+    configuration: Configuration, repository: GitHubRepositoryType
+) -> bool:
+    """Get the private vulnerability disclosures for a repository.
+
+    Args:
+        configuration (Configuration): The configuration to use.
+        repository (GitHubRepositoryType): The repository to get the private
+        vulnerability disclosures for.
+
+    Returns:
+        bool: The private vulnerability disclosures.
+    """
+    try:
+        response = get(
+            f"https://api.github.com/repos/{repository.full_name}/private-vulnerability-reporting",
+            headers={
+                "Accept": "application/vnd.github+json",
+                "Authorization": f"Bearer {configuration.github_token}",
+                "X-GitHub-Api-Version": "2022-11-28",
+            },
+            timeout=5,
+        )
+        response.raise_for_status()
+        return response.json()["enabled"]
+    except RequestException:
+        logger.exception(
+            "Could not fetch private vulnerability disclosures",
+            repository=repository.full_name,
+        )
+        return False

Test patch: diff --git a/validator/tests/test_repository_checks.py b/validator/tests/test_repository_checks.py
index aed318f..739a97d 100644
--- a/validator/tests/test_repository_checks.py
+++ b/validator/tests/test_repository_checks.py
@@ -11,6 +11,7 @@
 
 def test_check_repository() -> None:
     # Arrange
+    configuration = MagicMock()
     repository = MagicMock()
     repository.name = "test-repo"
     repository.full_name = "owner/test-repo"
@@ -18,7 +19,7 @@ def test_check_repository() -> None:
     repository.security_and_analysis.secret_scanning.status = "enabled"
     repository.security_and_analysis.dependabot_security_updates.status = "enabled"
     # Act
-    analysed_repository = check_repository(repository)
+    analysed_repository = check_repository(configuration, repository)
     # Assert
     assert analysed_repository.name == "test-repo"
     assert analysed_repository.full_name == "owner/test-repo"