feat(github): add organization base repository permission strict check (CIS GitHub 1.3.8) (#8785)

Co-authored-by: akorshak-afg <alex.korshak@afg.org>
Co-authored-by: Sergio Garcia <sergargar1@gmail.com>
Co-authored-by: Andoni Alonso <14891798+andoniaf@users.noreply.github.com>
This commit is contained in:
Alex K
2025-10-27 03:45:50 -05:00
committed by GitHub
parent b8dab5e0ed
commit ff4a186df6
9 changed files with 344 additions and 12 deletions
@@ -0,0 +1,201 @@
from unittest import mock
from prowler.providers.github.services.organization.organization_service import Org
from tests.providers.github.github_fixtures import set_mocked_github_provider
class Test_organization_default_repository_permission_strict:
def test_no_organizations(self):
organization_client = mock.MagicMock
organization_client.organizations = {}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_github_provider(),
),
mock.patch(
"prowler.providers.github.services.organization.organization_default_repository_permission_strict.organization_default_repository_permission_strict.organization_client",
new=organization_client,
),
):
from prowler.providers.github.services.organization.organization_default_repository_permission_strict.organization_default_repository_permission_strict import (
organization_default_repository_permission_strict,
)
check = organization_default_repository_permission_strict()
result = check.execute()
assert len(result) == 0
def test_permission_read(self):
organization_client = mock.MagicMock
org_name = "test-organization"
organization_client.organizations = {
1: Org(
id=1,
name=org_name,
base_permission="read",
),
}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_github_provider(),
),
mock.patch(
"prowler.providers.github.services.organization.organization_default_repository_permission_strict.organization_default_repository_permission_strict.organization_client",
new=organization_client,
),
):
from prowler.providers.github.services.organization.organization_default_repository_permission_strict.organization_default_repository_permission_strict import (
organization_default_repository_permission_strict,
)
check = organization_default_repository_permission_strict()
result = check.execute()
assert len(result) == 1
assert result[0].resource_id == 1
assert result[0].resource_name == org_name
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Organization {org_name} base repository permission is 'read', which is strict."
)
def test_permission_none(self):
organization_client = mock.MagicMock
org_name = "test-organization"
organization_client.organizations = {
1: Org(
id=1,
name=org_name,
base_permission="none",
),
}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_github_provider(),
),
mock.patch(
"prowler.providers.github.services.organization.organization_default_repository_permission_strict.organization_default_repository_permission_strict.organization_client",
new=organization_client,
),
):
from prowler.providers.github.services.organization.organization_default_repository_permission_strict.organization_default_repository_permission_strict import (
organization_default_repository_permission_strict,
)
check = organization_default_repository_permission_strict()
result = check.execute()
assert len(result) == 1
assert result[0].resource_id == 1
assert result[0].resource_name == org_name
assert result[0].status == "PASS"
assert (
result[0].status_extended
== f"Organization {org_name} base repository permission is 'none', which is strict."
)
def test_permission_write(self):
organization_client = mock.MagicMock
org_name = "test-organization"
organization_client.organizations = {
1: Org(
id=1,
name=org_name,
base_permission="write",
),
}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_github_provider(),
),
mock.patch(
"prowler.providers.github.services.organization.organization_default_repository_permission_strict.organization_default_repository_permission_strict.organization_client",
new=organization_client,
),
):
from prowler.providers.github.services.organization.organization_default_repository_permission_strict.organization_default_repository_permission_strict import (
organization_default_repository_permission_strict,
)
check = organization_default_repository_permission_strict()
result = check.execute()
assert len(result) == 1
assert result[0].resource_id == 1
assert result[0].resource_name == org_name
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Organization {org_name} base repository permission is 'write', which is not strict."
)
def test_permission_admin(self):
organization_client = mock.MagicMock
org_name = "test-organization"
organization_client.organizations = {
1: Org(
id=1,
name=org_name,
base_permission="admin",
),
}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_github_provider(),
),
mock.patch(
"prowler.providers.github.services.organization.organization_default_repository_permission_strict.organization_default_repository_permission_strict.organization_client",
new=organization_client,
),
):
from prowler.providers.github.services.organization.organization_default_repository_permission_strict.organization_default_repository_permission_strict import (
organization_default_repository_permission_strict,
)
check = organization_default_repository_permission_strict()
result = check.execute()
assert len(result) == 1
assert result[0].resource_id == 1
assert result[0].resource_name == org_name
assert result[0].status == "FAIL"
assert (
result[0].status_extended
== f"Organization {org_name} base repository permission is 'admin', which is not strict."
)
def test_permission_unknown_none_skipped(self):
organization_client = mock.MagicMock
org_name = "test-organization"
organization_client.organizations = {
1: Org(
id=1,
name=org_name,
base_permission=None,
),
}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_github_provider(),
),
mock.patch(
"prowler.providers.github.services.organization.organization_default_repository_permission_strict.organization_default_repository_permission_strict.organization_client",
new=organization_client,
),
):
from prowler.providers.github.services.organization.organization_default_repository_permission_strict.organization_default_repository_permission_strict import (
organization_default_repository_permission_strict,
)
check = organization_default_repository_permission_strict()
result = check.execute()
assert len(result) == 0
@@ -45,11 +45,13 @@ class Test_Organization_Scoping:
self.mock_org1.id = 1
self.mock_org1.login = "test-org1"
self.mock_org1.two_factor_requirement_enabled = True
self.mock_org1.default_repository_permission = None
self.mock_org2 = MagicMock()
self.mock_org2.id = 2
self.mock_org2.login = "test-org2"
self.mock_org2.two_factor_requirement_enabled = False
self.mock_org2.default_repository_permission = None
self.mock_user = MagicMock()
self.mock_user.id = 100
@@ -175,6 +177,35 @@ class Test_Organization_Scoping:
assert len(orgs) == 0
def test_base_permission_extraction(self):
"""Test that base_permission is populated from organization's default_repository_permission"""
provider = set_mocked_github_provider()
provider.repositories = []
provider.organizations = ["test-org1"]
mock_client = MagicMock()
# Organization with default_repository_permission set to "read"
org_with_perm = MagicMock()
org_with_perm.id = 1
org_with_perm.login = "test-org1"
org_with_perm.two_factor_requirement_enabled = True
org_with_perm.default_repository_permission = "read"
mock_client.get_organization.return_value = org_with_perm
with patch(
"prowler.providers.github.services.organization.organization_service.GithubService.__init__"
):
organization_service = Organization(provider)
organization_service.clients = [mock_client]
organization_service.provider = provider
orgs = organization_service._list_organizations()
assert len(orgs) == 1
assert 1 in orgs
assert orgs[1].name == "test-org1"
assert orgs[1].base_permission == "read"
def test_specific_organization_scoping(self):
"""Test that only specified organizations are returned"""
provider = set_mocked_github_provider()
@@ -287,11 +318,13 @@ class Test_Organization_Scoping:
mock_owner_org.id = 1
mock_owner_org.login = "owner1"
mock_owner_org.two_factor_requirement_enabled = True
mock_owner_org.default_repository_permission = None
mock_specific_org = MagicMock()
mock_specific_org.id = 2
mock_specific_org.login = "specific-org"
mock_specific_org.two_factor_requirement_enabled = False
mock_specific_org.default_repository_permission = None
mock_client.get_organization.side_effect = [
mock_owner_org,
@@ -393,6 +426,7 @@ class Test_Organization_ErrorHandling:
self.mock_org1.id = 1
self.mock_org1.login = "test-org1"
self.mock_org1.two_factor_requirement_enabled = True
self.mock_org1.default_repository_permission = None
def test_github_api_error_handling(self):
"""Test that GitHub API errors are handled properly"""