원클릭으로
prowler-test-api
Testing patterns for Prowler API: JSON:API, Celery tasks, RLS isolation, RBAC. Trigger: When writing tests for api/ (JSON:API requests/assertions, cross-tenant isolation, RBAC, Celery tasks, viewsets/serializers).
메뉴
Testing patterns for Prowler API: JSON:API, Celery tasks, RLS isolation, RBAC. Trigger: When writing tests for api/ (JSON:API requests/assertions, cross-tenant isolation, RBAC, Celery tasks, viewsets/serializers).
SOC 직업 분류 기준
Keeps product-tour definitions aligned with the UI features they describe. Trigger: When modifying UI components that have associated tours, editing tour definition files, or renaming data-tour-id attributes.
Django REST Framework patterns. Trigger: When implementing generic DRF APIs (ViewSets, serializers, routers, permissions, filtersets). For Prowler API specifics (RLS/RBAC/Providers), also use prowler-api.
Reviews Django migration files for PostgreSQL best practices specific to Prowler. Trigger: When creating migrations, running makemigrations/pgmakemigrations, reviewing migration PRs, adding indexes or constraints to database tables, modifying existing migration files, or writing data backfill migrations. Always use this skill when you see AddIndex, CreateModel, AddConstraint, RunPython, bulk_create, bulk_update, or backfill operations in migration files.
Create and maintain GitHub Agentic Workflows (gh-aw) for Prowler. Trigger: When creating agentic workflows, modifying gh-aw frontmatter, configuring safe-outputs, setting up MCP servers in workflows, importing Copilot Custom Agents, or debugging gh-aw compilation.
Strict JSON:API v1.1 specification compliance. Trigger: When creating or modifying API endpoints, reviewing API responses, or validating JSON:API compliance.
Next.js 16 App Router patterns. Trigger: When working in Next.js App Router (app/), Server Components vs Client Components, Server Actions, Route Handlers, proxy.ts, caching/revalidation, Cache Components, and streaming/Suspense.
| name | prowler-test-api |
| description | Testing patterns for Prowler API: JSON:API, Celery tasks, RLS isolation, RBAC. Trigger: When writing tests for api/ (JSON:API requests/assertions, cross-tenant isolation, RBAC, Celery tasks, viewsets/serializers). |
| license | Apache-2.0 |
| metadata | {"author":"prowler-cloud","version":"1.1.0","scope":["root","api"],"auto_invoke":["Writing Prowler API tests","Testing RLS tenant isolation"]} |
| allowed-tools | Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task |
response.json()["data"] not response.datacontent_type = "application/vnd.api+json" for PATCH/PUT requestsformat="vnd.api+json" for POST requests.delay() AND Task.objects.get for async task testscreate_test_user (session) ─► tenants_fixture (function) ─► authenticated_client
│
└─► providers_fixture ─► scans_fixture ─► findings_fixture
| Fixture | Description |
|---|---|
create_test_user | Session user (dev@prowler.com) |
tenants_fixture | 3 tenants: [0],[1] have membership, [2] isolated |
authenticated_client | JWT client for tenant[0] |
providers_fixture | 9 providers in tenant[0] |
tasks_fixture | 2 Celery tasks with TaskResult |
| Fixture | Permissions |
|---|---|
authenticated_client_rbac | All permissions (admin) |
authenticated_client_rbac_noroles | Membership but NO roles |
authenticated_client_no_permissions_rbac | All permissions = False |
response = client.post(
reverse("provider-list"),
data={"data": {"type": "providers", "attributes": {...}}},
format="vnd.api+json", # NOT content_type!
)
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!
)
data = response.json()["data"]
attrs = data["attributes"]
errors = response.json()["errors"] # For 400 responses
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!
| Strategy | Use For |
|---|---|
Mock .delay() + Task.objects.get | Testing views that trigger tasks |
task.apply() | Synchronous task logic testing |
Mock chain/group | Testing Canvas orchestration |
Mock connection | Testing @set_tenant decorator |
Mock apply_async | Testing Beat scheduled tasks |
task_always_eager| Problem | Impact |
|---|---|
| No task serialization | Misses argument type errors |
| No broker interaction | Hides connection issues |
| Different execution context | self.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.
# BAD - TruffleHog flags these:
api_key = "sk-test1234567890T3BlbkFJtest1234567890"
# GOOD - obviously fake:
api_key = "sk-fake-test-key-for-unit-testing-only"
| Scenario | Code |
|---|---|
| Successful GET | 200 |
| Successful POST | 201 |
| Async operation (DELETE/scan trigger) | 202 |
| Sync DELETE | 204 |
| Validation error | 400 |
| Missing permission (RBAC) | 403 |
| RLS isolation / not found | 404 |
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
api/src/backend/conftest.py