############################ Copyrights and license ############################
# #
# Copyright 2023 Enrico Minack #
# Copyright 2023 Jirka Borovec <6035284+Borda@users.noreply.github.com> #
# Copyright 2023 Jonathan Leitschuh #
# Copyright 2023 Joseph Henrich #
# Copyright 2023 Trim21 #
# Copyright 2024 Jirka Borovec <6035284+Borda@users.noreply.github.com> #
# #
# 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 . #
# #
################################################################################
from __future__ import annotations
from typing import TYPE_CHECKING, Any, Union
from typing_extensions import TypedDict
import github.AdvisoryVulnerabilityPackage
from github.GithubObject import Attribute, NonCompletableGithubObject, NotSet
if TYPE_CHECKING:
from github.AdvisoryVulnerabilityPackage import AdvisoryVulnerabilityPackage
class SimpleAdvisoryVulnerabilityPackage(TypedDict):
"""
A simple package in an advisory.
"""
ecosystem: str
name: str | None
class SimpleAdvisoryVulnerability(TypedDict):
"""
A simple vulnerability in a security advisory.
"""
package: SimpleAdvisoryVulnerabilityPackage
patched_versions: str | None
vulnerable_functions: list[str] | None
vulnerable_version_range: str | None
AdvisoryVulnerabilityInput = Union[SimpleAdvisoryVulnerability, "AdvisoryVulnerability"]
class AdvisoryVulnerability(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,
) -> AdvisoryVulnerabilityPackage:
"""
:type: :class:`github.AdvisoryVulnerability.AdvisoryVulnerability`
"""
return self._package.value
@property
def patched_versions(self) -> str:
"""
:type: string
"""
return self._patched_versions.value
@property
def vulnerable_functions(self) -> list[str] | None:
"""
:type: list of string
"""
return self._vulnerable_functions.value
@property
def vulnerable_version_range(self) -> str | None:
"""
:type: string
"""
return self._vulnerable_version_range.value
def _initAttributes(self) -> None:
self._package: Attribute[AdvisoryVulnerabilityPackage] = NotSet
self._patched_versions: Attribute[str] = NotSet
self._vulnerable_functions: Attribute[list[str]] = NotSet
self._vulnerable_version_range: Attribute[str] = NotSet
def _useAttributes(self, attributes: dict[str, Any]) -> None:
if "package" in attributes: # pragma no branch
self._package = self._makeClassAttribute(
github.AdvisoryVulnerabilityPackage.AdvisoryVulnerabilityPackage,
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: AdvisoryVulnerabilityInput) -> 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.AdvisoryVulnerabilityPackage.AdvisoryVulnerabilityPackage
), vulnerability
@staticmethod
def _to_github_dict(
vulnerability: AdvisoryVulnerabilityInput,
) -> 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,
}