diff --git a/backend/src/controllers/v1/secretApprovalRequestsController.ts b/backend/src/controllers/v1/secretApprovalRequestsController.ts index 33e84c07e..c97c9eed4 100644 --- a/backend/src/controllers/v1/secretApprovalRequestsController.ts +++ b/backend/src/controllers/v1/secretApprovalRequestsController.ts @@ -9,6 +9,8 @@ import { BadRequestError, UnauthorizedRequestError } from "../../utils/errors"; import { ISecretApprovalPolicy, SecretApprovalPolicy } from "../../models/secretApprovalPolicy"; import { performSecretApprovalRequestMerge } from "../../services/SecretApprovalService"; import { Types } from "mongoose"; +import { EEAuditLogService } from "../../ee/services"; +import { EventType } from "../../ee/models"; export const getSecretApprovalRequests = async (req: Request, res: Response) => { const { @@ -31,6 +33,7 @@ export const getSecretApprovalRequests = async (req: Request, res: Response) => { $match: query }, + { $sort: { createdAt: -1 } }, { $lookup: { from: SecretApprovalPolicy.collection.name, @@ -234,5 +237,37 @@ export const updateSecretApprovalRequestStatus = async (req: Request, res: Respo { status, statusChangeBy: membership._id }, { new: true } ); + + if (status === "close") { + await EEAuditLogService.createAuditLog( + req.authData, + { + type: EventType.SECRET_APPROVAL_CLOSED, + metadata: { + closedBy: membership._id.toString(), + secretApprovalRequestId: id, + secretApprovalRequestSlug: secretApprovalRequest.slug + } + }, + { + workspaceId: secretApprovalRequest.workspace + } + ); + } else { + await EEAuditLogService.createAuditLog( + req.authData, + { + type: EventType.SECRET_APPROVAL_REOPENED, + metadata: { + reopenedBy: membership._id.toString(), + secretApprovalRequestId: id, + secretApprovalRequestSlug: secretApprovalRequest.slug + } + }, + { + workspaceId: secretApprovalRequest.workspace + } + ); + } return res.send({ approval: updatedRequest }); }; diff --git a/backend/src/controllers/v3/secretsController.ts b/backend/src/controllers/v3/secretsController.ts index dd3e19200..27379a12a 100644 --- a/backend/src/controllers/v3/secretsController.ts +++ b/backend/src/controllers/v3/secretsController.ts @@ -595,33 +595,37 @@ export const createSecret = async (req: Request, res: Response) => { secretAction: ProjectPermissionActions.Create }); - const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath); - if (secretApprovalPolicy && membership && type !== "personal") { - const secretApprovalRequest = await generateSecretApprovalRequest({ - workspaceId, - environment, - secretPath, - policy: secretApprovalPolicy, - commiterMembershipId: membership._id.toString(), - data: { - [CommitType.CREATE]: [ - { - secretName, - secretValueCiphertext, - secretValueIV, - secretValueTag, - secretCommentIV, - secretCommentTag, - secretCommentCiphertext, - skipMultilineEncoding, - secretKeyTag, - secretKeyCiphertext, - secretKeyIV - } - ] - } - }); - return res.send({ approval: secretApprovalRequest }); + + if (membership && type !== "personal") { + const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath); + if (secretApprovalPolicy) { + const secretApprovalRequest = await generateSecretApprovalRequest({ + workspaceId, + environment, + secretPath, + policy: secretApprovalPolicy, + commiterMembershipId: membership._id.toString(), + authData:req.authData, + data: { + [CommitType.CREATE]: [ + { + secretName, + secretValueCiphertext, + secretValueIV, + secretValueTag, + secretCommentIV, + secretCommentTag, + secretCommentCiphertext, + skipMultilineEncoding, + secretKeyTag, + secretKeyCiphertext, + secretKeyIV + } + ] + } + }); + return res.send({ approval: secretApprovalRequest }); + } } const secret = await SecretService.createSecret({ @@ -700,35 +704,38 @@ export const updateSecretByName = async (req: Request, res: Response) => { secretAction: ProjectPermissionActions.Edit }); - const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath); - if (secretApprovalPolicy && membership && type !== "personal") { - const secretApprovalRequest = await generateSecretApprovalRequest({ - workspaceId, - environment, - secretPath, - policy: secretApprovalPolicy, - commiterMembershipId: membership._id.toString(), - data: { - [CommitType.UPDATE]: [ - { - secretName, - newSecretName, - secretValueCiphertext, - secretValueIV, - secretValueTag, - tags, - secretCommentIV, - secretCommentTag, - secretCommentCiphertext, - skipMultilineEncoding, - secretKeyTag, - secretKeyCiphertext, - secretKeyIV - } - ] - } - }); - return res.send({ approval: secretApprovalRequest }); + if (membership && type !== "personal") { + const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath); + if (secretApprovalPolicy) { + const secretApprovalRequest = await generateSecretApprovalRequest({ + workspaceId, + environment, + secretPath, + policy: secretApprovalPolicy, + commiterMembershipId: membership._id.toString(), + authData: req.authData, + data: { + [CommitType.UPDATE]: [ + { + secretName, + newSecretName, + secretValueCiphertext, + secretValueIV, + secretValueTag, + tags, + secretCommentIV, + secretCommentTag, + secretCommentCiphertext, + skipMultilineEncoding, + secretKeyTag, + secretKeyCiphertext, + secretKeyIV + } + ] + } + }); + return res.send({ approval: secretApprovalRequest }); + } } const secret = await SecretService.updateSecret({ @@ -784,23 +791,26 @@ export const deleteSecretByName = async (req: Request, res: Response) => { secretAction: ProjectPermissionActions.Delete }); - const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath); - if (secretApprovalPolicy && membership && type !== "personal") { - const secretApprovalRequest = await generateSecretApprovalRequest({ - workspaceId, - environment, - secretPath, - policy: secretApprovalPolicy, - commiterMembershipId: membership._id.toString(), - data: { - [CommitType.DELETE]: [ - { - secretName - } - ] - } - }); - return res.send({ approval: secretApprovalRequest }); + if (membership && type !== "personal") { + const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath); + if (secretApprovalPolicy) { + const secretApprovalRequest = await generateSecretApprovalRequest({ + workspaceId, + environment, + secretPath, + authData: req.authData, + policy: secretApprovalPolicy, + commiterMembershipId: membership._id.toString(), + data: { + [CommitType.DELETE]: [ + { + secretName + } + ] + } + }); + return res.send({ approval: secretApprovalRequest }); + } } const { secret } = await SecretService.deleteSecret({ @@ -838,19 +848,22 @@ export const createSecretByNameBatch = async (req: Request, res: Response) => { secretAction: ProjectPermissionActions.Create }); - const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath); - if (secretApprovalPolicy && membership) { - const secretApprovalRequest = await generateSecretApprovalRequest({ - workspaceId, - environment, - secretPath, - policy: secretApprovalPolicy, - commiterMembershipId: membership._id.toString(), - data: { - [CommitType.CREATE]: secrets.filter(({ type }) => type === "shared") - } - }); - return res.send({ approval: secretApprovalRequest }); + if (membership) { + const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath); + if (secretApprovalPolicy) { + const secretApprovalRequest = await generateSecretApprovalRequest({ + workspaceId, + environment, + secretPath, + authData: req.authData, + policy: secretApprovalPolicy, + commiterMembershipId: membership._id.toString(), + data: { + [CommitType.CREATE]: secrets.filter(({ type }) => type === "shared") + } + }); + return res.send({ approval: secretApprovalRequest }); + } } const createdSecrets = await SecretService.createSecretBatch({ @@ -879,19 +892,22 @@ export const updateSecretByNameBatch = async (req: Request, res: Response) => { secretAction: ProjectPermissionActions.Edit }); - const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath); - if (secretApprovalPolicy && membership) { - const secretApprovalRequest = await generateSecretApprovalRequest({ - workspaceId, - environment, - secretPath, - policy: secretApprovalPolicy, - commiterMembershipId: membership._id.toString(), - data: { - [CommitType.UPDATE]: secrets.filter(({ type }) => type === "shared") - } - }); - return res.send({ approval: secretApprovalRequest }); + if (membership) { + const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath); + if (secretApprovalPolicy) { + const secretApprovalRequest = await generateSecretApprovalRequest({ + workspaceId, + environment, + secretPath, + policy: secretApprovalPolicy, + commiterMembershipId: membership._id.toString(), + data: { + [CommitType.UPDATE]: secrets.filter(({ type }) => type === "shared") + }, + authData: req.authData + }); + return res.send({ approval: secretApprovalRequest }); + } } const updatedSecrets = await SecretService.updateSecretBatch({ @@ -920,19 +936,23 @@ export const deleteSecretByNameBatch = async (req: Request, res: Response) => { secretAction: ProjectPermissionActions.Delete }); - const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath); - if (secretApprovalPolicy && membership) { - const secretApprovalRequest = await generateSecretApprovalRequest({ - workspaceId, - environment, - secretPath, - policy: secretApprovalPolicy, - commiterMembershipId: membership._id.toString(), - data: { - [CommitType.DELETE]: secrets.filter(({ type }) => type === "shared") - } - }); - return res.send({ approval: secretApprovalRequest }); + + if (membership) { + const secretApprovalPolicy = await getSecretPolicyOfBoard(workspaceId, environment, secretPath); + if (secretApprovalPolicy) { + const secretApprovalRequest = await generateSecretApprovalRequest({ + workspaceId, + environment, + secretPath, + policy: secretApprovalPolicy, + commiterMembershipId: membership._id.toString(), + data: { + [CommitType.DELETE]: secrets.filter(({ type }) => type === "shared") + }, + authData: req.authData + }); + return res.send({ approval: secretApprovalRequest }); + } } const deletedSecrets = await SecretService.deleteSecretBatch({ diff --git a/backend/src/ee/models/auditLog/enums.ts b/backend/src/ee/models/auditLog/enums.ts index 3111db0af..a7be37a65 100644 --- a/backend/src/ee/models/auditLog/enums.ts +++ b/backend/src/ee/models/auditLog/enums.ts @@ -12,43 +12,47 @@ export enum UserAgentType { } export enum EventType { - GET_SECRETS = "get-secrets", - GET_SECRET = "get-secret", - REVEAL_SECRET = "reveal-secret", - CREATE_SECRET = "create-secret", - CREATE_SECRETS = "create-secrets", - UPDATE_SECRET = "update-secret", - UPDATE_SECRETS = "update-secrets", - DELETE_SECRET = "delete-secret", - DELETE_SECRETS = "delete-secrets", - GET_WORKSPACE_KEY = "get-workspace-key", - AUTHORIZE_INTEGRATION = "authorize-integration", - UNAUTHORIZE_INTEGRATION = "unauthorize-integration", - CREATE_INTEGRATION = "create-integration", - DELETE_INTEGRATION = "delete-integration", - ADD_TRUSTED_IP = "add-trusted-ip", - UPDATE_TRUSTED_IP = "update-trusted-ip", - DELETE_TRUSTED_IP = "delete-trusted-ip", - CREATE_SERVICE_TOKEN = "create-service-token", // v2 - DELETE_SERVICE_TOKEN = "delete-service-token", // v2 - CREATE_SERVICE_TOKEN_V3 = "create-service-token-v3", // v3 - UPDATE_SERVICE_TOKEN_V3 = "update-service-token-v3", // v3 - DELETE_SERVICE_TOKEN_V3 = "delete-service-token-v3", // v3 - CREATE_ENVIRONMENT = "create-environment", - UPDATE_ENVIRONMENT = "update-environment", - DELETE_ENVIRONMENT = "delete-environment", - ADD_WORKSPACE_MEMBER = "add-workspace-member", - REMOVE_WORKSPACE_MEMBER = "remove-workspace-member", - CREATE_FOLDER = "create-folder", - UPDATE_FOLDER = "update-folder", - DELETE_FOLDER = "delete-folder", - CREATE_WEBHOOK = "create-webhook", - UPDATE_WEBHOOK_STATUS = "update-webhook-status", - DELETE_WEBHOOK = "delete-webhook", - GET_SECRET_IMPORTS = "get-secret-imports", - CREATE_SECRET_IMPORT = "create-secret-import", - UPDATE_SECRET_IMPORT = "update-secret-import", - DELETE_SECRET_IMPORT = "delete-secret-import", - UPDATE_USER_WORKSPACE_ROLE = "update-user-workspace-role", - UPDATE_USER_WORKSPACE_DENIED_PERMISSIONS = "update-user-workspace-denied-permissions" -} \ No newline at end of file + GET_SECRETS = "get-secrets", + GET_SECRET = "get-secret", + REVEAL_SECRET = "reveal-secret", + CREATE_SECRET = "create-secret", + CREATE_SECRETS = "create-secrets", + UPDATE_SECRET = "update-secret", + UPDATE_SECRETS = "update-secrets", + DELETE_SECRET = "delete-secret", + DELETE_SECRETS = "delete-secrets", + GET_WORKSPACE_KEY = "get-workspace-key", + AUTHORIZE_INTEGRATION = "authorize-integration", + UNAUTHORIZE_INTEGRATION = "unauthorize-integration", + CREATE_INTEGRATION = "create-integration", + DELETE_INTEGRATION = "delete-integration", + ADD_TRUSTED_IP = "add-trusted-ip", + UPDATE_TRUSTED_IP = "update-trusted-ip", + DELETE_TRUSTED_IP = "delete-trusted-ip", + CREATE_SERVICE_TOKEN = "create-service-token", // v2 + DELETE_SERVICE_TOKEN = "delete-service-token", // v2 + CREATE_SERVICE_TOKEN_V3 = "create-service-token-v3", // v3 + UPDATE_SERVICE_TOKEN_V3 = "update-service-token-v3", // v3 + DELETE_SERVICE_TOKEN_V3 = "delete-service-token-v3", // v3 + CREATE_ENVIRONMENT = "create-environment", + UPDATE_ENVIRONMENT = "update-environment", + DELETE_ENVIRONMENT = "delete-environment", + ADD_WORKSPACE_MEMBER = "add-workspace-member", + REMOVE_WORKSPACE_MEMBER = "remove-workspace-member", + CREATE_FOLDER = "create-folder", + UPDATE_FOLDER = "update-folder", + DELETE_FOLDER = "delete-folder", + CREATE_WEBHOOK = "create-webhook", + UPDATE_WEBHOOK_STATUS = "update-webhook-status", + DELETE_WEBHOOK = "delete-webhook", + GET_SECRET_IMPORTS = "get-secret-imports", + CREATE_SECRET_IMPORT = "create-secret-import", + UPDATE_SECRET_IMPORT = "update-secret-import", + DELETE_SECRET_IMPORT = "delete-secret-import", + UPDATE_USER_WORKSPACE_ROLE = "update-user-workspace-role", + UPDATE_USER_WORKSPACE_DENIED_PERMISSIONS = "update-user-workspace-denied-permissions", + SECRET_APPROVAL_MERGED = "secret-approval-merged", + SECRET_APPROVAL_REQUEST = "secret-approval-request", + SECRET_APPROVAL_CLOSED = "secret-approval-closed", + SECRET_APPROVAL_REOPENED = "secret-approval-reopened" +} diff --git a/backend/src/ee/models/auditLog/types.ts b/backend/src/ee/models/auditLog/types.ts index 2f9fdb41c..579a02ccb 100644 --- a/backend/src/ee/models/auditLog/types.ts +++ b/backend/src/ee/models/auditLog/types.ts @@ -437,43 +437,82 @@ interface UpdateUserDeniedPermissions { }[] } } +interface SecretApprovalMerge { + type: EventType.SECRET_APPROVAL_MERGED; + metadata: { + mergedBy: string; + secretApprovalRequestSlug: string; + secretApprovalRequestId: string; + }; +} -export type Event = - | GetSecretsEvent - | GetSecretEvent - | CreateSecretEvent - | CreateSecretBatchEvent - | UpdateSecretEvent - | UpdateSecretBatchEvent - | DeleteSecretEvent - | DeleteSecretBatchEvent - | GetWorkspaceKeyEvent - | AuthorizeIntegrationEvent - | UnauthorizeIntegrationEvent - | CreateIntegrationEvent - | DeleteIntegrationEvent - | AddTrustedIPEvent - | UpdateTrustedIPEvent - | DeleteTrustedIPEvent - | CreateServiceTokenEvent - | DeleteServiceTokenEvent - | CreateServiceTokenV3Event - | UpdateServiceTokenV3Event - | DeleteServiceTokenV3Event - | CreateEnvironmentEvent - | UpdateEnvironmentEvent - | DeleteEnvironmentEvent - | AddWorkspaceMemberEvent - | RemoveWorkspaceMemberEvent - | CreateFolderEvent - | UpdateFolderEvent - | DeleteFolderEvent - | CreateWebhookEvent - | UpdateWebhookStatusEvent - | DeleteWebhookEvent - | GetSecretImportsEvent - | CreateSecretImportEvent - | UpdateSecretImportEvent - | DeleteSecretImportEvent - | UpdateUserRole - | UpdateUserDeniedPermissions; \ No newline at end of file +interface SecretApprovalClosed { + type: EventType.SECRET_APPROVAL_CLOSED; + metadata: { + closedBy: string; + secretApprovalRequestSlug: string; + secretApprovalRequestId: string; + }; +} + +interface SecretApprovalReopened { + type: EventType.SECRET_APPROVAL_REOPENED; + metadata: { + reopenedBy: string; + secretApprovalRequestSlug: string; + secretApprovalRequestId: string; + }; +} + +interface SecretApprovalRequest { + type: EventType.SECRET_APPROVAL_REQUEST; + metadata: { + committedBy: string; + secretApprovalRequestSlug: string; + secretApprovalRequestId: string; + }; +} + +export type Event = + | GetSecretsEvent + | GetSecretEvent + | CreateSecretEvent + | CreateSecretBatchEvent + | UpdateSecretEvent + | UpdateSecretBatchEvent + | DeleteSecretEvent + | DeleteSecretBatchEvent + | GetWorkspaceKeyEvent + | AuthorizeIntegrationEvent + | UnauthorizeIntegrationEvent + | CreateIntegrationEvent + | DeleteIntegrationEvent + | AddTrustedIPEvent + | UpdateTrustedIPEvent + | DeleteTrustedIPEvent + | CreateServiceTokenEvent + | DeleteServiceTokenEvent + | CreateServiceTokenV3Event + | UpdateServiceTokenV3Event + | DeleteServiceTokenV3Event + | CreateEnvironmentEvent + | UpdateEnvironmentEvent + | DeleteEnvironmentEvent + | AddWorkspaceMemberEvent + | RemoveWorkspaceMemberEvent + | CreateFolderEvent + | UpdateFolderEvent + | DeleteFolderEvent + | CreateWebhookEvent + | UpdateWebhookStatusEvent + | DeleteWebhookEvent + | GetSecretImportsEvent + | CreateSecretImportEvent + | UpdateSecretImportEvent + | DeleteSecretImportEvent + | UpdateUserRole + | UpdateUserDeniedPermissions + | SecretApprovalMerge + | SecretApprovalClosed + | SecretApprovalRequest + | SecretApprovalReopened; diff --git a/backend/src/models/secretApprovalRequest.ts b/backend/src/models/secretApprovalRequest.ts index d05d120f5..c3503e5dd 100644 --- a/backend/src/models/secretApprovalRequest.ts +++ b/backend/src/models/secretApprovalRequest.ts @@ -1,4 +1,5 @@ import { Schema, Types, model } from "mongoose"; +import { customAlphabet } from "nanoid"; import { ALGORITHM_AES_256_GCM, ENCODING_SCHEME_BASE64, ENCODING_SCHEME_UTF8 } from "../variables"; export enum ApprovalStatus { @@ -13,6 +14,9 @@ export enum CommitType { CREATE = "create" } +const SLUG_ALPHABETS = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +const nanoId = customAlphabet(SLUG_ALPHABETS, 10); + export interface ISecretApprovalSecChange { _id: Types.ObjectId; version: number; @@ -54,6 +58,7 @@ export type ISecretCommits = Array< export interface ISecretApprovalRequest { _id: Types.ObjectId; committer: Types.ObjectId; + slug: string; statusChangeBy: Types.ObjectId; reviewers: { member: Types.ObjectId; @@ -143,6 +148,10 @@ const secretApprovalRequestSchema = new Schema( required: true, default: "root" }, + slug: { + type: String, + default: () => nanoId() + }, reviewers: { type: [ { diff --git a/backend/src/services/SecretApprovalService.ts b/backend/src/services/SecretApprovalService.ts index ca38e3279..a9a42688f 100644 --- a/backend/src/services/SecretApprovalService.ts +++ b/backend/src/services/SecretApprovalService.ts @@ -96,6 +96,7 @@ type TGenerateSecretApprovalRequestArg = { [CommitType.DELETE]?: { secretName: string }[]; }; commiterMembershipId: string; + authData: AuthData; }; export const generateSecretApprovalRequest = async ({ @@ -104,7 +105,8 @@ export const generateSecretApprovalRequest = async ({ secretPath, policy, data, - commiterMembershipId + commiterMembershipId, + authData }: TGenerateSecretApprovalRequestArg) => { // calculate folder id from secret path let folderId = "root"; @@ -313,6 +315,22 @@ export const generateSecretApprovalRequest = async ({ committer: commiterMembershipId }); await secretApprovalRequest.save(); + + await EEAuditLogService.createAuditLog( + authData, + { + type: EventType.SECRET_APPROVAL_REQUEST, + metadata: { + committedBy: commiterMembershipId, + secretApprovalRequestId: secretApprovalRequest._id.toString(), + secretApprovalRequestSlug: secretApprovalRequest.slug + } + }, + { + workspaceId: secretApprovalRequest.workspace + } + ); + return secretApprovalRequest; }; @@ -436,26 +454,6 @@ export const performSecretApprovalRequestMerge = async ( }) ) }); - - // question to team where to keep secretKey - await EEAuditLogService.createAuditLog( - authData, - { - type: EventType.CREATE_SECRETS, - metadata: { - environment, - secretPath: "/", - secrets: newlyCreatedSecrets.map(({ version, _id }) => ({ - secretId: _id.toString(), - secretKey: "", - secretVersion: version - })) - } - }, - { - workspaceId - } - ); } const secretUpdationCommits = secretApprovalRequest.commits.filter( @@ -570,25 +568,6 @@ export const performSecretApprovalRequestMerge = async ( }); }) }); - - await EEAuditLogService.createAuditLog( - authData, - { - type: EventType.UPDATE_SECRETS, - metadata: { - environment, - secretPath: "/", - secrets: nonConflictSecrets.map(({ secret }) => ({ - secretId: secret._id.toString(), - secretKey: "", - secretVersion: secret.version + 1 - })) - } - }, - { - workspaceId - } - ); } const secretDeletionCommits = secretApprovalRequest.commits.filter( @@ -614,25 +593,6 @@ export const performSecretApprovalRequestMerge = async ( await EESecretService.markDeletedSecretVersions({ secretIds: secretDeletionCommits.map(({ secret }) => secret._id) }); - - await EEAuditLogService.createAuditLog( - authData, - { - type: EventType.DELETE_SECRETS, - metadata: { - environment, - secretPath: "/", - secrets: secretDeletionCommits.map(({ secret: { _id, version } }) => ({ - secretId: _id.toString(), - secretKey: "", - secretVersion: version - })) - } - }, - { - workspaceId - } - ); } const updatedSecretApproval = await SecretApprovalRequest.findByIdAndUpdate( @@ -671,5 +631,21 @@ export const performSecretApprovalRequestMerge = async ( folderId }); + // question to team where to keep secretKey + await EEAuditLogService.createAuditLog( + authData, + { + type: EventType.SECRET_APPROVAL_MERGED, + metadata: { + mergedBy: userMembershipId, + secretApprovalRequestId: id, + secretApprovalRequestSlug: secretApprovalRequest.slug + } + }, + { + workspaceId + } + ); + return updatedSecretApproval; }; diff --git a/frontend/src/hooks/api/secretApprovalRequest/types.ts b/frontend/src/hooks/api/secretApprovalRequest/types.ts index 12f2ce81f..c6ddfbb7c 100644 --- a/frontend/src/hooks/api/secretApprovalRequest/types.ts +++ b/frontend/src/hooks/api/secretApprovalRequest/types.ts @@ -47,6 +47,7 @@ export type TSecretApprovalRequest< J extends unknown = EncryptedSecret > = { _id: string; + slug: string; createdAt: string; committer: string; reviewers: { diff --git a/frontend/src/hooks/api/subscriptions/types.ts b/frontend/src/hooks/api/subscriptions/types.ts index 3fcdbb339..c61967eec 100644 --- a/frontend/src/hooks/api/subscriptions/types.ts +++ b/frontend/src/hooks/api/subscriptions/types.ts @@ -11,12 +11,21 @@ export type SubscriptionPlan = { rbac: boolean; secretVersioning: boolean; slug: string; + secretApproval: string; tier: number; workspaceLimit: number; workspacesUsed: number; environmentLimit: number; samlSSO: boolean; - status: "incomplete" | "incomplete_expired" | "trialing" | "active" | "past_due" | "canceled" | "unpaid" | null; + status: + | "incomplete" + | "incomplete_expired" + | "trialing" + | "active" + | "past_due" + | "canceled" + | "unpaid" + | null; trial_end: number | null; has_used_trial: boolean; }; diff --git a/frontend/src/views/SecretApprovalPage/components/SecretApprovalPolicyList/SecretApprovalPolicyList.tsx b/frontend/src/views/SecretApprovalPage/components/SecretApprovalPolicyList/SecretApprovalPolicyList.tsx index a15199d5e..76633aa28 100644 --- a/frontend/src/views/SecretApprovalPage/components/SecretApprovalPolicyList/SecretApprovalPolicyList.tsx +++ b/frontend/src/views/SecretApprovalPage/components/SecretApprovalPolicyList/SecretApprovalPolicyList.tsx @@ -14,9 +14,15 @@ import { Td, Th, THead, - Tr + Tr, + UpgradePlanModal } from "@app/components/v2"; -import { ProjectPermissionActions, ProjectPermissionSub, useProjectPermission } from "@app/context"; +import { + ProjectPermissionActions, + ProjectPermissionSub, + useProjectPermission, + useSubscription +} from "@app/context"; import { usePopUp } from "@app/hooks"; import { useDeleteSecretApprovalPolicy, @@ -35,9 +41,11 @@ type Props = { export const SecretApprovalPolicyList = ({ workspaceId }: Props) => { const { handlePopUpToggle, handlePopUpOpen, handlePopUpClose, popUp } = usePopUp([ "secretPolicyForm", - "deletePolicy" + "deletePolicy", + "upgradePlan" ] as const); const permission = useProjectPermission(); + const { subscription } = useSubscription(); const { createNotification } = useNotificationContext(); const { data: members } = useGetWorkspaceUsers(workspaceId); @@ -87,7 +95,13 @@ export const SecretApprovalPolicyList = ({ workspaceId }: Props) => { > {(isAllowed) => (