fix(core-dsr): flip processingRestrictedAt in soft-delete for self role
PayloadDataDelete.deleteSubjectData('soft') was NULLing PII fields and
emitting RESTRICT audit entries, but never setting processingRestrictedAt
on self-kind rows — violating GDPR Art. 17 restriction semantics.
softRedactOwnerRows now accepts optional extraData; processOwnerRows
passes { processingRestrictedAt: new Date().toISOString() } when
kind === 'self' and mode === 'soft'. Owner-kind rows are intentionally
excluded (restriction flag belongs on the subject record, not owned rows).
Added two dedicated tests: one asserting the field is present for self,
one asserting it is absent for owner.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -56,7 +56,7 @@ describe("PayloadDataDelete", () => {
|
||||
expect(mockPayload.update).toHaveBeenCalledWith({
|
||||
collection: "users",
|
||||
id: "alice",
|
||||
data: { email: null, name: null },
|
||||
data: expect.objectContaining({ email: null, name: null }),
|
||||
overrideAccess: true,
|
||||
});
|
||||
|
||||
@@ -70,6 +70,59 @@ describe("PayloadDataDelete", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("self role: sets processingRestrictedAt in the update call", async () => {
|
||||
const config = makeMockConfig([
|
||||
{
|
||||
slug: "users",
|
||||
custom: {
|
||||
subject: { field: "id", kind: "self" },
|
||||
pii: { email: { exportable: true } },
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
mockPayload.find.mockResolvedValue({
|
||||
docs: [{ id: "alice", email: "a@ex.com" }],
|
||||
});
|
||||
|
||||
const deleter = new PayloadDataDelete(config, auditLog, mockGetPayload);
|
||||
await deleter.deleteSubjectData("alice", "soft");
|
||||
|
||||
expect(mockPayload.update).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
data: expect.objectContaining({
|
||||
processingRestrictedAt: expect.any(String),
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("owner role: does NOT set processingRestrictedAt", async () => {
|
||||
const config = makeMockConfig([
|
||||
{
|
||||
slug: "orders",
|
||||
custom: {
|
||||
subject: { field: "userId", kind: "owner" },
|
||||
pii: { shippingAddress: { exportable: true } },
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
mockPayload.find.mockResolvedValue({
|
||||
docs: [{ id: "o-1", userId: "alice", shippingAddress: "1 Main" }],
|
||||
});
|
||||
|
||||
const deleter = new PayloadDataDelete(config, auditLog, mockGetPayload);
|
||||
await deleter.deleteSubjectData("alice", "soft");
|
||||
|
||||
expect(mockPayload.update).toHaveBeenCalledWith({
|
||||
collection: "orders",
|
||||
id: "o-1",
|
||||
data: { shippingAddress: null },
|
||||
overrideAccess: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("happy path — owner role: NULLs exportable fields in owned rows", async () => {
|
||||
const config = makeMockConfig([
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user