From 230b44fca1a0e856dd204ab3716ef50d9609d096 Mon Sep 17 00:00:00 2001
From: carlosmonastyrski
Date: Thu, 10 Apr 2025 20:10:38 -0300
Subject: [PATCH] Add access request note and change secret request to change
request
---
...410203010_add-comment-to-access-request.ts | 21 +++++++++++++++++++
.../db/schemas/access-approval-requests.ts | 3 ++-
.../v1/access-approval-request-router.ts | 6 ++++--
.../access-approval-request-service.ts | 12 +++++++----
.../access-approval-request-types.ts | 1 +
backend/src/services/slack/slack-fns.ts | 7 ++++++-
backend/src/services/slack/slack-types.ts | 1 +
.../accessApprovalRequest.handlebars | 3 +++
.../src/hooks/api/accessApproval/types.ts | 3 +++
.../SpecificPrivilegeSection.tsx | 18 ++++++++++++++--
.../SecretApprovalsPage.tsx | 2 +-
.../components/ReviewAccessModal.tsx | 7 +++++++
12 files changed, 73 insertions(+), 11 deletions(-)
create mode 100644 backend/src/db/migrations/20250410203010_add-comment-to-access-request.ts
diff --git a/backend/src/db/migrations/20250410203010_add-comment-to-access-request.ts b/backend/src/db/migrations/20250410203010_add-comment-to-access-request.ts
new file mode 100644
index 000000000..0e0b46fd8
--- /dev/null
+++ b/backend/src/db/migrations/20250410203010_add-comment-to-access-request.ts
@@ -0,0 +1,21 @@
+import { Knex } from "knex";
+
+import { TableName } from "../schemas";
+
+export async function up(knex: Knex): Promise {
+ const hasCol = await knex.schema.hasColumn(TableName.AccessApprovalRequest, "note");
+ if (!hasCol) {
+ await knex.schema.alterTable(TableName.AccessApprovalRequest, (t) => {
+ t.string("note").nullable();
+ });
+ }
+}
+
+export async function down(knex: Knex): Promise {
+ const hasCol = await knex.schema.hasColumn(TableName.AccessApprovalRequest, "note");
+ if (hasCol) {
+ await knex.schema.alterTable(TableName.AccessApprovalRequest, (t) => {
+ t.dropColumn("note");
+ });
+ }
+}
diff --git a/backend/src/db/schemas/access-approval-requests.ts b/backend/src/db/schemas/access-approval-requests.ts
index 0b20202f5..bfe990b3a 100644
--- a/backend/src/db/schemas/access-approval-requests.ts
+++ b/backend/src/db/schemas/access-approval-requests.ts
@@ -17,7 +17,8 @@ export const AccessApprovalRequestsSchema = z.object({
permissions: z.unknown(),
createdAt: z.date(),
updatedAt: z.date(),
- requestedByUserId: z.string().uuid()
+ requestedByUserId: z.string().uuid(),
+ note: z.string().nullable().optional()
});
export type TAccessApprovalRequests = z.infer;
diff --git a/backend/src/ee/routes/v1/access-approval-request-router.ts b/backend/src/ee/routes/v1/access-approval-request-router.ts
index 6a6ec3c07..f735b4363 100644
--- a/backend/src/ee/routes/v1/access-approval-request-router.ts
+++ b/backend/src/ee/routes/v1/access-approval-request-router.ts
@@ -22,7 +22,8 @@ export const registerAccessApprovalRequestRouter = async (server: FastifyZodProv
body: z.object({
permissions: z.any().array(),
isTemporary: z.boolean(),
- temporaryRange: z.string().optional()
+ temporaryRange: z.string().optional(),
+ note: z.string().optional()
}),
querystring: z.object({
projectSlug: z.string().trim()
@@ -43,7 +44,8 @@ export const registerAccessApprovalRequestRouter = async (server: FastifyZodProv
actorOrgId: req.permission.orgId,
projectSlug: req.query.projectSlug,
temporaryRange: req.body.temporaryRange,
- isTemporary: req.body.isTemporary
+ isTemporary: req.body.isTemporary,
+ note: req.body.note
});
return { approval: request };
}
diff --git a/backend/src/ee/services/access-approval-request/access-approval-request-service.ts b/backend/src/ee/services/access-approval-request/access-approval-request-service.ts
index 50670cb49..3606b4bdc 100644
--- a/backend/src/ee/services/access-approval-request/access-approval-request-service.ts
+++ b/backend/src/ee/services/access-approval-request/access-approval-request-service.ts
@@ -94,7 +94,8 @@ export const accessApprovalRequestServiceFactory = ({
actor,
actorOrgId,
actorAuthMethod,
- projectSlug
+ projectSlug,
+ note
}: TCreateAccessApprovalRequestDTO) => {
const cfg = getConfig();
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
@@ -209,7 +210,8 @@ export const accessApprovalRequestServiceFactory = ({
requestedByUserId: actorId,
temporaryRange: temporaryRange || null,
permissions: JSON.stringify(requestedPermissions),
- isTemporary
+ isTemporary,
+ note: note || null
},
tx
);
@@ -232,7 +234,8 @@ export const accessApprovalRequestServiceFactory = ({
secretPath,
environment: envSlug,
permissions: accessTypes,
- approvalUrl
+ approvalUrl,
+ note
}
}
});
@@ -252,7 +255,8 @@ export const accessApprovalRequestServiceFactory = ({
secretPath,
environment: envSlug,
permissions: accessTypes,
- approvalUrl
+ approvalUrl,
+ note
},
template: SmtpTemplates.AccessApprovalRequest
});
diff --git a/backend/src/ee/services/access-approval-request/access-approval-request-types.ts b/backend/src/ee/services/access-approval-request/access-approval-request-types.ts
index e11ca58d5..51a5e0ca2 100644
--- a/backend/src/ee/services/access-approval-request/access-approval-request-types.ts
+++ b/backend/src/ee/services/access-approval-request/access-approval-request-types.ts
@@ -24,6 +24,7 @@ export type TCreateAccessApprovalRequestDTO = {
permissions: unknown;
isTemporary: boolean;
temporaryRange?: string;
+ note?: string;
} & Omit;
export type TListApprovalRequestsDTO = {
diff --git a/backend/src/services/slack/slack-fns.ts b/backend/src/services/slack/slack-fns.ts
index f92f96a24..6c84c0e76 100644
--- a/backend/src/services/slack/slack-fns.ts
+++ b/backend/src/services/slack/slack-fns.ts
@@ -87,7 +87,12 @@ View the complete details <${appCfg.SITE_URL}/secret-manager/${payload.projectId
The following permissions are requested: ${payload.permissions.join(", ")}
-View the request and approve or deny it <${payload.approvalUrl}|here>.`;
+View the request and approve or deny it <${payload.approvalUrl}|here>.${
+ payload.note
+ ? `
+User Note: ${payload.note}`
+ : ""
+ }`;
const payloadBlocks = [
{
diff --git a/backend/src/services/slack/slack-types.ts b/backend/src/services/slack/slack-types.ts
index a92ba4e8b..3e8354adf 100644
--- a/backend/src/services/slack/slack-types.ts
+++ b/backend/src/services/slack/slack-types.ts
@@ -76,5 +76,6 @@ export type TSlackNotification =
projectName: string;
permissions: string[];
approvalUrl: string;
+ note?: string;
};
};
diff --git a/backend/src/services/smtp/templates/accessApprovalRequest.handlebars b/backend/src/services/smtp/templates/accessApprovalRequest.handlebars
index ef11957a7..6813c1200 100644
--- a/backend/src/services/smtp/templates/accessApprovalRequest.handlebars
+++ b/backend/src/services/smtp/templates/accessApprovalRequest.handlebars
@@ -40,6 +40,9 @@
{{/each}}
+ {{#if note}}
+ User Note: "{{note}}"
+ {{/if}}
View the request and approve or deny it
diff --git a/frontend/src/hooks/api/accessApproval/types.ts b/frontend/src/hooks/api/accessApproval/types.ts
index 40da0207a..e2d620fe2 100644
--- a/frontend/src/hooks/api/accessApproval/types.ts
+++ b/frontend/src/hooks/api/accessApproval/types.ts
@@ -79,6 +79,8 @@ export type TAccessApprovalRequest = {
member: string;
status: string;
}[];
+
+ note?: string;
};
export type TAccessApproval = {
@@ -119,6 +121,7 @@ export type TProjectUserPrivilege = {
export type TCreateAccessRequestDTO = {
projectSlug: string;
+ note?: string;
} & Omit;
export type TGetAccessApprovalRequestsDTO = {
diff --git a/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MemberRoleForm/SpecificPrivilegeSection.tsx b/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MemberRoleForm/SpecificPrivilegeSection.tsx
index 06641be7a..e9c9d15fc 100644
--- a/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MemberRoleForm/SpecificPrivilegeSection.tsx
+++ b/frontend/src/pages/project/AccessControlPage/components/MembersTab/components/MemberRoleForm/SpecificPrivilegeSection.tsx
@@ -67,7 +67,8 @@ const secretPermissionSchema = z.object({
z.object({
isTemporary: z.literal(false)
})
- ])
+ ]),
+ note: z.string().optional()
});
type TSecretPermissionForm = z.infer;
export const SpecificPrivilegeSecretForm = ({
@@ -231,7 +232,8 @@ export const SpecificPrivilegeSecretForm = ({
action,
subject: [ProjectPermissionSub.Secrets],
conditions
- }))
+ })),
+ note: data.note
});
createNotification({
@@ -541,6 +543,18 @@ export const SpecificPrivilegeSecretForm = ({
)}
+
{!!policies && (