feat(sdk): Enhance dynamic provider loading and compliance framework#10700
Conversation
…very - Implemented dynamic loading of external providers via entry points, allowing for greater flexibility in provider integration. - Added functionality to discover compliance directories from entry points, enabling external compliance frameworks to be loaded seamlessly. - Refactored check module resolution to prioritize built-in checks while falling back to entry points if necessary. - Improved compliance framework loading to include both built-in and external sources, ensuring comprehensive compliance coverage. - Enhanced CLI argument parsing to support external providers, improving user experience and configurability. - Introduced extensive unit tests to validate dynamic loading, compliance discovery, and overall integration of external providers.
|
✅ All necessary |
|
✅ Conflict Markers Resolved All conflict markers have been successfully resolved in this pull request. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #10700 +/- ##
===========================================
- Coverage 93.96% 73.96% -20.01%
===========================================
Files 243 110 -133
Lines 35653 8492 -27161
===========================================
- Hits 33503 6281 -27222
- Misses 2150 2211 +61
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
🔒 Container Security ScanImage: 📊 Vulnerability Summary
8 package(s) affected
|
…iders and add tests
…ific compliance rendering
There was a problem hiding this comment.
Request changes — see inline comments for the specifics. One cross-cutting issue that doesn't anchor to any single line in the diff:
YAML namespace unwrap only knows about 5 providers
prowler/config/config.py:244-253 only sniffs aws, gcp, azure, kubernetes and m365. Prowler ships 16+ built-ins, so twelve are outside the list (nhn, github, googleworkspace, cloudflare, iac, llm, image, mongodbatlas, oraclecloud, openstack, alibabacloud, vercel).
A github user writing a namespaced config:
github:
token: abcThe sniff finds none of the five keys, falls into the else at line 250, github isn't in the safeguard at line 252, and the function returns {'github': {'token': 'abc'}} whole. github_provider receives the wrapped dict instead of the inner block.
This is a latent bug in master for 12 built-ins; the PR inherits it and additionally blocks any external plug-in from using the namespaced format. One change covers both:
if provider in config_file:
config = config_file.get(provider, {})
else:
config = config_file if config_file else {}…iders load_and_validate_config_file only detected the namespaced format for 5 hardcoded providers (aws, gcp, azure, kubernetes, m365). For every other built-in (github, nhn, vercel, cloudflare, iac, llm, image, mongodbatlas, oraclecloud, openstack, alibabacloud, googleworkspace) and for any external plug-in, the full YAML was returned wrapped instead of the provider's own block. Replace the hardcoded list with a dynamic check: if the file has a top-level key matching the provider and its value is a dict, unwrap it. Keep the legacy flat format for AWS only (historical, pre-multicloud) and identify it by the absence of nested-dict top-level values, which prevents cross-provider config leakage when a namespaced file has no section for the requested provider.
…etadata validators
…er-contract-dynamic-discovery # Conflicts: # prowler/CHANGELOG.md
HugoPBrito
left a comment
There was a problem hiding this comment.
Functionally tested this branch in an isolated venv (PR head): built-in no-regression, external provider E2E (local-template), external checks on aws, built-in-name precedence, and the PR test suite (235 passed). Two confirmed issues below, both reproduced by running prowler — the rest of the contract works as expected.
External providers that do not override get_output_options no longer abort the run with NotImplementedError. The base contract returns a generic ProviderOutputOptions, honoring arguments.output_filename and otherwise falling back to a provider-typed filename. Built-ins are unaffected.
Move the models.py Provider import (used only in the shodan path) to a local import so models no longer depends on provider at module level. This breaks the provider <-> models import cycle CodeQL flagged after the generic OutputOptions default was added, and lets provider.py import ProviderOutputOptions without a cycle. The output_file_timestamp import is consolidated into the existing top-level config import.
External providers that do not override get_summary_entity no longer cause the summary table to be silently dropped. The base contract returns (self.type, account_id), mirroring the get_output_options default.
Resolve the provider<->models import cycle CodeQL flagged (py/cyclic-import #7267, #7268). provider.py no longer imports models: get_output_options stays override-only and __main__ falls back to a new default_output_options helper in models.py when a provider does not implement it. models.py keeps its original module-level Provider import (one-way, no cycle).
… schemas GenericCompliance is the documented last-resort renderer, but it read the universal attribute fields (Section, SubSection, SubGroup, Service, Type, Comment) directly and raised AttributeError on frameworks whose schema does not declare them (CIS, ENS, ISO27001), dropping the whole compliance CSV. Read all six fields with getattr defaulting to None, and dedupe the finding and manual rows into a single helper.
Remove a stray '=======' conflict marker left in prowler/CHANGELOG.md after the master merge, and move the elbv2_alb_drop_invalid_header_fields_enabled entry from Fixed to Added where it belongs.
Context
Enables external and custom providers to be discovered and integrated through Python
entry points, without modifying Prowler's core codebase.
Description
External and custom providers can now register themselves through Python entry points and
run through the same flows as built-in providers — output formatting, compliance,
mutelist, and check resolution — with no changes to Prowler's core.
entry points and merged with the built-ins.
Providerbase class lets a plug-in supply its own CLIparsing, output, compliance, and mutelist behavior; anything it does not implement falls
back to sensible defaults.
under a built-in's name is ignored with a warning and never executed.
prowler --helplists installed external providers alongside the built-ins.No behavior change for built-in providers.
Deferred follow-ups: surfacing plug-in override events; a fixer-module contract for
external providers.
Steps to review
prowler aws --list-checks,prowler aws --list-compliance.prowler --helplists any installed external providers in the usage/epilog.aws) is ignored with a warning andnever executed.
Checklist
Community Checklist
SDK/CLI
UI
API
License
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.