Merge pull request #3755 from Infisical/ENG-2773

feat(secret-rotation): Oracle Database
This commit is contained in:
x032205
2025-06-12 21:06:57 -04:00
committed by GitHub
78 changed files with 977 additions and 14 deletions
@@ -64,6 +64,7 @@ const Content = ({ secretRotation }: ContentProps) => {
case SecretRotation.PostgresCredentials:
case SecretRotation.MySqlCredentials:
case SecretRotation.MsSqlCredentials:
case SecretRotation.OracleDBCredentials:
Component = (
<ViewSqlCredentialsRotationGeneratedCredentials
generatedCredentialsResponse={generatedCredentialsResponse}
@@ -2,12 +2,14 @@ import { CredentialDisplay } from "@app/components/secret-rotations-v2/ViewSecre
import { ViewRotationGeneratedCredentialsDisplay } from "@app/components/secret-rotations-v2/ViewSecretRotationV2GeneratedCredentials/shared/ViewRotationGeneratedCredentialsDisplay";
import { TMsSqlCredentialsRotationGeneratedCredentialsResponse } from "@app/hooks/api/secretRotationsV2/types/mssql-credentials-rotation";
import { TMySqlCredentialsRotationGeneratedCredentialsResponse } from "@app/hooks/api/secretRotationsV2/types/mysql-credentials-rotation";
import { TOracleDBCredentialsRotationGeneratedCredentialsResponse } from "@app/hooks/api/secretRotationsV2/types/oracledb-credentials-rotation";
import { TPostgresCredentialsRotationGeneratedCredentialsResponse } from "@app/hooks/api/secretRotationsV2/types/postgres-credentials-rotation";
type Props = {
generatedCredentialsResponse:
| TMsSqlCredentialsRotationGeneratedCredentialsResponse
| TMySqlCredentialsRotationGeneratedCredentialsResponse
| TOracleDBCredentialsRotationGeneratedCredentialsResponse
| TPostgresCredentialsRotationGeneratedCredentialsResponse;
};
@@ -13,6 +13,7 @@ const COMPONENT_MAP: Record<SecretRotation, React.FC> = {
[SecretRotation.PostgresCredentials]: SqlCredentialsRotationParametersFields,
[SecretRotation.MsSqlCredentials]: SqlCredentialsRotationParametersFields,
[SecretRotation.MySqlCredentials]: SqlCredentialsRotationParametersFields,
[SecretRotation.OracleDBCredentials]: SqlCredentialsRotationParametersFields,
[SecretRotation.Auth0ClientSecret]: Auth0ClientSecretRotationParametersFields,
[SecretRotation.AzureClientSecret]: AzureClientSecretRotationParametersFields,
[SecretRotation.LdapPassword]: LdapPasswordRotationParametersFields,
@@ -3,6 +3,7 @@ import { Controller, useFormContext } from "react-hook-form";
import { TSecretRotationV2Form } from "@app/components/secret-rotations-v2/forms/schemas";
import { FormControl, Input } from "@app/components/v2";
import { NoticeBannerV2 } from "@app/components/v2/NoticeBannerV2/NoticeBannerV2";
import { AppConnection } from "@app/hooks/api/appConnections/enums";
import { SecretRotation, useSecretRotationV2Option } from "@app/hooks/api/secretRotationsV2";
export const SqlCredentialsRotationParametersFields = () => {
@@ -25,7 +26,15 @@ export const SqlCredentialsRotationParametersFields = () => {
errorText={error?.message}
label="Database Username 1"
>
<Input value={value} onChange={onChange} placeholder="infiscal_user_1" />
<Input
value={value}
onChange={onChange}
placeholder={
rotationOption.connection === AppConnection.OracleDB
? "INFISICAL_USER_1"
: "infisical_user_1"
}
/>
</FormControl>
)}
control={control}
@@ -38,7 +47,15 @@ export const SqlCredentialsRotationParametersFields = () => {
errorText={error?.message}
label="Database Username 2"
>
<Input value={value} onChange={onChange} placeholder="infiscal_user_2" />
<Input
value={value}
onChange={onChange}
placeholder={
rotationOption.connection === AppConnection.OracleDB
? "INFISICAL_USER_2"
: "infisical_user_2"
}
/>
</FormControl>
)}
control={control}
@@ -16,6 +16,7 @@ const COMPONENT_MAP: Record<SecretRotation, React.FC> = {
[SecretRotation.PostgresCredentials]: SqlCredentialsRotationReviewFields,
[SecretRotation.MsSqlCredentials]: SqlCredentialsRotationReviewFields,
[SecretRotation.MySqlCredentials]: SqlCredentialsRotationReviewFields,
[SecretRotation.OracleDBCredentials]: SqlCredentialsRotationReviewFields,
[SecretRotation.Auth0ClientSecret]: Auth0ClientSecretRotationReviewFields,
[SecretRotation.AzureClientSecret]: AzureClientSecretRotationReviewFields,
[SecretRotation.LdapPassword]: LdapPasswordRotationReviewFields,
@@ -13,6 +13,7 @@ const COMPONENT_MAP: Record<SecretRotation, React.FC> = {
[SecretRotation.PostgresCredentials]: SqlCredentialsRotationSecretsMappingFields,
[SecretRotation.MsSqlCredentials]: SqlCredentialsRotationSecretsMappingFields,
[SecretRotation.MySqlCredentials]: SqlCredentialsRotationSecretsMappingFields,
[SecretRotation.OracleDBCredentials]: SqlCredentialsRotationSecretsMappingFields,
[SecretRotation.Auth0ClientSecret]: Auth0ClientSecretRotationSecretsMappingFields,
[SecretRotation.AzureClientSecret]: AzureClientSecretRotationSecretsMappingFields,
[SecretRotation.LdapPassword]: LdapPasswordRotationSecretsMappingFields,
@@ -10,6 +10,8 @@ import { PostgresCredentialsRotationSchema } from "@app/components/secret-rotati
import { SecretRotation } from "@app/hooks/api/secretRotationsV2";
import { LdapPasswordRotationMethod } from "@app/hooks/api/secretRotationsV2/types/ldap-password-rotation";
import { OracleDBCredentialsRotationSchema } from "./oracledb-credentials-rotation-schema";
export const SecretRotationV2FormSchema = (isUpdate: boolean) =>
z
.intersection(
@@ -19,6 +21,7 @@ export const SecretRotationV2FormSchema = (isUpdate: boolean) =>
PostgresCredentialsRotationSchema,
MsSqlCredentialsRotationSchema,
MySqlCredentialsRotationSchema,
OracleDBCredentialsRotationSchema,
LdapPasswordRotationSchema,
AwsIamUserSecretRotationSchema
]),
@@ -0,0 +1,12 @@
import { z } from "zod";
import { BaseSecretRotationSchema } from "@app/components/secret-rotations-v2/forms/schemas/base-secret-rotation-v2-schema";
import { SqlCredentialsRotationSchema } from "@app/components/secret-rotations-v2/forms/schemas/shared";
import { SecretRotation } from "@app/hooks/api/secretRotationsV2";
export const OracleDBCredentialsRotationSchema = z
.object({
type: z.literal(SecretRotation.OracleDBCredentials)
})
.merge(SqlCredentialsRotationSchema)
.merge(BaseSecretRotationSchema);
+3
View File
@@ -28,6 +28,7 @@ import {
MsSqlConnectionMethod,
MySqlConnectionMethod,
OnePassConnectionMethod,
OracleDBConnectionMethod,
PostgresConnectionMethod,
TAppConnection,
TeamCityConnectionMethod,
@@ -69,6 +70,7 @@ export const APP_CONNECTION_MAP: Record<
[AppConnection.Postgres]: { name: "PostgreSQL", image: "Postgres.png" },
[AppConnection.MsSql]: { name: "Microsoft SQL Server", image: "MsSql.png" },
[AppConnection.MySql]: { name: "MySQL", image: "MySql.png" },
[AppConnection.OracleDB]: { name: "OracleDB", image: "Oracle.png", enterprise: true },
[AppConnection.Camunda]: { name: "Camunda", image: "Camunda.png" },
[AppConnection.Windmill]: { name: "Windmill", image: "Windmill.png" },
[AppConnection.Auth0]: { name: "Auth0", image: "Auth0.png", size: 40 },
@@ -109,6 +111,7 @@ export const getAppConnectionMethodDetails = (method: TAppConnection["method"])
case PostgresConnectionMethod.UsernameAndPassword:
case MsSqlConnectionMethod.UsernameAndPassword:
case MySqlConnectionMethod.UsernameAndPassword:
case OracleDBConnectionMethod.UsernameAndPassword:
return { name: "Username & Password", icon: faLock };
case HCVaultConnectionMethod.AccessToken:
case TeamCityConnectionMethod.AccessToken:
@@ -20,6 +20,11 @@ export const SECRET_ROTATION_MAP: Record<
image: "MySql.png",
size: 50
},
[SecretRotation.OracleDBCredentials]: {
name: "OracleDB Credentials",
image: "Oracle.png",
size: 50
},
[SecretRotation.Auth0ClientSecret]: {
name: "Auth0 Client Secret",
image: "Auth0.png",
@@ -46,6 +51,7 @@ export const SECRET_ROTATION_CONNECTION_MAP: Record<SecretRotation, AppConnectio
[SecretRotation.PostgresCredentials]: AppConnection.Postgres,
[SecretRotation.MsSqlCredentials]: AppConnection.MsSql,
[SecretRotation.MySqlCredentials]: AppConnection.MySql,
[SecretRotation.OracleDBCredentials]: AppConnection.OracleDB,
[SecretRotation.Auth0ClientSecret]: AppConnection.Auth0,
[SecretRotation.AzureClientSecret]: AppConnection.AzureClientSecrets,
[SecretRotation.LdapPassword]: AppConnection.LDAP,
@@ -57,6 +63,7 @@ export const IS_ROTATION_DUAL_CREDENTIALS: Record<SecretRotation, boolean> = {
[SecretRotation.PostgresCredentials]: true,
[SecretRotation.MsSqlCredentials]: true,
[SecretRotation.MySqlCredentials]: true,
[SecretRotation.OracleDBCredentials]: true,
[SecretRotation.Auth0ClientSecret]: false,
[SecretRotation.AzureClientSecret]: true,
[SecretRotation.LdapPassword]: false,
@@ -14,6 +14,7 @@ export enum AppConnection {
Postgres = "postgres",
MsSql = "mssql",
MySql = "mysql",
OracleDB = "oracledb",
Camunda = "camunda",
Windmill = "windmill",
Auth0 = "auth0",
@@ -74,6 +74,10 @@ export type TMySqlConnectionOption = TAppConnectionOptionBase & {
app: AppConnection.MySql;
};
export type TOracleDBConnectionOption = TAppConnectionOptionBase & {
app: AppConnection.OracleDB;
};
export type TCamundaConnectionOption = TAppConnectionOptionBase & {
app: AppConnection.Camunda;
};
@@ -121,6 +125,7 @@ export type TAppConnectionOption =
| TPostgresConnectionOption
| TMsSqlConnectionOption
| TMySqlConnectionOption
| TOracleDBConnectionOption
| TCamundaConnectionOption
| TWindmillConnectionOption
| TAuth0ConnectionOption
@@ -145,6 +150,7 @@ export type TAppConnectionOptionMap = {
[AppConnection.Postgres]: TPostgresConnectionOption;
[AppConnection.MsSql]: TMsSqlConnectionOption;
[AppConnection.MySql]: TMySqlConnectionOption;
[AppConnection.OracleDB]: TOracleDBConnectionOption;
[AppConnection.Camunda]: TCamundaConnectionOption;
[AppConnection.Windmill]: TWindmillConnectionOption;
[AppConnection.Auth0]: TAuth0ConnectionOption;
@@ -18,6 +18,7 @@ import { TLdapConnection } from "./ldap-connection";
import { TMsSqlConnection } from "./mssql-connection";
import { TMySqlConnection } from "./mysql-connection";
import { TOCIConnection } from "./oci-connection";
import { TOracleDBConnection } from "./oracledb-connection";
import { TPostgresConnection } from "./postgres-connection";
import { TTeamCityConnection } from "./teamcity-connection";
import { TTerraformCloudConnection } from "./terraform-cloud-connection";
@@ -42,6 +43,7 @@ export * from "./ldap-connection";
export * from "./mssql-connection";
export * from "./mysql-connection";
export * from "./oci-connection";
export * from "./oracledb-connection";
export * from "./postgres-connection";
export * from "./teamcity-connection";
export * from "./terraform-cloud-connection";
@@ -64,6 +66,7 @@ export type TAppConnection =
| TPostgresConnection
| TMsSqlConnection
| TMySqlConnection
| TOracleDBConnection
| TCamundaConnection
| TWindmillConnection
| TAuth0Connection
@@ -114,6 +117,7 @@ export type TAppConnectionMap = {
[AppConnection.Postgres]: TPostgresConnection;
[AppConnection.MsSql]: TMsSqlConnection;
[AppConnection.MySql]: TMySqlConnection;
[AppConnection.OracleDB]: TOracleDBConnection;
[AppConnection.Camunda]: TCamundaConnection;
[AppConnection.Windmill]: TWindmillConnection;
[AppConnection.Auth0]: TAuth0Connection;
@@ -0,0 +1,13 @@
import { AppConnection } from "@app/hooks/api/appConnections/enums";
import { TRootAppConnection } from "@app/hooks/api/appConnections/types/root-connection";
import { TBaseSqlConnectionCredentials } from "./shared";
export enum OracleDBConnectionMethod {
UsernameAndPassword = "username-and-password"
}
export type TOracleDBConnection = TRootAppConnection & { app: AppConnection.OracleDB } & {
method: OracleDBConnectionMethod.UsernameAndPassword;
credentials: TBaseSqlConnectionCredentials;
};
@@ -2,6 +2,7 @@ export enum SecretRotation {
PostgresCredentials = "postgres-credentials",
MsSqlCredentials = "mssql-credentials",
MySqlCredentials = "mysql-credentials",
OracleDBCredentials = "oracledb-credentials",
Auth0ClientSecret = "auth0-client-secret",
AzureClientSecret = "azure-client-secret",
LdapPassword = "ldap-password",
@@ -35,11 +35,16 @@ import {
TMySqlCredentialsRotation,
TMySqlCredentialsRotationGeneratedCredentialsResponse
} from "./mysql-credentials-rotation";
import {
TOracleDBCredentialsRotation,
TOracleDBCredentialsRotationGeneratedCredentialsResponse
} from "./oracledb-credentials-rotation";
export type TSecretRotationV2 = (
| TPostgresCredentialsRotation
| TMsSqlCredentialsRotation
| TMySqlCredentialsRotation
| TOracleDBCredentialsRotation
| TAuth0ClientSecretRotation
| TAzureClientSecretRotation
| TLdapPasswordRotation
@@ -63,6 +68,7 @@ export type TViewSecretRotationGeneratedCredentialsResponse =
| TPostgresCredentialsRotationGeneratedCredentialsResponse
| TMsSqlCredentialsRotationGeneratedCredentialsResponse
| TMySqlCredentialsRotationGeneratedCredentialsResponse
| TOracleDBCredentialsRotationGeneratedCredentialsResponse
| TAuth0ClientSecretRotationGeneratedCredentialsResponse
| TAzureClientSecretRotationGeneratedCredentialsResponse
| TLdapPasswordRotationGeneratedCredentialsResponse
@@ -113,6 +119,7 @@ export type TSecretRotationOptionMap = {
[SecretRotation.PostgresCredentials]: TSqlCredentialsRotationOption;
[SecretRotation.MsSqlCredentials]: TSqlCredentialsRotationOption;
[SecretRotation.MySqlCredentials]: TSqlCredentialsRotationOption;
[SecretRotation.OracleDBCredentials]: TSqlCredentialsRotationOption;
[SecretRotation.Auth0ClientSecret]: TAuth0ClientSecretRotationOption;
[SecretRotation.AzureClientSecret]: TAzureClientSecretRotationOption;
[SecretRotation.LdapPassword]: TLdapPasswordRotationOption;
@@ -123,6 +130,7 @@ export type TSecretRotationGeneratedCredentialsResponseMap = {
[SecretRotation.PostgresCredentials]: TPostgresCredentialsRotationGeneratedCredentialsResponse;
[SecretRotation.MsSqlCredentials]: TMsSqlCredentialsRotationGeneratedCredentialsResponse;
[SecretRotation.MySqlCredentials]: TMySqlCredentialsRotationGeneratedCredentialsResponse;
[SecretRotation.OracleDBCredentials]: TOracleDBCredentialsRotationGeneratedCredentialsResponse;
[SecretRotation.Auth0ClientSecret]: TAuth0ClientSecretRotationGeneratedCredentialsResponse;
[SecretRotation.AzureClientSecret]: TAzureClientSecretRotationGeneratedCredentialsResponse;
[SecretRotation.LdapPassword]: TLdapPasswordRotationGeneratedCredentialsResponse;
@@ -0,0 +1,17 @@
import { SecretRotation } from "@app/hooks/api/secretRotationsV2";
import {
TSecretRotationV2Base,
TSecretRotationV2GeneratedCredentialsResponseBase,
TSqlCredentialsRotationGeneratedCredentials,
TSqlCredentialsRotationProperties
} from "@app/hooks/api/secretRotationsV2/types/shared";
export type TOracleDBCredentialsRotation = TSecretRotationV2Base & {
type: SecretRotation.OracleDBCredentials;
} & TSqlCredentialsRotationProperties;
export type TOracleDBCredentialsRotationGeneratedCredentialsResponse =
TSecretRotationV2GeneratedCredentialsResponseBase<
SecretRotation.OracleDBCredentials,
TSqlCredentialsRotationGeneratedCredentials
>;
@@ -17,8 +17,13 @@ export type TSqlCredentialsRotationOption = {
type:
| SecretRotation.PostgresCredentials
| SecretRotation.MsSqlCredentials
| SecretRotation.MySqlCredentials;
connection: AppConnection.Postgres | AppConnection.MsSql | AppConnection.MySql;
| SecretRotation.MySqlCredentials
| SecretRotation.OracleDBCredentials;
connection:
| AppConnection.Postgres
| AppConnection.MsSql
| AppConnection.MySql
| AppConnection.OracleDB;
template: {
secretsMapping: TSqlCredentialsRotationProperties["secretsMapping"];
createUserStatement: string;
@@ -27,6 +27,7 @@ import { LdapConnectionForm } from "./LdapConnectionForm";
import { MsSqlConnectionForm } from "./MsSqlConnectionForm";
import { MySqlConnectionForm } from "./MySqlConnectionForm";
import { OCIConnectionForm } from "./OCIConnectionForm";
import { OracleDBConnectionForm } from "./OracleDBConnectionForm";
import { PostgresConnectionForm } from "./PostgresConnectionForm";
import { TeamCityConnectionForm } from "./TeamCityConnectionForm";
import { TerraformCloudConnectionForm } from "./TerraformCloudConnectionForm";
@@ -96,6 +97,8 @@ const CreateForm = ({ app, onComplete }: CreateFormProps) => {
return <MsSqlConnectionForm onSubmit={onSubmit} />;
case AppConnection.MySql:
return <MySqlConnectionForm onSubmit={onSubmit} />;
case AppConnection.OracleDB:
return <OracleDBConnectionForm onSubmit={onSubmit} />;
case AppConnection.Camunda:
return <CamundaConnectionForm onSubmit={onSubmit} />;
case AppConnection.AzureClientSecrets:
@@ -178,6 +181,8 @@ const UpdateForm = ({ appConnection, onComplete }: UpdateFormProps) => {
return <MsSqlConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
case AppConnection.MySql:
return <MySqlConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
case AppConnection.OracleDB:
return <OracleDBConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
case AppConnection.Camunda:
return <CamundaConnectionForm onSubmit={onSubmit} appConnection={appConnection} />;
case AppConnection.AzureClientSecrets:
@@ -0,0 +1,155 @@
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 { OracleDBConnectionMethod, TOracleDBConnection } from "@app/hooks/api/appConnections";
import { AppConnection } from "@app/hooks/api/appConnections/enums";
import { PlatformManagedConfirmationModal } from "@app/pages/organization/AppConnections/AppConnectionsPage/components/AppConnectionForm/shared/PlatformManagedConfirmationModal";
import {
genericAppConnectionFieldsSchema,
GenericAppConnectionsFields
} from "./GenericAppConnectionFields";
import {
BaseSqlUsernameAndPasswordConnectionSchema,
PlatformManagedNoticeBanner,
SqlConnectionFields
} from "./shared";
type Props = {
appConnection?: TOracleDBConnection;
onSubmit: (formData: FormData) => Promise<void>;
};
const rootSchema = genericAppConnectionFieldsSchema.extend({
app: z.literal(AppConnection.OracleDB),
isPlatformManagedCredentials: z.boolean().optional()
});
const formSchema = z.discriminatedUnion("method", [
rootSchema.extend({
method: z.literal(OracleDBConnectionMethod.UsernameAndPassword),
credentials: BaseSqlUsernameAndPasswordConnectionSchema
})
]);
type FormData = z.infer<typeof formSchema>;
export const OracleDBConnectionForm = ({ appConnection, onSubmit }: Props) => {
const isUpdate = Boolean(appConnection);
const [showConfirmation, setShowConfirmation] = useState(false);
const [selectedTabIndex, setSelectedTabIndex] = useState(0);
const form = useForm<FormData>({
resolver: zodResolver(formSchema),
defaultValues: appConnection ?? {
app: AppConnection.OracleDB,
method: OracleDBConnectionMethod.UsernameAndPassword,
credentials: {
host: "",
port: 1521,
database: "ORCL", // Typically FREEPDB1 or ORCL
username: "", // Typically pdbadmin or ADMIN
password: "",
sslEnabled: true,
sslRejectUnauthorized: true,
sslCertificate: undefined
}
}
});
const {
handleSubmit,
control,
formState: { isSubmitting, isDirty }
} = form;
const isPlatformManagedCredentials = appConnection?.isPlatformManagedCredentials ?? false;
const confirmSubmit = async (formData: FormData) => {
if (formData.isPlatformManagedCredentials) {
setShowConfirmation(true);
return;
}
await onSubmit(formData);
};
return (
<FormProvider {...form}>
<form
onSubmit={(e) => {
setSelectedTabIndex(0);
handleSubmit(confirmSubmit)(e);
}}
>
{!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.OracleDB].name
}. This field cannot be changed after creation.`}
errorText={error?.message}
isError={Boolean(error?.message)}
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(OracleDBConnectionMethod).map((method) => {
return (
<SelectItem value={method} key={method}>
{getAppConnectionMethodDetails(method).name}{" "}
</SelectItem>
);
})}
</Select>
</FormControl>
)}
/>
<SqlConnectionFields
isPlatformManagedCredentials={isPlatformManagedCredentials}
selectedTabIndex={selectedTabIndex}
setSelectedTabIndex={setSelectedTabIndex}
/>
{isPlatformManagedCredentials ? (
<PlatformManagedNoticeBanner />
) : (
<div className="mt-6 flex items-center">
<Button
className="mr-4"
size="sm"
type="submit"
colorSchema="secondary"
isLoading={isSubmitting}
isDisabled={isSubmitting || !isDirty}
>
{isUpdate ? "Update Credentials" : "Connect to Database"}
</Button>
<ModalClose asChild>
<Button colorSchema="secondary" variant="plain">
Cancel
</Button>
</ModalClose>
</div>
)}
</form>
<PlatformManagedConfirmationModal
onConfirm={() => handleSubmit(onSubmit)()}
onOpenChange={setShowConfirmation}
isOpen={showConfirmation}
/>
</FormProvider>
);
};