Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .github/workflows/sdk-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,30 @@ jobs:
flags: prowler-py${{ matrix.python-version }}-stackit
files: ./stackit_coverage.xml

# E2E Cloud Provider
- name: Check if E2E Cloud files changed
if: steps.check-changes.outputs.any_changed == 'true'
id: changed-e2e
uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v47.0.6
with:
files: |
./prowler/**/e2e/**
./tests/**/e2e/**
./uv.lock

- name: Run E2E Cloud tests
if: steps.changed-e2e.outputs.any_changed == 'true'
run: uv run pytest -n auto --cov=./prowler/providers/e2e --cov-report=xml:e2e_coverage.xml tests/providers/e2e

- name: Upload E2E Cloud coverage to Codecov
if: steps.changed-e2e.outputs.any_changed == 'true'
uses: codecov/codecov-action@671740ac38dd9b0130fbe1cec585b89eea48d3de # v5.5.2
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
flags: prowler-py${{ matrix.python-version }}-e2e
files: ./e2e_coverage.xml

# External Provider (dynamic loading)
- name: Check if External Provider files changed
if: steps.check-changes.outputs.any_changed == 'true'
Expand Down
46 changes: 46 additions & 0 deletions docs/developer-guide/e2e-details.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
title: 'E2E Cloud Provider'
---

This page documents the [E2E Cloud](https://www.e2enetworks.com/) provider implementation in Prowler SDK.

E2E Cloud uses the MyAccount REST API documented at [E2E Cloud API](https://docs.e2enetworks.com/api/myaccount/compute/nodes/). Authentication requires both an API key and a Bearer auth token generated from the MyAccount portal.

## Authentication

Set the following environment variables before running scans:

```bash
export E2E_API_KEY=<api-key>
export E2E_AUTH_TOKEN=<auth-token>
export E2E_PROJECT_ID=<project-id>
export E2E_LOCATION=Delhi
```

Optional CLI flags (`--e2e-api-key`, `--e2e-auth-token`, `--e2e-project-id`, `--e2e-location`) are available for backward compatibility, but environment variables are preferred.

## Usage

```bash
uv run python prowler-cli.py e2e --list-checks
uv run python prowler-cli.py e2e --service node --log-level DEBUG
```

## Services and Checks

The initial release includes four services:

- `node` — compute node posture (public IP, encryption, compliance, VPC attachment)
- `securitygroup` — security group rules and node attachments
- `loadbalancer` — appliance HTTPS, health checks, BitNinja protection
- `storage` — object storage buckets and block volumes

Provider code lives under [`prowler/providers/e2e/`](https://github.com/prowler-cloud/prowler/tree/master/prowler/providers/e2e).

## Architecture Notes
Comment on lines +9 to +40

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add Version Badge for New E2E Provider Sections

These sections document newly introduced provider functionality (authentication/flags, usage, and services/checks), but no VersionBadge is present immediately after the headers.

📝 Suggested placement
 ## Authentication
+<VersionBadge version="X.Y.Z" />
 
 Set the following environment variables before running scans:
@@
 ## Usage
+<VersionBadge version="X.Y.Z" />
 
 ```bash
@@
 ## Services and Checks
+<VersionBadge version="X.Y.Z" />
 
 The initial release includes four services:

As per coding guidelines, "Use the Version Badge component to indicate when a feature or functionality was introduced in Prowler" and place it immediately after the section header.

🤖 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 `@docs/developer-guide/e2e-details.mdx` around lines 9 - 40, The documentation
is missing VersionBadge components for the newly introduced E2E provider
functionality sections. Add a VersionBadge component immediately after each of
the three section headers: "## Authentication", "## Usage", and "## Services and
Checks". Each VersionBadge should be placed on the line directly after its
corresponding header and before the section content, with the format
`<VersionBadge version="X.Y.Z" />` where X.Y.Z should be replaced with the
appropriate version number for when the E2E provider was introduced.

Source: Coding guidelines


- API client: [`prowler/providers/e2e/lib/api/client.py`](https://github.com/prowler-cloud/prowler/blob/master/prowler/providers/e2e/lib/api/client.py)
- Provider class: [`prowler/providers/e2e/e2e_provider.py`](https://github.com/prowler-cloud/prowler/blob/master/prowler/providers/e2e/e2e_provider.py)
- Check reports use `CheckReportE2e` in [`prowler/lib/check/models.py`](https://github.com/prowler-cloud/prowler/blob/master/prowler/lib/check/models.py)

Supported regions default to `Delhi` and `Chennai` per the E2E Cloud OpenAPI specification.
1 change: 1 addition & 0 deletions prowler/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ All notable changes to the **Prowler SDK** are documented in this file.
- DORA (Digital Operational Resilience Act, Regulation (EU) 2022/2554) compliance coverage for the GCP provider, mapping existing GCP checks across the five DORA pillars [(#11642)](https://github.com/prowler-cloud/prowler/pull/11642)
- DORA (Digital Operational Resilience Act, Regulation (EU) 2022/2554) compliance coverage for the Cloudflare provider, mapping existing Cloudflare edge/network checks across the applicable DORA pillars [(#11645)](https://github.com/prowler-cloud/prowler/pull/11645)
- DORA (Digital Operational Resilience Act, Regulation (EU) 2022/2554) compliance coverage for the AlibabaCloud provider, mapping existing AlibabaCloud checks across the applicable DORA pillars [(#11646)](https://github.com/prowler-cloud/prowler/pull/11646)
- E2E Cloud provider with `network`, `database`, and extended `storage` services (32 checks across compute, network, security groups, load balancers, storage, and DBaaS), plus a Cartography-style resource graph schema at `prowler/providers/e2e/docs/schema.md`

### 🔄 Changed

Expand Down
5 changes: 5 additions & 0 deletions prowler/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@
from prowler.providers.oraclecloud.models import OCIOutputOptions
from prowler.providers.scaleway.models import ScalewayOutputOptions
from prowler.providers.stackit.models import StackITOutputOptions
from prowler.providers.e2e.models import E2eOutputOptions
from prowler.providers.vercel.models import VercelOutputOptions


Expand Down Expand Up @@ -431,6 +432,10 @@ def prowler():
output_options = VercelOutputOptions(
args, bulk_checks_metadata, global_provider.identity
)
elif provider == "e2e":
output_options = E2eOutputOptions(
args, bulk_checks_metadata, global_provider.identity
)
elif provider == "okta":
output_options = OktaOutputOptions(
args, bulk_checks_metadata, global_provider.identity
Expand Down
1 change: 1 addition & 0 deletions prowler/config/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ class Provider(str, Enum):
VERCEL = "vercel"
OKTA = "okta"
STACKIT = "stackit"
E2E = "e2e"


# Compliance
Expand Down
5 changes: 5 additions & 0 deletions prowler/config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -675,3 +675,8 @@ okta:
# Defaults to 15 per DISA STIG V-273187 (OKTA-APP-000025); raise it only
# with an explicit risk acceptance.
okta_admin_console_idle_timeout_max_minutes: 15

# E2E Cloud Configuration
e2e:
# load_balancer_bitninja_enabled
require_bitninja_on_load_balancers: false
23 changes: 23 additions & 0 deletions prowler/lib/check/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1255,6 +1255,29 @@ def __init__(self, metadata: Dict, resource: Any) -> None:
self.location = getattr(resource, "location", "kr1")


@dataclass
class CheckReportE2e(Check_Report):
"""Contains the E2E Cloud Check's finding information."""

resource_name: str
resource_id: str
location: str

def __init__(self, metadata: Dict, resource: Any) -> None:
"""Initialize the E2E Cloud Check's finding information.

Args:
metadata: The metadata of the check.
resource: Basic information about the E2E Cloud resource.
"""
super().__init__(metadata, resource)
self.resource_name = getattr(
resource, "name", getattr(resource, "resource_name", "")
)
self.resource_id = getattr(resource, "id", getattr(resource, "resource_id", ""))
self.location = getattr(resource, "location", "global")
Comment thread
coderabbitai[bot] marked this conversation as resolved.


@dataclass
class CheckReportStackIT(Check_Report):
"""Contains the StackIT Check's finding information."""
Expand Down
8 changes: 5 additions & 3 deletions prowler/lib/cli/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ def __init__(self):
"nhn",
"mongodbatlas",
"vercel",
"e2e",
"okta",
"scaleway",
"stackit",
Expand All @@ -73,10 +74,10 @@ def __init__(self):
self.parser = argparse.ArgumentParser(
prog="prowler",
formatter_class=RawTextHelpFormatter,
usage=f"prowler [-h] [--version] {{aws,azure,gcp,kubernetes,m365,github,googleworkspace,okta,nhn,mongodbatlas,oraclecloud,alibabacloud,cloudflare,openstack,scaleway,stackit,vercel,dashboard,iac,image,llm{extra_providers_csv}}} ...",
usage=f"prowler [-h] [--version] {{aws,azure,gcp,kubernetes,m365,github,googleworkspace,okta,nhn,mongodbatlas,oraclecloud,alibabacloud,cloudflare,openstack,scaleway,stackit,vercel,e2e,dashboard,iac,image,llm{extra_providers_csv}}} ...",
epilog=f"""
Available Cloud Providers:
{{aws,azure,gcp,kubernetes,m365,github,googleworkspace,okta,iac,llm,image,nhn,mongodbatlas,oraclecloud,alibabacloud,cloudflare,openstack,scaleway,stackit,vercel{extra_providers_csv}}}
{{aws,azure,gcp,kubernetes,m365,github,googleworkspace,okta,iac,llm,image,nhn,mongodbatlas,oraclecloud,alibabacloud,cloudflare,openstack,scaleway,stackit,vercel,e2e{extra_providers_csv}}}
aws AWS Provider
azure Azure Provider
gcp GCP Provider
Expand All @@ -96,7 +97,8 @@ def __init__(self):
nhn NHN Provider (Unofficial)
mongodbatlas MongoDB Atlas Provider
scaleway Scaleway Provider
vercel Vercel Provider{extra_providers_text}
vercel Vercel Provider
e2e E2E Cloud Provider{extra_providers_text}


Available components:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"oraclecloud": ("TenancyId", "account_uid", "Region", "region"),
"alibabacloud": ("AccountId", "account_uid", "Region", "region"),
"nhn": ("AccountId", "account_uid", "Region", "region"),
"e2e": ("ProjectId", "account_uid", "Location", "region"),
}
_DEFAULT_HEADERS = ("AccountId", "account_uid", "Region", "region")

Expand Down
12 changes: 12 additions & 0 deletions prowler/lib/outputs/finding.py
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,18 @@ def generate_output(
output_data["resource_uid"] = check_output.resource_id
output_data["region"] = check_output.location

elif provider.type == "e2e":
output_data["auth_method"] = "api_key_and_bearer_token"
output_data["account_uid"] = str(
get_nested_attribute(provider, "identity.project_id")
)
output_data["account_name"] = str(
get_nested_attribute(provider, "identity.project_id")
)
output_data["resource_name"] = check_output.resource_name
output_data["resource_uid"] = check_output.resource_id
output_data["region"] = check_output.location

elif provider.type == "stackit":
output_data["auth_method"] = getattr(
provider, "auth_method", "api_token"
Expand Down
39 changes: 39 additions & 0 deletions prowler/lib/outputs/html/html.py
Original file line number Diff line number Diff line change
Expand Up @@ -1396,6 +1396,45 @@ def get_googleworkspace_assessment_summary(provider: Provider) -> str:
)
return ""

@staticmethod
def get_e2e_assessment_summary(provider: Provider) -> str:
"""Get the HTML assessment summary for the E2E Cloud provider."""
try:
locations = ", ".join(provider.identity.locations)
return f"""
<div class="col-md-2">
<div class="card">
<div class="card-header">
E2E Cloud Assessment Summary
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item">
<b>Project ID:</b> {provider.identity.project_id}
</li>
<li class="list-group-item">
<b>Locations:</b> {locations}
</li>
</ul>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-header">
E2E Cloud Credentials
</div>
<ul class="list-group list-group-flush">
<li class="list-group-item">
<b>Authentication:</b> API Key + Bearer Token
</li>
</ul>
</div>
</div>"""
except Exception as error:
logger.error(
f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}] -- {error}"
)
return ""

@staticmethod
def get_vercel_assessment_summary(provider: Provider) -> str:
"""
Expand Down
2 changes: 2 additions & 0 deletions prowler/lib/outputs/outputs.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ def stdout_report(finding, color, verbose, status, fix, provider=None):
details = finding.location
elif finding.check_metadata.Provider == "nhn":
details = finding.location
elif finding.check_metadata.Provider == "e2e":
details = finding.location
elif finding.check_metadata.Provider == "stackit":
details = finding.location
elif finding.check_metadata.Provider == "llm":
Expand Down
3 changes: 3 additions & 0 deletions prowler/lib/outputs/summary_table.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ def display_summary_table(
elif provider.type == "nhn":
entity_type = "Tenant Domain"
audited_entities = provider.identity.tenant_domain
elif provider.type == "e2e":
entity_type = "Project"
audited_entities = str(provider.identity.project_id)
elif provider.type == "stackit":
if provider.identity.project_name:
entity_type = "Project"
Expand Down
10 changes: 10 additions & 0 deletions prowler/providers/common/provider.py
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,16 @@ def init_global_provider(arguments: Namespace) -> None:
mutelist_path=arguments.mutelist_file,
fixer_config=fixer_config,
)
elif arguments.provider == "e2e":
provider_class(
api_key=getattr(arguments, "e2e_api_key", None),
auth_token=getattr(arguments, "e2e_auth_token", None),
project_id=getattr(arguments, "e2e_project_id", None),
locations=getattr(arguments, "e2e_location", None),
config_path=arguments.config_file,
mutelist_path=arguments.mutelist_file,
fixer_config=fixer_config,
)
elif arguments.provider == "okta":
provider_class(
okta_org_domain=getattr(arguments, "okta_org_domain", ""),
Expand Down
Empty file.
Loading
Loading