From 4ba1c0259f0386b0bb5325453615bf7eebcb2ffc Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Wed, 27 Nov 2024 14:00:26 -0400 Subject: [PATCH 1/8] fix(gcp): use session credentials to check if API is active (#5935) --- prowler/providers/gcp/lib/service/service.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/prowler/providers/gcp/lib/service/service.py b/prowler/providers/gcp/lib/service/service.py index dbb7f22638..9763230153 100644 --- a/prowler/providers/gcp/lib/service/service.py +++ b/prowler/providers/gcp/lib/service/service.py @@ -55,7 +55,9 @@ def __is_api_active__(self, audited_project_ids): project_ids = [] for project_id in audited_project_ids: try: - client = discovery.build("serviceusage", "v1") + client = discovery.build( + "serviceusage", "v1", credentials=self.credentials + ) request = client.services().get( name=f"projects/{project_id}/services/{self.service}.googleapis.com" ) From fd8d34e8bc109024a28a13ed74cdd3c5e55abb18 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Thu, 28 Nov 2024 10:39:10 +0100 Subject: [PATCH 2/8] feat(ui:profile) add profile card (#5948) --- ui/actions/auth/auth.ts | 31 ++++++ ui/app/(prowler)/profile/page.tsx | 45 +++++---- .../filters/custom-region-selection.tsx | 32 +------ ui/components/users/profile/index.ts | 2 + .../users/profile/skeleton-user-info.tsx | 64 +++++++++++++ ui/components/users/profile/user-info.tsx | 77 +++++++++++++++ ui/lib/helper.ts | 94 +++++++++++++++++++ ui/types/components.ts | 26 +++++ 8 files changed, 322 insertions(+), 49 deletions(-) create mode 100644 ui/components/users/profile/index.ts create mode 100644 ui/components/users/profile/skeleton-user-info.tsx create mode 100644 ui/components/users/profile/user-info.tsx diff --git a/ui/actions/auth/auth.ts b/ui/actions/auth/auth.ts index 1bbc79b17e..19e0c62a38 100644 --- a/ui/actions/auth/auth.ts +++ b/ui/actions/auth/auth.ts @@ -1,9 +1,12 @@ "use server"; +import { revalidatePath } from "next/cache"; import { AuthError } from "next-auth"; import { z } from "zod"; import { signIn, signOut } from "@/auth.config"; +import { auth } from "@/auth.config"; +import { parseStringify } from "@/lib"; import { authFormSchema } from "@/types"; const formSchemaSignIn = authFormSchema("sign-in"); @@ -139,6 +142,34 @@ export const getToken = async (formData: z.infer) => { } }; +export const getProfileInfo = async () => { + const session = await auth(); + const keyServer = process.env.API_BASE_URL; + const url = new URL(`${keyServer}/users/me`); + + try { + const response = await fetch(url.toString(), { + method: "GET", + headers: { + Accept: "application/vnd.api+json", + Authorization: `Bearer ${session?.accessToken}`, + }, + }); + + if (!response.ok) { + throw new Error(`Failed to fetch user data: ${response.statusText}`); + } + + const data = await response.json(); + const parsedData = parseStringify(data); + revalidatePath("/profile"); + return parsedData; + } catch (error) { + console.error("Error fetching profile:", error); + return undefined; + } +}; + export const getUserByMe = async (accessToken: string) => { const keyServer = process.env.API_BASE_URL; const url = new URL(`${keyServer}/users/me`); diff --git a/ui/app/(prowler)/profile/page.tsx b/ui/app/(prowler)/profile/page.tsx index 0cfb4f8ab2..26d46a4380 100644 --- a/ui/app/(prowler)/profile/page.tsx +++ b/ui/app/(prowler)/profile/page.tsx @@ -1,30 +1,39 @@ import { Spacer } from "@nextui-org/react"; -import { redirect } from "next/navigation"; -import React from "react"; +import React, { Suspense } from "react"; -// import { getUserByMe } from "@/actions/auth/auth"; -import { auth } from "@/auth.config"; +import { getProfileInfo } from "@/actions/auth"; import { Header } from "@/components/ui"; +import { SkeletonUserInfo } from "@/components/users/profile"; +import { UserInfo } from "@/components/users/profile/user-info"; +import { UserProfileProps } from "@/types"; export default async function Profile() { - const session = await auth(); - - if (!session?.user) { - // redirect("/sign-in?returnTo=/profile"); - redirect("/sign-in"); - } - - // const user = await getUserByMe(); - return ( <>
- -
{JSON.stringify(session.user, null, 2)}
-
{JSON.stringify(session.userId, null, 2)}
-
{JSON.stringify(session.tenantId, null, 2)}
-
{JSON.stringify(session, null, 2)}
+
+
+
+
+ }> + + +
+
+
+
); } + +const SSRDataUser = async () => { + const userProfile: UserProfileProps = await getProfileInfo(); + + return ( + <> +

User Info

+ + + ); +}; diff --git a/ui/components/filters/custom-region-selection.tsx b/ui/components/filters/custom-region-selection.tsx index 7fc40fe0ea..f97179a5dd 100644 --- a/ui/components/filters/custom-region-selection.tsx +++ b/ui/components/filters/custom-region-selection.tsx @@ -4,37 +4,7 @@ import { Select, SelectItem } from "@nextui-org/react"; import { useRouter, useSearchParams } from "next/navigation"; import React, { useCallback, useMemo } from "react"; -const regions = [ - { key: "af-south-1", label: "AF South 1" }, - { key: "ap-east-1", label: "AP East 1" }, - { key: "ap-northeast-1", label: "AP Northeast 1" }, - { key: "ap-northeast-2", label: "AP Northeast 2" }, - { key: "ap-northeast-3", label: "AP Northeast 3" }, - { key: "ap-south-1", label: "AP South 1" }, - { key: "ap-south-2", label: "AP South 2" }, - { key: "ap-southeast-1", label: "AP Southeast 1" }, - { key: "ap-southeast-2", label: "AP Southeast 2" }, - { key: "ap-southeast-3", label: "AP Southeast 3" }, - { key: "ap-southeast-4", label: "AP Southeast 4" }, - { key: "ca-central-1", label: "CA Central 1" }, - { key: "ca-west-1", label: "CA West 1" }, - { key: "eu-central-1", label: "EU Central 1" }, - { key: "eu-central-2", label: "EU Central 2" }, - { key: "eu-north-1", label: "EU North 1" }, - { key: "eu-south-1", label: "EU South 1" }, - { key: "eu-south-2", label: "EU South 2" }, - { key: "eu-west-1", label: "EU West 1" }, - { key: "eu-west-2", label: "EU West 2" }, - { key: "eu-west-3", label: "EU West 3" }, - { key: "il-central-1", label: "IL Central 1" }, - { key: "me-central-1", label: "ME Central 1" }, - { key: "me-south-1", label: "ME South 1" }, - { key: "sa-east-1", label: "SA East 1" }, - { key: "us-east-1", label: "US East 1" }, - { key: "us-east-2", label: "US East 2" }, - { key: "us-west-1", label: "US West 1" }, - { key: "us-west-2", label: "US West 2" }, -]; +import { regions } from "@/lib/helper"; export const CustomRegionSelection: React.FC = () => { const router = useRouter(); diff --git a/ui/components/users/profile/index.ts b/ui/components/users/profile/index.ts new file mode 100644 index 0000000000..07aeca9b89 --- /dev/null +++ b/ui/components/users/profile/index.ts @@ -0,0 +1,2 @@ +export * from "./skeleton-user-info"; +export * from "./user-info"; diff --git a/ui/components/users/profile/skeleton-user-info.tsx b/ui/components/users/profile/skeleton-user-info.tsx new file mode 100644 index 0000000000..6bd52c322e --- /dev/null +++ b/ui/components/users/profile/skeleton-user-info.tsx @@ -0,0 +1,64 @@ +import { Card, CardBody, CardHeader, Skeleton } from "@nextui-org/react"; + +export const SkeletonUserInfo = () => { + const rows = 4; + + return ( + + + +
+
+
+ +
+ {/* Header Skeleton */} +
+ +
+
+ +
+
+ +
+
+ +
+
+
+ + {/* Row Skeletons */} + {Array.from({ length: rows }).map((_, index) => ( +
+ {/* Provider Name */} +
+ +
+
+ +
+
+
+ {/* Percent Passing */} + +
+
+ {/* Failing Checks */} + +
+
+ {/* Total Resources */} + +
+
+
+ ))} +
+
+
+ ); +}; diff --git a/ui/components/users/profile/user-info.tsx b/ui/components/users/profile/user-info.tsx new file mode 100644 index 0000000000..ac44770a04 --- /dev/null +++ b/ui/components/users/profile/user-info.tsx @@ -0,0 +1,77 @@ +"use client"; + +import { Card, CardBody } from "@nextui-org/react"; + +import { DateWithTime } from "@/components/ui/entities"; +import { UserProfileProps } from "@/types"; + +export const UserInfo = ({ + user, +}: { + user: UserProfileProps["data"] | null; +}) => { + if (!user || !user.attributes) { + return ( + + +
+
+

Name:

+ - +
+
+

Email:

+ - +
+
+

Company:

+ - +
+
+

+ Date Joined: +

+ - +
+
+
+ Unable to load user information. +
+ Please check your API connection. +
+
+
+ ); + } + + const { name, email, company_name, date_joined } = user.attributes; + + return ( + + +
+
+

Name:

+ {name} +
+
+

Email:

+ {email} +
+
+

Company:

+ {company_name} +
+
+

+ Date Joined: +

+ + + +
+
+
+
+ ); +}; diff --git a/ui/lib/helper.ts b/ui/lib/helper.ts index 5b6d2ec8f2..9c031b4e78 100644 --- a/ui/lib/helper.ts +++ b/ui/lib/helper.ts @@ -89,3 +89,97 @@ export const getErrorMessage = async (error: unknown): Promise => { } return message; }; + +export const regions = [ + // AWS Regions (ordered by usage) + { key: "us-east-1", label: "AWS - US East 1" }, + { key: "us-west-1", label: "AWS - US West 1" }, + { key: "us-west-2", label: "AWS - US West 2" }, + { key: "eu-west-1", label: "AWS - EU West 1" }, + { key: "eu-central-1", label: "AWS - EU Central 1" }, + { key: "ap-southeast-1", label: "AWS - AP Southeast 1" }, + { key: "ap-northeast-1", label: "AWS - AP Northeast 1" }, + { key: "ap-southeast-2", label: "AWS - AP Southeast 2" }, + { key: "ca-central-1", label: "AWS - CA Central 1" }, + { key: "sa-east-1", label: "AWS - SA East 1" }, + { key: "af-south-1", label: "AWS - AF South 1" }, + { key: "ap-east-1", label: "AWS - AP East 1" }, + { key: "ap-northeast-2", label: "AWS - AP Northeast 2" }, + { key: "ap-northeast-3", label: "AWS - AP Northeast 3" }, + { key: "ap-south-1", label: "AWS - AP South 1" }, + { key: "ap-south-2", label: "AWS - AP South 2" }, + { key: "ap-southeast-3", label: "AWS - AP Southeast 3" }, + { key: "ap-southeast-4", label: "AWS - AP Southeast 4" }, + { key: "ca-west-1", label: "AWS - CA West 1" }, + { key: "eu-central-2", label: "AWS - EU Central 2" }, + { key: "eu-north-1", label: "AWS - EU North 1" }, + { key: "eu-south-1", label: "AWS - EU South 1" }, + { key: "eu-south-2", label: "AWS - EU South 2" }, + { key: "eu-west-2", label: "AWS - EU West 2" }, + { key: "eu-west-3", label: "AWS - EU West 3" }, + { key: "il-central-1", label: "AWS - IL Central 1" }, + { key: "me-central-1", label: "AWS - ME Central 1" }, + { key: "me-south-1", label: "AWS - ME South 1" }, + + // Azure Regions (ordered by usage) + { key: "eastus", label: "Azure - East US" }, + { key: "eastus2", label: "Azure - East US 2" }, + { key: "westeurope", label: "Azure - West Europe" }, + { key: "southeastasia", label: "Azure - Southeast Asia" }, + { key: "uksouth", label: "Azure - UK South" }, + { key: "northeurope", label: "Azure - North Europe" }, + { key: "centralus", label: "Azure - Central US" }, + { key: "westus2", label: "Azure - West US 2" }, + { key: "southcentralus", label: "Azure - South Central US" }, + { key: "australiaeast", label: "Azure - Australia East" }, + { key: "canadacentral", label: "Azure - Canada Central" }, + { key: "japaneast", label: "Azure - Japan East" }, + { key: "koreacentral", label: "Azure - Korea Central" }, + { key: "southafricanorth", label: "Azure - South Africa North" }, + { key: "brazilsouth", label: "Azure - Brazil South" }, + { key: "francecentral", label: "Azure - France Central" }, + { key: "germanywestcentral", label: "Azure - Germany West Central" }, + { key: "switzerlandnorth", label: "Azure - Switzerland North" }, + { key: "uaenorth", label: "Azure - UAE North" }, + // Remaining Azure Regions (less frequently used) + { key: "westus", label: "Azure - West US" }, + { key: "northcentralus", label: "Azure - North Central US" }, + { key: "australiasoutheast", label: "Azure - Australia Southeast" }, + { key: "southindia", label: "Azure - South India" }, + { key: "westindia", label: "Azure - West India" }, + { key: "canadaeast", label: "Azure - Canada East" }, + { key: "francesouth", label: "Azure - France South" }, + { key: "norwayeast", label: "Azure - Norway East" }, + { key: "switzerlandwest", label: "Azure - Switzerland West" }, + { key: "ukwest", label: "Azure - UK West" }, + { key: "uaecentral", label: "Azure - UAE Central" }, + { key: "brazilsoutheast", label: "Azure - Brazil Southeast" }, + + // GCP Regions (ordered by usage) + { key: "us-central1", label: "GCP - US Central (Iowa)" }, + { key: "us-east1", label: "GCP - US East (South Carolina)" }, + { key: "us-west1", label: "GCP - US West (Oregon)" }, + { key: "europe-west1", label: "GCP - Europe West (Belgium)" }, + { key: "asia-east1", label: "GCP - Asia East (Taiwan)" }, + { key: "asia-northeast1", label: "GCP - Asia Northeast (Tokyo)" }, + { key: "europe-west2", label: "GCP - Europe West (London)" }, + { key: "europe-west3", label: "GCP - Europe West (Frankfurt)" }, + { key: "europe-west4", label: "GCP - Europe West (Netherlands)" }, + { key: "asia-southeast1", label: "GCP - Asia Southeast (Singapore)" }, + { key: "australia-southeast1", label: "GCP - Australia Southeast (Sydney)" }, + { + key: "northamerica-northeast1", + label: "GCP - North America Northeast (Montreal)", + }, + // Remaining GCP Regions + { key: "asia-east2", label: "GCP - Asia East (Hong Kong)" }, + { key: "asia-northeast2", label: "GCP - Asia Northeast (Osaka)" }, + { key: "asia-northeast3", label: "GCP - Asia Northeast (Seoul)" }, + { key: "asia-south1", label: "GCP - Asia South (Mumbai)" }, + { key: "asia-southeast2", label: "GCP - Asia Southeast (Jakarta)" }, + { key: "europe-north1", label: "GCP - Europe North (Finland)" }, + { key: "europe-west6", label: "GCP - Europe West (Zurich)" }, + { key: "southamerica-east1", label: "GCP - South America East (São Paulo)" }, + { key: "us-west2", label: "GCP - US West (Los Angeles)" }, + { key: "us-east4", label: "GCP - US East (Northern Virginia)" }, +]; diff --git a/ui/types/components.ts b/ui/types/components.ts index ffe10216e0..0eca498945 100644 --- a/ui/types/components.ts +++ b/ui/types/components.ts @@ -227,6 +227,32 @@ export interface InvitationProps { self: string; }; } +export interface UserProfileProps { + data: { + type: "users"; + id: string; + attributes: { + name: string; + email: string; + company_name: string; + date_joined: string; + }; + relationships: { + memberships: { + meta: { + count: number; + }; + data: Array<{ + type: "memberships"; + id: string; + }>; + }; + }; + }; + meta: { + version: string; + }; +} export interface UserProps { type: "users"; From d5187b3099d942ae4ae50e25427289bce69dc12d Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Thu, 28 Nov 2024 12:55:31 +0100 Subject: [PATCH 3/8] chore(auth): restore auth file and move the server action to user file (#5951) --- ui/actions/auth/auth.ts | 31 ------------------------------- ui/actions/users/users.ts | 28 ++++++++++++++++++++++++++++ ui/app/(prowler)/profile/page.tsx | 2 +- 3 files changed, 29 insertions(+), 32 deletions(-) diff --git a/ui/actions/auth/auth.ts b/ui/actions/auth/auth.ts index 19e0c62a38..1bbc79b17e 100644 --- a/ui/actions/auth/auth.ts +++ b/ui/actions/auth/auth.ts @@ -1,12 +1,9 @@ "use server"; -import { revalidatePath } from "next/cache"; import { AuthError } from "next-auth"; import { z } from "zod"; import { signIn, signOut } from "@/auth.config"; -import { auth } from "@/auth.config"; -import { parseStringify } from "@/lib"; import { authFormSchema } from "@/types"; const formSchemaSignIn = authFormSchema("sign-in"); @@ -142,34 +139,6 @@ export const getToken = async (formData: z.infer) => { } }; -export const getProfileInfo = async () => { - const session = await auth(); - const keyServer = process.env.API_BASE_URL; - const url = new URL(`${keyServer}/users/me`); - - try { - const response = await fetch(url.toString(), { - method: "GET", - headers: { - Accept: "application/vnd.api+json", - Authorization: `Bearer ${session?.accessToken}`, - }, - }); - - if (!response.ok) { - throw new Error(`Failed to fetch user data: ${response.statusText}`); - } - - const data = await response.json(); - const parsedData = parseStringify(data); - revalidatePath("/profile"); - return parsedData; - } catch (error) { - console.error("Error fetching profile:", error); - return undefined; - } -}; - export const getUserByMe = async (accessToken: string) => { const keyServer = process.env.API_BASE_URL; const url = new URL(`${keyServer}/users/me`); diff --git a/ui/actions/users/users.ts b/ui/actions/users/users.ts index 30a5b26d1f..cf3397a940 100644 --- a/ui/actions/users/users.ts +++ b/ui/actions/users/users.ts @@ -114,3 +114,31 @@ export const deleteUser = async (formData: FormData) => { }; } }; + +export const getProfileInfo = async () => { + const session = await auth(); + const keyServer = process.env.API_BASE_URL; + const url = new URL(`${keyServer}/users/me`); + + try { + const response = await fetch(url.toString(), { + method: "GET", + headers: { + Accept: "application/vnd.api+json", + Authorization: `Bearer ${session?.accessToken}`, + }, + }); + + if (!response.ok) { + throw new Error(`Failed to fetch user data: ${response.statusText}`); + } + + const data = await response.json(); + const parsedData = parseStringify(data); + revalidatePath("/profile"); + return parsedData; + } catch (error) { + console.error("Error fetching profile:", error); + return undefined; + } +}; diff --git a/ui/app/(prowler)/profile/page.tsx b/ui/app/(prowler)/profile/page.tsx index 26d46a4380..e09aeae757 100644 --- a/ui/app/(prowler)/profile/page.tsx +++ b/ui/app/(prowler)/profile/page.tsx @@ -1,7 +1,7 @@ import { Spacer } from "@nextui-org/react"; import React, { Suspense } from "react"; -import { getProfileInfo } from "@/actions/auth"; +import { getProfileInfo } from "@/actions/users/users"; import { Header } from "@/components/ui"; import { SkeletonUserInfo } from "@/components/users/profile"; import { UserInfo } from "@/components/users/profile/user-info"; From af815287ed412abcc551d1f5f6f8ec9ae031fc9d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Nov 2024 09:11:17 -0400 Subject: [PATCH 4/8] chore(deps-dev): bump bandit from 1.7.10 to 1.8.0 (#5943) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 10 +++++----- pyproject.toml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index 3bfa70b6cf..ea4545aaf5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -694,13 +694,13 @@ dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] [[package]] name = "bandit" -version = "1.7.10" +version = "1.8.0" description = "Security oriented static analyser for python code." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "bandit-1.7.10-py3-none-any.whl", hash = "sha256:665721d7bebbb4485a339c55161ac0eedde27d51e638000d91c8c2d68343ad02"}, - {file = "bandit-1.7.10.tar.gz", hash = "sha256:59ed5caf5d92b6ada4bf65bc6437feea4a9da1093384445fed4d472acc6cff7b"}, + {file = "bandit-1.8.0-py3-none-any.whl", hash = "sha256:b1a61d829c0968aed625381e426aa378904b996529d048f8d908fa28f6b13e38"}, + {file = "bandit-1.8.0.tar.gz", hash = "sha256:b5bfe55a095abd9fe20099178a7c6c060f844bfd4fe4c76d28e35e4c52b9d31e"}, ] [package.dependencies] @@ -5194,4 +5194,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.13" -content-hash = "6a868e7040647c561274f7bb54dd5a899690d2b8dc658559c9de7e175debee6e" +content-hash = "1c4e3f619bfc461c022448d3a43775baf01bcbd8f5972ae4f394da2e059fdb2c" diff --git a/pyproject.toml b/pyproject.toml index 582896a6c6..13a21d1641 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -75,7 +75,7 @@ tabulate = "0.9.0" tzlocal = "5.2" [tool.poetry.group.dev.dependencies] -bandit = "1.7.10" +bandit = "1.8.0" black = "24.10.0" coverage = "7.6.8" docker = "7.1.0" From 70e327a3c11018b3a1ba429089b3c8843a4f3cc7 Mon Sep 17 00:00:00 2001 From: Prowler Bot Date: Thu, 28 Nov 2024 14:11:29 +0100 Subject: [PATCH 5/8] chore(regions_update): Changes in regions for AWS services (#5947) Co-authored-by: sergargar <38561120+sergargar@users.noreply.github.com> --- prowler/providers/aws/aws_regions_by_service.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/prowler/providers/aws/aws_regions_by_service.json b/prowler/providers/aws/aws_regions_by_service.json index f8ec725446..cfc75a2e06 100644 --- a/prowler/providers/aws/aws_regions_by_service.json +++ b/prowler/providers/aws/aws_regions_by_service.json @@ -9265,10 +9265,7 @@ "us-west-2" ], "aws-cn": [], - "aws-us-gov": [ - "us-gov-east-1", - "us-gov-west-1" - ] + "aws-us-gov": [] } }, "sagemaker-runtime": { From 9bf3171cfa0c28f287619348ff362a43695bf32b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Nov 2024 11:57:35 -0400 Subject: [PATCH 6/8] chore(deps): bump botocore from 1.35.70 to 1.35.71 (#5944) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- poetry.lock | 8 ++++---- pyproject.toml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/poetry.lock b/poetry.lock index ea4545aaf5..daa6170f55 100644 --- a/poetry.lock +++ b/poetry.lock @@ -794,13 +794,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.35.70" +version = "1.35.71" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" files = [ - {file = "botocore-1.35.70-py3-none-any.whl", hash = "sha256:ba8a4797cf7c5d9c237e67a62692f5146e895613fd3e6a43b00b66f3a8c7fc73"}, - {file = "botocore-1.35.70.tar.gz", hash = "sha256:18d1bb505722d9efd50c50719ed8de7284bfe6d3908a9e08756a7646e549da21"}, + {file = "botocore-1.35.71-py3-none-any.whl", hash = "sha256:fc46e7ab1df3cef66dfba1633f4da77c75e07365b36f03bd64a3793634be8fc1"}, + {file = "botocore-1.35.71.tar.gz", hash = "sha256:f9fa058e0393660c3fe53c1e044751beb64b586def0bd2212448a7c328b0cbba"}, ] [package.dependencies] @@ -5194,4 +5194,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = ">=3.9,<3.13" -content-hash = "1c4e3f619bfc461c022448d3a43775baf01bcbd8f5972ae4f394da2e059fdb2c" +content-hash = "6e51c3d50d88e8bb5d91b7ace1aa07d599fad4b151465355e51c573a5ad41d85" diff --git a/pyproject.toml b/pyproject.toml index 13a21d1641..c0eab018ea 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,7 @@ azure-mgmt-subscription = "3.1.1" azure-mgmt-web = "7.3.1" azure-storage-blob = "12.24.0" boto3 = "1.35.70" -botocore = "1.35.70" +botocore = "1.35.71" colorama = "0.4.6" cryptography = "43.0.1" dash = "2.18.2" From bcf1ef1d31364da930007f6b652dbbed11b9e5de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pedro=20Mart=C3=ADn?= Date: Thu, 28 Nov 2024 18:06:06 +0100 Subject: [PATCH 7/8] chore(check): remove custom_report_interface (#5955) --- prowler/lib/check/check.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/prowler/lib/check/check.py b/prowler/lib/check/check.py index fc648ffc04..d760702fa8 100644 --- a/prowler/lib/check/check.py +++ b/prowler/lib/check/check.py @@ -556,19 +556,6 @@ def execute_checks( bar() bar.title = f"-> {Fore.GREEN}Scan completed!{Style.RESET_ALL}" - # Custom report interface - if os.environ.get("PROWLER_REPORT_LIB_PATH"): - try: - logger.info("Using custom report interface ...") - lib = os.environ["PROWLER_REPORT_LIB_PATH"] - outputs_module = importlib.import_module(lib) - custom_report_interface = getattr(outputs_module, "report") - - # TODO: review this call and see if we can remove the global_provider.output_options since it is contained in the global_provider - custom_report_interface(check_findings, output_options, global_provider) - except Exception: - sys.exit(1) - return all_findings From 6dea923866a3ab77b58e3fd3c8457f6bb67fb254 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Fri, 29 Nov 2024 06:54:38 +0100 Subject: [PATCH 8/8] chore(codebase) Update/UI code base (#5960) --- ui/actions/auth/auth.ts | 37 +++++++--- ui/app/(prowler)/compliance/page.tsx | 2 + ui/auth.config.ts | 1 + ui/components/auth/oss/auth-form.tsx | 12 ++- ui/components/compliance/compliance-card.tsx | 13 +++- .../data-compliance/data-compliance.tsx | 10 ++- .../via-credentials/k8s-credentials-form.tsx | 10 +-- ui/components/ui/custom/custom-textarea.tsx | 74 +++++++++++++++++++ ui/components/ui/custom/index.ts | 1 + 9 files changed, 138 insertions(+), 22 deletions(-) create mode 100644 ui/components/ui/custom/custom-textarea.tsx diff --git a/ui/actions/auth/auth.ts b/ui/actions/auth/auth.ts index 1bbc79b17e..d39314d2da 100644 --- a/ui/actions/auth/auth.ts +++ b/ui/actions/auth/auth.ts @@ -37,6 +37,10 @@ export async function authenticate( credentials: "Incorrect email or password", }, }; + case "CallbackRouteError": + return { + message: error.cause?.err?.message, + }; default: return { message: "Unknown error", @@ -152,22 +156,31 @@ export const getUserByMe = async (accessToken: string) => { }, }); - if (!response.ok) throw new Error("Error in trying to get user by me"); - const parsedResponse = await response.json(); + if (!response.ok) { + // Handle different HTTP error codes + switch (response.status) { + case 401: + throw new Error("Invalid or expired token"); + case 403: + throw new Error(parsedResponse.errors?.[0]?.detail); + case 404: + throw new Error("User not found"); + default: + throw new Error( + parsedResponse.errors?.[0]?.detail || "Unknown error", + ); + } + } - const name = parsedResponse.data.attributes.name; - const email = parsedResponse.data.attributes.email; - const company = parsedResponse.data.attributes.company_name; - const dateJoined = parsedResponse.data.attributes.date_joined; return { - name, - email, - company, - dateJoined, + name: parsedResponse.data.attributes.name, + email: parsedResponse.data.attributes.email, + company: parsedResponse.data.attributes.company_name, + dateJoined: parsedResponse.data.attributes.date_joined, }; - } catch (error) { - throw new Error("Error in trying to get user by me"); + } catch (error: any) { + throw new Error(error.message || "Network error or server unreachable"); } }; diff --git a/ui/app/(prowler)/compliance/page.tsx b/ui/app/(prowler)/compliance/page.tsx index 1bc58ad741..558caeaf9b 100644 --- a/ui/app/(prowler)/compliance/page.tsx +++ b/ui/app/(prowler)/compliance/page.tsx @@ -140,6 +140,7 @@ const SSRComplianceGrid = async ({ const { attributes } = compliance; const { framework, + version, requirements_status: { passed, total }, } = attributes; @@ -147,6 +148,7 @@ const SSRComplianceGrid = async ({ { const formSchema = authFormSchema(type); const router = useRouter(); @@ -47,7 +49,6 @@ export const AuthForm = ({ email: data.email.toLowerCase(), password: data.password, }); - if (result?.message === "Success") { router.push("/"); } else if (result?.errors && "credentials" in result.errors) { @@ -55,6 +56,8 @@ export const AuthForm = ({ type: "server", message: result.errors.credentials ?? "Incorrect email or password", }); + } else if (result?.message === "User email is not verified") { + router.push("/email-verification"); } else { toast({ variant: "destructive", @@ -73,7 +76,12 @@ export const AuthForm = ({ description: "The user was registered successfully.", }); form.reset(); - router.push("/sign-in"); + + if (isCloudEnv) { + router.push("/email-verification"); + } else { + router.push("/sign-in"); + } } else { newUser.errors.forEach((error: ApiError) => { const errorMessage = error.detail; diff --git a/ui/components/compliance/compliance-card.tsx b/ui/components/compliance/compliance-card.tsx index 7fcfdbf5dd..b1b8d8ec10 100644 --- a/ui/components/compliance/compliance-card.tsx +++ b/ui/components/compliance/compliance-card.tsx @@ -6,6 +6,7 @@ import { getComplianceIcon } from "../icons"; interface ComplianceCardProps { title: string; + version: string; passingRequirements: number; totalRequirements: number; prevPassingRequirements: number; @@ -14,9 +15,14 @@ interface ComplianceCardProps { export const ComplianceCard: React.FC = ({ title, + version, passingRequirements, totalRequirements, }) => { + const formatTitle = (title: string) => { + return title.split("-").join(" "); + }; + const ratingPercentage = Math.floor( (passingRequirements / totalRequirements) * 100, ); @@ -47,7 +53,7 @@ export const ComplianceCard: React.FC = ({ }; return ( - +
= ({ className="h-10 w-10 min-w-10 rounded-md border-1 border-gray-300 bg-white object-contain p-1" />
-

{title}

+

+ {formatTitle(title)} + {version ? ` - ${version}` : ""} +

{ const searchParams = useSearchParams(); const [showClearButton, setShowClearButton] = useState(false); const scanIdParam = searchParams.get("scanId"); - const selectedScanId = scanIdParam || scans[0]?.id; + const selectedScanId = scanIdParam || (scans.length > 0 ? scans[0].id : ""); + + useEffect(() => { + if (!scanIdParam && scans.length > 0) { + const params = new URLSearchParams(searchParams); + params.set("scanId", scans[0].id); + router.push(`?${params.toString()}`); + } + }, [scans, scanIdParam, searchParams, router]); useEffect(() => { const hasFilters = Array.from(searchParams.keys()).some( diff --git a/ui/components/providers/workflow/forms/via-credentials/k8s-credentials-form.tsx b/ui/components/providers/workflow/forms/via-credentials/k8s-credentials-form.tsx index 0725d134eb..3e6caeca88 100644 --- a/ui/components/providers/workflow/forms/via-credentials/k8s-credentials-form.tsx +++ b/ui/components/providers/workflow/forms/via-credentials/k8s-credentials-form.tsx @@ -1,6 +1,6 @@ import { Control } from "react-hook-form"; -import { CustomInput } from "@/components/ui/custom"; +import { CustomTextarea } from "@/components/ui/custom"; import { KubernetesCredentials } from "@/types"; export const KubernetesCredentialsForm = ({ @@ -15,17 +15,17 @@ export const KubernetesCredentialsForm = ({ Connect via Credentials
- Please provide the information for your Kubernetes credentials. + Please provide the kubeconfig content for your Kubernetes credentials.
- diff --git a/ui/components/ui/custom/custom-textarea.tsx b/ui/components/ui/custom/custom-textarea.tsx new file mode 100644 index 0000000000..c3f6dc0994 --- /dev/null +++ b/ui/components/ui/custom/custom-textarea.tsx @@ -0,0 +1,74 @@ +"use client"; + +import { Textarea } from "@nextui-org/input"; +import React from "react"; +import { Control, FieldPath, FieldValues } from "react-hook-form"; + +import { FormControl, FormField, FormMessage } from "@/components/ui/form"; + +interface CustomTextareaProps { + control: Control; + name: FieldPath; + label?: string; + labelPlacement?: "inside" | "outside" | "outside-left"; + variant?: "flat" | "bordered" | "underlined" | "faded"; + size?: "sm" | "md" | "lg"; + placeholder?: string; + defaultValue?: string; + isRequired?: boolean; + isInvalid?: boolean; + minRows?: number; + maxRows?: number; + fullWidth?: boolean; + disableAutosize?: boolean; + description?: React.ReactNode; +} + +export const CustomTextarea = ({ + control, + name, + label = name, + labelPlacement = "inside", + placeholder, + variant = "flat", + size = "md", + defaultValue, + isRequired = false, + isInvalid = false, + minRows = 3, + maxRows = 8, + fullWidth = true, + disableAutosize = false, + description, +}: CustomTextareaProps) => { + return ( + ( + <> + +