############################ Copyrights and license ############################ # # # Copyright 2023 Jonathan Leitschuh # # # # This file is part of PyGithub. # # http://pygithub.readthedocs.io/ # # # # PyGithub is free software: you can redistribute it and/or modify it under # # the terms of the GNU Lesser General Public License as published by the Free # # Software Foundation, either version 3 of the License, or (at your option) # # any later version. # # # # PyGithub is distributed in the hope that it will be useful, but WITHOUT ANY # # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS # # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more # # details. # # # # You should have received a copy of the GNU Lesser General Public License # # along with PyGithub. If not, see . # # # ################################################################################ import sys import typing from typing import List import github.GithubObject import github.RepositoryAdvisoryVulnerabilityPackage if sys.version_info >= (3, 8): # TypedDict is only available in Python 3.8 and later class SimpleAdvisoryVulnerabilityPackage(typing.TypedDict): """ A simple package in an advisory. """ ecosystem: str name: typing.Optional[str] # TODO: Python 3.11 make 'NotRequired' class SimpleAdvisoryVulnerability(typing.TypedDict): """ A simple vulnerability in a security advisory. """ package: SimpleAdvisoryVulnerabilityPackage patched_versions: typing.Optional[str] # TODO: Python 3.11 make 'NotRequired' vulnerable_functions: typing.Optional[ List[str] ] # TODO: Python 3.11 make 'NotRequired' vulnerable_version_range: typing.Optional[ str ] # TODO: Python 3.11 make 'NotRequired' else: SimpleAdvisoryVulnerabilityPackage = typing.Dict[str, typing.Any] SimpleAdvisoryVulnerability = typing.Dict[str, typing.Any] AdvisoryVulnerability = typing.Union[ SimpleAdvisoryVulnerability, "RepositoryAdvisoryVulnerability" ] class RepositoryAdvisoryVulnerability(github.GithubObject.NonCompletableGithubObject): """ This class represents a package that is vulnerable to a parent SecurityAdvisory. The reference can be found here https://docs.github.com/en/rest/security-advisories/repository-advisories """ @property def package( self, ) -> github.RepositoryAdvisoryVulnerabilityPackage.RepositoryAdvisoryVulnerabilityPackage: """ :type: :class:`github.RepositoryAdvisoryVulnerability.RepositoryAdvisoryVulnerability` """ return self._package.value @property def patched_versions(self) -> str: """ :type: string """ return self._patched_versions.value @property def vulnerable_functions(self) -> typing.Optional[List[str]]: """ :type: list of string """ return self._vulnerable_functions.value @property def vulnerable_version_range(self) -> typing.Optional[str]: """ :type: string """ return self._vulnerable_version_range.value # noinspection PyPep8Naming def _initAttributes(self): self._package = github.GithubObject.NotSet self._patched_versions = github.GithubObject.NotSet self._vulnerable_functions = github.GithubObject.NotSet self._vulnerable_version_range = github.GithubObject.NotSet # noinspection PyPep8Naming def _useAttributes(self, attributes): if "package" in attributes: # pragma no branch self._package = self._makeClassAttribute( github.RepositoryAdvisoryVulnerabilityPackage.RepositoryAdvisoryVulnerabilityPackage, attributes["package"], ) if "patched_versions" in attributes: # pragma no branch self._patched_versions = self._makeStringAttribute( attributes["patched_versions"] ) if "vulnerable_functions" in attributes: # pragma no branch self._vulnerable_functions = self._makeListOfStringsAttribute( attributes["vulnerable_functions"] ) if "vulnerable_version_range" in attributes: # pragma no branch self._vulnerable_version_range = self._makeStringAttribute( attributes["vulnerable_version_range"] ) @classmethod def _validate_vulnerability(cls, vulnerability: AdvisoryVulnerability) -> None: assert isinstance(vulnerability, (dict, cls)), vulnerability if isinstance(vulnerability, dict): assert "package" in vulnerability, vulnerability package: SimpleAdvisoryVulnerabilityPackage = vulnerability["package"] assert isinstance(package, dict), package assert "ecosystem" in package, package assert isinstance(package["ecosystem"], str), package assert "name" in package, package assert isinstance(package["name"], (str, type(None))), package assert "patched_versions" in vulnerability, vulnerability assert isinstance( vulnerability["patched_versions"], (str, type(None)) ), vulnerability assert "vulnerable_functions" in vulnerability, vulnerability assert isinstance( vulnerability["vulnerable_functions"], (list, type(None)) ), vulnerability assert "vulnerable_functions" in vulnerability, vulnerability assert ( all(isinstance(vf, str) for vf in vulnerability["vulnerable_functions"]) if vulnerability["vulnerable_functions"] is not None else True ), vulnerability assert "vulnerable_version_range" in vulnerability, vulnerability assert isinstance( vulnerability["vulnerable_version_range"], (str, type(None)) ), vulnerability else: assert ( vulnerability.package is github.RepositoryAdvisoryVulnerabilityPackage.RepositoryAdvisoryVulnerabilityPackage ), vulnerability @staticmethod def _to_github_dict( vulnerability: AdvisoryVulnerability, ) -> SimpleAdvisoryVulnerability: if isinstance(vulnerability, dict): vulnerability_package: SimpleAdvisoryVulnerabilityPackage = vulnerability[ "package" ] return { "package": { "ecosystem": vulnerability_package["ecosystem"], "name": vulnerability_package["name"], }, "patched_versions": vulnerability["patched_versions"], "vulnerable_functions": vulnerability["vulnerable_functions"], "vulnerable_version_range": vulnerability["vulnerable_version_range"], } return { "package": { "ecosystem": vulnerability.package.ecosystem, "name": vulnerability.package.name, }, "patched_versions": vulnerability.patched_versions, "vulnerable_functions": vulnerability.vulnerable_functions, "vulnerable_version_range": vulnerability.vulnerable_version_range, }