mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-01-25 02:08:11 +00:00
Co-authored-by: Rubén De la Torre Vico <ruben@prowler.com> Co-authored-by: Adrián Jesús Peña Rodríguez <adrianjpr@gmail.com> Co-authored-by: Pepe Fagoaga <pepe@prowler.com>
3.2 KiB
3.2 KiB
name, description, license, metadata, allowed-tools
| name | description | license | metadata | allowed-tools | ||||
|---|---|---|---|---|---|---|---|---|
| prowler-test-api | Testing patterns for Prowler API: ViewSets, Celery tasks, RLS isolation, RBAC. Trigger: When writing tests for api/ - viewsets, serializers, tasks, models. | Apache-2.0 |
|
Read, Edit, Write, Glob, Grep, Bash, WebFetch, WebSearch, Task |
Critical Rules
- ALWAYS use
response.json()["data"]notresponse.data - ALWAYS use
content_type = "application/vnd.api+json"in requests - ALWAYS test cross-tenant isolation with
other_tenant_providerfixture - NEVER skip RLS isolation tests when adding new endpoints
1. JSON:API Format (Critical)
content_type = "application/vnd.api+json"
payload = {
"data": {
"type": "providers", # Plural, kebab-case
"id": str(resource.id), # Required for PATCH
"attributes": {"alias": "updated"},
}
}
response.json()["data"]["attributes"]["alias"]
2. RLS Isolation Tests
def test_cross_tenant_access_denied(self, authenticated_client, other_tenant_provider):
"""User cannot see resources from other tenants."""
response = authenticated_client.get(
reverse("provider-detail", args=[other_tenant_provider.id])
)
assert response.status_code == status.HTTP_404_NOT_FOUND
3. RBAC Tests
def test_unlimited_visibility_sees_all(self, authenticated_client_admin, providers_fixture):
response = authenticated_client_admin.get(reverse("provider-list"))
assert len(response.json()["data"]) == len(providers_fixture)
def test_limited_visibility_sees_only_assigned(self, authenticated_client_limited):
# User with unlimited_visibility=False sees only providers in their provider_groups
pass
def test_permission_required(self, authenticated_client_readonly):
response = authenticated_client_readonly.post(reverse("provider-list"), ...)
assert response.status_code == status.HTTP_403_FORBIDDEN
4. Managers (objects vs all_objects)
def test_objects_excludes_deleted(self):
deleted_provider = Provider.objects.create(..., is_deleted=True)
assert deleted_provider not in Provider.objects.all()
assert deleted_provider in Provider.all_objects.all()
5. Celery Task Tests
@patch("tasks.tasks.perform_prowler_scan")
def test_task_success(self, mock_scan):
mock_scan.return_value = {"findings_count": 100}
result = perform_scan_task(tenant_id="...", scan_id="...", provider_id="...")
assert result["findings_count"] == 100
6. Key Fixtures
| Fixture | Description |
|---|---|
create_test_user |
Session user (dev@prowler.com) |
tenants_fixture |
3 tenants (2 with membership, 1 isolated) |
providers_fixture |
Providers in tenant 1 |
other_tenant_provider |
Provider in isolated tenant (RLS tests) |
authenticated_client |
Client with JWT for tenant 1 |
Commands
cd api && poetry run pytest -x --tb=short
cd api && poetry run pytest -k "test_provider"
cd api && poetry run pytest -k "TestRBAC"
Resources
- Documentation: See references/test-api-docs.md for local file paths and documentation