Skip to content
Security
Skill

/prowler-test-sdk

Testing patterns for the Prowler SDK (Python): checks, services, fixers and providers. Trigger: When writing or fixing tests for the Prowler SDK (checks/services/fixers/providers under tests/), including AWS mocking with moto or botocore and MagicMock-based mocking for the other

From plugin
prowler
15k39 skills1 MCP

Claude Code

$ npx -y skills add prowler-cloud/prowler --skill prowler-test-sdk --agent claude-code

SKILL.md

prowler-test-sdk.SKILL.md
name: prowler-test-sdk
description: >
  Testing patterns for the Prowler SDK (Python): checks, services, fixers and providers.
  Trigger: When writing or fixing tests for the Prowler SDK (checks/services/fixers/providers under tests/), including AWS mocking with moto or botocore and MagicMock-based mocking for the other providers.
license: Apache-2.0
metadata:
  author: prowler-cloud
  version: "1.1"
  scope: [root, sdk]
  auto_invoke:
    - "Writing Prowler SDK tests"
    - "Mocking AWS with moto in tests"
allowed-tools: Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task

> **Generic Patterns**: For base pytest patterns (fixtures, mocking, parametrize), see the `pytest` skill. > This skill covers **Prowler-specific** conventions only. Full guide: `docs/developer-guide/unit-testing.mdx`.

Mocking Approach by Provider

| Provider | Approach | |----------|----------| | AWS, API covered by moto | `@mock_aws`, create real resources with `boto3.client(...)`, instantiate the real service class | | AWS, API not or partially covered by moto | Patch `botocore.client.BaseClient._make_api_call` (wrap responses with `mocked_api_response`), or inject a `MagicMock` service client in check tests | | Every other provider | `MagicMock()` service client with Pydantic models from `{service}_service.py` |

**Never use moto for non-AWS providers.** For AWS, prefer moto and fall back to botocore/MagicMock only when moto lacks the API (check moto's `IMPLEMENTATION_COVERAGE.md`).

Critical Rules

  • Import the check **inside** the `mock.patch` context, otherwise the real `{service}_client` singleton is built at import time.
  • Patch `prowler.providers.common.provider.Provider.get_global_provider` and the client **where the check imports it**: `prowler.providers.{provider}.services.{service}.{check_name}.{check_name}.{service}_client`.
  • Prefer `mock.MagicMock()` (an instance). Older tests assign attributes on the class (`client = mock.MagicMock`); `tests/conftest.py` resets those after every test, but new tests should use instances.
  • Tests run in random order (`pytest-randomly`) and in parallel (`-n auto`): no shared state between tests.
  • Test file basenames must be unique across `tests/` (no `__init__.py`; the `SDK: Check Duplicate Test Names` workflow fails on duplicates). Prefix with the provider if needed: `stackit_objectstorage_service_test.py`.
  • Do not create `__init__.py` files in test folders.

AWS Check Test (moto)

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_s3_bucket_object_versioning:
    @mock_aws
    def test_bucket_no_versioning(self):
        s3 = client("s3", region_name=AWS_REGION_US_EAST_1)
        s3.create_bucket(Bucket="bucket-test")

        from prowler.providers.aws.services.s3.s3_service import S3

        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.s3.s3_bucket_object_versioning.s3_bucket_object_versioning.s3_client",
                new=S3(aws_provider),
            ),
        ):
            from prowler.providers.aws.services.s3.s3_bucket_object_versioning.s3_bucket_object_versioning import (
                s3_bucket_object_versioning,
            )

            result = s3_bucket_object_versioning().execute()

            assert len(result) == 1
            assert result[0].status == "FAIL"
            assert result[0].status_extended == "S3 Bucket bucket-test has versioning disabled."
            assert result[0].resource_id == "bucket-test"
            assert result[0].region == AWS_REGION_US_EAST_1

`set_mocked_aws_provider()` (`tests/providers/aws/utils.py`) takes `audited_regions` (a list, never `None`), `audit_config={...}` for configurable checks, `fixer_config`, `scan_unused_services`, `expected_checks`, and more; read its signature.

AWS: API Not Covered by moto

import botocore
from unittest.mock import patch

from tests.providers.aws.utils import mocked_api_response

orig = botocore.client.BaseClient._make_api_call


def mock_make_api_call(self, operation_name, api_params):
    if operation_name == "DescribeOrganizationConfiguration":
        # mocked_api_response fails the test if the dict does not match the real API output shape
        return mocked_api_response(
            "guardduty", operation_name, {"AutoEnableOrganizationMembers": "ALL", "MemberAccountLimitReached": False}
        )
    return orig(self, operation_name, api_params)


@patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call)
@mock_aws
def test_...(self): ...

Other Providers (MagicMock)

from unittest import mock

from prowler.providers.azure.services.storage.storage_service import Account
from tests.providers.azure.azure_fixtures import (
    AZURE_SUBSCRIPTION_ID,
    AZURE_SUBSCRIPTION_NAME,
    set_mocked_azure_provider,
)


def test_no_storage_accounts():
    storage_client = mock.MagicMock()
    storage_client.storage_accounts = {}
    storage_client.subscriptions = {AZURE_SUBSCRIPTION_ID: AZURE_SUBSCRIPTION_NAME}

    with (
        mock.patch(
            "prowler.providers.common.provider.Provider.get_global_provider",
            return_value=set_mocked_azure_provider(),
        ),
        mock.patch(
            "prowler.providers.azure.services.storage.{check_name}.{check_name}.storage_client",
            new=storage_client,
        ),
    ):
        from prowler.providers.azure.services.storage.{check_name}.{check_name} import {check_name}

        assert len({check_name}().execute()) == 0

Set **every** attribute the check reads on the mock (e.g. Azure checks read `storage_client.subscriptio

Read more
@prowler-cloud
Ships withprowler

Prowler is the world’s most widely used Open-Source Cloud Security Platform that automates security and compliance across any cloud environment.

15k39 skills1 MCP
Get the whole plugin

Stars on GitHub

Momentum

stars in total
15.2k
Star history of prowler-cloud/prowler on GitHub, a chart by star-history.com

Other skills on prowler.

ai-sdk-5

ai-sdk-5

Vercel AI SDK patterns for the installed major (ui/package.json: `ai` 6.x, `@ai-sdk/react` 3.x). The skill name is historical;…

django-drf

django-drf

Django REST Framework patterns. Trigger: When implementing generic DRF APIs (ViewSets, serializers, routers, permissions,…

gh-aw

gh-aw

Create and maintain GitHub Agentic Workflows (gh-aw) for Prowler. Trigger: When creating agentic workflows, modifying gh-aw…

jsonapi

jsonapi

Strict JSON:API v1.1 specification compliance. Trigger: When creating or modifying API endpoints, reviewing API responses, or…

More skills from other plugins.

api-security

api-security

Use for authorized security assessment of REST, GraphQL, WebSocket, or SOAP APIs, including discovery, authentication,…

@zhaoxuya520@zhaoxuya520Install Skill
nemoclaw-user-guide

nemoclaw-user-guide

Find official NemoClaw documentation for installation, configuration, operation, or troubleshooting. Also handles requested docs…

nemoclaw10d23k
@nvidia@nvidiaInstall Skill

Questions about prowler-test-sdk.

Which coding agents can use prowler-test-sdk?
prowler-test-sdk installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.