From 9d0020fa4e14148e7fa75710ec94bb163a2f0958 Mon Sep 17 00:00:00 2001 From: Scott Wilson Date: Mon, 14 Apr 2025 10:50:45 -0700 Subject: [PATCH] improvement: rollback deprecate all secret rotation v1 create, update UI to only prevent pg/mssql --- .../v1/secret-rotation-provider-router.ts | 3 +- .../ee/routes/v1/secret-rotation-router.ts | 13 +++-- .../secret-rotation-service.ts | 7 +++ .../secret-rotation/templates/index.ts | 6 ++- .../secret-rotation/templates/types.ts | 1 + backend/src/services/project/project-types.ts | 4 +- .../src/hooks/api/secretRotation/types.ts | 1 + .../SecretRotationPage/SecretRotationPage.tsx | 53 ++++++++++++++++--- 8 files changed, 73 insertions(+), 15 deletions(-) diff --git a/backend/src/ee/routes/v1/secret-rotation-provider-router.ts b/backend/src/ee/routes/v1/secret-rotation-provider-router.ts index 58419d3b7..e6a1ac72b 100644 --- a/backend/src/ee/routes/v1/secret-rotation-provider-router.ts +++ b/backend/src/ee/routes/v1/secret-rotation-provider-router.ts @@ -23,7 +23,8 @@ export const registerSecretRotationProviderRouter = async (server: FastifyZodPro title: z.string(), image: z.string().optional(), description: z.string().optional(), - template: z.any() + template: z.any(), + isDeprecated: z.boolean().optional() }) .array() }) diff --git a/backend/src/ee/routes/v1/secret-rotation-router.ts b/backend/src/ee/routes/v1/secret-rotation-router.ts index 1efc2c8aa..936459fa1 100644 --- a/backend/src/ee/routes/v1/secret-rotation-router.ts +++ b/backend/src/ee/routes/v1/secret-rotation-router.ts @@ -1,7 +1,6 @@ import { z } from "zod"; import { SecretRotationOutputsSchema, SecretRotationsSchema } from "@app/db/schemas"; -import { BadRequestError } from "@app/lib/errors"; import { removeTrailingSlash } from "@app/lib/fn"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -41,10 +40,16 @@ export const registerSecretRotationRouter = async (server: FastifyZodProvider) = } }, onRequest: verifyAuth([AuthMode.JWT]), - handler: async () => { - throw new BadRequestError({ - message: `This version of Secret Rotations has been deprecated. Please see docs for new version.` + handler: async (req) => { + const secretRotation = await server.services.secretRotation.createRotation({ + actor: req.permission.type, + actorAuthMethod: req.permission.authMethod, + actorId: req.permission.id, + actorOrgId: req.permission.orgId, + ...req.body, + projectId: req.body.workspaceId }); + return { secretRotation }; } }); diff --git a/backend/src/ee/services/secret-rotation/secret-rotation-service.ts b/backend/src/ee/services/secret-rotation/secret-rotation-service.ts index df7b86a0b..2364de79d 100644 --- a/backend/src/ee/services/secret-rotation/secret-rotation-service.ts +++ b/backend/src/ee/services/secret-rotation/secret-rotation-service.ts @@ -127,6 +127,13 @@ export const secretRotationServiceFactory = ({ }); if (selectedSecrets.length !== Object.values(outputs).length) throw new NotFoundError({ message: `Secrets not found in folder with ID '${folder.id}'` }); + const rotatedSecrets = selectedSecrets.filter(({ isRotatedSecret }) => isRotatedSecret); + if (rotatedSecrets.length) + throw new BadRequestError({ + message: `Selected secrets are already used for rotation: ${rotatedSecrets + .map((secret) => secret.key) + .join(", ")}` + }); } else { const selectedSecrets = await secretDAL.find({ folderId: folder.id, diff --git a/backend/src/ee/services/secret-rotation/templates/index.ts b/backend/src/ee/services/secret-rotation/templates/index.ts index 39774ae28..ce3ecd687 100644 --- a/backend/src/ee/services/secret-rotation/templates/index.ts +++ b/backend/src/ee/services/secret-rotation/templates/index.ts @@ -18,7 +18,8 @@ export const rotationTemplates: TSecretRotationProviderTemplate[] = [ title: "PostgreSQL", image: "postgres.png", description: "Rotate PostgreSQL/CockroachDB user credentials", - template: POSTGRES_TEMPLATE + template: POSTGRES_TEMPLATE, + isDeprecated: true }, { name: "mysql", @@ -32,7 +33,8 @@ export const rotationTemplates: TSecretRotationProviderTemplate[] = [ title: "Microsoft SQL Server", image: "mssqlserver.png", description: "Rotate Microsoft SQL server user credentials", - template: MSSQL_TEMPLATE + template: MSSQL_TEMPLATE, + isDeprecated: true }, { name: "aws-iam", diff --git a/backend/src/ee/services/secret-rotation/templates/types.ts b/backend/src/ee/services/secret-rotation/templates/types.ts index 2adc40ba3..2ec998db7 100644 --- a/backend/src/ee/services/secret-rotation/templates/types.ts +++ b/backend/src/ee/services/secret-rotation/templates/types.ts @@ -50,6 +50,7 @@ export type TSecretRotationProviderTemplate = { image?: string; description?: string; template: THttpProviderTemplate | TDbProviderTemplate | TAwsProviderTemplate; + isDeprecated?: boolean; }; export type THttpProviderTemplate = { diff --git a/backend/src/services/project/project-types.ts b/backend/src/services/project/project-types.ts index 4195f3dfc..4346ae2c4 100644 --- a/backend/src/services/project/project-types.ts +++ b/backend/src/services/project/project-types.ts @@ -1,11 +1,11 @@ import { Knex } from "knex"; -import { ProjectType, TProjectKeys, SortDirection } from "@app/db/schemas"; +import { ProjectType, SortDirection, TProjectKeys } from "@app/db/schemas"; import { TSshCertificateAuthorityDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-dal"; import { TSshCertificateAuthoritySecretDALFactory } from "@app/ee/services/ssh/ssh-certificate-authority-secret-dal"; +import { OrgServiceActor, TProjectPermission } from "@app/lib/types"; import { TKmsServiceFactory } from "@app/services/kms/kms-service"; import { TProjectSshConfigDALFactory } from "@app/services/project/project-ssh-config-dal"; -import { OrgServiceActor, TProjectPermission } from "@app/lib/types"; import { ActorAuthMethod, ActorType } from "../auth/auth-type"; diff --git a/frontend/src/hooks/api/secretRotation/types.ts b/frontend/src/hooks/api/secretRotation/types.ts index 07a4c70df..19c4cdcdf 100644 --- a/frontend/src/hooks/api/secretRotation/types.ts +++ b/frontend/src/hooks/api/secretRotation/types.ts @@ -45,6 +45,7 @@ export type TSecretRotationProviderTemplate = { image?: string; description?: string; template: THttpProviderTemplate | TDbProviderTemplate; + isDeprecated?: boolean; }; export type THttpProviderTemplate = { diff --git a/frontend/src/pages/secret-manager/SecretRotationPage/SecretRotationPage.tsx b/frontend/src/pages/secret-manager/SecretRotationPage/SecretRotationPage.tsx index a9d9f0bf0..5d40a4126 100644 --- a/frontend/src/pages/secret-manager/SecretRotationPage/SecretRotationPage.tsx +++ b/frontend/src/pages/secret-manager/SecretRotationPage/SecretRotationPage.tsx @@ -38,7 +38,12 @@ import { Tr } from "@app/components/v2"; import { NoticeBannerV2 } from "@app/components/v2/NoticeBannerV2/NoticeBannerV2"; -import { ProjectPermissionSub, useWorkspace } from "@app/context"; +import { + ProjectPermissionSub, + useProjectPermission, + useSubscription, + useWorkspace +} from "@app/context"; import { ProjectPermissionSecretRotationActions } from "@app/context/ProjectPermissionContext/types"; import { usePopUp } from "@app/hooks"; import { @@ -47,20 +52,29 @@ import { useGetSecretRotations, useRestartSecretRotation } from "@app/hooks/api"; +import { TSecretRotationProviderTemplate } from "@app/hooks/api/secretRotation/types"; import { ProjectType } from "@app/hooks/api/workspace/types"; +import { CreateRotationForm } from "@app/pages/secret-manager/SecretRotationPage/components/CreateRotationForm"; const Page = () => { const { currentWorkspace } = useWorkspace(); + const { permission } = useProjectPermission(); const navigate = useNavigate(); const { popUp, handlePopUpOpen, handlePopUpToggle, handlePopUpClose } = usePopUp([ + "createRotation", "activeBot", "deleteRotation", "upgradePlan", "secretRotationV2" ] as const); const workspaceId = currentWorkspace?.id || ""; + const canCreateRotation = permission.can( + ProjectPermissionSecretRotationActions.Create, + ProjectPermissionSub.SecretRotation + ); + const { subscription } = useSubscription(); const { data: secretRotationProviders, isPending: isRotationProviderLoading } = useGetSecretRotationProviders({ workspaceId }); @@ -119,6 +133,18 @@ const Page = () => { } }; + const handleCreateRotation = (provider: TSecretRotationProviderTemplate) => { + if (subscription && !subscription?.secretRotation) { + handlePopUpOpen("upgradePlan"); + return; + } + if (!canCreateRotation) { + createNotification({ type: "error", text: "Access permission denied!!" }); + return; + } + handlePopUpOpen("createRotation", provider); + }; + return (
{ Infisical is revamping its Secret Rotation experience.

- Secret Rotations can now be created from the{" "} + PostgreSQL and Microsoft SQL Server Rotations can now be created from the{" "} { key={`infisical-rotation-provider-${provider.name}`} tabIndex={0} role="button" - onKeyDown={() => { - handlePopUpOpen("secretRotationV2", provider.title); + onKeyDown={(evt) => { + if (evt.key !== "Enter") return; + if (provider.isDeprecated) { + handlePopUpOpen("secretRotationV2", provider.title); + } else { + handleCreateRotation(provider); + } }} onClick={() => { - handlePopUpOpen("secretRotationV2", provider.title); + if (provider.isDeprecated) { + handlePopUpOpen("secretRotationV2", provider.title); + } else { + handleCreateRotation(provider); + } }} > {

+ handlePopUpToggle("createRotation", isOpen)} + provider={(popUp.createRotation.data as TSecretRotationProviderTemplate) || {}} + /> { > Secret Manager Dashboard {" "} - to create a Secret Rotation. + to create a {popUp.secretRotationV2.data} Rotation.