mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-10-04 02:04:06 +00:00
feat(github): add organization_actions_pull_request_approval_disabled check (#12394)
Co-authored-by: Daniel Barranquero <danielbo2001@gmail.com>
This commit is contained in:
co-authored by
Daniel Barranquero
parent
bd1956446d
commit
2721d42594
+79
@@ -0,0 +1,79 @@
|
||||
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
|
||||
|
||||
CHECK_CLIENT_PATH = "prowler.providers.github.services.organization.organization_actions_pull_request_approval_disabled.organization_actions_pull_request_approval_disabled.organization_client"
|
||||
|
||||
|
||||
class Test_organization_actions_pull_request_approval_disabled:
|
||||
"""Unit tests for the organization_actions_pull_request_approval_disabled check."""
|
||||
|
||||
def _run_check(self, organizations):
|
||||
"""Execute the check against the provided organizations."""
|
||||
organization_client = mock.MagicMock
|
||||
organization_client.organizations = organizations
|
||||
|
||||
with (
|
||||
mock.patch(
|
||||
"prowler.providers.common.provider.Provider.get_global_provider",
|
||||
return_value=set_mocked_github_provider(),
|
||||
),
|
||||
mock.patch(CHECK_CLIENT_PATH, new=organization_client),
|
||||
):
|
||||
from prowler.providers.github.services.organization.organization_actions_pull_request_approval_disabled.organization_actions_pull_request_approval_disabled import (
|
||||
organization_actions_pull_request_approval_disabled,
|
||||
)
|
||||
|
||||
check = organization_actions_pull_request_approval_disabled()
|
||||
return check.execute()
|
||||
|
||||
def test_no_organizations(self):
|
||||
"""Test that no findings are reported when there are no organizations."""
|
||||
assert len(self._run_check({})) == 0
|
||||
|
||||
def test_pull_request_approval_unknown(self):
|
||||
"""Test that no finding is reported when the setting could not be read."""
|
||||
organizations = {
|
||||
1: Org(
|
||||
id=1, name="test-organization", can_approve_pull_request_reviews=None
|
||||
)
|
||||
}
|
||||
|
||||
assert len(self._run_check(organizations)) == 0
|
||||
|
||||
def test_pull_request_approval_disabled(self):
|
||||
"""Test that an organization not allowing workflow approvals passes the check."""
|
||||
organizations = {
|
||||
1: Org(
|
||||
id=1, name="test-organization", can_approve_pull_request_reviews=False
|
||||
)
|
||||
}
|
||||
result = self._run_check(organizations)
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].resource_id == 1
|
||||
assert result[0].resource_name == "test-organization"
|
||||
assert result[0].status == "PASS"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Organization test-organization does not allow GitHub Actions to approve pull requests."
|
||||
)
|
||||
|
||||
def test_pull_request_approval_enabled(self):
|
||||
"""Test that an organization allowing workflow approvals fails the check."""
|
||||
organizations = {
|
||||
1: Org(
|
||||
id=1, name="test-organization", can_approve_pull_request_reviews=True
|
||||
)
|
||||
}
|
||||
result = self._run_check(organizations)
|
||||
|
||||
assert len(result) == 1
|
||||
assert result[0].resource_id == 1
|
||||
assert result[0].resource_name == "test-organization"
|
||||
assert result[0].status == "FAIL"
|
||||
assert (
|
||||
result[0].status_extended
|
||||
== "Organization test-organization allows GitHub Actions to approve pull requests."
|
||||
)
|
||||
@@ -514,7 +514,8 @@ class Test_Organization_Default_Workflow_Permissions:
|
||||
)
|
||||
|
||||
assert (
|
||||
organization_service._get_default_workflow_permissions(mock_org) == "read"
|
||||
organization_service._get_actions_workflow_permissions(mock_org)[0]
|
||||
== "read"
|
||||
), "The organization default GITHUB_TOKEN permissions should be read from the Actions permissions endpoint"
|
||||
mock_org._requester.requestJsonAndCheck.assert_called_once_with(
|
||||
"GET",
|
||||
@@ -525,6 +526,27 @@ class Test_Organization_Default_Workflow_Permissions:
|
||||
},
|
||||
)
|
||||
|
||||
def test_can_approve_pull_request_reviews(self):
|
||||
"""Test that the pull request approval setting is read from the same API response"""
|
||||
organization_service = self._get_service()
|
||||
mock_org = MagicMock()
|
||||
mock_org.login = "test-org"
|
||||
mock_org._requester.requestJsonAndCheck.return_value = (
|
||||
{},
|
||||
{
|
||||
"default_workflow_permissions": "write",
|
||||
"can_approve_pull_request_reviews": True,
|
||||
},
|
||||
)
|
||||
|
||||
assert organization_service._get_actions_workflow_permissions(mock_org) == (
|
||||
"write",
|
||||
True,
|
||||
), "Both Actions workflow permissions settings should come from a single request"
|
||||
assert (
|
||||
mock_org._requester.requestJsonAndCheck.call_count == 1
|
||||
), "Both settings should be read without issuing a second request"
|
||||
|
||||
def test_default_workflow_permissions_missing_field(self):
|
||||
"""Test that a response without the permissions field yields no value"""
|
||||
organization_service = self._get_service()
|
||||
@@ -532,10 +554,31 @@ class Test_Organization_Default_Workflow_Permissions:
|
||||
mock_org.login = "test-org"
|
||||
mock_org._requester.requestJsonAndCheck.return_value = ({}, {})
|
||||
|
||||
assert (
|
||||
organization_service._get_default_workflow_permissions(mock_org) is None
|
||||
assert organization_service._get_actions_workflow_permissions(mock_org) == (
|
||||
None,
|
||||
None,
|
||||
), "An unexpected response payload should not be reported as a permissions value"
|
||||
|
||||
def test_default_workflow_permissions_unsupported_value(self):
|
||||
"""Test that a value outside read/write is treated as unknown rather than a failure
|
||||
|
||||
The endpoint documents only "read" and "write". Accepting any string meant a
|
||||
value such as "READ" or "none" reached the check and produced a FAIL finding,
|
||||
reporting a write-capable default the organization may not actually have.
|
||||
"""
|
||||
organization_service = self._get_service()
|
||||
mock_org = MagicMock()
|
||||
mock_org.login = "test-org"
|
||||
mock_org._requester.requestJsonAndCheck.return_value = (
|
||||
{},
|
||||
{"default_workflow_permissions": "none"},
|
||||
)
|
||||
|
||||
assert organization_service._get_actions_workflow_permissions(mock_org) == (
|
||||
None,
|
||||
None,
|
||||
), "An unsupported permissions value should be left unknown instead of reported as write"
|
||||
|
||||
def test_default_workflow_permissions_not_available(self):
|
||||
"""Test that accounts without Actions permissions settings yield no value"""
|
||||
organization_service = self._get_service()
|
||||
@@ -545,8 +588,9 @@ class Test_Organization_Default_Workflow_Permissions:
|
||||
404, "Not Found", None
|
||||
)
|
||||
|
||||
assert (
|
||||
organization_service._get_default_workflow_permissions(mock_org) is None
|
||||
assert organization_service._get_actions_workflow_permissions(mock_org) == (
|
||||
None,
|
||||
None,
|
||||
), "Accounts without Actions permissions settings should not produce a value"
|
||||
|
||||
def test_default_workflow_permissions_access_denied(self):
|
||||
@@ -561,8 +605,9 @@ class Test_Organization_Default_Workflow_Permissions:
|
||||
with patch(
|
||||
"prowler.providers.github.services.organization.organization_service.logger"
|
||||
) as mock_logger:
|
||||
assert (
|
||||
organization_service._get_default_workflow_permissions(mock_org) is None
|
||||
assert organization_service._get_actions_workflow_permissions(mock_org) == (
|
||||
None,
|
||||
None,
|
||||
), "Insufficient permissions should not produce a value"
|
||||
mock_logger.warning.assert_called()
|
||||
|
||||
@@ -576,4 +621,4 @@ class Test_Organization_Default_Workflow_Permissions:
|
||||
)
|
||||
|
||||
with raises(RateLimitExceededException):
|
||||
organization_service._get_default_workflow_permissions(mock_org)
|
||||
organization_service._get_actions_workflow_permissions(mock_org)
|
||||
|
||||
Reference in New Issue
Block a user