From a5187c6a4247e0d4f624b8a663bd84a573918134 Mon Sep 17 00:00:00 2001 From: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com> Date: Mon, 4 Aug 2025 16:04:10 +0200 Subject: [PATCH 1/2] feat(ui): S3 integration retouches (#8438) --- ui/app/(prowler)/integrations/page.tsx | 1 - ui/app/(prowler)/integrations/s3/page.tsx | 2 +- .../integrations/s3/s3-integration-card.tsx | 21 ++++++++----------- .../integrations/s3/s3-integration-form.tsx | 15 +++++++------ .../s3/s3-integrations-manager.tsx | 10 ++++++--- ui/components/ui/custom/custom-link.tsx | 2 +- ui/hooks/use-credentials-form.ts | 2 +- 7 files changed, 28 insertions(+), 25 deletions(-) diff --git a/ui/app/(prowler)/integrations/page.tsx b/ui/app/(prowler)/integrations/page.tsx index c9f03b6770..7270334756 100644 --- a/ui/app/(prowler)/integrations/page.tsx +++ b/ui/app/(prowler)/integrations/page.tsx @@ -11,7 +11,6 @@ export default async function Integrations() {
-

Available Integrations

Connect external services to enhance your security workflow and automatically export your scan results. diff --git a/ui/app/(prowler)/integrations/s3/page.tsx b/ui/app/(prowler)/integrations/s3/page.tsx index 8a5c0c09fb..9243130d17 100644 --- a/ui/app/(prowler)/integrations/s3/page.tsx +++ b/ui/app/(prowler)/integrations/s3/page.tsx @@ -36,7 +36,7 @@ export default async function S3Integrations() {

  • - Multiple bucket support + Multi-Cloud support
  • diff --git a/ui/components/integrations/s3/s3-integration-card.tsx b/ui/components/integrations/s3/s3-integration-card.tsx index 9e78b79592..f0833b246f 100644 --- a/ui/components/integrations/s3/s3-integration-card.tsx +++ b/ui/components/integrations/s3/s3-integration-card.tsx @@ -2,10 +2,10 @@ import { Card, CardBody, CardHeader, Chip } from "@nextui-org/react"; import { SettingsIcon } from "lucide-react"; -import Link from "next/link"; import { AmazonS3Icon } from "@/components/icons/services/IconServices"; import { CustomButton } from "@/components/ui/custom"; +import { CustomLink } from "@/components/ui/custom/custom-link"; import { IntegrationProps } from "@/types/integrations"; import { S3IntegrationCardSkeleton } from "./skeleton-s3-integration-card"; @@ -40,31 +40,28 @@ export const S3IntegrationCard = ({ return ( -
    +

    Amazon S3

    -
    -

    +

    +

    Export security findings to Amazon S3 buckets.

    - {/* Todo: add real DOCS, use CustomLink when available */} - Learn more - +
    -
    +
    {isConfigured && ( p.id) || [], - credentials_type: "aws-sdk-default" as const, + credentials_type: "access-secret-key" as const, aws_access_key_id: "", aws_secret_access_key: "", aws_session_token: "", @@ -372,6 +372,7 @@ export const S3IntegrationForm = ({ submitText="Create Integration" cancelText="Back" loadingText="Creating..." + leftIcon={} isDisabled={isLoading} /> ); @@ -392,16 +393,18 @@ export const S3IntegrationForm = ({ className="flex flex-col space-y-6" >
    -

    - Need help connecting your AWS account? +

    +

    + Need help configuring your Amazon S3 integrations? +

    Read the docs -

    +
    {renderStepContent()}
    {renderStepButtons()} diff --git a/ui/components/integrations/s3/s3-integrations-manager.tsx b/ui/components/integrations/s3/s3-integrations-manager.tsx index bf0386e40b..e1e9c49641 100644 --- a/ui/components/integrations/s3/s3-integrations-manager.tsx +++ b/ui/components/integrations/s3/s3-integrations-manager.tsx @@ -1,6 +1,7 @@ "use client"; import { Card, CardBody, CardHeader, Chip } from "@nextui-org/react"; +import { format } from "date-fns"; import { PlusIcon, Power, @@ -314,9 +315,12 @@ export const S3IntegrationsManager = ({ {integration.attributes.connection_last_checked_at && (

    Last checked:{" "} - {new Date( - integration.attributes.connection_last_checked_at, - ).toLocaleDateString()} + {format( + new Date( + integration.attributes.connection_last_checked_at, + ), + "yyyy/MM/dd", + )}

    )}
    diff --git a/ui/components/ui/custom/custom-link.tsx b/ui/components/ui/custom/custom-link.tsx index d52fbeaca2..6fa06244d2 100644 --- a/ui/components/ui/custom/custom-link.tsx +++ b/ui/components/ui/custom/custom-link.tsx @@ -34,7 +34,7 @@ export const CustomLink = React.forwardRef( href={href} scroll={scroll} className={cn( - `text-${size} break-all font-medium text-primary decoration-1 hover:underline`, + `text-${size} text-nowrap break-all font-medium text-primary decoration-1 hover:underline`, className, )} aria-label={ariaLabel} diff --git a/ui/hooks/use-credentials-form.ts b/ui/hooks/use-credentials-form.ts index 317d1749ae..0180c06431 100644 --- a/ui/hooks/use-credentials-form.ts +++ b/ui/hooks/use-credentials-form.ts @@ -66,7 +66,7 @@ export const useCredentialsForm = ({ if (providerType === "aws" && via === "role") { return { ...baseDefaults, - [ProviderCredentialFields.CREDENTIALS_TYPE]: "aws-sdk-default", + [ProviderCredentialFields.CREDENTIALS_TYPE]: "access-secret-key", [ProviderCredentialFields.ROLE_ARN]: "", [ProviderCredentialFields.EXTERNAL_ID]: session?.tenantId || "", [ProviderCredentialFields.AWS_ACCESS_KEY_ID]: "", From c748e57878beadbb6703d5743982f43d49134226 Mon Sep 17 00:00:00 2001 From: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com> Date: Mon, 4 Aug 2025 17:49:04 +0200 Subject: [PATCH 2/2] feat: manage integration permission behavior (#8441) Co-authored-by: Pepe Fagoaga --- ui/actions/roles/roles.ts | 3 +-- ui/components/roles/workflow/forms/add-role-form.tsx | 4 +++- .../roles/workflow/forms/edit-role-form.tsx | 2 +- ui/components/ui/sidebar/menu.tsx | 4 ++++ ui/lib/helper.ts | 12 ++++++------ ui/middleware.ts | 7 +++++++ ui/types/formSchemas.ts | 4 ++-- 7 files changed, 24 insertions(+), 12 deletions(-) diff --git a/ui/actions/roles/roles.ts b/ui/actions/roles/roles.ts index d0dd07bd9a..e69300ab26 100644 --- a/ui/actions/roles/roles.ts +++ b/ui/actions/roles/roles.ts @@ -120,8 +120,7 @@ export const addRole = async (formData: FormData) => { manage_providers: formData.get("manage_providers") === "true", manage_scans: formData.get("manage_scans") === "true", manage_account: formData.get("manage_account") === "true", - // TODO: Add back when we have integrations ready - // manage_integrations: formData.get("manage_integrations") === "true", + manage_integrations: formData.get("manage_integrations") === "true", unlimited_visibility: formData.get("unlimited_visibility") === "true", }, relationships: {}, diff --git a/ui/components/roles/workflow/forms/add-role-form.tsx b/ui/components/roles/workflow/forms/add-role-form.tsx index 6b16dbd09a..a833cbe2c2 100644 --- a/ui/components/roles/workflow/forms/add-role-form.tsx +++ b/ui/components/roles/workflow/forms/add-role-form.tsx @@ -36,6 +36,7 @@ export const AddRoleForm = ({ name: "", manage_users: false, manage_providers: false, + manage_integrations: false, manage_scans: false, unlimited_visibility: false, groups: [], @@ -68,7 +69,7 @@ export const AddRoleForm = ({ "manage_account", "manage_billing", "manage_providers", - // "manage_integrations", + "manage_integrations", "manage_scans", "unlimited_visibility", ]; @@ -87,6 +88,7 @@ export const AddRoleForm = ({ formData.append("name", values.name); formData.append("manage_users", String(values.manage_users)); formData.append("manage_providers", String(values.manage_providers)); + formData.append("manage_integrations", String(values.manage_integrations)); formData.append("manage_scans", String(values.manage_scans)); formData.append("manage_account", String(values.manage_account)); formData.append( diff --git a/ui/components/roles/workflow/forms/edit-role-form.tsx b/ui/components/roles/workflow/forms/edit-role-form.tsx index 70f2161355..7573d40502 100644 --- a/ui/components/roles/workflow/forms/edit-role-form.tsx +++ b/ui/components/roles/workflow/forms/edit-role-form.tsx @@ -99,7 +99,7 @@ export const EditRoleForm = ({ updatedFields.manage_users = values.manage_users; updatedFields.manage_providers = values.manage_providers; updatedFields.manage_account = values.manage_account; - // updatedFields.manage_integrations = values.manage_integrations; + updatedFields.manage_integrations = values.manage_integrations; updatedFields.manage_scans = values.manage_scans; updatedFields.unlimited_visibility = values.unlimited_visibility; diff --git a/ui/components/ui/sidebar/menu.tsx b/ui/components/ui/sidebar/menu.tsx index 7a1e20f261..9ce1b2feb3 100644 --- a/ui/components/ui/sidebar/menu.tsx +++ b/ui/components/ui/sidebar/menu.tsx @@ -33,6 +33,10 @@ const MENU_HIDE_RULES: MenuHideRule[] = [ label: "Billing", condition: (permissions) => permissions?.manage_billing === false, }, + { + label: "Integrations", + condition: (permissions) => permissions?.manage_integrations === false, + }, // Add more rules as needed: // { // label: "Users", diff --git a/ui/lib/helper.ts b/ui/lib/helper.ts index 6e0b89fbbb..61b431c7c9 100644 --- a/ui/lib/helper.ts +++ b/ui/lib/helper.ts @@ -322,12 +322,12 @@ export const permissionFormFields: PermissionInfo[] = [ description: "Allows configuration and management of cloud provider connections", }, - // { - // field: "manage_integrations", - // label: "Manage Integrations", - // description: - // "Controls the setup and management of third-party integrations", - // }, + { + field: "manage_integrations", + label: "Manage Integrations", + description: + "Allows configuration and management of third-party integrations", + }, { field: "manage_scans", label: "Manage Scans", diff --git a/ui/middleware.ts b/ui/middleware.ts index 54116aaa57..d332bc03e8 100644 --- a/ui/middleware.ts +++ b/ui/middleware.ts @@ -29,6 +29,13 @@ export default auth((req: NextRequest & { auth: any }) => { if (pathname.startsWith("/billing") && !permissions.manage_billing) { return NextResponse.redirect(new URL("/profile", req.url)); } + + if ( + pathname.startsWith("/integrations") && + !permissions.manage_integrations + ) { + return NextResponse.redirect(new URL("/profile", req.url)); + } } return NextResponse.next(); diff --git a/ui/types/formSchemas.ts b/ui/types/formSchemas.ts index b1deadf489..5b1891379f 100644 --- a/ui/types/formSchemas.ts +++ b/ui/types/formSchemas.ts @@ -11,7 +11,7 @@ export const addRoleFormSchema = z.object({ manage_account: z.boolean().default(false), manage_billing: z.boolean().default(false), manage_providers: z.boolean().default(false), - // manage_integrations: z.boolean().default(false), + manage_integrations: z.boolean().default(false), manage_scans: z.boolean().default(false), unlimited_visibility: z.boolean().default(false), groups: z.array(z.string()).optional(), @@ -23,7 +23,7 @@ export const editRoleFormSchema = z.object({ manage_account: z.boolean().default(false), manage_billing: z.boolean().default(false), manage_providers: z.boolean().default(false), - // manage_integrations: z.boolean().default(false), + manage_integrations: z.boolean().default(false), manage_scans: z.boolean().default(false), unlimited_visibility: z.boolean().default(false), groups: z.array(z.string()).optional(),