From 419916ee0cb8ed6d717f82c4220ec85e6f140507 Mon Sep 17 00:00:00 2001 From: Daniel Hougaard <62331820+DanielHougaard@users.noreply.github.com> Date: Sat, 17 Feb 2024 00:14:30 +0100 Subject: [PATCH] Block secret mutations during upgrade --- .../secret-approval-request-service.ts | 11 ++++ backend/src/server/routes/index.ts | 3 ++ backend/src/services/project/project-dal.ts | 10 +++- backend/src/services/project/project-queue.ts | 10 +--- .../secret-import/secret-import-service.ts | 11 ++++ backend/src/services/secret/secret-service.ts | 51 +++++++++++++++++++ 6 files changed, 86 insertions(+), 10 deletions(-) diff --git a/backend/src/ee/services/secret-approval-request/secret-approval-request-service.ts b/backend/src/ee/services/secret-approval-request/secret-approval-request-service.ts index ef10db804..9e2bb8477 100644 --- a/backend/src/ee/services/secret-approval-request/secret-approval-request-service.ts +++ b/backend/src/ee/services/secret-approval-request/secret-approval-request-service.ts @@ -11,6 +11,7 @@ import { BadRequestError, UnauthorizedError } from "@app/lib/errors"; import { groupBy, pick, unique } from "@app/lib/fn"; import { alphaNumericNanoId } from "@app/lib/nanoid"; import { ActorType } from "@app/services/auth/auth-type"; +import { TProjectDALFactory } from "@app/services/project/project-dal"; import { TSecretQueueFactory } from "@app/services/secret/secret-queue"; import { TSecretServiceFactory } from "@app/services/secret/secret-service"; import { TSecretVersionDALFactory } from "@app/services/secret/secret-version-dal"; @@ -47,6 +48,7 @@ type TSecretApprovalRequestServiceFactoryDep = { secretBlindIndexDAL: Pick; snapshotService: Pick; secretVersionDAL: Pick; + projectDAL: Pick; secretService: Pick< TSecretServiceFactory, | "fnSecretBulkInsert" @@ -67,6 +69,7 @@ export const secretApprovalRequestServiceFactory = ({ secretApprovalRequestReviewerDAL, secretApprovalRequestSecretDAL, secretBlindIndexDAL, + projectDAL, permissionService, snapshotService, secretService, @@ -434,6 +437,14 @@ export const secretApprovalRequestServiceFactory = ({ subject(ProjectPermissionSub.Secrets, { environment, secretPath }) ); + const isProjectBeingUpgraded = await projectDAL.isProjectBeingUpgraded(projectId); + + if (isProjectBeingUpgraded) { + throw new BadRequestError({ + message: "Project is currently being upgraded, and secrets cannot be written. Please try again" + }); + } + const folder = await folderDAL.findBySecretPath(projectId, environment, secretPath); if (!folder) throw new BadRequestError({ message: "Folder not found", name: "GenSecretApproval" }); const folderId = folder.id; diff --git a/backend/src/server/routes/index.ts b/backend/src/server/routes/index.ts index 0cdc98791..fd1b45878 100644 --- a/backend/src/server/routes/index.ts +++ b/backend/src/server/routes/index.ts @@ -376,6 +376,7 @@ export const registerRoutes = async ( folderDAL, permissionService, secretImportDAL, + projectDAL, secretDAL }); const integrationAuthService = integrationAuthServiceFactory({ @@ -411,6 +412,7 @@ export const registerRoutes = async ( secretVersionTagDAL, secretBlindIndexDAL, permissionService, + projectDAL, secretDAL, secretTagDAL, snapshotService, @@ -424,6 +426,7 @@ export const registerRoutes = async ( secretTagDAL, secretApprovalRequestSecretDAL: sarSecretDAL, secretApprovalRequestReviewerDAL: sarReviewerDAL, + projectDAL, secretVersionDAL, secretBlindIndexDAL, secretApprovalRequestDAL, diff --git a/backend/src/services/project/project-dal.ts b/backend/src/services/project/project-dal.ts index fd590b0bc..fafa02394 100644 --- a/backend/src/services/project/project-dal.ts +++ b/backend/src/services/project/project-dal.ts @@ -1,7 +1,7 @@ import { Knex } from "knex"; import { TDbClient } from "@app/db"; -import { ProjectsSchema, ProjectUpgradeStatus, TableName, TProjectsUpdate } from "@app/db/schemas"; +import { ProjectsSchema, ProjectUpgradeStatus, ProjectVersion, TableName, TProjectsUpdate } from "@app/db/schemas"; import { DatabaseError } from "@app/lib/errors"; import { ormify, selectAllTableCols, sqlNestRelationships } from "@app/lib/knex"; @@ -160,12 +160,18 @@ export const projectDALFactory = (db: TDbClient) => { } }; + const isProjectBeingUpgraded = async (projectId: string) => { + const project = await projectOrm.findById(projectId); + return project.upgradeStatus === ProjectUpgradeStatus.InProgress && project.version === ProjectVersion.V1; + }; + return { ...projectOrm, findAllProjects, setProjectUpgradeStatus, findAllProjectsByIdentity, findProjectGhostUser, - findProjectById + findProjectById, + isProjectBeingUpgraded }; }; diff --git a/backend/src/services/project/project-queue.ts b/backend/src/services/project/project-queue.ts index 5c1e35d82..81b0afe60 100644 --- a/backend/src/services/project/project-queue.ts +++ b/backend/src/services/project/project-queue.ts @@ -150,12 +150,6 @@ export const projectQueueFactory = ({ oldProjectKey ); - console.log( - decryptedSecrets - .filter((s) => s.docType === SecretDocType.ApprovalSecret) - .map((s) => `${s.secretKey} - ${s.secretValue}`) - ); - if (secrets.length !== decryptedSecrets.length) { throw new Error("Failed to decrypt some secret versions"); } @@ -396,10 +390,10 @@ export const projectQueueFactory = ({ await projectDAL.setProjectUpgradeStatus(data.projectId, null, tx); - throw new Error("Transaction was successful!"); + // await new Promise((resolve) => setTimeout(resolve, 60_000)); + // throw new Error("Transaction was successful!"); }); } catch (err) { - console.log(err); const [project] = await projectDAL .find({ id: data.projectId, diff --git a/backend/src/services/secret-import/secret-import-service.ts b/backend/src/services/secret-import/secret-import-service.ts index a519c7820..33d89f014 100644 --- a/backend/src/services/secret-import/secret-import-service.ts +++ b/backend/src/services/secret-import/secret-import-service.ts @@ -4,6 +4,7 @@ import { TPermissionServiceFactory } from "@app/ee/services/permission/permissio import { ProjectPermissionActions, ProjectPermissionSub } from "@app/ee/services/permission/project-permission"; import { BadRequestError } from "@app/lib/errors"; +import { TProjectDALFactory } from "../project/project-dal"; import { TProjectEnvDALFactory } from "../project-env/project-env-dal"; import { TSecretDALFactory } from "../secret/secret-dal"; import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal"; @@ -21,6 +22,7 @@ type TSecretImportServiceFactoryDep = { secretImportDAL: TSecretImportDALFactory; folderDAL: TSecretFolderDALFactory; secretDAL: Pick; + projectDAL: Pick; projectEnvDAL: TProjectEnvDALFactory; permissionService: Pick; }; @@ -34,6 +36,7 @@ export const secretImportServiceFactory = ({ projectEnvDAL, permissionService, folderDAL, + projectDAL, secretDAL }: TSecretImportServiceFactoryDep) => { const createImport = async ({ @@ -62,6 +65,14 @@ export const secretImportServiceFactory = ({ }) ); + const isProjectBeingUpgraded = await projectDAL.isProjectBeingUpgraded(projectId); + + if (isProjectBeingUpgraded) { + throw new BadRequestError({ + message: "Project is currently being upgraded, and secrets cannot be written. Please try again" + }); + } + const folder = await folderDAL.findBySecretPath(projectId, environment, path); if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Create import" }); diff --git a/backend/src/services/secret/secret-service.ts b/backend/src/services/secret/secret-service.ts index ff9dce9a8..e8af1ca66 100644 --- a/backend/src/services/secret/secret-service.ts +++ b/backend/src/services/secret/secret-service.ts @@ -11,6 +11,7 @@ import { groupBy, pick } from "@app/lib/fn"; import { logger } from "@app/lib/logger"; import { ActorType } from "../auth/auth-type"; +import { TProjectDALFactory } from "../project/project-dal"; import { TProjectBotServiceFactory } from "../project-bot/project-bot-service"; import { TSecretBlindIndexDALFactory } from "../secret-blind-index/secret-blind-index-dal"; import { TSecretFolderDALFactory } from "../secret-folder/secret-folder-dal"; @@ -49,6 +50,7 @@ type TSecretServiceFactoryDep = { secretTagDAL: TSecretTagDALFactory; secretVersionDAL: TSecretVersionDALFactory; folderDAL: Pick; + projectDAL: Pick; secretBlindIndexDAL: TSecretBlindIndexDALFactory; permissionService: Pick; snapshotService: Pick; @@ -68,6 +70,7 @@ export const secretServiceFactory = ({ permissionService, snapshotService, secretQueueService, + projectDAL, projectBotService, secretImportDAL, secretVersionTagDAL @@ -281,6 +284,14 @@ export const secretServiceFactory = ({ subject(ProjectPermissionSub.Secrets, { environment, secretPath: path }) ); + const isProjectBeingUpgraded = await projectDAL.isProjectBeingUpgraded(projectId); + + if (isProjectBeingUpgraded) { + throw new BadRequestError({ + message: "Project is currently being upgraded, and secrets cannot be written. Please try again" + }); + } + const folder = await folderDAL.findBySecretPath(projectId, environment, path); if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Create secret" }); const folderId = folder.id; @@ -359,6 +370,14 @@ export const secretServiceFactory = ({ subject(ProjectPermissionSub.Secrets, { environment, secretPath: path }) ); + const isProjectBeingUpgraded = await projectDAL.isProjectBeingUpgraded(projectId); + + if (isProjectBeingUpgraded) { + throw new BadRequestError({ + message: "Project is currently being upgraded, and secrets cannot be written. Please try again" + }); + } + const folder = await folderDAL.findBySecretPath(projectId, environment, path); if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Create secret" }); const folderId = folder.id; @@ -459,6 +478,14 @@ export const secretServiceFactory = ({ subject(ProjectPermissionSub.Secrets, { environment, secretPath: path }) ); + const isProjectBeingUpgraded = await projectDAL.isProjectBeingUpgraded(projectId); + + if (isProjectBeingUpgraded) { + throw new BadRequestError({ + message: "Project is currently being upgraded, and secrets cannot be written. Please try again" + }); + } + const folder = await folderDAL.findBySecretPath(projectId, environment, path); if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Create secret" }); const folderId = folder.id; @@ -650,6 +677,14 @@ export const secretServiceFactory = ({ subject(ProjectPermissionSub.Secrets, { environment, secretPath: path }) ); + const isProjectBeingUpgraded = await projectDAL.isProjectBeingUpgraded(projectId); + + if (isProjectBeingUpgraded) { + throw new BadRequestError({ + message: "Project is currently being upgraded, and secrets cannot be written. Please try again" + }); + } + const folder = await folderDAL.findBySecretPath(projectId, environment, path); if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Create secret" }); const folderId = folder.id; @@ -705,6 +740,14 @@ export const secretServiceFactory = ({ subject(ProjectPermissionSub.Secrets, { environment, secretPath: path }) ); + const isProjectBeingUpgraded = await projectDAL.isProjectBeingUpgraded(projectId); + + if (isProjectBeingUpgraded) { + throw new BadRequestError({ + message: "Project is currently being upgraded, and secrets cannot be written. Please try again" + }); + } + const folder = await folderDAL.findBySecretPath(projectId, environment, path); if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Create secret" }); const folderId = folder.id; @@ -776,6 +819,14 @@ export const secretServiceFactory = ({ subject(ProjectPermissionSub.Secrets, { environment, secretPath: path }) ); + const isProjectBeingUpgraded = await projectDAL.isProjectBeingUpgraded(projectId); + + if (isProjectBeingUpgraded) { + throw new BadRequestError({ + message: "Project is currently being upgraded, and secrets cannot be written. Please try again" + }); + } + const folder = await folderDAL.findBySecretPath(projectId, environment, path); if (!folder) throw new BadRequestError({ message: "Folder not found", name: "Create secret" }); const folderId = folder.id;