import { beforeEach, describe, expect, it, vi } from 'vitest' const { mockCheckWorkspaceAccess, dbState } = vi.hoisted(() => ({ mockCheckWorkspaceAccess: vi.fn(), dbState: { results: [] as any[][] }, })) function makeChain() { const chain: any = {} chain.from = vi.fn(() => chain) chain.where = vi.fn(() => chain) chain.limit = vi.fn(() => Promise.resolve(dbState.results.shift() ?? [])) return chain } vi.mock('@sim/db', () => ({ db: { select: vi.fn(() => makeChain()) }, })) vi.mock('@sim/db/schema', () => ({ credentialTypeEnum: { enumValues: ['oauth', 'env_workspace', 'env_personal', 'service_account'], }, credential: { id: 'credential.id', workspaceId: 'credential.workspaceId', type: 'credential.type', }, credentialMember: { credentialId: 'credentialMember.credentialId', userId: 'credentialMember.userId', status: 'credentialMember.status', role: 'credentialMember.role', }, })) vi.mock('drizzle-orm', () => ({ and: vi.fn((...args: unknown[]) => ({ and: args })), eq: vi.fn((a: unknown, b: unknown) => ({ eq: [a, b] })), inArray: vi.fn((a: unknown, b: unknown) => ({ inArray: [a, b] })), })) vi.mock('@/lib/workspaces/permissions/utils', () => ({ checkWorkspaceAccess: mockCheckWorkspaceAccess, })) import { getCredentialActorContext } from '@/lib/credentials/access' const workspaceAdminAccess = { hasAccess: true, canWrite: true, canAdmin: true } const noWorkspaceAccess = { hasAccess: false, canWrite: false, canAdmin: false } describe('getCredentialActorContext', () => { beforeEach(() => { vi.clearAllMocks() dbState.results = [] }) it('treats an explicit credential admin membership as admin', async () => { dbState.results = [[{ id: 'c1', workspaceId: 'ws', type: 'oauth' }], [{ role: 'admin' }]] mockCheckWorkspaceAccess.mockResolvedValue({ hasAccess: true, canWrite: true, canAdmin: false }) const ctx = await getCredentialActorContext('c1', 'user1') expect(ctx.isAdmin).toBe(true) }) it('derives credential admin from workspace admin for shared credentials', async () => { dbState.results = [[{ id: 'c1', workspaceId: 'ws', type: 'oauth' }], []] mockCheckWorkspaceAccess.mockResolvedValue(workspaceAdminAccess) const ctx = await getCredentialActorContext('c1', 'admin-user') expect(ctx.isAdmin).toBe(true) }) it('does not derive credential admin on personal env credentials', async () => { dbState.results = [[{ id: 'c1', workspaceId: 'ws', type: 'env_personal' }], []] mockCheckWorkspaceAccess.mockResolvedValue(workspaceAdminAccess) const ctx = await getCredentialActorContext('c1', 'admin-user') expect(ctx.isAdmin).toBe(false) }) it('is not admin for a non-admin without membership', async () => { dbState.results = [[{ id: 'c1', workspaceId: 'ws', type: 'oauth' }], []] mockCheckWorkspaceAccess.mockResolvedValue({ hasAccess: true, canWrite: false, canAdmin: false, }) const ctx = await getCredentialActorContext('c1', 'reader-user') expect(ctx.isAdmin).toBe(false) }) it('returns empty context when the credential does not exist', async () => { dbState.results = [[]] const ctx = await getCredentialActorContext('missing', 'user1') expect(ctx.credential).toBeNull() expect(ctx.isAdmin).toBe(false) expect(mockCheckWorkspaceAccess).not.toHaveBeenCalled() }) it('exposes workspace access flags from checkWorkspaceAccess', async () => { dbState.results = [[{ id: 'c1', workspaceId: 'ws', type: 'oauth' }], []] mockCheckWorkspaceAccess.mockResolvedValue(noWorkspaceAccess) const ctx = await getCredentialActorContext('c1', 'outsider') expect(ctx.hasWorkspaceAccess).toBe(false) expect(ctx.canWriteWorkspace).toBe(false) expect(ctx.isAdmin).toBe(false) }) })