feat(machine-identities): Delete protection

This commit is contained in:
x032205
2025-06-13 14:37:15 -04:00
parent 23a7c1b8cc
commit 19a403f467
17 changed files with 120 additions and 21 deletions
@@ -101,6 +101,7 @@ export const identityProjectDALFactory = (db: TDbClient) => {
db.ref("id").as("identityId").withSchema(TableName.Identity),
db.ref("name").as("identityName").withSchema(TableName.Identity),
db.ref("hasDeleteProtection").withSchema(TableName.Identity),
db.ref("id").withSchema(TableName.IdentityProjectMembership),
db.ref("role").withSchema(TableName.IdentityProjectMembershipRole),
db.ref("id").withSchema(TableName.IdentityProjectMembershipRole).as("membershipRoleId"),
@@ -130,6 +131,7 @@ export const identityProjectDALFactory = (db: TDbClient) => {
data: docs,
parentMapper: ({
identityName,
hasDeleteProtection,
uaId,
awsId,
gcpId,
@@ -151,6 +153,7 @@ export const identityProjectDALFactory = (db: TDbClient) => {
identity: {
id: identityId,
name: identityName,
hasDeleteProtection,
authMethods: buildAuthMethods({
uaId,
awsId,
@@ -114,16 +114,18 @@ export const identityOrgDALFactory = (db: TDbClient) => {
db.ref("id").as("tokenId").withSchema(TableName.IdentityTokenAuth),
db.ref("id").as("jwtId").withSchema(TableName.IdentityJwtAuth),
db.ref("id").as("ldapId").withSchema(TableName.IdentityLdapAuth),
db.ref("name").withSchema(TableName.Identity)
db.ref("name").withSchema(TableName.Identity),
db.ref("hasDeleteProtection").withSchema(TableName.Identity)
);
if (data) {
const { name } = data;
const { name, hasDeleteProtection } = data;
return {
...data,
identity: {
id: data.identityId,
name,
hasDeleteProtection,
authMethods: buildAuthMethods(data)
}
};
@@ -155,7 +157,8 @@ export const identityOrgDALFactory = (db: TDbClient) => {
.orderBy(`${TableName.Identity}.${orderBy}`, orderDirection)
.select(
selectAllTableCols(TableName.IdentityOrgMembership),
db.ref("name").withSchema(TableName.Identity).as("identityName")
db.ref("name").withSchema(TableName.Identity).as("identityName"),
db.ref("hasDeleteProtection").withSchema(TableName.Identity)
)
.where(filter)
.as("paginatedIdentity");
@@ -245,6 +248,7 @@ export const identityOrgDALFactory = (db: TDbClient) => {
db.ref("updatedAt").withSchema("paginatedIdentity"),
db.ref("identityId").withSchema("paginatedIdentity").as("identityId"),
db.ref("identityName").withSchema("paginatedIdentity"),
db.ref("hasDeleteProtection").withSchema("paginatedIdentity"),
db.ref("id").as("uaId").withSchema(TableName.IdentityUniversalAuth),
db.ref("id").as("gcpId").withSchema(TableName.IdentityGcpAuth),
@@ -286,6 +290,7 @@ export const identityOrgDALFactory = (db: TDbClient) => {
crName,
identityId,
identityName,
hasDeleteProtection,
role,
roleId,
id,
@@ -324,6 +329,7 @@ export const identityOrgDALFactory = (db: TDbClient) => {
identity: {
id: identityId,
name: identityName,
hasDeleteProtection,
authMethods: buildAuthMethods({
uaId,
alicloudId,
@@ -476,6 +482,7 @@ export const identityOrgDALFactory = (db: TDbClient) => {
db.ref("updatedAt").withSchema(TableName.IdentityOrgMembership),
db.ref("identityId").withSchema(TableName.IdentityOrgMembership).as("identityId"),
db.ref("name").withSchema(TableName.Identity).as("identityName"),
db.ref("hasDeleteProtection").withSchema(TableName.Identity),
db.ref("id").as("uaId").withSchema(TableName.IdentityUniversalAuth),
db.ref("id").as("gcpId").withSchema(TableName.IdentityGcpAuth),
@@ -518,6 +525,7 @@ export const identityOrgDALFactory = (db: TDbClient) => {
crName,
identityId,
identityName,
hasDeleteProtection,
role,
roleId,
total_count,
@@ -556,6 +564,7 @@ export const identityOrgDALFactory = (db: TDbClient) => {
identity: {
id: identityId,
name: identityName,
hasDeleteProtection,
authMethods: buildAuthMethods({
uaId,
alicloudId,
@@ -47,6 +47,7 @@ export const identityServiceFactory = ({
const createIdentity = async ({
name,
role,
hasDeleteProtection,
actor,
orgId,
actorId,
@@ -96,7 +97,7 @@ export const identityServiceFactory = ({
}
const identity = await identityDAL.transaction(async (tx) => {
const newIdentity = await identityDAL.create({ name }, tx);
const newIdentity = await identityDAL.create({ name, hasDeleteProtection }, tx);
await identityOrgMembershipDAL.create(
{
identityId: newIdentity.id,
@@ -138,6 +139,7 @@ export const identityServiceFactory = ({
const updateIdentity = async ({
id,
role,
hasDeleteProtection,
name,
actor,
actorId,
@@ -189,7 +191,9 @@ export const identityServiceFactory = ({
}
const identity = await identityDAL.transaction(async (tx) => {
const newIdentity = name ? await identityDAL.updateById(id, { name }, tx) : await identityDAL.findById(id, tx);
const newIdentity = name
? await identityDAL.updateById(id, { name, hasDeleteProtection }, tx)
: await identityDAL.findById(id, tx);
if (role) {
await identityOrgMembershipDAL.updateById(
identityOrgMembership.id,
@@ -272,6 +276,9 @@ export const identityServiceFactory = ({
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionIdentityActions.Delete, OrgPermissionSubjects.Identity);
if (identityOrgMembership.identity.hasDeleteProtection)
throw new BadRequestError({ message: "Identity has delete protection" });
const deletedIdentity = await identityDAL.deleteById(id);
await licenseService.updateSubscriptionOrgMemberCount(identityOrgMembership.orgId);
@@ -5,12 +5,14 @@ import { OrderByDirection, TOrgPermission } from "@app/lib/types";
export type TCreateIdentityDTO = {
role: string;
name: string;
hasDeleteProtection: boolean;
metadata?: { key: string; value: string }[];
} & TOrgPermission;
export type TUpdateIdentityDTO = {
id: string;
role?: string;
hasDeleteProtection?: boolean;
name?: string;
metadata?: { key: string; value: string }[];
isActorSuperAdmin?: boolean;
@@ -81,6 +81,7 @@ export type TMachineIdentityCreatedEvent = {
event: PostHogEventTypes.MachineIdentityCreated;
properties: {
name: string;
hasDeleteProtection: boolean;
orgId: string;
identityId: string;
};