with stripSchema and filterForSchema

This commit is contained in:
x032205
2025-05-13 23:08:54 -04:00
parent f6e1441dc0
commit bae62421ae
14 changed files with 275 additions and 151 deletions

View File

@@ -2109,6 +2109,7 @@ export const SecretSyncs = {
const destinationName = SECRET_SYNC_NAME_MAP[destination];
return {
initialSyncBehavior: `Specify how Infisical should resolve the initial sync to the ${destinationName} destination.`,
keySchema: `Specify the format to use for structuring secret keys in the ${destinationName} destination.`,
disableSecretDeletion: `Enable this flag to prevent removal of secrets from the ${destinationName} destination when syncing.`
};
},

View File

@@ -367,7 +367,17 @@ export const registerSyncSecretsEndpoints = <T extends TSecretSync, I extends TS
querystring: z.object({
importBehavior: z
.nativeEnum(SecretSyncImportBehavior)
.describe(SecretSyncs.IMPORT_SECRETS(destination).importBehavior)
.describe(SecretSyncs.IMPORT_SECRETS(destination).importBehavior),
filterForSchema: z
.enum(["true", "false"])
.optional()
.default("false")
.transform((v) => v === "true"),
stripSchema: z
.enum(["true", "false"])
.optional()
.default("false")
.transform((v) => v === "true")
}),
response: {
200: z.object({ secretSync: responseSchema })
@@ -376,13 +386,15 @@ export const registerSyncSecretsEndpoints = <T extends TSecretSync, I extends TS
onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]),
handler: async (req) => {
const { syncId } = req.params;
const { importBehavior } = req.query;
const { importBehavior, filterForSchema, stripSchema } = req.query;
const secretSync = (await server.services.secretSync.triggerSecretSyncImportSecretsById(
{
syncId,
destination,
importBehavior
importBehavior,
filterForSchema,
stripSchema
},
req.permission
)) as T;

View File

@@ -61,45 +61,63 @@ type TSyncSecretDeps = {
kmsService: Pick<TKmsServiceFactory, "createCipherPairWithDataKey">;
};
// const addAffixes = (secretSync: TSecretSyncWithCredentials, unprocessedSecretMap: TSecretMap) => {
// let secretMap = { ...unprocessedSecretMap };
//
// const { appendSuffix, prependPrefix } = secretSync.syncOptions;
//
// if (appendSuffix || prependPrefix) {
// secretMap = {};
// Object.entries(unprocessedSecretMap).forEach(([key, value]) => {
// secretMap[`${prependPrefix || ""}${key}${appendSuffix || ""}`] = value;
// });
// }
//
// return secretMap;
// };
//
// const stripAffixes = (secretSync: TSecretSyncWithCredentials, unprocessedSecretMap: TSecretMap) => {
// let secretMap = { ...unprocessedSecretMap };
//
// const { appendSuffix, prependPrefix } = secretSync.syncOptions;
//
// if (appendSuffix || prependPrefix) {
// secretMap = {};
// Object.entries(unprocessedSecretMap).forEach(([key, value]) => {
// let processedKey = key;
//
// if (prependPrefix && processedKey.startsWith(prependPrefix)) {
// processedKey = processedKey.slice(prependPrefix.length);
// }
//
// if (appendSuffix && processedKey.endsWith(appendSuffix)) {
// processedKey = processedKey.slice(0, -appendSuffix.length);
// }
//
// secretMap[processedKey] = value;
// });
// }
//
// return secretMap;
// };
interface TSyncSecretConfig {
filterForSchema?: boolean;
stripSchema?: boolean;
}
// Add schema to secret keys
const addSchema = (unprocessedSecretMap: TSecretMap, schema?: string): TSecretMap => {
if (!schema) return unprocessedSecretMap;
const processedSecretMap: TSecretMap = {};
for (const [key, value] of Object.entries(unprocessedSecretMap)) {
const newKey = schema.replace("{{secretKey}}", key);
processedSecretMap[newKey] = value;
}
return processedSecretMap;
};
// Strip schema from secret keys
const stripSchema = (unprocessedSecretMap: TSecretMap, schema?: string): TSecretMap => {
if (!schema) return unprocessedSecretMap;
const [prefix, suffix] = schema.split("{{secretKey}}");
const strippedMap: TSecretMap = {};
for (const [key, value] of Object.entries(unprocessedSecretMap)) {
if (!key.startsWith(prefix) || !key.endsWith(suffix)) {
// eslint-disable-next-line no-continue
continue;
}
const strippedKey = key.slice(prefix.length, key.length - suffix.length);
strippedMap[strippedKey] = value;
}
return strippedMap;
};
// Filter only for secrets with keys that match the schema
const filterForSchema = (secretMap: TSecretMap, schema?: string): TSecretMap => {
if (!schema) return secretMap;
const [prefix, suffix] = schema.split("{{secretKey}}");
if (prefix === undefined || suffix === undefined) return secretMap;
const filteredMap: TSecretMap = {};
for (const [key, value] of Object.entries(secretMap)) {
if (key.startsWith(prefix) && key.endsWith(suffix)) {
filteredMap[key] = value;
}
}
return filteredMap;
};
export const SecretSyncFns = {
syncSecrets: (
@@ -107,51 +125,51 @@ export const SecretSyncFns = {
secretMap: TSecretMap,
{ kmsService, appConnectionDAL }: TSyncSecretDeps
): Promise<void> => {
// const affixedSecretMap = addAffixes(secretSync, secretMap);
const schemaSecretMap = addSchema(secretMap, secretSync.syncOptions.keySchema);
switch (secretSync.destination) {
case SecretSync.AWSParameterStore:
return AwsParameterStoreSyncFns.syncSecrets(secretSync, secretMap);
return AwsParameterStoreSyncFns.syncSecrets(secretSync, schemaSecretMap);
case SecretSync.AWSSecretsManager:
return AwsSecretsManagerSyncFns.syncSecrets(secretSync, secretMap);
return AwsSecretsManagerSyncFns.syncSecrets(secretSync, schemaSecretMap);
case SecretSync.GitHub:
return GithubSyncFns.syncSecrets(secretSync, secretMap);
return GithubSyncFns.syncSecrets(secretSync, schemaSecretMap);
case SecretSync.GCPSecretManager:
return GcpSyncFns.syncSecrets(secretSync, secretMap);
return GcpSyncFns.syncSecrets(secretSync, schemaSecretMap);
case SecretSync.AzureKeyVault:
return azureKeyVaultSyncFactory({
appConnectionDAL,
kmsService
}).syncSecrets(secretSync, secretMap);
}).syncSecrets(secretSync, schemaSecretMap);
case SecretSync.AzureAppConfiguration:
return azureAppConfigurationSyncFactory({
appConnectionDAL,
kmsService
}).syncSecrets(secretSync, secretMap);
}).syncSecrets(secretSync, schemaSecretMap);
case SecretSync.Databricks:
return databricksSyncFactory({
appConnectionDAL,
kmsService
}).syncSecrets(secretSync, secretMap);
}).syncSecrets(secretSync, schemaSecretMap);
case SecretSync.Humanitec:
return HumanitecSyncFns.syncSecrets(secretSync, secretMap);
return HumanitecSyncFns.syncSecrets(secretSync, schemaSecretMap);
case SecretSync.TerraformCloud:
return TerraformCloudSyncFns.syncSecrets(secretSync, secretMap);
return TerraformCloudSyncFns.syncSecrets(secretSync, schemaSecretMap);
case SecretSync.Camunda:
return camundaSyncFactory({
appConnectionDAL,
kmsService
}).syncSecrets(secretSync, secretMap);
}).syncSecrets(secretSync, schemaSecretMap);
case SecretSync.Vercel:
return VercelSyncFns.syncSecrets(secretSync, secretMap);
return VercelSyncFns.syncSecrets(secretSync, schemaSecretMap);
case SecretSync.Windmill:
return WindmillSyncFns.syncSecrets(secretSync, secretMap);
return WindmillSyncFns.syncSecrets(secretSync, schemaSecretMap);
case SecretSync.HCVault:
return HCVaultSyncFns.syncSecrets(secretSync, secretMap);
return HCVaultSyncFns.syncSecrets(secretSync, schemaSecretMap);
case SecretSync.TeamCity:
return TeamCitySyncFns.syncSecrets(secretSync, secretMap);
return TeamCitySyncFns.syncSecrets(secretSync, schemaSecretMap);
case SecretSync.OCIVault:
return OCIVaultSyncFns.syncSecrets(secretSync, secretMap);
return OCIVaultSyncFns.syncSecrets(secretSync, schemaSecretMap);
default:
throw new Error(
`Unhandled sync destination for sync secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`
@@ -160,7 +178,8 @@ export const SecretSyncFns = {
},
getSecrets: async (
secretSync: TSecretSyncWithCredentials,
{ kmsService, appConnectionDAL }: TSyncSecretDeps
{ kmsService, appConnectionDAL }: TSyncSecretDeps,
config?: TSyncSecretConfig
): Promise<TSecretMap> => {
let secretMap: TSecretMap;
switch (secretSync.destination) {
@@ -226,59 +245,68 @@ export const SecretSyncFns = {
);
}
return secretMap;
// return stripAffixes(secretSync, secretMap);
let processedSecretMap = secretMap;
if (config?.filterForSchema) {
processedSecretMap = filterForSchema(processedSecretMap);
}
if (config?.stripSchema) {
return stripSchema(processedSecretMap, secretSync.syncOptions.keySchema);
}
return processedSecretMap;
},
removeSecrets: (
secretSync: TSecretSyncWithCredentials,
secretMap: TSecretMap,
{ kmsService, appConnectionDAL }: TSyncSecretDeps
): Promise<void> => {
// const affixedSecretMap = addAffixes(secretSync, secretMap);
const schemaSecretMap = addSchema(secretMap, secretSync.syncOptions.keySchema);
switch (secretSync.destination) {
case SecretSync.AWSParameterStore:
return AwsParameterStoreSyncFns.removeSecrets(secretSync, secretMap);
return AwsParameterStoreSyncFns.removeSecrets(secretSync, schemaSecretMap);
case SecretSync.AWSSecretsManager:
return AwsSecretsManagerSyncFns.removeSecrets(secretSync, secretMap);
return AwsSecretsManagerSyncFns.removeSecrets(secretSync, schemaSecretMap);
case SecretSync.GitHub:
return GithubSyncFns.removeSecrets(secretSync, secretMap);
return GithubSyncFns.removeSecrets(secretSync, schemaSecretMap);
case SecretSync.GCPSecretManager:
return GcpSyncFns.removeSecrets(secretSync, secretMap);
return GcpSyncFns.removeSecrets(secretSync, schemaSecretMap);
case SecretSync.AzureKeyVault:
return azureKeyVaultSyncFactory({
appConnectionDAL,
kmsService
}).removeSecrets(secretSync, secretMap);
}).removeSecrets(secretSync, schemaSecretMap);
case SecretSync.AzureAppConfiguration:
return azureAppConfigurationSyncFactory({
appConnectionDAL,
kmsService
}).removeSecrets(secretSync, secretMap);
}).removeSecrets(secretSync, schemaSecretMap);
case SecretSync.Databricks:
return databricksSyncFactory({
appConnectionDAL,
kmsService
}).removeSecrets(secretSync, secretMap);
}).removeSecrets(secretSync, schemaSecretMap);
case SecretSync.Humanitec:
return HumanitecSyncFns.removeSecrets(secretSync, secretMap);
return HumanitecSyncFns.removeSecrets(secretSync, schemaSecretMap);
case SecretSync.TerraformCloud:
return TerraformCloudSyncFns.removeSecrets(secretSync, secretMap);
return TerraformCloudSyncFns.removeSecrets(secretSync, schemaSecretMap);
case SecretSync.Camunda:
return camundaSyncFactory({
appConnectionDAL,
kmsService
}).removeSecrets(secretSync, secretMap);
}).removeSecrets(secretSync, schemaSecretMap);
case SecretSync.Vercel:
return VercelSyncFns.removeSecrets(secretSync, secretMap);
return VercelSyncFns.removeSecrets(secretSync, schemaSecretMap);
case SecretSync.Windmill:
return WindmillSyncFns.removeSecrets(secretSync, secretMap);
return WindmillSyncFns.removeSecrets(secretSync, schemaSecretMap);
case SecretSync.HCVault:
return HCVaultSyncFns.removeSecrets(secretSync, secretMap);
return HCVaultSyncFns.removeSecrets(secretSync, schemaSecretMap);
case SecretSync.TeamCity:
return TeamCitySyncFns.removeSecrets(secretSync, secretMap);
return TeamCitySyncFns.removeSecrets(secretSync, schemaSecretMap);
case SecretSync.OCIVault:
return OCIVaultSyncFns.removeSecrets(secretSync, secretMap);
return OCIVaultSyncFns.removeSecrets(secretSync, schemaSecretMap);
default:
throw new Error(
`Unhandled sync destination for remove secrets fns: ${(secretSync as TSecretSyncWithCredentials).destination}`

View File

@@ -319,9 +319,12 @@ export const secretSyncQueueFactory = ({
);
};
// TODO(andrey): Possibly add a "stripSchema" parameter for imports?
const $importSecrets = async (
secretSync: TSecretSyncWithCredentials,
importBehavior: SecretSyncImportBehavior
importBehavior: SecretSyncImportBehavior,
filterForSchema: boolean,
stripSchema: boolean
): Promise<TSecretMap> => {
const { projectId, environment, folder } = secretSync;
@@ -330,10 +333,17 @@ export const secretSyncQueueFactory = ({
"Invalid Secret Sync source configuration: folder no longer exists. Please update source environment and secret path."
);
const importedSecrets = await SecretSyncFns.getSecrets(secretSync, {
appConnectionDAL,
kmsService
});
const importedSecrets = await SecretSyncFns.getSecrets(
secretSync,
{
appConnectionDAL,
kmsService
},
{
filterForSchema,
stripSchema
}
);
if (!Object.keys(importedSecrets).length) return {};
@@ -439,11 +449,14 @@ export const secretSyncQueueFactory = ({
const secretMap = await $getInfisicalSecrets(secretSync);
if (!lastSyncedAt && initialSyncBehavior !== SecretSyncInitialSyncBehavior.OverwriteDestination) {
// TODO(andrey): Possibly add a way to filter / strip schemas on initial sync?
const importedSecretMap = await $importSecrets(
secretSyncWithCredentials,
initialSyncBehavior === SecretSyncInitialSyncBehavior.ImportPrioritizeSource
? SecretSyncImportBehavior.PrioritizeSource
: SecretSyncImportBehavior.PrioritizeDestination
: SecretSyncImportBehavior.PrioritizeDestination,
false,
false
);
Object.entries(importedSecretMap).forEach(([key, secretData]) => {
@@ -535,7 +548,7 @@ export const secretSyncQueueFactory = ({
const $handleImportSecretsJob = async (job: TSecretSyncImportSecretsDTO) => {
const {
data: { syncId, auditLogInfo, importBehavior }
data: { syncId, auditLogInfo, importBehavior, filterForSchema, stripSchema }
} = job;
const secretSync = await secretSyncDAL.findById(syncId);
@@ -573,7 +586,9 @@ export const secretSyncQueueFactory = ({
credentials
}
} as TSecretSyncWithCredentials,
importBehavior
importBehavior,
filterForSchema,
stripSchema
);
isSuccess = true;

View File

@@ -1,3 +1,4 @@
import RE2 from "re2";
import { AnyZodObject, z } from "zod";
import { SecretSyncsSchema } from "@app/db/schemas/secret-syncs";
@@ -24,6 +25,14 @@ const BaseSyncOptionsSchema = <T extends AnyZodObject | undefined = undefined>({
? z.nativeEnum(SecretSyncInitialSyncBehavior)
: z.literal(SecretSyncInitialSyncBehavior.OverwriteDestination)
).describe(SecretSyncs.SYNC_OPTIONS(destination).initialSyncBehavior),
keySchema: z
.string()
.optional()
.refine((val) => !val || new RE2(/^(?:[a-zA-Z0-9\-/]*)(?:\{\{secretKey\}\})(?:[a-zA-Z0-9\-/]*)$/).test(val), {
message:
"Key schema must include {{secretKey}} and only contain letters, numbers, dashes, slashes, and the {{secretKey}} placeholder."
})
.describe(SecretSyncs.SYNC_OPTIONS(destination).keySchema),
disableSecretDeletion: z.boolean().optional().describe(SecretSyncs.SYNC_OPTIONS(destination).disableSecretDeletion)
});

View File

@@ -231,6 +231,8 @@ export type TQueueSecretSyncImportSecretsByIdDTO = {
syncId: string;
importBehavior: SecretSyncImportBehavior;
auditLogInfo?: AuditLogInfo;
filterForSchema: boolean;
stripSchema: boolean;
};
export type TTriggerSecretSyncImportSecretsByIdDTO = {

View File

@@ -10,7 +10,8 @@ import {
ModalClose,
ModalContent,
Select,
SelectItem
SelectItem,
Switch
} from "@app/components/v2";
import { SECRET_SYNC_IMPORT_BEHAVIOR_MAP, SECRET_SYNC_MAP } from "@app/helpers/secretSyncs";
import {
@@ -31,30 +32,49 @@ type ContentProps = {
};
const FormSchema = z.object({
importBehavior: z.nativeEnum(SecretSyncImportBehavior)
importBehavior: z.nativeEnum(SecretSyncImportBehavior),
filterForSchema: z.boolean(),
stripSchema: z.boolean()
});
type TFormData = z.infer<typeof FormSchema>;
const Content = ({ secretSync, onComplete }: ContentProps) => {
const { id: syncId, destination, projectId } = secretSync;
const {
id: syncId,
destination,
projectId,
syncOptions: { keySchema }
} = secretSync;
const destinationName = SECRET_SYNC_MAP[destination].name;
const {
handleSubmit,
control,
formState: { isSubmitting, isDirty }
} = useForm<TFormData>({ resolver: zodResolver(FormSchema) });
} = useForm<TFormData>({
resolver: zodResolver(FormSchema),
defaultValues: {
filterForSchema: false,
stripSchema: false
}
});
const triggerImportSecrets = useTriggerSecretSyncImportSecrets();
const handleTriggerImportSecrets = async ({ importBehavior }: TFormData) => {
const handleTriggerImportSecrets = async ({
importBehavior,
filterForSchema,
stripSchema
}: TFormData) => {
try {
await triggerImportSecrets.mutateAsync({
syncId,
destination,
importBehavior,
projectId
projectId,
filterForSchema,
stripSchema
});
createNotification({
@@ -131,6 +151,64 @@ const Content = ({ secretSync, onComplete }: ContentProps) => {
</FormControl>
)}
/>
{keySchema && (
<>
<Controller
control={control}
name="filterForSchema"
defaultValue
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
tooltipClassName="max-w-md"
tooltipText={
<div className="flex flex-col gap-2">
<p>
If enabled, Infisical will only import destination secrets that match your key
schema:
</p>
<code className="text-mineshaft-300">{keySchema}</code>
</div>
}
label="Filter Keys for Schema"
isError={Boolean(error)}
errorText={error?.message}
>
<Switch
id="filter-for-schema"
thumbClassName="bg-mineshaft-800"
isChecked={value}
onCheckedChange={onChange}
>
Only import destination secrets that match schema
</Switch>
</FormControl>
)}
/>
<Controller
control={control}
name="stripSchema"
defaultValue
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
tooltipClassName="max-w-md"
tooltipText="If enabled, Infisical will strip secret keys according to your schema. Keys that do not match the schema will not be affected."
label="Strip Schema"
isError={Boolean(error)}
errorText={error?.message}
>
<Switch
id="strip-schema"
thumbClassName="bg-mineshaft-800"
isChecked={value}
onCheckedChange={onChange}
>
Strip schema from imported secret keys
</Switch>
</FormControl>
)}
/>
</>
)}
<div className="mt-8 flex w-full items-center justify-between gap-2">
<ModalClose asChild>
<Button colorSchema="secondary" variant="plain">

View File

@@ -3,7 +3,7 @@ import { Controller, useFormContext } from "react-hook-form";
import { faQuestionCircle, faTriangleExclamation } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { FormControl, Select, SelectItem, Switch, Tooltip } from "@app/components/v2";
import { FormControl, Input, Select, SelectItem, Switch, Tooltip } from "@app/components/v2";
import { SECRET_SYNC_INITIAL_SYNC_BEHAVIOR_MAP, SECRET_SYNC_MAP } from "@app/helpers/secretSyncs";
import { SecretSync, useSecretSyncOption } from "@app/hooks/api/secretSyncs";
@@ -122,6 +122,22 @@ export const SecretSyncOptionsFields = ({ hideInitialSync }: Props) => {
)}
</>
)}
<Controller
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
tooltipClassName="max-w-md"
tooltipText="When a secret is synced, it's key will be injected into the key schema before it reaches the destination. This is useful for organization."
isError={Boolean(error)}
isOptional
errorText={error?.message}
label="Key Schema"
>
<Input value={value} onChange={onChange} placeholder="prefix/{{secretKey}}/suffix" />
</FormControl>
)}
control={control}
name="syncOptions.keySchema"
/>
{AdditionalSyncOptionsFieldsComponent}
<Controller
control={control}
@@ -161,34 +177,6 @@ export const SecretSyncOptionsFields = ({ hideInitialSync }: Props) => {
);
}}
/>
{/* <Controller
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
isError={Boolean(error)}
isOptional
errorText={error?.message}
label="Prepend Prefix"
>
<Input className="uppercase" value={value} onChange={onChange} placeholder="INF_" />
</FormControl>
)}
control={control}
name="syncOptions.prependPrefix"
/>
<Controller
render={({ field: { value, onChange }, fieldState: { error } }) => (
<FormControl
isError={Boolean(error)}
isOptional
errorText={error?.message}
label="Append Suffix"
>
<Input className="uppercase" value={value} onChange={onChange} placeholder="_INF" />
</FormControl>
)}
control={control}
name="syncOptions.appendSuffix"
/> */}
</>
);
};

View File

@@ -41,11 +41,7 @@ export const SecretSyncReviewFields = () => {
connection,
environment,
secretPath,
syncOptions: {
// appendSuffix, prependPrefix,
disableSecretDeletion,
initialSyncBehavior
},
syncOptions: { disableSecretDeletion, initialSyncBehavior, keySchema },
destination,
isAutoSyncEnabled
} = watch();
@@ -137,8 +133,7 @@ export const SecretSyncReviewFields = () => {
<GenericFieldLabel label="Initial Sync Behavior">
{SECRET_SYNC_INITIAL_SYNC_BEHAVIOR_MAP[initialSyncBehavior](destinationName).name}
</GenericFieldLabel>
{/* <SecretSyncLabel label="Prepend Prefix">{prependPrefix}</SecretSyncLabel>
<SecretSyncLabel label="Append Suffix">{appendSuffix}</SecretSyncLabel> */}
<GenericFieldLabel label="Key Schema">{keySchema}</GenericFieldLabel>
{AdditionalSyncOptionsFieldsComponent}
{disableSecretDeletion && (
<GenericFieldLabel label="Secret Deletion">

View File

@@ -8,18 +8,17 @@ export const BaseSecretSyncSchema = <T extends AnyZodObject | undefined = undefi
) => {
const baseSyncOptionsSchema = z.object({
initialSyncBehavior: z.nativeEnum(SecretSyncInitialSyncBehavior),
disableSecretDeletion: z.boolean().optional().default(false)
// scott: removed temporarily for evaluation of template formatting
// prependPrefix: z
// .string()
// .trim()
// .transform((str) => str.toUpperCase())
// .optional(),
// appendSuffix: z
// .string()
// .trim()
// .transform((str) => str.toUpperCase())
// .optional()
disableSecretDeletion: z.boolean().optional().default(false),
keySchema: z
.string()
.optional()
.refine(
(val) => !val || /^(?:[a-zA-Z0-9\-/]*)(?:\{\{secretKey\}\})(?:[a-zA-Z0-9\-/]*)$/.test(val),
{
message:
"Key schema must include {{secretKey}} and only contain letters, numbers, dashes, slashes, and the {{secretKey}} placeholder."
}
)
});
const syncOptionsSchema = additionalSyncOptions

View File

@@ -86,10 +86,12 @@ export const useTriggerSecretSyncImportSecrets = () => {
mutationFn: async ({
syncId,
destination,
importBehavior
importBehavior,
filterForSchema,
stripSchema
}: TTriggerSecretSyncImportSecretsDTO) => {
const { data } = await apiRequest.post(
`/api/v1/secret-syncs/${destination}/${syncId}/import-secrets?importBehavior=${importBehavior}`
`/api/v1/secret-syncs/${destination}/${syncId}/import-secrets?importBehavior=${importBehavior}&filterForSchema=${filterForSchema}&stripSchema=${stripSchema}`
);
return data;

View File

@@ -82,6 +82,8 @@ export type TTriggerSecretSyncImportSecretsDTO = {
syncId: string;
importBehavior: SecretSyncImportBehavior;
projectId: string;
filterForSchema: boolean;
stripSchema: boolean;
};
export type TTriggerSecretSyncRemoveSecretsDTO = {

View File

@@ -4,8 +4,7 @@ import { SecretSyncInitialSyncBehavior, SecretSyncStatus } from "@app/hooks/api/
export type RootSyncOptions = {
initialSyncBehavior: SecretSyncInitialSyncBehavior;
disableSecretDeletion?: boolean;
// prependPrefix?: string;
// appendSuffix?: string;
keySchema?: string;
};
export type TRootSecretSync = {

View File

@@ -21,12 +21,7 @@ type Props = {
export const SecretSyncOptionsSection = ({ secretSync, onEditOptions }: Props) => {
const {
destination,
syncOptions: {
// appendSuffix,
// prependPrefix,
initialSyncBehavior,
disableSecretDeletion
}
syncOptions: { initialSyncBehavior, disableSecretDeletion, keySchema }
} = secretSync;
let AdditionalSyncOptionsComponent: ReactNode;
@@ -88,8 +83,7 @@ export const SecretSyncOptionsSection = ({ secretSync, onEditOptions }: Props) =
<GenericFieldLabel label="Initial Sync Behavior">
{SECRET_SYNC_INITIAL_SYNC_BEHAVIOR_MAP[initialSyncBehavior](destination).name}
</GenericFieldLabel>
{/* <SecretSyncLabel label="Prefix">{prependPrefix}</SecretSyncLabel>
<SecretSyncLabel label="Suffix">{appendSuffix}</SecretSyncLabel> */}
<GenericFieldLabel label="Key Schema">{keySchema}</GenericFieldLabel>
{AdditionalSyncOptionsComponent}
{disableSecretDeletion && (
<GenericFieldLabel label="Secret Deletion">