
Prowler Provider
- 62 installs
- 14.5k repo stars
- Updated August 4, 2026
- prowler-cloud/prowler
Helps with ai & agent building tasks.
About
prowler-provider is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted development.
- prowler-provider
- AI & Agent Building
- AI-coding skill
Prowler Provider by the numbers
- 62 all-time installs (skills.sh)
- Ranked #6,310 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/prowler-cloud/prowler --skill prowler-providerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 62 |
|---|---|
| repo stars | ★ 14.5k |
| Last updated | August 4, 2026 |
| Repository | prowler-cloud/prowler ↗ |
What it does
Helps with ai & agent building tasks.
Files
When to Use
Use this skill when:
- Adding a new cloud provider to Prowler
- Adding a new service to an existing provider
- Understanding the provider architecture pattern
Provider Architecture Pattern
Every provider MUST follow this structure:
prowler/providers/{provider}/
├── __init__.py
├── {provider}_provider.py # Main provider class
├── models.py # Provider-specific models
├── config.py # Provider configuration
├── exceptions/ # Provider-specific exceptions
├── lib/
│ ├── service/ # Base service class
│ ├── arguments/ # CLI arguments parser
│ └── mutelist/ # Mutelist functionality
└── services/
└── {service}/
├── {service}_service.py # Resource fetcher
├── {service}_client.py # Python singleton instance
└── {check_name}/ # Individual checks
├── {check_name}.py
└── {check_name}.metadata.jsonSensitive CLI Arguments
Flags that accept secrets (tokens, passwords, API keys) MUST follow these rules:
1. Use `nargs="?"` with `default=None` — the flag accepts an optional value for backward compatibility; the recommended path is environment variables. 2. Set `metavar` to the environment variable name users should use (e.g., metavar="GITHUB_PERSONAL_ACCESS_TOKEN"). 3. Add the flag to the `SENSITIVE_ARGUMENTS` frozenset at the top of the provider's arguments.py. This set is used to redact values in HTML output and warn users who pass secrets directly. 4. Do not add new arguments that require passing secrets as CLI values — secrets should come from environment variables. The flag accepts a value for backward compatibility, but CLI warns users to prefer env vars.
Pattern
# prowler/providers/{provider}/lib/arguments/arguments.py
SENSITIVE_ARGUMENTS = frozenset({"--my-api-key", "--my-password"})
def init_parser(self):
auth_subparser = parser.add_argument_group("Authentication Modes")
auth_subparser.add_argument(
"--my-api-key",
nargs="?",
default=None,
metavar="MY_API_KEY",
help="API key for authentication. Use MY_API_KEY env var instead of passing directly.",
)Provider Class Template
from prowler.providers.common.provider import Provider
class {Provider}Provider(Provider):
"""Provider class for {Provider} cloud platform."""
def __init__(self, arguments):
super().__init__(arguments)
self.session = self._setup_session(arguments)
self.regions = self._get_regions()
def _setup_session(self, arguments):
"""Provider-specific authentication."""
# Implement credential handling
pass
def _get_regions(self):
"""Get available regions for provider."""
# Return list of regions
passService Class Template
from prowler.providers.{provider}.lib.service.service import {Provider}Service
class {Service}({Provider}Service):
"""Service class for {service} resources."""
def __init__(self, provider):
super().__init__(provider)
self.{resources} = []
self._fetch_{resources}()
def _fetch_{resources}(self):
"""Fetch {resource} data from API."""
try:
response = self.client.list_{resources}()
for item in response:
self.{resources}.append(
{Resource}(
id=item["id"],
name=item["name"],
region=item.get("region"),
)
)
except Exception as e:
logger.error(f"Error fetching {resources}: {e}")Service Client Template
from prowler.providers.{provider}.services.{service}.{service}_service import {Service}
{service}_client = {Service}Supported Providers
Current providers:
- AWS (Amazon Web Services)
- Azure (Microsoft Azure)
- GCP (Google Cloud Platform)
- Kubernetes
- GitHub
- M365 (Microsoft 365)
- OracleCloud (Oracle Cloud Infrastructure)
- AlibabaCloud
- Cloudflare
- MongoDB Atlas
- NHN (NHN Cloud)
- LLM (Language Model providers)
- IaC (Infrastructure as Code)
Commands
# Run provider
uv run python prowler-cli.py {provider}
# List services for provider
uv run python prowler-cli.py {provider} --list-services
# List checks for provider
uv run python prowler-cli.py {provider} --list-checks
# Run specific service
uv run python prowler-cli.py {provider} --services {service}
# Debug mode
uv run python prowler-cli.py {provider} --log-level DEBUGResources
- Templates: See assets/ for Provider, Service, and Client singleton templates
- Documentation: See references/provider-docs.md for official Prowler Developer Guide links
# Example: Singleton Client Pattern
# Source: prowler/providers/github/services/repository/repository_client.py
"""
Singleton Client Pattern
This pattern is CRITICAL for how Prowler checks access service data.
How it works:
1. When this module is imported, the service is instantiated ONCE
2. The service fetches all data during __init__ (eager loading)
3. All checks import this singleton and access pre-fetched data
4. No additional API calls needed during check execution
File: prowler/providers/github/services/repository/repository_client.py
"""
from prowler.providers.common.provider import Provider
from prowler.providers.github.services.repository.repository_service import Repository
# SINGLETON: Instantiated once when module is first imported
# Provider.get_global_provider() returns the provider set in __init__
repository_client = Repository(Provider.get_global_provider())
"""
Usage in checks:
from prowler.providers.github.services.repository.repository_client import (
repository_client,
)
class repository_secret_scanning_enabled(Check):
def execute(self):
findings = []
for repo in repository_client.repositories.values():
# Access pre-fetched repository data
report = CheckReportGithub(metadata=self.metadata(), resource=repo)
if repo.secret_scanning_enabled:
report.status = "PASS"
else:
report.status = "FAIL"
findings.append(report)
return findings
"""
# Another example for organization service
# File: prowler/providers/github/services/organization/organization_client.py
# from prowler.providers.common.provider import Provider
# from prowler.providers.github.services.organization.organization_service import (
# Organization,
# )
#
# organization_client = Organization(Provider.get_global_provider())
# Example: Provider Class Template (GitHub Provider)
# Source: prowler/providers/github/github_provider.py
from prowler.config.config import (
default_config_file_path,
get_default_mute_file_path,
load_and_validate_config_file,
)
from prowler.lib.logger import logger
from prowler.lib.mutelist.mutelist import Mutelist
from prowler.providers.common.models import Audit_Metadata, Connection
from prowler.providers.common.provider import Provider
class GithubProvider(Provider):
"""
GitHub Provider - Template for creating new providers.
Required attributes (from abstract Provider):
- _type: str - Provider identifier
- _session: Session model - Authentication credentials
- _identity: Identity model - Authenticated user info
- _audit_config: dict - Check configuration
- _mutelist: Mutelist - Finding filtering
"""
_type: str = "github"
_auth_method: str = None
_session: "GithubSession"
_identity: "GithubIdentityInfo"
_audit_config: dict
_mutelist: Mutelist
audit_metadata: Audit_Metadata
def __init__(
self,
# Authentication credentials
personal_access_token: str = "",
# Provider configuration
config_path: str = None,
config_content: dict = None,
fixer_config: dict = {},
mutelist_path: str = None,
mutelist_content: dict = None,
# Provider scoping
repositories: list = None,
organizations: list = None,
):
logger.info("Instantiating GitHub Provider...")
# Store scoping configuration
self._repositories = repositories or []
self._organizations = organizations or []
# Step 1: Setup session (authentication)
self._session = self.setup_session(personal_access_token)
self._auth_method = "Personal Access Token"
# Step 2: Setup identity (who is authenticated)
self._identity = self.setup_identity(self._session)
# Step 3: Load audit config
if config_content:
self._audit_config = config_content
else:
if not config_path:
config_path = default_config_file_path
self._audit_config = load_and_validate_config_file(self._type, config_path)
# Step 4: Load fixer config
self._fixer_config = fixer_config
# Step 5: Load mutelist
if mutelist_content:
self._mutelist = GithubMutelist(mutelist_content=mutelist_content)
else:
if not mutelist_path:
mutelist_path = get_default_mute_file_path(self.type)
self._mutelist = GithubMutelist(mutelist_path=mutelist_path)
# CRITICAL: Register as global provider
Provider.set_global_provider(self)
# Required property implementations
@property
def type(self) -> str:
return self._type
@property
def session(self) -> "GithubSession":
return self._session
@property
def identity(self) -> "GithubIdentityInfo":
return self._identity
@property
def audit_config(self) -> dict:
return self._audit_config
@property
def mutelist(self) -> Mutelist:
return self._mutelist
@staticmethod
def setup_session(personal_access_token: str) -> "GithubSession":
"""Create authenticated session from credentials."""
if not personal_access_token:
raise ValueError("Personal access token required")
return GithubSession(token=personal_access_token)
@staticmethod
def setup_identity(session: "GithubSession") -> "GithubIdentityInfo":
"""Get identity info for authenticated user."""
# Make API call to get user info
# g = Github(auth=Auth.Token(session.token))
# user = g.get_user()
return GithubIdentityInfo(
account_id="user-id",
account_name="username",
account_url="https://github.com/username",
)
def print_credentials(self):
"""Display credentials in CLI output."""
print(f"GitHub Account: {self.identity.account_name}")
print(f"Auth Method: {self._auth_method}")
@staticmethod
def test_connection(
personal_access_token: str = None,
raise_on_exception: bool = True,
) -> Connection:
"""Test if credentials can connect to the provider."""
try:
session = GithubProvider.setup_session(personal_access_token)
GithubProvider.setup_identity(session)
return Connection(is_connected=True)
except Exception as e:
if raise_on_exception:
raise
return Connection(is_connected=False, error=str(e))
# Example: Service Base Class and Implementation
# Source: prowler/providers/github/lib/service/service.py
# Source: prowler/providers/github/services/repository/repository_service.py
from typing import Optional
from pydantic.v1 import BaseModel
from prowler.lib.logger import logger
# ============================================================
# Base Service Class
# ============================================================
class GithubService:
"""
Base service class for all GitHub services.
Key patterns:
1. Receives provider in __init__
2. Creates API clients in __set_clients__
3. Stores audit_config and fixer_config for check access
"""
def __init__(self, service: str, provider: "GithubProvider"):
self.provider = provider
self.clients = self.__set_clients__(provider.session)
self.audit_config = provider.audit_config
self.fixer_config = provider.fixer_config
def __set_clients__(self, session: "GithubSession") -> list:
"""Create API clients based on authentication type."""
clients = []
try:
# Create client(s) based on session credentials
# For token auth: single client
# For GitHub App: multiple clients (one per installation)
pass
except Exception as error:
logger.error(f"{error.__class__.__name__}: {error}")
return clients
# ============================================================
# Service Implementation
# ============================================================
class Repository(GithubService):
"""
Repository service - fetches and stores repository data.
Key patterns:
1. Inherits from GithubService
2. Fetches all data in __init__ (eager loading)
3. Stores data in attributes for check access
4. Defines Pydantic models for data structures
"""
def __init__(self, provider: "GithubProvider"):
super().__init__(__class__.__name__, provider)
# Fetch and store data during initialization
self.repositories = self._list_repositories()
def _list_repositories(self) -> dict:
"""List repositories based on provider scoping."""
logger.info("Repository - Listing Repositories...")
repos = {}
try:
for client in self.clients:
# Get repos from specified repositories
for repo_name in self.provider.repositories:
repo = client.get_repo(repo_name)
self._process_repository(repo, repos)
# Get repos from specified organizations
for org_name in self.provider.organizations:
org = client.get_organization(org_name)
for repo in org.get_repos():
self._process_repository(repo, repos)
except Exception as error:
logger.error(f"{error.__class__.__name__}: {error}")
return repos
def _process_repository(self, repo, repos: dict):
"""Process a single repository and add to repos dict."""
repos[repo.id] = Repo(
id=repo.id,
name=repo.name,
owner=repo.owner.login,
full_name=repo.full_name,
private=repo.private,
archived=repo.archived,
)
# ============================================================
# Pydantic Models for Service Data
# ============================================================
class Repo(BaseModel):
"""Model for GitHub Repository."""
id: int
name: str
owner: str
full_name: str
private: bool
archived: bool
secret_scanning_enabled: Optional[bool] = None
dependabot_enabled: Optional[bool] = None
class Config:
# Make model hashable for use as dict key
frozen = True
Provider Documentation
Local Documentation
For detailed provider development patterns, see:
Core Documentation
docs/developer-guide/provider.mdx- Provider architecture and creation guidedocs/developer-guide/services.mdx- Adding services to existing providers
Provider-Specific Details
docs/developer-guide/aws-details.mdx- AWS provider implementationdocs/developer-guide/azure-details.mdx- Azure provider implementationdocs/developer-guide/gcp-details.mdx- GCP provider implementationdocs/developer-guide/kubernetes-details.mdx- Kubernetes provider implementationdocs/developer-guide/github-details.mdx- GitHub provider implementationdocs/developer-guide/m365-details.mdx- Microsoft 365 provider implementationdocs/developer-guide/alibabacloud-details.mdx- Alibaba Cloud provider implementationdocs/developer-guide/llm-details.mdx- LLM provider implementation
Contents
The documentation covers:
- Provider types (SDK, API, Tool/Wrapper)
- Provider class structure and identity
- Service creation patterns
- Client singleton implementation
- Provider-specific authentication and API patterns