
Prowler Test Sdk
- 64 installs
- 14.5k repo stars
- Updated August 4, 2026
- prowler-cloud/prowler
Helps with testing & qa tasks.
About
prowler-test-sdk is a Claude Code skill for testing & qa. It helps solo builders move faster with AI-assisted development.
- prowler-test-sdk
- Testing & QA
- AI-coding skill
Prowler Test Sdk by the numbers
- 64 all-time installs (skills.sh)
- Ranked #1,138 of 2,153 Testing & QA skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/prowler-cloud/prowler --skill prowler-test-sdkAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 64 |
|---|---|
| repo stars | ★ 14.5k |
| Last updated | August 4, 2026 |
| Repository | prowler-cloud/prowler ↗ |
What it does
Helps with testing & qa tasks.
Files
Generic Patterns: For base pytest patterns (fixtures, mocking, parametrize, markers), see the pytest skill.This skill covers Prowler-specific conventions only.
>
Full Documentation: docs/developer-guide/unit-testing.mdxCRITICAL: Provider-Specific Testing
| Provider | Mocking Approach | Decorator |
|---|---|---|
| AWS | moto library | @mock_aws |
| Azure, GCP, K8s, others | MagicMock | None |
NEVER use moto for non-AWS providers. NEVER use MagicMock for AWS.
---
AWS Check Test Pattern
from unittest import mock
from boto3 import client
from moto import mock_aws
from tests.providers.aws.utils import AWS_REGION_US_EAST_1, set_mocked_aws_provider
class Test_{check_name}:
@mock_aws
def test_no_resources(self):
from prowler.providers.aws.services.{service}.{service}_service import {ServiceClass}
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
):
with mock.patch(
"prowler.providers.aws.services.{service}.{check_name}.{check_name}.{service}_client",
new={ServiceClass}(aws_provider),
):
from prowler.providers.aws.services.{service}.{check_name}.{check_name} import (
{check_name},
)
check = {check_name}()
result = check.execute()
assert len(result) == 0
@mock_aws
def test_{check_name}_pass(self):
# Setup AWS resources with moto
{service}_client = client("{service}", region_name=AWS_REGION_US_EAST_1)
# Create compliant resource...
from prowler.providers.aws.services.{service}.{service}_service import {ServiceClass}
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
):
with mock.patch(
"prowler.providers.aws.services.{service}.{check_name}.{check_name}.{service}_client",
new={ServiceClass}(aws_provider),
):
from prowler.providers.aws.services.{service}.{check_name}.{check_name} import (
{check_name},
)
check = {check_name}()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
@mock_aws
def test_{check_name}_fail(self):
# Setup AWS resources with moto
{service}_client = client("{service}", region_name=AWS_REGION_US_EAST_1)
# Create non-compliant resource...
from prowler.providers.aws.services.{service}.{service}_service import {ServiceClass}
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
with mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
):
with mock.patch(
"prowler.providers.aws.services.{service}.{check_name}.{check_name}.{service}_client",
new={ServiceClass}(aws_provider),
):
from prowler.providers.aws.services.{service}.{check_name}.{check_name} import (
{check_name},
)
check = {check_name}()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"Critical: Always import the check INSIDE the mock.patch context to ensure proper client mocking.
---
Azure Check Test Pattern
NO moto decorator. Use MagicMock to mock the service client directly.
from unittest import mock
from uuid import uuid4
from prowler.providers.azure.services.{service}.{service}_service import {ResourceModel}
from tests.providers.azure.azure_fixtures import (
AZURE_SUBSCRIPTION_ID,
set_mocked_azure_provider,
)
class Test_{check_name}:
def test_no_resources(self):
{service}_client = mock.MagicMock
{service}_client.{resources} = {}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
),
mock.patch(
"prowler.providers.azure.services.{service}.{check_name}.{check_name}.{service}_client",
new={service}_client,
),
):
from prowler.providers.azure.services.{service}.{check_name}.{check_name} import (
{check_name},
)
check = {check_name}()
result = check.execute()
assert len(result) == 0
def test_{check_name}_pass(self):
resource_id = str(uuid4())
resource_name = "Test Resource"
{service}_client = mock.MagicMock
{service}_client.{resources} = {
AZURE_SUBSCRIPTION_ID: {
resource_id: {ResourceModel}(
id=resource_id,
name=resource_name,
location="westeurope",
# ... compliant attributes
)
}
}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
),
mock.patch(
"prowler.providers.azure.services.{service}.{check_name}.{check_name}.{service}_client",
new={service}_client,
),
):
from prowler.providers.azure.services.{service}.{check_name}.{check_name} import (
{check_name},
)
check = {check_name}()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
assert result[0].resource_name == resource_name
def test_{check_name}_fail(self):
resource_id = str(uuid4())
resource_name = "Test Resource"
{service}_client = mock.MagicMock
{service}_client.{resources} = {
AZURE_SUBSCRIPTION_ID: {
resource_id: {ResourceModel}(
id=resource_id,
name=resource_name,
location="westeurope",
# ... non-compliant attributes
)
}
}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
),
mock.patch(
"prowler.providers.azure.services.{service}.{check_name}.{check_name}.{service}_client",
new={service}_client,
),
):
from prowler.providers.azure.services.{service}.{check_name}.{check_name} import (
{check_name},
)
check = {check_name}()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"---
GCP/Kubernetes/Other Providers
Follow the same MagicMock pattern as Azure:
from tests.providers.gcp.gcp_fixtures import set_mocked_gcp_provider, GCP_PROJECT_ID
from tests.providers.kubernetes.kubernetes_fixtures import set_mocked_kubernetes_providerKey difference: Each provider has its own fixtures file with set_mocked_{provider}_provider.
---
Provider Fixtures Reference
| Provider | Fixtures File | Key Constants |
|---|---|---|
| AWS | tests/providers/aws/utils.py | AWS_REGION_US_EAST_1, AWS_ACCOUNT_NUMBER |
| Azure | tests/providers/azure/azure_fixtures.py | AZURE_SUBSCRIPTION_ID |
| GCP | tests/providers/gcp/gcp_fixtures.py | GCP_PROJECT_ID |
| K8s | tests/providers/kubernetes/kubernetes_fixtures.py | - |
---
Test File Structure
tests/providers/{provider}/services/{service}/
├── {service}_service_test.py # Service tests
└── {check_name}/
└── {check_name}_test.py # Check testsNOTE: Do not create a __init__.py file in the test folder.
---
Required Test Scenarios
Every check MUST test:
| Scenario | Expected |
|---|---|
| Resource compliant | status == "PASS" |
| Resource non-compliant | status == "FAIL" |
| No resources | len(results) == 0 |
---
Assertions to Include
# Always verify these
assert result[0].status == "PASS" # or "FAIL"
assert result[0].status_extended == "Expected message..."
assert result[0].resource_id == expected_id
assert result[0].resource_name == expected_name
# Provider-specific
assert result[0].region == "us-east-1" # AWS
assert result[0].subscription == AZURE_SUBSCRIPTION_ID # Azure
assert result[0].project_id == GCP_PROJECT_ID # GCP---
Commands
# All SDK tests
uv run pytest -n auto -vvv tests/
# Specific provider
uv run pytest tests/providers/{provider}/ -v
# Specific check
uv run pytest tests/providers/{provider}/services/{service}/{check_name}/ -v
# Stop on first failure
uv run pytest -x tests/Resources
- Templates: See assets/ for complete test templates (AWS with moto, Azure/GCP with MagicMock)
- Documentation: See references/testing-docs.md for official Prowler Developer Guide links
# Example: AWS KMS Key Rotation Test
# Source: tests/providers/aws/services/kms/kms_cmk_rotation_enabled/
from unittest import mock
import pytest
from boto3 import client
from moto import mock_aws
from tests.providers.aws.utils import AWS_REGION_US_EAST_1, set_mocked_aws_provider
class Test_kms_cmk_rotation_enabled:
@mock_aws
def test_kms_no_key(self):
"""Test when no KMS keys exist."""
from prowler.providers.aws.services.kms.kms_service import KMS
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
),
mock.patch(
"prowler.providers.aws.services.kms.kms_cmk_rotation_enabled.kms_cmk_rotation_enabled.kms_client",
new=KMS(aws_provider),
),
):
from prowler.providers.aws.services.kms.kms_cmk_rotation_enabled.kms_cmk_rotation_enabled import (
kms_cmk_rotation_enabled,
)
check = kms_cmk_rotation_enabled()
result = check.execute()
assert len(result) == 0
@mock_aws
def test_kms_cmk_rotation_enabled(self):
"""Test PASS: KMS key with rotation enabled."""
# Create mocked AWS resources using boto3
kms_client = client("kms", region_name=AWS_REGION_US_EAST_1)
key = kms_client.create_key()["KeyMetadata"]
kms_client.enable_key_rotation(KeyId=key["KeyId"])
from prowler.providers.aws.services.kms.kms_service import KMS
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
),
mock.patch(
"prowler.providers.aws.services.kms.kms_cmk_rotation_enabled.kms_cmk_rotation_enabled.kms_client",
new=KMS(aws_provider),
),
):
from prowler.providers.aws.services.kms.kms_cmk_rotation_enabled.kms_cmk_rotation_enabled import (
kms_cmk_rotation_enabled,
)
check = kms_cmk_rotation_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert result[0].resource_id == key["KeyId"]
assert result[0].resource_arn == key["Arn"]
@mock_aws
def test_kms_cmk_rotation_disabled(self):
"""Test FAIL: KMS key without rotation enabled."""
kms_client = client("kms", region_name=AWS_REGION_US_EAST_1)
key = kms_client.create_key()["KeyMetadata"]
# Note: rotation NOT enabled
from prowler.providers.aws.services.kms.kms_service import KMS
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
),
mock.patch(
"prowler.providers.aws.services.kms.kms_cmk_rotation_enabled.kms_cmk_rotation_enabled.kms_client",
new=KMS(aws_provider),
),
):
from prowler.providers.aws.services.kms.kms_cmk_rotation_enabled.kms_cmk_rotation_enabled import (
kms_cmk_rotation_enabled,
)
check = kms_cmk_rotation_enabled()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert result[0].resource_id == key["KeyId"]
@pytest.mark.parametrize(
"no_of_keys_created,expected_no_of_passes",
[
(5, 3),
(7, 5),
(10, 8),
],
)
@mock_aws
def test_kms_rotation_parametrized(
self, no_of_keys_created: int, expected_no_of_passes: int
) -> None:
"""Parametrized test demonstrating multiple scenarios."""
kms_client = client("kms", region_name=AWS_REGION_US_EAST_1)
for i in range(no_of_keys_created):
key = kms_client.create_key()["KeyMetadata"]
if i not in [2, 4]: # Skip enabling rotation for some keys
kms_client.enable_key_rotation(KeyId=key["KeyId"])
from prowler.providers.aws.services.kms.kms_service import KMS
aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1])
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=aws_provider,
),
mock.patch(
"prowler.providers.aws.services.kms.kms_cmk_rotation_enabled.kms_cmk_rotation_enabled.kms_client",
new=KMS(aws_provider),
),
):
from prowler.providers.aws.services.kms.kms_cmk_rotation_enabled.kms_cmk_rotation_enabled import (
kms_cmk_rotation_enabled,
)
check = kms_cmk_rotation_enabled()
result = check.execute()
assert len(result) == no_of_keys_created
statuses = [r.status for r in result]
assert statuses.count("PASS") == expected_no_of_passes
# Example: Azure Storage Network Access Rule Test
# Source: tests/providers/azure/services/storage/storage_default_network_access_rule_is_denied/
from unittest import mock
from uuid import uuid4
from prowler.providers.azure.services.storage.storage_service import (
Account,
NetworkRuleSet,
)
from tests.providers.azure.azure_fixtures import (
AZURE_SUBSCRIPTION_ID,
set_mocked_azure_provider,
)
class Test_storage_default_network_access_rule_is_denied:
def test_storage_no_storage_accounts(self):
"""Test when no storage accounts exist."""
storage_client = mock.MagicMock
storage_client.storage_accounts = {}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
),
mock.patch(
"prowler.providers.azure.services.storage.storage_default_network_access_rule_is_denied.storage_default_network_access_rule_is_denied.storage_client",
new=storage_client,
),
):
from prowler.providers.azure.services.storage.storage_default_network_access_rule_is_denied.storage_default_network_access_rule_is_denied import (
storage_default_network_access_rule_is_denied,
)
check = storage_default_network_access_rule_is_denied()
result = check.execute()
assert len(result) == 0
def test_storage_network_access_rule_allowed(self):
"""Test FAIL: Network access rule set to Allow."""
storage_account_id = str(uuid4())
storage_account_name = "Test Storage Account"
storage_client = mock.MagicMock
storage_client.storage_accounts = {
AZURE_SUBSCRIPTION_ID: [
Account(
id=storage_account_id,
name=storage_account_name,
resouce_group_name="rg",
enable_https_traffic_only=False,
infrastructure_encryption=False,
allow_blob_public_access=False,
network_rule_set=NetworkRuleSet(
bypass="AzureServices", default_action="Allow"
),
encryption_type="None",
minimum_tls_version="TLS1_2",
key_expiration_period_in_days=None,
location="westeurope",
private_endpoint_connections=[],
)
]
}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
),
mock.patch(
"prowler.providers.azure.services.storage.storage_default_network_access_rule_is_denied.storage_default_network_access_rule_is_denied.storage_client",
new=storage_client,
),
):
from prowler.providers.azure.services.storage.storage_default_network_access_rule_is_denied.storage_default_network_access_rule_is_denied import (
storage_default_network_access_rule_is_denied,
)
check = storage_default_network_access_rule_is_denied()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
assert result[0].resource_name == storage_account_name
assert result[0].resource_id == storage_account_id
assert result[0].location == "westeurope"
def test_storage_network_access_rule_denied(self):
"""Test PASS: Network access rule set to Deny."""
storage_account_id = str(uuid4())
storage_account_name = "Test Storage Account"
storage_client = mock.MagicMock
storage_client.storage_accounts = {
AZURE_SUBSCRIPTION_ID: [
Account(
id=storage_account_id,
name=storage_account_name,
resouce_group_name="rg",
enable_https_traffic_only=False,
infrastructure_encryption=False,
allow_blob_public_access=False,
network_rule_set=NetworkRuleSet(
default_action="Deny", bypass="AzureServices"
),
encryption_type="None",
minimum_tls_version="TLS1_2",
key_expiration_period_in_days=None,
location="westeurope",
private_endpoint_connections=[],
)
]
}
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_azure_provider(),
),
mock.patch(
"prowler.providers.azure.services.storage.storage_default_network_access_rule_is_denied.storage_default_network_access_rule_is_denied.storage_client",
new=storage_client,
),
):
from prowler.providers.azure.services.storage.storage_default_network_access_rule_is_denied.storage_default_network_access_rule_is_denied import (
storage_default_network_access_rule_is_denied,
)
check = storage_default_network_access_rule_is_denied()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert result[0].subscription == AZURE_SUBSCRIPTION_ID
assert result[0].resource_name == storage_account_name
# Example: GCP Cloud Storage Bucket Public Access Test
# Source: tests/providers/gcp/services/cloudstorage/cloudstorage_bucket_public_access/
from unittest import mock
from tests.providers.gcp.gcp_fixtures import (
GCP_PROJECT_ID,
GCP_US_CENTER1_LOCATION,
set_mocked_gcp_provider,
)
class TestCloudStorageBucketPublicAccess:
def test_bucket_public_access(self):
"""Test FAIL: Bucket is publicly accessible."""
cloudstorage_client = mock.MagicMock()
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_gcp_provider(),
),
mock.patch(
"prowler.providers.gcp.services.cloudstorage.cloudstorage_bucket_public_access.cloudstorage_bucket_public_access.cloudstorage_client",
new=cloudstorage_client,
),
):
from prowler.providers.gcp.services.cloudstorage.cloudstorage_bucket_public_access.cloudstorage_bucket_public_access import (
cloudstorage_bucket_public_access,
)
from prowler.providers.gcp.services.cloudstorage.cloudstorage_service import (
Bucket,
)
cloudstorage_client.project_ids = [GCP_PROJECT_ID]
cloudstorage_client.region = GCP_US_CENTER1_LOCATION
cloudstorage_client.buckets = [
Bucket(
name="example-bucket",
id="example-bucket",
region=GCP_US_CENTER1_LOCATION,
uniform_bucket_level_access=True,
public=True,
project_id=GCP_PROJECT_ID,
)
]
check = cloudstorage_bucket_public_access()
result = check.execute()
assert len(result) == 1
assert result[0].status == "FAIL"
assert result[0].resource_id == "example-bucket"
assert result[0].resource_name == "example-bucket"
assert result[0].location == GCP_US_CENTER1_LOCATION
assert result[0].project_id == GCP_PROJECT_ID
def test_bucket_no_public_access(self):
"""Test PASS: Bucket is not publicly accessible."""
cloudstorage_client = mock.MagicMock()
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_gcp_provider(),
),
mock.patch(
"prowler.providers.gcp.services.cloudstorage.cloudstorage_bucket_public_access.cloudstorage_bucket_public_access.cloudstorage_client",
new=cloudstorage_client,
),
):
from prowler.providers.gcp.services.cloudstorage.cloudstorage_bucket_public_access.cloudstorage_bucket_public_access import (
cloudstorage_bucket_public_access,
)
from prowler.providers.gcp.services.cloudstorage.cloudstorage_service import (
Bucket,
)
cloudstorage_client.project_ids = [GCP_PROJECT_ID]
cloudstorage_client.region = GCP_US_CENTER1_LOCATION
cloudstorage_client.buckets = [
Bucket(
name="example-bucket",
id="example-bucket",
region=GCP_US_CENTER1_LOCATION,
uniform_bucket_level_access=True,
public=False,
project_id=GCP_PROJECT_ID,
)
]
check = cloudstorage_bucket_public_access()
result = check.execute()
assert len(result) == 1
assert result[0].status == "PASS"
assert result[0].resource_id == "example-bucket"
def test_no_buckets(self):
"""Test when no buckets exist."""
cloudstorage_client = mock.MagicMock()
with (
mock.patch(
"prowler.providers.common.provider.Provider.get_global_provider",
return_value=set_mocked_gcp_provider(),
),
mock.patch(
"prowler.providers.gcp.services.cloudstorage.cloudstorage_bucket_public_access.cloudstorage_bucket_public_access.cloudstorage_client",
new=cloudstorage_client,
),
):
from prowler.providers.gcp.services.cloudstorage.cloudstorage_bucket_public_access.cloudstorage_bucket_public_access import (
cloudstorage_bucket_public_access,
)
cloudstorage_client.project_ids = [GCP_PROJECT_ID]
cloudstorage_client.region = GCP_US_CENTER1_LOCATION
cloudstorage_client.buckets = []
check = cloudstorage_bucket_public_access()
result = check.execute()
assert len(result) == 0
SDK Testing Documentation
Local Documentation
For detailed SDK testing patterns, see:
docs/developer-guide/unit-testing.mdx- Complete guide for writing check tests
Contents
The documentation covers:
- AWS testing with moto (
@mock_awsdecorator) - Azure testing with MagicMock
- GCP testing with MagicMock
- Provider-specific fixtures (
set_mocked_aws_provider, etc.) - Service dependency table for CI optimization
- Test structure and required scenarios