import assert from 'node:assert/strict' import { createClient } from '@supabase/supabase-js' const supabaseUrl = 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 (!supabaseUrl.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 clientOptions = { auth: { persistSession: false, autoRefreshToken: false, detectSessionInUrl: false }, } const admin = createClient(supabaseUrl, serviceRoleKey, clientOptions) const ownerClient = createClient(supabaseUrl, anonKey, clientOptions) const adminClient = createClient(supabaseUrl, anonKey, clientOptions) const memberClient = createClient(supabaseUrl, anonKey, clientOptions) const suffix = `${Date.now()}-${Math.floor(Math.random() * 1_000_000)}` const password = `D3ro-${suffix}-Strong!` const createdUserIds = [] let assertions = 0 function checked(condition, message) { assert.ok(condition, message) assertions += 1 } async function createDisposableUser(client, marker, name) { const response = await client.auth.signUp({ email: `d3ro.team.${suffix}.${marker}@gmail.com`, password, options: { data: { name } }, }) assert.equal(response.error, null, `Could not create local user ${marker}`) assert.ok(response.data.user && response.data.session, `Local user ${marker} has no session`) createdUserIds.push(response.data.user.id) return response.data.user } function requireRpcSuccess(result, label) { assert.equal(result.error, null, `${label}: ${result.error?.message ?? 'unknown error'}`) assert.ok(result.data, `${label}: response data missing`) return result.data } function requireRpcFailure(result, expectedPattern, label) { assert.ok(result.error, `${label}: request unexpectedly succeeded`) const details = `${result.error.code ?? ''} ${result.error.message ?? ''} ${result.error.details ?? ''}` assert.match(details, expectedPattern, `${label}: unexpected error ${details}`) assertions += 1 } try { const [owner, teamAdmin, member] = await Promise.all([ createDisposableUser(ownerClient, 'owner', 'Owner'), createDisposableUser(adminClient, 'admin', 'Admin'), createDisposableUser(memberClient, 'member', 'Member'), ]) const directTeamInsert = await ownerClient .from('teams') .insert({ name: 'Direct bypass', owner_id: owner.id }) .select('id') checked(directTeamInsert.error !== null, 'Direct team creation bypassed the atomic RPC') const createdTeam = requireRpcSuccess( await ownerClient.rpc('create_team', { team_name: 'Mobile Secure Team' }), 'create_team', ) const teamId = createdTeam.id checked(createdTeam.owner_id === owner.id && createdTeam.role === 'owner', 'Atomic team creation lost owner invariants') const ownerMembership = await ownerClient .from('team_members') .select('role') .eq('team_id', teamId) .eq('user_id', owner.id) .single() checked(ownerMembership.data?.role === 'owner', 'Atomic team creation did not insert owner membership') const outsiderTeamRead = await memberClient.from('teams').select('id').eq('id', teamId) assert.equal(outsiderTeamRead.error, null) checked(outsiderTeamRead.data.length === 0, 'An outsider could read a private team') const directMemberInsert = await ownerClient .from('team_members') .insert({ team_id: teamId, user_id: teamAdmin.id, role: 'owner' }) .select('user_id') checked(directMemberInsert.error !== null, 'Direct team member insertion bypassed the role invariant') const inviteAdmin = requireRpcSuccess(await ownerClient.rpc('create_team_invite', { target_team_id: teamId, invited_email: teamAdmin.email, invited_role: 'admin', }), 'owner admin invitation') checked(inviteAdmin.role === 'admin' && inviteAdmin.duplicate === false, 'Owner admin invitation returned an invalid contract') const duplicateInvite = requireRpcSuccess(await ownerClient.rpc('create_team_invite', { target_team_id: teamId, invited_email: teamAdmin.email.toUpperCase(), invited_role: 'admin', }), 'duplicate invitation') checked(duplicateInvite.id === inviteAdmin.id && duplicateInvite.duplicate === true, 'Duplicate active invitation was not idempotent') requireRpcFailure( await memberClient.rpc('accept_team_invite', { invite_token: inviteAdmin.token }), /invite_email_mismatch|42501/i, 'wrong-account acceptance', ) const acceptedAdmin = requireRpcSuccess( await adminClient.rpc('accept_team_invite', { invite_token: inviteAdmin.token }), 'admin acceptance', ) checked(acceptedAdmin.team_id === teamId && acceptedAdmin.role === 'admin', 'Invitation acceptance assigned the wrong role') const repeatedAcceptance = requireRpcSuccess( await adminClient.rpc('accept_team_invite', { invite_token: inviteAdmin.token }), 'idempotent repeated acceptance', ) checked(repeatedAcceptance.duplicate === true && repeatedAcceptance.already_member === true, 'Repeated acceptance was not idempotent') const adminInviteMember = requireRpcSuccess(await adminClient.rpc('create_team_invite', { target_team_id: teamId, invited_email: member.email, invited_role: 'member', }), 'admin member invitation') checked(adminInviteMember.role === 'member', 'Admin could not create a member invitation') requireRpcFailure(await adminClient.rpc('create_team_invite', { target_team_id: teamId, invited_email: `another-${suffix}@gmail.com`, invited_role: 'admin', }), /owner_required_for_admin_invite|42501/i, 'admin-to-admin invitation') const acceptedMember = requireRpcSuccess( await memberClient.rpc('accept_team_invite', { invite_token: adminInviteMember.token }), 'member acceptance', ) checked(acceptedMember.team_id === teamId && acceptedMember.role === 'member', 'Member invitation acceptance failed') const memberDirectory = requireRpcSuccess( await memberClient.rpc('list_team_members', { target_team_id: teamId }), 'member directory', ) checked(memberDirectory.length === 3, 'A member could not read the complete team directory') checked(memberDirectory.some((row) => row.user_id === owner.id && row.display_name === 'Owner'), 'Limited team profile directory omitted the owner display name') const memberInviteList = requireRpcSuccess( await memberClient.rpc('list_team_invites', { target_team_id: teamId }), 'member invite list', ) checked(Array.isArray(memberInviteList) && memberInviteList.length === 0, 'A regular member could read pending invitations') const ownerInviteList = requireRpcSuccess( await ownerClient.rpc('list_team_invites', { target_team_id: teamId }), 'owner invite list', ) checked(ownerInviteList.every((row) => !Object.hasOwn(row, 'token')), 'Invitation listing leaked bearer tokens') requireRpcFailure(await adminClient.rpc('update_team_member_role', { target_team_id: teamId, member_user_id: member.id, new_role: 'admin', }), /team_owner_required|42501/i, 'admin role escalation') const promoted = requireRpcSuccess(await ownerClient.rpc('update_team_member_role', { target_team_id: teamId, member_user_id: member.id, new_role: 'admin', }), 'owner promotion') checked(promoted.role === 'admin' && promoted.user_id === member.id, 'Owner role update changed the wrong membership') requireRpcFailure(await adminClient.rpc('remove_team_member', { target_team_id: teamId, member_user_id: owner.id, }), /team_owner_cannot_leave|42501/i, 'admin owner removal') requireRpcFailure(await ownerClient.rpc('remove_team_member', { target_team_id: teamId, member_user_id: owner.id, }), /team_owner_cannot_leave|42501/i, 'owner self leave') const removedSelf = requireRpcSuccess(await memberClient.rpc('remove_team_member', { target_team_id: teamId, member_user_id: member.id, }), 'member self leave') checked(removedSelf.removed === true, 'Non-owner could not leave the team') const accessAfterLeave = await memberClient.from('teams').select('id').eq('id', teamId) checked(accessAfterLeave.data?.length === 0, 'A former member retained team read access') const expiringInvite = requireRpcSuccess(await ownerClient.rpc('create_team_invite', { target_team_id: teamId, invited_email: member.email, invited_role: 'member', }), 'expiring invitation') const expireUpdate = await admin .from('team_invites') .update({ expires_at: new Date(Date.now() - 60_000).toISOString() }) .eq('id', expiringInvite.id) assert.equal(expireUpdate.error, null) requireRpcFailure( await memberClient.rpc('accept_team_invite', { invite_token: expiringInvite.token }), /invite_expired|22023/i, 'expired invitation acceptance', ) const cancellableInvite = requireRpcSuccess(await ownerClient.rpc('create_team_invite', { target_team_id: teamId, invited_email: member.email, invited_role: 'member', }), 'replacement invitation') const cancelled = requireRpcSuccess( await ownerClient.rpc('cancel_team_invite', { invite_id: cancellableInvite.id }), 'cancel invitation', ) checked(cancelled.cancelled === true, 'Invitation cancellation did not report removal') requireRpcFailure( await memberClient.rpc('accept_team_invite', { invite_token: cancellableInvite.token }), /invite_not_found|P0002/i, 'cancelled invitation acceptance', ) const deviceA = await ownerClient .from('devices') .insert({ user_id: owner.id, installation_id: 'aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa', platform: 'android', device_name: 'Pixel integration A', app_version: '1.0.0', os_version: 'Android 14', }) .select('id') .single() assert.equal(deviceA.error, null, 'Owner device registration failed') const registrationId = `fcm_${'a'.repeat(128)}` const registeredPush = requireRpcSuccess(await ownerClient.rpc('register_push_registration', { push_device_id: deviceA.data.id, push_provider: 'fcm', registration_id: registrationId, }), 'owner push registration') checked(registeredPush.device_id === deviceA.data.id && registeredPush.provider === 'fcm', 'Push registration lost device/provider association') const hiddenPushRows = await ownerClient.from('push_tokens').select('*') assert.equal(hiddenPushRows.error, null) checked(hiddenPushRows.data.length === 0, 'Client could read its raw push registration secret') const directPushInsert = await ownerClient.from('push_tokens').insert({ user_id: owner.id, token: `fcm_${'b'.repeat(128)}`, platform: 'android', device_id: deviceA.data.id, provider: 'fcm', }) checked(directPushInsert.error !== null, 'Direct push token insertion bypassed the registration RPC') const deviceB = await adminClient .from('devices') .insert({ user_id: teamAdmin.id, installation_id: 'bbbbbbbb-bbbb-4bbb-8bbb-bbbbbbbbbbbb', platform: 'android', device_name: 'Pixel integration B', app_version: '1.0.0', os_version: 'Android 14', }) .select('id') .single() assert.equal(deviceB.error, null, 'Admin device registration failed') requireRpcFailure(await adminClient.rpc('register_push_registration', { push_device_id: deviceB.data.id, push_provider: 'fcm', registration_id: registrationId, }), /push_registration_owned_by_other_user|23505/i, 'cross-account token takeover') requireRpcFailure(await adminClient.rpc('register_push_registration', { push_device_id: deviceA.data.id, push_provider: 'fcm', registration_id: `fcm_${'c'.repeat(128)}`, }), /active_device_not_found|P0002/i, 'cross-account device registration') const unregisteredPush = requireRpcSuccess(await ownerClient.rpc('unregister_push_registration', { push_device_id: deviceA.data.id, }), 'push unregister') checked(unregisteredPush.removed === true, 'Push unregister did not remove the owned registration') const revokedDevice = requireRpcSuccess(await ownerClient.rpc('revoke_device', { target_device_id: deviceA.data.id, }), 'device revocation') checked(revokedDevice.id === deviceA.data.id && revokedDevice.revoked_at !== null, 'Device revocation did not persist') const reviveDevice = await ownerClient .from('devices') .update({ revoked_at: null }) .eq('id', deviceA.data.id) .select('id') checked(reviveDevice.error !== null || reviveDevice.data.length === 0, 'A client revived a permanently revoked device') requireRpcFailure(await ownerClient.rpc('register_push_registration', { push_device_id: deviceA.data.id, push_provider: 'fcm', registration_id: `fcm_${'d'.repeat(128)}`, }), /active_device_not_found|P0002/i, 'revoked device push registration') const adminRename = await adminClient .from('teams') .update({ name: 'Unauthorized rename' }) .eq('id', teamId) .select('id') assert.equal(adminRename.error, null) checked(adminRename.data.length === 0, 'A non-owner renamed the team') console.log(`teams/push local integration passed: ${assertions} assertions`) } finally { await Promise.allSettled(createdUserIds.map((userId) => admin.auth.admin.deleteUser(userId))) }