| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- import { describe, expect, it } from 'vitest'
- import { getTableAdmonitionMessage, getTableDataApiStatus } from './PolicyTableRow.utils'
- import type { TableApiAccessData } from '@/data/privileges/table-api-access-query'
- import type { ApiPrivilegesByRole } from '@/lib/data-api-types'
- const FULL_PRIVILEGES: ApiPrivilegesByRole = {
- anon: ['SELECT', 'INSERT', 'UPDATE', 'DELETE'],
- authenticated: ['SELECT', 'INSERT', 'UPDATE', 'DELETE'],
- service_role: ['SELECT', 'INSERT', 'UPDATE', 'DELETE'],
- }
- const PARTIAL_PRIVILEGES: ApiPrivilegesByRole = {
- anon: ['SELECT'],
- authenticated: [],
- service_role: ['SELECT', 'INSERT', 'UPDATE', 'DELETE'],
- }
- const grantedAccess: TableApiAccessData = {
- apiAccessType: 'access',
- grantStatus: 'granted',
- privileges: FULL_PRIVILEGES,
- }
- const customAccess: TableApiAccessData = {
- apiAccessType: 'access',
- grantStatus: 'custom',
- privileges: PARTIAL_PRIVILEGES,
- }
- const noGrants: TableApiAccessData = { apiAccessType: 'exposed-schema-no-grants' }
- const schemaNotExposedData: TableApiAccessData = { apiAccessType: 'none' }
- describe('getTableDataApiStatus', () => {
- it('returns schema-not-exposed when the schema is not in the exposed list', () => {
- const status = getTableDataApiStatus({
- isSchemaExposed: false,
- apiAccessData: grantedAccess,
- isRLSEnabled: true,
- policiesCount: 1,
- })
- expect(status).toBe('schema-not-exposed')
- })
- it('returns no-grants when schema is exposed but no API roles have privileges', () => {
- const status = getTableDataApiStatus({
- isSchemaExposed: true,
- apiAccessData: noGrants,
- isRLSEnabled: true,
- policiesCount: 0,
- })
- expect(status).toBe('no-grants')
- })
- it('returns custom-grants for partial/non-standard grants — even if RLS is off', () => {
- const status = getTableDataApiStatus({
- isSchemaExposed: true,
- apiAccessData: customAccess,
- isRLSEnabled: false,
- policiesCount: 0,
- })
- expect(status).toBe('custom-grants')
- })
- it('returns publicly-readable when fully granted and RLS is off', () => {
- const status = getTableDataApiStatus({
- isSchemaExposed: true,
- apiAccessData: grantedAccess,
- isRLSEnabled: false,
- policiesCount: 3,
- })
- expect(status).toBe('publicly-readable')
- })
- it('returns locked-by-rls when fully granted + RLS on + no policies', () => {
- const status = getTableDataApiStatus({
- isSchemaExposed: true,
- apiAccessData: grantedAccess,
- isRLSEnabled: true,
- policiesCount: 0,
- })
- expect(status).toBe('locked-by-rls')
- })
- it('returns secured when fully granted + RLS on + policies exist', () => {
- const status = getTableDataApiStatus({
- isSchemaExposed: true,
- apiAccessData: grantedAccess,
- isRLSEnabled: true,
- policiesCount: 2,
- })
- expect(status).toBe('secured')
- })
- it('returns unknown when apiAccessData is still loading or errored', () => {
- // apiAccessData is undefined during loading AND on query error (isPending flips false
- // but data stays undefined). We must not fall through to 'schema-not-exposed' — that
- // would tell the user to reconfigure API settings for a schema that is in fact exposed.
- const status = getTableDataApiStatus({
- isSchemaExposed: true,
- apiAccessData: undefined,
- isRLSEnabled: true,
- policiesCount: 0,
- })
- expect(status).toBe('unknown')
- })
- it('returns unknown when apiAccessData reports apiAccessType=none on an exposed schema', () => {
- // Defensive: the query shouldn't emit apiAccessType=none when schema is exposed,
- // but if it does we still don't want the false "schema not exposed" admonition.
- const status = getTableDataApiStatus({
- isSchemaExposed: true,
- apiAccessData: schemaNotExposedData,
- isRLSEnabled: true,
- policiesCount: 0,
- })
- expect(status).toBe('unknown')
- })
- it('isSchemaExposed=false wins over any apiAccessData value', () => {
- const status = getTableDataApiStatus({
- isSchemaExposed: false,
- apiAccessData: noGrants,
- isRLSEnabled: true,
- policiesCount: 0,
- })
- expect(status).toBe('schema-not-exposed')
- })
- it('custom-grants wins over RLS state — we never claim public-readable for partial grants', () => {
- const rlsOff = getTableDataApiStatus({
- isSchemaExposed: true,
- apiAccessData: customAccess,
- isRLSEnabled: false,
- policiesCount: 0,
- })
- const rlsOnNoPolicies = getTableDataApiStatus({
- isSchemaExposed: true,
- apiAccessData: customAccess,
- isRLSEnabled: true,
- policiesCount: 0,
- })
- expect(rlsOff).toBe('custom-grants')
- expect(rlsOnNoPolicies).toBe('custom-grants')
- })
- })
- describe('getTableAdmonitionMessage', () => {
- it('returns the custom-grants copy', () => {
- expect(getTableAdmonitionMessage('custom-grants')).toBe(
- 'This table has custom Data API permissions — access may be restricted for some roles or operations.'
- )
- })
- it('returns the no-grants copy', () => {
- expect(getTableAdmonitionMessage('no-grants')).toBe(
- 'This table cannot be accessed via the Data API. Enable access in your project’s Data API settings.'
- )
- })
- it('returns the publicly-readable copy', () => {
- expect(getTableAdmonitionMessage('publicly-readable')).toBe(
- 'This table can be accessed by anyone via the Data API as RLS is disabled.'
- )
- })
- it('returns the locked-by-rls copy', () => {
- expect(getTableAdmonitionMessage('locked-by-rls')).toBe(
- 'No data will be returned via the Data API as no RLS policies exist on this table.'
- )
- })
- it('returns null for secured — no admonition needed', () => {
- expect(getTableAdmonitionMessage('secured')).toBeNull()
- })
- it('returns null for schema-not-exposed — handled by a separate admonition with a link', () => {
- expect(getTableAdmonitionMessage('schema-not-exposed')).toBeNull()
- })
- it('returns null for unknown — caller should stay silent during loading/errored state', () => {
- expect(getTableAdmonitionMessage('unknown')).toBeNull()
- })
- })
|