import assert from 'node:assert/strict' import { randomUUID } from 'node:crypto' import { createClient } from '@supabase/supabase-js' const url = process.env.D3RO_LOCAL_SUPABASE_URL?.trim() ?? '' const anonKey = process.env.D3RO_LOCAL_SUPABASE_ANON_KEY?.trim() ?? '' const serviceRoleKey = process.env.D3RO_LOCAL_SUPABASE_SERVICE_ROLE_KEY?.trim() ?? '' if (!url.startsWith('http://127.0.0.1:55321') || anonKey.length < 20 || serviceRoleKey.length < 20) { throw new Error('D3RO local Supabase credentials for port 55321 are required') } const options = { auth: { persistSession: false, autoRefreshToken: false, detectSessionInUrl: false } } const service = createClient(url, serviceRoleKey, options) const anonymous = createClient(url, anonKey, options) const suffix = randomUUID() const createdUserIds = [] let assertions = 0 function checked(value, message) { assert.ok(value, message) assertions += 1 } async function createActor(label, role) { const email = `d3ro.admin.${suffix}.${label}@example.com` const { data, error } = await service.auth.admin.createUser({ email, password: `D3ro-${suffix}-${label}-Strong!`, email_confirm: true, app_metadata: { role }, user_metadata: { name: label } }) assert.equal(error, null, `${label} creation failed: ${error?.message ?? ''}`) createdUserIds.push(data.user.id) const profileUpdate = await service.from('profiles').update({ role }).eq('id', data.user.id) assert.equal(profileUpdate.error, null, `${label} profile role setup failed`) return { id: data.user.id, email } } function requireSuccess(result, label) { assert.equal(result.error, null, `${label}: ${result.error?.message ?? 'unknown error'}`) checked(result.data?.success === true, `${label}: success response missing`) return result.data } function requireFailure(result, pattern, label) { assert.ok(result.error, `${label}: unexpectedly succeeded`) assert.match(`${result.error.code ?? ''} ${result.error.message ?? ''}`, pattern, `${label}: wrong error`) assertions += 1 } try { const superAdmin = await createActor('super', 'super_admin') const admin = await createActor('admin', 'admin') const manager = await createActor('manager', 'manager') const target = await createActor('target', 'user') requireFailure(await anonymous.rpc('admin_change_user_role_v1', { p_actor_email: admin.email, p_idempotency_key: randomUUID(), p_target_user_id: target.id, p_new_role: 'manager', p_memo: 'anonymous bypass attempt' }), /permission denied|42501/i, 'anonymous RPC execution') requireFailure(await service.rpc('admin_change_user_role_v1', { p_actor_email: manager.email, p_idempotency_key: randomUUID(), p_target_user_id: target.id, p_new_role: 'manager', p_memo: 'manager escalation attempt' }), /insufficient_admin_role|42501/i, 'manager role mutation') const roleKey = randomUUID() const roleArgs = { p_actor_email: admin.email, p_idempotency_key: roleKey, p_target_user_id: target.id, p_new_role: 'manager', p_memo: 'verified customer support assignment' } const roleChanged = requireSuccess(await service.rpc('admin_change_user_role_v1', roleArgs), 'admin role change') const roleReplayed = requireSuccess(await service.rpc('admin_change_user_role_v1', roleArgs), 'role idempotent replay') checked(JSON.stringify(roleChanged) === JSON.stringify(roleReplayed), 'role replay response changed') const [{ data: targetProfile }, { data: targetAuth }, { count: roleAuditCount }] = await Promise.all([ service.from('profiles').select('role').eq('id', target.id).single(), service.auth.admin.getUserById(target.id), service.from('audit_log').select('id', { count: 'exact', head: true }).eq('admin_id', admin.id).eq('action', 'user.role_change').eq('target_id', target.id) ]) checked(targetProfile?.role === 'manager', 'profile role was not updated') checked(targetAuth?.user?.app_metadata?.role === 'manager', 'auth app_metadata role was not updated') checked(roleAuditCount === 1, 'idempotent role replay duplicated audit rows') requireFailure(await service.rpc('admin_change_user_role_v1', { ...roleArgs, p_memo: 'different request with reused key' }), /idempotency_key_reused|22023/i, 'role idempotency mismatch') requireFailure(await service.rpc('admin_change_user_role_v1', { p_actor_email: admin.email, p_idempotency_key: randomUUID(), p_target_user_id: target.id, p_new_role: 'admin', p_memo: 'unauthorized privileged assignment' }), /super_admin_required|42501/i, 'admin privileged role assignment') requireSuccess(await service.rpc('admin_change_user_role_v1', { p_actor_email: superAdmin.email, p_idempotency_key: randomUUID(), p_target_user_id: target.id, p_new_role: 'admin', p_memo: 'approved privileged assignment' }), 'super admin privileged assignment') await service.from('subscriptions').delete().eq('user_id', target.id) const subscriptionKey = randomUUID() const createArgs = { p_actor_email: admin.email, p_idempotency_key: subscriptionKey, p_action: 'create', p_user_id: target.id, p_tier: 'pro', p_status: 'active', p_overage_credits: 25, p_admin_note: 'verified support grant', p_memo: 'approved manual subscription grant' } const createdSubscription = requireSuccess(await service.rpc('admin_mutate_subscription_v1', createArgs), 'subscription create') checked(!JSON.stringify(createdSubscription).includes('provider_resource_id'), 'subscription RPC exposed provider resource id') checked(!JSON.stringify(createdSubscription).includes('payple_payer_id'), 'subscription RPC exposed Payple payer id') requireSuccess(await service.rpc('admin_mutate_subscription_v1', createArgs), 'subscription create replay') const { count: createAuditCount } = await service.from('audit_log').select('id', { count: 'exact', head: true }) .eq('admin_id', admin.id).eq('action', 'subscription.create').eq('target_id', target.id) checked(createAuditCount === 1, 'subscription replay duplicated audit rows') requireSuccess(await service.rpc('admin_mutate_subscription_v1', { p_actor_email: manager.email, p_idempotency_key: randomUUID(), p_action: 'update', p_user_id: target.id, p_tier: 'pro_plus', p_status: 'active', p_overage_credits: 50, p_memo: 'customer support entitlement correction' }), 'manager subscription update') const [{ data: updatedSubscription }, { data: updatedProfile }] = await Promise.all([ service.from('subscriptions').select('tier, overage_credits').eq('user_id', target.id).single(), service.from('profiles').select('tier').eq('id', target.id).single() ]) checked(updatedSubscription?.tier === 'pro_plus' && updatedSubscription?.overage_credits === 50, 'subscription update was not persisted') checked(updatedProfile?.tier === 'pro_plus', 'profile tier was not synchronized') requireFailure(await service.rpc('admin_mutate_subscription_v1', { p_actor_email: manager.email, p_idempotency_key: randomUUID(), p_action: 'delete', p_user_id: target.id, p_memo: 'manager delete attempt' }), /admin_role_required|42501/i, 'manager subscription delete') requireFailure(await service.rpc('admin_mutate_subscription_v1', { p_actor_email: admin.email, p_idempotency_key: randomUUID(), p_action: 'update', p_user_id: target.id, p_overage_credits: -1, p_memo: 'invalid negative credit mutation' }), /invalid_overage_credits|22023/i, 'negative credits validation') const { data: unchanged } = await service.from('subscriptions').select('overage_credits').eq('user_id', target.id).single() checked(unchanged?.overage_credits === 50, 'failed mutation changed subscription data') requireSuccess(await service.rpc('admin_mutate_subscription_v1', { p_actor_email: admin.email, p_idempotency_key: randomUUID(), p_action: 'delete', p_user_id: target.id, p_memo: 'approved subscription retirement' }), 'admin subscription soft delete') const [{ data: deletedSubscription }, { data: deletedProfile }] = await Promise.all([ service.from('subscriptions').select('tier, status').eq('user_id', target.id).single(), service.from('profiles').select('tier').eq('id', target.id).single() ]) checked(deletedSubscription?.tier === 'free' && deletedSubscription?.status === 'expired', 'soft delete state is invalid') checked(deletedProfile?.tier === 'free', 'soft delete did not synchronize profile tier') console.log(`admin management integration: ${assertions} assertions passed`) } finally { if (createdUserIds.length > 0) { await service.from('audit_log').delete().in('admin_id', createdUserIds) await service.from('admin_operation_requests').delete().in('actor_id', createdUserIds) for (const userId of createdUserIds.reverse()) await service.auth.admin.deleteUser(userId) } }