mirror of
https://github.com/prowler-cloud/prowler.git
synced 2025-12-19 05:17:47 +00:00
313 lines
9.1 KiB
TypeScript
313 lines
9.1 KiB
TypeScript
import { z } from "zod";
|
|
|
|
import type { TaskState } from "@/types/tasks";
|
|
|
|
export type IntegrationType = "amazon_s3" | "aws_security_hub" | "jira";
|
|
|
|
export interface IntegrationProps {
|
|
type: "integrations";
|
|
id: string;
|
|
attributes: {
|
|
inserted_at: string;
|
|
updated_at: string;
|
|
enabled: boolean;
|
|
connected: boolean;
|
|
connection_last_checked_at: string | null;
|
|
integration_type: IntegrationType;
|
|
configuration: {
|
|
bucket_name?: string;
|
|
output_directory?: string;
|
|
credentials?: {
|
|
aws_access_key_id?: string;
|
|
aws_secret_access_key?: string;
|
|
aws_session_token?: string;
|
|
role_arn?: string;
|
|
external_id?: string;
|
|
role_session_name?: string;
|
|
session_duration?: number;
|
|
};
|
|
// Jira specific configuration
|
|
domain?: string;
|
|
projects?: { [key: string]: string };
|
|
issue_types?: string[];
|
|
[key: string]: unknown;
|
|
};
|
|
url?: string;
|
|
};
|
|
relationships?: { providers?: { data: { type: "providers"; id: string }[] } };
|
|
links: { self: string };
|
|
}
|
|
|
|
// Jira dispatch types
|
|
export interface JiraDispatchRequest {
|
|
data: {
|
|
type: "integrations-jira-dispatches";
|
|
attributes: {
|
|
project_key: string;
|
|
issue_type: string;
|
|
};
|
|
};
|
|
}
|
|
|
|
export interface JiraDispatchResponse {
|
|
data: {
|
|
type: "tasks";
|
|
id: string;
|
|
attributes: {
|
|
inserted_at: string;
|
|
completed_at: string | null;
|
|
name: string;
|
|
state: TaskState;
|
|
result: {
|
|
success?: boolean;
|
|
error?: string;
|
|
message?: string;
|
|
issue_url?: string;
|
|
issue_key?: string;
|
|
} | null;
|
|
task_args: Record<string, unknown> | null;
|
|
metadata: Record<string, unknown> | null;
|
|
};
|
|
};
|
|
}
|
|
|
|
// Shared AWS credential fields schema
|
|
const awsCredentialFields = {
|
|
credentials_type: z.enum(["aws-sdk-default", "access-secret-key"]),
|
|
aws_access_key_id: z.string().optional(),
|
|
aws_secret_access_key: z.string().optional(),
|
|
aws_session_token: z.string().optional(),
|
|
role_arn: z.string().optional(),
|
|
external_id: z.string().optional(),
|
|
role_session_name: z.string().optional(),
|
|
session_duration: z.string().optional(),
|
|
show_role_section: z.boolean().optional(),
|
|
};
|
|
|
|
// Shared validation helper for AWS credentials (create mode)
|
|
type AwsCredentialsData = {
|
|
credentials_type?: "aws-sdk-default" | "access-secret-key";
|
|
aws_access_key_id?: string;
|
|
aws_secret_access_key?: string;
|
|
aws_session_token?: string;
|
|
role_arn?: string;
|
|
external_id?: string;
|
|
role_session_name?: string;
|
|
session_duration?: string;
|
|
show_role_section?: boolean;
|
|
};
|
|
|
|
const validateAwsCredentialsCreate = (
|
|
data: AwsCredentialsData,
|
|
ctx: z.RefinementCtx,
|
|
requireCredentials: boolean = true,
|
|
) => {
|
|
if (data.credentials_type === "access-secret-key" && requireCredentials) {
|
|
if (!data.aws_access_key_id) {
|
|
ctx.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
message:
|
|
"AWS Access Key ID is required when using access and secret key",
|
|
path: ["aws_access_key_id"],
|
|
});
|
|
}
|
|
if (!data.aws_secret_access_key) {
|
|
ctx.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
message:
|
|
"AWS Secret Access Key is required when using access and secret key",
|
|
path: ["aws_secret_access_key"],
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
// Shared validation helper for AWS credentials (edit mode)
|
|
const validateAwsCredentialsEdit = (
|
|
data: AwsCredentialsData,
|
|
ctx: z.RefinementCtx,
|
|
) => {
|
|
if (data.credentials_type === "access-secret-key") {
|
|
const hasAccessKey = !!data.aws_access_key_id;
|
|
const hasSecretKey = !!data.aws_secret_access_key;
|
|
|
|
if (hasAccessKey && !hasSecretKey) {
|
|
ctx.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
message:
|
|
"AWS Secret Access Key is required when providing Access Key ID",
|
|
path: ["aws_secret_access_key"],
|
|
});
|
|
}
|
|
|
|
if (hasSecretKey && !hasAccessKey) {
|
|
ctx.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
message:
|
|
"AWS Access Key ID is required when providing Secret Access Key",
|
|
path: ["aws_access_key_id"],
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
// Shared validation helper for IAM Role fields
|
|
const validateIamRole = (
|
|
data: AwsCredentialsData,
|
|
ctx: z.RefinementCtx,
|
|
checkShowSection: boolean = true,
|
|
) => {
|
|
const shouldValidate = checkShowSection
|
|
? data.show_role_section === true
|
|
: true;
|
|
|
|
if (shouldValidate && data.role_arn) {
|
|
if (data.role_arn.trim() === "") {
|
|
ctx.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
message: "Role ARN is required",
|
|
path: ["role_arn"],
|
|
});
|
|
} else if (!data.external_id || data.external_id.trim() === "") {
|
|
ctx.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
message: "External ID is required when using Role ARN",
|
|
path: ["external_id"],
|
|
});
|
|
}
|
|
}
|
|
|
|
if (checkShowSection && data.show_role_section === true) {
|
|
if (!data.role_arn || data.role_arn.trim() === "") {
|
|
ctx.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
message: "Role ARN is required",
|
|
path: ["role_arn"],
|
|
});
|
|
}
|
|
if (!data.external_id || data.external_id.trim() === "") {
|
|
ctx.addIssue({
|
|
code: z.ZodIssueCode.custom,
|
|
message: "External ID is required",
|
|
path: ["external_id"],
|
|
});
|
|
}
|
|
}
|
|
};
|
|
|
|
// S3 Integration Schemas
|
|
const baseS3IntegrationSchema = z.object({
|
|
integration_type: z.literal("amazon_s3"),
|
|
bucket_name: z.string().min(1, "Bucket name is required"),
|
|
output_directory: z.string().min(1, "Output directory is required"),
|
|
providers: z.array(z.string()).optional(),
|
|
enabled: z.boolean().optional(),
|
|
...awsCredentialFields,
|
|
});
|
|
|
|
export const s3IntegrationFormSchema = baseS3IntegrationSchema
|
|
.extend({
|
|
enabled: z.boolean().default(true),
|
|
credentials_type: z
|
|
.enum(["aws-sdk-default", "access-secret-key"])
|
|
.default("aws-sdk-default"),
|
|
})
|
|
.superRefine((data, ctx) => {
|
|
validateAwsCredentialsCreate(data, ctx);
|
|
validateIamRole(data, ctx);
|
|
});
|
|
|
|
export const editS3IntegrationFormSchema = baseS3IntegrationSchema
|
|
.extend({
|
|
bucket_name: z.string().min(1, "Bucket name is required").optional(),
|
|
output_directory: z
|
|
.string()
|
|
.min(1, "Output directory is required")
|
|
.optional(),
|
|
providers: z.array(z.string()).optional(),
|
|
credentials_type: z
|
|
.enum(["aws-sdk-default", "access-secret-key"])
|
|
.optional(),
|
|
})
|
|
.superRefine((data, ctx) => {
|
|
validateAwsCredentialsEdit(data, ctx);
|
|
validateIamRole(data, ctx);
|
|
});
|
|
|
|
// Security Hub Integration Schemas
|
|
const baseSecurityHubIntegrationSchema = z.object({
|
|
integration_type: z.literal("aws_security_hub"),
|
|
provider_id: z.string().min(1, "AWS Provider is required"),
|
|
send_only_fails: z.boolean().optional(),
|
|
archive_previous_findings: z.boolean().optional(),
|
|
use_custom_credentials: z.boolean().optional(),
|
|
enabled: z.boolean().optional(),
|
|
...awsCredentialFields,
|
|
});
|
|
|
|
export const securityHubIntegrationFormSchema = baseSecurityHubIntegrationSchema
|
|
.extend({
|
|
enabled: z.boolean().default(true),
|
|
send_only_fails: z.boolean().default(true),
|
|
archive_previous_findings: z.boolean().default(false),
|
|
use_custom_credentials: z.boolean().default(false),
|
|
credentials_type: z
|
|
.enum(["aws-sdk-default", "access-secret-key"])
|
|
.default("aws-sdk-default"),
|
|
})
|
|
.superRefine((data, ctx) => {
|
|
if (data.use_custom_credentials) {
|
|
validateAwsCredentialsCreate(data, ctx);
|
|
validateIamRole(data, ctx);
|
|
}
|
|
// Always validate role if role_arn is provided
|
|
if (!data.use_custom_credentials && data.role_arn) {
|
|
validateIamRole(data, ctx, false);
|
|
}
|
|
});
|
|
|
|
export const editSecurityHubIntegrationFormSchema =
|
|
baseSecurityHubIntegrationSchema
|
|
.extend({
|
|
provider_id: z.string().optional(),
|
|
send_only_fails: z.boolean().optional(),
|
|
archive_previous_findings: z.boolean().optional(),
|
|
use_custom_credentials: z.boolean().optional(),
|
|
credentials_type: z
|
|
.enum(["aws-sdk-default", "access-secret-key"])
|
|
.optional(),
|
|
})
|
|
.superRefine((data, ctx) => {
|
|
if (data.use_custom_credentials !== false) {
|
|
validateAwsCredentialsEdit(data, ctx);
|
|
}
|
|
// Always validate role if role_arn is provided
|
|
validateIamRole(data, ctx, false);
|
|
});
|
|
|
|
// Jira Integration Schemas
|
|
export const jiraIntegrationFormSchema = z.object({
|
|
integration_type: z.literal("jira"),
|
|
domain: z.string().min(1, "Domain is required"),
|
|
user_mail: z.email({ error: "Invalid email format" }),
|
|
api_token: z.string().min(1, "API token is required"),
|
|
enabled: z.boolean().default(true),
|
|
});
|
|
|
|
export const editJiraIntegrationFormSchema = z.object({
|
|
integration_type: z.literal("jira"),
|
|
domain: z.string().min(1, "Domain is required").optional(),
|
|
user_mail: z.email({ error: "Invalid email format" }).optional(),
|
|
api_token: z.string().min(1, "API token is required").optional(),
|
|
});
|
|
|
|
export type CreateValues = z.infer<typeof jiraIntegrationFormSchema>;
|
|
export type EditValues = z.infer<typeof editJiraIntegrationFormSchema>;
|
|
export type FormValues = CreateValues | EditValues;
|
|
|
|
export interface JiraCredentialsPayload {
|
|
domain?: string;
|
|
user_mail?: string;
|
|
api_token?: string;
|
|
}
|