mirror of
https://github.com/supabase/supabase.git
synced 2026-09-06 18:11:51 +08:00
## New Features - Initial work for showing configuration drift in Studio - This only works for Github-connected projects and it'll show a banner if the project state differs from the git-tracked `config.toml` - Currently behind a feature-flag `ConfigDrift`, enabled on local and staging. - There might be drift shown without changing any setting, this is work-in-progress. <img width="1217" height="1195" alt="Screenshot 2026-08-19 at 23 12 10" src="https://github.com/user-attachments/assets/fb0b18d8-1a93-4595-85cc-e8b8a3462847" /> ## How to test 1. Connect a project to a Github repo 2. Resync the branch on `/dashboard/project/_/branches`. This will trigger deployment of the `config.toml` on your project 3. Change some settings (I recommend `dashboard/project/_/auth/providers` 4. A banner should appear on all project pages with a link ## Tests - Added coverage for configuration conversion, normalization, matching, drift detection, and unmanaged settings. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
145 lines
5.3 KiB
TypeScript
145 lines
5.3 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
|
|
import { getConfigDriftSummary } from './github-config-drift'
|
|
|
|
describe('getConfigDriftSummary', () => {
|
|
it('counts a matching field as managed', () => {
|
|
const summary = getConfigDriftSummary({
|
|
dashboardConfig: { api: { max_rows: 1000 } },
|
|
githubConfig: { api: { max_rows: 1000 } },
|
|
})
|
|
|
|
expect(summary).toEqual({ managedCount: 1, driftedFields: [], unmanagedFields: [] })
|
|
})
|
|
|
|
it('reports a differing field as drifted, keeping raw (non-normalized) display values', () => {
|
|
const summary = getConfigDriftSummary({
|
|
dashboardConfig: { auth: { enable_signup: false } },
|
|
githubConfig: { auth: { enable_signup: true } },
|
|
})
|
|
|
|
expect(summary.managedCount).toBe(0)
|
|
expect(summary.driftedFields).toEqual([
|
|
{
|
|
section: 'auth',
|
|
configPath: 'auth.enable_signup',
|
|
settingHref: expect.any(Function),
|
|
dashboardValue: false,
|
|
githubValue: true,
|
|
},
|
|
])
|
|
})
|
|
|
|
it('excludes a secret field even when dashboard and config.toml values match', () => {
|
|
const summary = getConfigDriftSummary({
|
|
dashboardConfig: { auth: { jwt_secret: 'shh' } },
|
|
githubConfig: { auth: { jwt_secret: 'shh' } },
|
|
})
|
|
|
|
expect(summary).toEqual({ managedCount: 0, driftedFields: [], unmanagedFields: [] })
|
|
})
|
|
|
|
it('reports a field absent from config.toml as unmanaged', () => {
|
|
const summary = getConfigDriftSummary({
|
|
dashboardConfig: { auth: { site_url: 'https://example.com' } },
|
|
githubConfig: { auth: {} },
|
|
})
|
|
|
|
expect(summary).toEqual({
|
|
managedCount: 0,
|
|
driftedFields: [],
|
|
unmanagedFields: [
|
|
{ section: 'auth', configPath: 'auth.site_url', dashboardValue: 'https://example.com' },
|
|
],
|
|
})
|
|
})
|
|
|
|
it('falls back to the hosted default when config.toml is code-owned and silent on the field', () => {
|
|
const atDefault = getConfigDriftSummary({
|
|
dashboardConfig: { auth: { site_url: 'http://localhost:3000' } },
|
|
githubConfig: { auth: {}, config_source: 'code' },
|
|
})
|
|
expect(atDefault).toEqual({
|
|
managedCount: 0,
|
|
driftedFields: [],
|
|
unmanagedFields: [
|
|
{ section: 'auth', configPath: 'auth.site_url', dashboardValue: 'http://localhost:3000' },
|
|
],
|
|
})
|
|
|
|
const drifted = getConfigDriftSummary({
|
|
dashboardConfig: { auth: { site_url: 'https://example.com' } },
|
|
githubConfig: { auth: {}, config_source: 'code' },
|
|
})
|
|
expect(drifted.driftedFields).toHaveLength(1)
|
|
expect(drifted.driftedFields[0].githubValue).toBe('http://localhost:3000')
|
|
})
|
|
|
|
describe('auth.additional_redirect_urls', () => {
|
|
it('counts an identical list as managed', () => {
|
|
const summary = getConfigDriftSummary({
|
|
dashboardConfig: { auth: { additional_redirect_urls: ['https://a.com', 'https://b.com'] } },
|
|
githubConfig: { auth: { additional_redirect_urls: ['https://a.com', 'https://b.com'] } },
|
|
})
|
|
|
|
expect(summary).toEqual({ managedCount: 1, driftedFields: [], unmanagedFields: [] })
|
|
})
|
|
|
|
it('counts a list that differs only in order as managed', () => {
|
|
const summary = getConfigDriftSummary({
|
|
// `convertProjectConfigToGitHubConfig` sorts the dashboard list and `normalizeGithubValue`
|
|
// sorts the config.toml one, so ordering can never register as drift.
|
|
dashboardConfig: { auth: { additional_redirect_urls: ['https://a.com', 'https://b.com'] } },
|
|
githubConfig: { auth: { additional_redirect_urls: ['https://b.com', 'https://a.com'] } },
|
|
})
|
|
|
|
expect(summary).toEqual({ managedCount: 1, driftedFields: [], unmanagedFields: [] })
|
|
})
|
|
|
|
it('ignores duplicate and untrimmed entries in config.toml', () => {
|
|
const summary = getConfigDriftSummary({
|
|
dashboardConfig: { auth: { additional_redirect_urls: ['https://a.com'] } },
|
|
githubConfig: {
|
|
auth: { additional_redirect_urls: [' https://a.com ', 'https://a.com', ''] },
|
|
},
|
|
})
|
|
|
|
expect(summary.managedCount).toBe(1)
|
|
expect(summary.driftedFields).toEqual([])
|
|
})
|
|
|
|
it('reports a list the dashboard adds to as drifted, keeping the raw dashboard list', () => {
|
|
const summary = getConfigDriftSummary({
|
|
dashboardConfig: { auth: { additional_redirect_urls: ['https://a.com', 'https://b.com'] } },
|
|
githubConfig: { auth: { additional_redirect_urls: ['https://a.com'] } },
|
|
})
|
|
|
|
expect(summary.driftedFields).toEqual([
|
|
{
|
|
section: 'auth',
|
|
configPath: 'auth.additional_redirect_urls',
|
|
settingHref: expect.any(Function),
|
|
dashboardValue: ['https://a.com', 'https://b.com'],
|
|
githubValue: ['https://a.com'],
|
|
},
|
|
])
|
|
})
|
|
|
|
it('compares against the empty hosted default when code-owned config.toml is silent', () => {
|
|
const atDefault = getConfigDriftSummary({
|
|
dashboardConfig: { auth: { additional_redirect_urls: [] } },
|
|
githubConfig: { auth: {}, config_source: 'code' },
|
|
})
|
|
expect(atDefault.managedCount).toBe(0)
|
|
expect(atDefault.driftedFields).toEqual([])
|
|
|
|
const drifted = getConfigDriftSummary({
|
|
dashboardConfig: { auth: { additional_redirect_urls: ['https://a.com'] } },
|
|
githubConfig: { auth: {}, config_source: 'code' },
|
|
})
|
|
expect(drifted.driftedFields).toHaveLength(1)
|
|
expect(drifted.driftedFields[0].githubValue).toEqual([])
|
|
})
|
|
})
|
|
})
|