From e9b7acd2b4f392b1645c7bf2ca5b68b76e493174 Mon Sep 17 00:00:00 2001 From: Acbox Date: Wed, 8 Apr 2026 00:59:04 +0800 Subject: [PATCH] fix: guard all legacy migrations against fresh schema for CI compat On fresh databases, 0001_init.up.sql creates providers/provider_id (not llm_providers/llm_provider_id). Migrations 0013, 0041, 0046, 0047 referenced the old names without guards, causing CI migration failures. - 0013: check llm_provider_id column exists before adding old constraint - 0041: check llm_providers table exists before backfill/constraint DDL - 0046: wrap CREATE TABLE in DO block with llm_providers existence check - 0047: use ALTER TABLE IF EXISTS + DO block guard --- .../0013_model_id_unique_per_provider.up.sql | 6 ++- .../0041_provider_model_refactor.up.sql | 13 +++++-- db/migrations/0046_llm_provider_oauth.up.sql | 38 +++++++++++-------- .../0047_add_openai_codex_client_type.up.sql | 23 +++++++---- internal/db/sqlc/models.go | 14 ------- 5 files changed, 52 insertions(+), 42 deletions(-) diff --git a/db/migrations/0013_model_id_unique_per_provider.up.sql b/db/migrations/0013_model_id_unique_per_provider.up.sql index 91612a91..160246d3 100644 --- a/db/migrations/0013_model_id_unique_per_provider.up.sql +++ b/db/migrations/0013_model_id_unique_per_provider.up.sql @@ -7,7 +7,11 @@ BEGIN ALTER TABLE models DROP CONSTRAINT models_model_id_unique; END IF; - IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'models_provider_model_id_unique') THEN + -- Only add old-style constraint when llm_provider_id column exists (pre-0061 schema). + -- Fresh databases already have provider_id with models_provider_id_model_id_unique. + IF NOT EXISTS (SELECT 1 FROM pg_constraint WHERE conname = 'models_provider_model_id_unique') + AND EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'models' AND column_name = 'llm_provider_id') + THEN ALTER TABLE models ADD CONSTRAINT models_provider_model_id_unique UNIQUE (llm_provider_id, model_id); END IF; diff --git a/db/migrations/0041_provider_model_refactor.up.sql b/db/migrations/0041_provider_model_refactor.up.sql index d11ac5ad..976627a6 100644 --- a/db/migrations/0041_provider_model_refactor.up.sql +++ b/db/migrations/0041_provider_model_refactor.up.sql @@ -8,8 +8,11 @@ ALTER TABLE IF EXISTS llm_providers -- 2–6. Backfill and migrate only when old columns exist (idempotent for fresh DBs). DO $$ BEGIN - -- Back-fill provider client_type from models.client_type (old column) - IF EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'models' AND column_name = 'client_type') THEN + -- Back-fill provider client_type from models.client_type (old column). + -- Only runs on pre-0061 schema where llm_providers table still exists. + IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'llm_providers') + AND EXISTS (SELECT 1 FROM information_schema.columns WHERE table_name = 'models' AND column_name = 'client_type') + THEN UPDATE llm_providers p SET client_type = sub.client_type FROM ( @@ -21,8 +24,10 @@ DO $$ BEGIN WHERE p.id = sub.llm_provider_id; END IF; - -- Add CHECK constraint (skip if already present) - IF NOT EXISTS (SELECT 1 FROM information_schema.table_constraints WHERE constraint_name = 'llm_providers_client_type_check') THEN + -- Add CHECK constraint (skip if already present or table renamed) + IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'llm_providers') + AND NOT EXISTS (SELECT 1 FROM information_schema.table_constraints WHERE constraint_name = 'llm_providers_client_type_check') + THEN ALTER TABLE llm_providers ADD CONSTRAINT llm_providers_client_type_check CHECK (client_type IN ('openai-responses', 'openai-completions', 'anthropic-messages', 'google-generative-ai')); diff --git a/db/migrations/0046_llm_provider_oauth.up.sql b/db/migrations/0046_llm_provider_oauth.up.sql index e556976e..13e6e59d 100644 --- a/db/migrations/0046_llm_provider_oauth.up.sql +++ b/db/migrations/0046_llm_provider_oauth.up.sql @@ -1,18 +1,26 @@ -- 0046_llm_provider_oauth -- Add OAuth token storage for LLM providers to support OpenAI Codex OAuth. +-- On fresh databases, provider_oauth_tokens is already created by 0001_init. -CREATE TABLE IF NOT EXISTS llm_provider_oauth_tokens ( - id UUID PRIMARY KEY DEFAULT gen_random_uuid(), - llm_provider_id UUID NOT NULL UNIQUE REFERENCES llm_providers(id) ON DELETE CASCADE, - access_token TEXT NOT NULL DEFAULT '', - refresh_token TEXT NOT NULL DEFAULT '', - expires_at TIMESTAMPTZ, - scope TEXT NOT NULL DEFAULT '', - token_type TEXT NOT NULL DEFAULT '', - state TEXT NOT NULL DEFAULT '', - pkce_code_verifier TEXT NOT NULL DEFAULT '', - created_at TIMESTAMPTZ NOT NULL DEFAULT now(), - updated_at TIMESTAMPTZ NOT NULL DEFAULT now() -); - -CREATE INDEX IF NOT EXISTS idx_llm_provider_oauth_tokens_state ON llm_provider_oauth_tokens(state) WHERE state != ''; +DO $$ +BEGIN + -- Only create old-style table when llm_providers still exists (pre-0061 schema). + IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'llm_providers') + AND NOT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'llm_provider_oauth_tokens') + THEN + CREATE TABLE llm_provider_oauth_tokens ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + llm_provider_id UUID NOT NULL UNIQUE REFERENCES llm_providers(id) ON DELETE CASCADE, + access_token TEXT NOT NULL DEFAULT '', + refresh_token TEXT NOT NULL DEFAULT '', + expires_at TIMESTAMPTZ, + scope TEXT NOT NULL DEFAULT '', + token_type TEXT NOT NULL DEFAULT '', + state TEXT NOT NULL DEFAULT '', + pkce_code_verifier TEXT NOT NULL DEFAULT '', + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now() + ); + CREATE INDEX idx_llm_provider_oauth_tokens_state ON llm_provider_oauth_tokens(state) WHERE state != ''; + END IF; +END $$; diff --git a/db/migrations/0047_add_openai_codex_client_type.up.sql b/db/migrations/0047_add_openai_codex_client_type.up.sql index 37d7b527..358f3e73 100644 --- a/db/migrations/0047_add_openai_codex_client_type.up.sql +++ b/db/migrations/0047_add_openai_codex_client_type.up.sql @@ -1,12 +1,19 @@ -- 0047_add_openai_codex_client_type -- Add openai-codex as a first-class client_type and migrate existing codex-oauth providers. +-- On fresh databases, providers table already has the expanded CHECK from 0001_init. -ALTER TABLE llm_providers DROP CONSTRAINT IF EXISTS llm_providers_client_type_check; -ALTER TABLE llm_providers ADD CONSTRAINT llm_providers_client_type_check - CHECK (client_type IN ('openai-responses', 'openai-completions', 'anthropic-messages', 'google-generative-ai', 'openai-codex')); +ALTER TABLE IF EXISTS llm_providers DROP CONSTRAINT IF EXISTS llm_providers_client_type_check; -UPDATE llm_providers -SET client_type = 'openai-codex', - updated_at = now() -WHERE client_type = 'openai-responses' - AND metadata->>'auth_type' = 'openai-codex-oauth'; +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM information_schema.tables WHERE table_schema = 'public' AND table_name = 'llm_providers') THEN + ALTER TABLE llm_providers ADD CONSTRAINT llm_providers_client_type_check + CHECK (client_type IN ('openai-responses', 'openai-completions', 'anthropic-messages', 'google-generative-ai', 'openai-codex')); + + UPDATE llm_providers + SET client_type = 'openai-codex', + updated_at = now() + WHERE client_type = 'openai-responses' + AND metadata->>'auth_type' = 'openai-codex-oauth'; + END IF; +END $$; diff --git a/internal/db/sqlc/models.go b/internal/db/sqlc/models.go index 36991b22..701187fc 100644 --- a/internal/db/sqlc/models.go +++ b/internal/db/sqlc/models.go @@ -298,20 +298,6 @@ type LifecycleEvent struct { CreatedAt pgtype.Timestamptz `json:"created_at"` } -type LlmProviderOauthToken struct { - ID pgtype.UUID `json:"id"` - LlmProviderID pgtype.UUID `json:"llm_provider_id"` - AccessToken string `json:"access_token"` - RefreshToken string `json:"refresh_token"` - ExpiresAt pgtype.Timestamptz `json:"expires_at"` - Scope string `json:"scope"` - TokenType string `json:"token_type"` - State string `json:"state"` - PkceCodeVerifier string `json:"pkce_code_verifier"` - CreatedAt pgtype.Timestamptz `json:"created_at"` - UpdatedAt pgtype.Timestamptz `json:"updated_at"` -} - type McpConnection struct { ID pgtype.UUID `json:"id"` BotID pgtype.UUID `json:"bot_id"`