From eaa2e98f75fa9ae0d9b820a3f57c7c29d6e89b62 Mon Sep 17 00:00:00 2001 From: Jesse_Chen Date: Sat, 8 Aug 2026 14:31:40 +0800 Subject: [PATCH] Fix admin model catalog visibility --- ...0000_model_admin_runtime_read_policies.sql | 29 +++++++++++++++++++ .../model-configuration-security.test.ts | 10 +++++-- 2 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 frontend/supabase/migrations/20260808020000_model_admin_runtime_read_policies.sql diff --git a/frontend/supabase/migrations/20260808020000_model_admin_runtime_read_policies.sql b/frontend/supabase/migrations/20260808020000_model_admin_runtime_read_policies.sql new file mode 100644 index 00000000..3f6ddbed --- /dev/null +++ b/frontend/supabase/migrations/20260808020000_model_admin_runtime_read_policies.sql @@ -0,0 +1,29 @@ +begin; + +do $$ +begin + if exists (select 1 from pg_roles where rolname = 'admin_runtime') then + drop policy if exists model_providers_admin_select on public.model_providers; + create policy model_providers_admin_select on public.model_providers + for select to admin_runtime using (true); + + drop policy if exists model_configs_admin_select on public.model_configs; + create policy model_configs_admin_select on public.model_configs + for select to admin_runtime using (true); + + drop policy if exists model_config_versions_admin_select on public.model_config_versions; + create policy model_config_versions_admin_select on public.model_config_versions + for select to admin_runtime using (true); + + drop policy if exists model_publish_events_admin_select on public.model_publish_events; + create policy model_publish_events_admin_select on public.model_publish_events + for select to admin_runtime using (true); + + drop policy if exists model_connection_test_evidence_admin_select on public.model_connection_test_evidence; + create policy model_connection_test_evidence_admin_select on public.model_connection_test_evidence + for select to admin_runtime using (true); + end if; +end; +$$; + +commit; diff --git a/frontend/tests/model-configuration-security.test.ts b/frontend/tests/model-configuration-security.test.ts index 0b2c769f..235eec20 100644 --- a/frontend/tests/model-configuration-security.test.ts +++ b/frontend/tests/model-configuration-security.test.ts @@ -31,7 +31,7 @@ async function migrateModelConfigurationFixture(connectionString: string) { const target = join(temporaryRoot, relative.replace("/", "-")); mkdirSync(target, { recursive: true }); for (const filename of readdirSync(source)) { - if (!filename.endsWith(".sql") || filename > "20260808010000_model_provider_emergency_disable.sql") continue; + if (!filename.endsWith(".sql") || filename > "20260808020000_model_admin_runtime_read_policies.sql") continue; if ([ "20260806030000_settle_order_usage_authorization.sql", "20260806050000_operations_feature_flags.sql", @@ -202,6 +202,7 @@ test("database drops secret refs, generates immutable codes, and invalidates evi const sql = (statement: string) => fixture.psql(statement); const sqlAsOwner = (statement: string) => fixture.psqlAs("schema_owner", "schema-owner-test-password", statement); const expectSqlError = (statement: string, pattern: RegExp) => assert.throws(() => sqlAsOwner(statement), pattern); + const sqlAsAdminRuntime = (statement: string) => fixture.psqlAs("admin_runtime", "admin-runtime-test-password", statement); try { await migrateModelConfigurationFixture( @@ -232,7 +233,8 @@ test("database drops secret refs, generates immutable codes, and invalidates evi /model_provider_key_required/, ); - const provider = sql(`select public.admin_save_model_provider('${actorId}',null,'OpenAI','openai',null,'ciphertext-v1',true,'create provider','provider-create')`); + const provider = sqlAsAdminRuntime(`select public.admin_save_model_provider('${actorId}',null,'OpenAI','openai',null,'ciphertext-v1',true,'create provider','provider-create')`); + assert.equal(sqlAsAdminRuntime(`select code from public.model_providers where id='${provider}'`), "openai"); const conflictingProvider = sql(`select public.admin_save_model_provider('${actorId}',null,'OpenAI','openai',null,'ciphertext-other',true,'create collision','provider-collision')`); assert.equal(sql(`select code from public.model_providers where id='${provider}'`), "openai"); assert.equal(sql(`select code from public.model_providers where id='${conflictingProvider}'`), "openai-2"); @@ -260,6 +262,10 @@ test("database drops secret refs, generates immutable codes, and invalidates evi assert.equal(sql(`select public.model_connection_test_is_fresh('${versionOne}',null)`), "f"); sql(`select public.admin_record_model_connection_test('${actorId}','${versionOne}',200,'publish-v1')`); sql(`select public.admin_publish_model('${actorId}','${versionOne}','publish v1','publish-v1')`); + assert.equal(sqlAsAdminRuntime(`select model_id from public.model_configs where model_id='default-model'`), "default-model"); + assert.equal(sqlAsAdminRuntime(`select id from public.model_config_versions where id='${versionOne}'`), versionOne); + assert.equal(sqlAsAdminRuntime(`select to_version_id from public.model_publish_events where to_version_id='${versionOne}' and action='publish'`), versionOne); + assert.equal(sqlAsAdminRuntime(`select version_id from public.model_connection_test_evidence where version_id='${versionOne}' and request_id='publish-v1'`), versionOne); for (const mutation of [ `update public.model_providers set code='mutated' where id='${provider}'`, `update public.model_providers set provider_type='anthropic' where id='${provider}'`,