mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-21 10:28:54 +00:00
feature: secret scanning architecture and github data source (wip)
This commit is contained in:
+5
-1
@@ -18,6 +18,7 @@ import { CamundaConnectionForm } from "./CamundaConnectionForm";
|
||||
import { DatabricksConnectionForm } from "./DatabricksConnectionForm";
|
||||
import { GcpConnectionForm } from "./GcpConnectionForm";
|
||||
import { GitHubConnectionForm } from "./GitHubConnectionForm";
|
||||
import { GitHubRadarConnectionForm } from "./GitHubRadarConnectionForm";
|
||||
import { HCVaultConnectionForm } from "./HCVaultConnectionForm";
|
||||
import { HumanitecConnectionForm } from "./HumanitecConnectionForm";
|
||||
import { LdapConnectionForm } from "./LdapConnectionForm";
|
||||
@@ -70,6 +71,8 @@ const CreateForm = ({ app, onComplete }: CreateFormProps) => {
|
||||
return <AwsConnectionForm onSubmit={onSubmit} />;
|
||||
case AppConnection.GitHub:
|
||||
return <GitHubConnectionForm />;
|
||||
case AppConnection.GitHubRadar:
|
||||
return <GitHubRadarConnectionForm />;
|
||||
case AppConnection.GCP:
|
||||
return <GcpConnectionForm onSubmit={onSubmit} />;
|
||||
case AppConnection.AzureKeyVault:
|
||||
@@ -144,6 +147,8 @@ const UpdateForm = ({ appConnection, onComplete }: UpdateFormProps) => {
|
||||
return <AwsConnectionForm appConnection={appConnection} onSubmit={onSubmit} />;
|
||||
case AppConnection.GitHub:
|
||||
return <GitHubConnectionForm appConnection={appConnection} />;
|
||||
case AppConnection.GitHubRadar:
|
||||
return <GitHubRadarConnectionForm appConnection={appConnection} />;
|
||||
case AppConnection.GCP:
|
||||
return <GcpConnectionForm appConnection={appConnection} onSubmit={onSubmit} />;
|
||||
case AppConnection.AzureKeyVault:
|
||||
@@ -178,7 +183,6 @@ const UpdateForm = ({ appConnection, onComplete }: UpdateFormProps) => {
|
||||
return <TeamCityConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
|
||||
case AppConnection.OCI:
|
||||
return <OCIConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
|
||||
|
||||
default:
|
||||
throw new Error(`Unhandled App ${(appConnection as TAppConnection).app}`);
|
||||
}
|
||||
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
import crypto from "crypto";
|
||||
|
||||
import { useState } from "react";
|
||||
import { Controller, FormProvider, useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { z } from "zod";
|
||||
|
||||
import { Button, FormControl, ModalClose, Select, SelectItem } from "@app/components/v2";
|
||||
import { APP_CONNECTION_MAP, getAppConnectionMethodDetails } from "@app/helpers/appConnections";
|
||||
import { isInfisicalCloud } from "@app/helpers/platform";
|
||||
import {
|
||||
GitHubRadarConnectionMethod,
|
||||
TGitHubRadarConnection,
|
||||
useGetAppConnectionOption
|
||||
} from "@app/hooks/api/appConnections";
|
||||
import { AppConnection } from "@app/hooks/api/appConnections/enums";
|
||||
|
||||
import {
|
||||
genericAppConnectionFieldsSchema,
|
||||
GenericAppConnectionsFields
|
||||
} from "./GenericAppConnectionFields";
|
||||
|
||||
type Props = {
|
||||
appConnection?: TGitHubRadarConnection;
|
||||
};
|
||||
|
||||
const formSchema = genericAppConnectionFieldsSchema.extend({
|
||||
app: z.literal(AppConnection.GitHubRadar),
|
||||
method: z.nativeEnum(GitHubRadarConnectionMethod)
|
||||
});
|
||||
|
||||
type FormData = z.infer<typeof formSchema>;
|
||||
|
||||
export const GitHubRadarConnectionForm = ({ appConnection }: Props) => {
|
||||
const isUpdate = Boolean(appConnection);
|
||||
const [isRedirecting, setIsRedirecting] = useState(false);
|
||||
|
||||
const {
|
||||
option: { appClientSlug },
|
||||
isLoading
|
||||
} = useGetAppConnectionOption(AppConnection.GitHubRadar);
|
||||
|
||||
const form = useForm<FormData>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: appConnection ?? {
|
||||
app: AppConnection.GitHubRadar,
|
||||
method: GitHubRadarConnectionMethod.App
|
||||
}
|
||||
});
|
||||
|
||||
const {
|
||||
handleSubmit,
|
||||
control,
|
||||
watch,
|
||||
formState: { isSubmitting, isDirty }
|
||||
} = form;
|
||||
|
||||
const selectedMethod = watch("method");
|
||||
|
||||
const onSubmit = (formData: FormData) => {
|
||||
setIsRedirecting(true);
|
||||
const state = crypto.randomBytes(16).toString("hex");
|
||||
localStorage.setItem("latestCSRFToken", state);
|
||||
localStorage.setItem(
|
||||
"githubRadarConnectionFormData",
|
||||
JSON.stringify({ ...formData, connectionId: appConnection?.id })
|
||||
);
|
||||
|
||||
switch (formData.method) {
|
||||
case GitHubRadarConnectionMethod.App:
|
||||
window.location.assign(
|
||||
`https://github.com/apps/${appClientSlug}/installations/new?state=${state}`
|
||||
);
|
||||
break;
|
||||
default:
|
||||
throw new Error(
|
||||
`Unhandled GitHub Radar Connection method: ${(formData as FormData).method}`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
let isMissingConfig: boolean;
|
||||
|
||||
switch (selectedMethod) {
|
||||
case GitHubRadarConnectionMethod.App:
|
||||
isMissingConfig = !appClientSlug;
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unhandled GitHub Radar Connection method: ${selectedMethod}`);
|
||||
}
|
||||
|
||||
const methodDetails = getAppConnectionMethodDetails(selectedMethod);
|
||||
|
||||
return (
|
||||
<FormProvider {...form}>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
{!isUpdate && <GenericAppConnectionsFields />}
|
||||
<Controller
|
||||
name="method"
|
||||
control={control}
|
||||
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||
<FormControl
|
||||
tooltipText={`The method you would like to use to connect with ${
|
||||
APP_CONNECTION_MAP[AppConnection.GitHubRadar].name
|
||||
}. This field cannot be changed after creation.`}
|
||||
errorText={
|
||||
!isLoading && isMissingConfig
|
||||
? `Environment variables have not been configured. ${
|
||||
isInfisicalCloud()
|
||||
? "Please contact Infisical."
|
||||
: `See Docs to configure GitHub Radar ${methodDetails.name} Connections.`
|
||||
}`
|
||||
: error?.message
|
||||
}
|
||||
isError={Boolean(error?.message) || isMissingConfig}
|
||||
label="Method"
|
||||
>
|
||||
<Select
|
||||
isDisabled={isUpdate}
|
||||
value={value}
|
||||
onValueChange={(val) => onChange(val)}
|
||||
className="w-full border border-mineshaft-500"
|
||||
position="popper"
|
||||
dropdownContainerClassName="max-w-none"
|
||||
>
|
||||
{Object.values(GitHubRadarConnectionMethod).map((method) => {
|
||||
return (
|
||||
<SelectItem value={method} key={method}>
|
||||
{getAppConnectionMethodDetails(method).name}
|
||||
</SelectItem>
|
||||
);
|
||||
})}
|
||||
</Select>
|
||||
</FormControl>
|
||||
)}
|
||||
/>
|
||||
<div className="mt-8 flex items-center">
|
||||
<Button
|
||||
className="mr-4"
|
||||
size="sm"
|
||||
type="submit"
|
||||
colorSchema="secondary"
|
||||
isLoading={isSubmitting || isRedirecting}
|
||||
isDisabled={isSubmitting || (!isUpdate && !isDirty) || isMissingConfig || isRedirecting}
|
||||
>
|
||||
{isUpdate ? "Reconnect to GitHub" : "Connect to GitHub"}
|
||||
</Button>
|
||||
<ModalClose asChild>
|
||||
<Button colorSchema="secondary" variant="plain">
|
||||
Cancel
|
||||
</Button>
|
||||
</ModalClose>
|
||||
</div>
|
||||
</form>
|
||||
</FormProvider>
|
||||
);
|
||||
};
|
||||
+13
-5
@@ -15,11 +15,19 @@ export const AppConnectionHeader = ({ app, isConnected, onBack }: Props) => {
|
||||
|
||||
return (
|
||||
<div className="mb-4 flex w-full items-start gap-2 border-b border-mineshaft-500 pb-4">
|
||||
<img
|
||||
alt={`${appDetails.name} logo`}
|
||||
src={`/images/integrations/${appDetails.image}`}
|
||||
className="h-12 w-12 rounded-md bg-bunker-500 p-2"
|
||||
/>
|
||||
<div className="relative">
|
||||
<img
|
||||
alt={`${appDetails.name} logo`}
|
||||
src={`/images/integrations/${appDetails.image}`}
|
||||
className="h-12 w-12 rounded-md bg-bunker-500 p-2"
|
||||
/>
|
||||
{appDetails.icon && (
|
||||
<FontAwesomeIcon
|
||||
icon={appDetails.icon}
|
||||
className="absolute bottom-1 right-1 text-primary-700"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex items-center text-mineshaft-300">
|
||||
{appDetails.name}
|
||||
|
||||
+75
-63
@@ -1,4 +1,4 @@
|
||||
import { faWrench } from "@fortawesome/free-solid-svg-icons";
|
||||
import { faInfoCircle } from "@fortawesome/free-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
|
||||
import { Spinner, Tooltip } from "@app/components/v2";
|
||||
@@ -23,69 +23,81 @@ export const AppConnectionsSelect = ({ onSelect }: Props) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-4 gap-2">
|
||||
{appConnectionOptions?.map((option) => {
|
||||
const { image, name, size = 50 } = APP_CONNECTION_MAP[option.app];
|
||||
<>
|
||||
<div className="grid grid-cols-4 gap-2">
|
||||
{appConnectionOptions?.map((option) => {
|
||||
const { image, name, size = 50, icon } = APP_CONNECTION_MAP[option.app];
|
||||
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
key={option.app}
|
||||
onClick={() => onSelect(option.app)}
|
||||
className="group relative flex h-28 cursor-pointer flex-col items-center justify-center rounded-md border border-mineshaft-600 bg-mineshaft-700 p-4 duration-200 hover:bg-mineshaft-600"
|
||||
>
|
||||
<img
|
||||
src={`/images/integrations/${image}`}
|
||||
style={{
|
||||
width: `${size}px`
|
||||
}}
|
||||
className="mt-auto"
|
||||
alt={`${name} logo`}
|
||||
/>
|
||||
<div className="mt-auto max-w-xs text-center text-xs font-medium text-gray-300 duration-200 group-hover:text-gray-200">
|
||||
{name}
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
<Tooltip
|
||||
side="bottom"
|
||||
className="max-w-sm py-4"
|
||||
content={
|
||||
<>
|
||||
<p className="mb-2">Infisical is constantly adding support for more connections.</p>
|
||||
<p>
|
||||
{`If you don't see the third-party
|
||||
app you're looking for,`}{" "}
|
||||
<a
|
||||
target="_blank"
|
||||
className="underline hover:text-mineshaft-300"
|
||||
href="https://infisical.com/slack"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
let us know on Slack
|
||||
</a>{" "}
|
||||
or{" "}
|
||||
<a
|
||||
target="_blank"
|
||||
className="underline hover:text-mineshaft-300"
|
||||
href="https://github.com/Infisical/infisical/discussions"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
make a request on GitHub
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<div className="group relative flex h-28 flex-col items-center justify-center rounded-md border border-dashed border-mineshaft-600 bg-mineshaft-800 p-4">
|
||||
<FontAwesomeIcon className="mt-auto text-xl" icon={faWrench} />
|
||||
<div className="mt-auto max-w-xs text-center text-sm font-medium text-gray-300 duration-200 group-hover:text-gray-200">
|
||||
Coming Soon
|
||||
</div>
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
key={option.app}
|
||||
onClick={() => onSelect(option.app)}
|
||||
className="group relative flex h-28 cursor-pointer flex-col items-center justify-center rounded-md border border-mineshaft-600 bg-mineshaft-700 p-4 duration-200 hover:bg-mineshaft-600"
|
||||
>
|
||||
<div className="relative">
|
||||
<img
|
||||
src={`/images/integrations/${image}`}
|
||||
style={{
|
||||
width: `${size}px`
|
||||
}}
|
||||
className="mt-auto"
|
||||
alt={`${name} logo`}
|
||||
/>
|
||||
{icon && (
|
||||
<FontAwesomeIcon
|
||||
className="-right- absolute -bottom-1.5 -right-1.5 text-primary-700"
|
||||
size="xl"
|
||||
icon={icon}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-auto max-w-xs text-center text-xs font-medium text-gray-300 duration-200 group-hover:text-gray-200">
|
||||
{name}
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div className="mt-2 flex items-center gap-1">
|
||||
<div className="max-w-xs text-center text-sm font-medium text-mineshaft-400 duration-200">
|
||||
Don't see the connection you're looking for?
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<Tooltip
|
||||
side="bottom"
|
||||
className="max-w-sm py-4"
|
||||
content={
|
||||
<>
|
||||
<p className="mb-2">Infisical is constantly adding support for more connections.</p>
|
||||
<p>
|
||||
{`If you don't see the third-party
|
||||
app you're looking for,`}{" "}
|
||||
<a
|
||||
target="_blank"
|
||||
className="underline hover:text-mineshaft-300"
|
||||
href="https://infisical.com/slack"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
let us know on Slack
|
||||
</a>{" "}
|
||||
or{" "}
|
||||
<a
|
||||
target="_blank"
|
||||
className="underline hover:text-mineshaft-300"
|
||||
href="https://github.com/Infisical/infisical/discussions"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
make a request on GitHub
|
||||
</a>
|
||||
.
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<FontAwesomeIcon className="text-mineshaft-400" size="xs" icon={faInfoCircle} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
+17
-6
@@ -65,6 +65,8 @@ export const AppConnectionRow = ({
|
||||
|
||||
const methodDetails = getAppConnectionMethodDetails(method);
|
||||
|
||||
const connectionDetails = APP_CONNECTION_MAP[app];
|
||||
|
||||
return (
|
||||
<Tr
|
||||
className={twMerge("group h-12 transition-colors duration-100 hover:bg-mineshaft-700")}
|
||||
@@ -72,12 +74,21 @@ export const AppConnectionRow = ({
|
||||
>
|
||||
<Td>
|
||||
<div className="flex items-center gap-2">
|
||||
<img
|
||||
alt={`${APP_CONNECTION_MAP[app].name} integration`}
|
||||
src={`/images/integrations/${APP_CONNECTION_MAP[app].image}`}
|
||||
className="mr-0.5 w-5"
|
||||
/>
|
||||
<span className="hidden lg:inline">{APP_CONNECTION_MAP[app].name}</span>
|
||||
<div className="relative">
|
||||
<img
|
||||
alt={`${connectionDetails.name} integration`}
|
||||
src={`/images/integrations/${connectionDetails.image}`}
|
||||
className="mr-0.5 w-5"
|
||||
/>
|
||||
{connectionDetails.icon && (
|
||||
<FontAwesomeIcon
|
||||
icon={connectionDetails.icon}
|
||||
size="xs"
|
||||
className="absolute -bottom-0.5 -right-0.5 text-primary-700"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
<span className="hidden lg:inline">{connectionDetails.name}</span>
|
||||
</div>
|
||||
</Td>
|
||||
<Td className="!min-w-[8rem] max-w-0">
|
||||
|
||||
Reference in New Issue
Block a user