Files
Sauci/apps/supabase/tests/content-review-metadata.test.ts
T
jjbrunton 94c76535a4 feat(content): add catalogue review metadata
Add reversible review states, audit history, and super-admin controls for catalogue entities without changing current client visibility.

Stage 30 high-risk production packs for archival review, cap generated content at non-explicit language, and preserve a checksummed pre-change production catalogue snapshot.
2026-08-28 11:32:55 +01:00

382 lines
13 KiB
TypeScript

import { createClient } from "@supabase/supabase-js";
import { assertEquals, assertMatch } from "std/assert/mod.ts";
import {
adminClient,
createTestUser,
SUPABASE_URL,
} from "./utils.ts";
const anonKey = Deno.env.get("SUPABASE_ANON_KEY");
if (!anonKey) {
throw new Error("SUPABASE_ANON_KEY is required");
}
Deno.test("catalogue review migration stages the complete audited archive set", async () => {
const migrationSql = await Deno.readTextFile(
new URL(
"../migrations/20260827215907_add_catalog_content_review_metadata.sql",
import.meta.url,
),
);
const archiveBlocks = [...migrationSql.matchAll(
/WITH archive_packs\(id\) AS \(\s*VALUES([\s\S]*?)\)\s*UPDATE/g,
)];
assertEquals(archiveBlocks.length, 2);
const extractIds = (block: string) =>
[...block.matchAll(
/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/g,
)].map(([id]) => id);
const packIds = extractIds(archiveBlocks[0][1]);
const questionPackIds = extractIds(archiveBlocks[1][1]);
assertEquals(packIds.length, 30);
assertEquals(new Set(packIds).size, 30);
assertEquals(questionPackIds, packIds);
for (
const auditedMixedPackId of [
"f0f597b1-889c-4537-beeb-d0f459bb7907", // Body Mapping
"46288aa4-271c-44cf-bfe2-d25662d3f9f8", // Date Night Sparks
"d2000000-0000-0000-0000-000000000001", // First Impressions
"07f0da41-8ef7-4a48-8ec9-cef2dabaee73", // Love Notes
"42c00d6c-ab1f-42ce-afb0-00839064263b", // Romantic Gestures
"8a1e8650-a192-4f2e-86b0-0ec7bf6fb61c", // Sensual Massage
"d5d1b8d2-a868-4150-86bc-da3f8e3e8b00", // Testing the Waters
"19e4ddbd-a4aa-4b26-80bb-53b7187f0eba", // Missing You
]
) {
assertEquals(packIds.includes(auditedMixedPackId), true);
}
});
Deno.test("catalogue review metadata is reversible, audited, and non-super-admin decisions are rejected", async () => {
const suffix = crypto.randomUUID();
const email = `content-review-${suffix}@example.com`;
let packId: string | undefined;
let insertedPackId: string | undefined;
let userId: string | undefined;
try {
const { data: pack, error: packError } = await adminClient
.from("question_packs")
.insert({
name: `Content review test ${suffix}`,
is_public: true,
is_premium: false,
is_explicit: false,
})
.select("id, content_status")
.single();
if (packError) throw packError;
packId = pack.id;
assertEquals(pack.content_status, "unreviewed");
const { data: archived, error: archiveError } = await adminClient
.from("question_packs")
.update({
content_status: "archived",
content_review_reason: "Test archive decision",
})
.eq("id", packId)
.select("content_status, content_review_reason")
.single();
if (archiveError) throw archiveError;
assertEquals(archived.content_status, "archived");
assertEquals(archived.content_review_reason, "Test archive decision");
const { error: blankReasonError } = await adminClient
.from("question_packs")
.update({
content_status: "allowed",
content_review_reason: " ",
})
.eq("id", packId);
if (!blankReasonError) {
throw new Error("Expected blank review reason to be rejected");
}
assertMatch(blankReasonError.message, /non-blank content_review_reason/i);
const user = await createTestUser(email);
userId = user.id;
const userClient = createClient(SUPABASE_URL, anonKey, {
auth: { autoRefreshToken: false, persistSession: false },
});
const { error: signInError } = await userClient.auth.signInWithPassword({
email,
password: "password123",
});
if (signInError) throw signInError;
// The metadata-only migration must not hide content from existing clients.
const { data: stillVisible, error: visibilityError } = await userClient
.from("question_packs")
.select("id, content_status")
.eq("id", packId)
.single();
if (visibilityError) throw visibilityError;
assertEquals(stillVisible.id, packId);
assertEquals(stillVisible.content_status, "archived");
const { error: adminError } = await adminClient.from("admin_users").insert({
user_id: userId,
role: "pack_creator",
});
if (adminError) throw adminError;
const { error: forbiddenDecision } = await userClient
.from("question_packs")
.update({
content_status: "allowed",
content_review_reason: "Pack creator should not approve content",
})
.eq("id", packId);
if (!forbiddenDecision) {
throw new Error("Expected pack creator catalogue decision to be rejected");
}
assertMatch(forbiddenDecision.message, /Only super admins/i);
const { error: promoteError } = await adminClient
.from("admin_users")
.update({ role: "super_admin" })
.eq("user_id", userId);
if (promoteError) throw promoteError;
const { data: allowed, error: allowedError } = await userClient
.from("question_packs")
.update({
content_status: "allowed",
content_review_reason: "Test super admin approval",
})
.eq("id", packId)
.select("content_status, content_reviewed_by")
.single();
if (allowedError) throw allowedError;
assertEquals(allowed.content_status, "allowed");
assertEquals(allowed.content_reviewed_by, userId);
const { data: rereviewed, error: rereviewError } = await userClient
.from("question_packs")
.update({ content_review_reason: "Test approval independently rechecked" })
.eq("id", packId)
.select("content_status, content_review_reason, content_reviewed_by")
.single();
if (rereviewError) throw rereviewError;
assertEquals(rereviewed.content_status, "allowed");
assertEquals(
rereviewed.content_review_reason,
"Test approval independently rechecked",
);
assertEquals(rereviewed.content_reviewed_by, userId);
const { error: demoteError } = await adminClient
.from("admin_users")
.update({ role: "pack_creator" })
.eq("user_id", userId);
if (demoteError) throw demoteError;
const { error: forgedReason } = await userClient
.from("question_packs")
.update({ content_review_reason: "Pack creator forged review reason" })
.eq("id", packId);
if (!forgedReason) {
throw new Error("Expected pack creator review metadata change to be rejected");
}
assertMatch(forgedReason.message, /Only super admins/i);
const { error: forgedReviewer } = await userClient
.from("question_packs")
.update({ content_reviewed_by: null })
.eq("id", packId);
if (!forgedReviewer) {
throw new Error("Expected database-managed reviewer metadata to be rejected");
}
assertMatch(forgedReviewer.message, /database-managed/i);
const { data: guardedInsert, error: guardedInsertError } = await userClient
.from("question_packs")
.insert({
name: `Guarded content review insert ${suffix}`,
is_public: true,
is_premium: false,
is_explicit: false,
content_status: "allowed",
content_review_reason: "Forged approval on insert",
content_reviewed_at: new Date().toISOString(),
content_reviewed_by: userId,
})
.select(
"id, content_status, content_review_reason, content_reviewed_at, content_reviewed_by",
)
.single();
if (guardedInsertError) throw guardedInsertError;
insertedPackId = guardedInsert.id;
assertEquals(guardedInsert.content_status, "unreviewed");
assertEquals(guardedInsert.content_review_reason, null);
assertEquals(guardedInsert.content_reviewed_at, null);
assertEquals(guardedInsert.content_reviewed_by, null);
const { data: edited, error: editError } = await userClient
.from("question_packs")
.update({ name: `Edited content review test ${suffix}` })
.eq("id", packId)
.select("content_status, content_review_reason")
.single();
if (editError) throw editError;
assertEquals(edited.content_status, "unreviewed");
assertEquals(
edited.content_review_reason,
"Visible content changed; review required",
);
const { data: reviews, error: reviewsError } = await adminClient
.from("content_reviews")
.select("previous_status, new_status, reason, changed_by")
.eq("entity_type", "question_packs")
.eq("entity_id", packId)
.order("created_at", { ascending: true });
if (reviewsError) throw reviewsError;
assertEquals(reviews.length, 4);
assertEquals(reviews[0].previous_status, "unreviewed");
assertEquals(reviews[0].new_status, "archived");
assertEquals(reviews[1].previous_status, "archived");
assertEquals(reviews[1].new_status, "allowed");
assertEquals(reviews[1].changed_by, userId);
assertEquals(reviews[2].previous_status, "allowed");
assertEquals(reviews[2].new_status, "allowed");
assertEquals(reviews[2].changed_by, userId);
assertEquals(reviews[3].previous_status, "allowed");
assertEquals(reviews[3].new_status, "unreviewed");
assertEquals(reviews[3].changed_by, userId);
const { data: hiddenReviews, error: hiddenReviewsError } = await userClient
.from("content_reviews")
.select("id")
.eq("entity_type", "question_packs")
.eq("entity_id", packId);
if (hiddenReviewsError) throw hiddenReviewsError;
assertEquals(hiddenReviews.length, 0);
const { error: forgedAuditInsert } = await userClient
.from("content_reviews")
.insert({
entity_type: "question_packs",
entity_id: packId,
previous_status: "unreviewed",
new_status: "allowed",
reason: "Forged audit event",
});
if (!forgedAuditInsert) {
throw new Error("Expected authenticated audit insertion to be rejected");
}
} finally {
if (insertedPackId) {
await adminClient
.from("question_packs")
.delete()
.eq("id", insertedPackId);
}
if (packId) {
await adminClient
.from("content_reviews")
.delete()
.eq("entity_type", "question_packs")
.eq("entity_id", packId);
await adminClient.from("question_packs").delete().eq("id", packId);
}
if (userId) {
await adminClient.from("admin_users").delete().eq("user_id", userId);
await adminClient.auth.admin.deleteUser(userId);
}
}
});
Deno.test("deleting a reviewer preserves the decision and clears its current reviewer reference", async () => {
const suffix = crypto.randomUUID();
const email = `deleted-content-reviewer-${suffix}@example.com`;
let packId: string | undefined;
let userId: string | undefined;
try {
const user = await createTestUser(email);
userId = user.id;
const { error: adminError } = await adminClient.from("admin_users").insert({
user_id: userId,
role: "super_admin",
});
if (adminError) throw adminError;
const reviewerClient = createClient(SUPABASE_URL, anonKey, {
auth: { autoRefreshToken: false, persistSession: false },
});
const { error: signInError } = await reviewerClient.auth.signInWithPassword({
email,
password: "password123",
});
if (signInError) throw signInError;
const { data: pack, error: packError } = await adminClient
.from("question_packs")
.insert({
name: `Reviewer deletion test ${suffix}`,
is_public: true,
is_premium: false,
is_explicit: false,
})
.select("id")
.single();
if (packError) throw packError;
packId = pack.id;
const { error: approveError } = await reviewerClient
.from("question_packs")
.update({
content_status: "allowed",
content_review_reason: "Approval survives reviewer deletion",
})
.eq("id", packId);
if (approveError) throw approveError;
const { error: deleteUserError } = await adminClient.auth.admin.deleteUser(
userId,
);
if (deleteUserError) throw deleteUserError;
userId = undefined;
const { data: afterDeletion, error: afterDeletionError } = await adminClient
.from("question_packs")
.select("content_status, content_review_reason, content_reviewed_by")
.eq("id", packId)
.single();
if (afterDeletionError) throw afterDeletionError;
assertEquals(afterDeletion.content_status, "allowed");
assertEquals(
afterDeletion.content_review_reason,
"Approval survives reviewer deletion",
);
assertEquals(afterDeletion.content_reviewed_by, null);
} finally {
if (packId) {
await adminClient
.from("content_reviews")
.delete()
.eq("entity_type", "question_packs")
.eq("entity_id", packId);
await adminClient.from("question_packs").delete().eq("id", packId);
}
if (userId) {
await adminClient.from("admin_users").delete().eq("user_id", userId);
await adminClient.auth.admin.deleteUser(userId);
}
}
});