wip: add IaC to UI

This commit is contained in:
Andoni A.
2025-09-12 10:37:49 +02:00
parent 27f5c9591b
commit 75390c0979
19 changed files with 193 additions and 1 deletions
+10
View File
@@ -2,6 +2,14 @@
All notable changes to the **Prowler UI** are documented in this file.
## [Unreleased]
### 🚀 Added
- IaC (Infrastructure as Code) provider support for scanning remote repositories [(#TBD)](https://github.com/prowler-cloud/prowler/pull/TBD)
---
## [1.12.1] (Prowler v5.12.1)
### 🚀 Added
@@ -14,6 +22,8 @@ All notable changes to the **Prowler UI** are documented in this file.
- Field-level email validation message [(#8698)] (https://github.com/prowler-cloud/prowler/pull/8698)
- POST method on auth form [(#8699)] (https://github.com/prowler-cloud/prowler/pull/8699)
---
## [1.12.0] (Prowler v5.12.0)
### 🚀 Added
@@ -5,6 +5,7 @@ import {
AzureProviderBadge,
GCPProviderBadge,
GitHubProviderBadge,
IacProviderBadge,
KS8ProviderBadge,
M365ProviderBadge,
} from "../icons/providers-badge";
@@ -62,3 +63,12 @@ export const CustomProviderInputGitHub = () => {
</div>
);
};
export const CustomProviderInputIac = () => {
return (
<div className="flex items-center gap-x-2">
<IacProviderBadge width={25} height={25} />
<p className="text-sm">Infrastructure as Code</p>
</div>
);
};
@@ -11,6 +11,7 @@ import {
CustomProviderInputAzure,
CustomProviderInputGCP,
CustomProviderInputGitHub,
CustomProviderInputIac,
CustomProviderInputKubernetes,
CustomProviderInputM365,
} from "./custom-provider-inputs";
@@ -43,6 +44,10 @@ const providerDisplayData: Record<
label: "GitHub",
component: <CustomProviderInputGitHub />,
},
iac: {
label: "Infrastructure as Code",
component: <CustomProviderInputIac />,
},
};
const dataInputsProvider = PROVIDER_TYPES.map((providerType) => ({
@@ -0,0 +1,44 @@
import * as React from "react";
import { IconSvgProps } from "@/types";
export const IacProviderBadge: React.FC<IconSvgProps> = ({
size,
width,
height,
...props
}) => (
<svg
xmlns="http://www.w3.org/2000/svg"
aria-hidden="true"
fill="none"
focusable="false"
height={size || height}
role="presentation"
viewBox="0 0 24 24"
width={size || width}
{...props}
>
<path
d="M13 21L17 3"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M7 8L3 12L7 16"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M17 8L21 12L17 16"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
);
@@ -2,5 +2,6 @@ export * from "./aws-provider-badge";
export * from "./azure-provider-badge";
export * from "./gcp-provider-badge";
export * from "./github-provider-badge";
export * from "./iac-provider-badge";
export * from "./ks8-provider-badge";
export * from "./m365-provider-badge";
@@ -49,6 +49,7 @@ export const ProvidersOverview = ({
gcp: "GCP",
kubernetes: "Kubernetes",
github: "GitHub",
iac: "IaC",
};
const providers = PROVIDER_TYPES.map((providerType) => ({
@@ -15,6 +15,7 @@ const providerTypeLabels: Record<ProviderType, string> = {
m365: "Microsoft 365",
kubernetes: "Kubernetes",
github: "GitHub",
iac: "Infrastructure as Code",
};
interface EnhancedProviderSelectorProps {
@@ -12,6 +12,7 @@ import {
AzureProviderBadge,
GCPProviderBadge,
GitHubProviderBadge,
IacProviderBadge,
KS8ProviderBadge,
M365ProviderBadge,
} from "../icons/providers-badge";
@@ -78,6 +79,12 @@ export const RadioGroupProvider: React.FC<RadioGroupProviderProps> = ({
<span className="ml-2">GitHub</span>
</div>
</CustomRadio>
<CustomRadio description="Infrastructure as Code" value="iac">
<div className="flex items-center">
<IacProviderBadge size={26} />
<span className="ml-2">Infrastructure as Code</span>
</div>
</CustomRadio>
</div>
</RadioGroup>
{errorMessage && (
@@ -16,6 +16,7 @@ import {
AzureCredentials,
GCPDefaultCredentials,
GCPServiceAccountKey,
IacCredentials,
KubernetesCredentials,
M365Credentials,
ProviderType,
@@ -28,6 +29,7 @@ import { GCPDefaultCredentialsForm } from "./select-credentials-type/gcp/credent
import { GCPServiceAccountKeyForm } from "./select-credentials-type/gcp/credentials-type/gcp-service-account-key-form";
import { AzureCredentialsForm } from "./via-credentials/azure-credentials-form";
import { GitHubCredentialsForm } from "./via-credentials/github-credentials-form";
import { IacCredentialsForm } from "./via-credentials/iac-credentials-form";
import { KubernetesCredentialsForm } from "./via-credentials/k8s-credentials-form";
import { M365CredentialsForm } from "./via-credentials/m365-credentials-form";
@@ -133,6 +135,11 @@ export const BaseCredentialsForm = ({
credentialsType={searchParamsObj.get("via") || undefined}
/>
)}
{providerType === "iac" && (
<IacCredentialsForm
control={form.control as unknown as Control<IacCredentials>}
/>
)}
<div className="flex w-full justify-end sm:space-x-6">
{showBackButton && requiresBackButton(searchParamsObj.get("via")) && (
@@ -51,6 +51,11 @@ const getProviderFieldDetails = (providerType?: ProviderType) => {
label: "Username",
placeholder: "e.g. your-github-username",
};
case "iac":
return {
label: "Repository URL",
placeholder: "e.g. https://github.com/user/repo",
};
default:
return {
label: "Provider UID",
@@ -0,0 +1,44 @@
import { Control } from "react-hook-form";
import { CustomInput } from "@/components/ui/custom";
import { IacCredentials } from "@/types";
export const IacCredentialsForm = ({
control,
}: {
control: Control<IacCredentials>;
}) => {
return (
<>
<div className="flex flex-col">
<div className="text-md font-bold leading-9 text-default-foreground">
Connect via Repository
</div>
<div className="text-sm text-default-500">
Please provide the repository URL to scan for Infrastructure as Code
files.
</div>
</div>
<CustomInput
control={control}
name="repository_url"
label="Repository URL"
labelPlacement="inside"
placeholder="https://github.com/user/repo or https://github.com/user/repo.git"
variant="bordered"
isRequired
isInvalid={!!control._formState.errors.repository_url}
/>
<CustomInput
control={control}
name="access_token"
label="Access Token (Optional)"
labelPlacement="inside"
placeholder="Token for private repositories (optional)"
variant="bordered"
type="password"
isInvalid={!!control._formState.errors.access_token}
/>
</>
);
};
@@ -1,4 +1,5 @@
export * from "./azure-credentials-form";
export * from "./github-credentials-form";
export * from "./iac-credentials-form";
export * from "./k8s-credentials-form";
export * from "./m365-credentials-form";
@@ -5,6 +5,7 @@ import {
AzureProviderBadge,
GCPProviderBadge,
GitHubProviderBadge,
IacProviderBadge,
KS8ProviderBadge,
M365ProviderBadge,
} from "@/components/icons/providers-badge";
@@ -24,6 +25,8 @@ export const getProviderLogo = (provider: ProviderType) => {
return <M365ProviderBadge width={35} height={35} />;
case "github":
return <GitHubProviderBadge width={35} height={35} />;
case "iac":
return <IacProviderBadge width={35} height={35} />;
default:
return null;
}
@@ -43,6 +46,8 @@ export const getProviderName = (provider: ProviderType): string => {
return "Microsoft 365";
case "github":
return "GitHub";
case "iac":
return "Infrastructure as Code";
default:
return "Unknown Provider";
}
+5
View File
@@ -32,6 +32,11 @@ export const getProviderHelpText = (provider: string) => {
text: "Need help connecting your GitHub account?",
link: "https://goto.prowler.com/provider-github",
};
case "iac":
return {
text: "Need help scanning your Infrastructure as Code repository?",
link: "https://goto.prowler.com/provider-iac",
};
default:
return {
text: "How to setup a provider?",
@@ -190,6 +190,20 @@ export const buildGitHubSecret = (formData: FormData) => {
return {};
};
export const buildIacSecret = (formData: FormData) => {
const secret = {
[ProviderCredentialFields.REPOSITORY_URL]: getFormValue(
formData,
ProviderCredentialFields.REPOSITORY_URL,
),
[ProviderCredentialFields.ACCESS_TOKEN]: getFormValue(
formData,
ProviderCredentialFields.ACCESS_TOKEN,
),
};
return filterEmptyValues(secret);
};
// Main function to build secret configuration
export const buildSecretConfig = (
formData: FormData,
@@ -224,6 +238,10 @@ export const buildSecretConfig = (
secretType: "static",
secret: buildGitHubSecret(formData),
}),
iac: () => ({
secretType: "static",
secret: buildIacSecret(formData),
}),
};
const builder = secretBuilders[providerType];
@@ -42,6 +42,10 @@ export const ProviderCredentialFields = {
OAUTH_APP_TOKEN: "oauth_app_token",
GITHUB_APP_ID: "github_app_id",
GITHUB_APP_KEY: "github_app_key_content",
// IaC fields
REPOSITORY_URL: "repository_url",
ACCESS_TOKEN: "access_token",
} as const;
// Type for credential field values
@@ -70,6 +74,8 @@ export const ErrorPointers = {
OAUTH_APP_TOKEN: "/data/attributes/secret/oauth_app_token",
GITHUB_APP_ID: "/data/attributes/secret/github_app_id",
GITHUB_APP_KEY: "/data/attributes/secret/github_app_key_content",
REPOSITORY_URL: "/data/attributes/secret/repository_url",
ACCESS_TOKEN: "/data/attributes/secret/access_token",
} as const;
export type ErrorPointer = (typeof ErrorPointers)[keyof typeof ErrorPointers];
+7
View File
@@ -239,12 +239,19 @@ export type KubernetesCredentials = {
[ProviderCredentialFields.PROVIDER_ID]: string;
};
export type IacCredentials = {
[ProviderCredentialFields.REPOSITORY_URL]: string;
[ProviderCredentialFields.ACCESS_TOKEN]?: string;
[ProviderCredentialFields.PROVIDER_ID]: string;
};
export type CredentialsFormSchema =
| AWSCredentials
| AzureCredentials
| GCPDefaultCredentials
| GCPServiceAccountKey
| KubernetesCredentials
| IacCredentials
| M365Credentials;
export interface SearchParamsProps {
+15 -1
View File
@@ -110,6 +110,11 @@ export const addProviderFormSchema = z
[ProviderCredentialFields.PROVIDER_ALIAS]: z.string(),
providerUid: z.string(),
}),
z.object({
providerType: z.literal("iac"),
[ProviderCredentialFields.PROVIDER_ALIAS]: z.string(),
providerUid: z.string(),
}),
]),
);
@@ -190,7 +195,16 @@ export const addCredentialsFormSchema = (
.string()
.optional(),
}
: {}),
: providerType === "iac"
? {
[ProviderCredentialFields.REPOSITORY_URL]: z
.string()
.nonempty("Repository URL is required"),
[ProviderCredentialFields.ACCESS_TOKEN]: z
.string()
.optional(),
}
: {}),
})
.superRefine((data: Record<string, any>, ctx) => {
if (providerType === "m365") {
+1
View File
@@ -5,6 +5,7 @@ export const PROVIDER_TYPES = [
"kubernetes",
"m365",
"github",
"iac",
] as const;
export type ProviderType = (typeof PROVIDER_TYPES)[number];