mcp-advisors.test.ts 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. import { beforeEach, describe, expect, it, vi } from 'vitest'
  2. import { DEFAULT_EXPOSED_SCHEMAS } from '@/lib/api/self-hosted/constants'
  3. import { getDebuggingOperations } from '@/lib/api/self-hosted/mcp'
  4. const mockGetLints = vi.fn()
  5. // Mock getLints to capture what arguments the MCP operations pass
  6. vi.mock('@/lib/api/self-hosted/lints', () => ({
  7. getLints: (...args: unknown[]) => mockGetLints(...args),
  8. }))
  9. // Mock getProjectSettings to avoid assertSelfHosted() check
  10. vi.mock('@/lib/api/self-hosted/settings', () => ({
  11. getProjectSettings: () => ({
  12. app_config: {
  13. db_schema: 'public',
  14. endpoint: 'localhost',
  15. protocol: 'http',
  16. },
  17. service_api_keys: [{ api_key: 'test', name: 'anon key', tags: 'anon' }],
  18. }),
  19. }))
  20. describe('MCP advisor operations pass exposedSchemas to getLints', () => {
  21. const headers = { Authorization: 'Bearer test' }
  22. beforeEach(() => {
  23. vi.clearAllMocks()
  24. mockGetLints.mockResolvedValue({
  25. data: [
  26. {
  27. name: 'rls_disabled_in_public',
  28. title: 'RLS Disabled in Public',
  29. level: 'ERROR',
  30. categories: ['SECURITY'],
  31. description: 'test',
  32. detail: 'test',
  33. remediation: 'test',
  34. metadata: {},
  35. cache_key: 'test',
  36. },
  37. {
  38. name: 'unindexed_foreign_keys',
  39. title: 'Unindexed foreign keys',
  40. level: 'INFO',
  41. categories: ['PERFORMANCE'],
  42. description: 'test',
  43. detail: 'test',
  44. remediation: 'test',
  45. metadata: {},
  46. cache_key: 'test',
  47. },
  48. ],
  49. error: undefined,
  50. })
  51. })
  52. it('getSecurityAdvisors should pass exposedSchemas to getLints', async () => {
  53. const ops = getDebuggingOperations({ headers })
  54. await ops.getSecurityAdvisors('test-project')
  55. expect(mockGetLints).toHaveBeenCalledOnce()
  56. const callArgs = mockGetLints.mock.calls[0][0]
  57. expect(callArgs).toHaveProperty('exposedSchemas')
  58. expect(callArgs.exposedSchemas).toBeTruthy()
  59. })
  60. it('getPerformanceAdvisors should pass exposedSchemas to getLints', async () => {
  61. const ops = getDebuggingOperations({ headers })
  62. await ops.getPerformanceAdvisors('test-project')
  63. expect(mockGetLints).toHaveBeenCalledOnce()
  64. const callArgs = mockGetLints.mock.calls[0][0]
  65. expect(callArgs).toHaveProperty('exposedSchemas')
  66. expect(callArgs.exposedSchemas).toBeTruthy()
  67. })
  68. it('should use DEFAULT_EXPOSED_SCHEMAS constant', async () => {
  69. const ops = getDebuggingOperations({ headers })
  70. await ops.getSecurityAdvisors('test-project')
  71. const callArgs = mockGetLints.mock.calls[0][0]
  72. expect(callArgs.exposedSchemas).toBe(DEFAULT_EXPOSED_SCHEMAS)
  73. })
  74. it('getSecurityAdvisors should filter to SECURITY category', async () => {
  75. const ops = getDebuggingOperations({ headers })
  76. const result = await ops.getSecurityAdvisors('test-project')
  77. expect(result).toHaveLength(1)
  78. expect((result as Array<{ name: string }>)[0].name).toBe('rls_disabled_in_public')
  79. })
  80. it('getPerformanceAdvisors should filter to PERFORMANCE category', async () => {
  81. const ops = getDebuggingOperations({ headers })
  82. const result = await ops.getPerformanceAdvisors('test-project')
  83. expect(result).toHaveLength(1)
  84. expect((result as Array<{ name: string }>)[0].name).toBe('unindexed_foreign_keys')
  85. })
  86. })