feat: provider structural resemblance

This commit is contained in:
HugoPBrito committed 2024-11-15 14:03:56 +01:00
1 parent f8f1e6c076
commit 27b628152d
17 files changed
+313 -28

No files matched your search

+5
View File
@@ -75,6 +75,7 @@ from prowler.providers.azure.models import AzureOutputOptions
from prowler.providers.common.provider import Provider
from prowler.providers.common.quick_inventory import run_provider_quick_inventory
from prowler.providers.gcp.models import GCPOutputOptions
from prowler.providers.github.models import GithubOutputOptions
from prowler.providers.kubernetes.models import KubernetesOutputOptions
@@ -257,6 +258,10 @@ def prowler():
output_options = KubernetesOutputOptions(
args, bulk_checks_metadata, global_provider.identity
)
elif provider == "github":
output_options = GithubOutputOptions(
args, bulk_checks_metadata, global_provider.identity
)
# Run the quick inventory for the provider if available
if hasattr(args, "quick_inventory") and args.quick_inventory:
Whitespace-only changes.
@@ -0,0 +1,7 @@
{
"Framework": "CIS",
"Version": "1.0",
"Provider": "Github",
"Description": "This CIS Benchmark provides prescriptive guidance for establishing a secure configuration posture for securing the Software Supply Chain.",
"Requirements": []
}
+13
View File
@@ -502,3 +502,16 @@ def load_check_metadata(metadata_file: str) -> CheckMetadata:
sys.exit(1)
else:
return check_metadata
@dataclass
class Check_Report_GitHub(Check_Report):
"""Contains the GitHub Check's finding information."""
resource_name: str
resource_id: str
def __init__(self, metadata):
super().__init__(metadata)
self.resource_name = ""
self.resource_id = ""
+8
View File
@@ -211,6 +211,14 @@ class Provider(ABC):
mutelist_path=arguments.mutelist_file,
fixer_config=fixer_config,
)
elif "github" in provider_class_name.lower():
provider_class(
personal_access_token=arguments.personal_access_token,
github_app=arguments.github_app,
oauth_app=arguments.oauth_app,
config_content=arguments.config_content,
config_path=arguments.config_file,
)
except TypeError as error:
logger.critical(
+7 -28
View File
@@ -1,32 +1,11 @@
import json
from os import getenv
import requests
from github import Auth, Github
TOKEN = "token"
ENDPOINT = "https://api.github.com/graphql"
TOKEN = getenv("GITHUB_PERSONAL_ACCESS_TOKEN")
headers = {"Authorization": f"Bearer {TOKEN}", "Content-Type": "application/json"}
auth = Auth.Token(TOKEN)
g = Github(auth=auth)
query = """
{
user(login: "HugoPBrito") {
login
twoFactorAuthentication {
enabled
}
}
}
"""
response = requests.post(ENDPOINT, headers=headers, json={"query": query})
if response.status_code == 200:
print(json.dumps(response.json(), indent=2))
data = response.json()
two_factor_authentication = data["data"]["user"]["twoFactorAuthentication"][
"enabled"
]
print(two_factor_authentication)
else:
print(f"Error {response.status_code}: {response.text}")
for repo in g.get_user().get_repos():
print(repo)
Whitespace-only changes.
+141
View File
@@ -0,0 +1,141 @@
from os import getenv
from github import Auth, Github
from prowler.config.config import (
default_config_file_path,
load_and_validate_config_file,
)
from prowler.lib.logger import logger
from prowler.providers.common.models import Audit_Metadata
from prowler.providers.common.provider import Provider
from prowler.providers.github.models import GithubIdentityInfo, GithubSession
class GithubProvider(Provider):
_type: str = "github"
_session: GithubSession
_identity: GithubIdentityInfo
_audit_config: dict
audit_metadata: Audit_Metadata
def __init__(
self,
personal_access_token: bool = False,
github_app: bool = False,
oauth_app: bool = False,
config_content: dict = None,
config_path: str = None,
):
"""
GitHub Provider constructor
Args:
personal_access_token (str): GitHub token as authentication method
github_app (bool): GitHub App as authentication method
oauth_app (bool): OAuth App as authentication method
config_content (dict): Configuration content
config_path (str): Configuration path
"""
logger.info("Instantiating GitHub Provider...")
self._session = self.setup_session(
personal_access_token,
github_app,
oauth_app,
)
self._identity = self.setup_identity(
personal_access_token,
github_app,
oauth_app,
)
self._audit_config = {}
if config_content:
self._audit_config = config_content
else:
if not config_path:
config_path = default_config_file_path
self._audit_config = load_and_validate_config_file(self._type, config_path)
@property
def identity(self):
"""Returns the identity information for the GitHub provider."""
return self._identity
@property
def session(self):
"""Returns the session object for the GitHub provider."""
return self._session
@property
def type(self):
"""Returns the type of the GitHub provider."""
return self._type
@property
def audit_config(self):
"""Returns the audit configuration for the GitHub provider."""
return self._audit_config
@staticmethod
def setup_session(
self,
personal_access_token: bool = False,
github_app: bool = False,
oauth_app: bool = False,
) -> GithubSession:
"""
Returns the GitHub headers responsible authenticating API calls.
Args:
personal_access_token (str): Flag indicating whether to use GitHub personal access token as authentication method.
github_app (bool): Flag indicating whether to use GitHub App as authentication method.
oauth_app (bool): Flag indicating whether to use OAuth App as authentication method.
Returns:
GithubSession: Authenticated session for API requests.
"""
if personal_access_token:
token = getenv("GITHUB_PERSONAL_ACCESS_TOKEN")
elif github_app:
token = getenv("GITHUB_APP_TOKEN")
elif oauth_app:
token = getenv("GITHUB_OAUTH_TOKEN")
else:
raise ValueError(
"A GitHub API token of some kind is required to initialize GitHub provider."
)
credentials = GithubSession(token=Auth.Token(token=token))
return credentials
@staticmethod
def setup_identity(
self,
personal_access_token: bool = False,
github_app: bool = False,
oauth_app: bool = False,
) -> GithubIdentityInfo:
"""
Returns the GitHub identity information
Args:
personal_access_token (str): Flag indicating whether to use GitHub personal access token as authentication method.
github_app (bool): Flag indicating whether to use GitHub App as authentication method.
oauth_app (bool): Flag indicating whether to use OAuth App as authentication method.
Returns:
GithubIdentityInfo: An instance of GithubIdentityInfo containing the identity information.
"""
credentials = self.session
identity = GithubIdentityInfo()
if personal_access_token or github_app or oauth_app:
auth = Auth.Token(credentials.token)
g = Github(auth=auth)
identity.account_name = g.get_user().login
identity.account_id = g.get_user().id
identity.account_url = g.get_user().url
return identity
Whitespace-only changes.
@@ -0,0 +1,23 @@
def init_parser(self):
"""Init the Github Provider CLI parser"""
github_parser = self.subparsers.add_parser(
"github", parents=[self.common_providers_parser], help="GitHub Provider"
)
# Authentication Modes
github_auth_subparser = github_parser.add_argument_group("Authentication Modes")
github_auth_modes_group = github_auth_subparser.add_mutually_exclusive_group()
github_auth_modes_group.add_argument(
"--pat-auth",
action="store_true",
help="Use Personal Access Token to log in against GitHub",
)
github_auth_modes_group.add_argument(
"--oauth-auth",
action="store_true",
help="Use Oauth app token to log in against GitHub",
)
github_auth_modes_group.add_argument(
"--app-auth",
action="store_true",
help="Use GitHub app token to log in against GitHub",
)
Whitespace-only changes.
@@ -0,0 +1,17 @@
from prowler.lib.check.models import Check_Report_GitHub
from prowler.lib.mutelist.mutelist import Mutelist
from prowler.lib.outputs.utils import unroll_dict, unroll_tags
class GitHubMutelist(Mutelist):
def is_finding_muted(
self,
finding: Check_Report_GitHub,
) -> bool:
return self.is_muted(
finding.subscription,
finding.check_metadata.CheckID,
finding.location,
finding.resource_name,
unroll_dict(unroll_tags(finding.resource_tags)),
)
Whitespace-only changes.
@@ -0,0 +1,32 @@
from github import Auth, Github
from prowler.lib.logger import logger
from prowler.providers.github.github_provider import GithubProvider
class GithubService:
def __init__(
self,
service: str,
provider: GithubProvider,
):
self.clients = self.__set_clients__(
provider.identity,
provider.session,
service,
)
self.audit_config = provider.audit_config
self.fixer_config = provider.fixer_config
def __set_clients__(self, session):
client = {}
try:
auth = Auth.Token(session.token)
client = Github(auth=auth)
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
else:
return client
+29
View File
@@ -0,0 +1,29 @@
from pydantic import BaseModel
from prowler.config.config import output_file_timestamp
from prowler.providers.common.models import ProviderOutputOptions
class GithubIdentityInfo(BaseModel):
account_name: str
account_id: str
account_url: str
class GithubSession(BaseModel):
token: str
class GithubOutputOptions(ProviderOutputOptions):
def __init__(self, arguments, bulk_checks_metadata, identity):
# First call ProviderOutputOptions init
super().__init__(arguments, bulk_checks_metadata)
# TODO move the below if to ProviderOutputOptions
# Check if custom output filename was input, if not, set the default
if (
not hasattr(arguments, "output_filename")
or arguments.output_filename is None
):
self.output_filename = f"prowler-output-{identity.context.replace(':', '_').replace('/', '_')}-{output_file_timestamp}"
else:
self.output_filename = arguments.output_filename
Whitespace-only changes.
@@ -0,0 +1,31 @@
from pydantic import BaseModel
from prowler.lib.logger import logger
from prowler.providers.github.github_provider import GithubProvider
from prowler.providers.github.lib.service.service import GithubService
class GitHubAccount(GithubService):
def __init__(self, provider: GithubProvider):
super().__init__("GitHubAccount", provider)
self.account = Account(
name=provider.identity.account_name, id=provider.identity.account_id
)
self._get_ssh_keys_status()
def _get_ssh_keys_status(self):
try:
user = self.client.get_user()
keys = self.client.get_user_keys(user.login)
self.account.ssh_keys = keys.totalCount > 0
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}"
)
class Account(BaseModel):
name: str
id: str
ssh_keys: bool = False