diff --git a/ui/actions/overview/regions/threat-map.adapter.ts b/ui/actions/overview/regions/threat-map.adapter.ts index 8b0c60b844..0b7852b56a 100644 --- a/ui/actions/overview/regions/threat-map.adapter.ts +++ b/ui/actions/overview/regions/threat-map.adapter.ts @@ -2,6 +2,14 @@ import { getProviderDisplayName } from "@/types/providers"; import { RegionsOverviewResponse } from "./types"; +export const RISK_LEVELS = { + LOW_HIGH: "low-high", + HIGH: "high", + CRITICAL: "critical", +} as const; + +export type RiskLevel = (typeof RISK_LEVELS)[keyof typeof RISK_LEVELS]; + export interface ThreatMapLocation { id: string; name: string; @@ -11,7 +19,7 @@ export interface ThreatMapLocation { coordinates: [number, number]; totalFindings: number; failFindings: number; - riskLevel: "low-high" | "high" | "critical"; + riskLevel: RiskLevel; severityData: Array<{ name: string; value: number; @@ -215,6 +223,44 @@ const MONGODBATLAS_COORDINATES: Record = { global: { lat: 40.8, lng: -74.0 }, // Global fallback }; +// Alibaba Cloud regions +const ALIBABACLOUD_COORDINATES: Record = { + // China regions + "cn-hangzhou": { lat: 30.3, lng: 120.2 }, // Hangzhou + "cn-shanghai": { lat: 31.2, lng: 121.5 }, // Shanghai + "cn-beijing": { lat: 39.9, lng: 116.4 }, // Beijing + "cn-shenzhen": { lat: 22.5, lng: 114.1 }, // Shenzhen + "cn-zhangjiakou": { lat: 40.8, lng: 114.9 }, // Zhangjiakou + "cn-huhehaote": { lat: 40.8, lng: 111.7 }, // Hohhot + "cn-wulanchabu": { lat: 41.0, lng: 113.1 }, // Ulanqab + "cn-chengdu": { lat: 30.7, lng: 104.1 }, // Chengdu + "cn-qingdao": { lat: 36.1, lng: 120.4 }, // Qingdao + "cn-nanjing": { lat: 32.1, lng: 118.8 }, // Nanjing + "cn-fuzhou": { lat: 26.1, lng: 119.3 }, // Fuzhou + "cn-guangzhou": { lat: 23.1, lng: 113.3 }, // Guangzhou + "cn-heyuan": { lat: 23.7, lng: 114.7 }, // Heyuan + "cn-hongkong": { lat: 22.3, lng: 114.2 }, // Hong Kong + // Asia Pacific regions + "ap-southeast-1": { lat: 1.4, lng: 103.8 }, // Singapore + "ap-southeast-2": { lat: -33.9, lng: 151.2 }, // Sydney + "ap-southeast-3": { lat: 3.1, lng: 101.7 }, // Kuala Lumpur + "ap-southeast-5": { lat: -6.2, lng: 106.8 }, // Jakarta + "ap-southeast-6": { lat: 13.8, lng: 100.5 }, // Bangkok + "ap-southeast-7": { lat: 10.8, lng: 106.6 }, // Ho Chi Minh City + "ap-northeast-1": { lat: 35.7, lng: 139.7 }, // Tokyo + "ap-northeast-2": { lat: 37.6, lng: 127.0 }, // Seoul + "ap-south-1": { lat: 19.1, lng: 72.9 }, // Mumbai + // US & Europe regions + "us-west-1": { lat: 37.4, lng: -121.9 }, // Silicon Valley + "us-east-1": { lat: 39.0, lng: -77.5 }, // Virginia + "eu-west-1": { lat: 51.5, lng: -0.1 }, // London + "eu-central-1": { lat: 50.1, lng: 8.7 }, // Frankfurt + // Middle East regions + "me-east-1": { lat: 25.3, lng: 55.3 }, // Dubai + "me-central-1": { lat: 24.5, lng: 54.4 }, // Riyadh + global: { lat: 30.3, lng: 120.2 }, // Global fallback (Hangzhou HQ) +}; + const PROVIDER_COORDINATES: Record< string, Record @@ -230,6 +276,7 @@ const PROVIDER_COORDINATES: Record< iac: IAC_COORDINATES, oraclecloud: ORACLECLOUD_COORDINATES, mongodbatlas: MONGODBATLAS_COORDINATES, + alibabacloud: ALIBABACLOUD_COORDINATES, }; // Returns [lng, lat] format for D3/GeoJSON compatibility @@ -253,10 +300,10 @@ function getRegionCoordinates( return coords ? [coords.lng, coords.lat] : null; } -function getRiskLevel(failRate: number): "low-high" | "high" | "critical" { - if (failRate >= 0.5) return "critical"; - if (failRate >= 0.25) return "high"; - return "low-high"; +function getRiskLevel(failRate: number): RiskLevel { + if (failRate >= 0.5) return RISK_LEVELS.CRITICAL; + if (failRate >= 0.25) return RISK_LEVELS.HIGH; + return RISK_LEVELS.LOW_HIGH; } // CSS variables are used for Recharts inline styles, not className diff --git a/ui/app/(prowler)/_new-overview/_components/accounts-selector.tsx b/ui/app/(prowler)/_new-overview/_components/accounts-selector.tsx index 1593e6388d..80a22b1379 100644 --- a/ui/app/(prowler)/_new-overview/_components/accounts-selector.tsx +++ b/ui/app/(prowler)/_new-overview/_components/accounts-selector.tsx @@ -4,6 +4,7 @@ import { useRouter, useSearchParams } from "next/navigation"; import { ReactNode } from "react"; import { + AlibabaCloudProviderBadge, AWSProviderBadge, AzureProviderBadge, GCPProviderBadge, @@ -33,6 +34,7 @@ const PROVIDER_ICON: Record = { iac: , oraclecloud: , mongodbatlas: , + alibabacloud: , }; interface AccountsSelectorProps { diff --git a/ui/app/(prowler)/_new-overview/_components/provider-type-selector.tsx b/ui/app/(prowler)/_new-overview/_components/provider-type-selector.tsx index 9dadf46b97..e5eb7928f3 100644 --- a/ui/app/(prowler)/_new-overview/_components/provider-type-selector.tsx +++ b/ui/app/(prowler)/_new-overview/_components/provider-type-selector.tsx @@ -57,6 +57,11 @@ const MongoDBAtlasProviderBadge = lazy(() => default: m.MongoDBAtlasProviderBadge, })), ); +const AlibabaCloudProviderBadge = lazy(() => + import("@/components/icons/providers-badge").then((m) => ({ + default: m.AlibabaCloudProviderBadge, + })), +); type IconProps = { width: number; height: number }; @@ -104,6 +109,10 @@ const PROVIDER_DATA: Record< label: "MongoDB Atlas", icon: MongoDBAtlasProviderBadge, }, + alibabacloud: { + label: "Alibaba Cloud", + icon: AlibabaCloudProviderBadge, + }, }; type ProviderTypeSelectorProps = { diff --git a/ui/app/(prowler)/providers/(set-up-provider)/add-credentials/page.tsx b/ui/app/(prowler)/providers/(set-up-provider)/add-credentials/page.tsx index 447ea6bcda..56fc10c03b 100644 --- a/ui/app/(prowler)/providers/(set-up-provider)/add-credentials/page.tsx +++ b/ui/app/(prowler)/providers/(set-up-provider)/add-credentials/page.tsx @@ -1,10 +1,9 @@ -import React from "react"; - import { getProvider } from "@/actions/providers/providers"; import { AddViaCredentialsForm, AddViaRoleForm, } from "@/components/providers/workflow/forms"; +import { SelectViaAlibabaCloud } from "@/components/providers/workflow/forms/select-credentials-type/alibabacloud"; import { SelectViaAWS } from "@/components/providers/workflow/forms/select-credentials-type/aws"; import { AddViaServiceAccountForm, @@ -42,6 +41,8 @@ export default async function AddCredentialsPage({ searchParams }: Props) { if (providerType === "github") return ; if (providerType === "m365") return ; + if (providerType === "alibabacloud") + return ; return null; case "credentials": diff --git a/ui/components/filters/custom-provider-inputs.tsx b/ui/components/filters/custom-provider-inputs.tsx index 3df2b606ab..47fe62e3aa 100644 --- a/ui/components/filters/custom-provider-inputs.tsx +++ b/ui/components/filters/custom-provider-inputs.tsx @@ -1,6 +1,5 @@ -import React from "react"; - import { + AlibabaCloudProviderBadge, AWSProviderBadge, AzureProviderBadge, GCPProviderBadge, @@ -92,3 +91,12 @@ export const CustomProviderInputOracleCloud = () => { ); }; + +export const CustomProviderInputAlibabaCloud = () => { + return ( +
+ +

Alibaba Cloud

+
+ ); +}; diff --git a/ui/components/filters/custom-select-provider.tsx b/ui/components/filters/custom-select-provider.tsx index a61b2f96bb..bab26272cb 100644 --- a/ui/components/filters/custom-select-provider.tsx +++ b/ui/components/filters/custom-select-provider.tsx @@ -2,11 +2,12 @@ import { Select, SelectItem } from "@heroui/select"; import { useRouter, useSearchParams } from "next/navigation"; -import React, { useCallback, useMemo } from "react"; +import { ReactElement } from "react"; import { PROVIDER_TYPES, ProviderType } from "@/types/providers"; import { + CustomProviderInputAlibabaCloud, CustomProviderInputAWS, CustomProviderInputAzure, CustomProviderInputGCP, @@ -20,7 +21,7 @@ import { const providerDisplayData: Record< ProviderType, - { label: string; component: React.ReactElement } + { label: string; component: ReactElement } > = { aws: { label: "Amazon Web Services", @@ -58,6 +59,10 @@ const providerDisplayData: Record< label: "Oracle Cloud Infrastructure", component: , }, + alibabacloud: { + label: "Alibaba Cloud", + component: , + }, }; const dataInputsProvider = PROVIDER_TYPES.map((providerType) => ({ @@ -66,32 +71,27 @@ const dataInputsProvider = PROVIDER_TYPES.map((providerType) => ({ value: providerDisplayData[providerType].component, })); -export const CustomSelectProvider: React.FC = () => { +export const CustomSelectProvider = () => { const router = useRouter(); const searchParams = useSearchParams(); - const applyProviderFilter = useCallback( - (value: string) => { - const params = new URLSearchParams(searchParams.toString()); - if (value) { - params.set("filter[provider_type]", value); - } else { - params.delete("filter[provider_type]"); - } - router.push(`?${params.toString()}`, { scroll: false }); - }, - [router, searchParams], - ); + const applyProviderFilter = (value: string) => { + const params = new URLSearchParams(searchParams.toString()); + if (value) { + params.set("filter[provider_type]", value); + } else { + params.delete("filter[provider_type]"); + } + router.push(`?${params.toString()}`, { scroll: false }); + }; const currentProvider = searchParams.get("filter[provider_type]") || ""; - const selectedKeys = useMemo(() => { - return dataInputsProvider.some( - (provider) => provider.key === currentProvider, - ) - ? [currentProvider] - : []; - }, [currentProvider]); + const selectedKeys = dataInputsProvider.some( + (provider) => provider.key === currentProvider, + ) + ? [currentProvider] + : []; return (