Files
infisical/backend/src/services/secret-sync/aws-secrets-manager/aws-secrets-manager-sync-schemas.ts
T
2025-11-13 20:04:25 +05:30

179 lines
6.1 KiB
TypeScript

import { z } from "zod";
import { SecretSyncs } from "@app/lib/api-docs";
import { CharacterType, characterValidator } from "@app/lib/validator/validate-string";
import { AppConnection, AWSRegion } from "@app/services/app-connection/app-connection-enums";
import { AwsSecretsManagerSyncMappingBehavior } from "@app/services/secret-sync/aws-secrets-manager/aws-secrets-manager-sync-enums";
import { SecretSync } from "@app/services/secret-sync/secret-sync-enums";
import {
BaseSecretSyncSchema,
GenericCreateSecretSyncFieldsSchema,
GenericUpdateSecretSyncFieldsSchema
} from "@app/services/secret-sync/secret-sync-schemas";
import { TSyncOptionsConfig } from "@app/services/secret-sync/secret-sync-types";
import { SECRET_SYNC_NAME_MAP } from "../secret-sync-maps";
const AwsSecretsManagerSyncDestinationConfigSchema = z
.discriminatedUnion("mappingBehavior", [
z.object({
mappingBehavior: z
.literal(AwsSecretsManagerSyncMappingBehavior.OneToOne)
.describe(SecretSyncs.DESTINATION_CONFIG.AWS_SECRETS_MANAGER.mappingBehavior)
}),
z.object({
mappingBehavior: z
.literal(AwsSecretsManagerSyncMappingBehavior.ManyToOne)
.describe(SecretSyncs.DESTINATION_CONFIG.AWS_SECRETS_MANAGER.mappingBehavior),
secretName: z
.string()
.min(1, "Secret name is required")
.max(256, "Secret name cannot exceed 256 characters")
.refine(
(val) =>
characterValidator([
CharacterType.AlphaNumeric,
CharacterType.ForwardSlash,
CharacterType.Underscore,
CharacterType.Plus,
CharacterType.Equals,
CharacterType.Period,
CharacterType.At,
CharacterType.Hyphen
])(val),
"Secret name must contain only alphanumeric characters and the characters /_+=.@-"
)
.describe(SecretSyncs.DESTINATION_CONFIG.AWS_SECRETS_MANAGER.secretName)
})
])
.and(
z.object({
region: z.nativeEnum(AWSRegion).describe(SecretSyncs.DESTINATION_CONFIG.AWS_SECRETS_MANAGER.region)
})
);
const tagFieldCharacterValidator = characterValidator([
CharacterType.AlphaNumeric,
CharacterType.Spaces,
CharacterType.Period,
CharacterType.Underscore,
CharacterType.Colon,
CharacterType.ForwardSlash,
CharacterType.Equals,
CharacterType.Plus,
CharacterType.Hyphen,
CharacterType.At
]);
const AwsSecretsManagerSyncOptionsSchema = z.object({
keyId: z
.string()
.min(1, "Invalid KMS Key ID")
.max(256, "Invalid KMS Key ID")
.refine(
(val) =>
characterValidator([
CharacterType.AlphaNumeric,
CharacterType.Colon,
CharacterType.ForwardSlash,
CharacterType.Underscore,
CharacterType.Hyphen
])(val),
"Invalid KMS Key ID"
)
.optional()
.describe(SecretSyncs.ADDITIONAL_SYNC_OPTIONS.AWS_SECRETS_MANAGER.keyId),
tags: z
.object({
key: z
.string()
.min(1, "Tag key required")
.max(128, "Tag key cannot exceed 128 characters")
.refine(
(val) => tagFieldCharacterValidator(val),
"Invalid resource tag key: keys can only contain Unicode letters, digits, white space and any of the following: _.:/=+@-"
),
value: z
.string()
.max(256, "Tag value cannot exceed 256 characters")
.refine(
(val) => tagFieldCharacterValidator(val),
"Invalid resource tag value: tag values can only contain Unicode letters, digits, white space and any of the following: _.:/=+@-"
)
})
.array()
.max(50)
.refine((items) => new Set(items.map((item) => item.key)).size === items.length, {
message: "Tag keys must be unique"
})
.optional()
.describe(SecretSyncs.ADDITIONAL_SYNC_OPTIONS.AWS_SECRETS_MANAGER.tags),
syncSecretMetadataAsTags: z
.boolean()
.optional()
.describe(SecretSyncs.ADDITIONAL_SYNC_OPTIONS.AWS_SECRETS_MANAGER.syncSecretMetadataAsTags)
});
const AwsSecretsManagerSyncOptionsConfig: TSyncOptionsConfig = { canImportSecrets: true };
export const AwsSecretsManagerSyncSchema = BaseSecretSyncSchema(
SecretSync.AWSSecretsManager,
AwsSecretsManagerSyncOptionsConfig,
AwsSecretsManagerSyncOptionsSchema
)
.extend({
destination: z.literal(SecretSync.AWSSecretsManager),
destinationConfig: AwsSecretsManagerSyncDestinationConfigSchema
})
.describe(JSON.stringify({ title: SECRET_SYNC_NAME_MAP[SecretSync.AWSSecretsManager] }));
export const CreateAwsSecretsManagerSyncSchema = GenericCreateSecretSyncFieldsSchema(
SecretSync.AWSSecretsManager,
AwsSecretsManagerSyncOptionsConfig,
AwsSecretsManagerSyncOptionsSchema
)
.extend({
destinationConfig: AwsSecretsManagerSyncDestinationConfigSchema
})
.superRefine((sync, ctx) => {
if (
sync.destinationConfig.mappingBehavior === AwsSecretsManagerSyncMappingBehavior.ManyToOne &&
sync.syncOptions.syncSecretMetadataAsTags
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Syncing secret metadata is not supported with "Many-to-One" mapping behavior.'
});
}
});
export const UpdateAwsSecretsManagerSyncSchema = GenericUpdateSecretSyncFieldsSchema(
SecretSync.AWSSecretsManager,
AwsSecretsManagerSyncOptionsConfig,
AwsSecretsManagerSyncOptionsSchema
)
.extend({
destinationConfig: AwsSecretsManagerSyncDestinationConfigSchema.optional()
})
.superRefine((sync, ctx) => {
if (
sync.destinationConfig?.mappingBehavior === AwsSecretsManagerSyncMappingBehavior.ManyToOne &&
sync.syncOptions.syncSecretMetadataAsTags
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: 'Syncing secret metadata is not supported with "Many-to-One" mapping behavior.'
});
}
});
export const AwsSecretsManagerSyncListItemSchema = z
.object({
name: z.literal("AWS Secrets Manager"),
connection: z.literal(AppConnection.AWS),
destination: z.literal(SecretSync.AWSSecretsManager),
canImportSecrets: z.literal(true)
})
.describe(JSON.stringify({ title: SECRET_SYNC_NAME_MAP[SecretSync.AWSSecretsManager] }));