fix(backup): leave the admin wipe's off-host copies in place, and correct the backup and rotation runbooks

The admin wipe of every account is the operator clearing their own host,
and the bucket's copies are the documented way back from a wipe pressed
by mistake, so it writes no off-host deletion request. Deleting an
account, deleting a managed profile and "Delete all data" still do.

The backup runbook no longer says the worker never deletes an object: it
lists the grant the worker needs (DeleteObject included), when objects
are deleted, the version-4 envelope, the lifecycle check and how to
rotate the off-host key. The rotation runbook no longer says backups are
covered: rotation reaches a backup's envelope, not the content a restore
writes back, and a retired key stays needed until no backup lists it.
The privacy notice beside account deletion says the same about off-host
copies.

A failed import records its failure in a plain try block, and the
extraction test that inflates past the 64 MiB floor gets the time it
needs on a loaded runner.
This commit is contained in:
Marc-André Bombeck committed 2026-09-26 20:33:30 +02:00
1 parent 849748c4cd
commit 7da778760e
19 files changed
+223 -153

No files matched your search

-9
View File
@@ -1,8 +1,3 @@
import {
kickOffhostPurge,
PURGE_ALL_SUBJECTS,
requestOffhostPurge,
} from "@/lib/jobs/offhost-purge";
import { prisma } from "@/lib/db";
import { apiHandler, requireAdmin } from "@/lib/api-handler";
import { auditLog } from "@/lib/auth/audit";
@@ -113,9 +108,6 @@ export const DELETE = apiHandler(async (request: NextRequest) => {
// columns does not. Same classification contract as the model list.
await tx.user.updateMany({ data: USER_RESET });
// Every account's nightly off-host copies go too.
await requestOffhostPurge(tx, PURGE_ALL_SUBJECTS, "admin_wipe");
return perModel;
},
{
@@ -146,7 +138,6 @@ export const DELETE = apiHandler(async (request: NextRequest) => {
// v1.16.9 — the wipe touched every user's rows; clear every cache
// bucket so no per-user payload survives the reset.
invalidateAllCaches();
await kickOffhostPurge();
return apiSuccess({ cleared: true, deletedRows, models: counts });
});