Skip to content

feat(api): add provider group filters#11573

Merged
jfagoagas merged 10 commits into
masterfrom
implement-provider-groups-filter
Jun 16, 2026
Merged

feat(api): add provider group filters#11573
jfagoagas merged 10 commits into
masterfrom
implement-provider-groups-filter

Conversation

@AdriiiPRodri

@AdriiiPRodri AdriiiPRodri commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Context

Provider group filtering should be available wherever API consumers can already filter cloud-scoped data by provider type, so provider group based workflows can query the same API surfaces without expanding groups client-side.

Description

This PR adds provider_groups and provider_groups__in filters across the API filtersets and overview paths that already support cloud provider filtering.

The change covers exact provider group matching, comma-separated __in matching, distinct result handling for providers that belong to multiple groups, and OpenAPI filter documentation for the affected routes. Lighthouse endpoints are intentionally excluded because their provider_type parameter refers to LLM providers such as openai and bedrock, not Prowler cloud providers.

The API changelog includes the new provider group filters entry for this PR.

Steps to review

  1. Review api/src/backend/api/filters.py and confirm provider_groups / provider_groups__in are added alongside cloud provider type filters.
  2. Review api/src/backend/api/v1/views.py and confirm overview/manual filter handling includes provider groups, including overviews/threatscore query parameters.
  3. Review api/src/backend/api/tests/test_views.py for exact and __in coverage across providers, scans, resources, findings, finding groups, and overviews.
  4. Run uv run pytest src/backend/api/tests/test_views.py -k provider_groups -q from api/.
  5. Run uv run ruff check src/backend/api/filters.py src/backend/api/tests/test_views.py src/backend/api/v1/views.py from api/.
  6. Optionally run the local E2E helper in local_scripts/provider_groups_filter_e2e.py against the dev API to recreate provider groups and compare provider group filters against equivalent provider ID filters.

Checklist

Community Checklist
  • This feature/issue is listed in here or roadmap.prowler.com
  • Is it assigned to me, if not, request it via the issue/feature in here or Prowler Community Slack

SDK/CLI

  • Are there new checks included in this PR? No
    • If so, do we need to update permissions for the provider? No

UI

  • All issue/task requirements work as expected on the UI
  • If this PR adds or updates npm dependencies, include package-health evidence (maintenance, popularity, known vulnerabilities, license, release age) and explain why existing/native alternatives are insufficient.
  • Screenshots/Video of the functionality flow (if applicable) - Mobile (X < 640px)
  • Screenshots/Video of the functionality flow (if applicable) - Table (640px > X < 1024px)
  • Screenshots/Video of the functionality flow (if applicable) - Desktop (X > 1024px)
  • Ensure new entries are added to CHANGELOG.md, if applicable.

API

  • All issue/task requirements work as expected on the API
  • Endpoint response output (if applicable)
  • EXPLAIN ANALYZE output for new/modified queries or indexes (if applicable)
  • Performance test results (if applicable)
  • Any other relevant evidence of the implementation (if applicable)
  • Verify if API specs need to be regenerated.
  • Check if version updates are required (e.g., specs, uv, etc.).
  • Ensure new entries are added to CHANGELOG.md, if applicable.

License

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added provider-group filtering to API endpoints covering providers, scans, resources, findings, overview results, and finding-group list/latest.
    • Supports exact-match (filter[provider_groups]) and multi-value (filter[provider_groups__in]), aggregating using the latest completed scans per matching provider.
  • Documentation

    • Updated the 1.32.0 (unreleased) changelog and API schemas for the new provider-group filters, including compliance overview list, metadata, and requirements.
    • Improved compliance overview behavior so provider-filtered requests no longer require filter[scan_id].
  • Tests

    • Expanded automated coverage across the affected endpoints, including latest/aggregated behavior.

- Add provider group filters alongside provider type filters

- Support exact and comma-separated provider group filtering

- Cover provider group filtering across API views and overviews
@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR extends the Prowler API to support filtering by provider groups across multiple endpoints. FilterSet classes are updated with provider_groups and provider_groups__in fields; filtering mixins provide JSON:API and provider-filter parsing; view logic branches to latest-scan queries when provider filters are supplied; and comprehensive test coverage validates filtering behavior across all affected endpoints.

Changes

Provider Group Filtering Support

Layer / File(s) Summary
Provider-group filter fields across FilterSet classes
api/CHANGELOG.md, api/src/backend/api/filters.py
Adds provider_groups and provider_groups__in filter fields to 12 FilterSet classes, mapping to provider-group UUID relationships via ORM traversals with distinct=True. Refactors ComplianceOverviewFilter to inherit from BaseScanProviderFilter and removes the required=True constraint on scan_id. Updates filter docstrings and changelog documenting the new filtering capability.
Filtering mixins for JSON:API and provider-filter parsing
api/src/backend/api/v1/mixins.py
Introduces JsonApiFilterMixin to normalize JSON:API-style filter query parameters and apply validation. Introduces ProviderFilterParamsMixin to extract and parse provider-related filters from request parameters, supporting direct and __in variants plus optional dot-alias keys, with UUID and provider-type validation. Updated imports to include DRF ValidationError.
View class updates for provider-group filter support
api/src/backend/api/v1/views.py (class definitions and schemas)
ComplianceOverviewViewSet inherits ProviderFilterParamsMixin; OpenAPI schemas for list, metadata, and requirements document filter[scan_id] as optional when provider filters supplied. OverviewViewSet inherits ProviderFilterParamsMixin and threatscore schema documents provider-group filters; categories and resource_groups extend provider-filter key exclusions. FindingGroupViewSet inherits JsonApiFilterMixin with dot replacement enabled and latest schema clarifies provider-group filter support.
View runtime logic for latest-scan and provider-filter queries
api/src/backend/api/v1/views.py (implementation methods)
ComplianceOverviewViewSet.get_queryset applies RBAC-aware provider visibility filtering. New helpers validate scan-vs-provider-filter selection and compute latest-completed-scan IDs per provider filter. The list, metadata, and requirements actions branch to latest-provider-scan queries when provider filters are present, preserving region-aware and async-backfill behavior. OverviewViewSet refactored to use mixin-based provider-filter parsing and initialization.
Comprehensive test coverage for provider-group filtering
api/src/backend/api/tests/test_views.py
Adds test helpers to generate completed scans and compliance data. Adds test methods across 8 endpoint viewsets validating filter[provider_groups] and filter[provider_groups__in] behavior for provider, scan, resource, finding, overview-findings, compliance-watchlist, and finding-group endpoints. Extends parameterized filter tests for overview categories and resource-groups with provider-group cases. Compliance-overview tests verify latest-scan selection and aggregation for multiple provider-filter variants. Updates various assertions with clearer failure messages.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • alejandrobailo
  • josema-xyz
  • pedrooot
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.73% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main change: adding provider group filters to the API. It is specific, clear, and reflects the primary objective of the changeset.
Description check ✅ Passed The description follows the template with all major sections completed: Context, Description, Steps to review, Checklist with API subsection, and License. The author provides clear motivation, implementation details, review steps, and checklist confirmation of requirements.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch implement-provider-groups-filter

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Conflict Markers Resolved

All conflict markers have been successfully resolved in this pull request.

@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

✅ All necessary CHANGELOG.md files have been updated.

@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

🔒 Container Security Scan

Image: prowler-api:00e67d5
Last scan: 2026-06-16 09:41:46 UTC

✅ No Vulnerabilities Detected

The container image passed all security checks. No known CVEs were found.

📋 Resources:

@AdriiiPRodri AdriiiPRodri marked this pull request as ready for review June 12, 2026 17:14
@AdriiiPRodri AdriiiPRodri requested a review from a team as a code owner June 12, 2026 17:14

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
api/src/backend/api/tests/test_views.py (1)

1414-18238: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Run ruff formatter to fix code style.

The pipeline indicates this file needs reformatting.

Run the following command to fix:

uv run ruff format src/backend/api/tests/test_views.py
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/src/backend/api/tests/test_views.py` around lines 1414 - 18238, Summary:
The test file src/backend/api/tests/test_views.py is not formatted to project
style (ruff) causing CI failures. Fix: run the project formatter (ruff) over the
file and commit the changes; e.g. execute the ruff format command the reviewer
suggested to automatically reformat the whole file including tests like
test_providers_filter_provider_groups, TestProviderGroupViewSet, and other
test_* functions; verify no functional changes and then add/commit the formatted
file and push. Ensure you run the same command in CI/pre-commit locally (uv run
ruff format src/backend/api/tests/test_views.py) so lint/format passes.

Source: Pipeline failures

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@api/src/backend/api/tests/test_views.py`:
- Around line 1414-18238: Summary: The test file
src/backend/api/tests/test_views.py is not formatted to project style (ruff)
causing CI failures. Fix: run the project formatter (ruff) over the file and
commit the changes; e.g. execute the ruff format command the reviewer suggested
to automatically reformat the whole file including tests like
test_providers_filter_provider_groups, TestProviderGroupViewSet, and other
test_* functions; verify no functional changes and then add/commit the formatted
file and push. Ensure you run the same command in CI/pre-commit locally (uv run
ruff format src/backend/api/tests/test_views.py) so lint/format passes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 43caf620-81dd-49e3-a170-f580de34e505

📥 Commits

Reviewing files that changed from the base of the PR and between dc3433a and 9e5df42.

📒 Files selected for processing (4)
  • api/CHANGELOG.md
  • api/src/backend/api/filters.py
  • api/src/backend/api/tests/test_views.py
  • api/src/backend/api/v1/views.py

@codecov

codecov Bot commented Jun 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.94501% with 15 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.11%. Comparing base (36fe48d) to head (19b1db4).
⚠️ Report is 13 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master   #11573      +/-   ##
==========================================
+ Coverage   94.02%   94.11%   +0.08%     
==========================================
  Files         241      247       +6     
  Lines       35705    36352     +647     
==========================================
+ Hits        33573    34212     +639     
- Misses       2132     2140       +8     
Flag Coverage Δ
api 94.11% <96.94%> (+0.08%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
prowler ∅ <ø> (∅)
api 94.11% <96.78%> (+0.08%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 15, 2026
josema-xyz
josema-xyz previously approved these changes Jun 15, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jun 15, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
api/src/backend/api/v1/views.py (1)

5857-5866: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Document provider-group filters with JSON:API parameter names.

These new filters are exposed as top-level provider_groups params in the schema. Document the canonical JSON:API shape so generated clients send filter[provider_groups] / filter[provider_groups__in].

📝 Proposed schema fix
             OpenApiParameter(
-                name="provider_groups",
+                name="filter[provider_groups]",
                 type=OpenApiTypes.UUID,
                 location=OpenApiParameter.QUERY,
                 description="Filter by provider group ID",
             ),
             OpenApiParameter(
-                name="provider_groups__in",
+                name="filter[provider_groups__in]",
                 type=OpenApiTypes.STR,
                 location=OpenApiParameter.QUERY,
                 description="Filter by multiple provider group IDs (comma-separated UUIDs)",
             ),

As per coding guidelines, "Use JSON:API filtering with ?filter[field]=value and ?filter[field__in]=val1,val2 query parameters."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/src/backend/api/v1/views.py` around lines 5857 - 5866, The descriptions
for the OpenApiParameter definitions named "provider_groups" and
"provider_groups__in" do not document the canonical JSON:API query parameter
format that clients should use. Update the description fields for both
parameters to explicitly document the JSON:API filter syntax: clarify that
"provider_groups" should be sent as `filter[provider_groups]=value` and
"provider_groups__in" should be sent as
`filter[provider_groups__in]=value1,value2` so that generated clients follow the
JSON:API filtering convention.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@api/src/backend/api/tests/test_views.py`:
- Line 9777: Remove the redundant invariant assertion checks that verify
test-setup constraints rather than API behavior. In the test code at line 9777,
remove the assertion that verifies latest_scan1.provider_id == provider1.id, and
at line 9787, remove the corresponding assertion that verifies
latest_scan2.provider_id == provider2.id. These checks are redundant because the
subsequent assertions validating the requirements_passed and requirements_failed
counts are sufficient to validate the filter logic and expected API behavior,
while the provider_id assertions merely confirm that the test fixtures were set
up correctly.
- Around line 9448-9462: The failed_checks assignment in the _create_requirement
helper currently only excludes StatusChoices.PASS from setting failed_checks=1,
but production code and existing test fixtures show that StatusChoices.MANUAL
requirements should also have failed_checks=0. Update the condition on the
failed_checks line to include both StatusChoices.PASS and StatusChoices.MANUAL
in the tuple check: change from `failed_checks=0 if status_choice ==
StatusChoices.PASS else 1` to `failed_checks=0 if status_choice in
(StatusChoices.PASS, StatusChoices.MANUAL) else 1` to ensure consistency between
MANUAL and PASS requirement handling.

In `@api/src/backend/api/v1/views.py`:
- Around line 4813-4822: The method _filtered_queryset_for_latest_provider_scans
and the related code paths at lines 4979-4990, 5035-5050, and 5065-5150 retrieve
the latest scan IDs via _latest_scan_ids_for_provider_filters() but then discard
them and fall through to _task_response_if_running(None), which cannot check
individual scans for in-progress status. Preserve the latest_scan_ids obtained
from _latest_scan_ids_for_provider_filters() and before returning empty
compliance data, check _task_response_if_running() for each of the selected scan
IDs to detect and preserve in-progress compliance responses rather than
returning an empty 200 response. Apply this same pattern across all affected
locations so that provider-filtered latest scans properly check for running
tasks before returning empty results.

---

Outside diff comments:
In `@api/src/backend/api/v1/views.py`:
- Around line 5857-5866: The descriptions for the OpenApiParameter definitions
named "provider_groups" and "provider_groups__in" do not document the canonical
JSON:API query parameter format that clients should use. Update the description
fields for both parameters to explicitly document the JSON:API filter syntax:
clarify that "provider_groups" should be sent as `filter[provider_groups]=value`
and "provider_groups__in" should be sent as
`filter[provider_groups__in]=value1,value2` so that generated clients follow the
JSON:API filtering convention.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 459ef478-a216-452f-a824-c7c1d04d52d9

📥 Commits

Reviewing files that changed from the base of the PR and between 24232e7 and 3858f71.

📒 Files selected for processing (5)
  • api/CHANGELOG.md
  • api/src/backend/api/filters.py
  • api/src/backend/api/tests/test_views.py
  • api/src/backend/api/v1/mixins.py
  • api/src/backend/api/v1/views.py

Comment thread api/src/backend/api/tests/test_views.py
Comment thread api/src/backend/api/tests/test_views.py Outdated
Comment thread api/src/backend/api/v1/views.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
api/src/backend/api/v1/views.py (1)

5672-5685: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Initialize provider RBAC scope before counting providers.

This action never calls get_queryset() or _get_provider_filter(), so allowed_providers is unset on a fresh request and limited-visibility users can receive tenant-wide provider counts. Scope the Provider query through the same RBAC helper used by the other overview actions.

Suggested fix
     def providers_count(self, request):
         tenant_id = self.request.tenant_id
         providers_qs = Provider.objects.filter(tenant_id=tenant_id)
 
-        if hasattr(self, "allowed_providers"):
-            allowed_ids = list(self.allowed_providers.values_list("id", flat=True))
-            if not allowed_ids:
-                overview = []
-                return Response(
-                    self.get_serializer(overview, many=True).data,
-                    status=status.HTTP_200_OK,
-                )
-            providers_qs = providers_qs.filter(id__in=allowed_ids)
+        self._ensure_allowed_providers()
+        if hasattr(self, "allowed_providers"):
+            providers_qs = providers_qs.filter(
+                id__in=self.allowed_providers.values("id")
+            )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@api/src/backend/api/v1/views.py` around lines 5672 - 5685, The
providers_count method checks for the allowed_providers attribute without first
initializing it through proper RBAC scoping, which allows limited-visibility
users to see tenant-wide provider counts. Before checking for allowed_providers
in the method, call the same RBAC helper method (either get_queryset() or
_get_provider_filter()) that other overview actions use to properly initialize
the provider filter scope based on the user's permissions, ensuring the Provider
queryset is scoped through RBAC before counting.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@api/src/backend/api/tests/test_views.py`:
- Around line 9792-9893: The file api/src/backend/api/tests/test_views.py fails
the ruff format check, meaning the code does not conform to the project's
formatting standards. Run the repository's formatting command (typically `ruff
format api/src/backend/api/tests/test_views.py` or your project's equivalent
formatting tool) to automatically reformat the entire file according to the
configured style rules, then commit the reformatted result. This will resolve
the code-quality check failure.

In `@api/src/backend/api/v1/views.py`:
- Around line 4947-4970: The method `_latest_provider_scan_ids_without_data`
currently uses a queryset that already includes user filters like region or
compliance_id to determine if a scan has data. This causes scans to be
incorrectly marked as "without data" when filters legitimately exclude their
rows, leading to wrong 202/500 responses instead of 200. Create a separate
data-presence queryset scoped only by tenant/RBAC and latest_scan_ids (excluding
user filters) and pass this to `_latest_provider_scan_ids_without_data` instead
of the filtered queryset. Keep the original filtered queryset in
`_task_response_for_latest_provider_scans_without_data` for response aggregation
only.

---

Outside diff comments:
In `@api/src/backend/api/v1/views.py`:
- Around line 5672-5685: The providers_count method checks for the
allowed_providers attribute without first initializing it through proper RBAC
scoping, which allows limited-visibility users to see tenant-wide provider
counts. Before checking for allowed_providers in the method, call the same RBAC
helper method (either get_queryset() or _get_provider_filter()) that other
overview actions use to properly initialize the provider filter scope based on
the user's permissions, ensuring the Provider queryset is scoped through RBAC
before counting.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 91a95881-c58b-4e7b-9c64-69048a5c021e

📥 Commits

Reviewing files that changed from the base of the PR and between 3858f71 and 53d1a9d.

📒 Files selected for processing (3)
  • api/CHANGELOG.md
  • api/src/backend/api/tests/test_views.py
  • api/src/backend/api/v1/views.py

Comment thread api/src/backend/api/tests/test_views.py
Comment thread api/src/backend/api/v1/views.py Outdated
- Scope provider counts through RBAC visibility
- Check compliance data presence without response filters
- Add regression coverage for provider-filtered overview cases
@jfagoagas jfagoagas merged commit e4d5ca1 into master Jun 16, 2026
41 of 42 checks passed
@jfagoagas jfagoagas deleted the implement-provider-groups-filter branch June 16, 2026 12:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants