mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-02 21:25:45 +00:00
Merge pull request #3395 from Infisical/feat/addCommentToAccessRequests
Add access request note and change secret request to change request
This commit is contained in:
@@ -0,0 +1,21 @@
|
|||||||
|
import { Knex } from "knex";
|
||||||
|
|
||||||
|
import { TableName } from "../schemas";
|
||||||
|
|
||||||
|
export async function up(knex: Knex): Promise<void> {
|
||||||
|
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<void> {
|
||||||
|
const hasCol = await knex.schema.hasColumn(TableName.AccessApprovalRequest, "note");
|
||||||
|
if (hasCol) {
|
||||||
|
await knex.schema.alterTable(TableName.AccessApprovalRequest, (t) => {
|
||||||
|
t.dropColumn("note");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,7 +17,8 @@ export const AccessApprovalRequestsSchema = z.object({
|
|||||||
permissions: z.unknown(),
|
permissions: z.unknown(),
|
||||||
createdAt: z.date(),
|
createdAt: z.date(),
|
||||||
updatedAt: z.date(),
|
updatedAt: z.date(),
|
||||||
requestedByUserId: z.string().uuid()
|
requestedByUserId: z.string().uuid(),
|
||||||
|
note: z.string().nullable().optional()
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TAccessApprovalRequests = z.infer<typeof AccessApprovalRequestsSchema>;
|
export type TAccessApprovalRequests = z.infer<typeof AccessApprovalRequestsSchema>;
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ export const registerAccessApprovalRequestRouter = async (server: FastifyZodProv
|
|||||||
body: z.object({
|
body: z.object({
|
||||||
permissions: z.any().array(),
|
permissions: z.any().array(),
|
||||||
isTemporary: z.boolean(),
|
isTemporary: z.boolean(),
|
||||||
temporaryRange: z.string().optional()
|
temporaryRange: z.string().optional(),
|
||||||
|
note: z.string().max(255).optional()
|
||||||
}),
|
}),
|
||||||
querystring: z.object({
|
querystring: z.object({
|
||||||
projectSlug: z.string().trim()
|
projectSlug: z.string().trim()
|
||||||
@@ -43,7 +44,8 @@ export const registerAccessApprovalRequestRouter = async (server: FastifyZodProv
|
|||||||
actorOrgId: req.permission.orgId,
|
actorOrgId: req.permission.orgId,
|
||||||
projectSlug: req.query.projectSlug,
|
projectSlug: req.query.projectSlug,
|
||||||
temporaryRange: req.body.temporaryRange,
|
temporaryRange: req.body.temporaryRange,
|
||||||
isTemporary: req.body.isTemporary
|
isTemporary: req.body.isTemporary,
|
||||||
|
note: req.body.note
|
||||||
});
|
});
|
||||||
return { approval: request };
|
return { approval: request };
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,8 @@ export const accessApprovalRequestServiceFactory = ({
|
|||||||
actor,
|
actor,
|
||||||
actorOrgId,
|
actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
projectSlug
|
projectSlug,
|
||||||
|
note
|
||||||
}: TCreateAccessApprovalRequestDTO) => {
|
}: TCreateAccessApprovalRequestDTO) => {
|
||||||
const cfg = getConfig();
|
const cfg = getConfig();
|
||||||
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
||||||
@@ -209,7 +210,8 @@ export const accessApprovalRequestServiceFactory = ({
|
|||||||
requestedByUserId: actorId,
|
requestedByUserId: actorId,
|
||||||
temporaryRange: temporaryRange || null,
|
temporaryRange: temporaryRange || null,
|
||||||
permissions: JSON.stringify(requestedPermissions),
|
permissions: JSON.stringify(requestedPermissions),
|
||||||
isTemporary
|
isTemporary,
|
||||||
|
note: note || null
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
@@ -232,7 +234,8 @@ export const accessApprovalRequestServiceFactory = ({
|
|||||||
secretPath,
|
secretPath,
|
||||||
environment: envSlug,
|
environment: envSlug,
|
||||||
permissions: accessTypes,
|
permissions: accessTypes,
|
||||||
approvalUrl
|
approvalUrl,
|
||||||
|
note
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -252,7 +255,8 @@ export const accessApprovalRequestServiceFactory = ({
|
|||||||
secretPath,
|
secretPath,
|
||||||
environment: envSlug,
|
environment: envSlug,
|
||||||
permissions: accessTypes,
|
permissions: accessTypes,
|
||||||
approvalUrl
|
approvalUrl,
|
||||||
|
note
|
||||||
},
|
},
|
||||||
template: SmtpTemplates.AccessApprovalRequest
|
template: SmtpTemplates.AccessApprovalRequest
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ export type TCreateAccessApprovalRequestDTO = {
|
|||||||
permissions: unknown;
|
permissions: unknown;
|
||||||
isTemporary: boolean;
|
isTemporary: boolean;
|
||||||
temporaryRange?: string;
|
temporaryRange?: string;
|
||||||
|
note?: string;
|
||||||
} & Omit<TProjectPermission, "projectId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
export type TListApprovalRequestsDTO = {
|
export type TListApprovalRequestsDTO = {
|
||||||
|
|||||||
@@ -87,7 +87,12 @@ View the complete details <${appCfg.SITE_URL}/secret-manager/${payload.projectId
|
|||||||
|
|
||||||
The following permissions are requested: ${payload.permissions.join(", ")}
|
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 = [
|
const payloadBlocks = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -76,5 +76,6 @@ export type TSlackNotification =
|
|||||||
projectName: string;
|
projectName: string;
|
||||||
permissions: string[];
|
permissions: string[];
|
||||||
approvalUrl: string;
|
approvalUrl: string;
|
||||||
|
note?: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -40,6 +40,9 @@
|
|||||||
{{/each}}
|
{{/each}}
|
||||||
</ul>
|
</ul>
|
||||||
</p>
|
</p>
|
||||||
|
{{#if note}}
|
||||||
|
<p>User Note: "{{note}}"</p>
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
View the request and approve or deny it
|
View the request and approve or deny it
|
||||||
|
|||||||
@@ -79,6 +79,8 @@ export type TAccessApprovalRequest = {
|
|||||||
member: string;
|
member: string;
|
||||||
status: string;
|
status: string;
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
|
note?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TAccessApproval = {
|
export type TAccessApproval = {
|
||||||
@@ -119,6 +121,7 @@ export type TProjectUserPrivilege = {
|
|||||||
|
|
||||||
export type TCreateAccessRequestDTO = {
|
export type TCreateAccessRequestDTO = {
|
||||||
projectSlug: string;
|
projectSlug: string;
|
||||||
|
note?: string;
|
||||||
} & Omit<TProjectUserPrivilege, "id" | "createdAt" | "updatedAt" | "slug" | "projectMembershipId">;
|
} & Omit<TProjectUserPrivilege, "id" | "createdAt" | "updatedAt" | "slug" | "projectMembershipId">;
|
||||||
|
|
||||||
export type TGetAccessApprovalRequestsDTO = {
|
export type TGetAccessApprovalRequestsDTO = {
|
||||||
|
|||||||
+16
-2
@@ -67,7 +67,8 @@ const secretPermissionSchema = z.object({
|
|||||||
z.object({
|
z.object({
|
||||||
isTemporary: z.literal(false)
|
isTemporary: z.literal(false)
|
||||||
})
|
})
|
||||||
])
|
]),
|
||||||
|
note: z.string().optional()
|
||||||
});
|
});
|
||||||
type TSecretPermissionForm = z.infer<typeof secretPermissionSchema>;
|
type TSecretPermissionForm = z.infer<typeof secretPermissionSchema>;
|
||||||
export const SpecificPrivilegeSecretForm = ({
|
export const SpecificPrivilegeSecretForm = ({
|
||||||
@@ -231,7 +232,8 @@ export const SpecificPrivilegeSecretForm = ({
|
|||||||
action,
|
action,
|
||||||
subject: [ProjectPermissionSub.Secrets],
|
subject: [ProjectPermissionSub.Secrets],
|
||||||
conditions
|
conditions
|
||||||
}))
|
})),
|
||||||
|
note: data.note
|
||||||
});
|
});
|
||||||
|
|
||||||
createNotification({
|
createNotification({
|
||||||
@@ -541,6 +543,18 @@ export const SpecificPrivilegeSecretForm = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="mb-4 flex w-full">
|
||||||
|
<Controller
|
||||||
|
control={privilegeForm.control}
|
||||||
|
name="note"
|
||||||
|
render={({ field }) => (
|
||||||
|
<div className="w-full">
|
||||||
|
<FormLabel label="Note" className="mb-2" />
|
||||||
|
<Input {...field} isDisabled={isMemberEditDisabled} maxLength={255} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
{!!policies && (
|
{!!policies && (
|
||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ export const SecretApprovalsPage = () => {
|
|||||||
<Tabs defaultValue={defaultTab}>
|
<Tabs defaultValue={defaultTab}>
|
||||||
<TabList>
|
<TabList>
|
||||||
<Tab value={TabSection.SecretApprovalRequests}>
|
<Tab value={TabSection.SecretApprovalRequests}>
|
||||||
Secret Requests
|
Change Requests
|
||||||
{Boolean(secretApprovalReqCount?.open) && (
|
{Boolean(secretApprovalReqCount?.open) && (
|
||||||
<Badge className="ml-2">{secretApprovalReqCount?.open}</Badge>
|
<Badge className="ml-2">{secretApprovalReqCount?.open}</Badge>
|
||||||
)}
|
)}
|
||||||
|
|||||||
+7
@@ -136,6 +136,13 @@ export const ReviewAccessRequestModal = ({
|
|||||||
<span className="font-bold">Access Type: </span>
|
<span className="font-bold">Access Type: </span>
|
||||||
<span>{getAccessLabel()}</span>
|
<span>{getAccessLabel()}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{request.note && (
|
||||||
|
<div className="mt-1">
|
||||||
|
<span className="font-bold">User Note: </span>
|
||||||
|
<span>{request.note}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-x-2">
|
<div className="space-x-2">
|
||||||
|
|||||||
Reference in New Issue
Block a user