diff --git a/.github/workflows/release-standalone-docker-img-postgres-offical.yml b/.github/workflows/release-standalone-docker-img-postgres-offical.yml index 5c8809eb4..b17d5e50c 100644 --- a/.github/workflows/release-standalone-docker-img-postgres-offical.yml +++ b/.github/workflows/release-standalone-docker-img-postgres-offical.yml @@ -63,6 +63,8 @@ jobs: build-args: | POSTHOG_API_KEY=${{ secrets.PUBLIC_POSTHOG_API_KEY }} INFISICAL_PLATFORM_VERSION=${{ steps.extract_version.outputs.version }} + DD_GIT_REPOSITORY_URL=${{ github.server_url }}/${{ github.repository }} + DD_GIT_COMMIT_SHA=${{ github.sha }} infisical-fips-standalone: name: Build infisical standalone image postgres diff --git a/Dockerfile.standalone-infisical b/Dockerfile.standalone-infisical index a4e5c150a..9ca5e1dea 100644 --- a/Dockerfile.standalone-infisical +++ b/Dockerfile.standalone-infisical @@ -173,6 +173,12 @@ COPY --from=frontend-runner /app ./backend/frontend-build ARG INFISICAL_PLATFORM_VERSION ENV INFISICAL_PLATFORM_VERSION $INFISICAL_PLATFORM_VERSION +ARG DD_GIT_REPOSITORY_URL +ENV DD_GIT_REPOSITORY_URL $DD_GIT_REPOSITORY_URL + +ARG DD_GIT_COMMIT_SHA +ENV DD_GIT_COMMIT_SHA $DD_GIT_COMMIT_SHA + ENV PORT 8080 ENV HOST=0.0.0.0 ENV HTTPS_ENABLED false 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 d0ffc0239..dc361626d 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 c8ee03a99..070462d47 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 23633c8f5..5a20ad893 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 41a04974d..326bda06a 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 4d539fe4b..36c936cb0 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", @@ -3534,6 +3542,68 @@ interface DashboardGetSecretVersionValueEvent { }; } +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 @@ -3853,4 +3923,10 @@ export type Event = | SecretReminderDeleteEvent | DashboardListSecretsEvent | DashboardGetSecretValueEvent - | DashboardGetSecretVersionValueEvent; + | DashboardGetSecretVersionValueEvent + | ProjectRoleCreateEvent + | ProjectRoleUpdateEvent + | ProjectRoleDeleteEvent + | OrgRoleCreateEvent + | OrgRoleUpdateEvent + | OrgRoleDeleteEvent; diff --git a/backend/src/server/routes/v4/secret-router.ts b/backend/src/server/routes/v4/secret-router.ts index 88cf62902..e9cff7949 100644 --- a/backend/src/server/routes/v4/secret-router.ts +++ b/backend/src/server/routes/v4/secret-router.ts @@ -762,7 +762,7 @@ export const registerSecretRouter = async (server: FastifyZodProvider) => { hide: false, tags: [ApiDocsTags.Secrets], body: z.object({ - projectSlug: z.string().trim(), + projectId: z.string().trim(), sourceEnvironment: z.string().trim(), sourceSecretPath: z.string().trim().default("/").transform(removeTrailingSlash), destinationEnvironment: z.string().trim(), diff --git a/frontend/src/hooks/api/auditLogs/constants.tsx b/frontend/src/hooks/api/auditLogs/constants.tsx index d770a682f..df045fa53 100644 --- a/frontend/src/hooks/api/auditLogs/constants.tsx +++ b/frontend/src/hooks/api/auditLogs/constants.tsx @@ -230,7 +230,15 @@ export const eventToNameMap: { [K in EventType]: string } = { [EventType.DASHBOARD_LIST_SECRETS]: "Dashboard List Secrets", [EventType.DASHBOARD_GET_SECRET_VALUE]: "Dashboard Get Secret Value", - [EventType.DASHBOARD_GET_SECRET_VERSION_VALUE]: "Dashboard Get Secret Version Value" + [EventType.DASHBOARD_GET_SECRET_VERSION_VALUE]: "Dashboard Get Secret Version Value", + + [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 135319713..52ccc3cdc 100644 --- a/frontend/src/hooks/api/auditLogs/enums.tsx +++ b/frontend/src/hooks/api/auditLogs/enums.tsx @@ -224,5 +224,13 @@ export enum EventType { DASHBOARD_LIST_SECRETS = "dashboard-list-secrets", DASHBOARD_GET_SECRET_VALUE = "dashboard-get-secret-value", - DASHBOARD_GET_SECRET_VERSION_VALUE = "dashboard-get-secret-version-value" + DASHBOARD_GET_SECRET_VERSION_VALUE = "dashboard-get-secret-version-value", + + 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" } diff --git a/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx b/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx index 28233ca61..e48cfb78c 100644 --- a/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx +++ b/frontend/src/pages/secret-manager/OverviewPage/OverviewPage.tsx @@ -729,6 +729,9 @@ export const OverviewPage = () => { userAvailableEnvs.forEach((env) => { secrets?.forEach((secret) => { + // bulk actions don't apply to rotation secrets (move/delete) + if (secret.isRotatedSecret) return; + if (allRowsSelectedOnPage.isChecked) { delete newChecks[EntryType.SECRET][secret.key]; } else { diff --git a/frontend/src/pages/secret-manager/SecretDashboardPage/SecretDashboardPage.tsx b/frontend/src/pages/secret-manager/SecretDashboardPage/SecretDashboardPage.tsx index f6712e1fc..9b757e963 100644 --- a/frontend/src/pages/secret-manager/SecretDashboardPage/SecretDashboardPage.tsx +++ b/frontend/src/pages/secret-manager/SecretDashboardPage/SecretDashboardPage.tsx @@ -582,6 +582,9 @@ const Page = () => { const newChecks = { ...selectedSecrets }; secrets?.forEach((secret) => { + // bulk actions don't apply to rotation secrets (move/delete) + if (secret.isRotatedSecret) return; + if (allRowsSelectedOnPage.isChecked) { delete newChecks[secret.id]; } else {