Merge branch 'master' into PRWLR-6707-create-a-way-of-reporting-for-prowler-threatscore

This commit is contained in:
Pedro Martín authored and GitHub committed 2025-07-28 13:20:05 +02:00
commit 5a407ee4c2
112 files changed
+7682 -405

No files matched your search

+14 -18
View File
@@ -2,7 +2,7 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { Icon } from "@iconify/react";
import { Button, Checkbox, Divider, Link, Tooltip } from "@nextui-org/react";
import { Button, Checkbox, Divider, Tooltip } from "@nextui-org/react";
import { useRouter, useSearchParams } from "next/navigation";
import { useEffect } from "react";
import { useForm } from "react-hook-form";
@@ -15,6 +15,7 @@ import { NotificationIcon, ProwlerExtended } from "@/components/icons";
import { ThemeSwitch } from "@/components/ThemeSwitch";
import { useToast } from "@/components/ui";
import { CustomButton, CustomInput } from "@/components/ui/custom";
import { CustomLink } from "@/components/ui/custom/custom-link";
import {
Form,
FormControl,
@@ -301,13 +302,12 @@ export const AuthForm = ({
onChange={(e) => field.onChange(e.target.checked)}
>
I agree with the 
<Link
<CustomLink
href="https://prowler.com/terms-of-service/"
size="sm"
target="_blank"
>
Terms of Service
</Link>
</CustomLink>
&nbsp;of Prowler
</Checkbox>
</FormControl>
@@ -359,13 +359,9 @@ export const AuthForm = ({
content={
<div className="flex-inline text-small">
Social Login with Google is not enabled.{" "}
<Link
target="_blank"
rel="noopener noreferrer"
className="text-xs font-medium text-primary"
>
<CustomLink href="https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/prowler-app-social-login/#google-oauth-configuration">
Read the docs
</Link>
</CustomLink>
</div>
}
placement="right-start"
@@ -392,13 +388,9 @@ export const AuthForm = ({
content={
<div className="flex-inline text-small">
Social Login with Github is not enabled.{" "}
<Link
target="_blank"
rel="noopener noreferrer"
className="text-xs font-medium text-primary"
>
<CustomLink href="https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/prowler-app-social-login/#github-oauth-configuration">
Read the docs
</Link>
</CustomLink>
</div>
}
placement="right-start"
@@ -451,12 +443,16 @@ export const AuthForm = ({
{type === "sign-in" ? (
<p className="text-center text-small">
Need to create an account?&nbsp;
<Link href="/sign-up">Sign up</Link>
<CustomLink size="base" href="/sign-up" target="_self">
Sign up
</CustomLink>
</p>
) : (
<p className="text-center text-small">
Already have an account?&nbsp;
<Link href="/sign-in">Log in</Link>
<CustomLink size="base" href="/sign-in" target="_self">
Log in
</CustomLink>
</p>
)}
</div>
@@ -1,3 +1,4 @@
import { CustomLink } from "@/components/ui/custom/custom-link";
import { SeverityBadge } from "@/components/ui/table";
import { Requirement } from "@/types/compliance";
@@ -7,7 +8,6 @@ import {
ComplianceDetailContainer,
ComplianceDetailSection,
ComplianceDetailText,
ComplianceLink,
} from "./shared-components";
export const AWSWellArchitectedCustomDetails = ({
@@ -75,11 +75,9 @@ export const AWSWellArchitectedCustomDetails = ({
{requirement.implementation_guidance_url && (
<ComplianceDetailSection title="Implementation Guidance">
<ComplianceLink
href={requirement.implementation_guidance_url as string}
>
<CustomLink href={requirement.implementation_guidance_url as string}>
{requirement.implementation_guidance_url as string}
</ComplianceLink>
</CustomLink>
</ComplianceDetailSection>
)}
</ComplianceDetailContainer>
@@ -1,5 +1,6 @@
import ReactMarkdown from "react-markdown";
import { CustomLink } from "@/components/ui/custom/custom-link";
import { Requirement } from "@/types/compliance";
import {
@@ -8,7 +9,6 @@ import {
ComplianceDetailContainer,
ComplianceDetailSection,
ComplianceDetailText,
ComplianceLink,
} from "./shared-components";
interface CISDetailsProps {
@@ -121,7 +121,7 @@ export const CISCustomDetails = ({ requirement }: CISDetailsProps) => {
{processReferences(requirement.references).map(
(url: string, index: number) => (
<div key={index}>
<ComplianceLink href={url}>{url}</ComplianceLink>
<CustomLink href={url}>{url}</CustomLink>
</div>
),
)}
@@ -1,3 +1,4 @@
import { CustomLink } from "@/components/ui/custom/custom-link";
import { Requirement } from "@/types/compliance";
import {
@@ -7,7 +8,6 @@ import {
ComplianceDetailContainer,
ComplianceDetailSection,
ComplianceDetailText,
ComplianceLink,
} from "./shared-components";
export const MITRECustomDetails = ({
@@ -63,9 +63,9 @@ export const MITRECustomDetails = ({
{requirement.technique_url && (
<ComplianceDetailSection title="MITRE ATT&CK Reference">
<ComplianceLink href={requirement.technique_url as string}>
<CustomLink href={requirement.technique_url as string}>
{requirement.technique_url as string}
</ComplianceLink>
</CustomLink>
</ComplianceDetailSection>
)}
@@ -1,26 +1,5 @@
import Link from "next/link";
import { cn } from "@/lib/utils";
export const ComplianceLink = ({
href,
children,
}: {
href: string;
children: React.ReactNode;
}) => {
return (
<Link
href={href}
target="_blank"
rel="noopener noreferrer"
className="break-all text-sm text-blue-600 decoration-1 transition-colors hover:text-blue-800 dark:text-blue-400 dark:hover:text-blue-300"
>
{children}
</Link>
);
};
export const ComplianceDetailContainer = ({
children,
}: {
@@ -1,10 +1,10 @@
"use client";
import { Snippet } from "@nextui-org/react";
import Link from "next/link";
import { CodeSnippet } from "@/components/ui/code-snippet/code-snippet";
import { CustomSection } from "@/components/ui/custom";
import { CustomLink } from "@/components/ui/custom/custom-link";
import { EntityInfoShort, InfoField } from "@/components/ui/entities";
import { DateWithTime } from "@/components/ui/entities/date-with-time";
import { SeverityBadge } from "@/components/ui/table/severity-badge";
@@ -151,15 +151,14 @@ export const FindingDetail = ({
{attributes.check_metadata.remediation.recommendation.text}
</p>
{attributes.check_metadata.remediation.recommendation.url && (
<Link
<CustomLink
href={
attributes.check_metadata.remediation.recommendation.url
}
target="_blank"
className="text-sm text-blue-500 hover:underline"
size="sm"
>
Learn more
</Link>
</CustomLink>
)}
</div>
</InfoField>
@@ -179,13 +178,12 @@ export const FindingDetail = ({
{/* Additional Resources section */}
{attributes.check_metadata.remediation.code.other && (
<InfoField label="Additional Resources">
<Link
<CustomLink
href={attributes.check_metadata.remediation.code.other}
target="_blank"
className="text-sm text-blue-500 hover:underline"
size="sm"
>
View documentation
</Link>
</CustomLink>
</InfoField>
)}
</div>
@@ -1,6 +1,5 @@
"use client";
import Link from "next/link";
import { Dispatch, SetStateAction, useEffect, useRef, useState } from "react";
import { useFormState } from "react-dom";
import { z } from "zod";
@@ -9,6 +8,7 @@ import { createSamlConfig, updateSamlConfig } from "@/actions/integrations";
import { AddIcon } from "@/components/icons";
import { useToast } from "@/components/ui";
import { CustomButton, CustomServerInput } from "@/components/ui/custom";
import { CustomLink } from "@/components/ui/custom/custom-link";
import { SnippetChip } from "@/components/ui/entities";
import { FormButtons } from "@/components/ui/form";
import { apiBaseUrl } from "@/lib";
@@ -239,9 +239,9 @@ export const SamlConfigForm = ({
assign the user&apos;s role. If the role does not exist, one will
be created with minimal permissions. You can assign permissions to
roles on the{" "}
<Link href="/roles">
<span className="underline">Roles</span>
</Link>{" "}
<CustomLink href="/roles" target="_self">
<span>Roles</span>
</CustomLink>{" "}
page.
</p>
</div>
@@ -1,13 +1,13 @@
"use client";
import { Card, CardBody, CardHeader } from "@nextui-org/react";
import { Link } from "@nextui-org/react";
import { CheckIcon, Trash2Icon } from "lucide-react";
import { useState } from "react";
import { deleteSamlConfig } from "@/actions/integrations";
import { useToast } from "@/components/ui";
import { CustomAlertModal, CustomButton } from "@/components/ui/custom";
import { CustomLink } from "@/components/ui/custom/custom-link";
import { SamlConfigForm } from "./forms";
@@ -73,14 +73,9 @@ export const SamlIntegrationCard = ({ samlConfig }: { samlConfig?: any }) => {
) : (
<>
Configure SAML Single Sign-On for secure authentication.{" "}
<Link
target="_blank"
href="https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/prowler-app-sso"
rel="noopener noreferrer"
className="text-xs font-medium text-primary"
>
<CustomLink href="https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/prowler-app-sso">
Read the docs
</Link>
</CustomLink>
</>
)}
</p>
+6 -4
View File
@@ -1,12 +1,12 @@
"use client";
import { useChat } from "@ai-sdk/react";
import Link from "next/link";
import { useEffect, useRef } from "react";
import { useForm } from "react-hook-form";
import { MemoizedMarkdown } from "@/components/lighthouse/memoized-markdown";
import { CustomButton, CustomTextarea } from "@/components/ui/custom";
import { CustomLink } from "@/components/ui/custom/custom-link";
import { Form } from "@/components/ui/form";
interface SuggestedAction {
@@ -138,12 +138,14 @@ export const Chat = ({ hasConfig, isActive }: ChatProps) => {
? "Please configure your OpenAI API key to use Lighthouse AI."
: "OpenAI API key is invalid. Please update your key to use Lighthouse AI."}
</p>
<Link
<CustomLink
href="/lighthouse/config"
className="inline-flex items-center justify-center rounded-md bg-primary px-4 py-2 text-sm font-medium text-primary-foreground hover:bg-primary/90"
className="inline-flex items-center justify-center rounded-md bg-primary px-4 py-2 text-primary-foreground hover:bg-primary/90"
target="_self"
size="sm"
>
Configure API Key
</Link>
</CustomLink>
</div>
</div>
)}
@@ -1,7 +1,6 @@
"use client";
import { Textarea } from "@nextui-org/react";
import Link from "next/link";
import { Dispatch, SetStateAction, useEffect, useState } from "react";
import { useFormState } from "react-dom";
@@ -14,6 +13,7 @@ import {
import { DeleteIcon } from "@/components/icons";
import { useToast } from "@/components/ui";
import { CustomButton } from "@/components/ui/custom";
import { CustomLink } from "@/components/ui/custom/custom-link";
import { FormButtons } from "@/components/ui/form";
import { fontMono } from "@/config/fonts";
import { convertToYaml, parseYamlValidation } from "@/lib/yaml";
@@ -178,13 +178,9 @@ export const MutedFindingsConfigForm = ({
</li>
<li>
Learn more about configuring the Mutelist{" "}
<Link
href="https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/mutelist/"
target="_blank"
className="text-primary-600 hover:underline"
>
<CustomLink href="https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/mutelist/">
here
</Link>
</CustomLink>
.
</li>
<li>
@@ -3,7 +3,6 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { Icon } from "@iconify/react";
import { Checkbox } from "@nextui-org/react";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useState } from "react";
import { useForm } from "react-hook-form";
@@ -18,6 +17,7 @@ import { getTask } from "@/actions/task/tasks";
import { CheckIcon, RocketIcon } from "@/components/icons";
import { useToast } from "@/components/ui";
import { CustomButton } from "@/components/ui/custom";
import { CustomLink } from "@/components/ui/custom/custom-link";
import { Form } from "@/components/ui/form";
import { checkTaskStatus } from "@/lib/helper";
import { ProviderType } from "@/types";
@@ -295,8 +295,9 @@ export const TestConnectionForm = ({
<div className="flex w-full justify-end sm:space-x-6">
{apiErrorMessage ? (
<Link
<CustomLink
href="/providers"
target="_self"
className="mr-3 flex w-fit items-center justify-center space-x-2 rounded-lg border border-solid border-gray-200 px-4 py-2 hover:bg-gray-200 dark:hover:bg-gray-700"
>
<Icon
@@ -304,7 +305,7 @@ export const TestConnectionForm = ({
className="h-5 w-5 text-gray-600 dark:text-gray-400"
/>
<span>Back to providers</span>
</Link>
</CustomLink>
) : connectionStatus?.error ? (
<CustomButton
onPress={isUpdated ? () => router.back() : onResetCredentials}
@@ -1,8 +1,8 @@
import Link from "next/link";
import { Control } from "react-hook-form";
import { InfoIcon } from "@/components/icons";
import { CustomInput } from "@/components/ui/custom";
import { CustomLink } from "@/components/ui/custom/custom-link";
import { M365Credentials } from "@/types";
export const M365CredentialsForm = ({
@@ -57,14 +57,12 @@ export const M365CredentialsForm = ({
{" "}
User and password authentication is being deprecated due to
Microsoft&apos;s on-going MFA enforcement across all tenants (see{" "}
<Link
<CustomLink
href="https://azure.microsoft.com/en-us/blog/announcing-mandatory-multi-factor-authentication-for-azure-sign-in/"
target="_blank"
rel="noopener noreferrer"
className="text-sm text-primary hover:underline"
size="sm"
>
Microsoft docs
</Link>
</CustomLink>
).
</p>
@@ -76,14 +74,12 @@ export const M365CredentialsForm = ({
</div>
<p className="text-sm text-default-500">
Due to that change, you must only{" "}
<Link
<CustomLink
href="https://docs.prowler.com/projects/prowler-open-source/en/latest/tutorials/microsoft365/getting-started-m365/#step-3-configure-your-m365-account"
target="_blank"
rel="noopener noreferrer"
className="text-sm text-primary hover:underline"
size="sm"
>
use application authentication
</Link>{" "}
</CustomLink>{" "}
to maintain all Prowler M365 scan capabilities.
</p>
<CustomInput
@@ -1,5 +1,6 @@
import Link from "next/link";
"use client";
import { CustomLink } from "@/components/ui/custom/custom-link";
import { getProviderName } from "@/components/ui/entities/get-provider-logo";
import { getProviderLogo } from "@/components/ui/entities/get-provider-logo";
import { getProviderHelpText } from "@/lib";
@@ -24,13 +25,12 @@ export const ProviderTitleDocs = ({
<p className="text-sm text-default-500">
{getProviderHelpText(providerType as string).text}
</p>
<Link
<CustomLink
href={getProviderHelpText(providerType as string).link}
target="_blank"
className="text-sm font-medium text-primary"
size="sm"
>
Read the docs
</Link>
</CustomLink>
</div>
</div>
);
@@ -29,9 +29,13 @@ export const LaunchScanWorkflow = ({
const formSchema = z.object({
...onDemandScanFormSchema().shape,
scanName: z
.string()
.min(3, "Must have at least 3 characters")
.or(z.literal(""))
.union([
z
.string()
.min(3, "Must be at least 3 characters")
.max(32, "Must not exceed 32 characters"),
z.literal(""),
])
.optional(),
});
@@ -101,7 +105,7 @@ export const LaunchScanWorkflow = ({
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -50 }}
transition={{ duration: 0.3 }}
className="min-w-48 self-end"
className="h-[3.4rem] min-w-[15.2rem] self-end"
>
<CustomInput
control={form.control}
+51
View File
@@ -0,0 +1,51 @@
import Link from "next/link";
import React from "react";
import { cn } from "@/lib";
interface CustomLinkProps
extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
href: string;
target?: "_self" | "_blank" | string;
ariaLabel?: string;
className?: string;
children: React.ReactNode;
scroll?: boolean;
size?: string;
}
export const CustomLink = React.forwardRef<HTMLAnchorElement, CustomLinkProps>(
(
{
href,
target = "_blank",
ariaLabel,
className,
children,
scroll = true,
size = "xs",
...props
},
ref,
) => {
return (
<Link
ref={ref}
href={href}
scroll={scroll}
className={cn(
`text-${size} break-all font-medium text-primary decoration-1 hover:underline`,
className,
)}
aria-label={ariaLabel}
target={target}
rel="noopener noreferrer"
{...props}
>
{children}
</Link>
);
},
);
CustomLink.displayName = "CustomLink";
+8 -5
View File
@@ -1,7 +1,6 @@
"use client";
import { LogOut, User } from "lucide-react";
import Link from "next/link";
import { useSession } from "next-auth/react";
import { logOut } from "@/actions/auth";
@@ -10,6 +9,8 @@ import {
AvatarFallback,
AvatarImage,
} from "@/components/ui/avatar/avatar";
import { Button } from "@/components/ui/button/button";
import { CustomLink } from "@/components/ui/custom/custom-link";
import {
DropdownMenu,
DropdownMenuContent,
@@ -26,8 +27,6 @@ import {
TooltipTrigger,
} from "@/components/ui/tooltip/tooltip";
import { Button } from "../button/button";
export const UserNav = () => {
const { data: session } = useSession();
@@ -80,10 +79,14 @@ export const UserNav = () => {
<DropdownMenuSeparator />
<DropdownMenuGroup>
<DropdownMenuItem className="hover:cursor-pointer" asChild>
<Link href="/profile" className="flex items-center">
<CustomLink
href="/profile"
className="flex items-center font-normal text-prowler-black dark:text-prowler-white"
target="_self"
>
<User className="text-muted-foreground mr-3 h-4 w-4" />
Account
</Link>
</CustomLink>
</DropdownMenuItem>
</DropdownMenuGroup>
<DropdownMenuSeparator />