From 4bb36b944fe3bb5cc4825e9653e694c883f0f21b Mon Sep 17 00:00:00 2001 From: Matt Rossman <22670878+mattrossman@users.noreply.github.com> Date: Fri, 18 Sep 2026 08:21:50 -0400 Subject: [PATCH] feat(studio): let High Compliance projects opt-in to Assistant data access (#50548) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Orgs with the HIPAA add-on had the Assistant's opt-in level forced to `disabled` on any project marked High Compliance, regardless of what the org picked in its AI settings. The restriction predated our AI provider BAAs. The consequence is those users see the Assistant failing to answer questions about their data w/ no clear path how to fix it, even though the LLM provider supports this use case. This PR removes these Assistant restrictions on the server and client so those projects honor the org's chosen level. Braintrust conversation tracing is unchanged and still blocked for these projects, see [this test case](https://github.com/supabase/supabase/blob/b9800ccf16/apps/studio/lib/ai/braintrust-logger.test.ts#L16-L20). See [comments](https://linear.app/supabase/issue/AI-1153/allow-hipaa-orgs-to-opt-in-to-assistant-data-access-for-high#comment-485a0d46) for legal approval and conditions. The client-side changes enable features like "Debug with AI" on SQL query failures, “Generate/Rename with AI” for snippet titles, and generated Assistant chat titles for these customers. The AI opt-in copy now adds a reminder to obtain consent from data subjects, linking the [shared responsibility model](https://supabase.com/docs/guides/deployment/shared-responsibility-model) based also on [this comment](https://linear.app/supabase/issue/AI-1153/allow-hipaa-orgs-to-opt-in-to-assistant-data-access-for-high#comment-f81ee610). CleanShot 2026-09-17 at 5 01 02 PM@2x To test with a HIPAA-enabled project in staging, you can use this [Plan Change [Staging]](https://app.hex.tech/supabase/app/Plan-Change-Staging-032BD32jo1EaisCS85qunf/latest) Hex to add the HIPAA add-on. Once the add-on is present, you can turn on High Compliance from a project's settings. Also in org settings, crank up the Assistant data opt-in level and verify the Assistant is able to answer questions about the project's data. My results testing with opt-in level "Schema, Logs & Database Data": | High compliance setting | Data opt-in working | |--------|--------| | CleanShot 2026-09-17 at 5 03 36
PM@2x | CleanShot 2026-09-17 at 5 05
14 PM@2x | Closes AI-1153 ## Summary by CodeRabbit ## New Features - AI-assisted query renaming, snippet title generation, debugging, and tools now follow organization AI opt-in settings rather than project HIPAA status. - Debugging assistance and AI actions remain available for eligible users without additional HIPAA-based blocking. - AI metadata warnings consistently show standard opt-in messaging and permission settings. - AI settings remind users to obtain consent before entering personal data and link to shared responsibility guidance. --------- Co-authored-by: Joshen Lim --- .../Explorer/ExplorerChatToolbar.tsx | 2 - .../QueryResultError.selfhosted.test.tsx | 81 ------------------- .../QueryEditor/QueryResultError.test.tsx | 49 ----------- .../Explorer/QueryEditor/QueryResultError.tsx | 29 +------ .../GeneralSettings/AIOptInLevelSelector.tsx | 9 ++- .../GeneralSettings/OptInToOpenAIToggle.tsx | 8 +- .../interfaces/SQLEditor/RenameQueryModal.tsx | 19 ++--- .../interfaces/SQLEditor/SQLEditor.utils.ts | 7 +- .../UtilityPanel/UtilityTabResults.tsx | 28 ++----- .../ProjectComplianceMode.tsx | 2 +- .../AIAssistantHeader.test.tsx | 1 - .../ui/AIAssistantPanel/AIAssistantHeader.tsx | 3 - .../AIAssistantMetadataWarning.tsx | 30 +++---- .../ui/AIAssistantPanel/AssistantChat.tsx | 4 +- .../ui/EditorPanel/SaveSnippetDialog.tsx | 17 ++-- apps/studio/hooks/misc/useOrgOptedIntoAi.ts | 26 +----- apps/studio/lib/ai/ai-details.test.ts | 54 +++---------- apps/studio/lib/ai/ai-details.ts | 9 +-- apps/studio/lib/ai/tool-filter.test.ts | 32 ++------ apps/studio/lib/ai/tool-filter.ts | 23 ++---- apps/studio/lib/ai/tools/index.test.ts | 2 - apps/studio/lib/ai/tools/index.ts | 10 +-- apps/studio/lib/ai/tools/mcp-tools.test.ts | 1 - apps/studio/lib/ai/tools/mcp-tools.ts | 8 +- apps/studio/pages/api/ai/sql/generate-v4.ts | 3 - apps/studio/pages/api/ai/sql/policy.ts | 3 - 26 files changed, 86 insertions(+), 374 deletions(-) delete mode 100644 apps/studio/components/interfaces/Explorer/QueryEditor/QueryResultError.selfhosted.test.tsx diff --git a/apps/studio/components/interfaces/Explorer/ExplorerChatToolbar.tsx b/apps/studio/components/interfaces/Explorer/ExplorerChatToolbar.tsx index 0c2511aa07f..07748bfc964 100644 --- a/apps/studio/components/interfaces/Explorer/ExplorerChatToolbar.tsx +++ b/apps/studio/components/interfaces/Explorer/ExplorerChatToolbar.tsx @@ -36,7 +36,6 @@ export const ExplorerChatToolbar = ({ isChatLoading, showMetadataWarning, updatedOptInSinceMCP, - isHipaaProjectDisallowed, aiOptInLevel, }: ExplorerChatToolbarProps) => { const snap = useAiAssistantStateSnapshot() @@ -120,7 +119,6 @@ export const ExplorerChatToolbar = ({ onVisibleChange={setIsOptInModalOpen} showMetadataWarning={showMetadataWarning} updatedOptInSinceMCP={updatedOptInSinceMCP} - isHipaaProjectDisallowed={isHipaaProjectDisallowed} aiOptInLevel={aiOptInLevel} /> diff --git a/apps/studio/components/interfaces/Explorer/QueryEditor/QueryResultError.selfhosted.test.tsx b/apps/studio/components/interfaces/Explorer/QueryEditor/QueryResultError.selfhosted.test.tsx deleted file mode 100644 index 354291b5ed0..00000000000 --- a/apps/studio/components/interfaces/Explorer/QueryEditor/QueryResultError.selfhosted.test.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import { screen } from '@testing-library/react' -import { beforeEach, describe, expect, it, vi } from 'vitest' - -import { QueryResultError } from './QueryResultError' -import { customRender } from '@/tests/lib/custom-render' -import { addAPIMock } from '@/tests/lib/msw' - -const mocks = vi.hoisted(() => ({ - createChat: vi.fn(), - useParams: vi.fn(), -})) - -vi.mock('@/lib/constants', async () => { - const actual = await vi.importActual>('@/lib/constants') - return { ...actual, IS_PLATFORM: false } -}) - -vi.mock('common', async (importOriginal) => { - const actual = await importOriginal() - return { ...actual, useParams: () => mocks.useParams() } -}) - -vi.mock('../hooks', () => ({ - useCreateChat: () => ({ createChat: mocks.createChat, isCreating: false }), -})) - -vi.mock('@/hooks/misc/useSelectedOrganization', () => ({ - useSelectedOrganizationQuery: () => ({ data: undefined }), -})) - -// Self-hosted has no orgs/billing, so these eligibility queries are expected to never -// resolve (disabled or failing) - the dropdown must not stay hidden waiting on them. -vi.mock('@/data/subscriptions/org-subscription-query', () => ({ - useOrgSubscriptionQuery: () => ({ data: undefined, isSuccess: false }), -})) - -vi.mock('@/data/config/project-settings-v2-query', () => ({ - useProjectSettingsV2Query: () => ({ data: undefined, isSuccess: false }), -})) - -describe('QueryResultError (self-hosted)', () => { - beforeEach(() => { - mocks.useParams.mockReturnValue({ ref: 'default' }) - addAPIMock({ - method: 'get', - path: '/platform/projects/:ref', - response: { - id: 1, - ref: 'default', - organization_id: 1, - name: 'Test Project', - status: 'ACTIVE_HEALTHY', - cloud_provider: 'AWS', - region: 'us-east-1', - db_host: 'db.default.supabase.co', - restUrl: 'https://default.supabase.co/rest/v1/', - inserted_at: '2024-01-01T00:00:00Z', - updated_at: '2024-01-01T00:00:00Z', - subscription_id: 'sub_123', - is_branch_enabled: false, - is_physical_backups_enabled: false, - high_availability: false, - integration_source: null, - connectionString: 'postgresql://postgres@localhost:5432/postgres', - is_hibernating: false, - }, - }) - }) - - it('renders the assistant dropdown without waiting on HIPAA eligibility queries', () => { - customRender( - - ) - - expect(screen.getByRole('button', { name: 'Debug with Assistant' })).toBeInTheDocument() - }) -}) diff --git a/apps/studio/components/interfaces/Explorer/QueryEditor/QueryResultError.test.tsx b/apps/studio/components/interfaces/Explorer/QueryEditor/QueryResultError.test.tsx index 7b7f1732bb1..3a1bbe8b0f8 100644 --- a/apps/studio/components/interfaces/Explorer/QueryEditor/QueryResultError.test.tsx +++ b/apps/studio/components/interfaces/Explorer/QueryEditor/QueryResultError.test.tsx @@ -10,8 +10,6 @@ const mocks = vi.hoisted(() => ({ createChat: vi.fn(), useParams: vi.fn(), mockCopyToClipboard: vi.fn(), - useOrgSubscriptionQuery: vi.fn(), - useProjectSettingsV2Query: vi.fn(), })) vi.mock('common', async (importOriginal) => { @@ -19,13 +17,6 @@ vi.mock('common', async (importOriginal) => { return { ...actual, useParams: () => mocks.useParams() } }) -// This file covers the platform-mode HIPAA eligibility gate; the self-hosted bypass is -// covered separately in QueryResultError.selfhosted.test.tsx. -vi.mock('@/lib/constants', async () => { - const actual = await vi.importActual>('@/lib/constants') - return { ...actual, IS_PLATFORM: true } -}) - // CopyButton and AiAssistantDropdown write via copyToClipboard from 'ui'. Stub just that // export so we can assert the value handed to the clipboard without depending on jsdom's // document.hasFocus() / navigator.clipboard. Everything else in 'ui' stays real. @@ -42,19 +33,9 @@ vi.mock('@/hooks/misc/useSelectedOrganization', () => ({ useSelectedOrganizationQuery: () => ({ data: { slug: 'default-org' } }), })) -vi.mock('@/data/subscriptions/org-subscription-query', () => ({ - useOrgSubscriptionQuery: () => mocks.useOrgSubscriptionQuery(), -})) - -vi.mock('@/data/config/project-settings-v2-query', () => ({ - useProjectSettingsV2Query: () => mocks.useProjectSettingsV2Query(), -})) - describe('QueryResultError', () => { beforeEach(() => { mocks.useParams.mockReturnValue({ ref: 'default' }) - mocks.useOrgSubscriptionQuery.mockReturnValue({ data: undefined, isSuccess: true }) - mocks.useProjectSettingsV2Query.mockReturnValue({ data: undefined, isSuccess: true }) // useTrack() (invoked by AiAssistantDropdown) reads the selected project to attach // telemetry context, so the platform project fetch needs a handler even though this // component doesn't read project data itself. @@ -145,34 +126,4 @@ describe('QueryResultError', () => { expect(screen.queryByRole('button', { name: 'Debug with Assistant' })).not.toBeInTheDocument() }) - - it('does not render the assistant dropdown while HIPAA eligibility is still resolving', () => { - mocks.useOrgSubscriptionQuery.mockReturnValue({ data: undefined, isSuccess: false }) - - customRender( - - ) - - expect(screen.queryByRole('button', { name: 'Debug with Assistant' })).not.toBeInTheDocument() - }) - - it('does not render the assistant dropdown when an eligibility query is disabled or failed', () => { - // A disabled or failed query also settles with isSuccess: false forever - same as - // still-loading from this component's point of view, so it stays denied. - mocks.useProjectSettingsV2Query.mockReturnValue({ data: undefined, isSuccess: false }) - - customRender( - - ) - - expect(screen.queryByRole('button', { name: 'Debug with Assistant' })).not.toBeInTheDocument() - }) }) diff --git a/apps/studio/components/interfaces/Explorer/QueryEditor/QueryResultError.tsx b/apps/studio/components/interfaces/Explorer/QueryEditor/QueryResultError.tsx index 0ce4fc3af25..be46a183770 100644 --- a/apps/studio/components/interfaces/Explorer/QueryEditor/QueryResultError.tsx +++ b/apps/studio/components/interfaces/Explorer/QueryEditor/QueryResultError.tsx @@ -1,10 +1,8 @@ -import { useParams } from 'common' import { ExternalLink } from 'lucide-react' import { parseAsBoolean, useQueryState } from 'nuqs' import { useCallback } from 'react' import { Button, cn, Tooltip, TooltipContent, TooltipTrigger } from 'ui' -import { subscriptionHasHipaaAddon } from '../../Billing/Subscription/Subscription.utils' import { type SqlSnippetSource } from '../../SQLEditor/querySource' import { buildDebugPromptText } from '../../SQLEditor/SQLEditor.utils' import { useCreateChat } from '../hooks' @@ -12,11 +10,8 @@ import { type QueryResult } from '../types' import { AiAssistantDropdown } from '@/components/ui/AiAssistantDropdown' import CopyButton from '@/components/ui/CopyButton' import { InlineLink, InlineLinkClassName } from '@/components/ui/InlineLink' -import { useProjectSettingsV2Query } from '@/data/config/project-settings-v2-query' import { getSqlErrorLines } from '@/data/sql/utils' -import { useOrgSubscriptionQuery } from '@/data/subscriptions/org-subscription-query' -import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' -import { DOCS_URL, IS_PLATFORM } from '@/lib/constants' +import { DOCS_URL } from '@/lib/constants' export const QueryResultError = ({ error, @@ -34,26 +29,6 @@ export const QueryResultError = ({ * into that conversation's composer instead of abandoning it for a new chat. */ onDebug?: (prompt: string) => void }) => { - const { ref } = useParams() - - const { data: org } = useSelectedOrganizationQuery() - const { data: subscription, isSuccess: isSubscriptionResolved } = useOrgSubscriptionQuery({ - orgSlug: org?.slug, - }) - const { data: projectSettings, isSuccess: isProjectSettingsResolved } = useProjectSettingsV2Query( - { - projectRef: ref, - } - ) - const hasHipaaAddon = subscriptionHasHipaaAddon(subscription) && projectSettings?.is_sensitive - // Default deny until both eligibility queries have actually succeeded - a disabled or - // failed query also reports isLoading: false, so isLoading can't tell "confirmed no - // addon" apart from "don't know yet", and the assistant sends the SQL and error to an - // LLM. Self-hosted has no HIPAA concept at all (subscriptionHasHipaaAddon short-circuits - // to false there), so there's nothing to wait on outside of platform. - const isCheckingHipaaEligibility = - IS_PLATFORM && (!isSubscriptionResolved || !isProjectSettingsResolved) - const { createChat, isCreating } = useCreateChat() const [, setShowConnect] = useQueryState('showConnect', parseAsBoolean.withDefault(false)) @@ -175,7 +150,7 @@ export const QueryResultError = ({ )} - {!hasHipaaAddon && !isCheckingHipaaEligibility && canDebug && ( + {canDebug && ( @@ -89,7 +91,12 @@ export const AIOptInLevelSelector = ({

For organizations with HIPAA compliance enabled in their Supabase configuration, any consented information will only be shared with third-party AI providers with whom - Supabase has established a Business Associate Agreement (BAA). + Supabase has established a Business Associate Agreement (BAA). Don't input personal data + unless you've{' '} + + obtained consent + {' '} + from the individuals it relates to.

diff --git a/apps/studio/components/interfaces/Organization/GeneralSettings/OptInToOpenAIToggle.tsx b/apps/studio/components/interfaces/Organization/GeneralSettings/OptInToOpenAIToggle.tsx index 44272d1bcf5..52c31dd73d0 100644 --- a/apps/studio/components/interfaces/Organization/GeneralSettings/OptInToOpenAIToggle.tsx +++ b/apps/studio/components/interfaces/Organization/GeneralSettings/OptInToOpenAIToggle.tsx @@ -9,6 +9,7 @@ import { } from 'ui' import { InlineLink } from '@/components/ui/InlineLink' +import { DOCS_URL } from '@/lib/constants' export const OptInToOpenAIToggle = () => { return ( @@ -42,7 +43,12 @@ export const OptInToOpenAIToggle = () => {

For organizations with HIPAA compliance enabled in their Supabase configuration, any consented information will only be shared with third-party AI providers with whom - Supabase has established a Business Associate Agreement (BAA). + Supabase has established a Business Associate Agreement (BAA). Don't input personal data + unless you've{' '} + + obtained consent + {' '} + from the individuals it relates to.

diff --git a/apps/studio/components/interfaces/SQLEditor/RenameQueryModal.tsx b/apps/studio/components/interfaces/SQLEditor/RenameQueryModal.tsx index 98d9f54786d..4a0e55a4230 100644 --- a/apps/studio/components/interfaces/SQLEditor/RenameQueryModal.tsx +++ b/apps/studio/components/interfaces/SQLEditor/RenameQueryModal.tsx @@ -63,8 +63,7 @@ const RenameQueryForm = ({ snippet, onCancel, onComplete }: RenameQueryFormProps const tabsSnap = useTabsStateSnapshot() const isSQLSnippet = snippet.type === 'sql' - // Orgs on HIPAA plans or that have disabled AI should not have access to Supabase AI - const { aiOptInLevel, isHipaaProjectDisallowed } = useOrgAiOptInLevel() + const { aiOptInLevel } = useOrgAiOptInLevel() const isAiOptedOut = aiOptInLevel === 'disabled' const { id, name, description } = snippet @@ -180,19 +179,15 @@ const RenameQueryForm = ({ snippet, onCancel, onComplete }: RenameQueryFormProps generateTitle()} size="tiny" - disabled={ - isTitleGenerationLoading || !isApiKeySet || isHipaaProjectDisallowed || isAiOptedOut - } + disabled={isTitleGenerationLoading || !isApiKeySet || isAiOptedOut} tooltip={{ content: { side: 'bottom', - text: isHipaaProjectDisallowed - ? 'This feature is not available for HIPAA projects.' - : isAiOptedOut - ? 'Your organization has opted out of AI features.' - : isApiKeySet - ? undefined - : 'Add your "OPENAI_API_KEY" to your environment variables to use this feature.', + text: isAiOptedOut + ? 'Your organization has opted out of AI features.' + : isApiKeySet + ? undefined + : 'Add your "OPENAI_API_KEY" to your environment variables to use this feature.', }, }} > diff --git a/apps/studio/components/interfaces/SQLEditor/SQLEditor.utils.ts b/apps/studio/components/interfaces/SQLEditor/SQLEditor.utils.ts index 406ac4419ca..b8bcd369c9c 100644 --- a/apps/studio/components/interfaces/SQLEditor/SQLEditor.utils.ts +++ b/apps/studio/components/interfaces/SQLEditor/SQLEditor.utils.ts @@ -263,10 +263,9 @@ export function resolveConnectionString( /** * Whether a query run should lazily kick off AI title generation for the - * snippet: only when the org has AI enabled (not disabled/HIPAA — which would - * silently forward the query to the AI provider without consent), the - * snippet still has its placeholder name, and we're running on the hosted - * platform. + * snippet: only when the org has AI enabled (a disabled org would silently + * forward the query to the AI provider without consent), the snippet still + * has its placeholder name, and we're running on the hosted platform. */ export function shouldAutoGenerateTitle({ aiOptInLevel, diff --git a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/UtilityTabResults.tsx b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/UtilityTabResults.tsx index 077c86eaa5d..1f24875a615 100644 --- a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/UtilityTabResults.tsx +++ b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/UtilityTabResults.tsx @@ -4,15 +4,11 @@ import { parseAsBoolean, useQueryState } from 'nuqs' import { forwardRef } from 'react' import { Button, cn, Tooltip, TooltipContent, TooltipTrigger } from 'ui' -import { subscriptionHasHipaaAddon } from '@/components/interfaces/Billing/Subscription/Subscription.utils' import { AiAssistantDropdown } from '@/components/ui/AiAssistantDropdown' import CopyButton from '@/components/ui/CopyButton' import { DataGridResults } from '@/components/ui/DataGridResults' import { InlineLink, InlineLinkClassName } from '@/components/ui/InlineLink' -import { useProjectSettingsV2Query } from '@/data/config/project-settings-v2-query' import { getSqlErrorLines } from '@/data/sql/utils' -import { useOrgSubscriptionQuery } from '@/data/subscriptions/org-subscription-query' -import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' import { DOCS_URL } from '@/lib/constants' import { useDatabaseSelectorStateSnapshot } from '@/state/database-selector' import { useSqlEditorSessionSnapshot } from '@/state/sql-editor/sql-editor-session-state' @@ -30,16 +26,10 @@ export const UtilityTabResults = forwardRef { const { ref } = useParams() const state = useDatabaseSelectorStateSnapshot() - const { data: organization } = useSelectedOrganizationQuery() const sessionSnap = useSqlEditorSessionSnapshot() const [, setShowConnect] = useQueryState('showConnect', parseAsBoolean.withDefault(false)) const result = sessionSnap.results[id]?.[0] - const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: organization?.slug }) - - // Customers on HIPAA plans should not have access to Supabase AI - const { data: projectSettings } = useProjectSettingsV2Query({ projectRef: ref }) - const hasHipaaAddon = subscriptionHasHipaaAddon(subscription) && projectSettings?.is_sensitive const isTimeout = result?.error?.message?.includes('canceling statement due to statement timeout') || @@ -154,16 +144,14 @@ export const UtilityTabResults = forwardRef )} - {!hasHipaaAddon && ( - - )} + diff --git a/apps/studio/components/interfaces/Settings/General/ComplianceConfig/ProjectComplianceMode.tsx b/apps/studio/components/interfaces/Settings/General/ComplianceConfig/ProjectComplianceMode.tsx index d4ee5778de4..a5213b1b05a 100644 --- a/apps/studio/components/interfaces/Settings/General/ComplianceConfig/ProjectComplianceMode.tsx +++ b/apps/studio/components/interfaces/Settings/General/ComplianceConfig/ProjectComplianceMode.tsx @@ -68,7 +68,7 @@ export const ComplianceConfig = () => { return ( -

+
High Compliance Configuration diff --git a/apps/studio/components/ui/AIAssistantPanel/AIAssistantHeader.test.tsx b/apps/studio/components/ui/AIAssistantPanel/AIAssistantHeader.test.tsx index be9b541589b..7de470967cb 100644 --- a/apps/studio/components/ui/AIAssistantPanel/AIAssistantHeader.test.tsx +++ b/apps/studio/components/ui/AIAssistantPanel/AIAssistantHeader.test.tsx @@ -50,7 +50,6 @@ const defaultProps = { onCloseAssistant: vi.fn(), showMetadataWarning: false, updatedOptInSinceMCP: true, - isHipaaProjectDisallowed: false, aiOptInLevel: 'full', } diff --git a/apps/studio/components/ui/AIAssistantPanel/AIAssistantHeader.tsx b/apps/studio/components/ui/AIAssistantPanel/AIAssistantHeader.tsx index 91b3873c2bc..47b06e4f606 100644 --- a/apps/studio/components/ui/AIAssistantPanel/AIAssistantHeader.tsx +++ b/apps/studio/components/ui/AIAssistantPanel/AIAssistantHeader.tsx @@ -39,7 +39,6 @@ interface AIAssistantHeaderProps { onCloseAssistant: () => void showMetadataWarning: boolean updatedOptInSinceMCP: boolean - isHipaaProjectDisallowed: boolean aiOptInLevel: 'disabled' | 'schema' | 'full' | string | undefined } @@ -50,7 +49,6 @@ export const AIAssistantHeader = ({ onCloseAssistant, showMetadataWarning, updatedOptInSinceMCP, - isHipaaProjectDisallowed, aiOptInLevel, }: AIAssistantHeaderProps) => { const { openChat } = useCreateChat() @@ -244,7 +242,6 @@ export const AIAssistantHeader = ({ onVisibleChange={setIsOptInModalOpen} showMetadataWarning={showMetadataWarning} updatedOptInSinceMCP={updatedOptInSinceMCP} - isHipaaProjectDisallowed={isHipaaProjectDisallowed} aiOptInLevel={aiOptInLevel} />
diff --git a/apps/studio/components/ui/AIAssistantPanel/AIAssistantMetadataWarning.tsx b/apps/studio/components/ui/AIAssistantPanel/AIAssistantMetadataWarning.tsx index fba455d0ced..abf8a313909 100644 --- a/apps/studio/components/ui/AIAssistantPanel/AIAssistantMetadataWarning.tsx +++ b/apps/studio/components/ui/AIAssistantPanel/AIAssistantMetadataWarning.tsx @@ -8,7 +8,6 @@ interface AIAssistantMetadataWarningProps { onVisibleChange: (visible: boolean) => void showMetadataWarning: boolean updatedOptInSinceMCP: boolean - isHipaaProjectDisallowed: boolean aiOptInLevel: 'disabled' | 'schema' | 'full' | string | undefined } @@ -17,7 +16,6 @@ export const AIAssistantMetadataWarning = ({ onVisibleChange, showMetadataWarning, updatedOptInSinceMCP, - isHipaaProjectDisallowed, aiOptInLevel, }: AIAssistantMetadataWarningProps) => ( <> @@ -27,30 +25,24 @@ export const AIAssistantMetadataWarning = ({ title={ !updatedOptInSinceMCP ? 'The Assistant has just been updated to help you better!' - : isHipaaProjectDisallowed - ? 'Project metadata is not shared due to HIPAA' - : aiOptInLevel === 'disabled' - ? 'Project metadata is currently not shared' - : 'Limited metadata is shared to the Assistant' + : aiOptInLevel === 'disabled' + ? 'Project metadata is currently not shared' + : 'Limited metadata is shared to the Assistant' } description={ !updatedOptInSinceMCP ? 'You may now opt-in to share schema metadata and even logs for better results' - : isHipaaProjectDisallowed - ? 'Your organization has the HIPAA addon and will not send project metadata with your prompts for projects marked as HIPAA.' - : aiOptInLevel === 'disabled' - ? 'The Assistant can provide better answers if you opt-in to share schema metadata.' - : aiOptInLevel === 'schema' - ? 'Sharing query data in addition to schema can further improve responses. Update AI settings to enable this.' - : '' + : aiOptInLevel === 'disabled' + ? 'The Assistant can provide better answers if you opt-in to share schema metadata.' + : aiOptInLevel === 'schema' + ? 'Sharing query data in addition to schema can further improve responses. Update AI settings to enable this.' + : '' } className="border-0 border-b rounded-none bg-background" > - {!isHipaaProjectDisallowed && ( - - )} + )} onVisibleChange(false)} /> diff --git a/apps/studio/components/ui/AIAssistantPanel/AssistantChat.tsx b/apps/studio/components/ui/AIAssistantPanel/AssistantChat.tsx index 636122430ac..24c7add23cc 100644 --- a/apps/studio/components/ui/AIAssistantPanel/AssistantChat.tsx +++ b/apps/studio/components/ui/AIAssistantPanel/AssistantChat.tsx @@ -51,7 +51,6 @@ export interface AssistantChatHeaderProps { isChatLoading: boolean showMetadataWarning: boolean updatedOptInSinceMCP: boolean - isHipaaProjectDisallowed: boolean aiOptInLevel: 'disabled' | 'schema' | 'full' | string | undefined } @@ -110,7 +109,7 @@ export const AssistantChat = ({ const inputRef = useRef(null) - const { aiOptInLevel, isHipaaProjectDisallowed } = useOrgAiOptInLevel() + const { aiOptInLevel } = useOrgAiOptInLevel() // Whether attached queries are sent at all. One definition, shared by the chat form // (which folds them into the message text) and the message metadata (which states // whether any of them was a logs query), so the two can't disagree. @@ -559,7 +558,6 @@ export const AssistantChat = ({ isChatLoading, showMetadataWarning, updatedOptInSinceMCP, - isHipaaProjectDisallowed, aiOptInLevel, })} {hasMessages ? ( diff --git a/apps/studio/components/ui/EditorPanel/SaveSnippetDialog.tsx b/apps/studio/components/ui/EditorPanel/SaveSnippetDialog.tsx index ffc8df9e106..f669642324c 100644 --- a/apps/studio/components/ui/EditorPanel/SaveSnippetDialog.tsx +++ b/apps/studio/components/ui/EditorPanel/SaveSnippetDialog.tsx @@ -34,8 +34,7 @@ export const SaveSnippetDialog = ({ open, sql, onOpenChange, onSave }: SaveSnipp const isApiKeySet = !!check?.hasKey - // Orgs on HIPAA plans or that have disabled AI should not have access to Supabase AI - const { aiOptInLevel, isHipaaProjectDisallowed } = useOrgAiOptInLevel() + const { aiOptInLevel } = useOrgAiOptInLevel() const isAiOptedOut = aiOptInLevel === 'disabled' const { mutate: generateTitle, isPending: isGenerating } = useSqlTitleGenerateMutation({ @@ -78,18 +77,16 @@ export const SaveSnippetDialog = ({ open, sql, onOpenChange, onSave }: SaveSnipp
generateTitle({ sql })} tooltip={{ content: { side: 'bottom', - text: isHipaaProjectDisallowed - ? 'This feature is not available for HIPAA projects.' - : isAiOptedOut - ? 'Your organization has opted out of AI features.' - : isApiKeySet - ? undefined - : 'Add your "OPENAI_API_KEY" to your environment variables to use this feature.', + text: isAiOptedOut + ? 'Your organization has opted out of AI features.' + : isApiKeySet + ? undefined + : 'Add your "OPENAI_API_KEY" to your environment variables to use this feature.', }, }} > diff --git a/apps/studio/hooks/misc/useOrgOptedIntoAi.ts b/apps/studio/hooks/misc/useOrgOptedIntoAi.ts index 00ba0a91862..d23dd36a18f 100644 --- a/apps/studio/hooks/misc/useOrgOptedIntoAi.ts +++ b/apps/studio/hooks/misc/useOrgOptedIntoAi.ts @@ -1,10 +1,6 @@ import { z } from 'zod' -import { subscriptionHasHipaaAddon } from '@/components/interfaces/Billing/Subscription/Subscription.utils' -import { useProjectSettingsV2Query } from '@/data/config/project-settings-v2-query' -import { useOrgSubscriptionQuery } from '@/data/subscriptions/org-subscription-query' import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' -import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' import { IS_PLATFORM, OPT_IN_TAGS } from '@/lib/constants' export const aiOptInLevelSchema = z.enum([ @@ -49,9 +45,7 @@ export function useOrgOptedIntoAi(): boolean { export function useOrgAiOptInLevel(): { aiOptInLevel: AiOptInLevel includeSchemaMetadata: boolean - isHipaaProjectDisallowed: boolean } { - const { data: selectedProject } = useSelectedProjectQuery() const { data: selectedOrganization } = useSelectedOrganizationQuery() // [Joshen] Default to disabled until migration to clean up existing opt in tags are completed @@ -60,25 +54,9 @@ export function useOrgAiOptInLevel(): { const level = getAiOptInLevel(optInTags) const isOptedIntoAI = level !== 'disabled' - const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: selectedOrganization?.slug }) - const hasHipaaAddon = subscriptionHasHipaaAddon(subscription) - - const { data: projectSettings } = useProjectSettingsV2Query({ projectRef: selectedProject?.ref }) - const isProjectSensitive = !!projectSettings?.is_sensitive - - const preventProjectFromUsingAI = hasHipaaAddon && isProjectSensitive - // [Joshen] For CLI / self-host, we'd default to 'schema' as opt in level - const aiOptInLevel = !IS_PLATFORM - ? 'schema' - : (isOptedIntoAI && !selectedProject) || (isOptedIntoAI && !preventProjectFromUsingAI) - ? level - : 'disabled' + const aiOptInLevel = !IS_PLATFORM ? 'schema' : isOptedIntoAI ? level : 'disabled' const includeSchemaMetadata = !IS_PLATFORM || aiOptInLevel !== 'disabled' - return { - aiOptInLevel, - includeSchemaMetadata, - isHipaaProjectDisallowed: preventProjectFromUsingAI, - } + return { aiOptInLevel, includeSchemaMetadata } } diff --git a/apps/studio/lib/ai/ai-details.test.ts b/apps/studio/lib/ai/ai-details.test.ts index 2e8375cc394..5589621f098 100644 --- a/apps/studio/lib/ai/ai-details.test.ts +++ b/apps/studio/lib/ai/ai-details.test.ts @@ -93,7 +93,6 @@ describe('getAIDetails', () => { planId: 'pro', region: 'us-east-1', isSensitive: false, - isRestrictedByHipaa: false, }) }) @@ -233,49 +232,20 @@ describe('getAIDetails', () => { expect(result.region).toBeUndefined() }) - describe('HIPAA organizations', () => { - beforeEach(() => { - mockSubscriptionHasHipaaAddon.mockReturnValue(true) - mockGetAiOptInLevel.mockReturnValue('schema_and_log_and_data') + it('keeps the opt-in level for a sensitive project in a HIPAA org', async () => { + mockSubscriptionHasHipaaAddon.mockReturnValue(true) + mockGetAiOptInLevel.mockReturnValue('schema_and_log_and_data') + mockGetProjectSettings.mockResolvedValue({ is_sensitive: true }) + + const result = await getAIDetails({ + orgSlug: ORG_SLUG, + projectRef: PROJECT_REF, + authorization: AUTH, }) - it('disables the opt-in level for a sensitive project', async () => { - mockGetProjectSettings.mockResolvedValue({ is_sensitive: true }) - - const result = await getAIDetails({ - orgSlug: ORG_SLUG, - projectRef: PROJECT_REF, - authorization: AUTH, - }) - - expect(result.aiOptInLevel).toBe('disabled') - expect(result.hasHipaaAddon).toBe(true) - expect(result.isRestrictedByHipaa).toBe(true) - }) - - it('disables the opt-in level when project sensitivity is unknown', async () => { - mockGetProjectSettings.mockResolvedValue(undefined) - - const result = await getAIDetails({ - orgSlug: ORG_SLUG, - projectRef: PROJECT_REF, - authorization: AUTH, - }) - - expect(result.aiOptInLevel).toBe('disabled') - }) - - it('keeps the opt-in level for a project explicitly marked not sensitive', async () => { - mockGetProjectSettings.mockResolvedValue({ is_sensitive: false }) - - const result = await getAIDetails({ - orgSlug: ORG_SLUG, - projectRef: PROJECT_REF, - authorization: AUTH, - }) - - expect(result.aiOptInLevel).toBe('schema_and_log_and_data') - }) + expect(result.aiOptInLevel).toBe('schema_and_log_and_data') + expect(result.hasHipaaAddon).toBe(true) + expect(result.isSensitive).toBe(true) }) it('keeps the opt-in level for a sensitive project outside a HIPAA org', async () => { diff --git a/apps/studio/lib/ai/ai-details.ts b/apps/studio/lib/ai/ai-details.ts index 5452433c544..63db823ff32 100644 --- a/apps/studio/lib/ai/ai-details.ts +++ b/apps/studio/lib/ai/ai-details.ts @@ -15,8 +15,6 @@ export type AIDetails = { planId: string | undefined region: string | undefined isSensitive: boolean | null | undefined - // True when HIPAA forced the opt-in level to `disabled`, rather than the org choosing it. - isRestrictedByHipaa: boolean } // Resolves the AI opt-in level, model access and tracing inputs for one org/project pair. @@ -63,17 +61,13 @@ export const getAIDetails = async ({ planId: undefined, region, isSensitive, - isRestrictedByHipaa: false, } } const hasHipaaAddon = subscriptionHasHipaaAddon(subscription) - // Mirrors the client-side gate in useOrgAiOptInLevel, which had no server-side equivalent - const isRestrictedByHipaa = hasHipaaAddon && isSensitive !== false - return { - aiOptInLevel: isRestrictedByHipaa ? 'disabled' : getAiOptInLevel(selectedOrg.opt_in_tags), + aiOptInLevel: getAiOptInLevel(selectedOrg.opt_in_tags), hasAccessToAdvanceModel: advanceModelAccess.hasAccess, hasHipaaAddon, orgId: selectedOrg.id, @@ -81,6 +75,5 @@ export const getAIDetails = async ({ planId: selectedOrg.plan.id, region, isSensitive, - isRestrictedByHipaa, } } diff --git a/apps/studio/lib/ai/tool-filter.test.ts b/apps/studio/lib/ai/tool-filter.test.ts index 47c91261876..c1c7cd9e51c 100644 --- a/apps/studio/lib/ai/tool-filter.test.ts +++ b/apps/studio/lib/ai/tool-filter.test.ts @@ -38,7 +38,7 @@ describe('tool allowance by opt-in level', () => { query_logs: { execute: vitest.fn().mockResolvedValue({ status: 'success' }) }, } as unknown as ToolSet - const filtered = filterToolsByOptInLevel(mockTools, optInLevel as any, false) + const filtered = filterToolsByOptInLevel(mockTools, optInLevel as any) const allowedTools: string[] = [] Object.entries(filtered).forEach(([toolName, tool]) => { @@ -163,14 +163,14 @@ describe('filterToolsByOptInLevel', () => { } it('should filter out unknown tools entirely', async () => { - const tools = filterToolsByOptInLevel(mockTools, 'disabled', false) + const tools = filterToolsByOptInLevel(mockTools, 'disabled') // Unknown tools should be completely filtered out (not present in result) expect(tools).not.toHaveProperty('some_other_tool') }) it('should always allow UI tools regardless of opt-in level', async () => { - const tools = filterToolsByOptInLevel(mockTools, 'disabled', false) + const tools = filterToolsByOptInLevel(mockTools, 'disabled') expect(tools).toHaveProperty('execute_sql') expect(tools).toHaveProperty('deploy_edge_function') @@ -189,7 +189,7 @@ describe('filterToolsByOptInLevel', () => { }) it('should stub all managed tools for disabled opt-in level', async () => { - const tools = filterToolsByOptInLevel(mockTools, 'disabled', false) + const tools = filterToolsByOptInLevel(mockTools, 'disabled') await expectStubsFor(tools, [ 'list_tables', @@ -203,7 +203,7 @@ describe('filterToolsByOptInLevel', () => { }) it('should stub log tools for schema opt-in level', async () => { - const tools = filterToolsByOptInLevel(mockTools, 'schema', false) + const tools = filterToolsByOptInLevel(mockTools, 'schema') await expectStubsFor(tools, ['get_advisors', 'query_logs']) }) @@ -211,7 +211,7 @@ describe('filterToolsByOptInLevel', () => { // No execute_sql tool, so nothing additional to stub for schema_and_log opt-in level it('should not stub any tools for schema_and_log_and_data opt-in level', async () => { - const tools = filterToolsByOptInLevel(mockTools, 'schema_and_log_and_data', false) + const tools = filterToolsByOptInLevel(mockTools, 'schema_and_log_and_data') await expectStubsFor(tools, []) }) @@ -226,7 +226,7 @@ describe('createPrivacyMessageTool', () => { toModelOutput: vitest.fn(), } - const privacyTool = createPrivacyMessageTool(originalTool, false) + const privacyTool = createPrivacyMessageTool(originalTool) expect(privacyTool.description).toContain('Original description') expect(privacyTool.description).toContain('Requires opting in') @@ -236,24 +236,6 @@ describe('createPrivacyMessageTool', () => { expect(result.status).toContain("You don't have permission to use this tool") expect(result.status).toContain('third-party AI providers') }) - - it('uses HIPAA copy when the project is HIPAA-restricted', async () => { - const originalTool = { - description: 'Original description', - inputSchema: z.object({}), - execute: vitest.fn(), - } - - const hipaaTool = createPrivacyMessageTool(originalTool, true) - const optInTool = createPrivacyMessageTool(originalTool, false) - - const hipaaStatus = (await hipaaTool.execute({}, {})).status - const optInStatus = (await optInTool.execute({}, {})).status - - expect(hipaaStatus).toContain('HIPAA') - expect(hipaaStatus).not.toEqual(optInStatus) - expect(hipaaTool.description).not.toEqual(optInTool.description) - }) }) describe('toolSetValidationSchema', () => { diff --git a/apps/studio/lib/ai/tool-filter.ts b/apps/studio/lib/ai/tool-filter.ts index d93663d8a8f..477dc761921 100644 --- a/apps/studio/lib/ai/tool-filter.ts +++ b/apps/studio/lib/ai/tool-filter.ts @@ -167,16 +167,11 @@ function isToolAllowed(toolName: string, aiOptInLevel: AiOptInLevel): boolean { * Names no provider. Studio switches inference providers, and a stale name here becomes a * false privacy claim shown to users. */ -export function createPrivacyMessageTool( - toolInstance: Tool, - isRestrictedByHipaa: boolean -) { - const privacyMessage = isRestrictedByHipaa - ? "You don't have permission to use this tool. This project is configured as High Compliance and your organization has the HIPAA add-on, so Supabase does not send project metadata with your prompts. The user cannot change this in their organization's AI settings, so continue without project metadata rather than asking them to opt in." - : "You don't have permission to use this tool. This is an organization-wide setting requiring you to opt-in. Please choose your preferred data sharing level in your organization's settings. By default, no data is shared. Granting permission allows Supabase to send information (like schema, logs, or data, depending on your chosen level) to third-party AI providers solely to generate responses." - const condensedPrivacyMessage = isRestrictedByHipaa - ? 'Unavailable because this project is configured as High Compliance, which prevents project metadata from being shared. This cannot be changed in organization settings.' - : 'Requires opting in to sharing data with third-party AI providers. You can opt in via organization settings.' +export function createPrivacyMessageTool(toolInstance: Tool) { + const privacyMessage = + "You don't have permission to use this tool. This is an organization-wide setting requiring you to opt-in. Please choose your preferred data sharing level in your organization's settings. By default, no data is shared. Granting permission allows Supabase to send information (like schema, logs, or data, depending on your chosen level) to third-party AI providers solely to generate responses." + const condensedPrivacyMessage = + 'Requires opting in to sharing data with third-party AI providers. You can opt in via organization settings.' const toolDescription = toolInstance.description const description = typeof toolDescription === 'function' @@ -197,11 +192,7 @@ export function createPrivacyMessageTool( /** * Filter tools based on the AI opt-in level */ -export function filterToolsByOptInLevel( - tools: ToolSet, - aiOptInLevel: AiOptInLevel, - isRestrictedByHipaa: boolean -): ToolSet { +export function filterToolsByOptInLevel(tools: ToolSet, aiOptInLevel: AiOptInLevel): ToolSet { return Object.fromEntries( Object.entries(tools) .filter(([toolName]) => TOOL_CATEGORY_MAP[toolName] !== undefined) @@ -211,7 +202,7 @@ export function filterToolsByOptInLevel( } // If the tool is not allowed, provide a stub that returns a privacy message - return [toolName, createPrivacyMessageTool(toolInstance, isRestrictedByHipaa)] + return [toolName, createPrivacyMessageTool(toolInstance)] }) ) } diff --git a/apps/studio/lib/ai/tools/index.test.ts b/apps/studio/lib/ai/tools/index.test.ts index fcf580f2446..c0157b35069 100644 --- a/apps/studio/lib/ai/tools/index.test.ts +++ b/apps/studio/lib/ai/tools/index.test.ts @@ -18,7 +18,6 @@ const BASE_PARAMS = { connectionString: 'postgresql://localhost', authorization: 'Bearer token', aiOptInLevel: 'schema_and_log_and_data' as const, - isRestrictedByHipaa: false, accessToken: 'access-token', baseUrl: 'https://supabase.com/dashboard', signal: new AbortController().signal, @@ -40,7 +39,6 @@ describe('ai/tools getTools', () => { accessToken: BASE_PARAMS.accessToken, projectRef: BASE_PARAMS.projectRef, aiOptInLevel: BASE_PARAMS.aiOptInLevel, - isRestrictedByHipaa: BASE_PARAMS.isRestrictedByHipaa, signal: BASE_PARAMS.signal, }) expect(tools).toHaveProperty('studio_tool') diff --git a/apps/studio/lib/ai/tools/index.ts b/apps/studio/lib/ai/tools/index.ts index b4b0eabbc1f..b4b041a78c6 100644 --- a/apps/studio/lib/ai/tools/index.ts +++ b/apps/studio/lib/ai/tools/index.ts @@ -17,7 +17,6 @@ export const getTools = async ({ connectionString, authorization, aiOptInLevel, - isRestrictedByHipaa, accessToken, baseUrl, supportMode, @@ -28,8 +27,6 @@ export const getTools = async ({ connectionString: string authorization?: string aiOptInLevel: AiOptInLevel - // Only changes the blocked-tool wording. - isRestrictedByHipaa: boolean accessToken?: string baseUrl?: string supportMode?: boolean @@ -66,7 +63,6 @@ export const getTools = async ({ accessToken, projectRef, aiOptInLevel, - isRestrictedByHipaa, signal, }) } catch (error) { @@ -95,11 +91,7 @@ export const getTools = async ({ // Filter all tools based on the (potentially modified) AI opt-in level const toolsWithSupport = supportMode ? { ...tools, ...getSupportLifecycleTools() } : tools - const filteredTools: ToolSet = filterToolsByOptInLevel( - toolsWithSupport, - aiOptInLevel, - isRestrictedByHipaa - ) + const filteredTools: ToolSet = filterToolsByOptInLevel(toolsWithSupport, aiOptInLevel) return filteredTools } diff --git a/apps/studio/lib/ai/tools/mcp-tools.test.ts b/apps/studio/lib/ai/tools/mcp-tools.test.ts index 538c2d16084..349c642c71a 100644 --- a/apps/studio/lib/ai/tools/mcp-tools.test.ts +++ b/apps/studio/lib/ai/tools/mcp-tools.test.ts @@ -11,7 +11,6 @@ const BASE_PARAMS = { accessToken: 'token', projectRef: 'abcdefghijklmnopqrst', aiOptInLevel: 'schema_and_log_and_data' as const, - isRestrictedByHipaa: false, // A fresh, non-aborted signal by default; lifecycle tests override it signal: new AbortController().signal, } diff --git a/apps/studio/lib/ai/tools/mcp-tools.ts b/apps/studio/lib/ai/tools/mcp-tools.ts index 27b1174d969..d14043528a7 100644 --- a/apps/studio/lib/ai/tools/mcp-tools.ts +++ b/apps/studio/lib/ai/tools/mcp-tools.ts @@ -41,13 +41,11 @@ export const getMcpTools = async ({ accessToken, projectRef, aiOptInLevel, - isRestrictedByHipaa, signal, }: { accessToken: string projectRef: string aiOptInLevel: AiOptInLevel - isRestrictedByHipaa: boolean // Required: the remote client holds an HTTP connection that must be torn down // when the request ends. The caller owns that lifecycle via this signal. signal: AbortSignal @@ -101,11 +99,7 @@ export const getMcpTools = async ({ // write/destructive tools (apply_migration, create_branch, ...) from reaching // the assistant. `read_only` is defense-in-depth (those tools throw at // runtime). Do not remove this filter on the assumption `read_only` suffices. - const allowedMcpTools = filterToolsByOptInLevel( - availableMcpTools, - aiOptInLevel, - isRestrictedByHipaa - ) + const allowedMcpTools = filterToolsByOptInLevel(availableMcpTools, aiOptInLevel) // Remove UI-executed tools handled locally const filteredMcpTools: ToolSet = { ...allowedMcpTools } diff --git a/apps/studio/pages/api/ai/sql/generate-v4.ts b/apps/studio/pages/api/ai/sql/generate-v4.ts index 59998e32472..b68ba949bc3 100644 --- a/apps/studio/pages/api/ai/sql/generate-v4.ts +++ b/apps/studio/pages/api/ai/sql/generate-v4.ts @@ -120,7 +120,6 @@ async function handlePost(req: NextApiRequest, res: NextApiResponse, claims?: Jw const includesLogsSnippets = messagesIncludeLogsSnippets(messages) let aiOptInLevel: AiOptInLevel = 'disabled' - let isRestrictedByHipaa = false let hasAccessToAdvanceModel = false let orgHasHipaaAddon: boolean | undefined let projectIsSensitive: boolean | null | undefined @@ -139,7 +138,6 @@ async function handlePost(req: NextApiRequest, res: NextApiResponse, claims?: Jw const aiDetails = await getAIDetails({ orgSlug: rawOrgSlug, projectRef, authorization }) aiOptInLevel = aiDetails.aiOptInLevel - isRestrictedByHipaa = aiDetails.isRestrictedByHipaa hasAccessToAdvanceModel = aiDetails.hasAccessToAdvanceModel orgHasHipaaAddon = aiDetails.hasHipaaAddon orgId = aiDetails.orgId @@ -189,7 +187,6 @@ async function handlePost(req: NextApiRequest, res: NextApiResponse, claims?: Jw connectionString, authorization, aiOptInLevel, - isRestrictedByHipaa, accessToken, baseUrl: getURL(), supportMode, diff --git a/apps/studio/pages/api/ai/sql/policy.ts b/apps/studio/pages/api/ai/sql/policy.ts index 9f70dbf432c..6edc896bd37 100644 --- a/apps/studio/pages/api/ai/sql/policy.ts +++ b/apps/studio/pages/api/ai/sql/policy.ts @@ -73,7 +73,6 @@ export async function handlePost(req: NextApiRequest, res: NextApiResponse, clai const { tableName, schema, columns = [], projectRef, connectionString, orgSlug, message } = data let aiOptInLevel: AiOptInLevel = 'disabled' - let isRestrictedByHipaa = false if (!IS_PLATFORM) { aiOptInLevel = 'schema' @@ -84,7 +83,6 @@ export async function handlePost(req: NextApiRequest, res: NextApiResponse, clai const aiDetails = await getAIDetails({ orgSlug, projectRef, authorization }) aiOptInLevel = aiDetails.aiOptInLevel - isRestrictedByHipaa = aiDetails.isRestrictedByHipaa } catch (error) { return res.status(400).json({ error: 'There was an error fetching your organization details', @@ -119,7 +117,6 @@ export async function handlePost(req: NextApiRequest, res: NextApiResponse, clai connectionString, authorization, aiOptInLevel, - isRestrictedByHipaa, accessToken, isExplorerEnabled: explorerEnabled, signal: toolsAbortController.signal,