♻️ prevent deleting resource policies if they have attached resources

This commit is contained in:
Fred KISSIE
2026-03-07 01:12:10 +01:00
parent 884482ec35
commit f8e18de2fc
3 changed files with 44 additions and 18 deletions

View File

@@ -102,6 +102,12 @@ export const resources = pgTable("resources", {
() => resourcePolicies.resourcePolicyId,
{ onDelete: "set null" }
),
defaultResourcePolicyId: integer("defaultResourcePolicyId").references(
() => resourcePolicies.resourcePolicyId,
{
onDelete: "restrict"
}
),
resourceGuid: varchar("resourceGuid", { length: 36 })
.unique()
.notNull()

View File

@@ -344,6 +344,17 @@ authenticated.get(
approval.countApprovals
);
authenticated.delete(
"/resource-policy/:resourcePolicyId",
verifyResourcePolicyAccess,
verifyValidLicense,
// verifyValidSubscription(tierMatrix.loginPageDomain), // todo: use the correct subscription ?
verifyLimits,
verifyUserHasAction(ActionsEnum.deleteResourcePolicy),
logActionAudit(ActionsEnum.deleteResourcePolicy),
policy.deleteResourcePolicy
);
authenticated.get(
"/org/:orgId/resource-policies",
verifyValidLicense,
@@ -355,18 +366,6 @@ authenticated.get(
policy.listResourcePolicies
);
authenticated.delete(
"/resource-policy/:resourcePolicyId",
verifyResourcePolicyAccess,
verifyValidLicense,
// verifyValidSubscription(tierMatrix.loginPageDomain), // todo: use the correct subscription ?
verifyOrgAccess,
verifyLimits,
verifyUserHasAction(ActionsEnum.deleteResourcePolicy),
logActionAudit(ActionsEnum.deleteResourcePolicy),
policy.deleteResourcePolicy
);
authenticated.post(
"/org/:orgId/resource-policy",
verifyValidLicense,

View File

@@ -11,7 +11,7 @@
* This file is not licensed under the AGPLv3.
*/
import { db, resourcePolicies } from "@server/db";
import { db, resourcePolicies, resources } from "@server/db";
import response from "@server/lib/response";
import logger from "@server/logger";
import { OpenAPITags, registry } from "@server/openApi";
@@ -56,12 +56,12 @@ export async function deleteResourcePolicy(
const { resourcePolicyId } = parsedParams.data;
const [deletedResource] = await db
.delete(resourcePolicies)
.where(eq(resourcePolicies.resourcePolicyId, resourcePolicyId))
.returning();
const [existingResource] = await db
.select()
.from(resourcePolicies)
.where(eq(resourcePolicies.resourcePolicyId, resourcePolicyId));
if (!deletedResource) {
if (!existingResource) {
return next(
createHttpError(
HttpCode.NOT_FOUND,
@@ -70,6 +70,27 @@ export async function deleteResourcePolicy(
);
}
const totalAffectedResources = await db.$count(
db
.select()
.from(resources)
.where(eq(resources.resourcePolicyId, resourcePolicyId))
);
if (totalAffectedResources > 0) {
return next(
createHttpError(
HttpCode.FORBIDDEN,
`Cannot delete Policy '${existingResource.name}' as it's being used by at least one resource`
)
);
}
// delete policy
await db
.delete(resourcePolicies)
.where(eq(resourcePolicies.resourcePolicyId, resourcePolicyId));
return response(res, {
data: null,
success: true,