From 9cda85f03ed44c4f29a677782f59df6f9eb05467 Mon Sep 17 00:00:00 2001 From: Akhil Mohan Date: Mon, 4 Sep 2023 15:05:54 +0530 Subject: [PATCH] checkpoint --- backend/src/models/secretApproval.ts | 44 ++++++ backend/src/models/secretApprovalRequest.ts | 128 ++++++++---------- frontend/public/locales/en/translations.json | 5 + frontend/src/layouts/AppLayout/AppLayout.tsx | 12 ++ .../src/pages/project/[id]/approval/index.tsx | 27 ++++ .../SecretApprovalListPage.tsx | 73 ++++++++++ .../SecretApprovalListPage/index.tsx | 1 + 7 files changed, 218 insertions(+), 72 deletions(-) create mode 100644 backend/src/models/secretApproval.ts create mode 100644 frontend/src/pages/project/[id]/approval/index.tsx create mode 100644 frontend/src/views/SecretApproval/SecretApprovalListPage/SecretApprovalListPage.tsx create mode 100644 frontend/src/views/SecretApproval/SecretApprovalListPage/index.tsx diff --git a/backend/src/models/secretApproval.ts b/backend/src/models/secretApproval.ts new file mode 100644 index 000000000..f4e2fc92e --- /dev/null +++ b/backend/src/models/secretApproval.ts @@ -0,0 +1,44 @@ +import { Schema, Types, model } from "mongoose"; + +export interface ISecretApproval { + _id: Types.ObjectId; + workspace: Types.ObjectId; + environment: string; + secretPath?: string; + approvers: Types.ObjectId[]; + approvals: number; +} + +const secretApprovalSchema = new Schema( + { + workspace: { + type: Schema.Types.ObjectId, + ref: "Workspace", + required: true + }, + approvers: [ + { + // user associated with the personal secret + type: Schema.Types.ObjectId, + ref: "Membership" + } + ], + environment: { + type: String, + required: true + }, + secretPath: { + type: String, + required: false + }, + approvals: { + type: Number, + default: 1 + } + }, + { + timestamps: true + } +); + +export const SecretApproval = model("SecretApproval", secretApprovalSchema); diff --git a/backend/src/models/secretApprovalRequest.ts b/backend/src/models/secretApprovalRequest.ts index 910ca9135..4133f06a7 100644 --- a/backend/src/models/secretApprovalRequest.ts +++ b/backend/src/models/secretApprovalRequest.ts @@ -1,81 +1,65 @@ -import mongoose, { Schema, model } from "mongoose"; -import { ISecret, Secret } from "./secret"; +import { Schema, Types, model } from "mongoose"; +import { ISecretVersion, SecretVersion } from "../ee/models/secretVersion"; -interface ISecretApprovalRequest { - secret: mongoose.Types.ObjectId; - requestedChanges: ISecret; - requestedBy: mongoose.Types.ObjectId; - approvers: IApprover[]; - status: ApprovalStatus; - timestamp: Date; - requestType: RequestType; - requestId: string; +enum ApprovalStatus { + PENDING = "pending", + APPROVED = "approved", + REJECTED = "rejected" } -interface IApprover { - userId: mongoose.Types.ObjectId; - status: ApprovalStatus; +enum CommitType { + DELETE = "delete", + UPDATE = "update", + CREATE = "create" } -export enum ApprovalStatus { - PENDING = "pending", - APPROVED = "approved", - REJECTED = "rejected" +export interface ISecretApprovalRequest { + _id: Types.ObjectId; + committer: Types.ObjectId; + approvers: { + member: Types.ObjectId; + status: ApprovalStatus; + }[]; + approvals: number; + hasMerged: boolean; + status: ApprovalStatus; + commits: { + secretVersion: Types.ObjectId; + newVersion: ISecretVersion; + op: CommitType; + }[]; } -export enum RequestType { - UPDATE = "update", - DELETE = "delete", - CREATE = "create" -} - -const approverSchema = new mongoose.Schema({ - user: { - type: mongoose.Schema.Types.ObjectId, - ref: "User", - required: true, - }, - status: { - type: String, - enum: [ApprovalStatus], - default: ApprovalStatus.PENDING, - }, -}); - -const secretApprovalRequestSchema = new Schema( - { - secret: { - type: mongoose.Schema.Types.ObjectId, - ref: "Secret", - }, - requestedChanges: Secret, - requestedBy: { - type: mongoose.Schema.Types.ObjectId, - ref: "User", - }, - approvers: [approverSchema], - status: { - type: String, - enum: ApprovalStatus, - default: ApprovalStatus.PENDING, - }, - timestamp: { - type: Date, - default: Date.now, - }, - requestType: { - type: String, - enum: RequestType, - required: true, - }, - requestId: { - type: String, - required: false, - }, - }, - { - timestamps: true, - } +const secretApprovalSchema = new Schema( + { + approvers: [ + { + member: { + // user associated with the personal secret + type: Schema.Types.ObjectId, + ref: "Membership" + }, + status: { type: String, enum: ApprovalStatus, default: ApprovalStatus.PENDING } + } + ], + approvals: { + type: Number, + required: true + }, + hasMerged: { type: Boolean, default: false }, + status: { type: String, enum: ApprovalStatus, default: ApprovalStatus.PENDING }, + committer: { type: Schema.Types.ObjectId, ref: "Membership" }, + commits: [ + { + secretVersion: { type: Types.ObjectId, ref: "SecretVersion" }, + newVersion: SecretVersion, + op: { type: String, enum: [CommitType], required: true } + } + ] + }, + { + timestamps: true + } ); -export const SecretApprovalRequest = model("SecretApprovalRequest", secretApprovalRequestSchema); \ No newline at end of file +export const SecretApproval = model("SecretApproval", secretApprovalSchema); diff --git a/frontend/public/locales/en/translations.json b/frontend/public/locales/en/translations.json index f989f2f3a..9900176e1 100644 --- a/frontend/public/locales/en/translations.json +++ b/frontend/public/locales/en/translations.json @@ -107,6 +107,11 @@ } } }, + "approval": { + "title": "Admin Panel", + "og-title": "Manage your secret change management", + "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files." + }, "integrations": { "title": "Project Integrations", "description": "Manage your integrations of Infisical with third-party services.", diff --git a/frontend/src/layouts/AppLayout/AppLayout.tsx b/frontend/src/layouts/AppLayout/AppLayout.tsx index 05f266f49..d8c522110 100644 --- a/frontend/src/layouts/AppLayout/AppLayout.tsx +++ b/frontend/src/layouts/AppLayout/AppLayout.tsx @@ -475,6 +475,18 @@ export const AppLayout = ({ children }: LayoutProps) => { + + + + Secret Change Management + + + { + const { t } = useTranslation(); + + return ( + <> + + {t("common.head-title", { title: t("approval.title") })} + + + + + +
+ +
+ + ); +}; + +export default SecretApproval; + +SecretApproval.requireAuth = true; diff --git a/frontend/src/views/SecretApproval/SecretApprovalListPage/SecretApprovalListPage.tsx b/frontend/src/views/SecretApproval/SecretApprovalListPage/SecretApprovalListPage.tsx new file mode 100644 index 000000000..3264382fb --- /dev/null +++ b/frontend/src/views/SecretApproval/SecretApprovalListPage/SecretApprovalListPage.tsx @@ -0,0 +1,73 @@ +import { faCheck, faCodeBranch, faXmark } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; + +import { Button, Table, TableContainer, TBody, Td, Th, THead, Tr } from "@app/components/v2"; + +export const SecretApprovalListPage = () => { + return ( +
+
+

Admin Panels

+
+
+
+
+ + 27 Open +
+
+ + 27 Closed +
+
+
+
+
+ 2 secrets added and 1 deleted +
+ + Opened 2 hours ago by akhilmhdh - Review required + +
+
+
+
+
+ Request for secret change +
+
+ + + + + + + + + + + + + + + + + + +
SecretValueCommentTags
TWILIO_SECRET_TOKENvalueSome values-
+
+
+
+ + +
+
+
+ ); +}; diff --git a/frontend/src/views/SecretApproval/SecretApprovalListPage/index.tsx b/frontend/src/views/SecretApproval/SecretApprovalListPage/index.tsx new file mode 100644 index 000000000..71d0f7cf3 --- /dev/null +++ b/frontend/src/views/SecretApproval/SecretApprovalListPage/index.tsx @@ -0,0 +1 @@ +export { SecretApprovalListPage } from "./SecretApprovalListPage";