Files
prowler/dashboard/pages/cloud.py
2026-07-15 12:17:02 +02:00

266 lines
9.9 KiB
Python

"""Prowler Cloud upsell (gated) informational pages.
These routes live inside the Local Dashboard but do NOT reproduce any Prowler
Cloud functionality. Each renders the same reusable upgrade template with a
feature-specific name, icon, description, benefit bullets and UTM-tagged CTA.
All copy in ``CLOUD_FEATURES`` is normative — do not change wording,
capitalization or punctuation without Product approval.
"""
import dash
from dash import html
# Shared subtitle used across every gated page header.
CLOUD_SUBTITLE = "Discover more ways to protect and operate your cloud."
# Base Prowler Cloud URL; the UTM content value identifies the feature.
CLOUD_CTA_BASE = (
"https://cloud.prowler.com/sign-up?utm_source=prowler-local-dashboard&utm_content="
)
# Path to the recolorable checkmark mask used for benefit bullets.
CHECK_ICON = "/assets/images/icons/cloud/check.svg"
# Normative feature definitions. ``icon`` points to a local mask asset so no
# external requests are needed and the glyph recolors per context.
CLOUD_FEATURES = [
{
"slug": "lighthouse-ai",
"route": "/cloud/lighthouse-ai",
"nav_label": "Lighthouse AI",
"page_title": "Lighthouse AI",
"card_title": "Unlock Lighthouse AI",
"description": (
"Work with an AI security analyst that understands your cloud "
"posture and helps turn risk into action."
),
"benefits": [
"Ask questions about your security posture in plain language",
"Investigate findings with context from your connected providers",
"Move from insight to remediation faster",
],
"utm_content": "lighthouse-ai",
"icon": "/assets/images/icons/cloud/lighthouse-ai.svg",
},
{
"slug": "attack-paths",
"route": "/cloud/attack-paths",
"nav_label": "Attack Paths",
"page_title": "Attack Paths",
"card_title": "Unlock Attack Paths",
"description": (
"Visualize the paths an attacker could take through connected "
"resources before risk becomes compromise."
),
"benefits": [
"See exploitable relationships across your AWS environment",
"Focus remediation on the paths with the greatest impact",
"Explore each scan as a point-in-time security graph",
],
"utm_content": "attack-paths",
"icon": "/assets/images/icons/cloud/attack-paths.svg",
},
{
"slug": "findings",
"route": "/cloud/findings",
"nav_label": "Findings",
"page_title": "Findings",
"card_title": "Unlock Findings",
"description": (
"Filter, investigate, and prioritize security findings across "
"providers and scans from one workspace."
),
"benefits": [
"Search and filter findings across all connected accounts",
"Track status, severity, ownership, and remediation context",
"Triage findings and share a consistent source of truth with your security team",
],
"utm_content": "findings",
"icon": "/assets/images/icons/cloud/findings.svg",
},
{
"slug": "alerts",
"route": "/cloud/alerts",
"nav_label": "Alerts",
"page_title": "Alerts",
"card_title": "Unlock Alerts",
"description": (
"Create alert rules and stay informed when scan results reveal "
"the risks your team cares about."
),
"benefits": [
"Define alerts around the findings that matter most",
"Route security signals to the right responders",
"Reduce the time between detection and action",
],
"utm_content": "alerts",
"icon": "/assets/images/icons/cloud/alerts.svg",
},
{
"slug": "mutelist",
"route": "/cloud/mutelist",
"nav_label": "Mutelist",
"page_title": "Mutelist",
"card_title": "Unlock Mutelist",
"description": (
"Quiet expected findings, document accepted risk, and keep your "
"team focused on actionable work."
),
"benefits": [
"Create reusable rules for known exceptions",
"Keep muted findings available for audit and review",
"Cut noise without losing security context",
],
"utm_content": "mutelist",
"icon": "/assets/images/icons/cloud/mutelist.svg",
},
{
"slug": "integrations",
"route": "/cloud/integrations",
"nav_label": "Integrations",
"page_title": "Integrations",
"card_title": "Unlock Integrations",
"description": (
"Connect Prowler to your security workflow so findings and scan "
"data reach the tools your team already uses."
),
"benefits": [
"Connect ticketing, notification, and cloud security services",
"Automate the handoff from detection to response",
"Keep teams aligned without manual exports",
],
"utm_content": "integrations",
"icon": "/assets/images/icons/cloud/integrations.svg",
},
{
"slug": "organization",
"route": "/cloud/organization",
"nav_label": "Organization",
"page_title": "Organization",
"card_title": "Unlock Organization",
"description": (
"Manage users, roles, and invitations while organizing cloud "
"security work across your team."
),
"benefits": [
"Invite teammates into a shared security workspace",
"Control access with role-based permissions",
"Coordinate security operations across accounts and teams",
],
"utm_content": "organization",
"icon": "/assets/images/icons/cloud/organization.svg",
},
]
# Convenience lookup for the navigation builder in ``__main__``.
CLOUD_FEATURES_BY_SLUG = {feature["slug"]: feature for feature in CLOUD_FEATURES}
def _mask_style(icon_url):
"""Return the inline style that renders a recolorable mask icon."""
return {
"WebkitMaskImage": f"url({icon_url})",
"maskImage": f"url({icon_url})",
}
def _benefit_item(text):
return html.Li(
[
html.Span(
className="pc-ico pc-benefit-check",
style=_mask_style(CHECK_ICON),
),
html.Span(text),
],
className="pc-benefit",
)
def build_cloud_layout(feature):
"""Build the reusable gated informational page for a single feature."""
cta_url = f"{CLOUD_CTA_BASE}{feature['utm_content']}"
return html.Div(
html.Div(
[
# Page header: title + Prowler Cloud badge + shared subtitle.
html.Div(
[
html.Div(
[
html.H1(
feature["page_title"],
className="pc-page-title",
),
html.Span("Prowler Cloud", className="pc-pill"),
],
className="pc-page-title-row",
),
html.P(CLOUD_SUBTITLE, className="pc-page-subtitle"),
],
className="pc-page-header",
),
# Centered upgrade card.
html.Div(
[
html.Div(className="pc-card-glow"),
html.Div(
[
html.Div(
html.Span(
className="pc-ico",
style=_mask_style(feature["icon"]),
),
className="pc-feature-icon",
),
html.Div(
"Available in Prowler Cloud",
className="pc-avail",
),
html.H2(
feature["card_title"],
className="pc-card-title",
),
html.P(
feature["description"],
className="pc-card-desc",
),
html.Ul(
[
_benefit_item(benefit)
for benefit in feature["benefits"]
],
className="pc-benefits",
),
html.A(
"Upgrade to Prowler Cloud",
href=cta_url,
target="_blank",
rel="noopener noreferrer",
className="pc-cta",
),
],
className="pc-card-body",
),
],
className="pc-card",
),
],
className="pc-page pc-font",
),
)
# Register one page per gated feature. A distinct module key keeps each entry
# unique in Dash's page registry while sharing the same template.
for _feature in CLOUD_FEATURES:
dash.register_page(
f"cloud_{_feature['slug'].replace('-', '_')}",
path=_feature["route"],
name=_feature["nav_label"],
title=f"Prowler Dashboard - {_feature['page_title']}",
layout=build_cloud_layout(_feature),
)