mcpField
P
prowler-test-api

prowler-test-api

github.com/prowler-cloudTesting & quality15.1k68 installsUpdated today
Repository

About prowler-test-api

prowler-test-api is a testing skill for contributors working on Prowler API endpoints and tasks. It provides conventions for JSON:API requests, tenant isolation, fixtures, and Celery tests.

Key features

  1. 01JSON:API request and response patterns
  2. 02Tenant-isolation test guidance
  3. 03Reusable fixture reference
  4. 04Celery task testing strategies
  5. 05API test commands

Use cases

  1. 01Testing API endpoint changes
  2. 02Verifying cross-tenant access isolation
  3. 03Testing asynchronous views and Celery tasks

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/prowler-cloud/prowler --skill prowler-test-api

After installing, type/prowler-test-apiin Claude Code to confirm it loaded.

Bundled filesassets/api_test.pyreferences/test-api-docs.md

Details

From the project README

Critical Rules

  • ALWAYS use response.json()["data"] not response.data
  • ALWAYS use content_type = "application/vnd.api+json" for PATCH/PUT requests
  • ALWAYS use format="vnd.api+json" for POST requests
  • ALWAYS test cross-tenant isolation - RLS returns 404, NOT 403
  • NEVER skip RLS isolation tests when adding new endpoints
  • NEVER use realistic-looking API keys in tests (TruffleHog will flag them)
  • ALWAYS mock BOTH .delay() AND Task.objects.get for async task tests

1. Fixture Dependency Chain

create_test_user (session) ─► tenants_fixture (function) ─► authenticated_client
                                     │
                                     └─► aws_provider ─► scans_fixture ─► findings_fixture
Key Fixtures
FixtureDescription
create_test_userSession user ([email protected])
tenants_fixture3 tenants: [0],[1] have membership, [2] isolated
authenticated_clientDjango test client with JWT for tenant[0]
authenticated_client_for_tenant_factoryCreates a Django test client with JWT for a specific user and tenant
provider_factoryCreates one validated provider with provider-specific defaults
aws_provider1 AWS provider in tenant[0]
aws_provider_pair2 AWS providers in tenant[0]
all_provider_types_fixture1 provider for every supported provider type
tasks_fixture2 Celery tasks with TaskResult
RBAC Fixtures
FixturePermissions
authenticated_client_rbacAll permissions (admin)
authenticated_client_rbac_norolesMembership but NO roles
authenticated_client_no_permissions_rbacAll permissions = False

Use authenticated_client for normal view behavior tests. It uses a cheap JWT and still runs the real request authentication path. Use serializer-generated JWTs or API-key clients only when the test is specifically about token obtain/refresh, invalid tokens, expired tokens, tenant switching by token, API keys, or unauthenticated 401 behavior. Use authenticated_client_for_tenant_factory when a test needs a cheap JWT client for a different user or tenant.


2. JSON:API Requests

POST (Create)
response = client.post(
    reverse("provider-list"),
    data={"data": {"type": "providers", "attributes": {...}}},
    format="vnd.api+json",  # NOT content_type!
)
PATCH (Update)
response = client.patch(
    reverse("provider-detail", kwargs={"pk": provider.id}),
    data={"data": {"type": "providers", "id": str(provider.id), "attributes": {...}}},
    content_type="application/vnd.api+json",  # NOT format!
)
Reading Responses
data = response.json()["data"]
attrs = data["attributes"]
errors = response.json()["errors"]  # For 400 responses

3. RLS Isolation (Cross-Tenant)

RLS returns 404, NOT 403 - the resource is invisible, not forbidden.

def test_cross_tenant_access_denied(self, authenticated_client, tenants_fixture):
    other_tenant = tenants_fixture[2]  # Isolated tenant
    foreign_provider = Provider.objects.create(tenant_id=other_tenant.id, ...)

    response = authenticated_client.get(reverse("provider-detail", args=[foreign_provider.id]))
    assert response.status_code == status.HTTP_404_NOT_FOUND  # NOT 403!

4. Celery Task Testing

Testing Strategies
StrategyUse For
Mock .delay() + Task.objects.getTesting views that trigger tasks
task.apply()Synchronous task logic testing
Mock chain/groupTesting Canvas orchestration
Mock connectionTesting @set_tenant decorator
Mock apply_asyncTesting Beat scheduled tasks
Why NOT task_always_eager
ProblemImpact
No task serializationMisses argument type errors
No broker interactionHides connection issues
Different execution contextself.request behaves differently

Instead, use: task.apply() for sync execution, mocking for isolation.

Full examples: See assets/api_test.py for TestCeleryTaskLogic, TestCeleryCanvas, TestSetTenantDecorator, TestBeatScheduling.


5. Fake Secrets (TruffleHog)

# BAD - TruffleHog flags these:
api_key = "sk-test1234567890T3BlbkFJtest1234567890"

# GOOD - obviously fake:
api_key = "sk-fake-test-key-for-unit-testing-only"

6. Response Status Codes

ScenarioCode
Successful GET200
Successful POST201
Async operation (DELETE/scan trigger)202
Sync DELETE204
Validation error400
Missing permission (RBAC)403
RLS isolation / not found404

Commands

cd api && uv run pytest -x --tb=short
cd api && uv run pytest -k "test_provider"
cd api && uv run pytest api/src/backend/api/tests/test_rbac.py

Resources

Comments

Markdown supported