diff --git a/backend/src/controllers/v1/index.ts b/backend/src/controllers/v1/index.ts index 9dcbb12c2..c2bb1b94d 100644 --- a/backend/src/controllers/v1/index.ts +++ b/backend/src/controllers/v1/index.ts @@ -16,7 +16,7 @@ import * as workspaceController from "./workspaceController"; import * as secretScanningController from "./secretScanningController"; import * as webhookController from "./webhookController"; import * as secretImpsController from "./secretImpsController"; -import * as secretApprovalController from "./secretApprovalController"; +import * as secretApprovalPolicyController from "./secretApprovalPolicyController"; export { authController, @@ -37,5 +37,5 @@ export { secretScanningController, webhookController, secretImpsController, - secretApprovalController + secretApprovalPolicyController }; diff --git a/backend/src/controllers/v1/secretApprovalController.ts b/backend/src/controllers/v1/secretApprovalPolicyController.ts similarity index 73% rename from backend/src/controllers/v1/secretApprovalController.ts rename to backend/src/controllers/v1/secretApprovalPolicyController.ts index 8441a93b0..245932353 100644 --- a/backend/src/controllers/v1/secretApprovalController.ts +++ b/backend/src/controllers/v1/secretApprovalPolicyController.ts @@ -6,13 +6,13 @@ import { getUserProjectPermissions } from "../../ee/services/ProjectRoleService"; import { validateRequest } from "../../helpers/validation"; -import { SecretApproval } from "../../models/secretApproval"; +import { SecretApprovalPolicy } from "../../models/secretApprovalPolicy"; import { BadRequestError } from "../../utils/errors"; import * as reqValidator from "../../validation/secretApproval"; const ERR_SECRET_APPROVAL_NOT_FOUND = BadRequestError({ message: "secret approval not found" }); -export const createSecretApprovalRule = async (req: Request, res: Response) => { +export const createSecretApprovalPolicy = async (req: Request, res: Response) => { const { body: { approvals, secretPath, approvers, environment, workspaceId } } = await validateRequest(reqValidator.CreateSecretApprovalRule, req); @@ -23,7 +23,7 @@ export const createSecretApprovalRule = async (req: Request, res: Response) => { ProjectPermissionSub.SecretApproval ); - const secretApproval = new SecretApproval({ + const secretApproval = new SecretApprovalPolicy({ workspace: workspaceId, secretPath, environment, @@ -37,13 +37,13 @@ export const createSecretApprovalRule = async (req: Request, res: Response) => { }); }; -export const updateSecretApprovalRule = async (req: Request, res: Response) => { +export const updateSecretApprovalPolicy = async (req: Request, res: Response) => { const { body: { approvals, approvers, secretPath }, params: { id } } = await validateRequest(reqValidator.UpdateSecretApprovalRule, req); - const secretApproval = await SecretApproval.findById(id); + const secretApproval = await SecretApprovalPolicy.findById(id); if (!secretApproval) throw ERR_SECRET_APPROVAL_NOT_FOUND; const { permission } = await getUserProjectPermissions( @@ -55,10 +55,10 @@ export const updateSecretApprovalRule = async (req: Request, res: Response) => { ProjectPermissionSub.SecretApproval ); - const updatedDoc = await SecretApproval.findByIdAndUpdate(id, { + const updatedDoc = await SecretApprovalPolicy.findByIdAndUpdate(id, { approvals, approvers, - $set: secretPath === "-" ? undefined : { secretPath } + ...(secretPath === null ? { $unset: { secretPath: 1 } } : { secretPath }) }); return res.send({ @@ -66,12 +66,12 @@ export const updateSecretApprovalRule = async (req: Request, res: Response) => { }); }; -export const deleteSecretApprovalRule = async (req: Request, res: Response) => { +export const deleteSecretApprovalPolicy = async (req: Request, res: Response) => { const { params: { id } } = await validateRequest(reqValidator.DeleteSecretApprovalRule, req); - const secretApproval = await SecretApproval.findById(id); + const secretApproval = await SecretApprovalPolicy.findById(id); if (!secretApproval) throw ERR_SECRET_APPROVAL_NOT_FOUND; const { permission } = await getUserProjectPermissions( @@ -83,14 +83,14 @@ export const deleteSecretApprovalRule = async (req: Request, res: Response) => { ProjectPermissionSub.SecretApproval ); - const deletedDoc = await SecretApproval.findByIdAndDelete(id); + const deletedDoc = await SecretApprovalPolicy.findByIdAndDelete(id); return res.send({ approval: deletedDoc }); }; -export const getSecretApprovalRules = async (req: Request, res: Response) => { +export const getSecretApprovalPolicy = async (req: Request, res: Response) => { const { query: { workspaceId } } = await validateRequest(reqValidator.GetSecretApprovalRuleList, req); @@ -101,7 +101,7 @@ export const getSecretApprovalRules = async (req: Request, res: Response) => { ProjectPermissionSub.SecretApproval ); - const doc = await SecretApproval.find({ workspace: workspaceId }); + const doc = await SecretApprovalPolicy.find({ workspace: workspaceId }); return res.send({ approvals: doc diff --git a/backend/src/index.ts b/backend/src/index.ts index c3aed4b7b..2a5159738 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -38,7 +38,7 @@ import { membership as v1MembershipRouter, organization as v1OrganizationRouter, password as v1PasswordRouter, - secretApproval as v1SecretApproval, + secretApprovalPolicy as v1SecretApprovalPolicy, secretImps as v1SecretImpsRouter, secret as v1SecretRouter, secretsFolder as v1SecretsFolder, @@ -177,7 +177,7 @@ const main = async () => { app.use("/api/v1/webhooks", v1WebhooksRouter); app.use("/api/v1/secret-imports", v1SecretImpsRouter); app.use("/api/v1/roles", v1RoleRouter); - app.use("/api/v1/secret-approvals", v1SecretApproval); + app.use("/api/v1/secret-approvals", v1SecretApprovalPolicy); // v2 routes (improvements) app.use("/api/v2/signup", v2SignupRouter); diff --git a/backend/src/models/secretApproval.ts b/backend/src/models/secretApprovalPolicy.ts similarity index 74% rename from backend/src/models/secretApproval.ts rename to backend/src/models/secretApprovalPolicy.ts index f4e2fc92e..9471f82db 100644 --- a/backend/src/models/secretApproval.ts +++ b/backend/src/models/secretApprovalPolicy.ts @@ -1,6 +1,6 @@ import { Schema, Types, model } from "mongoose"; -export interface ISecretApproval { +export interface ISecretApprovalPolicy { _id: Types.ObjectId; workspace: Types.ObjectId; environment: string; @@ -9,7 +9,7 @@ export interface ISecretApproval { approvals: number; } -const secretApprovalSchema = new Schema( +const secretApprovalPolicySchema = new Schema( { workspace: { type: Schema.Types.ObjectId, @@ -41,4 +41,7 @@ const secretApprovalSchema = new Schema( } ); -export const SecretApproval = model("SecretApproval", secretApprovalSchema); +export const SecretApprovalPolicy = model( + "SecretApprovalPolicy", + secretApprovalPolicySchema +); diff --git a/backend/src/models/secretApprovalRequest.ts b/backend/src/models/secretApprovalRequest.ts index 4133f06a7..a145b5773 100644 --- a/backend/src/models/secretApprovalRequest.ts +++ b/backend/src/models/secretApprovalRequest.ts @@ -30,7 +30,7 @@ export interface ISecretApprovalRequest { }[]; } -const secretApprovalSchema = new Schema( +const secretApprovalRequestSchema = new Schema( { approvers: [ { @@ -62,4 +62,7 @@ const secretApprovalSchema = new Schema( } ); -export const SecretApproval = model("SecretApproval", secretApprovalSchema); +export const SecretApprovalRequest = model( + "SecretApprovalRequest", + secretApprovalRequestSchema +); diff --git a/backend/src/routes/v1/index.ts b/backend/src/routes/v1/index.ts index 7c0f94972..cfdccdc92 100644 --- a/backend/src/routes/v1/index.ts +++ b/backend/src/routes/v1/index.ts @@ -17,7 +17,7 @@ import integrationAuth from "./integrationAuth"; import secretsFolder from "./secretsFolder"; import webhooks from "./webhook"; import secretImps from "./secretImps"; -import secretApproval from "./secretApproval"; +import secretApprovalPolicy from "./secretApprovalPolicy"; export { signup, @@ -39,5 +39,5 @@ export { secretsFolder, webhooks, secretImps, - secretApproval + secretApprovalPolicy }; diff --git a/backend/src/routes/v1/secretApproval.ts b/backend/src/routes/v1/secretApprovalPolicy.ts similarity index 62% rename from backend/src/routes/v1/secretApproval.ts rename to backend/src/routes/v1/secretApprovalPolicy.ts index 213bb3cc3..51c2aa3e7 100644 --- a/backend/src/routes/v1/secretApproval.ts +++ b/backend/src/routes/v1/secretApprovalPolicy.ts @@ -1,7 +1,7 @@ import express from "express"; const router = express.Router(); import { requireAuth } from "../../middleware"; -import { secretApprovalController } from "../../controllers/v1"; +import { secretApprovalPolicyController } from "../../controllers/v1"; import { AuthMode } from "../../variables"; router.get( @@ -9,7 +9,7 @@ router.get( requireAuth({ acceptedAuthModes: [AuthMode.JWT] }), - secretApprovalController.getSecretApprovalRules + secretApprovalPolicyController.getSecretApprovalPolicy ); router.post( @@ -17,7 +17,7 @@ router.post( requireAuth({ acceptedAuthModes: [AuthMode.JWT] }), - secretApprovalController.createSecretApprovalRule + secretApprovalPolicyController.createSecretApprovalPolicy ); router.patch( @@ -25,7 +25,7 @@ router.patch( requireAuth({ acceptedAuthModes: [AuthMode.JWT] }), - secretApprovalController.updateSecretApprovalRule + secretApprovalPolicyController.updateSecretApprovalPolicy ); router.delete( @@ -33,7 +33,7 @@ router.delete( requireAuth({ acceptedAuthModes: [AuthMode.JWT] }), - secretApprovalController.deleteSecretApprovalRule + secretApprovalPolicyController.deleteSecretApprovalPolicy ); export default router; diff --git a/backend/src/validation/secretApproval.ts b/backend/src/validation/secretApproval.ts index a25da81b2..9d4b10ce5 100644 --- a/backend/src/validation/secretApproval.ts +++ b/backend/src/validation/secretApproval.ts @@ -10,7 +10,7 @@ export const CreateSecretApprovalRule = z.object({ body: z.object({ workspaceId: z.string(), environment: z.string(), - secretPath: z.string().optional(), + secretPath: z.string().optional().nullable(), approvers: z.string().array().optional(), approvals: z.number().min(1).default(1) }) @@ -23,7 +23,7 @@ export const UpdateSecretApprovalRule = z.object({ body: z.object({ approvers: z.string().array().optional(), approvals: z.number().min(1).optional(), - secretPath: z.string().optional() + secretPath: z.string().optional().nullable() }) }); diff --git a/frontend/src/hooks/api/secretApproval/types.ts b/frontend/src/hooks/api/secretApproval/types.ts index b77fc1a91..8eb486664 100644 --- a/frontend/src/hooks/api/secretApproval/types.ts +++ b/frontend/src/hooks/api/secretApproval/types.ts @@ -10,7 +10,7 @@ export type TSecretApprovalPolicy = { export type TCreateSecretPolicyDTO = { workspaceId: string; environment: string; - secretPath?: string; + secretPath?: string | null; approvers?: string[]; approvals?: number; }; @@ -18,7 +18,7 @@ export type TCreateSecretPolicyDTO = { export type TUpdateSecretPolicyDTO = { id: string; approvers?: string[]; - secretPath?: string; + secretPath?: string | null; approvals?: number; // for invalidating list workspaceId: string; diff --git a/frontend/src/views/SecretApprovalPage/components/SecretApprovalPolicyList/SecretApprovalPolicyList.tsx b/frontend/src/views/SecretApprovalPage/components/SecretApprovalPolicyList/SecretApprovalPolicyList.tsx index dcc27e49f..700b1a785 100644 --- a/frontend/src/views/SecretApprovalPage/components/SecretApprovalPolicyList/SecretApprovalPolicyList.tsx +++ b/frontend/src/views/SecretApprovalPage/components/SecretApprovalPolicyList/SecretApprovalPolicyList.tsx @@ -1,14 +1,16 @@ -import { faPlus } from "@fortawesome/free-solid-svg-icons"; +import { faFileShield, faPlus } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider"; import { Button, DeleteActionModal, + EmptyState, Table, TableContainer, TableSkeleton, TBody, + Td, Th, THead, Tr @@ -96,6 +98,11 @@ export const SecretApprovalPolicyList = ({ workspaceId }: Props) => { {isPoliciesLoading && ( )} + {!isPoliciesLoading && !policies?.length && ( + + + + )} {policies?.map((policy) => ( ( - + )} /> @@ -220,7 +220,11 @@ export const SecretPolicyForm = ({ isError={Boolean(error)} errorText={error?.message} > - + field.onChange(parseInt(el.target.value, 10))} + /> )} />