External plug-ins ship multi-provider (universal-schema) frameworks through a
dedicated prowler.compliance.universal entry point group, separate from the
per-provider prowler.compliance group. Both get_bulk_compliance_frameworks_universal
(loading) and get_available_compliance_frameworks (listing / --compliance
choices) scan the new group. Built-ins load first and win on a name collision;
multiple packages under the same provider are merged. load_compliance_framework
gains fatal=False so the legacy external path skips a non-legacy JSON with a
warning instead of aborting the run.
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.
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).
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.
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.
- Reword get_class docstring: it may populate the _ep_providers cache,
rather than claiming "no global state"
- Assert ImportError specifically in the unknown-provider test to enforce
the public API contract
- Drop the unused provider_class_name left over after get_class delegation
- Compare the module's last dotted segment instead of substring
- Prevent a provider name from capturing overlapping built-ins
- Add parametrized regression test (cloud, git, work, open cases)
- Update get_bulk test mock to the real dotted module name
- Match shadowing entry point by name instead of calling ep.load()
- Prevent plug-in code from executing during a built-in run
- Update regression test to assert ep.load is never called
- Short-circuit on is_builtin_provider before loading entry points
- Prevent same-name plug-ins from flipping a built-in onto the tool-wrapper path
- Avoid executing plug-in code via ep.load() for built-in names
- Add regression test asserting ep.load is never called
- Add public get_class() resolving built-in and entry-point providers
- Refactor init_global_provider to use it; collision warning stays there
- Refactor get_providers_help_text to use it