diff --git a/backend/src/ee/routes/v1/deprecated-project-role-router.ts b/backend/src/ee/routes/v1/deprecated-project-role-router.ts index d0ffc0239a..dc361626d8 100644 --- a/backend/src/ee/routes/v1/deprecated-project-role-router.ts +++ b/backend/src/ee/routes/v1/deprecated-project-role-router.ts @@ -2,6 +2,7 @@ import { packRules } from "@casl/ability/extra"; import { z } from "zod"; import { ProjectMembershipRole, ProjectRolesSchema } from "@app/db/schemas"; +import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { backfillPermissionV1SchemaToV2Schema, ProjectPermissionV1Schema @@ -50,6 +51,10 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { + const stringifiedPermissions = JSON.stringify( + packRules(backfillPermissionV1SchemaToV2Schema(req.body.permissions, true)) + ); + const role = await server.services.projectRole.createRole({ actorAuthMethod: req.permission.authMethod, actorId: req.permission.id, @@ -61,7 +66,23 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv }, data: { ...req.body, - permissions: JSON.stringify(packRules(backfillPermissionV1SchemaToV2Schema(req.body.permissions, true))) + permissions: stringifiedPermissions + } + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: req.permission.orgId, + projectId: role.projectId, + event: { + type: EventType.CREATE_PROJECT_ROLE, + metadata: { + roleId: role.id, + slug: req.body.slug, + name: req.body.name, + description: req.body.description, + permissions: stringifiedPermissions + } } }); @@ -106,6 +127,10 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { + const stringifiedPermissions = req.body.permissions + ? JSON.stringify(packRules(backfillPermissionV1SchemaToV2Schema(req.body.permissions, true))) + : undefined; + const role = await server.services.projectRole.updateRole({ actorAuthMethod: req.permission.authMethod, actorId: req.permission.id, @@ -114,11 +139,26 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv roleId: req.params.roleId, data: { ...req.body, - permissions: req.body.permissions - ? JSON.stringify(packRules(backfillPermissionV1SchemaToV2Schema(req.body.permissions, true))) - : undefined + permissions: stringifiedPermissions + } + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: req.permission.orgId, + projectId: role.projectId, + event: { + type: EventType.UPDATE_PROJECT_ROLE, + metadata: { + roleId: role.id, + slug: req.body.slug, + name: req.body.name, + description: req.body.description, + permissions: stringifiedPermissions + } } }); + return { role }; } }); @@ -155,6 +195,21 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv actor: req.permission.type, roleId: req.params.roleId }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: req.permission.orgId, + projectId: role.projectId, + event: { + type: EventType.DELETE_PROJECT_ROLE, + metadata: { + roleId: role.id, + slug: role.slug, + name: role.name + } + } + }); + return { role }; } }); diff --git a/backend/src/ee/routes/v1/org-role-router.ts b/backend/src/ee/routes/v1/org-role-router.ts index c8ee03a99b..070462d47c 100644 --- a/backend/src/ee/routes/v1/org-role-router.ts +++ b/backend/src/ee/routes/v1/org-role-router.ts @@ -1,6 +1,7 @@ import { z } from "zod"; import { OrgMembershipRole, OrgMembershipsSchema, OrgRolesSchema } from "@app/db/schemas"; +import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { readLimit, writeLimit } from "@app/server/config/rateLimiter"; import { slugSchema } from "@app/server/lib/schemas"; import { verifyAuth } from "@app/server/plugins/auth/verify-auth"; @@ -42,6 +43,22 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => { req.permission.authMethod, req.permission.orgId ); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: req.permission.orgId, + event: { + type: EventType.CREATE_ORG_ROLE, + metadata: { + roleId: role.id, + slug: req.body.slug, + name: req.body.name, + description: req.body.description, + permissions: JSON.stringify(req.body.permissions) + } + } + }); + return { role }; } }); @@ -116,6 +133,22 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => { req.permission.authMethod, req.permission.orgId ); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: req.permission.orgId, + event: { + type: EventType.UPDATE_ORG_ROLE, + metadata: { + roleId: role.id, + slug: req.body.slug, + name: req.body.name, + description: req.body.description, + permissions: req.body.permissions ? JSON.stringify(req.body.permissions) : undefined + } + } + }); + return { role }; } }); @@ -146,6 +179,16 @@ export const registerOrgRoleRouter = async (server: FastifyZodProvider) => { req.permission.authMethod, req.permission.orgId ); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: req.permission.orgId, + event: { + type: EventType.DELETE_ORG_ROLE, + metadata: { roleId: role.id, slug: role.slug, name: role.name } + } + }); + return { role }; } }); diff --git a/backend/src/ee/routes/v1/project-role-router.ts b/backend/src/ee/routes/v1/project-role-router.ts index 23633c8f53..5a20ad893d 100644 --- a/backend/src/ee/routes/v1/project-role-router.ts +++ b/backend/src/ee/routes/v1/project-role-router.ts @@ -2,6 +2,7 @@ import { packRules } from "@casl/ability/extra"; import { z } from "zod"; import { ProjectMembershipRole, ProjectRolesSchema } from "@app/db/schemas"; +import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { checkForInvalidPermissionCombination } from "@app/ee/services/permission/permission-fns"; import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission"; import { ApiDocsTags, PROJECT_ROLE } from "@app/lib/api-docs"; @@ -52,6 +53,8 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { + const stringifiedPermissions = JSON.stringify(packRules(req.body.permissions)); + const role = await server.services.projectRole.createRole({ actorAuthMethod: req.permission.authMethod, actorId: req.permission.id, @@ -63,9 +66,26 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { }, data: { ...req.body, - permissions: JSON.stringify(packRules(req.body.permissions)) + permissions: stringifiedPermissions + } + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: req.permission.orgId, + projectId: role.projectId, + event: { + type: EventType.CREATE_PROJECT_ROLE, + metadata: { + roleId: role.id, + slug: req.body.slug, + name: req.body.name, + description: req.body.description, + permissions: stringifiedPermissions + } } }); + return { role }; } }); @@ -112,6 +132,7 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { + const stringifiedPermissions = req.body.permissions ? JSON.stringify(packRules(req.body.permissions)) : undefined; const role = await server.services.projectRole.updateRole({ actorAuthMethod: req.permission.authMethod, actorId: req.permission.id, @@ -120,9 +141,26 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { roleId: req.params.roleId, data: { ...req.body, - permissions: req.body.permissions ? JSON.stringify(packRules(req.body.permissions)) : undefined + permissions: stringifiedPermissions } }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: req.permission.orgId, + projectId: role.projectId, + event: { + type: EventType.UPDATE_PROJECT_ROLE, + metadata: { + roleId: role.id, + slug: req.body.slug, + name: req.body.name, + description: req.body.description, + permissions: stringifiedPermissions + } + } + }); + return { role }; } }); @@ -161,6 +199,21 @@ export const registerProjectRoleRouter = async (server: FastifyZodProvider) => { actor: req.permission.type, roleId: req.params.roleId }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: req.permission.orgId, + projectId: role.projectId, + event: { + type: EventType.DELETE_PROJECT_ROLE, + metadata: { + roleId: role.id, + slug: role.slug, + name: role.name + } + } + }); + return { role }; } }); diff --git a/backend/src/ee/routes/v2/deprecated-project-role-router.ts b/backend/src/ee/routes/v2/deprecated-project-role-router.ts index 41a04974de..326bda06a4 100644 --- a/backend/src/ee/routes/v2/deprecated-project-role-router.ts +++ b/backend/src/ee/routes/v2/deprecated-project-role-router.ts @@ -2,6 +2,7 @@ import { packRules } from "@casl/ability/extra"; import { z } from "zod"; import { ProjectMembershipRole, ProjectRolesSchema } from "@app/db/schemas"; +import { EventType } from "@app/ee/services/audit-log/audit-log-types"; import { checkForInvalidPermissionCombination } from "@app/ee/services/permission/permission-fns"; import { ProjectPermissionV2Schema } from "@app/ee/services/permission/project-permission"; import { ApiDocsTags, PROJECT_ROLE } from "@app/lib/api-docs"; @@ -52,6 +53,8 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { + const stringifiedPermissions = JSON.stringify(packRules(req.body.permissions)); + const role = await server.services.projectRole.createRole({ actorAuthMethod: req.permission.authMethod, actorId: req.permission.id, @@ -63,9 +66,26 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv }, data: { ...req.body, - permissions: JSON.stringify(packRules(req.body.permissions)) + permissions: stringifiedPermissions + } + }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: req.permission.orgId, + projectId: role.projectId, + event: { + type: EventType.CREATE_PROJECT_ROLE, + metadata: { + roleId: role.id, + slug: req.body.slug, + name: req.body.name, + description: req.body.description, + permissions: stringifiedPermissions + } } }); + return { role }; } }); @@ -112,6 +132,7 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv }, onRequest: verifyAuth([AuthMode.JWT, AuthMode.IDENTITY_ACCESS_TOKEN]), handler: async (req) => { + const stringifiedPermissions = req.body.permissions ? JSON.stringify(packRules(req.body.permissions)) : undefined; const role = await server.services.projectRole.updateRole({ actorAuthMethod: req.permission.authMethod, actorId: req.permission.id, @@ -120,9 +141,26 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv roleId: req.params.roleId, data: { ...req.body, - permissions: req.body.permissions ? JSON.stringify(packRules(req.body.permissions)) : undefined + permissions: stringifiedPermissions } }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: req.permission.orgId, + projectId: role.projectId, + event: { + type: EventType.UPDATE_PROJECT_ROLE, + metadata: { + roleId: role.id, + slug: req.body.slug, + name: req.body.name, + description: req.body.description, + permissions: stringifiedPermissions + } + } + }); + return { role }; } }); @@ -161,6 +199,21 @@ export const registerDeprecatedProjectRoleRouter = async (server: FastifyZodProv actor: req.permission.type, roleId: req.params.roleId }); + + await server.services.auditLog.createAuditLog({ + ...req.auditLogInfo, + orgId: req.permission.orgId, + projectId: role.projectId, + event: { + type: EventType.DELETE_PROJECT_ROLE, + metadata: { + roleId: role.id, + slug: role.slug, + name: role.name + } + } + }); + return { role }; } }); diff --git a/backend/src/ee/services/audit-log/audit-log-types.ts b/backend/src/ee/services/audit-log/audit-log-types.ts index 07773885ad..a6111f6aec 100644 --- a/backend/src/ee/services/audit-log/audit-log-types.ts +++ b/backend/src/ee/services/audit-log/audit-log-types.ts @@ -478,6 +478,14 @@ export enum EventType { UPDATE_PROJECT = "update-project", DELETE_PROJECT = "delete-project", + CREATE_PROJECT_ROLE = "create-project-role", + UPDATE_PROJECT_ROLE = "update-project-role", + DELETE_PROJECT_ROLE = "delete-project-role", + + CREATE_ORG_ROLE = "create-org-role", + UPDATE_ORG_ROLE = "update-org-role", + DELETE_ORG_ROLE = "delete-org-role", + CREATE_SECRET_REMINDER = "create-secret-reminder", GET_SECRET_REMINDER = "get-secret-reminder", DELETE_SECRET_REMINDER = "delete-secret-reminder" @@ -3502,6 +3510,68 @@ interface ProjectDeleteEvent { }; } +interface ProjectRoleCreateEvent { + type: EventType.CREATE_PROJECT_ROLE; + metadata: { + roleId: string; + slug: string; + name: string; + description?: string | null; + permissions: string; + }; +} + +interface ProjectRoleUpdateEvent { + type: EventType.UPDATE_PROJECT_ROLE; + metadata: { + roleId: string; + slug?: string; + name?: string; + description?: string | null; + permissions?: string; + }; +} + +interface ProjectRoleDeleteEvent { + type: EventType.DELETE_PROJECT_ROLE; + metadata: { + roleId: string; + slug: string; + name: string; + }; +} + +interface OrgRoleCreateEvent { + type: EventType.CREATE_ORG_ROLE; + metadata: { + roleId: string; + slug: string; + name: string; + description?: string | null; + permissions: string; + }; +} + +interface OrgRoleUpdateEvent { + type: EventType.UPDATE_ORG_ROLE; + metadata: { + roleId: string; + slug?: string; + name?: string; + description?: string | null; + permissions?: string; + }; +} + +interface OrgRoleDeleteEvent { + type: EventType.DELETE_ORG_ROLE; + metadata: { + roleId: string; + slug: string; + name: string; + }; +} + export type Event = | GetSecretsEvent | GetSecretEvent @@ -3818,4 +3888,10 @@ export type Event = | ProjectDeleteEvent | SecretReminderCreateEvent | SecretReminderGetEvent - | SecretReminderDeleteEvent; + | SecretReminderDeleteEvent + | ProjectRoleCreateEvent + | ProjectRoleUpdateEvent + | ProjectRoleDeleteEvent + | OrgRoleCreateEvent + | OrgRoleUpdateEvent + | OrgRoleDeleteEvent; diff --git a/frontend/src/hooks/api/auditLogs/constants.tsx b/frontend/src/hooks/api/auditLogs/constants.tsx index 503264fb28..15993023e2 100644 --- a/frontend/src/hooks/api/auditLogs/constants.tsx +++ b/frontend/src/hooks/api/auditLogs/constants.tsx @@ -222,7 +222,15 @@ export const eventToNameMap: { [K in EventType]: string } = { [EventType.UPDATE_ORG]: "Update Organization", [EventType.CREATE_PROJECT]: "Create Project", [EventType.UPDATE_PROJECT]: "Update Project", - [EventType.DELETE_PROJECT]: "Delete Project" + [EventType.DELETE_PROJECT]: "Delete Project", + + [EventType.CREATE_PROJECT_ROLE]: "Create Project Role", + [EventType.UPDATE_PROJECT_ROLE]: "Update Project Role", + [EventType.DELETE_PROJECT_ROLE]: "Delete Project Role", + + [EventType.CREATE_ORG_ROLE]: "Create Org Role", + [EventType.UPDATE_ORG_ROLE]: "Update Org Role", + [EventType.DELETE_ORG_ROLE]: "Delete Org Role" }; export const userAgentTypeToNameMap: { [K in UserAgentType]: string } = { diff --git a/frontend/src/hooks/api/auditLogs/enums.tsx b/frontend/src/hooks/api/auditLogs/enums.tsx index bfa983188d..77baaa9904 100644 --- a/frontend/src/hooks/api/auditLogs/enums.tsx +++ b/frontend/src/hooks/api/auditLogs/enums.tsx @@ -216,5 +216,13 @@ export enum EventType { CREATE_PROJECT = "create-project", UPDATE_PROJECT = "update-project", - DELETE_PROJECT = "delete-project" + DELETE_PROJECT = "delete-project", + + CREATE_PROJECT_ROLE = "create-project-role", + UPDATE_PROJECT_ROLE = "update-project-role", + DELETE_PROJECT_ROLE = "delete-project-role", + + CREATE_ORG_ROLE = "create-org-role", + UPDATE_ORG_ROLE = "update-org-role", + DELETE_ORG_ROLE = "delete-org-role" }