mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
feat(studio): add dashboard_auth:sign_in_with_chatgpt enabled feature (#48677)
Adds a `dashboard_auth:sign_in_with_chatgpt` enabled-features flag so deployments can disable the sign in with ChatGPT button via `disabled_features`, the same way `dashboard_auth:sign_in_with_github` works. Previously the button was only gated by the ConfigCat rollout flag / localStorage opt-in, so white-labeled deployments with custom auth providers had no way to turn it off. **Added:** - `dashboard_auth:sign_in_with_chatgpt` (default `true`) in `enabled-features.json` + schema - Tests covering the feature-disabled state **Changed:** - `useEnabledIdentityProviders` now gates ChatGPT as `featureEnabled && (localStorageOptIn || configCatFlag)` — the feature flag is the static kill switch, the existing OR'd pair remains the rollout mechanism ## To test - Sign-in and sign-up pages behave exactly as before by default (flag defaults to `true`, ConfigCat/localStorage rollout gate unchanged) - With `dashboard_auth:sign_in_with_chatgpt` in a profile's `disabled_features`, the ChatGPT button no longer renders even with `?siwc-enabled=1` or the ConfigCat flag on - GitHub button gating unaffected <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added a feature flag to control ChatGPT sign-in availability. - ChatGPT sign-in is now available only when the feature is enabled and an applicable rollout or opt-in condition is met. - **Tests** - Expanded coverage for ChatGPT and GitHub sign-in provider availability under different feature-flag and rollout conditions. <!-- end of auto-generated comment: release notes by coderabbit.ai --> Co-authored-by: Alaister Young <10985857+alaister@users.noreply.github.com>
This commit is contained in:
1 parent
1123a74813
commit
270925b680
4 files changed
+66
-19
No files matched your search
@@ -24,15 +24,20 @@ vi.mock('common', async (importOriginal) => ({
|
||||
useFlag: mockUseFlag,
|
||||
}))
|
||||
|
||||
function mockFeatures({ github = false, chatgpt = true }: { github?: boolean; chatgpt?: boolean }) {
|
||||
mockIsFeatureEnabled.mockReturnValue({
|
||||
dashboardAuthSignInWithGithub: github,
|
||||
dashboardAuthSignInWithChatgpt: chatgpt,
|
||||
})
|
||||
}
|
||||
|
||||
describe('useEnabledIdentityProviders', () => {
|
||||
beforeEach(() => {
|
||||
mockUseFlag.mockReset()
|
||||
})
|
||||
|
||||
it('returns every provider when all flags are enabled', () => {
|
||||
mockIsFeatureEnabled.mockReturnValue({
|
||||
dashboardAuthSignInWithGithub: true,
|
||||
})
|
||||
mockFeatures({ github: true, chatgpt: true })
|
||||
mockUseLocalStorageQuery.mockReturnValue([true])
|
||||
mockUseFlag.mockReturnValue(true)
|
||||
|
||||
@@ -42,9 +47,7 @@ describe('useEnabledIdentityProviders', () => {
|
||||
})
|
||||
|
||||
it('returns no providers when all flags are disabled', () => {
|
||||
mockIsFeatureEnabled.mockReturnValue({
|
||||
dashboardAuthSignInWithGithub: false,
|
||||
})
|
||||
mockFeatures({ github: false, chatgpt: false })
|
||||
mockUseLocalStorageQuery.mockReturnValue([false])
|
||||
mockUseFlag.mockReturnValue(false)
|
||||
|
||||
@@ -54,7 +57,7 @@ describe('useEnabledIdentityProviders', () => {
|
||||
})
|
||||
|
||||
it('includes ChatGPT when localStorage is true and configcat is true', () => {
|
||||
mockIsFeatureEnabled.mockReturnValue({ dashboardAuthSignInWithGithub: false })
|
||||
mockFeatures({ chatgpt: true })
|
||||
mockUseLocalStorageQuery.mockReturnValue([true])
|
||||
mockUseFlag.mockReturnValue(true)
|
||||
|
||||
@@ -64,7 +67,7 @@ describe('useEnabledIdentityProviders', () => {
|
||||
})
|
||||
|
||||
it('includes ChatGPT when localStorage is true and configcat is false', () => {
|
||||
mockIsFeatureEnabled.mockReturnValue({ dashboardAuthSignInWithGithub: false })
|
||||
mockFeatures({ chatgpt: true })
|
||||
mockUseLocalStorageQuery.mockReturnValue([true])
|
||||
mockUseFlag.mockReturnValue(false)
|
||||
|
||||
@@ -74,7 +77,7 @@ describe('useEnabledIdentityProviders', () => {
|
||||
})
|
||||
|
||||
it('includes ChatGPT when localStorage is false and configcat is true', () => {
|
||||
mockIsFeatureEnabled.mockReturnValue({ dashboardAuthSignInWithGithub: false })
|
||||
mockFeatures({ chatgpt: true })
|
||||
mockUseLocalStorageQuery.mockReturnValue([false])
|
||||
mockUseFlag.mockReturnValue(true)
|
||||
|
||||
@@ -84,7 +87,7 @@ describe('useEnabledIdentityProviders', () => {
|
||||
})
|
||||
|
||||
it('excludes ChatGPT when localStorage is false and configcat is false', () => {
|
||||
mockIsFeatureEnabled.mockReturnValue({ dashboardAuthSignInWithGithub: false })
|
||||
mockFeatures({ chatgpt: true })
|
||||
mockUseLocalStorageQuery.mockReturnValue([false])
|
||||
mockUseFlag.mockReturnValue(false)
|
||||
|
||||
@@ -93,8 +96,38 @@ describe('useEnabledIdentityProviders', () => {
|
||||
expect(result.current).toEqual([])
|
||||
})
|
||||
|
||||
it('excludes ChatGPT when its feature flag is disabled but configcat is true', () => {
|
||||
mockFeatures({ chatgpt: false })
|
||||
mockUseLocalStorageQuery.mockReturnValue([false])
|
||||
mockUseFlag.mockReturnValue(true)
|
||||
|
||||
const { result } = renderHook(() => useEnabledIdentityProviders())
|
||||
|
||||
expect(result.current).toEqual([])
|
||||
})
|
||||
|
||||
it('excludes ChatGPT when its feature flag is disabled but localStorage is opted in', () => {
|
||||
mockFeatures({ chatgpt: false })
|
||||
mockUseLocalStorageQuery.mockReturnValue([true])
|
||||
mockUseFlag.mockReturnValue(false)
|
||||
|
||||
const { result } = renderHook(() => useEnabledIdentityProviders())
|
||||
|
||||
expect(result.current).toEqual([])
|
||||
})
|
||||
|
||||
it('excludes ChatGPT when its feature flag is disabled and both rollout gates are on', () => {
|
||||
mockFeatures({ github: true, chatgpt: false })
|
||||
mockUseLocalStorageQuery.mockReturnValue([true])
|
||||
mockUseFlag.mockReturnValue(true)
|
||||
|
||||
const { result } = renderHook(() => useEnabledIdentityProviders())
|
||||
|
||||
expect(result.current).toEqual([GITHUB_IDENTITY_PROVIDER])
|
||||
})
|
||||
|
||||
it('includes GitHub when its feature flag is enabled', () => {
|
||||
mockIsFeatureEnabled.mockReturnValue({ dashboardAuthSignInWithGithub: true })
|
||||
mockFeatures({ github: true, chatgpt: true })
|
||||
mockUseLocalStorageQuery.mockReturnValue([false])
|
||||
mockUseFlag.mockReturnValue(false)
|
||||
|
||||
@@ -104,7 +137,7 @@ describe('useEnabledIdentityProviders', () => {
|
||||
})
|
||||
|
||||
it('excludes GitHub when its feature flag is disabled', () => {
|
||||
mockIsFeatureEnabled.mockReturnValue({ dashboardAuthSignInWithGithub: false })
|
||||
mockFeatures({ github: false, chatgpt: true })
|
||||
mockUseLocalStorageQuery.mockReturnValue([false])
|
||||
mockUseFlag.mockReturnValue(false)
|
||||
|
||||
|
||||
@@ -14,14 +14,19 @@ import {
|
||||
* To add a provider: declare its config in `lib/external-identity-providers.ts`, add a
|
||||
* `dashboard_auth:sign_in_with_*` flag, and gate it here.
|
||||
*
|
||||
* ChatGPT is a deliberate exception: it's rolled out via the `ShowSignInWithChatGptButton`
|
||||
* ConfigCat flag OR'd with a manual, localStorage-only opt-in switch
|
||||
* (`LOCAL_STORAGE_KEYS.SIGN_IN_CHATGPT_ENABLED`, flippable via the `?siwc-enabled=1` query param —
|
||||
* see `useSiwcQueryParamOptIn`), instead of the static `dashboard_auth:sign_in_with_*` pattern.
|
||||
* ChatGPT carries an extra rollout gate on top of its `dashboard_auth:sign_in_with_chatgpt` flag:
|
||||
* the feature flag must be enabled AND either the `ShowSignInWithChatGptButton` ConfigCat flag or a
|
||||
* manual, localStorage-only opt-in switch (`LOCAL_STORAGE_KEYS.SIGN_IN_CHATGPT_ENABLED`, flippable
|
||||
* via the `?siwc-enabled=1` query param — see `useSiwcQueryParamOptIn`) must be on. The feature flag
|
||||
* is the static kill switch; the OR'd pair is the progressive rollout mechanism.
|
||||
*/
|
||||
export function useEnabledIdentityProviders(): ExternalIdentityProviderConfig[] {
|
||||
const { dashboardAuthSignInWithGithub: githubEnabled } = useIsFeatureEnabled([
|
||||
const {
|
||||
dashboardAuthSignInWithGithub: githubEnabled,
|
||||
dashboardAuthSignInWithChatgpt: chatgptFeatureEnabled,
|
||||
} = useIsFeatureEnabled([
|
||||
'dashboard_auth:sign_in_with_github',
|
||||
'dashboard_auth:sign_in_with_chatgpt',
|
||||
])
|
||||
|
||||
const [chatgptLocalStorageEnabled] = useLocalStorageQuery(
|
||||
@@ -30,12 +35,15 @@ export function useEnabledIdentityProviders(): ExternalIdentityProviderConfig[]
|
||||
)
|
||||
const chatGptConfigCatFlagEnabled = useFlag('ShowSignInWithChatGptButton')
|
||||
|
||||
const isChatGptEnabled =
|
||||
chatgptFeatureEnabled && (chatgptLocalStorageEnabled || chatGptConfigCatFlagEnabled)
|
||||
|
||||
return useMemo(
|
||||
() =>
|
||||
[
|
||||
githubEnabled && GITHUB_IDENTITY_PROVIDER,
|
||||
(chatgptLocalStorageEnabled || chatGptConfigCatFlagEnabled) && CHATGPT_IDENTITY_PROVIDER,
|
||||
isChatGptEnabled && CHATGPT_IDENTITY_PROVIDER,
|
||||
].filter((p): p is ExternalIdentityProviderConfig => Boolean(p)),
|
||||
[githubEnabled, chatgptLocalStorageEnabled, chatGptConfigCatFlagEnabled]
|
||||
[githubEnabled, isChatGptEnabled]
|
||||
)
|
||||
}
|
||||
@@ -34,6 +34,7 @@
|
||||
|
||||
"dashboard_auth:sign_up": true,
|
||||
"dashboard_auth:sign_in_with_github": true,
|
||||
"dashboard_auth:sign_in_with_chatgpt": true,
|
||||
"dashboard_auth:sign_in_with_sso": true,
|
||||
"dashboard_auth:sign_in_with_email": true,
|
||||
"dashboard_auth:show_testimonial": true,
|
||||
|
||||
@@ -115,6 +115,10 @@
|
||||
"type": "boolean",
|
||||
"description": "Enable the sign in with github provider"
|
||||
},
|
||||
"dashboard_auth:sign_in_with_chatgpt": {
|
||||
"type": "boolean",
|
||||
"description": "Enable the sign in with ChatGPT provider"
|
||||
},
|
||||
"dashboard_auth:sign_in_with_sso": {
|
||||
"type": "boolean",
|
||||
"description": "Enable the sign in with sso provider"
|
||||
@@ -468,6 +472,7 @@
|
||||
"billing:all",
|
||||
"dashboard_auth:sign_up",
|
||||
"dashboard_auth:sign_in_with_github",
|
||||
"dashboard_auth:sign_in_with_chatgpt",
|
||||
"dashboard_auth:sign_in_with_sso",
|
||||
"dashboard_auth:sign_in_with_email",
|
||||
"dashboard_auth:show_tos",
|
||||
|
||||
Reference in new issue
Block a user