feat: added check logic and metadata

This commit is contained in:
HugoPBrito committed 2024-12-11 14:22:17 +01:00
1 parent 0715c659c8
commit 7d10727c34
5 files changed
+120 -41

No files matched your search

@@ -28,7 +28,7 @@ class repository_code_changes_multi_approval_requirement(Check):
report.status = "FAIL"
report.status_extended = f"Repository {repo.name} does not enforce at least 2 approvals for code changes."
if repo.approval_count >= 2:
if repo.default_branch_protection.approval_count >= 2:
report.status = "PASS"
report.status_extended = f"Repository {repo.name} does enforce at least 2 approvals for code changes."
@@ -0,0 +1,30 @@
{
"Provider": "github",
"CheckID": "repository_enforces_default_branch_protection",
"CheckTitle": "Check if branch protection is enforced on the default branch ",
"CheckType": [],
"ServiceName": "repository",
"SubServiceName": "",
"ResourceIdTemplate": "github:user-id:repository/repository-name",
"Severity": "critical",
"ResourceType": "Other",
"Description": "Ensure branch protection is enforced on the default branch",
"Risk": "The absence of branch protection on the default branch increases the risk of unauthorized, unreviewed, or untested changes being merged. This can compromise the stability, security, and reliability of the codebase, which is especially critical for production deployments.",
"RelatedUrl": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches",
"Remediation": {
"Code": {
"CLI": "",
"NativeIaC": "",
"Other": "",
"Terraform": ""
},
"Recommendation": {
"Text": "Apply branch protection rules to the default branch to ensure it is safeguarded against unauthorized or improper modifications. This helps maintain code quality, enforces proper review and testing procedures, and reduces the risk of accidental or malicious changes.",
"Url": "https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/managing-a-branch-protection-rule#creating-a-branch-protection-rule"
}
},
"Categories": [],
"DependsOn": [],
"RelatedTo": [],
"Notes": ""
}
@@ -0,0 +1,37 @@
from typing import List
from prowler.lib.check.models import Check, Check_Report_Github
from prowler.providers.github.services.repository.repository_client import (
repository_client,
)
class repository_enforces_default_branch_protection(Check):
"""Check if a repository enforces default branch protection
This class verifies whether each repository enforces default branch protection.
"""
def execute(self) -> List[Check_Report_Github]:
"""Execute the Github Repository Enforces Default Branch Protection check
Iterates over all repositories and checks if they enforce default branch protection.
Returns:
List[Check_Report_Github]: A list of reports for each repository
"""
findings = []
for repo in repository_client.repositories.values():
report = Check_Report_Github(self.metadata())
report.resource_id = repo.id
report.resource_name = repo.name
report.status = "FAIL"
report.status_extended = f"Repository {repo.name} does not enforce branch protection on default branch ({repo.default_branch})."
if repo.default_branch_protection:
report.status = "PASS"
report.status_extended = f"Repository {repo.name} does enforce branch protection on default branch ({repo.default_branch})."
findings.append(report)
return findings
@@ -17,45 +17,51 @@ class Repository(GithubService):
try:
for client in self.clients:
for repo in client.get_user().get_repos():
default_branch = repo.default_branch
securitymd_exists = False
try:
securitymd_exists = repo.get_contents("SECURITY.md") is not None
except Exception as e:
logger.warning(
f"Could not find SECURITY.md for repo {repo.name}: {e}"
)
if not repo.private: # Only for testing purposes
default_branch = repo.default_branch
securitymd_exists = False
try:
securitymd_exists = (
repo.get_contents("SECURITY.md") is not None
)
except Exception as e:
logger.warning(
f"Could not find SECURITY.md for repo {repo.name}: {e}"
)
require_pr = False
approval_cnt = 0
try:
branch = repo.get_branch(default_branch)
if branch.protected:
protection = branch.get_protection()
if protection:
require_pr = (
protection.required_pull_request_reviews is not None
)
approval_cnt = (
protection.required_pull_request_reviews.required_approving_review_count
if require_pr
else 0
)
except Exception as e:
logger.warning(
f"Could not get branch protection for repo {repo.name}: {e}"
)
branch_protection = None
try:
branch = repo.get_branch(default_branch)
if branch.protected:
protection = branch.get_protection()
if protection:
require_pr = (
protection.required_pull_request_reviews
is not None
)
approval_cnt = (
protection.required_pull_request_reviews.required_approving_review_count
if require_pr
else 0
)
branch_protection = Protection(
require_pull_request=require_pr,
approval_count=approval_cnt,
)
except Exception as e:
logger.warning(
f"Could not get branch protection for repo {repo.name}: {e}"
)
repos[repo.id] = Repo(
id=repo.id,
name=repo.name,
full_name=repo.full_name,
default_branch=repo.default_branch,
private=repo.private,
securitymd=securitymd_exists,
require_pull_request=require_pr,
approval_count=approval_cnt,
)
repos[repo.id] = Repo(
id=repo.id,
name=repo.name,
full_name=repo.full_name,
default_branch=repo.default_branch,
private=repo.private,
securitymd=securitymd_exists,
default_branch_protection=branch_protection,
)
except Exception as error:
logger.error(
@@ -64,14 +70,20 @@ class Repository(GithubService):
return repos
class Protection(BaseModel):
"""Model for Github Branch Protection"""
require_pull_request: Optional[bool] = False
approval_count: Optional[int] = 0
class Repo(BaseModel):
"""Model for Github Repository"""
id: int
name: str
full_name: str
default_branch: str
private: bool
default_branch: str
default_branch_protection: Optional[Protection]
securitymd: Optional[bool] = False
require_pull_request: Optional[bool] = False
approval_count: Optional[int] = 0