mirror of
https://github.com/supabase/supabase.git
synced 2026-09-06 09:59:03 +08:00
Multigres (High Availability) projects ship with legacy API keys disabled and the management API rejects re-enabling them, so the Dashboard should not surface them at all. Hides the "Legacy anon, service_role API keys" tab, renders an empty state on the legacy page for direct URL access, and drops the "Copy anonymous API key" / "Copy service API key" commands from the command menu. Non-HA projects are unchanged. Fixes FE-4276 <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * High Availability projects now hide legacy API key navigation and commands. * Legacy API key settings display an unavailable message for High Availability projects. * Publishable and secret key options remain available where supported. * Other projects continue to provide access to supported legacy API key options. * **Bug Fixes** * Prevented unsupported legacy API key controls from appearing on High Availability projects. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
117 lines
3.7 KiB
TypeScript
117 lines
3.7 KiB
TypeScript
import { screen } from '@testing-library/react'
|
|
import userEvent from '@testing-library/user-event'
|
|
import type { components } from 'api-types'
|
|
import { HttpResponse } from 'msw'
|
|
import { Button } from 'ui'
|
|
import { useCurrentPage, useSetPage } from 'ui-patterns/CommandMenu'
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
|
|
import { useApiKeysCommands } from './ApiKeys'
|
|
import { customRender } from '@/tests/lib/custom-render'
|
|
import { addAPIMock } from '@/tests/lib/msw'
|
|
|
|
type ApiKeyResponse = components['schemas']['ApiKeyResponse']
|
|
|
|
const { mockUseAsyncCheckPermissions, mockUseHighAvailability, mockUseSelectedProjectQuery } =
|
|
vi.hoisted(() => ({
|
|
mockUseAsyncCheckPermissions: vi.fn(),
|
|
mockUseHighAvailability: vi.fn(),
|
|
mockUseSelectedProjectQuery: vi.fn(),
|
|
}))
|
|
|
|
vi.mock('@/hooks/misc/useCheckPermissions', () => ({
|
|
useAsyncCheckPermissions: mockUseAsyncCheckPermissions,
|
|
}))
|
|
|
|
vi.mock('@/hooks/misc/useHighAvailability', () => ({
|
|
useHighAvailability: mockUseHighAvailability,
|
|
}))
|
|
|
|
vi.mock('@/hooks/misc/useSelectedProject', () => ({
|
|
useSelectedProjectQuery: mockUseSelectedProjectQuery,
|
|
}))
|
|
|
|
const API_KEYS: ApiKeyResponse[] = [
|
|
{ api_key: 'anon-key', name: 'anon', type: 'legacy' },
|
|
{ api_key: 'service-key', name: 'service_role', type: 'legacy' },
|
|
{
|
|
api_key: 'publishable-key',
|
|
hash: 'hash',
|
|
id: 'publishable-id',
|
|
inserted_at: '2025-02-16T22:24:42.115195Z',
|
|
name: 'default',
|
|
type: 'publishable',
|
|
},
|
|
{
|
|
api_key: 'secret-key',
|
|
hash: 'hash',
|
|
id: 'secret-id',
|
|
inserted_at: '2025-02-16T22:24:42.115195Z',
|
|
name: 'sb_secret',
|
|
type: 'secret',
|
|
},
|
|
]
|
|
|
|
/** Renders the API keys command page so its commands can be asserted on. */
|
|
const CommandPageHarness = () => {
|
|
useApiKeysCommands()
|
|
const setPage = useSetPage()
|
|
const page = useCurrentPage()
|
|
const commands =
|
|
page && 'sections' in page ? page.sections.flatMap((section) => section.commands) : []
|
|
|
|
return (
|
|
<>
|
|
<Button onClick={() => setPage('API Keys')}>Open API keys page</Button>
|
|
<ul>
|
|
{commands.map((command) => (
|
|
<li key={command.id}>{command.name}</li>
|
|
))}
|
|
</ul>
|
|
</>
|
|
)
|
|
}
|
|
|
|
async function renderCommandPage() {
|
|
customRender(<CommandPageHarness />)
|
|
|
|
await userEvent.click(screen.getByRole('button', { name: 'Open API keys page' }))
|
|
}
|
|
|
|
describe('useApiKeysCommands', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks()
|
|
|
|
mockUseAsyncCheckPermissions.mockReturnValue({ can: true })
|
|
mockUseSelectedProjectQuery.mockReturnValue({
|
|
data: { id: 1, ref: 'default', name: 'default' },
|
|
})
|
|
mockUseHighAvailability.mockReturnValue({ isHighAvailability: false, isPending: false })
|
|
addAPIMock({
|
|
method: 'get',
|
|
path: '/v1/projects/:ref/api-keys',
|
|
response: () => HttpResponse.json<ApiKeyResponse[]>(API_KEYS),
|
|
})
|
|
})
|
|
|
|
it('omits the legacy key commands on High Availability projects', async () => {
|
|
mockUseHighAvailability.mockReturnValue({ isHighAvailability: true, isPending: false })
|
|
|
|
await renderCommandPage()
|
|
|
|
expect(await screen.findByText('Copy publishable key')).toBeInTheDocument()
|
|
expect(screen.getByText('Copy secret key (sb_secret)')).toBeInTheDocument()
|
|
expect(screen.queryByText('Copy anonymous API key')).not.toBeInTheDocument()
|
|
expect(screen.queryByText('Copy service API key')).not.toBeInTheDocument()
|
|
})
|
|
|
|
it('includes the legacy key commands on other projects', async () => {
|
|
await renderCommandPage()
|
|
|
|
expect(await screen.findByText('Copy anonymous API key')).toBeInTheDocument()
|
|
expect(screen.getByText('Copy service API key')).toBeInTheDocument()
|
|
expect(screen.getByText('Copy publishable key')).toBeInTheDocument()
|
|
expect(screen.getByText('Copy secret key (sb_secret)')).toBeInTheDocument()
|
|
})
|
|
})
|