feat: add Lovable AI app builder provider

- Add lovable SDK provider with apps and published services
- Add 12 security checks mapped to Lovable security best practices
- Add Prowler ThreatScore for Lovable compliance framework
- Add API support: provider type, secret schema, UID validator, migration
- Add UI support: provider choice, credentials form, badges, wiring
- Add SDK tests for provider, services, and critical checks
This commit is contained in:
Toni de la Fuente committed 2026-05-08 18:14:18 +02:00
1 parent 34727a7237
commit 077a4e7dab
100 files changed
+3106 -4

No files matched your search

@@ -9,6 +9,7 @@ import {
IacProviderBadge,
ImageProviderBadge,
KS8ProviderBadge,
LovableProviderBadge,
M365ProviderBadge,
MongoDBAtlasProviderBadge,
OpenStackProviderBadge,
@@ -34,6 +35,7 @@ export const PROVIDER_ICONS = {
cloudflare: CloudflareProviderBadge,
openstack: OpenStackProviderBadge,
vercel: VercelProviderBadge,
lovable: LovableProviderBadge,
} as const;
interface ProviderIconCellProps {
@@ -12,6 +12,7 @@ import { GoogleWorkspaceProviderBadge } from "./googleworkspace-provider-badge";
import { IacProviderBadge } from "./iac-provider-badge";
import { ImageProviderBadge } from "./image-provider-badge";
import { KS8ProviderBadge } from "./ks8-provider-badge";
import { LovableProviderBadge } from "./lovable-provider-badge";
import { M365ProviderBadge } from "./m365-provider-badge";
import { MongoDBAtlasProviderBadge } from "./mongodbatlas-provider-badge";
import { OpenStackProviderBadge } from "./openstack-provider-badge";
@@ -29,6 +30,7 @@ export {
IacProviderBadge,
ImageProviderBadge,
KS8ProviderBadge,
LovableProviderBadge,
M365ProviderBadge,
MongoDBAtlasProviderBadge,
OpenStackProviderBadge,
@@ -53,4 +55,5 @@ export const PROVIDER_BADGE_BY_NAME: Record<string, FC<IconSvgProps>> = {
Cloudflare: CloudflareProviderBadge,
OpenStack: OpenStackProviderBadge,
Vercel: VercelProviderBadge,
Lovable: LovableProviderBadge,
};
@@ -0,0 +1,26 @@
import { IconSvgProps } from "@/types";
export const LovableProviderBadge: 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 256 256"
width={size || width}
{...props}
>
<rect width="256" height="256" fill="#FF4F8B" rx="60" />
<path
d="M128 196c-7 0-13.6-2.7-18.6-7.7l-44.7-44.7c-15.6-15.6-15.6-40.9 0-56.6 15.6-15.6 40.9-15.6 56.6 0L128 94.7l6.7-6.7c15.6-15.6 40.9-15.6 56.6 0 15.6 15.6 15.6 40.9 0 56.6l-44.7 44.7c-5 5-11.6 7.7-18.6 7.7Z"
fill="#FFFFFF"
/>
</svg>
);
@@ -19,6 +19,7 @@ import {
IacProviderBadge,
ImageProviderBadge,
KS8ProviderBadge,
LovableProviderBadge,
M365ProviderBadge,
MongoDBAtlasProviderBadge,
OpenStackProviderBadge,
@@ -103,6 +104,11 @@ const PROVIDERS = [
label: "Vercel",
badge: VercelProviderBadge,
},
{
value: "lovable",
label: "Lovable",
badge: LovableProviderBadge,
},
] as const;
interface RadioGroupProviderProps {
@@ -26,6 +26,7 @@ import {
IacCredentials,
ImageCredentials,
KubernetesCredentials,
LovableCredentials,
M365CertificateCredentials,
M365ClientSecretCredentials,
MongoDBAtlasCredentials,
@@ -58,6 +59,7 @@ import { GoogleWorkspaceCredentialsForm } from "./via-credentials/googleworkspac
import { IacCredentialsForm } from "./via-credentials/iac-credentials-form";
import { ImageCredentialsForm } from "./via-credentials/image-credentials-form";
import { KubernetesCredentialsForm } from "./via-credentials/k8s-credentials-form";
import { LovableCredentialsForm } from "./via-credentials/lovable-credentials-form";
import { MongoDBAtlasCredentialsForm } from "./via-credentials/mongodbatlas-credentials-form";
import { OpenStackCredentialsForm } from "./via-credentials/openstack-credentials-form";
import { OracleCloudCredentialsForm } from "./via-credentials/oraclecloud-credentials-form";
@@ -279,6 +281,11 @@ export const BaseCredentialsForm = ({
control={form.control as unknown as Control<VercelCredentials>}
/>
)}
{providerType === "lovable" && (
<LovableCredentialsForm
control={form.control as unknown as Control<LovableCredentials>}
/>
)}
{!hideActions && (
<div className="flex w-full justify-end gap-4">
@@ -121,6 +121,11 @@ const getProviderFieldDetails = (providerType?: ProviderType) => {
label: "Team ID",
placeholder: "e.g. team_xxxxxxxxxxxxxxxxxxxxxxxx",
};
case "lovable":
return {
label: "Workspace ID",
placeholder: "e.g. my-workspace or ws_xxxxxxxx",
};
default:
return {
label: "Provider UID",
@@ -0,0 +1,61 @@
import { Control } from "react-hook-form";
import { WizardInputField } from "@/components/providers/workflow/forms/fields";
import { ProviderCredentialFields } from "@/lib/provider-credentials/provider-credential-fields";
import { LovableCredentials } from "@/types";
export const LovableCredentialsForm = ({
control,
}: {
control: Control<LovableCredentials>;
}) => {
return (
<>
<div className="flex flex-col">
<div className="text-md text-default-foreground leading-9 font-bold">
Connect via API Token
</div>
<div className="text-default-500 text-sm">
Provide a Lovable Cloud API Token with read access to the workspace
and projects you want Prowler to assess.
</div>
</div>
<WizardInputField
control={control}
name={ProviderCredentialFields.LOVABLE_API_TOKEN}
type="password"
label="Lovable API Token"
labelPlacement="inside"
placeholder="Enter your Lovable Cloud API Token"
variant="bordered"
isRequired
/>
<div className="flex flex-col">
<div className="text-md text-default-foreground leading-9 font-bold">
Optional: Supabase access token
</div>
<div className="text-default-500 text-sm">
If your Lovable apps are backed by Supabase, supply a Supabase
Management API token to enable deeper checks (RLS posture, Edge
Function authentication, storage privacy).
</div>
</div>
<WizardInputField
control={control}
name={ProviderCredentialFields.LOVABLE_SUPABASE_ACCESS_TOKEN}
type="password"
label="Supabase Access Token (optional)"
labelPlacement="inside"
placeholder="sbp_..."
variant="bordered"
/>
<div className="text-default-400 text-xs">
Tokens never leave your browser unencrypted and are stored as secrets in
the backend. You can revoke either token from the relevant dashboard at
any time.
</div>
</>
);
};
@@ -9,6 +9,7 @@ import {
IacProviderBadge,
ImageProviderBadge,
KS8ProviderBadge,
LovableProviderBadge,
M365ProviderBadge,
MongoDBAtlasProviderBadge,
OpenStackProviderBadge,
@@ -49,6 +50,8 @@ export const getProviderLogo = (provider: ProviderType) => {
return <OpenStackProviderBadge width={35} height={35} />;
case "vercel":
return <VercelProviderBadge width={35} height={35} />;
case "lovable":
return <LovableProviderBadge width={35} height={35} />;
default:
return null;
}
@@ -86,6 +89,8 @@ export const getProviderName = (provider: ProviderType): string => {
return "OpenStack";
case "vercel":
return "Vercel";
case "lovable":
return "Lovable";
default:
return "Unknown Provider";
}