Unlink servers before deleting a Proxmox integration

servers.proxmox_integration_id was created (migration 0001) without an ON DELETE
rule, although schema.ts asks for "set null", so with foreign keys on, deleting
an integration that a server was linked to failed with a constraint error.
The delete route now clears the four proxmox_* columns on those servers first
and records how many it unlinked in the audit entry. schema.ts notes the gap.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
bobbanandClaude Sonnet 5.5 committed 2026-10-05 00:53:06 +02:00
1 parent 3035d7fc08
commit 86dfa9ae2e
2 files changed
+12 -2

No files matched your search

+3 -1
View File
@@ -224,7 +224,9 @@ export const servers = sqliteTable("servers", {
lastPortScan: text("last_port_scan"), // JSON string: summary of the most recent network scan from this app lastPortScan: text("last_port_scan"), // JSON string: summary of the most recent network scan from this app
tags: text("tags"), // JSON string: string[] — free-form labels for grouping and filtering, normalized by services/serverTags tags: text("tags"), // JSON string: string[] — free-form labels for grouping and filtering, normalized by services/serverTags
// Optional link to a Proxmox VM/LXC — set by an admin, not the agent. // Optional link to a Proxmox VM/LXC — set by an admin, not the agent. The "set null" below is what this file asks for,
// but migration 0001 created the column without it, so the database itself has no ON DELETE rule here: deleting an
// integration clears these columns in routes/integrations.ts instead. (See DATABASE.md.)
proxmoxIntegrationId: integer("proxmox_integration_id").references(() => integrations.id, { proxmoxIntegrationId: integer("proxmox_integration_id").references(() => integrations.id, {
onDelete: "set null", onDelete: "set null",
}), }),
+9 -1
View File
@@ -272,6 +272,14 @@ integrationsRouter.delete("/:id", requireRole("admin"), asyncHandler(async (req,
return res.status(404).json({ error: "not_found" }); return res.status(404).json({ error: "not_found" });
} }
// servers.proxmox_integration_id was meant to clear itself, but the database only has a plain REFERENCES on it (see
// DATABASE.md), so a linked server would block the delete. Clear the whole link here — the four columns go together.
const unlinked = await db
.update(servers)
.set({ proxmoxIntegrationId: null, proxmoxNode: null, proxmoxGuestType: null, proxmoxVmid: null })
.where(eq(servers.proxmoxIntegrationId, id))
.returning({ id: servers.id });
await db.delete(integrations).where(eq(integrations.id, id)); await db.delete(integrations).where(eq(integrations.id, id));
if (existing.credentialId) { if (existing.credentialId) {
await db.delete(integrationCredentials).where(eq(integrationCredentials.id, existing.credentialId)); await db.delete(integrationCredentials).where(eq(integrationCredentials.id, existing.credentialId));
@@ -283,7 +291,7 @@ integrationsRouter.delete("/:id", requireRole("admin"), asyncHandler(async (req,
action: "delete", action: "delete",
targetType: "integration", targetType: "integration",
targetId: id, targetId: id,
detail: { name: existing.name }, detail: { name: existing.name, ...(unlinked.length > 0 ? { unlinkedServers: unlinked.length } : {}) },
}); });
res.status(204).end(); res.status(204).end();