mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-23 20:42:02 +00:00
feat(providers): make external id field mandatory in the aws role secret form (#6656)
This commit is contained in:
@@ -175,13 +175,13 @@ export const addCredentialsProvider = async (formData: FormData) => {
|
||||
secretType = "role";
|
||||
secret = {
|
||||
role_arn: formData.get("role_arn"),
|
||||
external_id: formData.get("external_id"),
|
||||
aws_access_key_id: formData.get("aws_access_key_id") || undefined,
|
||||
aws_secret_access_key:
|
||||
formData.get("aws_secret_access_key") || undefined,
|
||||
aws_session_token: formData.get("aws_session_token") || undefined,
|
||||
session_duration:
|
||||
parseInt(formData.get("session_duration") as string, 10) || 3600,
|
||||
external_id: formData.get("external_id") || undefined,
|
||||
role_session_name: formData.get("role_session_name") || undefined,
|
||||
};
|
||||
} else {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import React from "react";
|
||||
import React, { Suspense } from "react";
|
||||
|
||||
import { getProvider } from "@/actions/providers";
|
||||
import { LaunchScanForm } from "@/components/providers/workflow/forms";
|
||||
import { SkeletonProviderWorkflow } from "@/components/providers/workflow/skeleton-provider-workflow";
|
||||
|
||||
interface Props {
|
||||
searchParams: { type: string; id: string };
|
||||
@@ -26,6 +27,23 @@ export default async function LaunchScanPage({ searchParams }: Props) {
|
||||
redirect("/providers/connect-account");
|
||||
}
|
||||
|
||||
return (
|
||||
<Suspense fallback={<SkeletonProviderWorkflow />}>
|
||||
<SSRLaunchScan searchParams={searchParams} />
|
||||
</Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
async function SSRLaunchScan({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: { type: string; id: string };
|
||||
}) {
|
||||
const formData = new FormData();
|
||||
formData.append("id", searchParams.id);
|
||||
|
||||
const providerData = await getProvider(formData);
|
||||
|
||||
return (
|
||||
<LaunchScanForm searchParams={searchParams} providerData={providerData} />
|
||||
);
|
||||
|
||||
@@ -2,6 +2,7 @@ import { redirect } from "next/navigation";
|
||||
import React, { Suspense } from "react";
|
||||
|
||||
import { getProvider } from "@/actions/providers";
|
||||
import { SkeletonProviderWorkflow } from "@/components/providers/workflow";
|
||||
import { TestConnectionForm } from "@/components/providers/workflow/forms";
|
||||
|
||||
interface Props {
|
||||
@@ -16,7 +17,7 @@ export default async function TestConnectionPage({ searchParams }: Props) {
|
||||
}
|
||||
|
||||
return (
|
||||
<Suspense fallback={<p>Loading...</p>}>
|
||||
<Suspense fallback={<SkeletonProviderWorkflow />}>
|
||||
<SSRTestConnection searchParams={searchParams} />
|
||||
</Suspense>
|
||||
);
|
||||
|
||||
@@ -93,10 +93,8 @@ export const LaunchScanForm = ({
|
||||
className="flex flex-col space-y-4"
|
||||
>
|
||||
<div className="text-left">
|
||||
<div className="text-2xl font-bold leading-9 text-default-foreground">
|
||||
Scan started
|
||||
</div>
|
||||
<div className="py-2 text-default-500">
|
||||
<div className="mb-1 text-xl font-medium">Scan started</div>
|
||||
<div className="py-2 text-small text-default-500">
|
||||
The scan has just started. From now on, a new scan will be launched
|
||||
every 24 hours, starting from this moment.
|
||||
</div>
|
||||
|
||||
@@ -66,6 +66,7 @@ export const TestConnectionForm = ({
|
||||
error: string | null;
|
||||
} | null>(null);
|
||||
const [isResettingCredentials, setIsResettingCredentials] = useState(false);
|
||||
const [isRedirecting, setIsRedirecting] = useState(false);
|
||||
|
||||
const form = useForm<FormValues>({
|
||||
resolver: zodResolver(formSchema),
|
||||
@@ -129,9 +130,9 @@ export const TestConnectionForm = ({
|
||||
const isUpdated = urlParams.get("updated") === "true";
|
||||
|
||||
if (!isUpdated) {
|
||||
router.push(
|
||||
`/providers/launch-scan?type=${providerType}&id=${providerId}`,
|
||||
);
|
||||
setIsRedirecting(true);
|
||||
router.push("/scans");
|
||||
return;
|
||||
} else {
|
||||
setConnectionStatus({
|
||||
connected: true,
|
||||
@@ -191,6 +192,25 @@ export const TestConnectionForm = ({
|
||||
}
|
||||
};
|
||||
|
||||
if (isRedirecting) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center space-y-6 py-12">
|
||||
<div className="relative">
|
||||
<div className="h-24 w-24 animate-pulse rounded-full bg-primary/20" />
|
||||
<div className="absolute inset-0 h-24 w-24 animate-spin rounded-full border-4 border-primary border-t-transparent" />
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<p className="text-xl font-medium text-primary">
|
||||
Scan initiated successfully
|
||||
</p>
|
||||
<p className="mt-2 text-gray-500">
|
||||
Redirecting to scans dashboard...
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
@@ -198,13 +218,11 @@ export const TestConnectionForm = ({
|
||||
className="flex flex-col space-y-4"
|
||||
>
|
||||
<div className="text-left">
|
||||
<div className="text-2xl font-bold leading-9 text-default-foreground">
|
||||
Test connection
|
||||
<div className="mb-2 text-xl font-medium">
|
||||
Check connection and launch scan
|
||||
</div>
|
||||
<p className="py-2 text-default-500">
|
||||
Ensure all required credentials and configurations are completed
|
||||
accurately. A successful connection will enable the option to
|
||||
initiate a scan in the following step.
|
||||
<p className="py-2 text-small text-default-500">
|
||||
A successful connection will launch a daily scheduled scan.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -224,12 +242,12 @@ export const TestConnectionForm = ({
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<p className="text-danger">
|
||||
<p className="text-small text-danger">
|
||||
{connectionStatus.error || "Unknown error"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-md text-danger">
|
||||
<p className="text-small text-danger">
|
||||
It seems there was an issue with your credentials. Please review
|
||||
your credentials and try again.
|
||||
</p>
|
||||
@@ -243,11 +261,11 @@ export const TestConnectionForm = ({
|
||||
providerUID={providerData.data.attributes.uid}
|
||||
/>
|
||||
|
||||
{!isResettingCredentials && !connectionStatus?.error && (
|
||||
<p className="py-2 text-default-500">
|
||||
{/* {!isResettingCredentials && !connectionStatus?.error && (
|
||||
<p className="py-2 text-small text-default-500">
|
||||
Test connection and launch scan
|
||||
</p>
|
||||
)}
|
||||
)} */}
|
||||
|
||||
<input type="hidden" name="providerId" value={providerId} />
|
||||
|
||||
@@ -308,7 +326,7 @@ export const TestConnectionForm = ({
|
||||
<span>
|
||||
{isUpdated && connectionStatus?.connected
|
||||
? "Go to providers"
|
||||
: "Launch"}
|
||||
: "Launch scan"}
|
||||
</span>
|
||||
)}
|
||||
</CustomButton>
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import { Control, useForm } from "react-hook-form";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { Control, useForm, UseFormSetValue } from "react-hook-form";
|
||||
import * as z from "zod";
|
||||
|
||||
import { updateCredentialsProvider } from "@/actions/providers/providers";
|
||||
@@ -25,80 +26,119 @@ export const UpdateViaRoleForm = ({
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const { toast } = useToast();
|
||||
const { data: session } = useSession();
|
||||
|
||||
const searchParamsObj = useSearchParams();
|
||||
|
||||
// Handler for back button
|
||||
const handleBackStep = () => {
|
||||
const currentParams = new URLSearchParams(window.location.search);
|
||||
currentParams.delete("via");
|
||||
router.push(`?${currentParams.toString()}`);
|
||||
};
|
||||
|
||||
// Extract values from searchParams
|
||||
const providerType = searchParams.type;
|
||||
const providerId = searchParams.id;
|
||||
const providerSecretId = searchParams.secretId || "";
|
||||
const externalId = session?.tenantId;
|
||||
|
||||
const formSchema = addCredentialsRoleFormSchema(providerType);
|
||||
type FormSchemaType = z.infer<typeof formSchema>;
|
||||
type FormSchemaType = z.infer<typeof formSchema> & {
|
||||
credentials_type: "aws-sdk-default" | "access-secret-key";
|
||||
};
|
||||
|
||||
const form = useForm<FormSchemaType>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerId,
|
||||
providerType,
|
||||
...(providerType === "aws"
|
||||
? {
|
||||
role_arn: "",
|
||||
aws_access_key_id: "",
|
||||
aws_secret_access_key: "",
|
||||
aws_session_token: "",
|
||||
session_duration: 3600,
|
||||
external_id: "",
|
||||
role_session_name: "",
|
||||
}
|
||||
: {}),
|
||||
credentials_type: "aws-sdk-default",
|
||||
...(providerType === "aws" && {
|
||||
role_arn: "",
|
||||
external_id: externalId,
|
||||
aws_access_key_id: "",
|
||||
aws_secret_access_key: "",
|
||||
aws_session_token: "",
|
||||
role_session_name: "",
|
||||
session_duration: 3600,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
const isLoading = form.formState.isSubmitting;
|
||||
|
||||
// Handle form submission
|
||||
const onSubmitClient = async (values: FormSchemaType) => {
|
||||
const formData = new FormData();
|
||||
try {
|
||||
const formData = new FormData();
|
||||
|
||||
Object.entries(values).forEach(
|
||||
([key, value]) =>
|
||||
value !== undefined && formData.append(key, String(value)),
|
||||
);
|
||||
Object.entries(values).forEach(([key, value]) => {
|
||||
if (key === "credentials_type") return;
|
||||
|
||||
const data = await updateCredentialsProvider(providerSecretId, formData);
|
||||
if (
|
||||
values.credentials_type === "access-secret-key" &&
|
||||
[
|
||||
"aws_access_key_id",
|
||||
"aws_secret_access_key",
|
||||
"aws_session_token",
|
||||
].includes(key)
|
||||
) {
|
||||
if (value !== undefined && value !== "") {
|
||||
formData.append(key, String(value));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (data?.errors && data.errors.length > 0) {
|
||||
data.errors.forEach((error: ApiError) => {
|
||||
const errorMessage = error.detail;
|
||||
switch (error.source.pointer) {
|
||||
case "/data/attributes/secret/role_arn":
|
||||
form.setError("role_arn" as keyof FormSchemaType, {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Oops! Something went wrong",
|
||||
description: errorMessage,
|
||||
});
|
||||
if (value !== undefined && value !== "") {
|
||||
formData.append(key, String(value));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
router.push(
|
||||
`/providers/test-connection?type=${providerType}&id=${providerId}&updated=true`,
|
||||
);
|
||||
|
||||
const data = await updateCredentialsProvider(providerSecretId, formData);
|
||||
|
||||
// Handle errors
|
||||
if (data?.errors?.length) {
|
||||
data.errors.forEach((error: ApiError) => {
|
||||
const errorMessage = error.detail;
|
||||
switch (error.source.pointer) {
|
||||
case "/data/attributes/secret/role_arn":
|
||||
form.setError("role_arn" as keyof FormSchemaType, {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
case "/data/attributes/secret/external_id":
|
||||
form.setError("external_id" as keyof FormSchemaType, {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Oops! Something went wrong",
|
||||
description: errorMessage,
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// Redirect on success
|
||||
router.push(
|
||||
`/providers/test-connection?type=${providerType}&id=${providerId}&updated=true`,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error("Error during submission:", error);
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Submission failed",
|
||||
description: "An error occurred while processing your request.",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Handle back navigation
|
||||
const handleBackStep = () => {
|
||||
const currentParams = new URLSearchParams(window.location.search);
|
||||
currentParams.delete("via");
|
||||
router.push(`?${currentParams.toString()}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<Form {...form}>
|
||||
<form
|
||||
@@ -108,12 +148,18 @@ export const UpdateViaRoleForm = ({
|
||||
<input type="hidden" name="providerId" value={providerId} />
|
||||
<input type="hidden" name="providerType" value={providerType} />
|
||||
|
||||
{/* Conditional AWS Form */}
|
||||
{providerType === "aws" && (
|
||||
<AWSCredentialsRoleForm
|
||||
control={form.control as unknown as Control<AWSCredentialsRole>}
|
||||
setValue={
|
||||
form.setValue as unknown as UseFormSetValue<AWSCredentialsRole>
|
||||
}
|
||||
externalId={externalId || ""}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Action Buttons */}
|
||||
<div className="flex w-full justify-end sm:space-x-6">
|
||||
{searchParamsObj.get("via") === "role" && (
|
||||
<CustomButton
|
||||
@@ -132,7 +178,7 @@ export const UpdateViaRoleForm = ({
|
||||
)}
|
||||
<CustomButton
|
||||
type="submit"
|
||||
ariaLabel={"Save"}
|
||||
ariaLabel="Save"
|
||||
className="w-1/2"
|
||||
variant="solid"
|
||||
color="action"
|
||||
|
||||
@@ -14,7 +14,7 @@ export const AWScredentialsForm = ({
|
||||
<div className="text-2xl font-bold leading-9 text-default-foreground">
|
||||
Connect via Credentials
|
||||
</div>
|
||||
<div className="py-2 text-default-500">
|
||||
<div className="py-2 text-small text-default-500">
|
||||
Please provide the information for your AWS credentials.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { ChevronLeftIcon, ChevronRightIcon } from "lucide-react";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
import { Control, useForm } from "react-hook-form";
|
||||
import { useSession } from "next-auth/react";
|
||||
import { Control, useForm, UseFormSetValue } from "react-hook-form";
|
||||
import * as z from "zod";
|
||||
|
||||
import { addCredentialsProvider } from "@/actions/providers/providers";
|
||||
@@ -25,8 +26,9 @@ export const ViaRoleForm = ({
|
||||
}) => {
|
||||
const router = useRouter();
|
||||
const { toast } = useToast();
|
||||
|
||||
const { data: session } = useSession();
|
||||
const searchParamsObj = useSearchParams();
|
||||
const externalId = session?.tenantId;
|
||||
|
||||
// Handler for back button
|
||||
const handleBackStep = () => {
|
||||
@@ -39,22 +41,25 @@ export const ViaRoleForm = ({
|
||||
const providerId = searchParams.id;
|
||||
|
||||
const formSchema = addCredentialsRoleFormSchema(providerType);
|
||||
type FormSchemaType = z.infer<typeof formSchema>;
|
||||
type FormSchemaType = z.infer<typeof formSchema> & {
|
||||
credentials_type: "aws-sdk-default" | "access-secret-key";
|
||||
};
|
||||
|
||||
const form = useForm<FormSchemaType>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
providerId,
|
||||
providerType,
|
||||
credentials_type: "aws-sdk-default",
|
||||
...(providerType === "aws"
|
||||
? {
|
||||
role_arn: "",
|
||||
external_id: externalId,
|
||||
aws_access_key_id: "",
|
||||
aws_secret_access_key: "",
|
||||
aws_session_token: "",
|
||||
session_duration: 3600,
|
||||
external_id: "",
|
||||
role_session_name: "",
|
||||
session_duration: 3600,
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
@@ -65,36 +70,72 @@ export const ViaRoleForm = ({
|
||||
const onSubmitClient = async (values: FormSchemaType) => {
|
||||
const formData = new FormData();
|
||||
|
||||
Object.entries(values).forEach(
|
||||
([key, value]) =>
|
||||
value !== undefined && formData.append(key, String(value)),
|
||||
);
|
||||
Object.entries(values).forEach(([key, value]) => {
|
||||
// Do not include credentials_type
|
||||
if (key === "credentials_type") return;
|
||||
|
||||
const data = await addCredentialsProvider(formData);
|
||||
|
||||
if (data?.errors && data.errors.length > 0) {
|
||||
data.errors.forEach((error: ApiError) => {
|
||||
const errorMessage = error.detail;
|
||||
switch (error.source.pointer) {
|
||||
case "/data/attributes/secret/role_arn":
|
||||
form.setError("role_arn" as keyof FormSchemaType, {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
|
||||
default:
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Oops! Something went wrong",
|
||||
description: errorMessage,
|
||||
});
|
||||
// If credentials_type is "access-secret-key", include the relevant fields
|
||||
if (
|
||||
values.credentials_type === "access-secret-key" &&
|
||||
[
|
||||
"aws_access_key_id",
|
||||
"aws_secret_access_key",
|
||||
"aws_session_token",
|
||||
].includes(key)
|
||||
) {
|
||||
if (value !== undefined && value !== "") {
|
||||
formData.append(key, String(value));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Add any other valid field
|
||||
if (value !== undefined && value !== "") {
|
||||
formData.append(key, String(value));
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
const data = await addCredentialsProvider(formData);
|
||||
|
||||
if (data?.errors && data.errors.length > 0) {
|
||||
data.errors.forEach((error: ApiError) => {
|
||||
const errorMessage = error.detail;
|
||||
|
||||
switch (error.source.pointer) {
|
||||
case "/data/attributes/secret/role_arn":
|
||||
form.setError("role_arn" as keyof FormSchemaType, {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
case "/data/attributes/secret/external_id":
|
||||
form.setError("external_id" as keyof FormSchemaType, {
|
||||
type: "server",
|
||||
message: errorMessage,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Oops! Something went wrong",
|
||||
description: errorMessage,
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
router.push(
|
||||
`/providers/test-connection?type=${providerType}&id=${providerId}`,
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error("Error during submission:", error);
|
||||
toast({
|
||||
variant: "destructive",
|
||||
title: "Submission failed",
|
||||
description: "An error occurred while processing your request.",
|
||||
});
|
||||
} else {
|
||||
router.push(
|
||||
`/providers/test-connection?type=${providerType}&id=${providerId}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -110,6 +151,10 @@ export const ViaRoleForm = ({
|
||||
{providerType === "aws" && (
|
||||
<AWSCredentialsRoleForm
|
||||
control={form.control as unknown as Control<AWSCredentialsRole>}
|
||||
setValue={
|
||||
form.setValue as unknown as UseFormSetValue<AWSCredentialsRole>
|
||||
}
|
||||
externalId={externalId || ""}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
@@ -1,24 +1,95 @@
|
||||
import { Control } from "react-hook-form";
|
||||
import { Select, SelectItem, Spacer } from "@nextui-org/react";
|
||||
import { Control, UseFormSetValue, useWatch } from "react-hook-form";
|
||||
|
||||
import { CustomInput } from "@/components/ui/custom";
|
||||
import { AWSCredentialsRole } from "@/types";
|
||||
|
||||
export const AWSCredentialsRoleForm = ({
|
||||
control,
|
||||
setValue,
|
||||
externalId,
|
||||
}: {
|
||||
control: Control<AWSCredentialsRole>;
|
||||
setValue: UseFormSetValue<AWSCredentialsRole>;
|
||||
externalId: string;
|
||||
}) => {
|
||||
const credentialsType = useWatch({
|
||||
control,
|
||||
name: "credentials_type" as const,
|
||||
defaultValue: "aws-sdk-default",
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="mb-4 text-left">
|
||||
<div className="text-2xl font-bold leading-9 text-default-foreground">
|
||||
Connect assuming IAM Role
|
||||
</div>
|
||||
<div className="py-2 text-default-500">
|
||||
<div className="py-2 text-small text-default-500">
|
||||
Please provide the information for your AWS credentials.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span className="text-xs font-bold text-default-500">Authentication</span>
|
||||
|
||||
<Select
|
||||
name="credentials_type"
|
||||
label="Authentication Method"
|
||||
placeholder="Select credentials type"
|
||||
defaultSelectedKeys={["aws-sdk-default"]}
|
||||
className="mb-4"
|
||||
variant="bordered"
|
||||
onSelectionChange={(keys) =>
|
||||
setValue(
|
||||
"credentials_type",
|
||||
Array.from(keys)[0] as "aws-sdk-default" | "access-secret-key",
|
||||
)
|
||||
}
|
||||
>
|
||||
<SelectItem key="aws-sdk-default">AWS SDK default</SelectItem>
|
||||
<SelectItem key="access-secret-key">Access & secret key</SelectItem>
|
||||
</Select>
|
||||
|
||||
{credentialsType === "access-secret-key" && (
|
||||
<>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="aws_access_key_id"
|
||||
type="password"
|
||||
label="AWS Access Key ID"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the AWS Access Key ID"
|
||||
variant="bordered"
|
||||
isRequired
|
||||
isInvalid={!!control._formState.errors.aws_access_key_id}
|
||||
/>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="aws_secret_access_key"
|
||||
type="password"
|
||||
label="AWS Secret Access Key"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the AWS Secret Access Key"
|
||||
variant="bordered"
|
||||
isRequired
|
||||
isInvalid={!!control._formState.errors.aws_secret_access_key}
|
||||
/>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="aws_session_token"
|
||||
type="password"
|
||||
label="AWS Session Token (optional)"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the AWS Session Token"
|
||||
variant="bordered"
|
||||
isRequired={false}
|
||||
isInvalid={!!control._formState.errors.aws_session_token}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
<Spacer y={2} />
|
||||
<span className="text-xs font-bold text-default-500">Assume Role</span>
|
||||
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="role_arn"
|
||||
@@ -30,40 +101,6 @@ export const AWSCredentialsRoleForm = ({
|
||||
isRequired
|
||||
isInvalid={!!control._formState.errors.role_arn}
|
||||
/>
|
||||
<span className="text-sm text-default-500">Optional fields</span>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="aws_access_key_id"
|
||||
type="password"
|
||||
label="AWS Access Key ID"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the AWS Access Key ID"
|
||||
variant="bordered"
|
||||
isRequired={false}
|
||||
isInvalid={!!control._formState.errors.aws_access_key_id}
|
||||
/>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="aws_secret_access_key"
|
||||
type="password"
|
||||
label="AWS Secret Access Key"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the AWS Secret Access Key"
|
||||
variant="bordered"
|
||||
isRequired={false}
|
||||
isInvalid={!!control._formState.errors.aws_secret_access_key}
|
||||
/>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="aws_session_token"
|
||||
type="password"
|
||||
label="AWS Session Token"
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the AWS Session Token"
|
||||
variant="bordered"
|
||||
isRequired={false}
|
||||
isInvalid={!!control._formState.errors.aws_session_token}
|
||||
/>
|
||||
<CustomInput
|
||||
control={control}
|
||||
name="external_id"
|
||||
@@ -72,10 +109,12 @@ export const AWSCredentialsRoleForm = ({
|
||||
labelPlacement="inside"
|
||||
placeholder="Enter the External ID"
|
||||
variant="bordered"
|
||||
isRequired={false}
|
||||
defaultValue={externalId}
|
||||
isRequired
|
||||
isInvalid={!!control._formState.errors.external_id}
|
||||
/>
|
||||
|
||||
<span className="text-sm text-default-500">Optional fields</span>
|
||||
<div className="mt-4 grid grid-cols-1 gap-4 md:grid-cols-2">
|
||||
<CustomInput
|
||||
control={control}
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export * from "./skeleton-provider-workflow";
|
||||
export * from "./vertical-steps";
|
||||
export * from "./workflow-add-provider";
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import { Card, CardBody, CardHeader, Skeleton } from "@nextui-org/react";
|
||||
|
||||
export const SkeletonProviderWorkflow = () => {
|
||||
return (
|
||||
<Card>
|
||||
<CardHeader className="flex flex-col items-start space-y-2">
|
||||
<Skeleton className="h-6 w-2/3 rounded-lg">
|
||||
<div className="h-6 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="h-4 w-1/2 rounded-lg">
|
||||
<div className="h-4 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
</CardHeader>
|
||||
<CardBody className="flex flex-col items-start space-y-6">
|
||||
<div className="flex space-x-4">
|
||||
<Skeleton className="h-12 w-12 rounded-lg">
|
||||
<div className="h-12 w-12 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="h-12 w-12 rounded-lg">
|
||||
<div className="h-12 w-12 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
</div>
|
||||
<Skeleton className="h-5 w-3/4 rounded-lg">
|
||||
<div className="h-5 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
<Skeleton className="h-12 w-40 self-end rounded-lg">
|
||||
<div className="h-12 bg-default-200"></div>
|
||||
</Skeleton>
|
||||
</CardBody>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -19,17 +19,11 @@ const steps = [
|
||||
href: "/providers/add-credentials",
|
||||
},
|
||||
{
|
||||
title: "Test connection",
|
||||
title: "Check connection and launch scan",
|
||||
description:
|
||||
"Test your connection to verify that the credentials provided are valid for accessing your cloud account.",
|
||||
"Test your connection to verify that the credentials provided are valid for accessing your cloud account and launch a scan.",
|
||||
href: "/providers/test-connection",
|
||||
},
|
||||
{
|
||||
title: "Success",
|
||||
description:
|
||||
"Your cloud account has been successfully connected and the scan has been launched.",
|
||||
href: "/providers/launch-scan",
|
||||
},
|
||||
];
|
||||
|
||||
export const WorkflowAddProvider = () => {
|
||||
|
||||
@@ -182,6 +182,7 @@ export type AWSCredentialsRole = {
|
||||
external_id?: string;
|
||||
role_session_name?: string;
|
||||
session_duration?: number;
|
||||
credentials_type?: "aws-sdk-default" | "access-secret-key";
|
||||
};
|
||||
|
||||
export type AzureCredentials = {
|
||||
|
||||
+22
-11
@@ -133,17 +133,28 @@ export const addCredentialsFormSchema = (providerType: string) =>
|
||||
|
||||
export const addCredentialsRoleFormSchema = (providerType: string) =>
|
||||
providerType === "aws"
|
||||
? z.object({
|
||||
providerId: z.string(),
|
||||
providerType: z.string(),
|
||||
role_arn: z.string().optional(),
|
||||
aws_access_key_id: z.string().optional(),
|
||||
aws_secret_access_key: z.string().optional(),
|
||||
aws_session_token: z.string().optional(),
|
||||
session_duration: z.number().optional(),
|
||||
external_id: z.string().optional(),
|
||||
role_session_name: z.string().optional(),
|
||||
})
|
||||
? z
|
||||
.object({
|
||||
providerId: z.string(),
|
||||
providerType: z.string(),
|
||||
role_arn: z.string().optional(),
|
||||
external_id: z.string().optional(),
|
||||
aws_access_key_id: z.string().optional(),
|
||||
aws_secret_access_key: z.string().optional(),
|
||||
aws_session_token: z.string().optional(),
|
||||
session_duration: z.number().optional(),
|
||||
role_session_name: z.string().optional(),
|
||||
credentials_type: z.string().optional(),
|
||||
})
|
||||
.refine(
|
||||
(data) =>
|
||||
data.credentials_type !== "access-secret-key" ||
|
||||
(data.aws_access_key_id && data.aws_secret_access_key),
|
||||
{
|
||||
message: "AWS Access Key ID and Secret Access Key are required.",
|
||||
path: ["aws_access_key_id"],
|
||||
},
|
||||
)
|
||||
: z.object({
|
||||
providerId: z.string(),
|
||||
providerType: z.string(),
|
||||
|
||||
Reference in New Issue
Block a user