From bcb0e8e705a176d2c30d09fa7e66e46b52042cfe Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Fri, 24 Oct 2025 15:53:38 +0400 Subject: [PATCH 01/12] fix: gateway improvements --- backend/src/lib/gateway-v2/gateway-v2.ts | 6 +++++- .../identity-kubernetes-auth-service.ts | 3 ++- .../templates/serviceaccount-token-reviewer.yaml | 14 ++++++++++++++ .../templates/serviceaccount.yaml | 1 + helm-charts/infisical-gateway/values.yaml | 1 + 5 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 helm-charts/infisical-gateway/templates/serviceaccount-token-reviewer.yaml diff --git a/backend/src/lib/gateway-v2/gateway-v2.ts b/backend/src/lib/gateway-v2/gateway-v2.ts index 5ae0e5b1d..46abe4bf1 100644 --- a/backend/src/lib/gateway-v2/gateway-v2.ts +++ b/backend/src/lib/gateway-v2/gateway-v2.ts @@ -7,6 +7,7 @@ import https from "https"; import { verifyHostInputValidity } from "@app/ee/services/dynamic-secret/dynamic-secret-fns"; import { splitPemChain } from "@app/services/certificate/certificate-fns"; +import { getConfig } from "../config/env"; import { BadRequestError } from "../errors"; import { GatewayProxyProtocol } from "../gateway/types"; import { logger } from "../logger"; @@ -80,6 +81,8 @@ const createGatewayConnection = async ( gateway: { clientCertificate: string; clientPrivateKey: string; serverCertificateChain: string }, protocol: GatewayProxyProtocol ): Promise => { + const appCfg = getConfig(); + const protocolToAlpn = { [GatewayProxyProtocol.Http]: "infisical-http-proxy", [GatewayProxyProtocol.Tcp]: "infisical-tcp-proxy", @@ -94,7 +97,8 @@ const createGatewayConnection = async ( minVersion: "TLSv1.2", maxVersion: "TLSv1.3", rejectUnauthorized: true, - ALPNProtocols: [protocolToAlpn[protocol]] + ALPNProtocols: [protocolToAlpn[protocol]], + checkServerIdentity: appCfg.isDevelopmentMode ? () => undefined : tls.checkServerIdentity }; return new Promise((resolve, reject) => { diff --git a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts index 49fb597f5..8a8fd5091 100644 --- a/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts +++ b/backend/src/services/identity-kubernetes-auth/identity-kubernetes-auth-service.ts @@ -719,7 +719,8 @@ export const identityKubernetesAuthServiceFactory = ({ ); } - const shouldUpdateGatewayId = Boolean(gatewayId); + // Strict check to see if gateway ID is undefined. It should update the gateway ID to null if its strictly set to null. + const shouldUpdateGatewayId = Boolean(gatewayId !== undefined); const gatewayIdValue = isGatewayV1 ? gatewayId : null; const gatewayV2IdValue = isGatewayV1 ? null : gatewayId; diff --git a/helm-charts/infisical-gateway/templates/serviceaccount-token-reviewer.yaml b/helm-charts/infisical-gateway/templates/serviceaccount-token-reviewer.yaml new file mode 100644 index 000000000..e92352318 --- /dev/null +++ b/helm-charts/infisical-gateway/templates/serviceaccount-token-reviewer.yaml @@ -0,0 +1,14 @@ +{{- if and .Values.serviceAccount.createAsAuthDelegator .Values.serviceAccount.create -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "infisical-gateway.serviceAccountName" . }}-system-auth-delegator-cluster-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: system:auth-delegator +subjects: + - kind: ServiceAccount + name: {{ include "infisical-gateway.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +{{- end }} \ No newline at end of file diff --git a/helm-charts/infisical-gateway/templates/serviceaccount.yaml b/helm-charts/infisical-gateway/templates/serviceaccount.yaml index c0040963f..1ed3d38d6 100644 --- a/helm-charts/infisical-gateway/templates/serviceaccount.yaml +++ b/helm-charts/infisical-gateway/templates/serviceaccount.yaml @@ -2,6 +2,7 @@ apiVersion: v1 kind: ServiceAccount metadata: + namespace: {{ .Release.Namespace }} name: {{ include "infisical-gateway.serviceAccountName" . }} labels: {{- include "infisical-gateway.labels" . | nindent 4 }} diff --git a/helm-charts/infisical-gateway/values.yaml b/helm-charts/infisical-gateway/values.yaml index c792d67a6..dab76f6a0 100644 --- a/helm-charts/infisical-gateway/values.yaml +++ b/helm-charts/infisical-gateway/values.yaml @@ -21,6 +21,7 @@ fullnameOverride: "" serviceAccount: create: true automount: true + createAsAuthDelegator: true annotations: {} name: "" From d441e4197f2c1cc95bcff4101982a61c522d6e32 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Fri, 24 Oct 2025 16:00:41 +0400 Subject: [PATCH 02/12] fix: lint test --- .github/workflows/release_helm_gateway.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/release_helm_gateway.yaml b/.github/workflows/release_helm_gateway.yaml index 7fd0eb03a..cfd29a56e 100644 --- a/.github/workflows/release_helm_gateway.yaml +++ b/.github/workflows/release_helm_gateway.yaml @@ -24,6 +24,8 @@ jobs: - name: Set up chart-testing uses: helm/chart-testing-action@v2.7.0 + with: + yamale_version: "6.0.0" - name: Run chart-testing (lint) run: ct lint --config ct.yaml --charts helm-charts/infisical-gateway From e9fee3eb4b5fb8f5f108388980585f706a445e2b Mon Sep 17 00:00:00 2001 From: Daniel Hougaard Date: Fri, 24 Oct 2025 21:46:00 +0400 Subject: [PATCH 03/12] Update run-helm-chart-tests-infisical-gateway.yml --- .github/workflows/run-helm-chart-tests-infisical-gateway.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/run-helm-chart-tests-infisical-gateway.yml b/.github/workflows/run-helm-chart-tests-infisical-gateway.yml index eff42506e..b382669e3 100644 --- a/.github/workflows/run-helm-chart-tests-infisical-gateway.yml +++ b/.github/workflows/run-helm-chart-tests-infisical-gateway.yml @@ -27,6 +27,8 @@ jobs: - name: Set up chart-testing uses: helm/chart-testing-action@v2.7.0 + with: + yamale_version: "6.0.0" - name: Run chart-testing (lint) run: ct lint --config ct.yaml --charts helm-charts/infisical-gateway From 1722f85e67586af62ee57968d218ae71b45cff6a Mon Sep 17 00:00:00 2001 From: Carlos Monastyrski Date: Fri, 24 Oct 2025 20:12:35 -0300 Subject: [PATCH 04/12] Add org option to block duplicate destinations on secret syncs --- ...ock-duplicate-sync-destinations-setting.ts | 27 ++++ backend/src/db/schemas/organizations.ts | 3 +- backend/src/server/routes/index.ts | 2 + .../server/routes/v1/organization-router.ts | 4 + backend/src/services/org/org-schema.ts | 3 +- backend/src/services/org/org-service.ts | 6 +- backend/src/services/org/org-types.ts | 1 + .../secret-sync/secret-sync-service.ts | 140 +++++++++++------- .../forms/CreateSecretSyncForm.tsx | 21 ++- .../SecretSyncReviewFields.tsx | 49 +++++- .../src/hooks/api/organization/queries.tsx | 6 +- frontend/src/hooks/api/organization/types.ts | 2 + ...DuplicateSecretSyncDestinationsSection.tsx | 64 ++++++++ .../index.ts | 1 + .../OrgProductSettingsTab.tsx | 72 +++++++++ .../OrgProductSettingsTab/index.tsx | 1 + .../components/OrgTabGroup/OrgTabGroup.tsx | 8 +- .../SettingsPage/components/index.tsx | 2 + 18 files changed, 339 insertions(+), 73 deletions(-) create mode 100644 backend/src/db/migrations/20251023123213_block-duplicate-sync-destinations-setting.ts create mode 100644 frontend/src/pages/organization/SettingsPage/components/BlockDuplicateSecretSyncDestinationsSection/BlockDuplicateSecretSyncDestinationsSection.tsx create mode 100644 frontend/src/pages/organization/SettingsPage/components/BlockDuplicateSecretSyncDestinationsSection/index.ts create mode 100644 frontend/src/pages/organization/SettingsPage/components/OrgProductSettingsTab/OrgProductSettingsTab.tsx create mode 100644 frontend/src/pages/organization/SettingsPage/components/OrgProductSettingsTab/index.tsx diff --git a/backend/src/db/migrations/20251023123213_block-duplicate-sync-destinations-setting.ts b/backend/src/db/migrations/20251023123213_block-duplicate-sync-destinations-setting.ts new file mode 100644 index 000000000..7675eb3e1 --- /dev/null +++ b/backend/src/db/migrations/20251023123213_block-duplicate-sync-destinations-setting.ts @@ -0,0 +1,27 @@ +import { Knex } from "knex"; + +import { TableName } from "../schemas"; + +export async function up(knex: Knex): Promise { + const hasOrgBlockDuplicateColumn = await knex.schema.hasColumn( + TableName.Organization, + "blockDuplicateSecretSyncDestinations" + ); + if (!hasOrgBlockDuplicateColumn) { + await knex.schema.table(TableName.Organization, (table) => { + table.boolean("blockDuplicateSecretSyncDestinations").notNullable().defaultTo(false); + }); + } +} + +export async function down(knex: Knex): Promise { + const hasOrgBlockDuplicateColumn = await knex.schema.hasColumn( + TableName.Organization, + "blockDuplicateSecretSyncDestinations" + ); + if (hasOrgBlockDuplicateColumn) { + await knex.schema.table(TableName.Organization, (table) => { + table.dropColumn("blockDuplicateSecretSyncDestinations"); + }); + } +} diff --git a/backend/src/db/schemas/organizations.ts b/backend/src/db/schemas/organizations.ts index a1c01151f..3cc7fe858 100644 --- a/backend/src/db/schemas/organizations.ts +++ b/backend/src/db/schemas/organizations.ts @@ -40,7 +40,8 @@ export const OrganizationsSchema = z.object({ googleSsoAuthEnforced: z.boolean().default(false), googleSsoAuthLastUsed: z.date().nullable().optional(), parentOrgId: z.string().uuid().nullable().optional(), - rootOrgId: z.string().uuid().nullable().optional() + rootOrgId: z.string().uuid().nullable().optional(), + blockDuplicateSecretSyncDestinations: z.boolean().default(false) }); export type TOrganizations = z.infer; diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index 53cf1f961..44b9a1601 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -1960,6 +1960,8 @@ export const registerRoutes = async ( secretImportDAL, permissionService, appConnectionService, + projectDAL, + orgDAL, folderDAL, secretSyncQueue, projectBotService, diff --git a/backend/src/server/routes/v1/organization-router.ts b/backend/src/server/routes/v1/organization-router.ts index 76b3eae51..d4b0058f9 100644 --- a/backend/src/server/routes/v1/organization-router.ts +++ b/backend/src/server/routes/v1/organization-router.ts @@ -323,7 +323,11 @@ export const registerOrgRouter = async (server: FastifyZodProvider) => { .min(1, "Max Shared Secret view count cannot be lower than 1") .max(1000, "Max Shared Secret view count cannot exceed 1000") .nullable() + .optional(), + blockDuplicateSecretSyncDestinations: z + .boolean() .optional() + .describe("Block duplicate secret sync destinations across the organization") }), response: { 200: z.object({ diff --git a/backend/src/services/org/org-schema.ts b/backend/src/services/org/org-schema.ts index 4a3bdb06e..be5c300b5 100644 --- a/backend/src/services/org/org-schema.ts +++ b/backend/src/services/org/org-schema.ts @@ -27,5 +27,6 @@ export const sanitizedOrganizationSchema = OrganizationsSchema.pick({ scannerProductEnabled: true, shareSecretsProductEnabled: true, maxSharedSecretLifetime: true, - maxSharedSecretViewLimit: true + maxSharedSecretViewLimit: true, + blockDuplicateSecretSyncDestinations: true }); diff --git a/backend/src/services/org/org-service.ts b/backend/src/services/org/org-service.ts index 20ed37a06..f0eff547a 100644 --- a/backend/src/services/org/org-service.ts +++ b/backend/src/services/org/org-service.ts @@ -408,7 +408,8 @@ export const orgServiceFactory = ({ scannerProductEnabled, shareSecretsProductEnabled, maxSharedSecretLifetime, - maxSharedSecretViewLimit + maxSharedSecretViewLimit, + blockDuplicateSecretSyncDestinations } }: TUpdateOrgDTO) => { const appCfg = getConfig(); @@ -592,7 +593,8 @@ export const orgServiceFactory = ({ scannerProductEnabled, shareSecretsProductEnabled, maxSharedSecretLifetime, - maxSharedSecretViewLimit + maxSharedSecretViewLimit, + blockDuplicateSecretSyncDestinations }); if (!org) throw new NotFoundError({ message: `Organization with ID '${orgId}' not found` }); return org; diff --git a/backend/src/services/org/org-types.ts b/backend/src/services/org/org-types.ts index 48680456c..2587045bb 100644 --- a/backend/src/services/org/org-types.ts +++ b/backend/src/services/org/org-types.ts @@ -90,6 +90,7 @@ export type TUpdateOrgDTO = { shareSecretsProductEnabled: boolean; maxSharedSecretLifetime: number; maxSharedSecretViewLimit: number | null; + blockDuplicateSecretSyncDestinations: boolean; }>; } & TOrgPermission; diff --git a/backend/src/services/secret-sync/secret-sync-service.ts b/backend/src/services/secret-sync/secret-sync-service.ts index 6a2f49386..b3eb05369 100644 --- a/backend/src/services/secret-sync/secret-sync-service.ts +++ b/backend/src/services/secret-sync/secret-sync-service.ts @@ -15,6 +15,8 @@ import { BadRequestError, DatabaseError, NotFoundError } from "@app/lib/errors"; import { deepEqualSkipFields } from "@app/lib/fn/object"; import { OrgServiceActor } from "@app/lib/types"; import { TAppConnectionServiceFactory } from "@app/services/app-connection/app-connection-service"; +import { TOrgDALFactory } from "@app/services/org/org-dal"; +import { TProjectDALFactory } from "@app/services/project/project-dal"; import { TProjectBotServiceFactory } from "@app/services/project-bot/project-bot-service"; import { TSecretFolderDALFactory } from "@app/services/secret-folder/secret-folder-dal"; import { SecretSync } from "@app/services/secret-sync/secret-sync-enums"; @@ -50,6 +52,8 @@ type TSecretSyncServiceFactoryDep = { secretImportDAL: TSecretImportDALFactory; appConnectionService: Pick; permissionService: Pick; + projectDAL: Pick; + orgDAL: Pick; projectBotService: Pick; folderDAL: Pick; keyStore: Pick; @@ -68,6 +72,8 @@ export const secretSyncServiceFactory = ({ secretImportDAL, permissionService, appConnectionService, + projectDAL, + orgDAL, projectBotService, secretSyncQueue, keyStore, @@ -225,6 +231,61 @@ export const secretSyncServiceFactory = ({ return secretSync as TSecretSync; }; + const checkDuplicateDestination = async ( + { destination, destinationConfig, excludeSyncId, projectId }: TCheckDuplicateDestinationDTO, + actor: OrgServiceActor + ) => { + const skipFields = SECRET_SYNC_SKIP_FIELDS_MAP[destination]; + const { permission } = await permissionService.getProjectPermission({ + actor: actor.type, + actorId: actor.id, + actorAuthMethod: actor.authMethod, + actorOrgId: actor.orgId, + actionProjectType: ActionProjectType.SecretManager, + projectId + }); + + ForbiddenError.from(permission).throwUnlessCan( + ProjectPermissionSecretSyncActions.Read, + ProjectPermissionSub.SecretSyncs + ); + + if (!destinationConfig || Object.keys(destinationConfig).length === 0) { + return { hasDuplicate: false, duplicateProjectId: undefined }; + } + + try { + const existingSyncs = await secretSyncDAL.findByDestinationAndOrgId(destination, actor.orgId); + + const duplicates = existingSyncs.filter((sync) => { + if (sync.id === excludeSyncId) { + return false; + } + + try { + const baseFieldsMatch = deepEqualSkipFields(sync.destinationConfig, destinationConfig, skipFields); + if (baseFieldsMatch) { + return DESTINATION_DUPLICATE_CHECK_MAP[destination]( + sync.destinationConfig as Record, + destinationConfig + ); + } + return false; + } catch { + return false; + } + }); + + const hasDuplicate = duplicates.length > 0; + return { + hasDuplicate, + duplicateProjectId: hasDuplicate ? duplicates[0].projectId : undefined + }; + } catch (error) { + return { hasDuplicate: false, duplicateProjectId: undefined }; + } + }; + const createSecretSync = async ( { projectId, secretPath, environment, ...params }: TCreateSecretSyncDTO, actor: OrgServiceActor @@ -271,6 +332,30 @@ export const secretSyncServiceFactory = ({ message: `Could not find folder with path "${secretPath}" in environment "${environment}" for project with ID "${projectId}"` }); + const project = await projectDAL.findById(projectId); + if (!project) { + throw new NotFoundError({ message: "Project not found" }); + } + + const organization = await orgDAL.findById(project.orgId); + if (organization?.blockDuplicateSecretSyncDestinations) { + const duplicateCheck = await checkDuplicateDestination( + { + destination: params.destination, + destinationConfig: params.destinationConfig, + projectId + }, + actor + ); + if (duplicateCheck.hasDuplicate) { + throw new BadRequestError({ + message: `A secret sync with this destination already exists${ + duplicateCheck.duplicateProjectId ? ` in project ${duplicateCheck.duplicateProjectId}` : "" + }.` + }); + } + } + const destinationApp = SECRET_SYNC_CONNECTION_MAP[params.destination]; // validates permission to connect and app is valid for sync destination @@ -703,61 +788,6 @@ export const secretSyncServiceFactory = ({ return updatedSecretSync as TSecretSync; }; - const checkDuplicateDestination = async ( - { destination, destinationConfig, excludeSyncId, projectId }: TCheckDuplicateDestinationDTO, - actor: OrgServiceActor - ) => { - const skipFields = SECRET_SYNC_SKIP_FIELDS_MAP[destination]; - const { permission } = await permissionService.getProjectPermission({ - actor: actor.type, - actorId: actor.id, - actorAuthMethod: actor.authMethod, - actorOrgId: actor.orgId, - actionProjectType: ActionProjectType.SecretManager, - projectId - }); - - ForbiddenError.from(permission).throwUnlessCan( - ProjectPermissionSecretSyncActions.Read, - ProjectPermissionSub.SecretSyncs - ); - - if (!destinationConfig || Object.keys(destinationConfig).length === 0) { - return { hasDuplicate: false, duplicateProjectId: undefined }; - } - - try { - const existingSyncs = await secretSyncDAL.findByDestinationAndOrgId(destination, actor.orgId); - - const duplicates = existingSyncs.filter((sync) => { - if (sync.id === excludeSyncId) { - return false; - } - - try { - const baseFieldsMatch = deepEqualSkipFields(sync.destinationConfig, destinationConfig, skipFields); - if (baseFieldsMatch) { - return DESTINATION_DUPLICATE_CHECK_MAP[destination]( - sync.destinationConfig as Record, - destinationConfig - ); - } - return false; - } catch { - return false; - } - }); - - const hasDuplicate = duplicates.length > 0; - return { - hasDuplicate, - duplicateProjectId: hasDuplicate ? duplicates[0].projectId : undefined - }; - } catch (error) { - return { hasDuplicate: false, duplicateProjectId: undefined }; - } - }; - return { listSecretSyncOptions, listSecretSyncsByProjectId, diff --git a/frontend/src/components/secret-syncs/forms/CreateSecretSyncForm.tsx b/frontend/src/components/secret-syncs/forms/CreateSecretSyncForm.tsx index 45e0297bd..d10d27803 100644 --- a/frontend/src/components/secret-syncs/forms/CreateSecretSyncForm.tsx +++ b/frontend/src/components/secret-syncs/forms/CreateSecretSyncForm.tsx @@ -8,13 +8,14 @@ import { twMerge } from "tailwind-merge"; import { createNotification } from "@app/components/notifications"; import { Button, FormControl, Switch } from "@app/components/v2"; -import { useProject } from "@app/context"; +import { useOrganization, useProject } from "@app/context"; import { SECRET_SYNC_MAP } from "@app/helpers/secretSyncs"; import { SecretSync, SecretSyncInitialSyncBehavior, TSecretSync, useCreateSecretSync, + useDuplicateDestinationCheck, useSecretSyncOption } from "@app/hooks/api/secretSyncs"; @@ -48,6 +49,7 @@ export const CreateSecretSyncForm = ({ }: Props) => { const createSecretSync = useCreateSecretSync(); const { currentProject } = useProject(); + const { currentOrg } = useOrganization(); const { name: destinationName } = SECRET_SYNC_MAP[destination]; const [showConfirmation, setShowConfirmation] = useState(false); @@ -106,11 +108,20 @@ export const CreateSecretSyncForm = ({ setSelectedTabIndex((prev) => prev - 1); }; - const { handleSubmit, trigger, control } = formMethods; + const { handleSubmit, trigger, control, watch } = formMethods; + + const { hasDuplicate } = useDuplicateDestinationCheck({ + destination, + projectId: currentProject?.id || "", + enabled: true, + destinationConfig: watch("destinationConfig") + }); const isStepValid = async (index: number) => trigger(FORM_TABS[index].fields); const isFinalStep = selectedTabIndex === FORM_TABS.length - 1; + const isCreateButtonDisabled = + isFinalStep && hasDuplicate && currentOrg?.blockDuplicateSecretSyncDestinations; const handleNext = async () => { if (isFinalStep) { @@ -245,7 +256,11 @@ export const CreateSecretSyncForm = ({
- {selectedTabIndex > 0 && ( diff --git a/frontend/src/components/secret-syncs/forms/SecretSyncReviewFields/SecretSyncReviewFields.tsx b/frontend/src/components/secret-syncs/forms/SecretSyncReviewFields/SecretSyncReviewFields.tsx index 44d35cd2c..4a796933d 100644 --- a/frontend/src/components/secret-syncs/forms/SecretSyncReviewFields/SecretSyncReviewFields.tsx +++ b/frontend/src/components/secret-syncs/forms/SecretSyncReviewFields/SecretSyncReviewFields.tsx @@ -6,7 +6,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { GenericFieldLabel } from "@app/components/secret-syncs"; import { TSecretSyncForm } from "@app/components/secret-syncs/forms/schemas"; import { Badge } from "@app/components/v2"; -import { useProject } from "@app/context"; +import { useOrganization, useProject } from "@app/context"; import { SECRET_SYNC_INITIAL_SYNC_BEHAVIOR_MAP, SECRET_SYNC_MAP } from "@app/helpers/secretSyncs"; import { SecretSync, useDuplicateDestinationCheck } from "@app/hooks/api/secretSyncs"; @@ -51,6 +51,7 @@ import { ZabbixSyncReviewFields } from "./ZabbixSyncReviewFields"; export const SecretSyncReviewFields = () => { const { watch } = useFormContext(); const { currentProject } = useProject(); + const { currentOrg } = useOrganization(); let DestinationFieldsComponent: ReactNode; let AdditionalSyncOptionsFieldsComponent: ReactNode; @@ -193,18 +194,50 @@ export const SecretSyncReviewFields = () => { {isChecking && Checking...}
{hasDuplicate && ( -
-
- +
+
+

- Another secret sync in your organization is already configured with the same - destination. This may lead to conflicts or unexpected behavior. + {currentOrg?.blockDuplicateSecretSyncDestinations + ? "Another secret sync in your organization is already configured with the same destination. This organization has blocking duplicate destinations enabled." + : "Another secret sync in your organization is already configured with the same destination. This may lead to conflicts or unexpected behavior."}

{duplicateProjectId && ( -

+

Duplicate found in project ID:{" "} - + {duplicateProjectId}

diff --git a/frontend/src/hooks/api/organization/queries.tsx b/frontend/src/hooks/api/organization/queries.tsx index bbf73dd25..4340f9718 100644 --- a/frontend/src/hooks/api/organization/queries.tsx +++ b/frontend/src/hooks/api/organization/queries.tsx @@ -125,7 +125,8 @@ export const useUpdateOrg = () => { scannerProductEnabled, shareSecretsProductEnabled, maxSharedSecretLifetime, - maxSharedSecretViewLimit + maxSharedSecretViewLimit, + blockDuplicateSecretSyncDestinations }) => { return apiRequest.patch(`/api/v1/organization/${orgId}`, { name, @@ -146,7 +147,8 @@ export const useUpdateOrg = () => { scannerProductEnabled, shareSecretsProductEnabled, maxSharedSecretLifetime, - maxSharedSecretViewLimit + maxSharedSecretViewLimit, + blockDuplicateSecretSyncDestinations }); }, onSuccess: () => { diff --git a/frontend/src/hooks/api/organization/types.ts b/frontend/src/hooks/api/organization/types.ts index e9c36fada..78daa07b5 100644 --- a/frontend/src/hooks/api/organization/types.ts +++ b/frontend/src/hooks/api/organization/types.ts @@ -29,6 +29,7 @@ export type Organization = { shareSecretsProductEnabled: boolean; maxSharedSecretLifetime: number; maxSharedSecretViewLimit: number | null; + blockDuplicateSecretSyncDestinations: boolean; }; export type UpdateOrgDTO = { @@ -52,6 +53,7 @@ export type UpdateOrgDTO = { shareSecretsProductEnabled?: boolean; maxSharedSecretViewLimit?: number | null; maxSharedSecretLifetime?: number; + blockDuplicateSecretSyncDestinations?: boolean; }; export type BillingDetails = { diff --git a/frontend/src/pages/organization/SettingsPage/components/BlockDuplicateSecretSyncDestinationsSection/BlockDuplicateSecretSyncDestinationsSection.tsx b/frontend/src/pages/organization/SettingsPage/components/BlockDuplicateSecretSyncDestinationsSection/BlockDuplicateSecretSyncDestinationsSection.tsx new file mode 100644 index 000000000..a2346bd91 --- /dev/null +++ b/frontend/src/pages/organization/SettingsPage/components/BlockDuplicateSecretSyncDestinationsSection/BlockDuplicateSecretSyncDestinationsSection.tsx @@ -0,0 +1,64 @@ +import { useState } from "react"; + +import { createNotification } from "@app/components/notifications"; +import { OrgPermissionCan } from "@app/components/permissions"; +import { Checkbox } from "@app/components/v2"; +import { OrgPermissionActions, OrgPermissionSubjects, useOrganization } from "@app/context"; +import { useUpdateOrg } from "@app/hooks/api/organization/queries"; + +export const BlockDuplicateSecretSyncDestinationsSection = () => { + const { currentOrg } = useOrganization(); + const { mutateAsync: updateOrg } = useUpdateOrg(); + + const [isLoading, setIsLoading] = useState(false); + + const handleToggle = async (state: boolean) => { + setIsLoading(true); + + try { + if (!currentOrg?.id) { + setIsLoading(false); + return; + } + + await updateOrg({ + orgId: currentOrg.id, + blockDuplicateSecretSyncDestinations: state + }); + + createNotification({ + text: `Successfully ${state ? "enabled" : "disabled"} blocking duplicate secret sync destinations for this organization`, + type: "success" + }); + } catch (err) { + console.error(err); + createNotification({ + text: "Failed to update blocking duplicate secret sync destinations setting for this organization", + type: "error" + }); + } finally { + setIsLoading(false); + } + }; + + return ( +
+

Block Duplicate Secret Sync Destinations

+ + {(isAllowed) => ( +
+ handleToggle(state as boolean)} + > + This feature prevents creating secret syncs with destinations that are already in use + by other syncs in your organization. + +
+ )} +
+
+ ); +}; diff --git a/frontend/src/pages/organization/SettingsPage/components/BlockDuplicateSecretSyncDestinationsSection/index.ts b/frontend/src/pages/organization/SettingsPage/components/BlockDuplicateSecretSyncDestinationsSection/index.ts new file mode 100644 index 000000000..0426a6178 --- /dev/null +++ b/frontend/src/pages/organization/SettingsPage/components/BlockDuplicateSecretSyncDestinationsSection/index.ts @@ -0,0 +1 @@ +export { BlockDuplicateSecretSyncDestinationsSection } from "./BlockDuplicateSecretSyncDestinationsSection"; diff --git a/frontend/src/pages/organization/SettingsPage/components/OrgProductSettingsTab/OrgProductSettingsTab.tsx b/frontend/src/pages/organization/SettingsPage/components/OrgProductSettingsTab/OrgProductSettingsTab.tsx new file mode 100644 index 000000000..5e23a4f97 --- /dev/null +++ b/frontend/src/pages/organization/SettingsPage/components/OrgProductSettingsTab/OrgProductSettingsTab.tsx @@ -0,0 +1,72 @@ +import { useState } from "react"; + +import { createNotification } from "@app/components/notifications"; +import { OrgPermissionCan } from "@app/components/permissions"; +import { Switch } from "@app/components/v2"; +import { OrgPermissionActions, OrgPermissionSubjects, useOrganization } from "@app/context"; +import { useUpdateOrg } from "@app/hooks/api/organization/queries"; + +export const OrgProductSettingsTab = () => { + const { currentOrg } = useOrganization(); + const { mutateAsync: updateOrg } = useUpdateOrg(); + + const [isLoading, setIsLoading] = useState(false); + + const handleToggle = async (state: boolean) => { + setIsLoading(true); + + try { + if (!currentOrg?.id) { + setIsLoading(false); + return; + } + + await updateOrg({ + orgId: currentOrg.id, + blockDuplicateSecretSyncDestinations: state + }); + + createNotification({ + text: `Successfully ${state ? "enabled" : "disabled"} blocking duplicate secret sync destinations for this organization`, + type: "success" + }); + } catch (err) { + console.error(err); + createNotification({ + text: "Failed to update blocking duplicate secret sync destinations setting for this organization", + type: "error" + }); + } finally { + setIsLoading(false); + } + }; + + return ( +
+
+

Secrets Management

+
+
+
+

+ Block Duplicate Secret Sync Destinations +

+

+ When enabled, this setting prevents the creation of multiple sync configurations + pointing to the same destination. +

+
+ + {(isAllowed) => ( + handleToggle(state as boolean)} + /> + )} + +
+
+ ); +}; diff --git a/frontend/src/pages/organization/SettingsPage/components/OrgProductSettingsTab/index.tsx b/frontend/src/pages/organization/SettingsPage/components/OrgProductSettingsTab/index.tsx new file mode 100644 index 000000000..c2b12e31f --- /dev/null +++ b/frontend/src/pages/organization/SettingsPage/components/OrgProductSettingsTab/index.tsx @@ -0,0 +1 @@ +export { OrgProductSettingsTab } from "./OrgProductSettingsTab"; diff --git a/frontend/src/pages/organization/SettingsPage/components/OrgTabGroup/OrgTabGroup.tsx b/frontend/src/pages/organization/SettingsPage/components/OrgTabGroup/OrgTabGroup.tsx index 10eb0f6c0..85d4b259c 100644 --- a/frontend/src/pages/organization/SettingsPage/components/OrgTabGroup/OrgTabGroup.tsx +++ b/frontend/src/pages/organization/SettingsPage/components/OrgTabGroup/OrgTabGroup.tsx @@ -10,6 +10,7 @@ import { ExternalMigrationsTab } from "../ExternalMigrationsTab"; import { KmipTab } from "../KmipTab/OrgKmipTab"; import { OrgEncryptionTab } from "../OrgEncryptionTab"; import { OrgGeneralTab } from "../OrgGeneralTab"; +import { OrgProductSettingsTab } from "../OrgProductSettingsTab"; import { OrgProvisioningTab } from "../OrgProvisioningTab"; import { OrgSecurityTab } from "../OrgSecurityTab"; import { OrgSsoTab } from "../OrgSsoTab"; @@ -63,7 +64,12 @@ export const OrgTabGroup = () => { key: "project-templates", component: ProjectTemplatesTab }, - { name: "KMIP", key: "kmip", component: KmipTab } + { name: "KMIP", key: "kmip", component: KmipTab }, + { + name: "Product Enforcements", + key: "product-enforcements", + component: OrgProductSettingsTab + } ]; const [selectedTab, setSelectedTab] = useState(search.selectedTab || tabs[0].key); diff --git a/frontend/src/pages/organization/SettingsPage/components/index.tsx b/frontend/src/pages/organization/SettingsPage/components/index.tsx index 648613642..3387ed32b 100644 --- a/frontend/src/pages/organization/SettingsPage/components/index.tsx +++ b/frontend/src/pages/organization/SettingsPage/components/index.tsx @@ -1 +1,3 @@ +export { BlockDuplicateSecretSyncDestinationsSection } from "./BlockDuplicateSecretSyncDestinationsSection"; +export { OrgProductSettingsTab } from "./OrgProductSettingsTab"; export { OrgTabGroup } from "./OrgTabGroup"; From 15a57e29ef1e605dfde8bfa0ae4a7975938c111c Mon Sep 17 00:00:00 2001 From: x032205 Date: Sat, 25 Oct 2025 05:24:28 -0400 Subject: [PATCH 05/12] docs: API versioning info --- docs/api-reference/overview/introduction.mdx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/api-reference/overview/introduction.mdx b/docs/api-reference/overview/introduction.mdx index 6d577e15b..2f75bf0f5 100644 --- a/docs/api-reference/overview/introduction.mdx +++ b/docs/api-reference/overview/introduction.mdx @@ -7,4 +7,10 @@ Infisical's Public (REST) API provides users an alternative way to programmatica secrets via HTTPS requests. This can be useful for automating tasks, such as rotating credentials, or for integrating secret management into a larger system. -With the Public API, you can create, read, update, and delete secrets, as well as manage access control, query audit logs, and more. \ No newline at end of file +With the Public API, you can create, read, update, and delete secrets, as well as manage access control, query audit logs, and more. + +## API Versioning + +The API is versioned on a per-resource basis. A resource's version is only incremented for breaking changes, so different endpoints may have different version numbers (e.g., `/api/v4/secrets` vs. `/api/v1/secret-syncs`). + +As a best practice, always use the latest available version for each endpoint to ensure access to the most recent features and improvements. From 5e9ff006309219138fac793629508b9347eba4f1 Mon Sep 17 00:00:00 2001 From: Victor Santos Date: Mon, 27 Oct 2025 14:51:16 -0300 Subject: [PATCH 06/12] refactor: update TTL validation to allow a maximum of 10 years and adjust environment variable defaults for AWS credentials --- backend/src/ee/routes/v1/dynamic-secret-router.ts | 4 ++-- backend/src/lib/config/env.ts | 14 +++++++------- .../CreateDynamicSecretForm/AwsIamInputForm.tsx | 5 ++--- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/backend/src/ee/routes/v1/dynamic-secret-router.ts b/backend/src/ee/routes/v1/dynamic-secret-router.ts index b1b3cea8e..7fb3e8374 100644 --- a/backend/src/ee/routes/v1/dynamic-secret-router.ts +++ b/backend/src/ee/routes/v1/dynamic-secret-router.ts @@ -72,8 +72,8 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) => const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > daysToMillisecond(1)) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }) .nullable(), path: z.string().describe(DYNAMIC_SECRETS.CREATE.path).trim().default("/").transform(removeTrailingSlash), diff --git a/backend/src/lib/config/env.ts b/backend/src/lib/config/env.ts index 9fc4cff92..81d28167e 100644 --- a/backend/src/lib/config/env.ts +++ b/backend/src/lib/config/env.ts @@ -266,12 +266,8 @@ const envSchema = z RELAY_AUTH_SECRET: zpStr(z.string().optional()), DYNAMIC_SECRET_ALLOW_INTERNAL_IP: zodStrBool.default("false"), - DYNAMIC_SECRET_AWS_ACCESS_KEY_ID: zpStr(z.string().optional()).default( - process.env.INF_APP_CONNECTION_AWS_ACCESS_KEY_ID - ), - DYNAMIC_SECRET_AWS_SECRET_ACCESS_KEY: zpStr(z.string().optional()).default( - process.env.INF_APP_CONNECTION_AWS_SECRET_ACCESS_KEY - ), + DYNAMIC_SECRET_AWS_ACCESS_KEY_ID: zpStr(z.string().optional()), + DYNAMIC_SECRET_AWS_SECRET_ACCESS_KEY: zpStr(z.string().optional()), /* ----------------------------------------------------------------------------- */ /* App Connections ----------------------------------------------------------------------------- */ @@ -439,7 +435,11 @@ const envSchema = z data.INF_APP_CONNECTION_AZURE_APP_CONFIGURATION_CLIENT_SECRET || data.INF_APP_CONNECTION_AZURE_CLIENT_SECRET, INF_APP_CONNECTION_HEROKU_OAUTH_CLIENT_ID: data.INF_APP_CONNECTION_HEROKU_OAUTH_CLIENT_ID || data.CLIENT_ID_HEROKU, INF_APP_CONNECTION_HEROKU_OAUTH_CLIENT_SECRET: - data.INF_APP_CONNECTION_HEROKU_OAUTH_CLIENT_SECRET || data.CLIENT_SECRET_HEROKU + data.INF_APP_CONNECTION_HEROKU_OAUTH_CLIENT_SECRET || data.CLIENT_SECRET_HEROKU, + DYNAMIC_SECRET_AWS_ACCESS_KEY_ID: + data.DYNAMIC_SECRET_AWS_ACCESS_KEY_ID || data.INF_APP_CONNECTION_AWS_ACCESS_KEY_ID, + DYNAMIC_SECRET_AWS_SECRET_ACCESS_KEY: + data.DYNAMIC_SECRET_AWS_SECRET_ACCESS_KEY || data.INF_APP_CONNECTION_AWS_SECRET_ACCESS_KEY })); export type TEnvConfig = Readonly>; diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx index 9f9cc01aa..042eb56e9 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx @@ -107,9 +107,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"), environment: z.object({ name: z.string(), slug: z.string() }), From 0bf26d4fa21da41ecce98d9296db4910b025623b Mon Sep 17 00:00:00 2001 From: Sheen Capadngan Date: Tue, 28 Oct 2025 02:17:51 +0800 Subject: [PATCH 07/12] fix: add bypass for instance relay heartbeat --- backend/src/server/plugins/auth/inject-identity.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/backend/src/server/plugins/auth/inject-identity.ts b/backend/src/server/plugins/auth/inject-identity.ts index b33f2fbe6..9de15cd34 100644 --- a/backend/src/server/plugins/auth/inject-identity.ts +++ b/backend/src/server/plugins/auth/inject-identity.ts @@ -138,6 +138,11 @@ export const injectIdentity = fp( return; } + // Authentication is handled on a route-level + if (req.url === "/api/v1/relays/heartbeat-instance-relay") { + return; + } + // Authentication is handled on a route-level here. if (req.url.includes("/api/v1/workflow-integrations/microsoft-teams/message-endpoint")) { return; From c0618cf1d6e4e84c154ea9b0794e70dbb42daeb3 Mon Sep 17 00:00:00 2001 From: Victor Santos Date: Mon, 27 Oct 2025 15:20:16 -0300 Subject: [PATCH 08/12] refactor: update TTL validation across dynamic secret forms to allow a maximum of 10 years --- .../src/ee/routes/v1/dynamic-secret-lease-router.ts | 9 ++++----- .../kubernetes-lease-router.ts | 5 ++--- backend/src/ee/routes/v1/dynamic-secret-router.ts | 13 ++++++------- .../AwsElastiCacheInputForm.tsx | 10 ++++------ .../CreateDynamicSecretForm/AwsIamInputForm.tsx | 5 ++--- .../AzureEntraIdInputForm.tsx | 10 ++++------ .../AzureSqlDatabaseInputForm.tsx | 8 ++++---- .../CreateDynamicSecretForm/CassandraInputForm.tsx | 10 ++++------ .../CreateDynamicSecretForm/CouchbaseInputForm.tsx | 8 ++++---- .../ElasticSearchInputForm.tsx | 10 ++++------ .../CreateDynamicSecretForm/KubernetesInputForm.tsx | 8 ++++---- .../CreateDynamicSecretForm/LdapInputForm.tsx | 10 ++++------ .../CreateDynamicSecretForm/MongoAtlasInputForm.tsx | 10 ++++------ .../CreateDynamicSecretForm/MongoDBInputForm.tsx | 10 ++++------ .../CreateDynamicSecretForm/RabbitMqInputForm.tsx | 10 ++++------ .../CreateDynamicSecretForm/RedisInputForm.tsx | 10 ++++------ .../CreateDynamicSecretForm/SapAseInputForm.tsx | 10 ++++------ .../CreateDynamicSecretForm/SapHanaInputForm.tsx | 10 ++++------ .../CreateDynamicSecretForm/SnowflakeInputForm.tsx | 10 ++++------ .../SqlDatabaseInputForm.tsx | 10 ++++------ .../CreateDynamicSecretForm/VerticaInputForm.tsx | 8 ++++---- .../EditDynamicSecretAwsElastiCacheProviderForm.tsx | 10 ++++------ .../EditDynamicSecretAwsIamForm.tsx | 10 ++++------ .../EditDynamicSecretAzureEntraIdForm.tsx | 10 ++++------ .../EditDynamicSecretAzureSqlDatabaseForm.tsx | 8 ++++---- .../EditDynamicSecretCassandraForm.tsx | 10 ++++------ .../EditDynamicSecretCouchbaseForm.tsx | 8 ++++---- .../EditDynamicSecretElasticSearchForm.tsx | 10 ++++------ .../EditDynamicSecretKubernetesForm.tsx | 8 ++++---- .../EditDynamicSecretLdapForm.tsx | 10 ++++------ .../EditDynamicSecretMongoAtlasForm.tsx | 10 ++++------ .../EditDynamicSecretMongoDBForm.tsx | 10 ++++------ .../EditDynamicSecretRabbitMqForm.tsx | 10 ++++------ .../EditDynamicSecretRedisProviderForm.tsx | 10 ++++------ .../EditDynamicSecretSapAseForm.tsx | 10 ++++------ .../EditDynamicSecretSapHanaForm.tsx | 10 ++++------ .../EditDynamicSecretSnowflakeForm.tsx | 10 ++++------ .../EditDynamicSecretSqlProviderForm.tsx | 10 ++++------ .../EditDynamicSecretVertica.tsx | 8 ++++---- 39 files changed, 154 insertions(+), 212 deletions(-) diff --git a/backend/src/ee/routes/v1/dynamic-secret-lease-router.ts b/backend/src/ee/routes/v1/dynamic-secret-lease-router.ts index 26c27d0d3..62911d523 100644 --- a/backend/src/ee/routes/v1/dynamic-secret-lease-router.ts +++ b/backend/src/ee/routes/v1/dynamic-secret-lease-router.ts @@ -2,7 +2,6 @@ import { z } from "zod"; import { DynamicSecretLeasesSchema } from "@app/db/schemas"; import { ApiDocsTags, DYNAMIC_SECRET_LEASES } from "@app/lib/api-docs"; -import { daysToMillisecond } from "@app/lib/dates"; import { removeTrailingSlash } from "@app/lib/fn"; import { ms } from "@app/lib/ms"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; @@ -32,8 +31,8 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > daysToMillisecond(1)) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), path: z.string().trim().default("/").transform(removeTrailingSlash).describe(DYNAMIC_SECRET_LEASES.CREATE.path), environmentSlug: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.CREATE.environmentSlug), @@ -127,8 +126,8 @@ export const registerDynamicSecretLeaseRouter = async (server: FastifyZodProvide const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > daysToMillisecond(1)) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), projectSlug: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.RENEW.projectSlug), path: z diff --git a/backend/src/ee/routes/v1/dynamic-secret-lease-routers/kubernetes-lease-router.ts b/backend/src/ee/routes/v1/dynamic-secret-lease-routers/kubernetes-lease-router.ts index f2751c635..30de7f08a 100644 --- a/backend/src/ee/routes/v1/dynamic-secret-lease-routers/kubernetes-lease-router.ts +++ b/backend/src/ee/routes/v1/dynamic-secret-lease-routers/kubernetes-lease-router.ts @@ -2,7 +2,6 @@ import { z } from "zod"; import { DynamicSecretLeasesSchema } from "@app/db/schemas"; import { ApiDocsTags, DYNAMIC_SECRET_LEASES } from "@app/lib/api-docs"; -import { daysToMillisecond } from "@app/lib/dates"; import { removeTrailingSlash } from "@app/lib/fn"; import { ms } from "@app/lib/ms"; import { writeLimit } from "@app/server/config/rateLimiter"; @@ -32,8 +31,8 @@ export const registerKubernetesDynamicSecretLeaseRouter = async (server: Fastify const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be greater than 1min" }); - if (valMs > daysToMillisecond(1)) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), path: z.string().trim().default("/").transform(removeTrailingSlash).describe(DYNAMIC_SECRET_LEASES.CREATE.path), environmentSlug: z.string().min(1).describe(DYNAMIC_SECRET_LEASES.CREATE.environmentSlug), diff --git a/backend/src/ee/routes/v1/dynamic-secret-router.ts b/backend/src/ee/routes/v1/dynamic-secret-router.ts index 7fb3e8374..0e48206dc 100644 --- a/backend/src/ee/routes/v1/dynamic-secret-router.ts +++ b/backend/src/ee/routes/v1/dynamic-secret-router.ts @@ -3,7 +3,6 @@ import { z } from "zod"; import { DynamicSecretLeasesSchema } from "@app/db/schemas"; import { DynamicSecretProviderSchema } from "@app/ee/services/dynamic-secret/providers/models"; import { ApiDocsTags, DYNAMIC_SECRETS } from "@app/lib/api-docs"; -import { daysToMillisecond } from "@app/lib/dates"; import { removeTrailingSlash } from "@app/lib/fn"; import { ms } from "@app/lib/ms"; import { isValidHandleBarTemplate } from "@app/lib/template/validate-handlebars"; @@ -60,8 +59,8 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) => const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > daysToMillisecond(1)) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -130,8 +129,8 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) => const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > daysToMillisecond(1)) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -142,8 +141,8 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) => const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > daysToMillisecond(1)) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }) .nullable(), newName: z.string().describe(DYNAMIC_SECRETS.UPDATE.newName).optional(), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsElastiCacheInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsElastiCacheInputForm.tsx index 692493980..c58f2a754 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsElastiCacheInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsElastiCacheInputForm.tsx @@ -36,9 +36,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -48,9 +47,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"), environment: z.object({ name: z.string(), slug: z.string() }), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx index 042eb56e9..35a416224 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AwsIamInputForm.tsx @@ -95,9 +95,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx index 05f85a9e6..581c473b9 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureEntraIdInputForm.tsx @@ -37,9 +37,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -49,9 +48,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), name: z .string() diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureSqlDatabaseInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureSqlDatabaseInputForm.tsx index 56a914977..aece11f38 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureSqlDatabaseInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/AzureSqlDatabaseInputForm.tsx @@ -75,8 +75,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -86,8 +86,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), name: slugSchema(), environment: z.object({ name: z.string(), slug: z.string() }), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CassandraInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CassandraInputForm.tsx index ef05d8a83..15f9387df 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CassandraInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CassandraInputForm.tsx @@ -39,9 +39,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -51,9 +50,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), name: slugSchema(), environment: z.object({ name: z.string(), slug: z.string() }), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CouchbaseInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CouchbaseInputForm.tsx index 3cc41bf2c..17bfeddca 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CouchbaseInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/CouchbaseInputForm.tsx @@ -240,8 +240,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -251,8 +251,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), name: slugSchema(), environment: z.object({ name: z.string(), slug: z.string() }), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx index 31d68e877..1d0b6c268 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/ElasticSearchInputForm.tsx @@ -60,9 +60,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -72,9 +71,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), name: slugSchema(), environment: z.object({ name: z.string(), slug: z.string() }), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/KubernetesInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/KubernetesInputForm.tsx index 8e9206695..4165805b1 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/KubernetesInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/KubernetesInputForm.tsx @@ -99,8 +99,8 @@ const formSchema = z const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -110,8 +110,8 @@ const formSchema = z const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), name: slugSchema(), environment: z.object({ name: z.string(), slug: z.string() }), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx index 824538706..7b7397625 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/LdapInputForm.tsx @@ -61,9 +61,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -73,9 +72,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), name: slugSchema(), environment: z.object({ name: z.string(), slug: z.string() }), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx index e19c09576..3b0c7bb3b 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoAtlasInputForm.tsx @@ -50,9 +50,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -62,9 +61,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), name: slugSchema(), environment: z.object({ name: z.string(), slug: z.string() }), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx index 0cdb72e27..ac60a77b0 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/MongoDBInputForm.tsx @@ -40,9 +40,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -52,9 +51,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), name: slugSchema(), environment: z.object({ name: z.string(), slug: z.string() }), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx index 137ee0d95..7b2e56464 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RabbitMqInputForm.tsx @@ -44,9 +44,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -56,9 +55,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), name: slugSchema(), environment: z.object({ name: z.string(), slug: z.string() }), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx index 940c43c9c..472d30783 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/RedisInputForm.tsx @@ -37,9 +37,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -49,9 +48,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), name: slugSchema(), environment: z.object({ name: z.string(), slug: z.string() }), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx index b6909af2a..621451fda 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapAseInputForm.tsx @@ -35,9 +35,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -47,9 +46,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), name: slugSchema(), environment: z.object({ name: z.string(), slug: z.string() }), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx index 66b974f66..034afee2c 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SapHanaInputForm.tsx @@ -37,9 +37,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -49,9 +48,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), name: slugSchema(), environment: z.object({ name: z.string(), slug: z.string() }), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx index abbb115a3..11357e26a 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SnowflakeInputForm.tsx @@ -35,9 +35,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -47,9 +46,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), name: slugSchema(), environment: z.object({ name: z.string(), slug: z.string() }), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx index 4119cf94d..0a836fec2 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/SqlDatabaseInputForm.tsx @@ -75,9 +75,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -87,9 +86,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), name: slugSchema(), environment: z.object({ name: z.string(), slug: z.string() }), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/VerticaInputForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/VerticaInputForm.tsx index 98cd41165..b48eab850 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/VerticaInputForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/ActionBar/CreateDynamicSecretForm/VerticaInputForm.tsx @@ -66,8 +66,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -77,8 +77,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"), environment: z.object({ name: z.string(), slug: z.string() }), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretAwsElastiCacheProviderForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretAwsElastiCacheProviderForm.tsx index f741e8215..5740e2061 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretAwsElastiCacheProviderForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretAwsElastiCacheProviderForm.tsx @@ -37,9 +37,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -49,9 +48,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }) .nullable(), newName: slugSchema().optional(), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretAwsIamForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretAwsIamForm.tsx index 687d0d52b..555ed9eae 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretAwsIamForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretAwsIamForm.tsx @@ -71,9 +71,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -83,9 +82,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }) .nullable(), newName: slugSchema().optional(), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretAzureEntraIdForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretAzureEntraIdForm.tsx index e6a09d755..c9bfc92cc 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretAzureEntraIdForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretAzureEntraIdForm.tsx @@ -22,9 +22,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -34,9 +33,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), newName: slugSchema().optional() }); diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretAzureSqlDatabaseForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretAzureSqlDatabaseForm.tsx index 36be1b8e5..77bb7aa1f 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretAzureSqlDatabaseForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretAzureSqlDatabaseForm.tsx @@ -73,8 +73,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -84,8 +84,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), newName: slugSchema().optional(), metadata: z diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretCassandraForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretCassandraForm.tsx index 3b95dc8d3..515ee19e3 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretCassandraForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretCassandraForm.tsx @@ -39,9 +39,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -51,9 +50,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }) .nullable(), newName: slugSchema().optional(), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretCouchbaseForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretCouchbaseForm.tsx index 4282ae256..e69b3460f 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretCouchbaseForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretCouchbaseForm.tsx @@ -241,8 +241,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -252,8 +252,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }) .nullable(), newName: slugSchema().optional(), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretElasticSearchForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretElasticSearchForm.tsx index e519423a5..000762bc5 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretElasticSearchForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretElasticSearchForm.tsx @@ -58,9 +58,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -70,9 +69,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), newName: slugSchema().optional(), usernameTemplate: z.string().trim().nullable().optional() diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretKubernetesForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretKubernetesForm.tsx index 0858816bf..95f40f9f5 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretKubernetesForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretKubernetesForm.tsx @@ -97,8 +97,8 @@ const formSchema = z const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -108,8 +108,8 @@ const formSchema = z const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), newName: slugSchema().optional(), usernameTemplate: z.string().trim().optional() diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretLdapForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretLdapForm.tsx index 75edf5600..09d345d3d 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretLdapForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretLdapForm.tsx @@ -51,9 +51,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -63,9 +62,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }) .nullable(), newName: slugSchema().optional(), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretMongoAtlasForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretMongoAtlasForm.tsx index c381f395c..5b577192a 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretMongoAtlasForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretMongoAtlasForm.tsx @@ -50,9 +50,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -62,9 +61,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }) .nullable(), newName: slugSchema().optional(), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretMongoDBForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretMongoDBForm.tsx index 689a56b95..90c31e1f0 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretMongoDBForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretMongoDBForm.tsx @@ -33,9 +33,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -45,9 +44,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }) .nullable(), newName: slugSchema().optional(), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretRabbitMqForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretRabbitMqForm.tsx index ab40914f4..d80acc6de 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretRabbitMqForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretRabbitMqForm.tsx @@ -35,9 +35,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -47,9 +46,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), newName: slugSchema().optional(), usernameTemplate: z.string().trim().nullable().optional() diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretRedisProviderForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretRedisProviderForm.tsx index d77c605e1..bc21a17d7 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretRedisProviderForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretRedisProviderForm.tsx @@ -38,9 +38,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -50,9 +49,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }) .nullable(), newName: slugSchema().optional(), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretSapAseForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretSapAseForm.tsx index 86327a767..37dbae5ee 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretSapAseForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretSapAseForm.tsx @@ -37,9 +37,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), usernameTemplate: z.string().trim().nullable().optional(), maxTTL: z @@ -50,9 +49,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), newName: slugSchema().optional() }); diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretSapHanaForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretSapHanaForm.tsx index 8051f883c..430f13e83 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretSapHanaForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretSapHanaForm.tsx @@ -37,9 +37,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -49,9 +48,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), newName: slugSchema().optional(), usernameTemplate: z.string().trim().nullable().optional() diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretSnowflakeForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretSnowflakeForm.tsx index 5e23cb2a3..1cbc20cfb 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretSnowflakeForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretSnowflakeForm.tsx @@ -35,9 +35,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -47,9 +46,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), newName: slugSchema().optional(), usernameTemplate: z.string().trim().nullable().optional() diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretSqlProviderForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretSqlProviderForm.tsx index 6beeba169..929a1485d 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretSqlProviderForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretSqlProviderForm.tsx @@ -73,9 +73,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z .string() @@ -85,9 +84,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - // a day - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }) .nullable(), newName: slugSchema().optional(), diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretVertica.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretVertica.tsx index e2f3e5b4d..e4ccda943 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretVertica.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretVertica.tsx @@ -64,8 +64,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), usernameTemplate: z.string().trim().nullable().optional(), maxTTL: z @@ -76,8 +76,8 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > 24 * 60 * 60 * 1000) - ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" }); + if (valMs > ms("10y")) + ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), newName: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase") }); From 28b37efd60e099863171a3100f1de10b6ee95546 Mon Sep 17 00:00:00 2001 From: Victor Santos Date: Mon, 27 Oct 2025 15:29:06 -0300 Subject: [PATCH 09/12] refactor: set default values for AWS access keys in environment configuration --- backend/src/lib/config/env.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/backend/src/lib/config/env.ts b/backend/src/lib/config/env.ts index 81d28167e..9fc4cff92 100644 --- a/backend/src/lib/config/env.ts +++ b/backend/src/lib/config/env.ts @@ -266,8 +266,12 @@ const envSchema = z RELAY_AUTH_SECRET: zpStr(z.string().optional()), DYNAMIC_SECRET_ALLOW_INTERNAL_IP: zodStrBool.default("false"), - DYNAMIC_SECRET_AWS_ACCESS_KEY_ID: zpStr(z.string().optional()), - DYNAMIC_SECRET_AWS_SECRET_ACCESS_KEY: zpStr(z.string().optional()), + DYNAMIC_SECRET_AWS_ACCESS_KEY_ID: zpStr(z.string().optional()).default( + process.env.INF_APP_CONNECTION_AWS_ACCESS_KEY_ID + ), + DYNAMIC_SECRET_AWS_SECRET_ACCESS_KEY: zpStr(z.string().optional()).default( + process.env.INF_APP_CONNECTION_AWS_SECRET_ACCESS_KEY + ), /* ----------------------------------------------------------------------------- */ /* App Connections ----------------------------------------------------------------------------- */ @@ -435,11 +439,7 @@ const envSchema = z data.INF_APP_CONNECTION_AZURE_APP_CONFIGURATION_CLIENT_SECRET || data.INF_APP_CONNECTION_AZURE_CLIENT_SECRET, INF_APP_CONNECTION_HEROKU_OAUTH_CLIENT_ID: data.INF_APP_CONNECTION_HEROKU_OAUTH_CLIENT_ID || data.CLIENT_ID_HEROKU, INF_APP_CONNECTION_HEROKU_OAUTH_CLIENT_SECRET: - data.INF_APP_CONNECTION_HEROKU_OAUTH_CLIENT_SECRET || data.CLIENT_SECRET_HEROKU, - DYNAMIC_SECRET_AWS_ACCESS_KEY_ID: - data.DYNAMIC_SECRET_AWS_ACCESS_KEY_ID || data.INF_APP_CONNECTION_AWS_ACCESS_KEY_ID, - DYNAMIC_SECRET_AWS_SECRET_ACCESS_KEY: - data.DYNAMIC_SECRET_AWS_SECRET_ACCESS_KEY || data.INF_APP_CONNECTION_AWS_SECRET_ACCESS_KEY + data.INF_APP_CONNECTION_HEROKU_OAUTH_CLIENT_SECRET || data.CLIENT_SECRET_HEROKU })); export type TEnvConfig = Readonly>; From 0d778dd73709ea0fa3272df99c5afdfdceb1629f Mon Sep 17 00:00:00 2001 From: Victor Santos Date: Mon, 27 Oct 2025 16:05:08 -0300 Subject: [PATCH 10/12] refactor: improve TTL validation logic in EditDynamicSecretRabbitMqForm to ensure proper limits --- .../EditDynamicSecretForm/EditDynamicSecretRabbitMqForm.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretRabbitMqForm.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretRabbitMqForm.tsx index d80acc6de..984e68831 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretRabbitMqForm.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/components/DynamicSecretListView/EditDynamicSecretForm/EditDynamicSecretRabbitMqForm.tsx @@ -35,7 +35,7 @@ const formSchema = z.object({ const valMs = ms(val); if (valMs < 60 * 1000) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be a greater than 1min" }); - if (valMs > ms("10y")) + if (valMs > ms("10y")) ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than 10 years" }); }), maxTTL: z From 97a01bdcb40a0ce5f0d826d4330f113d4c7d3f3d Mon Sep 17 00:00:00 2001 From: Carlos Monastyrski Date: Mon, 27 Oct 2025 18:57:28 -0300 Subject: [PATCH 11/12] Address PR comments --- .../forms/CreateSecretSyncForm.tsx | 6 +- .../DuplicateDestinationConfirmationModal.tsx | 49 ++++++++------ .../secret-syncs/forms/EditSecretSyncForm.tsx | 3 + .../SecretSyncReviewFields.tsx | 2 +- ...DuplicateSecretSyncDestinationsSection.tsx | 64 ------------------- .../index.ts | 1 - .../OrgProductSettingsTab.tsx | 6 +- .../SettingsPage/components/index.tsx | 1 - 8 files changed, 37 insertions(+), 95 deletions(-) delete mode 100644 frontend/src/pages/organization/SettingsPage/components/BlockDuplicateSecretSyncDestinationsSection/BlockDuplicateSecretSyncDestinationsSection.tsx delete mode 100644 frontend/src/pages/organization/SettingsPage/components/BlockDuplicateSecretSyncDestinationsSection/index.ts diff --git a/frontend/src/components/secret-syncs/forms/CreateSecretSyncForm.tsx b/frontend/src/components/secret-syncs/forms/CreateSecretSyncForm.tsx index d10d27803..ebad86cbd 100644 --- a/frontend/src/components/secret-syncs/forms/CreateSecretSyncForm.tsx +++ b/frontend/src/components/secret-syncs/forms/CreateSecretSyncForm.tsx @@ -256,11 +256,7 @@ export const CreateSecretSyncForm = ({
- {selectedTabIndex > 0 && ( diff --git a/frontend/src/components/secret-syncs/forms/DuplicateDestinationConfirmationModal.tsx b/frontend/src/components/secret-syncs/forms/DuplicateDestinationConfirmationModal.tsx index d80dbc640..59871e880 100644 --- a/frontend/src/components/secret-syncs/forms/DuplicateDestinationConfirmationModal.tsx +++ b/frontend/src/components/secret-syncs/forms/DuplicateDestinationConfirmationModal.tsx @@ -6,6 +6,7 @@ type Props = { onConfirm: () => void; isLoading?: boolean; duplicateProjectId?: string; + isDisabled?: boolean; }; export const DuplicateDestinationConfirmationModal = ({ @@ -13,7 +14,8 @@ export const DuplicateDestinationConfirmationModal = ({ onOpenChange, onConfirm, isLoading, - duplicateProjectId + duplicateProjectId, + isDisabled }: Props) => { return ( @@ -21,7 +23,12 @@ export const DuplicateDestinationConfirmationModal = ({

Another secret sync in your organization is already configured with the same - destination. Proceeding may cause conflicts or overwrite existing data. + destination.{" "} + + {isDisabled + ? "Your organization does not allow duplicate destination configurations." + : "Proceeding may cause conflicts or overwrite existing data."} +

{duplicateProjectId && (

@@ -31,26 +38,28 @@ export const DuplicateDestinationConfirmationModal = ({

)} -

Are you sure you want to continue?

+ {!isDisabled &&

Are you sure you want to continue?

}
-
- - - - - - -
+ {!isDisabled && ( +
+ + + + + + +
+ )} ); diff --git a/frontend/src/components/secret-syncs/forms/EditSecretSyncForm.tsx b/frontend/src/components/secret-syncs/forms/EditSecretSyncForm.tsx index 3c0e4ea17..2085afe9c 100644 --- a/frontend/src/components/secret-syncs/forms/EditSecretSyncForm.tsx +++ b/frontend/src/components/secret-syncs/forms/EditSecretSyncForm.tsx @@ -5,6 +5,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { createNotification } from "@app/components/notifications"; import { SecretSyncEditFields } from "@app/components/secret-syncs/types"; import { Button, ModalClose } from "@app/components/v2"; +import { useOrganization } from "@app/context"; import { SECRET_SYNC_MAP } from "@app/helpers/secretSyncs"; import { TSecretSync, @@ -30,6 +31,7 @@ export const EditSecretSyncForm = ({ secretSync, fields, onComplete }: Props) => const { name: destinationName } = SECRET_SYNC_MAP[secretSync.destination]; const [showDuplicateConfirmation, setShowDuplicateConfirmation] = useState(false); const [pendingFormData, setPendingFormData] = useState(null); + const { currentOrg } = useOrganization(); const formMethods = useForm({ resolver: zodResolver(UpdateSecretSyncFormSchema), @@ -209,6 +211,7 @@ export const EditSecretSyncForm = ({ secretSync, fields, onComplete }: Props) => onConfirm={handleConfirmDuplicate} isLoading={updateSecretSync.isPending} duplicateProjectId={storedDuplicateProjectId} + isDisabled={currentOrg?.blockDuplicateSecretSyncDestinations} /> ); diff --git a/frontend/src/components/secret-syncs/forms/SecretSyncReviewFields/SecretSyncReviewFields.tsx b/frontend/src/components/secret-syncs/forms/SecretSyncReviewFields/SecretSyncReviewFields.tsx index 4a796933d..5c04fb308 100644 --- a/frontend/src/components/secret-syncs/forms/SecretSyncReviewFields/SecretSyncReviewFields.tsx +++ b/frontend/src/components/secret-syncs/forms/SecretSyncReviewFields/SecretSyncReviewFields.tsx @@ -219,7 +219,7 @@ export const SecretSyncReviewFields = () => {

{currentOrg?.blockDuplicateSecretSyncDestinations - ? "Another secret sync in your organization is already configured with the same destination. This organization has blocking duplicate destinations enabled." + ? "Another secret sync in your organization is already configured with the same destination. Your organization does not allow duplicate destination configurations." : "Another secret sync in your organization is already configured with the same destination. This may lead to conflicts or unexpected behavior."}

{duplicateProjectId && ( diff --git a/frontend/src/pages/organization/SettingsPage/components/BlockDuplicateSecretSyncDestinationsSection/BlockDuplicateSecretSyncDestinationsSection.tsx b/frontend/src/pages/organization/SettingsPage/components/BlockDuplicateSecretSyncDestinationsSection/BlockDuplicateSecretSyncDestinationsSection.tsx deleted file mode 100644 index a2346bd91..000000000 --- a/frontend/src/pages/organization/SettingsPage/components/BlockDuplicateSecretSyncDestinationsSection/BlockDuplicateSecretSyncDestinationsSection.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import { useState } from "react"; - -import { createNotification } from "@app/components/notifications"; -import { OrgPermissionCan } from "@app/components/permissions"; -import { Checkbox } from "@app/components/v2"; -import { OrgPermissionActions, OrgPermissionSubjects, useOrganization } from "@app/context"; -import { useUpdateOrg } from "@app/hooks/api/organization/queries"; - -export const BlockDuplicateSecretSyncDestinationsSection = () => { - const { currentOrg } = useOrganization(); - const { mutateAsync: updateOrg } = useUpdateOrg(); - - const [isLoading, setIsLoading] = useState(false); - - const handleToggle = async (state: boolean) => { - setIsLoading(true); - - try { - if (!currentOrg?.id) { - setIsLoading(false); - return; - } - - await updateOrg({ - orgId: currentOrg.id, - blockDuplicateSecretSyncDestinations: state - }); - - createNotification({ - text: `Successfully ${state ? "enabled" : "disabled"} blocking duplicate secret sync destinations for this organization`, - type: "success" - }); - } catch (err) { - console.error(err); - createNotification({ - text: "Failed to update blocking duplicate secret sync destinations setting for this organization", - type: "error" - }); - } finally { - setIsLoading(false); - } - }; - - return ( -
-

Block Duplicate Secret Sync Destinations

- - {(isAllowed) => ( -
- handleToggle(state as boolean)} - > - This feature prevents creating secret syncs with destinations that are already in use - by other syncs in your organization. - -
- )} -
-
- ); -}; diff --git a/frontend/src/pages/organization/SettingsPage/components/BlockDuplicateSecretSyncDestinationsSection/index.ts b/frontend/src/pages/organization/SettingsPage/components/BlockDuplicateSecretSyncDestinationsSection/index.ts deleted file mode 100644 index 0426a6178..000000000 --- a/frontend/src/pages/organization/SettingsPage/components/BlockDuplicateSecretSyncDestinationsSection/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { BlockDuplicateSecretSyncDestinationsSection } from "./BlockDuplicateSecretSyncDestinationsSection"; diff --git a/frontend/src/pages/organization/SettingsPage/components/OrgProductSettingsTab/OrgProductSettingsTab.tsx b/frontend/src/pages/organization/SettingsPage/components/OrgProductSettingsTab/OrgProductSettingsTab.tsx index 5e23a4f97..e4d935996 100644 --- a/frontend/src/pages/organization/SettingsPage/components/OrgProductSettingsTab/OrgProductSettingsTab.tsx +++ b/frontend/src/pages/organization/SettingsPage/components/OrgProductSettingsTab/OrgProductSettingsTab.tsx @@ -49,11 +49,11 @@ export const OrgProductSettingsTab = () => {

- Block Duplicate Secret Sync Destinations + Unique Secret Sync Destination Policy

- When enabled, this setting prevents the creation of multiple sync configurations - pointing to the same destination. + When enabled, ensures each destination can only be used by one secret sync + configuration, preventing potential conflicts or overwrites.

diff --git a/frontend/src/pages/organization/SettingsPage/components/index.tsx b/frontend/src/pages/organization/SettingsPage/components/index.tsx index 3387ed32b..82909f799 100644 --- a/frontend/src/pages/organization/SettingsPage/components/index.tsx +++ b/frontend/src/pages/organization/SettingsPage/components/index.tsx @@ -1,3 +1,2 @@ -export { BlockDuplicateSecretSyncDestinationsSection } from "./BlockDuplicateSecretSyncDestinationsSection"; export { OrgProductSettingsTab } from "./OrgProductSettingsTab"; export { OrgTabGroup } from "./OrgTabGroup"; From d860c5380b16df862020ab73d16d6189f51e3ace Mon Sep 17 00:00:00 2001 From: Carlos Monastyrski Date: Mon, 27 Oct 2025 21:13:16 -0300 Subject: [PATCH 12/12] Block duplicate destinations on updates if flag is enabled --- .../secret-sync/secret-sync-service.ts | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/backend/src/services/secret-sync/secret-sync-service.ts b/backend/src/services/secret-sync/secret-sync-service.ts index b3eb05369..a4e2fc467 100644 --- a/backend/src/services/secret-sync/secret-sync-service.ts +++ b/backend/src/services/secret-sync/secret-sync-service.ts @@ -454,6 +454,33 @@ export const secretSyncServiceFactory = ({ let { folderId } = secretSync; + if (params.destinationConfig) { + const project = await projectDAL.findById(secretSync.projectId); + if (!project) { + throw new NotFoundError({ message: "Project not found" }); + } + const organization = await orgDAL.findById(project.orgId); + + if (organization?.blockDuplicateSecretSyncDestinations) { + const duplicateCheck = await checkDuplicateDestination( + { + destination, + destinationConfig: params.destinationConfig, + projectId: secretSync.projectId, + excludeSyncId: secretSync.id + }, + actor + ); + if (duplicateCheck.hasDuplicate) { + throw new BadRequestError({ + message: `A secret sync with this destination already exists${ + duplicateCheck.duplicateProjectId ? ` in project ${duplicateCheck.duplicateProjectId}` : "" + }.` + }); + } + } + } + if (params.connectionId) { const destinationApp = SECRET_SYNC_CONNECTION_MAP[secretSync.destination as SecretSync];