feat: added testing

Added testing classes for provider, new service and check and corrected minor issues.
This commit is contained in:
HugoPBrito
2024-11-20 18:09:10 +01:00
parent c11e6449f9
commit 5ee960e13d
10 changed files with 334 additions and 17 deletions
@@ -0,0 +1,117 @@
from prowler.exceptions.exceptions import ProwlerException
# Exceptions codes from 5000 to 5999 are reserved for GitHub exceptions
class GitHubBaseException(ProwlerException):
"""Base class for GitHub Errors."""
GITHUB_ERROR_CODES = {
(2000, "GitHubEnvironmentVariableError"): {
"message": "GitHub environment variable error",
"remediation": "Check the GitHub environment variables and ensure they are properly set.",
},
(2001, "GitHubInvalidTokenError"): {
"message": "GitHub token provided is not valid",
"remediation": "Check the GitHub token and ensure it is valid.",
},
(2002, "GitHubSetUpIdentityError"): {
"message": "GitHub identity setup error related with credentials",
"remediation": "Check credentials and ensure they are properly set up for GitHub and the identity provider.",
},
(2003, "GitHubNoAuthenticationMethodError"): {
"message": "No GitHub authentication method found",
"remediation": "Check that any authentication method is properly set up for GitHub.",
},
(2006, "GitHubArgumentTypeValidationError"): {
"message": "GitHub argument type validation error",
"remediation": "Check the provided argument types specific to GitHub and ensure they meet the required format.",
},
(2010, "GitHubHTTPResponseError"): {
"message": "Error in HTTP response from GitHub",
"remediation": "",
},
(2014, "GitHubClientAuthenticationError"): {
"message": "Error in client authentication",
"remediation": "Check the client authentication and ensure it is properly set up.",
},
(2015, "GitHubSetUpSessionError"): {
"message": "Error setting up session",
"remediation": "Check the session setup and ensure it is properly set up.",
},
}
def __init__(self, code, file=None, original_exception=None, message=None):
provider = "GitHub"
error_info = self.GITHUB_ERROR_CODES.get((code, self.__class__.__name__))
if message:
error_info["message"] = message
super().__init__(
code=code,
source=provider,
file=file,
original_exception=original_exception,
error_info=error_info,
)
class GitHubCredentialsError(GitHubBaseException):
"""Base class for GitHub credentials errors."""
def __init__(self, code, file=None, original_exception=None, message=None):
super().__init__(code, file, original_exception, message)
class GitHubEnvironmentVariableError(GitHubCredentialsError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
2000, file=file, original_exception=original_exception, message=message
)
class GitHubInvalidTokenError(GitHubCredentialsError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
2001, file=file, original_exception=original_exception, message=message
)
class GitHubSetUpIdentityError(GitHubCredentialsError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
2002, file=file, original_exception=original_exception, message=message
)
class GitHubNoAuthenticationMethodError(GitHubCredentialsError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
2003, file=file, original_exception=original_exception, message=message
)
class GitHubArgumentTypeValidationError(GitHubBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
2006, file=file, original_exception=original_exception, message=message
)
class GitHubHTTPResponseError(GitHubBaseException):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
2010, file=file, original_exception=original_exception, message=message
)
class GitHubClientAuthenticationError(GitHubCredentialsError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
2014, file=file, original_exception=original_exception, message=message
)
class GitHubSetUpSessionError(GitHubCredentialsError):
def __init__(self, file=None, original_exception=None, message=None):
super().__init__(
2015, file=file, original_exception=original_exception, message=message
)
+4 -4
View File
@@ -11,7 +11,7 @@ from prowler.lib.logger import logger
from prowler.lib.mutelist.mutelist import Mutelist
from prowler.providers.common.models import Audit_Metadata
from prowler.providers.common.provider import Provider
from prowler.providers.github.lib.mutelist.mutelist import GitHubMutelist
from prowler.providers.github.lib.mutelist.mutelist import GithubMutelist
from prowler.providers.github.models import GithubIdentityInfo, GithubSession
@@ -70,13 +70,13 @@ class GithubProvider(Provider):
# Mutelist
if mutelist_content:
self._mutelist = GitHubMutelist(
self._mutelist = GithubMutelist(
mutelist_content=mutelist_content,
)
else:
if not mutelist_path:
mutelist_path = get_default_mute_file_path(self.type)
self._mutelist = GitHubMutelist(
self._mutelist = GithubMutelist(
mutelist_path=mutelist_path,
)
Provider.set_global_provider(self)
@@ -110,7 +110,7 @@ class GithubProvider(Provider):
return self._fixer_config
@property
def mutelist(self) -> GitHubMutelist:
def mutelist(self) -> GithubMutelist:
"""
mutelist method returns the provider's mutelist.
"""
@@ -3,7 +3,7 @@ from prowler.lib.mutelist.mutelist import Mutelist
from prowler.lib.outputs.utils import unroll_dict, unroll_tags
class GitHubMutelist(Mutelist):
class GithubMutelist(Mutelist):
def is_finding_muted(
self,
finding: Check_Report_Github,
@@ -9,18 +9,18 @@ from prowler.providers.github.lib.service.service import GithubService
class Repository(GithubService):
def __init__(self, provider):
super().__init__(__class__.__name__, provider)
self.repositories = {}
self._list_repositories()
self.repositories = self._list_repositories()
def _list_repositories(self):
logger.info("Repository - Listing Repositories...")
repos = {}
try:
for repo in self.client.get_user().get_repos():
try:
securitymd_exists = repo.get_contents("SECURITY.md") is not None
except Exception:
securitymd_exists = False
self.repositories[repo.id] = Repo(
repos[repo.id] = Repo(
id=repo.id,
name=repo.name,
full_name=repo.full_name,
@@ -31,6 +31,7 @@ class Repository(GithubService):
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
return repos
class Repo(BaseModel):
-1
View File
@@ -739,7 +739,6 @@ class TestGCPProvider:
), patch(
"prowler.providers.gcp.gcp_provider.GcpProvider.validate_project_id"
) as mock_validate_project_id:
mock_validate_project_id.side_effect = GCPInvalidProviderIdError(
"Invalid project ID"
)
+20 -8
View File
@@ -1,4 +1,5 @@
from mock import MagicMock
from prowler.providers.github.github_provider import GithubProvider
from prowler.providers.github.models import GithubIdentityInfo, GithubSession
@@ -7,16 +8,27 @@ ACCOUNT_NAME = "account-name"
ACCOUNT_ID = "account-id"
ACCOUNT_URL = "/user"
# GitHub Credentials
TOKEN = "github-token"
# Mocked GitHub Provider
def set_mocked_github_provider(
credentials:
) -> GithubProvider:
provider = MagicMock()
provider.type = "github"
provider.session = GithubSession()
provider.identity = GithubIdentityInfo(
auth_method: str = "personal_access_token",
credentials: GithubSession = GithubSession(token=TOKEN),
identity: GithubIdentityInfo = GithubIdentityInfo(
account_name=ACCOUNT_NAME,
account_id=ACCOUNT_ID,
account_url=ACCOUNT_URL,
)
return provider
),
audit_config: dict = None,
) -> GithubProvider:
provider = MagicMock()
provider.type = "github"
provider.auth_method = auth_method
provider.session = credentials
provider.identity = identity
provider.audit_config = audit_config
return provider
@@ -0,0 +1,52 @@
from unittest.mock import patch
from prowler.config.config import (
default_fixer_config_file_path,
load_and_validate_config_file,
)
from prowler.providers.github.github_provider import GithubProvider
from prowler.providers.github.models import GithubIdentityInfo, GithubSession
from tests.providers.github.github_fixtures import (
ACCOUNT_ID,
ACCOUNT_NAME,
ACCOUNT_URL,
TOKEN,
)
class TestGitHubProvider:
def test_github_provider(self):
# We need to set exactly one auth method
personal_access_token = True
oauth_app = False
github_app = False
fixer_config = load_and_validate_config_file(
"github", default_fixer_config_file_path
)
with patch(
"prowler.providers.github.github_provider.GithubProvider.setup_session",
return_value=GithubSession(token=TOKEN),
), patch(
"prowler.providers.github.github_provider.GithubProvider.setup_identity",
return_value=GithubIdentityInfo(
account_id=ACCOUNT_ID,
account_name=ACCOUNT_NAME,
account_url=ACCOUNT_URL,
),
):
provider = GithubProvider(
personal_access_token,
github_app,
oauth_app,
)
assert provider._type == "github"
assert provider.session == GithubSession(token=TOKEN)
assert provider.identity == GithubIdentityInfo(
account_name=ACCOUNT_NAME,
account_id=ACCOUNT_ID,
account_url=ACCOUNT_URL,
)
assert provider._audit_config == {}
assert provider._fixer_config == fixer_config
@@ -0,0 +1,95 @@
from unittest import mock
from prowler.providers.github.services.repository.repository_service import Repo
from tests.providers.github.github_fixtures import set_mocked_github_provider
class Test_repository_public_has_securitymd_file_test:
def test_no_repositories(self):
repository_client = mock.MagicMock
repository_client.repositories = {}
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_github_provider(),
), mock.patch(
"prowler.providers.github.services.repository.repository_public_has_securitymd_file.repository_public_has_securitymd_file.repository_client",
new=repository_client,
):
from prowler.providers.github.services.repository.repository_public_has_securitymd_file.repository_public_has_securitymd_file import (
repository_public_has_securitymd_file,
)
check = repository_public_has_securitymd_file()
result = check.execute()
assert len(result) == 0
def test_one_repository_no_securitymd(self):
repository_client = mock.MagicMock
repo_name = "repo1"
repository_client.repositories = {
1: Repo(
id=1,
name=repo_name,
full_name="account-name/repo1",
private=False,
securitymd=False,
),
}
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_github_provider(),
), mock.patch(
"prowler.providers.github.services.repository.repository_public_has_securitymd_file.repository_public_has_securitymd_file.repository_client",
new=repository_client,
):
from prowler.providers.github.services.repository.repository_public_has_securitymd_file.repository_public_has_securitymd_file import (
repository_public_has_securitymd_file,
)
check = repository_public_has_securitymd_file()
result = check.execute()
assert len(result) == 1
assert result[0].resource_id == 1
assert result[0].resource_name == "repo1"
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Repository {repo_name} does not have a SECURITY.md file."
)
def test_one_repository_securitymd(self):
repository_client = mock.MagicMock
repo_name = "repo1"
repository_client.repositories = {
1: Repo(
id=1,
name=repo_name,
full_name="account-name/repo1",
private=False,
securitymd=True,
),
}
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_github_provider(),
), mock.patch(
"prowler.providers.github.services.repository.repository_public_has_securitymd_file.repository_public_has_securitymd_file.repository_client",
new=repository_client,
):
from prowler.providers.github.services.repository.repository_public_has_securitymd_file.repository_public_has_securitymd_file import (
repository_public_has_securitymd_file,
)
check = repository_public_has_securitymd_file()
result = check.execute()
assert len(result) == 1
assert result[0].resource_id == 1
assert result[0].resource_name == "repo1"
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Repository {repo_name} does have a SECURITY.md file."
)
@@ -0,0 +1,41 @@
from unittest.mock import patch
from prowler.providers.github.services.repository.repository_service import (
Repo,
Repository,
)
from tests.providers.github.github_fixtures import set_mocked_github_provider
def mock_list_repositories(_):
return {
1: Repo(
id=1,
name="repo1",
full_name="account-name/repo1",
private=False,
securitymd=False,
),
}
@patch(
"prowler.providers.github.services.repository.repository_service.Repository._list_repositories",
new=mock_list_repositories,
)
class Test_Repository_Service:
def test_get_client(self):
repository_service = Repository(set_mocked_github_provider())
assert repository_service.client.__class__.__name__ == "Github"
def test_get_service(self):
repository_service = Repository(set_mocked_github_provider())
assert repository_service.__class__.__name__ == "Repository"
def test_list_repositories(self):
repository_service = Repository(set_mocked_github_provider())
assert len(repository_service.repositories) == 1
assert repository_service.repositories[1].name == "repo1"
assert repository_service.repositories[1].full_name == "account-name/repo1"
assert repository_service.repositories[1].private is False
assert repository_service.repositories[1].securitymd is False