mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-15 07:54:21 +00:00
feat: provider structural resemblance
This commit is contained in:
17 files changed
+313
-28
No files matched your search
@@ -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": []
|
||||
}
|
||||
@@ -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 = ""
|
||||
@@ -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(
|
||||
|
||||
@@ -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.
@@ -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
|
||||
@@ -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
|
||||
Reference in new issue
Block a user