From a1330e3a8ce2cd45a4d6b2069f2cb609ab0cb423 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Tue, 16 Jun 2026 11:01:43 +0200 Subject: [PATCH] refactor: rename Ai* database identifiers to AI* (AIGOV-369) (#26327) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds `ai` to sqlc's `gen.go.initialisms` in `coderd/database/sqlc.yaml` so the generated DB code follows Go's initialism convention. Adds the matching `ai` -> `AI` case to the dbgen PascalCase helper (`scripts/dbgen/main.go`) so the corresponding `dbmem` / mock identifiers stay in sync. `make gen` regenerates the rest; hand-written call sites that consume DB-generated identifiers (`enterprise/audit/table.go`, `coderd/database/modelmethods.go`, `enterprise/coderd/aigatewaykeys.go`, `coderd/database/dbauthz/*`, etc.) are updated to match. Scope is deliberately limited to the database layer: - `coderd/rbac/*` (resource and scope generators) is untouched — `ResourceAi*` / `ScopeAi*` constants stay on main's casing. - `codersdk/*` (Go SDK) is untouched — `codersdk.ResourceAi*` / `codersdk.APIKeyScopeAi*` constants stay on main's casing, so external Go SDK consumers see no source-level break. - `Aibridge*` identifiers (one SQL token `aibridge`, not `ai_bridge`) are out of scope. On-the-wire values are unchanged: enum strings, RBAC resource type strings, API key scope strings, and JSON tags all stay the same. The HTTP/JSON surface is unaffected. Refs: [AIGOV-369](https://linear.app/codercom/issue/AIGOV-369/change-ai-references-in-coderddatabasemodelsgo-to-ai) 🤖 Generated with [Coder Agents](https://coder.com) --- cli/aibridged.go | 20 +- cli/aibridged_internal_test.go | 22 +- cli/server.go | 14 +- cli/server_aibridge_internal_test.go | 22 +- coderd/ai_providers.go | 6 +- coderd/ai_providers_backfill.go | 4 +- coderd/ai_providers_backfill_test.go | 62 ++-- coderd/ai_providers_migrate.go | 14 +- coderd/ai_providers_migrate_test.go | 12 +- coderd/aiseats/aiseats.go | 6 +- coderd/audit.go | 4 +- coderd/audit/diff.go | 6 +- coderd/audit/request.go | 30 +- coderd/database/check_constraint.go | 24 +- coderd/database/db2sdk/db2sdk.go | 4 +- coderd/database/dbauthz/dbauthz.go | 74 ++-- coderd/database/dbauthz/dbauthz_test.go | 38 +- coderd/database/dbgen/dbgen.go | 2 +- coderd/database/dbmetrics/querymetrics.go | 26 +- coderd/database/dbmock/dbmock.go | 52 +-- coderd/database/foreign_key_constraint.go | 22 +- coderd/database/modelmethods.go | 26 +- coderd/database/models.go | 326 +++++++++--------- coderd/database/querier.go | 26 +- coderd/database/querier_test.go | 40 +-- coderd/database/queries.sql.go | 58 ++-- coderd/database/sqlc.yaml | 5 + coderd/database/unique_constraint.go | 26 +- coderd/exp_chats_internal_test.go | 18 +- coderd/exp_chats_test.go | 4 +- ...kspaceagents_chat_context_internal_test.go | 2 +- coderd/x/chatd/advisor_internal_test.go | 6 +- coderd/x/chatd/chatd_chainmode_test.go | 2 +- coderd/x/chatd/chatd_internal_test.go | 16 +- coderd/x/chatd/chatd_test.go | 6 +- .../generation_preparer_internal_test.go | 2 +- coderd/x/chatd/model_routing_aibridge.go | 8 +- coderd/x/chatd/model_routing_internal_test.go | 44 +-- coderd/x/chatd/subagent_internal_test.go | 14 +- .../x/chatd/title_override_internal_test.go | 12 +- docs/admin/security/audit-logs.md | 6 +- enterprise/aiseats/tracker.go | 4 +- enterprise/aiseats/tracker_test.go | 2 +- enterprise/audit/diff_internal_test.go | 4 +- enterprise/audit/table.go | 12 +- .../cli/aibridgeproxyd_internal_test.go | 4 +- .../coderd/ai_providers_backfill_test.go | 4 +- enterprise/coderd/aibridge.go | 8 +- enterprise/coderd/aibridge_test.go | 18 +- enterprise/coderd/aigatewaykeys.go | 4 +- enterprise/dbcrypt/dbcrypt.go | 36 +- enterprise/dbcrypt/dbcrypt_internal_test.go | 8 +- scripts/dbgen/main.go | 2 + 53 files changed, 612 insertions(+), 605 deletions(-) diff --git a/cli/aibridged.go b/cli/aibridged.go index 0a30c44c40..e838c1db5a 100644 --- a/cli/aibridged.go +++ b/cli/aibridged.go @@ -235,12 +235,12 @@ func buildAIProviderFromRow( // OpenAI-compatible endpoints. Bedrock routes through the Anthropic // provider with a Bedrock discriminator in Settings. switch row.Type { - case database.AiProviderTypeOpenai, - database.AiProviderTypeAzure, - database.AiProviderTypeGoogle, - database.AiProviderTypeOpenaiCompat, - database.AiProviderTypeOpenrouter, - database.AiProviderTypeVercel: + case database.AIProviderTypeOpenai, + database.AIProviderTypeAzure, + database.AIProviderTypeGoogle, + database.AIProviderTypeOpenaiCompat, + database.AIProviderTypeOpenrouter, + database.AIProviderTypeVercel: if len(keys) == 0 && !cfg.AllowBYOK.Value() { return nil, xerrors.Errorf("%s provider has no api keys configured and BYOK is not enabled", row.Type) } @@ -261,13 +261,13 @@ func buildAIProviderFromRow( SendActorHeaders: sendActorHeaders, }), nil - case database.AiProviderTypeAnthropic, database.AiProviderTypeBedrock: + case database.AIProviderTypeAnthropic, database.AIProviderTypeBedrock: bedrock := bedrockConfigFromRow(row, settings) // A row typed 'bedrock' authenticates exclusively via settings; // without populated Bedrock credentials it cannot make upstream // calls, so refuse rather than falling back to an unsigned // Anthropic client. - if row.Type == database.AiProviderTypeBedrock && bedrock == nil { + if row.Type == database.AIProviderTypeBedrock && bedrock == nil { return nil, xerrors.New("bedrock provider has no bedrock credentials configured") } // Bedrock-backed Anthropic authenticates via AWS credentials in @@ -293,7 +293,7 @@ func buildAIProviderFromRow( SendActorHeaders: sendActorHeaders, }, bedrock), nil - case database.AiProviderTypeCopilot: + case database.AIProviderTypeCopilot: // Copilot is always BYOK; the per-user token is supplied on each // request via the Authorization header, so no keypool is built. return aibridge.NewCopilotProvider(aibridge.CopilotConfig{ @@ -310,7 +310,7 @@ func buildAIProviderFromRow( // disabledProviderFromRow builds a Provider stub for a disabled row. // Using provider.DisabledStub rather than a concrete provider avoids -// duplicating the row.Type switch and ensures that a new AiProviderType +// duplicating the row.Type switch and ensures that a new AIProviderType // value is automatically handled without requiring a matching case here. func disabledProviderFromRow(row database.AIProvider) (aibridge.Provider, error) { return aibridge.NewDisabledProviderStub(row.Name, string(row.Type)), nil diff --git a/cli/aibridged_internal_test.go b/cli/aibridged_internal_test.go index 536ae1d490..20d0164502 100644 --- a/cli/aibridged_internal_test.go +++ b/cli/aibridged_internal_test.go @@ -239,7 +239,7 @@ func TestBuildProviders(t *testing.T) { t.Run("NativeAnthropicDefaultBaseURL", func(t *testing.T) { t.Parallel() row := database.AIProvider{ - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, Name: aibridge.ProviderAnthropic, BaseUrl: "https://api.anthropic.com/", } @@ -249,7 +249,7 @@ func TestBuildProviders(t *testing.T) { t.Run("NativeAnthropicCustomBaseURL", func(t *testing.T) { t.Parallel() row := database.AIProvider{ - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, Name: "anthropic-proxy", BaseUrl: "https://internal-proxy.example.com/anthropic/", } @@ -263,7 +263,7 @@ func TestBuildProviders(t *testing.T) { model := "anthropic.claude-3-5-sonnet-20241022-v2:0" smallModel := "anthropic.claude-3-5-haiku-20241022-v1:0" row := database.AIProvider{ - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, Name: "anthropic-bedrock", BaseUrl: "https://bedrock-runtime.us-west-2.amazonaws.com/", } @@ -292,7 +292,7 @@ func TestBuildProviders(t *testing.T) { // produce a Bedrock config; the provider's generic BaseUrl is // not a Bedrock detection signal. row := database.AIProvider{ - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, Name: "anthropic-empty-bedrock", BaseUrl: "https://api.anthropic.com/", } @@ -319,7 +319,7 @@ func TestBuildProvidersSkipsBadRows(t *testing.T) { logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true}) dbgen.AIProvider(t, db, database.AIProvider{ - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, Name: "anthropic-broken", BaseUrl: "https://api.anthropic.com/", Settings: sql.NullString{String: "not-json", Valid: true}, @@ -344,7 +344,7 @@ func TestBuildProvidersSkipsBadRows(t *testing.T) { // rows without keys when BYOK is disabled. The row must be // classified as error and excluded from the snapshot. dbgen.AIProvider(t, db, database.AIProvider{ - Type: database.AiProviderTypeAzure, + Type: database.AIProviderTypeAzure, Name: "azure-openai", BaseUrl: "https://example.openai.azure.com/", }) @@ -363,13 +363,13 @@ func TestBuildProvidersSkipsBadRows(t *testing.T) { logger := slogtest.Make(t, &slogtest.Options{IgnoreErrors: true}) dbgen.AIProvider(t, db, database.AIProvider{ - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, Name: "anthropic-broken", BaseUrl: "https://api.anthropic.com/", Settings: sql.NullString{String: "{not valid json", Valid: true}, }) good := dbgen.AIProvider(t, db, database.AIProvider{ - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, Name: "openai-good", BaseUrl: "https://api.openai.com/", }) @@ -401,7 +401,7 @@ func TestBuildProvidersSkipsBadRows(t *testing.T) { { name: "OpenAI", row: database.AIProvider{ - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, Name: "openai-off", BaseUrl: "https://api.openai.com/", }, @@ -412,7 +412,7 @@ func TestBuildProvidersSkipsBadRows(t *testing.T) { // must reach them too. No keys, no bedrock settings. name: "Anthropic", row: database.AIProvider{ - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, Name: "anthropic-off", BaseUrl: "https://api.anthropic.com/", }, @@ -420,7 +420,7 @@ func TestBuildProvidersSkipsBadRows(t *testing.T) { { name: "Bedrock", row: database.AIProvider{ - Type: database.AiProviderTypeBedrock, + Type: database.AIProviderTypeBedrock, Name: "bedrock-off", BaseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com/", }, diff --git a/cli/server.go b/cli/server.go index 1dbdc5a152..51357a9dca 100644 --- a/cli/server.go +++ b/cli/server.go @@ -3074,26 +3074,26 @@ func ReadAIProvidersFromEnv(logger slog.Logger, environ []string) ([]codersdk.AI // BEDROCK_* fields are accepted on anthropic (mutually exclusive // with KEYS) and required on bedrock. Any other TYPE rejecting // them prevents silently-ignored credentials. - isBedrockType := providerType == database.AiProviderTypeBedrock - isAnthropicType := providerType == database.AiProviderTypeAnthropic + isBedrockType := providerType == database.AIProviderTypeBedrock + isAnthropicType := providerType == database.AIProviderTypeAnthropic if !isAnthropicType && !isBedrockType && isBedrock { return nil, xerrors.Errorf("provider %d (%s): BEDROCK_* fields are only supported with TYPE %q or %q", - i, p.Type, database.AiProviderTypeAnthropic, database.AiProviderTypeBedrock) + i, p.Type, database.AIProviderTypeAnthropic, database.AIProviderTypeBedrock) } if isBedrockType && !isBedrock { return nil, xerrors.Errorf("provider %d (%s): TYPE %q requires BEDROCK_* fields to be configured", - i, p.Type, database.AiProviderTypeBedrock) + i, p.Type, database.AIProviderTypeBedrock) } if isBedrockType && len(p.Keys) > 0 { return nil, xerrors.Errorf("provider %d (%s): KEY/KEYS are not supported for TYPE %q (use BEDROCK_* fields)", - i, p.Type, database.AiProviderTypeBedrock) + i, p.Type, database.AIProviderTypeBedrock) } - if providerType == database.AiProviderTypeCopilot && len(p.Keys) > 0 { + if providerType == database.AIProviderTypeCopilot && len(p.Keys) > 0 { return nil, xerrors.Errorf("provider %d (%s): KEY/KEYS are not supported for TYPE %q", - i, p.Type, database.AiProviderTypeCopilot) + i, p.Type, database.AIProviderTypeCopilot) } // An Anthropic provider authenticates either via a bearer diff --git a/cli/server_aibridge_internal_test.go b/cli/server_aibridge_internal_test.go index 09311a145a..21711b0289 100644 --- a/cli/server_aibridge_internal_test.go +++ b/cli/server_aibridge_internal_test.go @@ -377,7 +377,7 @@ func TestReadAIProvidersFromEnv(t *testing.T) { }, expected: []codersdk.AIProviderConfig{ { - Type: string(database.AiProviderTypeBedrock), + Type: string(database.AIProviderTypeBedrock), Name: "bedrock-prod", BedrockRegion: "us-east-1", BedrockAccessKeys: []string{"AKID"}, @@ -642,7 +642,7 @@ func TestBuildAIProviderFromRowSetsAPIDumpDir(t *testing.T) { name: "OpenAI", row: database.AIProvider{ Enabled: true, - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, Name: "openai", BaseUrl: "https://api.openai.com/", }, @@ -652,7 +652,7 @@ func TestBuildAIProviderFromRowSetsAPIDumpDir(t *testing.T) { name: "Anthropic", row: database.AIProvider{ Enabled: true, - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, Name: "anthropic", BaseUrl: "https://api.anthropic.com/", }, @@ -662,7 +662,7 @@ func TestBuildAIProviderFromRowSetsAPIDumpDir(t *testing.T) { name: "Copilot", row: database.AIProvider{ Enabled: true, - Type: database.AiProviderTypeCopilot, + Type: database.AIProviderTypeCopilot, Name: "copilot", BaseUrl: "https://api.githubcopilot.com/", }, @@ -672,7 +672,7 @@ func TestBuildAIProviderFromRowSetsAPIDumpDir(t *testing.T) { name: "Azure", row: database.AIProvider{ Enabled: true, - Type: database.AiProviderTypeAzure, + Type: database.AIProviderTypeAzure, Name: "azure", BaseUrl: "https://example.openai.azure.com/", }, @@ -682,7 +682,7 @@ func TestBuildAIProviderFromRowSetsAPIDumpDir(t *testing.T) { name: "Google", row: database.AIProvider{ Enabled: true, - Type: database.AiProviderTypeGoogle, + Type: database.AIProviderTypeGoogle, Name: "google", BaseUrl: "https://generativelanguage.googleapis.com/v1beta/openai/", }, @@ -692,7 +692,7 @@ func TestBuildAIProviderFromRowSetsAPIDumpDir(t *testing.T) { name: "OpenAICompat", row: database.AIProvider{ Enabled: true, - Type: database.AiProviderTypeOpenaiCompat, + Type: database.AIProviderTypeOpenaiCompat, Name: "openai-compat", BaseUrl: "https://compat.example.com/v1/", }, @@ -702,7 +702,7 @@ func TestBuildAIProviderFromRowSetsAPIDumpDir(t *testing.T) { name: "OpenRouter", row: database.AIProvider{ Enabled: true, - Type: database.AiProviderTypeOpenrouter, + Type: database.AIProviderTypeOpenrouter, Name: "openrouter", BaseUrl: "https://openrouter.ai/api/v1/", }, @@ -712,7 +712,7 @@ func TestBuildAIProviderFromRowSetsAPIDumpDir(t *testing.T) { name: "Vercel", row: database.AIProvider{ Enabled: true, - Type: database.AiProviderTypeVercel, + Type: database.AIProviderTypeVercel, Name: "vercel", BaseUrl: "https://api.v0.dev/v1/", }, @@ -722,7 +722,7 @@ func TestBuildAIProviderFromRowSetsAPIDumpDir(t *testing.T) { name: "Bedrock", row: database.AIProvider{ Enabled: true, - Type: database.AiProviderTypeBedrock, + Type: database.AIProviderTypeBedrock, Name: "bedrock", BaseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com/", Settings: mustMarshalSettings(codersdk.AIProviderSettings{ @@ -757,7 +757,7 @@ func TestBuildAIProviderFromRowBedrockWithoutSettings(t *testing.T) { _, err := buildAIProviderFromRow(database.AIProvider{ Enabled: true, - Type: database.AiProviderTypeBedrock, + Type: database.AIProviderTypeBedrock, Name: "bedrock-no-settings", BaseUrl: "https://bedrock-runtime.us-east-1.amazonaws.com/", }, nil, codersdk.AIBridgeConfig{ diff --git a/coderd/ai_providers.go b/coderd/ai_providers.go index 19f7c7e20d..49e5bb8750 100644 --- a/coderd/ai_providers.go +++ b/coderd/ai_providers.go @@ -325,8 +325,8 @@ func (api *API) aiProvidersUpdate(rw http.ResponseWriter, r *http.Request) { // misconfiguration from sitting silently in the encrypted // blob. if existing.Bedrock != nil && - old.Type != database.AiProviderTypeAnthropic && - old.Type != database.AiProviderTypeBedrock { + old.Type != database.AIProviderTypeAnthropic && + old.Type != database.AIProviderTypeBedrock { return errAIProviderBedrockTypeMismatch } settings, err := encodeAIProviderSettings(existing) @@ -340,7 +340,7 @@ func (api *API) aiProvidersUpdate(rw http.ResponseWriter, r *http.Request) { return errBedrockRejectsAPIKeys } - if req.APIKeys != nil && old.Type == database.AiProviderTypeCopilot && len(*req.APIKeys) > 0 { + if req.APIKeys != nil && old.Type == database.AIProviderTypeCopilot && len(*req.APIKeys) > 0 { return errCopilotRejectsAPIKeys } diff --git a/coderd/ai_providers_backfill.go b/coderd/ai_providers_backfill.go index 99b14075b9..9ab2e8c95e 100644 --- a/coderd/ai_providers_backfill.go +++ b/coderd/ai_providers_backfill.go @@ -32,7 +32,7 @@ func BackfillBedrockProviderType(ctx context.Context, db database.Store, logger } var promoted int for _, provider := range providers { - if provider.Type != database.AiProviderTypeAnthropic { + if provider.Type != database.AIProviderTypeAnthropic { continue } settings, err := db2sdk.AIProviderSettings(provider.Settings) @@ -46,7 +46,7 @@ func BackfillBedrockProviderType(ctx context.Context, db database.Store, logger } _, err = db.UpdateAIProvider(sysCtx, database.UpdateAIProviderParams{ ID: provider.ID, - Type: database.AiProviderTypeBedrock, + Type: database.AIProviderTypeBedrock, DisplayName: provider.DisplayName, Enabled: provider.Enabled, BaseUrl: provider.BaseUrl, diff --git a/coderd/ai_providers_backfill_test.go b/coderd/ai_providers_backfill_test.go index 16d6961072..a813078193 100644 --- a/coderd/ai_providers_backfill_test.go +++ b/coderd/ai_providers_backfill_test.go @@ -49,16 +49,16 @@ func TestBackfillBedrockProviderType(t *testing.T) { t.Run("PromotesLegacyRow", func(t *testing.T) { legacy := dbgen.AIProvider(t, db, database.AIProvider{ - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, Settings: bedrockSettings, }) - require.Equal(t, database.AiProviderTypeAnthropic, legacy.Type, "pre-condition: row must start as anthropic") + require.Equal(t, database.AIProviderTypeAnthropic, legacy.Type, "pre-condition: row must start as anthropic") coderd.BackfillBedrockProviderType(ctx, db, logger) row, err := db.GetAIProviderByName(ctx, legacy.Name) require.NoError(t, err) - require.Equal(t, database.AiProviderTypeBedrock, row.Type) + require.Equal(t, database.AIProviderTypeBedrock, row.Type) }) t.Run("Idempotent", func(t *testing.T) { @@ -70,7 +70,7 @@ func TestBackfillBedrockProviderType(t *testing.T) { }) require.NoError(t, err) for _, r := range before { - require.Equal(t, database.AiProviderTypeBedrock, r.Type, + require.Equal(t, database.AIProviderTypeBedrock, r.Type, "pre-condition: all rows must already be promoted before testing idempotency") } @@ -89,37 +89,37 @@ func TestBackfillBedrockProviderType(t *testing.T) { t.Run("PreservesNativeAnthropicRow", func(t *testing.T) { native := dbgen.AIProvider(t, db, database.AIProvider{ - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, }) - require.Equal(t, database.AiProviderTypeAnthropic, native.Type, "pre-condition") + require.Equal(t, database.AIProviderTypeAnthropic, native.Type, "pre-condition") coderd.BackfillBedrockProviderType(ctx, db, logger) row, err := db.GetAIProviderByName(ctx, native.Name) require.NoError(t, err) - require.Equal(t, database.AiProviderTypeAnthropic, row.Type) + require.Equal(t, database.AIProviderTypeAnthropic, row.Type) }) t.Run("PreservesNativeBedrockRow", func(t *testing.T) { native := dbgen.AIProvider(t, db, database.AIProvider{ - Type: database.AiProviderTypeBedrock, + Type: database.AIProviderTypeBedrock, Settings: bedrockSettings, }) - require.Equal(t, database.AiProviderTypeBedrock, native.Type, "pre-condition") + require.Equal(t, database.AIProviderTypeBedrock, native.Type, "pre-condition") coderd.BackfillBedrockProviderType(ctx, db, logger) row, err := db.GetAIProviderByName(ctx, native.Name) require.NoError(t, err) - require.Equal(t, database.AiProviderTypeBedrock, row.Type) + require.Equal(t, database.AIProviderTypeBedrock, row.Type) }) t.Run("SkipsDeletedRows", func(t *testing.T) { deleted := dbgen.AIProvider(t, db, database.AIProvider{ - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, Settings: bedrockSettings, }) - require.Equal(t, database.AiProviderTypeAnthropic, deleted.Type, "pre-condition") + require.Equal(t, database.AIProviderTypeAnthropic, deleted.Type, "pre-condition") require.NoError(t, db.DeleteAIProviderByID(ctx, deleted.ID)) coderd.BackfillBedrockProviderType(ctx, db, logger) @@ -133,7 +133,7 @@ func TestBackfillBedrockProviderType(t *testing.T) { for _, r := range row { if r.ID == deleted.ID { found = true - require.Equal(t, database.AiProviderTypeAnthropic, r.Type, "deleted row must not be promoted") + require.Equal(t, database.AIProviderTypeAnthropic, r.Type, "deleted row must not be promoted") } } require.True(t, found, "deleted row must appear in IncludeDeleted result set") @@ -141,17 +141,17 @@ func TestBackfillBedrockProviderType(t *testing.T) { t.Run("IncludesDisabledRows", func(t *testing.T) { disabled := dbgen.AIProvider(t, db, database.AIProvider{ - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, Enabled: false, Settings: bedrockSettings, }) - require.Equal(t, database.AiProviderTypeAnthropic, disabled.Type, "pre-condition") + require.Equal(t, database.AIProviderTypeAnthropic, disabled.Type, "pre-condition") coderd.BackfillBedrockProviderType(ctx, db, logger) row, err := db.GetAIProviderByName(ctx, disabled.Name) require.NoError(t, err) - require.Equal(t, database.AiProviderTypeBedrock, row.Type, "disabled legacy row must be promoted") + require.Equal(t, database.AIProviderTypeBedrock, row.Type, "disabled legacy row must be promoted") }) t.Run("PreservesAnthropicRowWithNonBedrockSettings", func(t *testing.T) { @@ -159,39 +159,39 @@ func TestBackfillBedrockProviderType(t *testing.T) { // and the row is skipped via the unparsable-settings path, not the // settings.Bedrock == nil guard. Either way the row must stay anthropic. nonBedrock := dbgen.AIProvider(t, db, database.AIProvider{ - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, Settings: sql.NullString{String: "{}", Valid: true}, }) - require.Equal(t, database.AiProviderTypeAnthropic, nonBedrock.Type, "pre-condition") + require.Equal(t, database.AIProviderTypeAnthropic, nonBedrock.Type, "pre-condition") coderd.BackfillBedrockProviderType(ctx, db, logger) row, err := db.GetAIProviderByName(ctx, nonBedrock.Name) require.NoError(t, err) - require.Equal(t, database.AiProviderTypeAnthropic, row.Type, "anthropic row with non-bedrock settings must not be promoted") + require.Equal(t, database.AIProviderTypeAnthropic, row.Type, "anthropic row with non-bedrock settings must not be promoted") }) t.Run("SkipsUnparsableSettings", func(t *testing.T) { malformed := dbgen.AIProvider(t, db, database.AIProvider{ - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, Settings: sql.NullString{String: "{", Valid: true}, }) - require.Equal(t, database.AiProviderTypeAnthropic, malformed.Type, "pre-condition") + require.Equal(t, database.AIProviderTypeAnthropic, malformed.Type, "pre-condition") good := dbgen.AIProvider(t, db, database.AIProvider{ - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, Settings: bedrockSettings, }) - require.Equal(t, database.AiProviderTypeAnthropic, good.Type, "pre-condition") + require.Equal(t, database.AIProviderTypeAnthropic, good.Type, "pre-condition") coderd.BackfillBedrockProviderType(ctx, db, logger) malformedRow, err := db.GetAIProviderByName(ctx, malformed.Name) require.NoError(t, err) - require.Equal(t, database.AiProviderTypeAnthropic, malformedRow.Type, "row with unparsable settings must not be touched") + require.Equal(t, database.AIProviderTypeAnthropic, malformedRow.Type, "row with unparsable settings must not be touched") goodRow, err := db.GetAIProviderByName(ctx, good.Name) require.NoError(t, err) - require.Equal(t, database.AiProviderTypeBedrock, goodRow.Type, "valid row alongside unparsable one must still be promoted") + require.Equal(t, database.AIProviderTypeBedrock, goodRow.Type, "valid row alongside unparsable one must still be promoted") }) // --- chat_model_configs.provider backfill --- @@ -203,7 +203,7 @@ func TestBackfillBedrockProviderType(t *testing.T) { // type=anthropic. The stored provider string is "anthropic" but the // linked provider row now has type=bedrock. bedrockProvider := dbgen.AIProvider(t, db, database.AIProvider{ - Type: database.AiProviderTypeBedrock, + Type: database.AIProviderTypeBedrock, Settings: bedrockSettings, }) staleConfig := dbgen.ChatModelConfig(t, db, database.ChatModelConfig{ @@ -240,7 +240,7 @@ func TestBackfillBedrockProviderType(t *testing.T) { // A model config with provider="openai" linked to a Bedrock provider // must not be touched. Only "anthropic" → "bedrock" is in scope. bedrockProvider := dbgen.AIProvider(t, db, database.AIProvider{ - Type: database.AiProviderTypeBedrock, + Type: database.AIProviderTypeBedrock, Settings: bedrockSettings, }) openAIConfig := dbgen.ChatModelConfig(t, db, database.ChatModelConfig{ @@ -261,7 +261,7 @@ func TestBackfillBedrockProviderType(t *testing.T) { // the linked provider is deleted and therefore excluded by the // AND deleted = FALSE condition in the query. deletedProvider := dbgen.AIProvider(t, db, database.AIProvider{ - Type: database.AiProviderTypeBedrock, + Type: database.AIProviderTypeBedrock, Settings: bedrockSettings, }) staleConfig := dbgen.ChatModelConfig(t, db, database.ChatModelConfig{ @@ -281,7 +281,7 @@ func TestBackfillBedrockProviderType(t *testing.T) { // The SQL query guards on deleted = FALSE. Capture the config ID // before deletion so we delete the right row regardless of ordering. bedrockProvider := dbgen.AIProvider(t, db, database.AIProvider{ - Type: database.AiProviderTypeBedrock, + Type: database.AIProviderTypeBedrock, Settings: bedrockSettings, }) cfg := dbgen.ChatModelConfig(t, db, database.ChatModelConfig{ @@ -323,7 +323,7 @@ func TestBackfillBedrockProviderType(t *testing.T) { db.EXPECT(). GetAIProviders(gomock.Any(), gomock.Any()). Return([]database.AIProvider{{ - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, Settings: bedrockSettings, }}, nil) db.EXPECT(). @@ -342,7 +342,7 @@ func TestBackfillBedrockProviderType(t *testing.T) { db.EXPECT(). GetAIProviders(gomock.Any(), gomock.Any()). Return([]database.AIProvider{{ - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, Settings: bedrockSettings, }}, nil) db.EXPECT(). diff --git a/coderd/ai_providers_migrate.go b/coderd/ai_providers_migrate.go index cc317a57fa..7ec6a997b0 100644 --- a/coderd/ai_providers_migrate.go +++ b/coderd/ai_providers_migrate.go @@ -130,8 +130,8 @@ func SeedAIProvidersFromEnv( // type=anthropic to type=bedrock by the startup backfill // is not mistaken for drift on the next startup. existingType := existing.Type - if existingSettings.Bedrock != nil && existing.Type == database.AiProviderTypeAnthropic { - existingType = database.AiProviderTypeBedrock + if existingSettings.Bedrock != nil && existing.Type == database.AIProviderTypeAnthropic { + existingType = database.AIProviderTypeBedrock } existingDP := desiredAIProvider{ Type: existingType, @@ -309,7 +309,7 @@ func providersFromEnv(ctx context.Context, cfg codersdk.AIBridgeConfig, logger s if cfg.LegacyOpenAI.Key.String() != "" { dp := desiredAIProvider{ Name: aibridge.ProviderOpenAI, - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, BaseURL: cfg.LegacyOpenAI.BaseURL.String(), Keys: []string{cfg.LegacyOpenAI.Key.String()}, } @@ -334,10 +334,10 @@ func providersFromEnv(ctx context.Context, cfg codersdk.AIBridgeConfig, logger s if hasAnthropicKey || hasLegacyBedrock { dp := desiredAIProvider{ Name: aibridge.ProviderAnthropic, - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, } if hasLegacyBedrock { - dp.Type = database.AiProviderTypeBedrock + dp.Type = database.AIProviderTypeBedrock if hasAnthropicKey { logger.Warn(ctx, "ignoring legacy Anthropic API key because Bedrock credentials are configured; Bedrock authenticates via access keys or credential chain", slog.F("provider", aibridge.ProviderAnthropic), @@ -389,7 +389,7 @@ func providersFromEnv(ctx context.Context, cfg codersdk.AIBridgeConfig, logger s // AIProviderBedrockSettings.IsConfigured() so the legacy and // indexed paths agree on what counts as a Bedrock provider. isBedrock := false - if dp.Type == database.AiProviderTypeAnthropic || dp.Type == database.AiProviderTypeBedrock { + if dp.Type == database.AIProviderTypeAnthropic || dp.Type == database.AIProviderTypeBedrock { var accessKey, accessKeySecret string if len(p.BedrockAccessKeys) > 0 { accessKey = p.BedrockAccessKeys[0] @@ -426,7 +426,7 @@ func providersFromEnv(ctx context.Context, cfg codersdk.AIBridgeConfig, logger s slog.F("ignored_key_count", len(p.Keys)), ) } - case dp.Type == database.AiProviderTypeCopilot: + case dp.Type == database.AIProviderTypeCopilot: if len(p.Keys) > 0 { logger.Warn(ctx, "ignoring bearer keys configured on Copilot AI provider; Copilot authenticates via request-time GitHub OAuth tokens", slog.F("name", name), diff --git a/coderd/ai_providers_migrate_test.go b/coderd/ai_providers_migrate_test.go index 3e4324e17d..c9fc607e78 100644 --- a/coderd/ai_providers_migrate_test.go +++ b/coderd/ai_providers_migrate_test.go @@ -47,7 +47,7 @@ func TestSeedAIProvidersFromEnv(t *testing.T) { // One row exists for "openai". row, err := db.GetAIProviderByName(ctx, "openai") require.NoError(t, err) - require.Equal(t, database.AiProviderTypeOpenai, row.Type) + require.Equal(t, database.AIProviderTypeOpenai, row.Type) require.Equal(t, "https://api.openai.com/v1", row.BaseUrl) require.True(t, row.Enabled) @@ -161,7 +161,7 @@ func TestSeedAIProvidersFromEnv(t *testing.T) { row, err := db.GetAIProviderByName(ctx, "anthropic") require.NoError(t, err) - require.Equal(t, database.AiProviderTypeBedrock, row.Type) + require.Equal(t, database.AIProviderTypeBedrock, row.Type) require.Contains(t, row.Settings.String, "us-west-2") require.Contains(t, row.Settings.String, "anthropic.claude-3-5-sonnet") require.Contains(t, row.Settings.String, "anthropic.claude-3-5-haiku") @@ -280,7 +280,7 @@ func TestSeedAIProvidersFromEnv(t *testing.T) { oa, err := db.GetAIProviderByName(ctx, "primary-openai") require.NoError(t, err) - require.Equal(t, database.AiProviderTypeOpenai, oa.Type) + require.Equal(t, database.AIProviderTypeOpenai, oa.Type) oaKeys, err := db.GetAIProviderKeysByProviderID(ctx, oa.ID) require.NoError(t, err) require.Len(t, oaKeys, 2) @@ -289,7 +289,7 @@ func TestSeedAIProvidersFromEnv(t *testing.T) { an, err := db.GetAIProviderByName(ctx, "primary-anthropic") require.NoError(t, err) - require.Equal(t, database.AiProviderTypeAnthropic, an.Type) + require.Equal(t, database.AIProviderTypeAnthropic, an.Type) // Plain bearer-token Anthropic with no Bedrock fields: no // settings blob, one bearer key. require.False(t, an.Settings.Valid, "no settings blob for bearer-token Anthropic") @@ -625,7 +625,7 @@ func TestSeedAIProvidersFromEnv(t *testing.T) { require.NoError(t, err) _, err = db.UpdateAIProvider(ctx, database.UpdateAIProviderParams{ ID: row.ID, - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, DisplayName: row.DisplayName, Enabled: row.Enabled, BaseUrl: row.BaseUrl, @@ -635,7 +635,7 @@ func TestSeedAIProvidersFromEnv(t *testing.T) { require.NoError(t, err) row, err = db.GetAIProviderByName(ctx, "anthropic") require.NoError(t, err) - require.Equal(t, database.AiProviderTypeAnthropic, row.Type, "pre-condition: row must be anthropic before seed runs") + require.Equal(t, database.AIProviderTypeAnthropic, row.Type, "pre-condition: row must be anthropic before seed runs") require.NoError(t, coderd.SeedAIProvidersFromEnv(ctx, db, cfg, testLogger(t))) }) diff --git a/coderd/aiseats/aiseats.go b/coderd/aiseats/aiseats.go index 06c48e28a6..a22d980ae9 100644 --- a/coderd/aiseats/aiseats.go +++ b/coderd/aiseats/aiseats.go @@ -11,18 +11,18 @@ import ( ) type Reason struct { - EventType database.AiSeatUsageReason + EventType database.AISeatUsageReason Description string } // ReasonAIBridge constructs a reason for usage originating from AI Bridge. func ReasonAIBridge(description string) Reason { - return Reason{EventType: database.AiSeatUsageReasonAibridge, Description: description} + return Reason{EventType: database.AISeatUsageReasonAibridge, Description: description} } // ReasonTask constructs a reason for usage originating from tasks. func ReasonTask(description string) Reason { - return Reason{EventType: database.AiSeatUsageReasonTask, Description: description} + return Reason{EventType: database.AISeatUsageReasonTask, Description: description} } // SeatTracker records AI seat consumption state. diff --git a/coderd/audit.go b/coderd/audit.go index 3b38f8a7c2..44ed30770b 100644 --- a/coderd/audit.go +++ b/coderd/audit.go @@ -608,7 +608,7 @@ func (api *API) auditLogResourceLink(ctx context.Context, alog database.GetAudit // TODO(PLAT-102): point at the user secrets management page once // it ships. Until then, the audit row links nowhere. return "" - case database.ResourceTypeGroupAiBudget: + case database.ResourceTypeGroupAIBudget: // The resource_id is the group's UUID; link to the group's // settings page. group, err := api.Database.GetGroupByID(ctx, alog.AuditLog.ResourceID) @@ -620,7 +620,7 @@ func (api *API) auditLogResourceLink(ctx context.Context, alog database.GetAudit return "" } return fmt.Sprintf("/organizations/%s/groups/%s", org.Name, group.Name) - case database.ResourceTypeUserAiBudgetOverride: + case database.ResourceTypeUserAIBudgetOverride: // TODO: point at the user's AI budget override management page // once it ships. Until then, the audit row links nowhere. return "" diff --git a/coderd/audit/diff.go b/coderd/audit/diff.go index 49232f8d69..c28ec8f7cb 100644 --- a/coderd/audit/diff.go +++ b/coderd/audit/diff.go @@ -33,13 +33,13 @@ type Auditable interface { idpsync.GroupSyncSettings | idpsync.RoleSyncSettings | database.TaskTable | - database.AiSeatState | + database.AISeatState | database.AIProvider | database.AIProviderKey | database.AIGatewayKey | database.Chat | - database.AuditableGroupAiBudget | - database.AuditableUserAiBudgetOverride | + database.AuditableGroupAIBudget | + database.AuditableUserAIBudgetOverride | database.UserSecret | database.UserSkill } diff --git a/coderd/audit/request.go b/coderd/audit/request.go index 49162990c2..88671316e7 100644 --- a/coderd/audit/request.go +++ b/coderd/audit/request.go @@ -132,7 +132,7 @@ func ResourceTarget[T Auditable](tgt T) string { return "Organization Role Sync" case database.TaskTable: return typed.Name - case database.AiSeatState: + case database.AISeatState: return "AI Seat" case database.AIProvider: return typed.Name @@ -140,9 +140,9 @@ func ResourceTarget[T Auditable](tgt T) string { return typed.ID.String() case database.AIGatewayKey: return typed.Name - case database.AuditableGroupAiBudget: + case database.AuditableGroupAIBudget: return typed.GroupName - case database.AuditableUserAiBudgetOverride: + case database.AuditableUserAIBudgetOverride: return typed.Username case database.Chat: // Chat titles can contain sensitive content (secrets, internal @@ -220,7 +220,7 @@ func ResourceID[T Auditable](tgt T) uuid.UUID { return noID // Org field on audit log has org id case database.TaskTable: return typed.ID - case database.AiSeatState: + case database.AISeatState: return typed.UserID case database.AIProvider: return typed.ID @@ -228,9 +228,9 @@ func ResourceID[T Auditable](tgt T) uuid.UUID { return typed.ID case database.AIGatewayKey: return typed.ID - case database.AuditableGroupAiBudget: + case database.AuditableGroupAIBudget: return typed.GroupID - case database.AuditableUserAiBudgetOverride: + case database.AuditableUserAIBudgetOverride: return typed.UserID case database.Chat: return typed.ID @@ -293,18 +293,18 @@ func ResourceType[T Auditable](tgt T) database.ResourceType { return database.ResourceTypeIdpSyncSettingsGroup case database.TaskTable: return database.ResourceTypeTask - case database.AiSeatState: - return database.ResourceTypeAiSeat + case database.AISeatState: + return database.ResourceTypeAISeat case database.AIProvider: return database.ResourceTypeAIProvider case database.AIProviderKey: return database.ResourceTypeAIProviderKey case database.AIGatewayKey: return database.ResourceTypeAIGatewayKey - case database.AuditableGroupAiBudget: - return database.ResourceTypeGroupAiBudget - case database.AuditableUserAiBudgetOverride: - return database.ResourceTypeUserAiBudgetOverride + case database.AuditableGroupAIBudget: + return database.ResourceTypeGroupAIBudget + case database.AuditableUserAIBudgetOverride: + return database.ResourceTypeUserAIBudgetOverride case database.Chat: return database.ResourceTypeChat case database.UserSecret: @@ -369,7 +369,7 @@ func ResourceRequiresOrgID[T Auditable]() bool { return true case database.TaskTable: return true - case database.AiSeatState: + case database.AISeatState: return false case database.AIProvider: // AI providers are deployment-scoped, not org-scoped. @@ -381,10 +381,10 @@ func ResourceRequiresOrgID[T Auditable]() bool { case database.AIGatewayKey: // AI Gateway keys are deployment-scoped, not org-scoped. return false - case database.AuditableGroupAiBudget: + case database.AuditableGroupAIBudget: // Group AI budgets are org-scoped through their parent group. return true - case database.AuditableUserAiBudgetOverride: + case database.AuditableUserAIBudgetOverride: // User AI budget overrides are org-scoped through their // attributed group. return true diff --git a/coderd/database/check_constraint.go b/coderd/database/check_constraint.go index c1fa991032..67122363f5 100644 --- a/coderd/database/check_constraint.go +++ b/coderd/database/check_constraint.go @@ -6,17 +6,17 @@ type CheckConstraint string // CheckConstraint enums. const ( - CheckAiGatewayKeysHashedSecretCheck CheckConstraint = "ai_gateway_keys_hashed_secret_check" // ai_gateway_keys - CheckAiGatewayKeysNameCheck CheckConstraint = "ai_gateway_keys_name_check" // ai_gateway_keys - CheckAiGatewayKeysSecretPrefixCheck CheckConstraint = "ai_gateway_keys_secret_prefix_check" // ai_gateway_keys - CheckAiModelPricesCacheReadPriceCheck CheckConstraint = "ai_model_prices_cache_read_price_check" // ai_model_prices - CheckAiModelPricesCacheWritePriceCheck CheckConstraint = "ai_model_prices_cache_write_price_check" // ai_model_prices - CheckAiModelPricesInputPriceCheck CheckConstraint = "ai_model_prices_input_price_check" // ai_model_prices - CheckAiModelPricesOutputPriceCheck CheckConstraint = "ai_model_prices_output_price_check" // ai_model_prices - CheckAiProvidersNameCheck CheckConstraint = "ai_providers_name_check" // ai_providers + CheckAIGatewayKeysHashedSecretCheck CheckConstraint = "ai_gateway_keys_hashed_secret_check" // ai_gateway_keys + CheckAIGatewayKeysNameCheck CheckConstraint = "ai_gateway_keys_name_check" // ai_gateway_keys + CheckAIGatewayKeysSecretPrefixCheck CheckConstraint = "ai_gateway_keys_secret_prefix_check" // ai_gateway_keys + CheckAIModelPricesCacheReadPriceCheck CheckConstraint = "ai_model_prices_cache_read_price_check" // ai_model_prices + CheckAIModelPricesCacheWritePriceCheck CheckConstraint = "ai_model_prices_cache_write_price_check" // ai_model_prices + CheckAIModelPricesInputPriceCheck CheckConstraint = "ai_model_prices_input_price_check" // ai_model_prices + CheckAIModelPricesOutputPriceCheck CheckConstraint = "ai_model_prices_output_price_check" // ai_model_prices + CheckAIProvidersNameCheck CheckConstraint = "ai_providers_name_check" // ai_providers CheckAPIKeysAllowListNotEmpty CheckConstraint = "api_keys_allow_list_not_empty" // api_keys CheckBoundaryLogsSequenceNumberCheck CheckConstraint = "boundary_logs_sequence_number_check" // boundary_logs - CheckChatModelConfigsAiProviderRequiredWhenActive CheckConstraint = "chat_model_configs_ai_provider_required_when_active" // chat_model_configs + CheckChatModelConfigsAIProviderRequiredWhenActive CheckConstraint = "chat_model_configs_ai_provider_required_when_active" // chat_model_configs CheckChatModelConfigsCompressionThresholdCheck CheckConstraint = "chat_model_configs_compression_threshold_check" // chat_model_configs CheckChatModelConfigsContextLimitCheck CheckConstraint = "chat_model_configs_context_limit_check" // chat_model_configs CheckChatUsageLimitConfigDefaultLimitMicrosCheck CheckConstraint = "chat_usage_limit_config_default_limit_micros_check" // chat_usage_limit_config @@ -33,7 +33,7 @@ const ( CheckUsersServiceAccountLoginType CheckConstraint = "users_service_account_login_type" // users CheckUsersUsernameMinLength CheckConstraint = "users_username_min_length" // users CheckOrganizationIDNotZero CheckConstraint = "organization_id_not_zero" // custom_roles - CheckGroupAiBudgetsSpendLimitMicrosCheck CheckConstraint = "group_ai_budgets_spend_limit_micros_check" // group_ai_budgets + CheckGroupAIBudgetsSpendLimitMicrosCheck CheckConstraint = "group_ai_budgets_spend_limit_micros_check" // group_ai_budgets CheckGroupsChatSpendLimitMicrosCheck CheckConstraint = "groups_chat_spend_limit_micros_check" // groups CheckMcpServerConfigsAuthTypeCheck CheckConstraint = "mcp_server_configs_auth_type_check" // mcp_server_configs CheckMcpServerConfigsAvailabilityCheck CheckConstraint = "mcp_server_configs_availability_check" // mcp_server_configs @@ -47,8 +47,8 @@ const ( CheckTelemetryLockEventTypeConstraint CheckConstraint = "telemetry_lock_event_type_constraint" // telemetry_locks CheckValidationMonotonicOrder CheckConstraint = "validation_monotonic_order" // template_version_parameters CheckUsageEventTypeCheck CheckConstraint = "usage_event_type_check" // usage_events - CheckUserAiBudgetOverridesSpendLimitMicrosCheck CheckConstraint = "user_ai_budget_overrides_spend_limit_micros_check" // user_ai_budget_overrides - CheckUserAiProviderKeysAPIKeyCheck CheckConstraint = "user_ai_provider_keys_api_key_check" // user_ai_provider_keys + CheckUserAIBudgetOverridesSpendLimitMicrosCheck CheckConstraint = "user_ai_budget_overrides_spend_limit_micros_check" // user_ai_budget_overrides + CheckUserAIProviderKeysAPIKeyCheck CheckConstraint = "user_ai_provider_keys_api_key_check" // user_ai_provider_keys CheckUserSkillsContentSize CheckConstraint = "user_skills_content_size" // user_skills CheckUserSkillsDescriptionSize CheckConstraint = "user_skills_description_size" // user_skills CheckUserSkillsNameFormat CheckConstraint = "user_skills_name_format" // user_skills diff --git a/coderd/database/db2sdk/db2sdk.go b/coderd/database/db2sdk/db2sdk.go index c4203ff2cc..e28f594356 100644 --- a/coderd/database/db2sdk/db2sdk.go +++ b/coderd/database/db2sdk/db2sdk.go @@ -1421,7 +1421,7 @@ func flattenAndSum(sums map[string]int64, prefix string, m map[string]json.RawMe } } -func GroupAIBudget(b database.GroupAiBudget) codersdk.GroupAIBudget { +func GroupAIBudget(b database.GroupAIBudget) codersdk.GroupAIBudget { return codersdk.GroupAIBudget{ GroupID: b.GroupID, SpendLimitMicros: b.SpendLimitMicros, @@ -1430,7 +1430,7 @@ func GroupAIBudget(b database.GroupAiBudget) codersdk.GroupAIBudget { } } -func UserAIBudgetOverride(o database.UserAiBudgetOverride) codersdk.UserAIBudgetOverride { +func UserAIBudgetOverride(o database.UserAIBudgetOverride) codersdk.UserAIBudgetOverride { return codersdk.UserAIBudgetOverride{ UserID: o.UserID, GroupID: o.GroupID, diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 39edc4a8b6..995bb2612d 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -2171,14 +2171,14 @@ func (q *querier) DeleteExternalAuthLink(ctx context.Context, arg database.Delet }, q.db.DeleteExternalAuthLink)(ctx, arg) } -func (q *querier) DeleteGroupAIBudget(ctx context.Context, groupID uuid.UUID) (database.GroupAiBudget, error) { +func (q *querier) DeleteGroupAIBudget(ctx context.Context, groupID uuid.UUID) (database.GroupAIBudget, error) { // Removing a group's AI budget counts as updating the group. group, err := q.db.GetGroupByID(ctx, groupID) if err != nil { - return database.GroupAiBudget{}, err + return database.GroupAIBudget{}, err } if err := q.authorizeContext(ctx, policy.ActionUpdate, group); err != nil { - return database.GroupAiBudget{}, err + return database.GroupAIBudget{}, err } return q.db.DeleteGroupAIBudget(ctx, groupID) } @@ -2439,28 +2439,28 @@ func (q *querier) DeleteTask(ctx context.Context, arg database.DeleteTaskParams) return q.db.DeleteTask(ctx, arg) } -func (q *querier) DeleteUserAIBudgetOverride(ctx context.Context, userID uuid.UUID) (database.UserAiBudgetOverride, error) { +func (q *querier) DeleteUserAIBudgetOverride(ctx context.Context, userID uuid.UUID) (database.UserAIBudgetOverride, error) { // Removing a user's AI budget override affects both the user (clearing // their per-user spend cap) and the group it was attributed to. u, err := q.db.GetUserByID(ctx, userID) if err != nil { - return database.UserAiBudgetOverride{}, err + return database.UserAIBudgetOverride{}, err } if err := q.authorizeContext(ctx, policy.ActionUpdate, u); err != nil { - return database.UserAiBudgetOverride{}, err + return database.UserAIBudgetOverride{}, err } // Fetch the existing override to learn which group it attributes spend to, // so we can authorize the caller against that group as well. userOverride, err := q.db.GetUserAIBudgetOverride(ctx, userID) if err != nil { - return database.UserAiBudgetOverride{}, err + return database.UserAIBudgetOverride{}, err } g, err := q.db.GetGroupByID(ctx, userOverride.GroupID) if err != nil { - return database.UserAiBudgetOverride{}, err + return database.UserAIBudgetOverride{}, err } if err := q.authorizeContext(ctx, policy.ActionUpdate, g); err != nil { - return database.UserAiBudgetOverride{}, err + return database.UserAIBudgetOverride{}, err } return q.db.DeleteUserAIBudgetOverride(ctx, userID) } @@ -2727,9 +2727,9 @@ func (q *querier) GetAIBridgeUserPromptsByInterceptionID(ctx context.Context, in return q.db.GetAIBridgeUserPromptsByInterceptionID(ctx, interceptionID) } -func (q *querier) GetAIModelPriceByProviderModel(ctx context.Context, arg database.GetAIModelPriceByProviderModelParams) (database.AiModelPrice, error) { +func (q *querier) GetAIModelPriceByProviderModel(ctx context.Context, arg database.GetAIModelPriceByProviderModelParams) (database.AIModelPrice, error) { if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceAiModelPrice); err != nil { - return database.AiModelPrice{}, err + return database.AIModelPrice{}, err } return q.db.GetAIModelPriceByProviderModel(ctx, arg) } @@ -3737,14 +3737,14 @@ func (q *querier) GetGitSSHKey(ctx context.Context, userID uuid.UUID) (database. return fetchWithAction(q.log, q.auth, policy.ActionReadPersonal, q.db.GetGitSSHKey)(ctx, userID) } -func (q *querier) GetGroupAIBudget(ctx context.Context, groupID uuid.UUID) (database.GroupAiBudget, error) { +func (q *querier) GetGroupAIBudget(ctx context.Context, groupID uuid.UUID) (database.GroupAIBudget, error) { // Reading a group's AI budget requires read on the parent group. group, err := q.db.GetGroupByID(ctx, groupID) if err != nil { - return database.GroupAiBudget{}, err + return database.GroupAIBudget{}, err } if err := q.authorizeContext(ctx, policy.ActionRead, group); err != nil { - return database.GroupAiBudget{}, err + return database.GroupAIBudget{}, err } return q.db.GetGroupAIBudget(ctx, groupID) } @@ -4794,32 +4794,32 @@ func (q *querier) GetUnexpiredLicenses(ctx context.Context) ([]database.License, return q.db.GetUnexpiredLicenses(ctx) } -func (q *querier) GetUserAIBudgetOverride(ctx context.Context, userID uuid.UUID) (database.UserAiBudgetOverride, error) { +func (q *querier) GetUserAIBudgetOverride(ctx context.Context, userID uuid.UUID) (database.UserAIBudgetOverride, error) { if _, err := q.GetUserByID(ctx, userID); err != nil { // AuthZ check - return database.UserAiBudgetOverride{}, err + return database.UserAIBudgetOverride{}, err } return q.db.GetUserAIBudgetOverride(ctx, userID) } -func (q *querier) GetUserAIProviderKeyByProviderID(ctx context.Context, arg database.GetUserAIProviderKeyByProviderIDParams) (database.UserAiProviderKey, error) { +func (q *querier) GetUserAIProviderKeyByProviderID(ctx context.Context, arg database.GetUserAIProviderKeyByProviderIDParams) (database.UserAIProviderKey, error) { u, err := q.db.GetUserByID(ctx, arg.UserID) if err != nil { - return database.UserAiProviderKey{}, err + return database.UserAIProviderKey{}, err } if err := q.authorizeContext(ctx, policy.ActionReadPersonal, u); err != nil { - return database.UserAiProviderKey{}, err + return database.UserAIProviderKey{}, err } return q.db.GetUserAIProviderKeyByProviderID(ctx, arg) } -func (q *querier) GetUserAIProviderKeys(ctx context.Context) ([]database.UserAiProviderKey, error) { +func (q *querier) GetUserAIProviderKeys(ctx context.Context) ([]database.UserAIProviderKey, error) { if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceAIProvider); err != nil { return nil, err } return q.db.GetUserAIProviderKeys(ctx) } -func (q *querier) GetUserAIProviderKeysByUserID(ctx context.Context, userID uuid.UUID) ([]database.UserAiProviderKey, error) { +func (q *querier) GetUserAIProviderKeysByUserID(ctx context.Context, userID uuid.UUID) ([]database.UserAIProviderKey, error) { u, err := q.db.GetUserByID(ctx, userID) if err != nil { return nil, err @@ -7295,12 +7295,12 @@ func (q *querier) UpdateEncryptedAIProviderSettings(ctx context.Context, arg dat return q.db.UpdateEncryptedAIProviderSettings(ctx, arg) } -func (q *querier) UpdateEncryptedUserAIProviderKey(ctx context.Context, arg database.UpdateEncryptedUserAIProviderKeyParams) (database.UserAiProviderKey, error) { +func (q *querier) UpdateEncryptedUserAIProviderKey(ctx context.Context, arg database.UpdateEncryptedUserAIProviderKeyParams) (database.UserAIProviderKey, error) { // Encrypted user-owned provider keys can be rewritten on any row so // dbcrypt rotation can move every key to a new digest. This is a // maintenance path, not the self-service user key API. if err := q.authorizeContext(ctx, policy.ActionUpdate, rbac.ResourceAIProvider); err != nil { - return database.UserAiProviderKey{}, err + return database.UserAIProviderKey{}, err } return q.db.UpdateEncryptedUserAIProviderKey(ctx, arg) } @@ -7831,13 +7831,13 @@ func (q *querier) UpdateUsageEventsPostPublish(ctx context.Context, arg database return q.db.UpdateUsageEventsPostPublish(ctx, arg) } -func (q *querier) UpdateUserAIProviderKey(ctx context.Context, arg database.UpdateUserAIProviderKeyParams) (database.UserAiProviderKey, error) { +func (q *querier) UpdateUserAIProviderKey(ctx context.Context, arg database.UpdateUserAIProviderKeyParams) (database.UserAIProviderKey, error) { u, err := q.db.GetUserByID(ctx, arg.UserID) if err != nil { - return database.UserAiProviderKey{}, err + return database.UserAIProviderKey{}, err } if err := q.authorizeContext(ctx, policy.ActionUpdatePersonal, u); err != nil { - return database.UserAiProviderKey{}, err + return database.UserAIProviderKey{}, err } return q.db.UpdateUserAIProviderKey(ctx, arg) } @@ -8645,14 +8645,14 @@ func (q *querier) UpsertDefaultProxy(ctx context.Context, arg database.UpsertDef return q.db.UpsertDefaultProxy(ctx, arg) } -func (q *querier) UpsertGroupAIBudget(ctx context.Context, arg database.UpsertGroupAIBudgetParams) (database.GroupAiBudget, error) { +func (q *querier) UpsertGroupAIBudget(ctx context.Context, arg database.UpsertGroupAIBudgetParams) (database.GroupAIBudget, error) { // Setting a group's AI budget counts as updating the group. group, err := q.db.GetGroupByID(ctx, arg.GroupID) if err != nil { - return database.GroupAiBudget{}, err + return database.GroupAIBudget{}, err } if err := q.authorizeContext(ctx, policy.ActionUpdate, group); err != nil { - return database.GroupAiBudget{}, err + return database.GroupAIBudget{}, err } return q.db.UpsertGroupAIBudget(ctx, arg) } @@ -8792,33 +8792,33 @@ func (q *querier) UpsertTemplateUsageStats(ctx context.Context) error { return q.db.UpsertTemplateUsageStats(ctx) } -func (q *querier) UpsertUserAIBudgetOverride(ctx context.Context, arg database.UpsertUserAIBudgetOverrideParams) (database.UserAiBudgetOverride, error) { +func (q *querier) UpsertUserAIBudgetOverride(ctx context.Context, arg database.UpsertUserAIBudgetOverrideParams) (database.UserAIBudgetOverride, error) { // Setting a user's AI budget override affects both the user (their // per-user spend cap) and the group (spend attribution). u, err := q.db.GetUserByID(ctx, arg.UserID) if err != nil { - return database.UserAiBudgetOverride{}, err + return database.UserAIBudgetOverride{}, err } if err := q.authorizeContext(ctx, policy.ActionUpdate, u); err != nil { - return database.UserAiBudgetOverride{}, err + return database.UserAIBudgetOverride{}, err } g, err := q.db.GetGroupByID(ctx, arg.GroupID) if err != nil { - return database.UserAiBudgetOverride{}, err + return database.UserAIBudgetOverride{}, err } if err := q.authorizeContext(ctx, policy.ActionUpdate, g); err != nil { - return database.UserAiBudgetOverride{}, err + return database.UserAIBudgetOverride{}, err } return q.db.UpsertUserAIBudgetOverride(ctx, arg) } -func (q *querier) UpsertUserAIProviderKey(ctx context.Context, arg database.UpsertUserAIProviderKeyParams) (database.UserAiProviderKey, error) { +func (q *querier) UpsertUserAIProviderKey(ctx context.Context, arg database.UpsertUserAIProviderKeyParams) (database.UserAIProviderKey, error) { u, err := q.db.GetUserByID(ctx, arg.UserID) if err != nil { - return database.UserAiProviderKey{}, err + return database.UserAIProviderKey{}, err } if err := q.authorizeContext(ctx, policy.ActionUpdatePersonal, u); err != nil { - return database.UserAiProviderKey{}, err + return database.UserAIProviderKey{}, err } return q.db.UpsertUserAIProviderKey(ctx, arg) } diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 91bacb9bb5..ab18e654ca 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -3134,17 +3134,17 @@ func (s *MethodTestSuite) TestUser() { s.Run("GetUserAIProviderKeyByProviderID", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) { u := testutil.Fake(s.T(), faker, database.User{}) arg := database.GetUserAIProviderKeyByProviderIDParams{UserID: u.ID, AIProviderID: uuid.New()} - key := testutil.Fake(s.T(), faker, database.UserAiProviderKey{UserID: u.ID, AIProviderID: arg.AIProviderID}) + key := testutil.Fake(s.T(), faker, database.UserAIProviderKey{UserID: u.ID, AIProviderID: arg.AIProviderID}) dbm.EXPECT().GetUserByID(gomock.Any(), u.ID).Return(u, nil).AnyTimes() dbm.EXPECT().GetUserAIProviderKeyByProviderID(gomock.Any(), arg).Return(key, nil).AnyTimes() check.Args(arg).Asserts(u, policy.ActionReadPersonal).Returns(key) })) s.Run("GetUserAIProviderKeysByUserID", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) { u := testutil.Fake(s.T(), faker, database.User{}) - key := testutil.Fake(s.T(), faker, database.UserAiProviderKey{UserID: u.ID}) + key := testutil.Fake(s.T(), faker, database.UserAIProviderKey{UserID: u.ID}) dbm.EXPECT().GetUserByID(gomock.Any(), u.ID).Return(u, nil).AnyTimes() - dbm.EXPECT().GetUserAIProviderKeysByUserID(gomock.Any(), u.ID).Return([]database.UserAiProviderKey{key}, nil).AnyTimes() - check.Args(u.ID).Asserts(u, policy.ActionReadPersonal).Returns([]database.UserAiProviderKey{key}) + dbm.EXPECT().GetUserAIProviderKeysByUserID(gomock.Any(), u.ID).Return([]database.UserAIProviderKey{key}, nil).AnyTimes() + check.Args(u.ID).Asserts(u, policy.ActionReadPersonal).Returns([]database.UserAIProviderKey{key}) })) s.Run("DeleteUserAIProviderKeysByProviderID", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) { providerID := uuid.New() @@ -3161,7 +3161,7 @@ func (s *MethodTestSuite) TestUser() { s.Run("UpdateUserAIProviderKey", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) { u := testutil.Fake(s.T(), faker, database.User{}) arg := database.UpdateUserAIProviderKeyParams{UserID: u.ID, AIProviderID: uuid.New(), APIKey: "updated-api-key"} - key := testutil.Fake(s.T(), faker, database.UserAiProviderKey{UserID: u.ID, AIProviderID: arg.AIProviderID, APIKey: arg.APIKey}) + key := testutil.Fake(s.T(), faker, database.UserAIProviderKey{UserID: u.ID, AIProviderID: arg.AIProviderID, APIKey: arg.APIKey}) dbm.EXPECT().GetUserByID(gomock.Any(), u.ID).Return(u, nil).AnyTimes() dbm.EXPECT().UpdateUserAIProviderKey(gomock.Any(), arg).Return(key, nil).AnyTimes() check.Args(arg).Asserts(u, policy.ActionUpdatePersonal).Returns(key) @@ -3169,7 +3169,7 @@ func (s *MethodTestSuite) TestUser() { s.Run("UpsertUserAIProviderKey", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) { u := testutil.Fake(s.T(), faker, database.User{}) arg := database.UpsertUserAIProviderKeyParams{UserID: u.ID, AIProviderID: uuid.New(), APIKey: "upserted-api-key"} - key := testutil.Fake(s.T(), faker, database.UserAiProviderKey{UserID: u.ID, AIProviderID: arg.AIProviderID, APIKey: arg.APIKey}) + key := testutil.Fake(s.T(), faker, database.UserAIProviderKey{UserID: u.ID, AIProviderID: arg.AIProviderID, APIKey: arg.APIKey}) dbm.EXPECT().GetUserByID(gomock.Any(), u.ID).Return(u, nil).AnyTimes() dbm.EXPECT().UpsertUserAIProviderKey(gomock.Any(), arg).Return(key, nil).AnyTimes() check.Args(arg).Asserts(u, policy.ActionUpdatePersonal).Returns(key) @@ -6681,13 +6681,13 @@ func (s *MethodTestSuite) TestAIBridge() { })) s.Run("GetAIModelPriceByProviderModel", s.Mocked(func(db *dbmock.MockStore, _ *gofakeit.Faker, check *expects) { - db.EXPECT().GetAIModelPriceByProviderModel(gomock.Any(), gomock.Any()).Return(database.AiModelPrice{}, nil).AnyTimes() + db.EXPECT().GetAIModelPriceByProviderModel(gomock.Any(), gomock.Any()).Return(database.AIModelPrice{}, nil).AnyTimes() check.Args(database.GetAIModelPriceByProviderModelParams{}).Asserts(rbac.ResourceAiModelPrice, policy.ActionRead) })) s.Run("GetGroupAIBudget", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) { g := testutil.Fake(s.T(), faker, database.Group{}) - b := testutil.Fake(s.T(), faker, database.GroupAiBudget{GroupID: g.ID}) + b := testutil.Fake(s.T(), faker, database.GroupAIBudget{GroupID: g.ID}) dbm.EXPECT().GetGroupByID(gomock.Any(), g.ID).Return(g, nil).AnyTimes() dbm.EXPECT().GetGroupAIBudget(gomock.Any(), g.ID).Return(b, nil).AnyTimes() check.Args(g.ID).Asserts(g, policy.ActionRead).Returns(b) @@ -6695,7 +6695,7 @@ func (s *MethodTestSuite) TestAIBridge() { s.Run("UpsertGroupAIBudget", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) { g := testutil.Fake(s.T(), faker, database.Group{}) - b := testutil.Fake(s.T(), faker, database.GroupAiBudget{GroupID: g.ID}) + b := testutil.Fake(s.T(), faker, database.GroupAIBudget{GroupID: g.ID}) arg := database.UpsertGroupAIBudgetParams{GroupID: g.ID, SpendLimitMicros: b.SpendLimitMicros} dbm.EXPECT().GetGroupByID(gomock.Any(), g.ID).Return(g, nil).AnyTimes() dbm.EXPECT().UpsertGroupAIBudget(gomock.Any(), arg).Return(b, nil).AnyTimes() @@ -6704,7 +6704,7 @@ func (s *MethodTestSuite) TestAIBridge() { s.Run("DeleteGroupAIBudget", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) { g := testutil.Fake(s.T(), faker, database.Group{}) - b := testutil.Fake(s.T(), faker, database.GroupAiBudget{GroupID: g.ID}) + b := testutil.Fake(s.T(), faker, database.GroupAIBudget{GroupID: g.ID}) dbm.EXPECT().GetGroupByID(gomock.Any(), g.ID).Return(g, nil).AnyTimes() dbm.EXPECT().DeleteGroupAIBudget(gomock.Any(), g.ID).Return(b, nil).AnyTimes() check.Args(g.ID).Asserts(g, policy.ActionUpdate).Returns(b) @@ -6712,7 +6712,7 @@ func (s *MethodTestSuite) TestAIBridge() { s.Run("GetUserAIBudgetOverride", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) { user := testutil.Fake(s.T(), faker, database.User{}) - override := testutil.Fake(s.T(), faker, database.UserAiBudgetOverride{UserID: user.ID}) + override := testutil.Fake(s.T(), faker, database.UserAIBudgetOverride{UserID: user.ID}) dbm.EXPECT().GetUserByID(gomock.Any(), user.ID).Return(user, nil).AnyTimes() dbm.EXPECT().GetUserAIBudgetOverride(gomock.Any(), user.ID).Return(override, nil).AnyTimes() check.Args(user.ID).Asserts(user, policy.ActionRead).Returns(override) @@ -6729,7 +6729,7 @@ func (s *MethodTestSuite) TestAIBridge() { s.Run("UpsertUserAIBudgetOverride", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) { user := testutil.Fake(s.T(), faker, database.User{}) group := testutil.Fake(s.T(), faker, database.Group{}) - override := testutil.Fake(s.T(), faker, database.UserAiBudgetOverride{UserID: user.ID, GroupID: group.ID}) + override := testutil.Fake(s.T(), faker, database.UserAIBudgetOverride{UserID: user.ID, GroupID: group.ID}) arg := database.UpsertUserAIBudgetOverrideParams{UserID: user.ID, GroupID: group.ID, SpendLimitMicros: override.SpendLimitMicros} dbm.EXPECT().GetUserByID(gomock.Any(), user.ID).Return(user, nil).AnyTimes() dbm.EXPECT().GetGroupByID(gomock.Any(), group.ID).Return(group, nil).AnyTimes() @@ -6740,7 +6740,7 @@ func (s *MethodTestSuite) TestAIBridge() { s.Run("DeleteUserAIBudgetOverride", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) { user := testutil.Fake(s.T(), faker, database.User{}) group := testutil.Fake(s.T(), faker, database.Group{}) - override := testutil.Fake(s.T(), faker, database.UserAiBudgetOverride{UserID: user.ID, GroupID: group.ID}) + override := testutil.Fake(s.T(), faker, database.UserAIBudgetOverride{UserID: user.ID, GroupID: group.ID}) dbm.EXPECT().GetUserByID(gomock.Any(), user.ID).Return(user, nil).AnyTimes() dbm.EXPECT().GetUserAIBudgetOverride(gomock.Any(), user.ID).Return(override, nil).AnyTimes() dbm.EXPECT().GetGroupByID(gomock.Any(), group.ID).Return(group, nil).AnyTimes() @@ -6773,7 +6773,7 @@ func (s *MethodTestSuite) TestAIBridge() { s.Run("InsertAIProvider", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) { arg := database.InsertAIProviderParams{ ID: uuid.New(), - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, Name: "test-provider", Enabled: true, BaseUrl: "https://api.example.com/", @@ -6876,13 +6876,13 @@ func (s *MethodTestSuite) TestAIBridge() { check.Args(arg).Asserts(rbac.ResourceAIProvider, policy.ActionUpdate).Returns(key) })) s.Run("GetUserAIProviderKeys", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) { - keyA := testutil.Fake(s.T(), faker, database.UserAiProviderKey{}) - keyB := testutil.Fake(s.T(), faker, database.UserAiProviderKey{}) - dbm.EXPECT().GetUserAIProviderKeys(gomock.Any()).Return([]database.UserAiProviderKey{keyA, keyB}, nil).AnyTimes() - check.Args().Asserts(rbac.ResourceAIProvider, policy.ActionRead).Returns([]database.UserAiProviderKey{keyA, keyB}) + keyA := testutil.Fake(s.T(), faker, database.UserAIProviderKey{}) + keyB := testutil.Fake(s.T(), faker, database.UserAIProviderKey{}) + dbm.EXPECT().GetUserAIProviderKeys(gomock.Any()).Return([]database.UserAIProviderKey{keyA, keyB}, nil).AnyTimes() + check.Args().Asserts(rbac.ResourceAIProvider, policy.ActionRead).Returns([]database.UserAIProviderKey{keyA, keyB}) })) s.Run("UpdateEncryptedUserAIProviderKey", s.Mocked(func(dbm *dbmock.MockStore, faker *gofakeit.Faker, check *expects) { - key := testutil.Fake(s.T(), faker, database.UserAiProviderKey{}) + key := testutil.Fake(s.T(), faker, database.UserAIProviderKey{}) arg := database.UpdateEncryptedUserAIProviderKeyParams{ ID: key.ID, APIKey: "encrypted-api-key", diff --git a/coderd/database/dbgen/dbgen.go b/coderd/database/dbgen/dbgen.go index 249038ffc0..845d3f1a06 100644 --- a/coderd/database/dbgen/dbgen.go +++ b/coderd/database/dbgen/dbgen.go @@ -210,7 +210,7 @@ func AIProvider(t testing.TB, db database.Store, seed database.AIProvider, munge } provType := seed.Type if provType == "" { - provType = database.AiProviderTypeOpenai + provType = database.AIProviderTypeOpenai } name := takeFirst(seed.Name, testutil.GetRandomNameHyphenated(t)) displayName := seed.DisplayName diff --git a/coderd/database/dbmetrics/querymetrics.go b/coderd/database/dbmetrics/querymetrics.go index 3758bcb535..c0bc2af8a2 100644 --- a/coderd/database/dbmetrics/querymetrics.go +++ b/coderd/database/dbmetrics/querymetrics.go @@ -594,7 +594,7 @@ func (m queryMetricsStore) DeleteExternalAuthLink(ctx context.Context, arg datab return r0 } -func (m queryMetricsStore) DeleteGroupAIBudget(ctx context.Context, groupID uuid.UUID) (database.GroupAiBudget, error) { +func (m queryMetricsStore) DeleteGroupAIBudget(ctx context.Context, groupID uuid.UUID) (database.GroupAIBudget, error) { start := time.Now() r0, r1 := m.s.DeleteGroupAIBudget(ctx, groupID) m.queryLatencies.WithLabelValues("DeleteGroupAIBudget").Observe(time.Since(start).Seconds()) @@ -866,7 +866,7 @@ func (m queryMetricsStore) DeleteTask(ctx context.Context, arg database.DeleteTa return r0, r1 } -func (m queryMetricsStore) DeleteUserAIBudgetOverride(ctx context.Context, userID uuid.UUID) (database.UserAiBudgetOverride, error) { +func (m queryMetricsStore) DeleteUserAIBudgetOverride(ctx context.Context, userID uuid.UUID) (database.UserAIBudgetOverride, error) { start := time.Now() r0, r1 := m.s.DeleteUserAIBudgetOverride(ctx, userID) m.queryLatencies.WithLabelValues("DeleteUserAIBudgetOverride").Observe(time.Since(start).Seconds()) @@ -1106,7 +1106,7 @@ func (m queryMetricsStore) GetAIBridgeUserPromptsByInterceptionID(ctx context.Co return r0, r1 } -func (m queryMetricsStore) GetAIModelPriceByProviderModel(ctx context.Context, arg database.GetAIModelPriceByProviderModelParams) (database.AiModelPrice, error) { +func (m queryMetricsStore) GetAIModelPriceByProviderModel(ctx context.Context, arg database.GetAIModelPriceByProviderModelParams) (database.AIModelPrice, error) { start := time.Now() r0, r1 := m.s.GetAIModelPriceByProviderModel(ctx, arg) m.queryLatencies.WithLabelValues("GetAIModelPriceByProviderModel").Observe(time.Since(start).Seconds()) @@ -2082,7 +2082,7 @@ func (m queryMetricsStore) GetGitSSHKey(ctx context.Context, userID uuid.UUID) ( return r0, r1 } -func (m queryMetricsStore) GetGroupAIBudget(ctx context.Context, groupID uuid.UUID) (database.GroupAiBudget, error) { +func (m queryMetricsStore) GetGroupAIBudget(ctx context.Context, groupID uuid.UUID) (database.GroupAIBudget, error) { start := time.Now() r0, r1 := m.s.GetGroupAIBudget(ctx, groupID) m.queryLatencies.WithLabelValues("GetGroupAIBudget").Observe(time.Since(start).Seconds()) @@ -3106,7 +3106,7 @@ func (m queryMetricsStore) GetUnexpiredLicenses(ctx context.Context) ([]database return r0, r1 } -func (m queryMetricsStore) GetUserAIBudgetOverride(ctx context.Context, userID uuid.UUID) (database.UserAiBudgetOverride, error) { +func (m queryMetricsStore) GetUserAIBudgetOverride(ctx context.Context, userID uuid.UUID) (database.UserAIBudgetOverride, error) { start := time.Now() r0, r1 := m.s.GetUserAIBudgetOverride(ctx, userID) m.queryLatencies.WithLabelValues("GetUserAIBudgetOverride").Observe(time.Since(start).Seconds()) @@ -3114,7 +3114,7 @@ func (m queryMetricsStore) GetUserAIBudgetOverride(ctx context.Context, userID u return r0, r1 } -func (m queryMetricsStore) GetUserAIProviderKeyByProviderID(ctx context.Context, arg database.GetUserAIProviderKeyByProviderIDParams) (database.UserAiProviderKey, error) { +func (m queryMetricsStore) GetUserAIProviderKeyByProviderID(ctx context.Context, arg database.GetUserAIProviderKeyByProviderIDParams) (database.UserAIProviderKey, error) { start := time.Now() r0, r1 := m.s.GetUserAIProviderKeyByProviderID(ctx, arg) m.queryLatencies.WithLabelValues("GetUserAIProviderKeyByProviderID").Observe(time.Since(start).Seconds()) @@ -3122,7 +3122,7 @@ func (m queryMetricsStore) GetUserAIProviderKeyByProviderID(ctx context.Context, return r0, r1 } -func (m queryMetricsStore) GetUserAIProviderKeys(ctx context.Context) ([]database.UserAiProviderKey, error) { +func (m queryMetricsStore) GetUserAIProviderKeys(ctx context.Context) ([]database.UserAIProviderKey, error) { start := time.Now() r0, r1 := m.s.GetUserAIProviderKeys(ctx) m.queryLatencies.WithLabelValues("GetUserAIProviderKeys").Observe(time.Since(start).Seconds()) @@ -3130,7 +3130,7 @@ func (m queryMetricsStore) GetUserAIProviderKeys(ctx context.Context) ([]databas return r0, r1 } -func (m queryMetricsStore) GetUserAIProviderKeysByUserID(ctx context.Context, userID uuid.UUID) ([]database.UserAiProviderKey, error) { +func (m queryMetricsStore) GetUserAIProviderKeysByUserID(ctx context.Context, userID uuid.UUID) ([]database.UserAIProviderKey, error) { start := time.Now() r0, r1 := m.s.GetUserAIProviderKeysByUserID(ctx, userID) m.queryLatencies.WithLabelValues("GetUserAIProviderKeysByUserID").Observe(time.Since(start).Seconds()) @@ -5234,7 +5234,7 @@ func (m queryMetricsStore) UpdateEncryptedAIProviderSettings(ctx context.Context return r0, r1 } -func (m queryMetricsStore) UpdateEncryptedUserAIProviderKey(ctx context.Context, arg database.UpdateEncryptedUserAIProviderKeyParams) (database.UserAiProviderKey, error) { +func (m queryMetricsStore) UpdateEncryptedUserAIProviderKey(ctx context.Context, arg database.UpdateEncryptedUserAIProviderKeyParams) (database.UserAIProviderKey, error) { start := time.Now() r0, r1 := m.s.UpdateEncryptedUserAIProviderKey(ctx, arg) m.queryLatencies.WithLabelValues("UpdateEncryptedUserAIProviderKey").Observe(time.Since(start).Seconds()) @@ -5570,7 +5570,7 @@ func (m queryMetricsStore) UpdateUsageEventsPostPublish(ctx context.Context, arg return r0 } -func (m queryMetricsStore) UpdateUserAIProviderKey(ctx context.Context, arg database.UpdateUserAIProviderKeyParams) (database.UserAiProviderKey, error) { +func (m queryMetricsStore) UpdateUserAIProviderKey(ctx context.Context, arg database.UpdateUserAIProviderKeyParams) (database.UserAIProviderKey, error) { start := time.Now() r0, r1 := m.s.UpdateUserAIProviderKey(ctx, arg) m.queryLatencies.WithLabelValues("UpdateUserAIProviderKey").Observe(time.Since(start).Seconds()) @@ -6226,7 +6226,7 @@ func (m queryMetricsStore) UpsertDefaultProxy(ctx context.Context, arg database. return r0 } -func (m queryMetricsStore) UpsertGroupAIBudget(ctx context.Context, arg database.UpsertGroupAIBudgetParams) (database.GroupAiBudget, error) { +func (m queryMetricsStore) UpsertGroupAIBudget(ctx context.Context, arg database.UpsertGroupAIBudgetParams) (database.GroupAIBudget, error) { start := time.Now() r0, r1 := m.s.UpsertGroupAIBudget(ctx, arg) m.queryLatencies.WithLabelValues("UpsertGroupAIBudget").Observe(time.Since(start).Seconds()) @@ -6370,7 +6370,7 @@ func (m queryMetricsStore) UpsertTemplateUsageStats(ctx context.Context) error { return r0 } -func (m queryMetricsStore) UpsertUserAIBudgetOverride(ctx context.Context, arg database.UpsertUserAIBudgetOverrideParams) (database.UserAiBudgetOverride, error) { +func (m queryMetricsStore) UpsertUserAIBudgetOverride(ctx context.Context, arg database.UpsertUserAIBudgetOverrideParams) (database.UserAIBudgetOverride, error) { start := time.Now() r0, r1 := m.s.UpsertUserAIBudgetOverride(ctx, arg) m.queryLatencies.WithLabelValues("UpsertUserAIBudgetOverride").Observe(time.Since(start).Seconds()) @@ -6378,7 +6378,7 @@ func (m queryMetricsStore) UpsertUserAIBudgetOverride(ctx context.Context, arg d return r0, r1 } -func (m queryMetricsStore) UpsertUserAIProviderKey(ctx context.Context, arg database.UpsertUserAIProviderKeyParams) (database.UserAiProviderKey, error) { +func (m queryMetricsStore) UpsertUserAIProviderKey(ctx context.Context, arg database.UpsertUserAIProviderKeyParams) (database.UserAIProviderKey, error) { start := time.Now() r0, r1 := m.s.UpsertUserAIProviderKey(ctx, arg) m.queryLatencies.WithLabelValues("UpsertUserAIProviderKey").Observe(time.Since(start).Seconds()) diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index d9807d3cbb..b71b72d100 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -978,10 +978,10 @@ func (mr *MockStoreMockRecorder) DeleteExternalAuthLink(ctx, arg any) *gomock.Ca } // DeleteGroupAIBudget mocks base method. -func (m *MockStore) DeleteGroupAIBudget(ctx context.Context, groupID uuid.UUID) (database.GroupAiBudget, error) { +func (m *MockStore) DeleteGroupAIBudget(ctx context.Context, groupID uuid.UUID) (database.GroupAIBudget, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "DeleteGroupAIBudget", ctx, groupID) - ret0, _ := ret[0].(database.GroupAiBudget) + ret0, _ := ret[0].(database.GroupAIBudget) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -1468,10 +1468,10 @@ func (mr *MockStoreMockRecorder) DeleteTask(ctx, arg any) *gomock.Call { } // DeleteUserAIBudgetOverride mocks base method. -func (m *MockStore) DeleteUserAIBudgetOverride(ctx context.Context, userID uuid.UUID) (database.UserAiBudgetOverride, error) { +func (m *MockStore) DeleteUserAIBudgetOverride(ctx context.Context, userID uuid.UUID) (database.UserAIBudgetOverride, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "DeleteUserAIBudgetOverride", ctx, userID) - ret0, _ := ret[0].(database.UserAiBudgetOverride) + ret0, _ := ret[0].(database.UserAIBudgetOverride) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -1904,10 +1904,10 @@ func (mr *MockStoreMockRecorder) GetAIBridgeUserPromptsByInterceptionID(ctx, int } // GetAIModelPriceByProviderModel mocks base method. -func (m *MockStore) GetAIModelPriceByProviderModel(ctx context.Context, arg database.GetAIModelPriceByProviderModelParams) (database.AiModelPrice, error) { +func (m *MockStore) GetAIModelPriceByProviderModel(ctx context.Context, arg database.GetAIModelPriceByProviderModelParams) (database.AIModelPrice, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetAIModelPriceByProviderModel", ctx, arg) - ret0, _ := ret[0].(database.AiModelPrice) + ret0, _ := ret[0].(database.AIModelPrice) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -3854,10 +3854,10 @@ func (mr *MockStoreMockRecorder) GetGitSSHKey(ctx, userID any) *gomock.Call { } // GetGroupAIBudget mocks base method. -func (m *MockStore) GetGroupAIBudget(ctx context.Context, groupID uuid.UUID) (database.GroupAiBudget, error) { +func (m *MockStore) GetGroupAIBudget(ctx context.Context, groupID uuid.UUID) (database.GroupAIBudget, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetGroupAIBudget", ctx, groupID) - ret0, _ := ret[0].(database.GroupAiBudget) + ret0, _ := ret[0].(database.GroupAIBudget) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -5804,10 +5804,10 @@ func (mr *MockStoreMockRecorder) GetUnexpiredLicenses(ctx any) *gomock.Call { } // GetUserAIBudgetOverride mocks base method. -func (m *MockStore) GetUserAIBudgetOverride(ctx context.Context, userID uuid.UUID) (database.UserAiBudgetOverride, error) { +func (m *MockStore) GetUserAIBudgetOverride(ctx context.Context, userID uuid.UUID) (database.UserAIBudgetOverride, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetUserAIBudgetOverride", ctx, userID) - ret0, _ := ret[0].(database.UserAiBudgetOverride) + ret0, _ := ret[0].(database.UserAIBudgetOverride) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -5819,10 +5819,10 @@ func (mr *MockStoreMockRecorder) GetUserAIBudgetOverride(ctx, userID any) *gomoc } // GetUserAIProviderKeyByProviderID mocks base method. -func (m *MockStore) GetUserAIProviderKeyByProviderID(ctx context.Context, arg database.GetUserAIProviderKeyByProviderIDParams) (database.UserAiProviderKey, error) { +func (m *MockStore) GetUserAIProviderKeyByProviderID(ctx context.Context, arg database.GetUserAIProviderKeyByProviderIDParams) (database.UserAIProviderKey, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetUserAIProviderKeyByProviderID", ctx, arg) - ret0, _ := ret[0].(database.UserAiProviderKey) + ret0, _ := ret[0].(database.UserAIProviderKey) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -5834,10 +5834,10 @@ func (mr *MockStoreMockRecorder) GetUserAIProviderKeyByProviderID(ctx, arg any) } // GetUserAIProviderKeys mocks base method. -func (m *MockStore) GetUserAIProviderKeys(ctx context.Context) ([]database.UserAiProviderKey, error) { +func (m *MockStore) GetUserAIProviderKeys(ctx context.Context) ([]database.UserAIProviderKey, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetUserAIProviderKeys", ctx) - ret0, _ := ret[0].([]database.UserAiProviderKey) + ret0, _ := ret[0].([]database.UserAIProviderKey) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -5849,10 +5849,10 @@ func (mr *MockStoreMockRecorder) GetUserAIProviderKeys(ctx any) *gomock.Call { } // GetUserAIProviderKeysByUserID mocks base method. -func (m *MockStore) GetUserAIProviderKeysByUserID(ctx context.Context, userID uuid.UUID) ([]database.UserAiProviderKey, error) { +func (m *MockStore) GetUserAIProviderKeysByUserID(ctx context.Context, userID uuid.UUID) ([]database.UserAIProviderKey, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "GetUserAIProviderKeysByUserID", ctx, userID) - ret0, _ := ret[0].([]database.UserAiProviderKey) + ret0, _ := ret[0].([]database.UserAIProviderKey) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -9862,10 +9862,10 @@ func (mr *MockStoreMockRecorder) UpdateEncryptedAIProviderSettings(ctx, arg any) } // UpdateEncryptedUserAIProviderKey mocks base method. -func (m *MockStore) UpdateEncryptedUserAIProviderKey(ctx context.Context, arg database.UpdateEncryptedUserAIProviderKeyParams) (database.UserAiProviderKey, error) { +func (m *MockStore) UpdateEncryptedUserAIProviderKey(ctx context.Context, arg database.UpdateEncryptedUserAIProviderKeyParams) (database.UserAIProviderKey, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpdateEncryptedUserAIProviderKey", ctx, arg) - ret0, _ := ret[0].(database.UserAiProviderKey) + ret0, _ := ret[0].(database.UserAIProviderKey) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -10468,10 +10468,10 @@ func (mr *MockStoreMockRecorder) UpdateUsageEventsPostPublish(ctx, arg any) *gom } // UpdateUserAIProviderKey mocks base method. -func (m *MockStore) UpdateUserAIProviderKey(ctx context.Context, arg database.UpdateUserAIProviderKeyParams) (database.UserAiProviderKey, error) { +func (m *MockStore) UpdateUserAIProviderKey(ctx context.Context, arg database.UpdateUserAIProviderKeyParams) (database.UserAIProviderKey, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpdateUserAIProviderKey", ctx, arg) - ret0, _ := ret[0].(database.UserAiProviderKey) + ret0, _ := ret[0].(database.UserAIProviderKey) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -11651,10 +11651,10 @@ func (mr *MockStoreMockRecorder) UpsertDefaultProxy(ctx, arg any) *gomock.Call { } // UpsertGroupAIBudget mocks base method. -func (m *MockStore) UpsertGroupAIBudget(ctx context.Context, arg database.UpsertGroupAIBudgetParams) (database.GroupAiBudget, error) { +func (m *MockStore) UpsertGroupAIBudget(ctx context.Context, arg database.UpsertGroupAIBudgetParams) (database.GroupAIBudget, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpsertGroupAIBudget", ctx, arg) - ret0, _ := ret[0].(database.GroupAiBudget) + ret0, _ := ret[0].(database.GroupAIBudget) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -11910,10 +11910,10 @@ func (mr *MockStoreMockRecorder) UpsertTemplateUsageStats(ctx any) *gomock.Call } // UpsertUserAIBudgetOverride mocks base method. -func (m *MockStore) UpsertUserAIBudgetOverride(ctx context.Context, arg database.UpsertUserAIBudgetOverrideParams) (database.UserAiBudgetOverride, error) { +func (m *MockStore) UpsertUserAIBudgetOverride(ctx context.Context, arg database.UpsertUserAIBudgetOverrideParams) (database.UserAIBudgetOverride, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpsertUserAIBudgetOverride", ctx, arg) - ret0, _ := ret[0].(database.UserAiBudgetOverride) + ret0, _ := ret[0].(database.UserAIBudgetOverride) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -11925,10 +11925,10 @@ func (mr *MockStoreMockRecorder) UpsertUserAIBudgetOverride(ctx, arg any) *gomoc } // UpsertUserAIProviderKey mocks base method. -func (m *MockStore) UpsertUserAIProviderKey(ctx context.Context, arg database.UpsertUserAIProviderKeyParams) (database.UserAiProviderKey, error) { +func (m *MockStore) UpsertUserAIProviderKey(ctx context.Context, arg database.UpsertUserAIProviderKeyParams) (database.UserAIProviderKey, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "UpsertUserAIProviderKey", ctx, arg) - ret0, _ := ret[0].(database.UserAiProviderKey) + ret0, _ := ret[0].(database.UserAIProviderKey) ret1, _ := ret[1].(error) return ret0, ret1 } diff --git a/coderd/database/foreign_key_constraint.go b/coderd/database/foreign_key_constraint.go index d48fca5c73..8b8d658fa6 100644 --- a/coderd/database/foreign_key_constraint.go +++ b/coderd/database/foreign_key_constraint.go @@ -6,10 +6,10 @@ type ForeignKeyConstraint string // ForeignKeyConstraint enums. const ( - ForeignKeyAiProviderKeysAPIKeyKeyID ForeignKeyConstraint = "ai_provider_keys_api_key_key_id_fkey" // ALTER TABLE ONLY ai_provider_keys ADD CONSTRAINT ai_provider_keys_api_key_key_id_fkey FOREIGN KEY (api_key_key_id) REFERENCES dbcrypt_keys(active_key_digest); - ForeignKeyAiProviderKeysProviderID ForeignKeyConstraint = "ai_provider_keys_provider_id_fkey" // ALTER TABLE ONLY ai_provider_keys ADD CONSTRAINT ai_provider_keys_provider_id_fkey FOREIGN KEY (provider_id) REFERENCES ai_providers(id) ON DELETE CASCADE; - ForeignKeyAiProvidersSettingsKeyID ForeignKeyConstraint = "ai_providers_settings_key_id_fkey" // ALTER TABLE ONLY ai_providers ADD CONSTRAINT ai_providers_settings_key_id_fkey FOREIGN KEY (settings_key_id) REFERENCES dbcrypt_keys(active_key_digest); - ForeignKeyAiSeatStateUserID ForeignKeyConstraint = "ai_seat_state_user_id_fkey" // ALTER TABLE ONLY ai_seat_state ADD CONSTRAINT ai_seat_state_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; + ForeignKeyAIProviderKeysAPIKeyKeyID ForeignKeyConstraint = "ai_provider_keys_api_key_key_id_fkey" // ALTER TABLE ONLY ai_provider_keys ADD CONSTRAINT ai_provider_keys_api_key_key_id_fkey FOREIGN KEY (api_key_key_id) REFERENCES dbcrypt_keys(active_key_digest); + ForeignKeyAIProviderKeysProviderID ForeignKeyConstraint = "ai_provider_keys_provider_id_fkey" // ALTER TABLE ONLY ai_provider_keys ADD CONSTRAINT ai_provider_keys_provider_id_fkey FOREIGN KEY (provider_id) REFERENCES ai_providers(id) ON DELETE CASCADE; + ForeignKeyAIProvidersSettingsKeyID ForeignKeyConstraint = "ai_providers_settings_key_id_fkey" // ALTER TABLE ONLY ai_providers ADD CONSTRAINT ai_providers_settings_key_id_fkey FOREIGN KEY (settings_key_id) REFERENCES dbcrypt_keys(active_key_digest); + ForeignKeyAISeatStateUserID ForeignKeyConstraint = "ai_seat_state_user_id_fkey" // ALTER TABLE ONLY ai_seat_state ADD CONSTRAINT ai_seat_state_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; ForeignKeyAibridgeInterceptionsInitiatorID ForeignKeyConstraint = "aibridge_interceptions_initiator_id_fkey" // ALTER TABLE ONLY aibridge_interceptions ADD CONSTRAINT aibridge_interceptions_initiator_id_fkey FOREIGN KEY (initiator_id) REFERENCES users(id); ForeignKeyAPIKeysUserIDUUID ForeignKeyConstraint = "api_keys_user_id_uuid_fkey" // ALTER TABLE ONLY api_keys ADD CONSTRAINT api_keys_user_id_uuid_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; ForeignKeyBoundarySessionsOwnerID ForeignKeyConstraint = "boundary_sessions_owner_id_fkey" // ALTER TABLE ONLY boundary_sessions ADD CONSTRAINT boundary_sessions_owner_id_fkey FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE SET NULL; @@ -25,7 +25,7 @@ const ( ForeignKeyChatMessagesAPIKeyID ForeignKeyConstraint = "chat_messages_api_key_id_fkey" // ALTER TABLE ONLY chat_messages ADD CONSTRAINT chat_messages_api_key_id_fkey FOREIGN KEY (api_key_id) REFERENCES api_keys(id) ON DELETE SET NULL; ForeignKeyChatMessagesChatID ForeignKeyConstraint = "chat_messages_chat_id_fkey" // ALTER TABLE ONLY chat_messages ADD CONSTRAINT chat_messages_chat_id_fkey FOREIGN KEY (chat_id) REFERENCES chats(id) ON DELETE CASCADE; ForeignKeyChatMessagesModelConfigID ForeignKeyConstraint = "chat_messages_model_config_id_fkey" // ALTER TABLE ONLY chat_messages ADD CONSTRAINT chat_messages_model_config_id_fkey FOREIGN KEY (model_config_id) REFERENCES chat_model_configs(id); - ForeignKeyChatModelConfigsAiProviderID ForeignKeyConstraint = "chat_model_configs_ai_provider_id_fkey" // ALTER TABLE ONLY chat_model_configs ADD CONSTRAINT chat_model_configs_ai_provider_id_fkey FOREIGN KEY (ai_provider_id) REFERENCES ai_providers(id); + ForeignKeyChatModelConfigsAIProviderID ForeignKeyConstraint = "chat_model_configs_ai_provider_id_fkey" // ALTER TABLE ONLY chat_model_configs ADD CONSTRAINT chat_model_configs_ai_provider_id_fkey FOREIGN KEY (ai_provider_id) REFERENCES ai_providers(id); ForeignKeyChatModelConfigsCreatedBy ForeignKeyConstraint = "chat_model_configs_created_by_fkey" // ALTER TABLE ONLY chat_model_configs ADD CONSTRAINT chat_model_configs_created_by_fkey FOREIGN KEY (created_by) REFERENCES users(id); ForeignKeyChatModelConfigsUpdatedBy ForeignKeyConstraint = "chat_model_configs_updated_by_fkey" // ALTER TABLE ONLY chat_model_configs ADD CONSTRAINT chat_model_configs_updated_by_fkey FOREIGN KEY (updated_by) REFERENCES users(id); ForeignKeyChatQueuedMessagesAPIKeyID ForeignKeyConstraint = "chat_queued_messages_api_key_id_fkey" // ALTER TABLE ONLY chat_queued_messages ADD CONSTRAINT chat_queued_messages_api_key_id_fkey FOREIGN KEY (api_key_id) REFERENCES api_keys(id) ON DELETE SET NULL; @@ -48,7 +48,7 @@ const ( ForeignKeyGitAuthLinksOauthRefreshTokenKeyID ForeignKeyConstraint = "git_auth_links_oauth_refresh_token_key_id_fkey" // ALTER TABLE ONLY external_auth_links ADD CONSTRAINT git_auth_links_oauth_refresh_token_key_id_fkey FOREIGN KEY (oauth_refresh_token_key_id) REFERENCES dbcrypt_keys(active_key_digest); ForeignKeyGitSSHKeysPrivateKeyKeyID ForeignKeyConstraint = "gitsshkeys_private_key_key_id_fkey" // ALTER TABLE ONLY gitsshkeys ADD CONSTRAINT gitsshkeys_private_key_key_id_fkey FOREIGN KEY (private_key_key_id) REFERENCES dbcrypt_keys(active_key_digest); ForeignKeyGitSSHKeysUserID ForeignKeyConstraint = "gitsshkeys_user_id_fkey" // ALTER TABLE ONLY gitsshkeys ADD CONSTRAINT gitsshkeys_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id); - ForeignKeyGroupAiBudgetsGroupID ForeignKeyConstraint = "group_ai_budgets_group_id_fkey" // ALTER TABLE ONLY group_ai_budgets ADD CONSTRAINT group_ai_budgets_group_id_fkey FOREIGN KEY (group_id) REFERENCES groups(id) ON DELETE CASCADE; + ForeignKeyGroupAIBudgetsGroupID ForeignKeyConstraint = "group_ai_budgets_group_id_fkey" // ALTER TABLE ONLY group_ai_budgets ADD CONSTRAINT group_ai_budgets_group_id_fkey FOREIGN KEY (group_id) REFERENCES groups(id) ON DELETE CASCADE; ForeignKeyGroupMembersGroupID ForeignKeyConstraint = "group_members_group_id_fkey" // ALTER TABLE ONLY group_members ADD CONSTRAINT group_members_group_id_fkey FOREIGN KEY (group_id) REFERENCES groups(id) ON DELETE CASCADE; ForeignKeyGroupMembersUserID ForeignKeyConstraint = "group_members_user_id_fkey" // ALTER TABLE ONLY group_members ADD CONSTRAINT group_members_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; ForeignKeyGroupsOrganizationID ForeignKeyConstraint = "groups_organization_id_fkey" // ALTER TABLE ONLY groups ADD CONSTRAINT groups_organization_id_fkey FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE; @@ -106,11 +106,11 @@ const ( ForeignKeyTemplateVersionsTemplateID ForeignKeyConstraint = "template_versions_template_id_fkey" // ALTER TABLE ONLY template_versions ADD CONSTRAINT template_versions_template_id_fkey FOREIGN KEY (template_id) REFERENCES templates(id) ON DELETE CASCADE; ForeignKeyTemplatesCreatedBy ForeignKeyConstraint = "templates_created_by_fkey" // ALTER TABLE ONLY templates ADD CONSTRAINT templates_created_by_fkey FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE RESTRICT; ForeignKeyTemplatesOrganizationID ForeignKeyConstraint = "templates_organization_id_fkey" // ALTER TABLE ONLY templates ADD CONSTRAINT templates_organization_id_fkey FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE; - ForeignKeyUserAiBudgetOverridesGroupID ForeignKeyConstraint = "user_ai_budget_overrides_group_id_fkey" // ALTER TABLE ONLY user_ai_budget_overrides ADD CONSTRAINT user_ai_budget_overrides_group_id_fkey FOREIGN KEY (group_id) REFERENCES groups(id) ON DELETE CASCADE; - ForeignKeyUserAiBudgetOverridesUserID ForeignKeyConstraint = "user_ai_budget_overrides_user_id_fkey" // ALTER TABLE ONLY user_ai_budget_overrides ADD CONSTRAINT user_ai_budget_overrides_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; - ForeignKeyUserAiProviderKeysAiProviderID ForeignKeyConstraint = "user_ai_provider_keys_ai_provider_id_fkey" // ALTER TABLE ONLY user_ai_provider_keys ADD CONSTRAINT user_ai_provider_keys_ai_provider_id_fkey FOREIGN KEY (ai_provider_id) REFERENCES ai_providers(id) ON DELETE CASCADE; - ForeignKeyUserAiProviderKeysAPIKeyKeyID ForeignKeyConstraint = "user_ai_provider_keys_api_key_key_id_fkey" // ALTER TABLE ONLY user_ai_provider_keys ADD CONSTRAINT user_ai_provider_keys_api_key_key_id_fkey FOREIGN KEY (api_key_key_id) REFERENCES dbcrypt_keys(active_key_digest); - ForeignKeyUserAiProviderKeysUserID ForeignKeyConstraint = "user_ai_provider_keys_user_id_fkey" // ALTER TABLE ONLY user_ai_provider_keys ADD CONSTRAINT user_ai_provider_keys_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; + ForeignKeyUserAIBudgetOverridesGroupID ForeignKeyConstraint = "user_ai_budget_overrides_group_id_fkey" // ALTER TABLE ONLY user_ai_budget_overrides ADD CONSTRAINT user_ai_budget_overrides_group_id_fkey FOREIGN KEY (group_id) REFERENCES groups(id) ON DELETE CASCADE; + ForeignKeyUserAIBudgetOverridesUserID ForeignKeyConstraint = "user_ai_budget_overrides_user_id_fkey" // ALTER TABLE ONLY user_ai_budget_overrides ADD CONSTRAINT user_ai_budget_overrides_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; + ForeignKeyUserAIProviderKeysAIProviderID ForeignKeyConstraint = "user_ai_provider_keys_ai_provider_id_fkey" // ALTER TABLE ONLY user_ai_provider_keys ADD CONSTRAINT user_ai_provider_keys_ai_provider_id_fkey FOREIGN KEY (ai_provider_id) REFERENCES ai_providers(id) ON DELETE CASCADE; + ForeignKeyUserAIProviderKeysAPIKeyKeyID ForeignKeyConstraint = "user_ai_provider_keys_api_key_key_id_fkey" // ALTER TABLE ONLY user_ai_provider_keys ADD CONSTRAINT user_ai_provider_keys_api_key_key_id_fkey FOREIGN KEY (api_key_key_id) REFERENCES dbcrypt_keys(active_key_digest); + ForeignKeyUserAIProviderKeysUserID ForeignKeyConstraint = "user_ai_provider_keys_user_id_fkey" // ALTER TABLE ONLY user_ai_provider_keys ADD CONSTRAINT user_ai_provider_keys_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; ForeignKeyUserConfigsUserID ForeignKeyConstraint = "user_configs_user_id_fkey" // ALTER TABLE ONLY user_configs ADD CONSTRAINT user_configs_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; ForeignKeyUserDeletedUserID ForeignKeyConstraint = "user_deleted_user_id_fkey" // ALTER TABLE ONLY user_deleted ADD CONSTRAINT user_deleted_user_id_fkey FOREIGN KEY (user_id) REFERENCES users(id); ForeignKeyUserLinksOauthAccessTokenKeyID ForeignKeyConstraint = "user_links_oauth_access_token_key_id_fkey" // ALTER TABLE ONLY user_links ADD CONSTRAINT user_links_oauth_access_token_key_id_fkey FOREIGN KEY (oauth_access_token_key_id) REFERENCES dbcrypt_keys(active_key_digest); diff --git a/coderd/database/modelmethods.go b/coderd/database/modelmethods.go index 63b367a6a5..cec3e1d291 100644 --- a/coderd/database/modelmethods.go +++ b/coderd/database/modelmethods.go @@ -84,38 +84,38 @@ type AuditableGroup struct { Members []GroupMemberTable `json:"members"` } -// AuditableGroupAiBudget is the audit-log representation of GroupAiBudget. +// AuditableGroupAIBudget is the audit-log representation of GroupAIBudget. // It enriches the raw record with the group's name and a human-readable // spend limit so audit entries can display meaningful values instead of // UUIDs and micros. -type AuditableGroupAiBudget struct { - GroupAiBudget +type AuditableGroupAIBudget struct { + GroupAIBudget GroupName string `json:"group_name"` SpendLimit string `json:"spend_limit"` } -func (b GroupAiBudget) Auditable(groupName string) AuditableGroupAiBudget { - return AuditableGroupAiBudget{ - GroupAiBudget: b, +func (b GroupAIBudget) Auditable(groupName string) AuditableGroupAIBudget { + return AuditableGroupAIBudget{ + GroupAIBudget: b, GroupName: groupName, SpendLimit: fmt.Sprintf("$%.2f", float64(b.SpendLimitMicros)/1_000_000), } } -// AuditableUserAiBudgetOverride is the audit-log representation of -// UserAiBudgetOverride. It enriches the raw record with the username, the +// AuditableUserAIBudgetOverride is the audit-log representation of +// UserAIBudgetOverride. It enriches the raw record with the username, the // attributed group's name, and a human-readable spend limit so audit // entries can display meaningful values instead of UUIDs and micros. -type AuditableUserAiBudgetOverride struct { - UserAiBudgetOverride +type AuditableUserAIBudgetOverride struct { + UserAIBudgetOverride Username string `json:"username"` GroupName string `json:"group_name"` SpendLimit string `json:"spend_limit"` } -func (o UserAiBudgetOverride) Auditable(username, groupName string) AuditableUserAiBudgetOverride { - return AuditableUserAiBudgetOverride{ - UserAiBudgetOverride: o, +func (o UserAIBudgetOverride) Auditable(username, groupName string) AuditableUserAIBudgetOverride { + return AuditableUserAIBudgetOverride{ + UserAIBudgetOverride: o, Username: username, GroupName: groupName, SpendLimit: fmt.Sprintf("$%.2f", float64(o.SpendLimitMicros)/1_000_000), diff --git a/coderd/database/models.go b/coderd/database/models.go index f3069f9994..705c441816 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -19,15 +19,15 @@ import ( type AIProviderType string const ( - AiProviderTypeOpenai AIProviderType = "openai" - AiProviderTypeAnthropic AIProviderType = "anthropic" - AiProviderTypeAzure AIProviderType = "azure" - AiProviderTypeBedrock AIProviderType = "bedrock" - AiProviderTypeGoogle AIProviderType = "google" - AiProviderTypeOpenaiCompat AIProviderType = "openai-compat" - AiProviderTypeOpenrouter AIProviderType = "openrouter" - AiProviderTypeVercel AIProviderType = "vercel" - AiProviderTypeCopilot AIProviderType = "copilot" + AIProviderTypeOpenai AIProviderType = "openai" + AIProviderTypeAnthropic AIProviderType = "anthropic" + AIProviderTypeAzure AIProviderType = "azure" + AIProviderTypeBedrock AIProviderType = "bedrock" + AIProviderTypeGoogle AIProviderType = "google" + AIProviderTypeOpenaiCompat AIProviderType = "openai-compat" + AIProviderTypeOpenrouter AIProviderType = "openrouter" + AIProviderTypeVercel AIProviderType = "vercel" + AIProviderTypeCopilot AIProviderType = "copilot" ) func (e *AIProviderType) Scan(src interface{}) error { @@ -67,15 +67,15 @@ func (ns NullAIProviderType) Value() (driver.Value, error) { func (e AIProviderType) Valid() bool { switch e { - case AiProviderTypeOpenai, - AiProviderTypeAnthropic, - AiProviderTypeAzure, - AiProviderTypeBedrock, - AiProviderTypeGoogle, - AiProviderTypeOpenaiCompat, - AiProviderTypeOpenrouter, - AiProviderTypeVercel, - AiProviderTypeCopilot: + case AIProviderTypeOpenai, + AIProviderTypeAnthropic, + AIProviderTypeAzure, + AIProviderTypeBedrock, + AIProviderTypeGoogle, + AIProviderTypeOpenaiCompat, + AIProviderTypeOpenrouter, + AIProviderTypeVercel, + AIProviderTypeCopilot: return true } return false @@ -83,15 +83,73 @@ func (e AIProviderType) Valid() bool { func AllAIProviderTypeValues() []AIProviderType { return []AIProviderType{ - AiProviderTypeOpenai, - AiProviderTypeAnthropic, - AiProviderTypeAzure, - AiProviderTypeBedrock, - AiProviderTypeGoogle, - AiProviderTypeOpenaiCompat, - AiProviderTypeOpenrouter, - AiProviderTypeVercel, - AiProviderTypeCopilot, + AIProviderTypeOpenai, + AIProviderTypeAnthropic, + AIProviderTypeAzure, + AIProviderTypeBedrock, + AIProviderTypeGoogle, + AIProviderTypeOpenaiCompat, + AIProviderTypeOpenrouter, + AIProviderTypeVercel, + AIProviderTypeCopilot, + } +} + +type AISeatUsageReason string + +const ( + AISeatUsageReasonAibridge AISeatUsageReason = "aibridge" + AISeatUsageReasonTask AISeatUsageReason = "task" +) + +func (e *AISeatUsageReason) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = AISeatUsageReason(s) + case string: + *e = AISeatUsageReason(s) + default: + return fmt.Errorf("unsupported scan type for AISeatUsageReason: %T", src) + } + return nil +} + +type NullAISeatUsageReason struct { + AISeatUsageReason AISeatUsageReason `json:"ai_seat_usage_reason"` + Valid bool `json:"valid"` // Valid is true if AISeatUsageReason is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullAISeatUsageReason) Scan(value interface{}) error { + if value == nil { + ns.AISeatUsageReason, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.AISeatUsageReason.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullAISeatUsageReason) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.AISeatUsageReason), nil +} + +func (e AISeatUsageReason) Valid() bool { + switch e { + case AISeatUsageReasonAibridge, + AISeatUsageReasonTask: + return true + } + return false +} + +func AllAISeatUsageReasonValues() []AISeatUsageReason { + return []AISeatUsageReason{ + AISeatUsageReasonAibridge, + AISeatUsageReasonTask, } } @@ -303,17 +361,17 @@ const ( ApiKeyScopeChatUpdate APIKeyScope = "chat:update" ApiKeyScopeChatDelete APIKeyScope = "chat:delete" ApiKeyScopeChat APIKeyScope = "chat:*" - ApiKeyScopeAiSeat APIKeyScope = "ai_seat:*" - ApiKeyScopeAiSeatCreate APIKeyScope = "ai_seat:create" - ApiKeyScopeAiSeatRead APIKeyScope = "ai_seat:read" - ApiKeyScopeAiModelPrice APIKeyScope = "ai_model_price:*" - ApiKeyScopeAiModelPriceRead APIKeyScope = "ai_model_price:read" - ApiKeyScopeAiModelPriceUpdate APIKeyScope = "ai_model_price:update" - ApiKeyScopeAiProvider APIKeyScope = "ai_provider:*" - ApiKeyScopeAiProviderCreate APIKeyScope = "ai_provider:create" - ApiKeyScopeAiProviderDelete APIKeyScope = "ai_provider:delete" - ApiKeyScopeAiProviderRead APIKeyScope = "ai_provider:read" - ApiKeyScopeAiProviderUpdate APIKeyScope = "ai_provider:update" + ApiKeyScopeAISeat APIKeyScope = "ai_seat:*" + ApiKeyScopeAISeatCreate APIKeyScope = "ai_seat:create" + ApiKeyScopeAISeatRead APIKeyScope = "ai_seat:read" + ApiKeyScopeAIModelPrice APIKeyScope = "ai_model_price:*" + ApiKeyScopeAIModelPriceRead APIKeyScope = "ai_model_price:read" + ApiKeyScopeAIModelPriceUpdate APIKeyScope = "ai_model_price:update" + ApiKeyScopeAIProvider APIKeyScope = "ai_provider:*" + ApiKeyScopeAIProviderCreate APIKeyScope = "ai_provider:create" + ApiKeyScopeAIProviderDelete APIKeyScope = "ai_provider:delete" + ApiKeyScopeAIProviderRead APIKeyScope = "ai_provider:read" + ApiKeyScopeAIProviderUpdate APIKeyScope = "ai_provider:update" ApiKeyScopeChatShare APIKeyScope = "chat:share" ApiKeyScopeUserSkillCreate APIKeyScope = "user_skill:create" ApiKeyScopeUserSkillRead APIKeyScope = "user_skill:read" @@ -324,10 +382,10 @@ const ( ApiKeyScopeBoundaryLogCreate APIKeyScope = "boundary_log:create" ApiKeyScopeBoundaryLogDelete APIKeyScope = "boundary_log:delete" ApiKeyScopeBoundaryLogRead APIKeyScope = "boundary_log:read" - ApiKeyScopeAiGatewayKey APIKeyScope = "ai_gateway_key:*" - ApiKeyScopeAiGatewayKeyCreate APIKeyScope = "ai_gateway_key:create" - ApiKeyScopeAiGatewayKeyDelete APIKeyScope = "ai_gateway_key:delete" - ApiKeyScopeAiGatewayKeyRead APIKeyScope = "ai_gateway_key:read" + ApiKeyScopeAIGatewayKey APIKeyScope = "ai_gateway_key:*" + ApiKeyScopeAIGatewayKeyCreate APIKeyScope = "ai_gateway_key:create" + ApiKeyScopeAIGatewayKeyDelete APIKeyScope = "ai_gateway_key:delete" + ApiKeyScopeAIGatewayKeyRead APIKeyScope = "ai_gateway_key:read" ) func (e *APIKeyScope) Scan(src interface{}) error { @@ -572,17 +630,17 @@ func (e APIKeyScope) Valid() bool { ApiKeyScopeChatUpdate, ApiKeyScopeChatDelete, ApiKeyScopeChat, - ApiKeyScopeAiSeat, - ApiKeyScopeAiSeatCreate, - ApiKeyScopeAiSeatRead, - ApiKeyScopeAiModelPrice, - ApiKeyScopeAiModelPriceRead, - ApiKeyScopeAiModelPriceUpdate, - ApiKeyScopeAiProvider, - ApiKeyScopeAiProviderCreate, - ApiKeyScopeAiProviderDelete, - ApiKeyScopeAiProviderRead, - ApiKeyScopeAiProviderUpdate, + ApiKeyScopeAISeat, + ApiKeyScopeAISeatCreate, + ApiKeyScopeAISeatRead, + ApiKeyScopeAIModelPrice, + ApiKeyScopeAIModelPriceRead, + ApiKeyScopeAIModelPriceUpdate, + ApiKeyScopeAIProvider, + ApiKeyScopeAIProviderCreate, + ApiKeyScopeAIProviderDelete, + ApiKeyScopeAIProviderRead, + ApiKeyScopeAIProviderUpdate, ApiKeyScopeChatShare, ApiKeyScopeUserSkillCreate, ApiKeyScopeUserSkillRead, @@ -593,10 +651,10 @@ func (e APIKeyScope) Valid() bool { ApiKeyScopeBoundaryLogCreate, ApiKeyScopeBoundaryLogDelete, ApiKeyScopeBoundaryLogRead, - ApiKeyScopeAiGatewayKey, - ApiKeyScopeAiGatewayKeyCreate, - ApiKeyScopeAiGatewayKeyDelete, - ApiKeyScopeAiGatewayKeyRead: + ApiKeyScopeAIGatewayKey, + ApiKeyScopeAIGatewayKeyCreate, + ApiKeyScopeAIGatewayKeyDelete, + ApiKeyScopeAIGatewayKeyRead: return true } return false @@ -809,17 +867,17 @@ func AllAPIKeyScopeValues() []APIKeyScope { ApiKeyScopeChatUpdate, ApiKeyScopeChatDelete, ApiKeyScopeChat, - ApiKeyScopeAiSeat, - ApiKeyScopeAiSeatCreate, - ApiKeyScopeAiSeatRead, - ApiKeyScopeAiModelPrice, - ApiKeyScopeAiModelPriceRead, - ApiKeyScopeAiModelPriceUpdate, - ApiKeyScopeAiProvider, - ApiKeyScopeAiProviderCreate, - ApiKeyScopeAiProviderDelete, - ApiKeyScopeAiProviderRead, - ApiKeyScopeAiProviderUpdate, + ApiKeyScopeAISeat, + ApiKeyScopeAISeatCreate, + ApiKeyScopeAISeatRead, + ApiKeyScopeAIModelPrice, + ApiKeyScopeAIModelPriceRead, + ApiKeyScopeAIModelPriceUpdate, + ApiKeyScopeAIProvider, + ApiKeyScopeAIProviderCreate, + ApiKeyScopeAIProviderDelete, + ApiKeyScopeAIProviderRead, + ApiKeyScopeAIProviderUpdate, ApiKeyScopeChatShare, ApiKeyScopeUserSkillCreate, ApiKeyScopeUserSkillRead, @@ -830,10 +888,10 @@ func AllAPIKeyScopeValues() []APIKeyScope { ApiKeyScopeBoundaryLogCreate, ApiKeyScopeBoundaryLogDelete, ApiKeyScopeBoundaryLogRead, - ApiKeyScopeAiGatewayKey, - ApiKeyScopeAiGatewayKeyCreate, - ApiKeyScopeAiGatewayKeyDelete, - ApiKeyScopeAiGatewayKeyRead, + ApiKeyScopeAIGatewayKey, + ApiKeyScopeAIGatewayKeyCreate, + ApiKeyScopeAIGatewayKeyDelete, + ApiKeyScopeAIGatewayKeyRead, } } @@ -895,64 +953,6 @@ func AllAgentKeyScopeEnumValues() []AgentKeyScopeEnum { } } -type AiSeatUsageReason string - -const ( - AiSeatUsageReasonAibridge AiSeatUsageReason = "aibridge" - AiSeatUsageReasonTask AiSeatUsageReason = "task" -) - -func (e *AiSeatUsageReason) Scan(src interface{}) error { - switch s := src.(type) { - case []byte: - *e = AiSeatUsageReason(s) - case string: - *e = AiSeatUsageReason(s) - default: - return fmt.Errorf("unsupported scan type for AiSeatUsageReason: %T", src) - } - return nil -} - -type NullAiSeatUsageReason struct { - AiSeatUsageReason AiSeatUsageReason `json:"ai_seat_usage_reason"` - Valid bool `json:"valid"` // Valid is true if AiSeatUsageReason is not NULL -} - -// Scan implements the Scanner interface. -func (ns *NullAiSeatUsageReason) Scan(value interface{}) error { - if value == nil { - ns.AiSeatUsageReason, ns.Valid = "", false - return nil - } - ns.Valid = true - return ns.AiSeatUsageReason.Scan(value) -} - -// Value implements the driver Valuer interface. -func (ns NullAiSeatUsageReason) Value() (driver.Value, error) { - if !ns.Valid { - return nil, nil - } - return string(ns.AiSeatUsageReason), nil -} - -func (e AiSeatUsageReason) Valid() bool { - switch e { - case AiSeatUsageReasonAibridge, - AiSeatUsageReasonTask: - return true - } - return false -} - -func AllAiSeatUsageReasonValues() []AiSeatUsageReason { - return []AiSeatUsageReason{ - AiSeatUsageReasonAibridge, - AiSeatUsageReasonTask, - } -} - type AppSharingLevel string const ( @@ -3361,15 +3361,15 @@ const ( ResourceTypeWorkspaceApp ResourceType = "workspace_app" ResourceTypePrebuildsSettings ResourceType = "prebuilds_settings" ResourceTypeTask ResourceType = "task" - ResourceTypeAiSeat ResourceType = "ai_seat" + ResourceTypeAISeat ResourceType = "ai_seat" ResourceTypeChat ResourceType = "chat" ResourceTypeUserSecret ResourceType = "user_secret" ResourceTypeAIProvider ResourceType = "ai_provider" ResourceTypeAIProviderKey ResourceType = "ai_provider_key" - ResourceTypeGroupAiBudget ResourceType = "group_ai_budget" + ResourceTypeGroupAIBudget ResourceType = "group_ai_budget" ResourceTypeUserSkill ResourceType = "user_skill" ResourceTypeAIGatewayKey ResourceType = "ai_gateway_key" - ResourceTypeUserAiBudgetOverride ResourceType = "user_ai_budget_override" + ResourceTypeUserAIBudgetOverride ResourceType = "user_ai_budget_override" ) func (e *ResourceType) Scan(src interface{}) error { @@ -3435,15 +3435,15 @@ func (e ResourceType) Valid() bool { ResourceTypeWorkspaceApp, ResourceTypePrebuildsSettings, ResourceTypeTask, - ResourceTypeAiSeat, + ResourceTypeAISeat, ResourceTypeChat, ResourceTypeUserSecret, ResourceTypeAIProvider, ResourceTypeAIProviderKey, - ResourceTypeGroupAiBudget, + ResourceTypeGroupAIBudget, ResourceTypeUserSkill, ResourceTypeAIGatewayKey, - ResourceTypeUserAiBudgetOverride: + ResourceTypeUserAIBudgetOverride: return true } return false @@ -3477,15 +3477,15 @@ func AllResourceTypeValues() []ResourceType { ResourceTypeWorkspaceApp, ResourceTypePrebuildsSettings, ResourceTypeTask, - ResourceTypeAiSeat, + ResourceTypeAISeat, ResourceTypeChat, ResourceTypeUserSecret, ResourceTypeAIProvider, ResourceTypeAIProviderKey, - ResourceTypeGroupAiBudget, + ResourceTypeGroupAIBudget, ResourceTypeUserSkill, ResourceTypeAIGatewayKey, - ResourceTypeUserAiBudgetOverride, + ResourceTypeUserAIBudgetOverride, } } @@ -4614,6 +4614,18 @@ type AIGatewayKey struct { LastUsedAt sql.NullTime `db:"last_used_at" json:"last_used_at"` } +// Per-model token prices used by AI Bridge to compute interception cost. +type AIModelPrice struct { + Provider string `db:"provider" json:"provider"` + Model string `db:"model" json:"model"` + InputPrice sql.NullInt64 `db:"input_price" json:"input_price"` + OutputPrice sql.NullInt64 `db:"output_price" json:"output_price"` + CacheReadPrice sql.NullInt64 `db:"cache_read_price" json:"cache_read_price"` + CacheWritePrice sql.NullInt64 `db:"cache_write_price" json:"cache_write_price"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` +} + // Runtime configuration for AI providers. Authoritative source for the provider set served by aibridged. Replaces deployment-time CODER_AIBRIDGE_* environment variables. type AIProvider struct { ID uuid.UUID `db:"id" json:"id"` @@ -4645,6 +4657,15 @@ type AIProviderKey struct { UpdatedAt time.Time `db:"updated_at" json:"updated_at"` } +type AISeatState struct { + UserID uuid.UUID `db:"user_id" json:"user_id"` + FirstUsedAt time.Time `db:"first_used_at" json:"first_used_at"` + LastUsedAt time.Time `db:"last_used_at" json:"last_used_at"` + LastEventType AISeatUsageReason `db:"last_event_type" json:"last_event_type"` + LastEventDescription string `db:"last_event_description" json:"last_event_description"` + UpdatedAt time.Time `db:"updated_at" json:"updated_at"` +} + type APIKey struct { ID string `db:"id" json:"id"` // hashed_secret contains a SHA256 hash of the key secret. This is considered a secret and MUST NOT be returned from the API as it is used for API key encryption in app proxying code. @@ -4662,27 +4683,6 @@ type APIKey struct { AllowList AllowList `db:"allow_list" json:"allow_list"` } -// Per-model token prices used by AI Bridge to compute interception cost. -type AiModelPrice struct { - Provider string `db:"provider" json:"provider"` - Model string `db:"model" json:"model"` - InputPrice sql.NullInt64 `db:"input_price" json:"input_price"` - OutputPrice sql.NullInt64 `db:"output_price" json:"output_price"` - CacheReadPrice sql.NullInt64 `db:"cache_read_price" json:"cache_read_price"` - CacheWritePrice sql.NullInt64 `db:"cache_write_price" json:"cache_write_price"` - CreatedAt time.Time `db:"created_at" json:"created_at"` - UpdatedAt time.Time `db:"updated_at" json:"updated_at"` -} - -type AiSeatState struct { - UserID uuid.UUID `db:"user_id" json:"user_id"` - FirstUsedAt time.Time `db:"first_used_at" json:"first_used_at"` - LastUsedAt time.Time `db:"last_used_at" json:"last_used_at"` - LastEventType AiSeatUsageReason `db:"last_event_type" json:"last_event_type"` - LastEventDescription string `db:"last_event_description" json:"last_event_description"` - UpdatedAt time.Time `db:"updated_at" json:"updated_at"` -} - type AuditLog struct { ID uuid.UUID `db:"id" json:"id"` Time time.Time `db:"time" json:"time"` @@ -5126,7 +5126,7 @@ type Group struct { } // Per-group AI spend limit applied to each member of the group. No row means no budget is enforced. -type GroupAiBudget struct { +type GroupAIBudget struct { GroupID uuid.UUID `db:"group_id" json:"group_id"` SpendLimitMicros int64 `db:"spend_limit_micros" json:"spend_limit_micros"` CreatedAt time.Time `db:"created_at" json:"created_at"` @@ -5955,7 +5955,7 @@ type User struct { } // Per-user AI spend override that supersedes group budget resolution. -type UserAiBudgetOverride struct { +type UserAIBudgetOverride struct { UserID uuid.UUID `db:"user_id" json:"user_id"` GroupID uuid.UUID `db:"group_id" json:"group_id"` SpendLimitMicros int64 `db:"spend_limit_micros" json:"spend_limit_micros"` @@ -5964,7 +5964,7 @@ type UserAiBudgetOverride struct { } // User-owned API keys associated with AI providers. These keys are used only when BYOK is enabled. -type UserAiProviderKey struct { +type UserAIProviderKey struct { ID uuid.UUID `db:"id" json:"id"` UserID uuid.UUID `db:"user_id" json:"user_id"` AIProviderID uuid.UUID `db:"ai_provider_id" json:"ai_provider_id"` diff --git a/coderd/database/querier.go b/coderd/database/querier.go index c0401c1889..2169c3c767 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -153,7 +153,7 @@ type sqlcQuerier interface { DeleteCustomRole(ctx context.Context, arg DeleteCustomRoleParams) error DeleteExpiredAPIKeys(ctx context.Context, arg DeleteExpiredAPIKeysParams) (int64, error) DeleteExternalAuthLink(ctx context.Context, arg DeleteExternalAuthLinkParams) error - DeleteGroupAIBudget(ctx context.Context, groupID uuid.UUID) (GroupAiBudget, error) + DeleteGroupAIBudget(ctx context.Context, groupID uuid.UUID) (GroupAIBudget, error) DeleteGroupByID(ctx context.Context, id uuid.UUID) error DeleteGroupMemberFromGroup(ctx context.Context, arg DeleteGroupMemberFromGroupParams) error DeleteLicense(ctx context.Context, id int32) (int32, error) @@ -223,7 +223,7 @@ type sqlcQuerier interface { DeleteTailnetPeer(ctx context.Context, arg DeleteTailnetPeerParams) (DeleteTailnetPeerRow, error) DeleteTailnetTunnel(ctx context.Context, arg DeleteTailnetTunnelParams) (DeleteTailnetTunnelRow, error) DeleteTask(ctx context.Context, arg DeleteTaskParams) (uuid.UUID, error) - DeleteUserAIBudgetOverride(ctx context.Context, userID uuid.UUID) (UserAiBudgetOverride, error) + DeleteUserAIBudgetOverride(ctx context.Context, userID uuid.UUID) (UserAIBudgetOverride, error) DeleteUserAIProviderKey(ctx context.Context, arg DeleteUserAIProviderKeyParams) error DeleteUserAIProviderKeysByProviderID(ctx context.Context, aiProviderID uuid.UUID) error DeleteUserChatCompactionThreshold(ctx context.Context, arg DeleteUserChatCompactionThresholdParams) error @@ -290,7 +290,7 @@ type sqlcQuerier interface { GetAIBridgeTokenUsagesByInterceptionID(ctx context.Context, interceptionID uuid.UUID) ([]AIBridgeTokenUsage, error) GetAIBridgeToolUsagesByInterceptionID(ctx context.Context, interceptionID uuid.UUID) ([]AIBridgeToolUsage, error) GetAIBridgeUserPromptsByInterceptionID(ctx context.Context, interceptionID uuid.UUID) ([]AIBridgeUserPrompt, error) - GetAIModelPriceByProviderModel(ctx context.Context, arg GetAIModelPriceByProviderModelParams) (AiModelPrice, error) + GetAIModelPriceByProviderModel(ctx context.Context, arg GetAIModelPriceByProviderModelParams) (AIModelPrice, error) GetAIProviderByID(ctx context.Context, id uuid.UUID) (AIProvider, error) // Lock the provider row until the model-config write completes. The // transaction alone does not stop a concurrent soft-delete or disable @@ -552,7 +552,7 @@ type sqlcQuerier interface { GetFilteredInboxNotificationsByUserID(ctx context.Context, arg GetFilteredInboxNotificationsByUserIDParams) ([]InboxNotification, error) GetForcedMCPServerConfigs(ctx context.Context) ([]MCPServerConfig, error) GetGitSSHKey(ctx context.Context, userID uuid.UUID) (GitSSHKey, error) - GetGroupAIBudget(ctx context.Context, groupID uuid.UUID) (GroupAiBudget, error) + GetGroupAIBudget(ctx context.Context, groupID uuid.UUID) (GroupAIBudget, error) GetGroupByID(ctx context.Context, id uuid.UUID) (Group, error) GetGroupByOrgAndName(ctx context.Context, arg GetGroupByOrgAndNameParams) (Group, error) GetGroupMembers(ctx context.Context, includeSystem bool) ([]GroupMember, error) @@ -824,12 +824,12 @@ type sqlcQuerier interface { // inclusive. GetTotalUsageDCManagedAgentsV1(ctx context.Context, arg GetTotalUsageDCManagedAgentsV1Params) (int64, error) GetUnexpiredLicenses(ctx context.Context) ([]License, error) - GetUserAIBudgetOverride(ctx context.Context, userID uuid.UUID) (UserAiBudgetOverride, error) - GetUserAIProviderKeyByProviderID(ctx context.Context, arg GetUserAIProviderKeyByProviderIDParams) (UserAiProviderKey, error) + GetUserAIBudgetOverride(ctx context.Context, userID uuid.UUID) (UserAIBudgetOverride, error) + GetUserAIProviderKeyByProviderID(ctx context.Context, arg GetUserAIProviderKeyByProviderIDParams) (UserAIProviderKey, error) // GetUserAIProviderKeys is used by dbcrypt key rotation. Request paths should use // user-scoped lookups instead of this bulk accessor. - GetUserAIProviderKeys(ctx context.Context) ([]UserAiProviderKey, error) - GetUserAIProviderKeysByUserID(ctx context.Context, userID uuid.UUID) ([]UserAiProviderKey, error) + GetUserAIProviderKeys(ctx context.Context) ([]UserAIProviderKey, error) + GetUserAIProviderKeysByUserID(ctx context.Context, userID uuid.UUID) ([]UserAIProviderKey, error) // Returns user IDs from the provided list that are consuming an AI seat. // Filters to active, non-deleted, non-system users to match the canonical // seat count query (GetActiveAISeatCount). @@ -1377,7 +1377,7 @@ type sqlcQuerier interface { // Used by the dbcrypt key rotation utility to re-encrypt or decrypt // rows in place. UpdateEncryptedAIProviderSettings(ctx context.Context, arg UpdateEncryptedAIProviderSettingsParams) (AIProvider, error) - UpdateEncryptedUserAIProviderKey(ctx context.Context, arg UpdateEncryptedUserAIProviderKeyParams) (UserAiProviderKey, error) + UpdateEncryptedUserAIProviderKey(ctx context.Context, arg UpdateEncryptedUserAIProviderKeyParams) (UserAIProviderKey, error) UpdateExternalAuthLink(ctx context.Context, arg UpdateExternalAuthLinkParams) (ExternalAuthLink, error) // Optimistic lock: only update the row if the refresh token in the database // still matches the one we read before attempting the refresh. This prevents @@ -1426,7 +1426,7 @@ type sqlcQuerier interface { UpdateTemplateVersionFlagsByJobID(ctx context.Context, arg UpdateTemplateVersionFlagsByJobIDParams) error UpdateTemplateWorkspacesLastUsedAt(ctx context.Context, arg UpdateTemplateWorkspacesLastUsedAtParams) error UpdateUsageEventsPostPublish(ctx context.Context, arg UpdateUsageEventsPostPublishParams) error - UpdateUserAIProviderKey(ctx context.Context, arg UpdateUserAIProviderKeyParams) (UserAiProviderKey, error) + UpdateUserAIProviderKey(ctx context.Context, arg UpdateUserAIProviderKeyParams) (UserAIProviderKey, error) UpdateUserAgentChatSendShortcut(ctx context.Context, arg UpdateUserAgentChatSendShortcutParams) (string, error) UpdateUserChatCompactionThreshold(ctx context.Context, arg UpdateUserChatCompactionThresholdParams) (UserConfig, error) UpdateUserChatCustomPrompt(ctx context.Context, arg UpdateUserChatCustomPromptParams) (UserConfig, error) @@ -1532,7 +1532,7 @@ type sqlcQuerier interface { // So we need to store it's configuration here for display purposes. // The functional values are immutable and controlled implicitly. UpsertDefaultProxy(ctx context.Context, arg UpsertDefaultProxyParams) error - UpsertGroupAIBudget(ctx context.Context, arg UpsertGroupAIBudgetParams) (GroupAiBudget, error) + UpsertGroupAIBudget(ctx context.Context, arg UpsertGroupAIBudgetParams) (GroupAIBudget, error) UpsertHealthSettings(ctx context.Context, value string) error UpsertLastUpdateCheck(ctx context.Context, value string) error UpsertLogoURL(ctx context.Context, value string) error @@ -1555,11 +1555,11 @@ type sqlcQuerier interface { // used to store the data, and the minutes are summed for each user and template // combination. The result is stored in the template_usage_stats table. UpsertTemplateUsageStats(ctx context.Context) error - UpsertUserAIBudgetOverride(ctx context.Context, arg UpsertUserAIBudgetOverrideParams) (UserAiBudgetOverride, error) + UpsertUserAIBudgetOverride(ctx context.Context, arg UpsertUserAIBudgetOverrideParams) (UserAIBudgetOverride, error) // UpsertUserAIProviderKey preserves the original id and created_at when the // user/provider pair already exists. On conflict, callers provide id and // created_at for the insert path only. - UpsertUserAIProviderKey(ctx context.Context, arg UpsertUserAIProviderKeyParams) (UserAiProviderKey, error) + UpsertUserAIProviderKey(ctx context.Context, arg UpsertUserAIProviderKeyParams) (UserAIProviderKey, error) UpsertUserChatDebugLoggingEnabled(ctx context.Context, arg UpsertUserChatDebugLoggingEnabledParams) error UpsertUserChatPersonalModelOverride(ctx context.Context, arg UpsertUserChatPersonalModelOverrideParams) error UpsertWebpushVAPIDKeys(ctx context.Context, arg UpsertWebpushVAPIDKeysParams) error diff --git a/coderd/database/querier_test.go b/coderd/database/querier_test.go index 9efdd91dcb..7dbdccf93f 100644 --- a/coderd/database/querier_test.go +++ b/coderd/database/querier_test.go @@ -11087,11 +11087,11 @@ func TestGetEnabledChatModelConfigsUsesAIProviders(t *testing.T) { ctx := testutil.Context(t, testutil.WaitMedium) enabledProvider := dbgen.AIProvider(t, store, database.AIProvider{ - Type: database.AiProviderTypeOpenrouter, + Type: database.AIProviderTypeOpenrouter, Name: "openrouter-" + uuid.NewString(), }) disabledProvider := dbgen.AIProvider(t, store, database.AIProvider{ - Type: database.AiProviderTypeVercel, + Type: database.AIProviderTypeVercel, Name: "vercel-" + uuid.NewString(), }, func(params *database.InsertAIProviderParams) { params.Enabled = false @@ -11400,7 +11400,7 @@ func TestGetChatMessagesForPromptByChatID(t *testing.T) { // An AI provider row is required as a FK for model configs. provider := dbgen.AIProvider(t, db, database.AIProvider{ - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, Name: "test-" + uuid.NewString(), DisplayName: sql.NullString{String: "OpenAI", Valid: true}, Enabled: true, @@ -11739,7 +11739,7 @@ func TestUpsertAISeats(t *testing.T) { newRow, err := db.UpsertAISeatState(ctx, database.UpsertAISeatStateParams{ UserID: user.ID, FirstUsedAt: now.Add(time.Hour * -24), - LastEventType: database.AiSeatUsageReasonTask, + LastEventType: database.AISeatUsageReasonTask, }) require.NoError(t, err) require.True(t, newRow) @@ -11747,7 +11747,7 @@ func TestUpsertAISeats(t *testing.T) { alreadyExists, err := db.UpsertAISeatState(ctx, database.UpsertAISeatStateParams{ UserID: user.ID, FirstUsedAt: now.Add(time.Hour * -23), - LastEventType: database.AiSeatUsageReasonTask, + LastEventType: database.AISeatUsageReasonTask, }) require.NoError(t, err) require.False(t, alreadyExists) @@ -11755,7 +11755,7 @@ func TestUpsertAISeats(t *testing.T) { alreadyExists, err = db.UpsertAISeatState(ctx, database.UpsertAISeatStateParams{ UserID: user.ID, FirstUsedAt: now, - LastEventType: database.AiSeatUsageReasonTask, + LastEventType: database.AISeatUsageReasonTask, }) require.NoError(t, err) require.False(t, alreadyExists) @@ -14604,7 +14604,7 @@ func TestGetChatsFilter(t *testing.T) { dbgen.OrganizationMember(t, store, database.OrganizationMember{UserID: user.ID, OrganizationID: org.ID}) provider := dbgen.AIProviderWithOptionalKey(t, store, database.AIProvider{ - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, }, "test-key") modelCfg, err := store.InsertChatModelConfig(ctx, database.InsertChatModelConfigParams{ @@ -15395,67 +15395,67 @@ func TestAIGatewayKeysTableConstraints(t *testing.T) { { name: "duplicate name", params: aiGatewayKeyParams(preExisting.Name, "key_test002"), - expectUniqueErr: database.UniqueAiGatewayKeysNameIndex, + expectUniqueErr: database.UniqueAIGatewayKeysNameIndex, }, { name: "duplicate secret prefix", params: aiGatewayKeyParams("different-key", preExisting.SecretPrefix), - expectUniqueErr: database.UniqueAiGatewayKeysSecretPrefixIndex, + expectUniqueErr: database.UniqueAIGatewayKeysSecretPrefixIndex, }, { name: "duplicate hashed secret", params: database.InsertAIGatewayKeyParams{ID: uuid.New(), Name: "other-name", SecretPrefix: "key_1234567", HashedSecret: preExisting.HashedSecret}, - expectUniqueErr: database.UniqueAiGatewayKeysHashedSecretIndex, + expectUniqueErr: database.UniqueAIGatewayKeysHashedSecretIndex, }, { name: "empty name", params: aiGatewayKeyParams("", "key_empty__"), - expectCheckErr: database.CheckAiGatewayKeysNameCheck, + expectCheckErr: database.CheckAIGatewayKeysNameCheck, }, { name: "name with trailing dash", params: aiGatewayKeyParams("other-name-", "key_trail__"), - expectCheckErr: database.CheckAiGatewayKeysNameCheck, + expectCheckErr: database.CheckAIGatewayKeysNameCheck, }, { name: "name with consecutive dashes", params: aiGatewayKeyParams("other--name", "key_consec_"), - expectCheckErr: database.CheckAiGatewayKeysNameCheck, + expectCheckErr: database.CheckAIGatewayKeysNameCheck, }, { name: "name with underscore", params: aiGatewayKeyParams("other_name", "key_undersc"), - expectCheckErr: database.CheckAiGatewayKeysNameCheck, + expectCheckErr: database.CheckAIGatewayKeysNameCheck, }, { name: "name with space", params: aiGatewayKeyParams("other name", "key_spacen_"), - expectCheckErr: database.CheckAiGatewayKeysNameCheck, + expectCheckErr: database.CheckAIGatewayKeysNameCheck, }, { name: "name with leading dash", params: aiGatewayKeyParams("-other-name", "key_leadng_"), - expectCheckErr: database.CheckAiGatewayKeysNameCheck, + expectCheckErr: database.CheckAIGatewayKeysNameCheck, }, { name: "name longer than 64 characters", params: aiGatewayKeyParams(strings.Repeat("a", 65), "key_longna_"), - expectCheckErr: database.CheckAiGatewayKeysNameCheck, + expectCheckErr: database.CheckAIGatewayKeysNameCheck, }, { name: "empty secret prefix", params: aiGatewayKeyParams("check-empty-pfx", ""), - expectCheckErr: database.CheckAiGatewayKeysSecretPrefixCheck, + expectCheckErr: database.CheckAIGatewayKeysSecretPrefixCheck, }, { name: "invalid secret prefix length", params: aiGatewayKeyParams("check-short-pfx", "key_short"), - expectCheckErr: database.CheckAiGatewayKeysSecretPrefixCheck, + expectCheckErr: database.CheckAIGatewayKeysSecretPrefixCheck, }, { name: "empty hashed secret", params: database.InsertAIGatewayKeyParams{ID: uuid.New(), Name: "check-empty-hash", SecretPrefix: "key_ehash__", HashedSecret: []byte{}}, - expectCheckErr: database.CheckAiGatewayKeysHashedSecretCheck, + expectCheckErr: database.CheckAIGatewayKeysHashedSecretCheck, }, } diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index fd2ce87426..998ec0464b 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -2346,9 +2346,9 @@ const deleteGroupAIBudget = `-- name: DeleteGroupAIBudget :one DELETE FROM group_ai_budgets WHERE group_id = $1 RETURNING group_id, spend_limit_micros, created_at, updated_at ` -func (q *sqlQuerier) DeleteGroupAIBudget(ctx context.Context, groupID uuid.UUID) (GroupAiBudget, error) { +func (q *sqlQuerier) DeleteGroupAIBudget(ctx context.Context, groupID uuid.UUID) (GroupAIBudget, error) { row := q.db.QueryRowContext(ctx, deleteGroupAIBudget, groupID) - var i GroupAiBudget + var i GroupAIBudget err := row.Scan( &i.GroupID, &i.SpendLimitMicros, @@ -2362,9 +2362,9 @@ const deleteUserAIBudgetOverride = `-- name: DeleteUserAIBudgetOverride :one DELETE FROM user_ai_budget_overrides WHERE user_id = $1 RETURNING user_id, group_id, spend_limit_micros, created_at, updated_at ` -func (q *sqlQuerier) DeleteUserAIBudgetOverride(ctx context.Context, userID uuid.UUID) (UserAiBudgetOverride, error) { +func (q *sqlQuerier) DeleteUserAIBudgetOverride(ctx context.Context, userID uuid.UUID) (UserAIBudgetOverride, error) { row := q.db.QueryRowContext(ctx, deleteUserAIBudgetOverride, userID) - var i UserAiBudgetOverride + var i UserAIBudgetOverride err := row.Scan( &i.UserID, &i.GroupID, @@ -2386,9 +2386,9 @@ type GetAIModelPriceByProviderModelParams struct { Model string `db:"model" json:"model"` } -func (q *sqlQuerier) GetAIModelPriceByProviderModel(ctx context.Context, arg GetAIModelPriceByProviderModelParams) (AiModelPrice, error) { +func (q *sqlQuerier) GetAIModelPriceByProviderModel(ctx context.Context, arg GetAIModelPriceByProviderModelParams) (AIModelPrice, error) { row := q.db.QueryRowContext(ctx, getAIModelPriceByProviderModel, arg.Provider, arg.Model) - var i AiModelPrice + var i AIModelPrice err := row.Scan( &i.Provider, &i.Model, @@ -2408,9 +2408,9 @@ FROM group_ai_budgets WHERE group_id = $1 ` -func (q *sqlQuerier) GetGroupAIBudget(ctx context.Context, groupID uuid.UUID) (GroupAiBudget, error) { +func (q *sqlQuerier) GetGroupAIBudget(ctx context.Context, groupID uuid.UUID) (GroupAIBudget, error) { row := q.db.QueryRowContext(ctx, getGroupAIBudget, groupID) - var i GroupAiBudget + var i GroupAIBudget err := row.Scan( &i.GroupID, &i.SpendLimitMicros, @@ -2461,9 +2461,9 @@ FROM user_ai_budget_overrides WHERE user_id = $1 ` -func (q *sqlQuerier) GetUserAIBudgetOverride(ctx context.Context, userID uuid.UUID) (UserAiBudgetOverride, error) { +func (q *sqlQuerier) GetUserAIBudgetOverride(ctx context.Context, userID uuid.UUID) (UserAIBudgetOverride, error) { row := q.db.QueryRowContext(ctx, getUserAIBudgetOverride, userID) - var i UserAiBudgetOverride + var i UserAIBudgetOverride err := row.Scan( &i.UserID, &i.GroupID, @@ -2516,9 +2516,9 @@ type UpsertGroupAIBudgetParams struct { SpendLimitMicros int64 `db:"spend_limit_micros" json:"spend_limit_micros"` } -func (q *sqlQuerier) UpsertGroupAIBudget(ctx context.Context, arg UpsertGroupAIBudgetParams) (GroupAiBudget, error) { +func (q *sqlQuerier) UpsertGroupAIBudget(ctx context.Context, arg UpsertGroupAIBudgetParams) (GroupAIBudget, error) { row := q.db.QueryRowContext(ctx, upsertGroupAIBudget, arg.GroupID, arg.SpendLimitMicros) - var i GroupAiBudget + var i GroupAIBudget err := row.Scan( &i.GroupID, &i.SpendLimitMicros, @@ -2544,9 +2544,9 @@ type UpsertUserAIBudgetOverrideParams struct { SpendLimitMicros int64 `db:"spend_limit_micros" json:"spend_limit_micros"` } -func (q *sqlQuerier) UpsertUserAIBudgetOverride(ctx context.Context, arg UpsertUserAIBudgetOverrideParams) (UserAiBudgetOverride, error) { +func (q *sqlQuerier) UpsertUserAIBudgetOverride(ctx context.Context, arg UpsertUserAIBudgetOverrideParams) (UserAIBudgetOverride, error) { row := q.db.QueryRowContext(ctx, upsertUserAIBudgetOverride, arg.UserID, arg.GroupID, arg.SpendLimitMicros) - var i UserAiBudgetOverride + var i UserAIBudgetOverride err := row.Scan( &i.UserID, &i.GroupID, @@ -2604,7 +2604,7 @@ RETURNING type UpsertAISeatStateParams struct { UserID uuid.UUID `db:"user_id" json:"user_id"` FirstUsedAt time.Time `db:"first_used_at" json:"first_used_at"` - LastEventType AiSeatUsageReason `db:"last_event_type" json:"last_event_type"` + LastEventType AISeatUsageReason `db:"last_event_type" json:"last_event_type"` LastEventDescription string `db:"last_event_description" json:"last_event_description"` } @@ -28593,9 +28593,9 @@ type GetUserAIProviderKeyByProviderIDParams struct { AIProviderID uuid.UUID `db:"ai_provider_id" json:"ai_provider_id"` } -func (q *sqlQuerier) GetUserAIProviderKeyByProviderID(ctx context.Context, arg GetUserAIProviderKeyByProviderIDParams) (UserAiProviderKey, error) { +func (q *sqlQuerier) GetUserAIProviderKeyByProviderID(ctx context.Context, arg GetUserAIProviderKeyByProviderIDParams) (UserAIProviderKey, error) { row := q.db.QueryRowContext(ctx, getUserAIProviderKeyByProviderID, arg.UserID, arg.AIProviderID) - var i UserAiProviderKey + var i UserAIProviderKey err := row.Scan( &i.ID, &i.UserID, @@ -28622,15 +28622,15 @@ ORDER BY // GetUserAIProviderKeys is used by dbcrypt key rotation. Request paths should use // user-scoped lookups instead of this bulk accessor. -func (q *sqlQuerier) GetUserAIProviderKeys(ctx context.Context) ([]UserAiProviderKey, error) { +func (q *sqlQuerier) GetUserAIProviderKeys(ctx context.Context) ([]UserAIProviderKey, error) { rows, err := q.db.QueryContext(ctx, getUserAIProviderKeys) if err != nil { return nil, err } defer rows.Close() - var items []UserAiProviderKey + var items []UserAIProviderKey for rows.Next() { - var i UserAiProviderKey + var i UserAIProviderKey if err := rows.Scan( &i.ID, &i.UserID, @@ -28666,15 +28666,15 @@ ORDER BY id ASC ` -func (q *sqlQuerier) GetUserAIProviderKeysByUserID(ctx context.Context, userID uuid.UUID) ([]UserAiProviderKey, error) { +func (q *sqlQuerier) GetUserAIProviderKeysByUserID(ctx context.Context, userID uuid.UUID) ([]UserAIProviderKey, error) { rows, err := q.db.QueryContext(ctx, getUserAIProviderKeysByUserID, userID) if err != nil { return nil, err } defer rows.Close() - var items []UserAiProviderKey + var items []UserAIProviderKey for rows.Next() { - var i UserAiProviderKey + var i UserAIProviderKey if err := rows.Scan( &i.ID, &i.UserID, @@ -28716,9 +28716,9 @@ type UpdateEncryptedUserAIProviderKeyParams struct { ID uuid.UUID `db:"id" json:"id"` } -func (q *sqlQuerier) UpdateEncryptedUserAIProviderKey(ctx context.Context, arg UpdateEncryptedUserAIProviderKeyParams) (UserAiProviderKey, error) { +func (q *sqlQuerier) UpdateEncryptedUserAIProviderKey(ctx context.Context, arg UpdateEncryptedUserAIProviderKeyParams) (UserAIProviderKey, error) { row := q.db.QueryRowContext(ctx, updateEncryptedUserAIProviderKey, arg.APIKey, arg.ApiKeyKeyID, arg.ID) - var i UserAiProviderKey + var i UserAIProviderKey err := row.Scan( &i.ID, &i.UserID, @@ -28752,14 +28752,14 @@ type UpdateUserAIProviderKeyParams struct { AIProviderID uuid.UUID `db:"ai_provider_id" json:"ai_provider_id"` } -func (q *sqlQuerier) UpdateUserAIProviderKey(ctx context.Context, arg UpdateUserAIProviderKeyParams) (UserAiProviderKey, error) { +func (q *sqlQuerier) UpdateUserAIProviderKey(ctx context.Context, arg UpdateUserAIProviderKeyParams) (UserAIProviderKey, error) { row := q.db.QueryRowContext(ctx, updateUserAIProviderKey, arg.APIKey, arg.ApiKeyKeyID, arg.UserID, arg.AIProviderID, ) - var i UserAiProviderKey + var i UserAIProviderKey err := row.Scan( &i.ID, &i.UserID, @@ -28812,7 +28812,7 @@ type UpsertUserAIProviderKeyParams struct { // UpsertUserAIProviderKey preserves the original id and created_at when the // user/provider pair already exists. On conflict, callers provide id and // created_at for the insert path only. -func (q *sqlQuerier) UpsertUserAIProviderKey(ctx context.Context, arg UpsertUserAIProviderKeyParams) (UserAiProviderKey, error) { +func (q *sqlQuerier) UpsertUserAIProviderKey(ctx context.Context, arg UpsertUserAIProviderKeyParams) (UserAIProviderKey, error) { row := q.db.QueryRowContext(ctx, upsertUserAIProviderKey, arg.ID, arg.UserID, @@ -28822,7 +28822,7 @@ func (q *sqlQuerier) UpsertUserAIProviderKey(ctx context.Context, arg UpsertUser arg.CreatedAt, arg.UpdatedAt, ) - var i UserAiProviderKey + var i UserAIProviderKey err := row.Scan( &i.ID, &i.UserID, diff --git a/coderd/database/sqlc.yaml b/coderd/database/sqlc.yaml index 78448df9de..3a72a147ef 100644 --- a/coderd/database/sqlc.yaml +++ b/coderd/database/sqlc.yaml @@ -27,6 +27,11 @@ sql: emit_db_tags: true emit_enum_valid_method: true emit_all_enum_values: true + initialisms: + # Keep the sqlc default initialism and add AI so generated + # identifiers follow Go naming conventions. + - id + - ai overrides: - column: "api_keys.scopes" go_type: diff --git a/coderd/database/unique_constraint.go b/coderd/database/unique_constraint.go index dd46294cfa..8bae44cfd4 100644 --- a/coderd/database/unique_constraint.go +++ b/coderd/database/unique_constraint.go @@ -7,11 +7,11 @@ type UniqueConstraint string // UniqueConstraint enums. const ( UniqueAgentStatsPkey UniqueConstraint = "agent_stats_pkey" // ALTER TABLE ONLY workspace_agent_stats ADD CONSTRAINT agent_stats_pkey PRIMARY KEY (id); - UniqueAiGatewayKeysPkey UniqueConstraint = "ai_gateway_keys_pkey" // ALTER TABLE ONLY ai_gateway_keys ADD CONSTRAINT ai_gateway_keys_pkey PRIMARY KEY (id); - UniqueAiModelPricesPkey UniqueConstraint = "ai_model_prices_pkey" // ALTER TABLE ONLY ai_model_prices ADD CONSTRAINT ai_model_prices_pkey PRIMARY KEY (provider, model); - UniqueAiProviderKeysPkey UniqueConstraint = "ai_provider_keys_pkey" // ALTER TABLE ONLY ai_provider_keys ADD CONSTRAINT ai_provider_keys_pkey PRIMARY KEY (id); - UniqueAiProvidersPkey UniqueConstraint = "ai_providers_pkey" // ALTER TABLE ONLY ai_providers ADD CONSTRAINT ai_providers_pkey PRIMARY KEY (id); - UniqueAiSeatStatePkey UniqueConstraint = "ai_seat_state_pkey" // ALTER TABLE ONLY ai_seat_state ADD CONSTRAINT ai_seat_state_pkey PRIMARY KEY (user_id); + UniqueAIGatewayKeysPkey UniqueConstraint = "ai_gateway_keys_pkey" // ALTER TABLE ONLY ai_gateway_keys ADD CONSTRAINT ai_gateway_keys_pkey PRIMARY KEY (id); + UniqueAIModelPricesPkey UniqueConstraint = "ai_model_prices_pkey" // ALTER TABLE ONLY ai_model_prices ADD CONSTRAINT ai_model_prices_pkey PRIMARY KEY (provider, model); + UniqueAIProviderKeysPkey UniqueConstraint = "ai_provider_keys_pkey" // ALTER TABLE ONLY ai_provider_keys ADD CONSTRAINT ai_provider_keys_pkey PRIMARY KEY (id); + UniqueAIProvidersPkey UniqueConstraint = "ai_providers_pkey" // ALTER TABLE ONLY ai_providers ADD CONSTRAINT ai_providers_pkey PRIMARY KEY (id); + UniqueAISeatStatePkey UniqueConstraint = "ai_seat_state_pkey" // ALTER TABLE ONLY ai_seat_state ADD CONSTRAINT ai_seat_state_pkey PRIMARY KEY (user_id); UniqueAibridgeInterceptionsPkey UniqueConstraint = "aibridge_interceptions_pkey" // ALTER TABLE ONLY aibridge_interceptions ADD CONSTRAINT aibridge_interceptions_pkey PRIMARY KEY (id); UniqueAibridgeTokenUsagesPkey UniqueConstraint = "aibridge_token_usages_pkey" // ALTER TABLE ONLY aibridge_token_usages ADD CONSTRAINT aibridge_token_usages_pkey PRIMARY KEY (id); UniqueAibridgeToolUsagesPkey UniqueConstraint = "aibridge_tool_usages_pkey" // ALTER TABLE ONLY aibridge_tool_usages ADD CONSTRAINT aibridge_tool_usages_pkey PRIMARY KEY (id); @@ -43,7 +43,7 @@ const ( UniqueFilesPkey UniqueConstraint = "files_pkey" // ALTER TABLE ONLY files ADD CONSTRAINT files_pkey PRIMARY KEY (id); UniqueGitAuthLinksProviderIDUserIDKey UniqueConstraint = "git_auth_links_provider_id_user_id_key" // ALTER TABLE ONLY external_auth_links ADD CONSTRAINT git_auth_links_provider_id_user_id_key UNIQUE (provider_id, user_id); UniqueGitSSHKeysPkey UniqueConstraint = "gitsshkeys_pkey" // ALTER TABLE ONLY gitsshkeys ADD CONSTRAINT gitsshkeys_pkey PRIMARY KEY (user_id); - UniqueGroupAiBudgetsPkey UniqueConstraint = "group_ai_budgets_pkey" // ALTER TABLE ONLY group_ai_budgets ADD CONSTRAINT group_ai_budgets_pkey PRIMARY KEY (group_id); + UniqueGroupAIBudgetsPkey UniqueConstraint = "group_ai_budgets_pkey" // ALTER TABLE ONLY group_ai_budgets ADD CONSTRAINT group_ai_budgets_pkey PRIMARY KEY (group_id); UniqueGroupMembersUserIDGroupIDKey UniqueConstraint = "group_members_user_id_group_id_key" // ALTER TABLE ONLY group_members ADD CONSTRAINT group_members_user_id_group_id_key UNIQUE (user_id, group_id); UniqueGroupsNameOrganizationIDKey UniqueConstraint = "groups_name_organization_id_key" // ALTER TABLE ONLY groups ADD CONSTRAINT groups_name_organization_id_key UNIQUE (name, organization_id); UniqueGroupsPkey UniqueConstraint = "groups_pkey" // ALTER TABLE ONLY groups ADD CONSTRAINT groups_pkey PRIMARY KEY (id); @@ -99,9 +99,9 @@ const ( UniqueTemplatesPkey UniqueConstraint = "templates_pkey" // ALTER TABLE ONLY templates ADD CONSTRAINT templates_pkey PRIMARY KEY (id); UniqueUsageEventsDailyPkey UniqueConstraint = "usage_events_daily_pkey" // ALTER TABLE ONLY usage_events_daily ADD CONSTRAINT usage_events_daily_pkey PRIMARY KEY (day, event_type); UniqueUsageEventsPkey UniqueConstraint = "usage_events_pkey" // ALTER TABLE ONLY usage_events ADD CONSTRAINT usage_events_pkey PRIMARY KEY (id); - UniqueUserAiBudgetOverridesPkey UniqueConstraint = "user_ai_budget_overrides_pkey" // ALTER TABLE ONLY user_ai_budget_overrides ADD CONSTRAINT user_ai_budget_overrides_pkey PRIMARY KEY (user_id); - UniqueUserAiProviderKeysPkey UniqueConstraint = "user_ai_provider_keys_pkey" // ALTER TABLE ONLY user_ai_provider_keys ADD CONSTRAINT user_ai_provider_keys_pkey PRIMARY KEY (id); - UniqueUserAiProviderKeysUserIDAiProviderIDKey UniqueConstraint = "user_ai_provider_keys_user_id_ai_provider_id_key" // ALTER TABLE ONLY user_ai_provider_keys ADD CONSTRAINT user_ai_provider_keys_user_id_ai_provider_id_key UNIQUE (user_id, ai_provider_id); + UniqueUserAIBudgetOverridesPkey UniqueConstraint = "user_ai_budget_overrides_pkey" // ALTER TABLE ONLY user_ai_budget_overrides ADD CONSTRAINT user_ai_budget_overrides_pkey PRIMARY KEY (user_id); + UniqueUserAIProviderKeysPkey UniqueConstraint = "user_ai_provider_keys_pkey" // ALTER TABLE ONLY user_ai_provider_keys ADD CONSTRAINT user_ai_provider_keys_pkey PRIMARY KEY (id); + UniqueUserAIProviderKeysUserIDAIProviderIDKey UniqueConstraint = "user_ai_provider_keys_user_id_ai_provider_id_key" // ALTER TABLE ONLY user_ai_provider_keys ADD CONSTRAINT user_ai_provider_keys_user_id_ai_provider_id_key UNIQUE (user_id, ai_provider_id); UniqueUserConfigsPkey UniqueConstraint = "user_configs_pkey" // ALTER TABLE ONLY user_configs ADD CONSTRAINT user_configs_pkey PRIMARY KEY (user_id, key); UniqueUserDeletedPkey UniqueConstraint = "user_deleted_pkey" // ALTER TABLE ONLY user_deleted ADD CONSTRAINT user_deleted_pkey PRIMARY KEY (id); UniqueUserLinksPkey UniqueConstraint = "user_links_pkey" // ALTER TABLE ONLY user_links ADD CONSTRAINT user_links_pkey PRIMARY KEY (user_id, login_type); @@ -139,10 +139,10 @@ const ( UniqueWorkspaceResourceMetadataPkey UniqueConstraint = "workspace_resource_metadata_pkey" // ALTER TABLE ONLY workspace_resource_metadata ADD CONSTRAINT workspace_resource_metadata_pkey PRIMARY KEY (id); UniqueWorkspaceResourcesPkey UniqueConstraint = "workspace_resources_pkey" // ALTER TABLE ONLY workspace_resources ADD CONSTRAINT workspace_resources_pkey PRIMARY KEY (id); UniqueWorkspacesPkey UniqueConstraint = "workspaces_pkey" // ALTER TABLE ONLY workspaces ADD CONSTRAINT workspaces_pkey PRIMARY KEY (id); - UniqueAiGatewayKeysHashedSecretIndex UniqueConstraint = "ai_gateway_keys_hashed_secret_idx" // CREATE UNIQUE INDEX ai_gateway_keys_hashed_secret_idx ON ai_gateway_keys USING btree (hashed_secret); - UniqueAiGatewayKeysNameIndex UniqueConstraint = "ai_gateway_keys_name_idx" // CREATE UNIQUE INDEX ai_gateway_keys_name_idx ON ai_gateway_keys USING btree (lower(name)); - UniqueAiGatewayKeysSecretPrefixIndex UniqueConstraint = "ai_gateway_keys_secret_prefix_idx" // CREATE UNIQUE INDEX ai_gateway_keys_secret_prefix_idx ON ai_gateway_keys USING btree (secret_prefix); - UniqueAiProvidersNameUnique UniqueConstraint = "ai_providers_name_unique" // CREATE UNIQUE INDEX ai_providers_name_unique ON ai_providers USING btree (name) WHERE (deleted = false); + UniqueAIGatewayKeysHashedSecretIndex UniqueConstraint = "ai_gateway_keys_hashed_secret_idx" // CREATE UNIQUE INDEX ai_gateway_keys_hashed_secret_idx ON ai_gateway_keys USING btree (hashed_secret); + UniqueAIGatewayKeysNameIndex UniqueConstraint = "ai_gateway_keys_name_idx" // CREATE UNIQUE INDEX ai_gateway_keys_name_idx ON ai_gateway_keys USING btree (lower(name)); + UniqueAIGatewayKeysSecretPrefixIndex UniqueConstraint = "ai_gateway_keys_secret_prefix_idx" // CREATE UNIQUE INDEX ai_gateway_keys_secret_prefix_idx ON ai_gateway_keys USING btree (secret_prefix); + UniqueAIProvidersNameUnique UniqueConstraint = "ai_providers_name_unique" // CREATE UNIQUE INDEX ai_providers_name_unique ON ai_providers USING btree (name) WHERE (deleted = false); UniqueIndexAPIKeyName UniqueConstraint = "idx_api_key_name" // CREATE UNIQUE INDEX idx_api_key_name ON api_keys USING btree (user_id, token_name) WHERE (login_type = 'token'::login_type); UniqueIndexChatDebugRunsIDChat UniqueConstraint = "idx_chat_debug_runs_id_chat" // CREATE UNIQUE INDEX idx_chat_debug_runs_id_chat ON chat_debug_runs USING btree (id, chat_id); UniqueIndexChatDebugStepsRunStep UniqueConstraint = "idx_chat_debug_steps_run_step" // CREATE UNIQUE INDEX idx_chat_debug_steps_run_step ON chat_debug_steps USING btree (run_id, step_number); diff --git a/coderd/exp_chats_internal_test.go b/coderd/exp_chats_internal_test.go index 93d22bd7f4..51a55b4918 100644 --- a/coderd/exp_chats_internal_test.go +++ b/coderd/exp_chats_internal_test.go @@ -60,7 +60,7 @@ func TestValidateChatModelConfigProviderModel(t *testing.T) { model: "anthropic/claude-opus-4.6", provider: database.AIProvider{ Name: "openrouter", - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, }, wantErr: true, wantDetail: "Change the AI provider type to openrouter or openai-compat.", @@ -70,7 +70,7 @@ func TestValidateChatModelConfigProviderModel(t *testing.T) { model: "anthropic/claude-opus-4.6", provider: database.AIProvider{ Name: " OpenRouter ", - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, }, wantErr: true, wantDetail: "Change the AI provider type to openrouter or openai-compat.", @@ -80,7 +80,7 @@ func TestValidateChatModelConfigProviderModel(t *testing.T) { model: "anthropic/claude-opus-4.6", provider: database.AIProvider{ Name: "private-relay", - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, BaseUrl: "https://openrouter.ai/api/v1", }, wantErr: true, @@ -91,7 +91,7 @@ func TestValidateChatModelConfigProviderModel(t *testing.T) { model: "anthropic/claude-opus-4.6", provider: database.AIProvider{ Name: "private-relay", - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, BaseUrl: "https://openrouter.ai:443/api/v1", }, wantErr: true, @@ -102,7 +102,7 @@ func TestValidateChatModelConfigProviderModel(t *testing.T) { model: "anthropic/claude-opus-4.6", provider: database.AIProvider{ Name: "private-relay", - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, BaseUrl: "https://api.openrouter.ai/v1", }, wantErr: true, @@ -113,7 +113,7 @@ func TestValidateChatModelConfigProviderModel(t *testing.T) { model: "anthropic/claude-opus-4.6", provider: database.AIProvider{ Name: "openrouter", - Type: database.AiProviderTypeOpenrouter, + Type: database.AIProviderTypeOpenrouter, }, }, { @@ -121,7 +121,7 @@ func TestValidateChatModelConfigProviderModel(t *testing.T) { model: "anthropic/claude-opus-4.6", provider: database.AIProvider{ Name: "openrouter", - Type: database.AiProviderTypeOpenaiCompat, + Type: database.AIProviderTypeOpenaiCompat, }, }, { @@ -129,7 +129,7 @@ func TestValidateChatModelConfigProviderModel(t *testing.T) { model: "anthropic/claude-opus-4.6", provider: database.AIProvider{ Name: "private-relay", - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, BaseUrl: "https://llm-relay.internal/v1", }, }, @@ -138,7 +138,7 @@ func TestValidateChatModelConfigProviderModel(t *testing.T) { model: "gpt-4.1", provider: database.AIProvider{ Name: "openrouter", - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, }, }, } diff --git a/coderd/exp_chats_test.go b/coderd/exp_chats_test.go index b2540edb16..795c0fe262 100644 --- a/coderd/exp_chats_test.go +++ b/coderd/exp_chats_test.go @@ -1749,7 +1749,7 @@ func TestListChatModels(t *testing.T) { client := newChatClient(t) _ = coderdtest.CreateFirstUser(t, client.Client) - providerType := database.AiProviderTypeAnthropic + providerType := database.AIProviderTypeAnthropic provider := createAIProviderForTest(t, client, string(providerType), "") contextLimit := int64(4096) @@ -3997,7 +3997,7 @@ func TestUpdateChatModelConfig(t *testing.T) { require.NoError(t, err) modelConfig := dbgen.ChatModelConfig(t, db, database.ChatModelConfig{ - Provider: string(database.AiProviderTypeOpenai), + Provider: string(database.AIProviderTypeOpenai), Model: "anthropic/claude-opus-4.6", AIProviderID: uuid.NullUUID{UUID: aiProvider.ID, Valid: true}, }) diff --git a/coderd/workspaceagents_chat_context_internal_test.go b/coderd/workspaceagents_chat_context_internal_test.go index cf3811d64b..8a8d126b65 100644 --- a/coderd/workspaceagents_chat_context_internal_test.go +++ b/coderd/workspaceagents_chat_context_internal_test.go @@ -98,7 +98,7 @@ func insertAgentChatTestModelConfig( createdBy := uuid.NullUUID{UUID: userID, Valid: true} provider := dbgen.AIProvider(t, db, database.AIProvider{ - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, Name: "test-openai", DisplayName: sql.NullString{String: "OpenAI", Valid: true}, }) diff --git a/coderd/x/chatd/advisor_internal_test.go b/coderd/x/chatd/advisor_internal_test.go index e8b9dc1841..e76c287787 100644 --- a/coderd/x/chatd/advisor_internal_test.go +++ b/coderd/x/chatd/advisor_internal_test.go @@ -294,7 +294,7 @@ func TestResolveAdvisorModelOverride(t *testing.T) { getAIProviders: func(context.Context, database.GetAIProvidersParams) ([]database.AIProvider, error) { return []database.AIProvider{{ ID: providerID, - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, Enabled: true, }}, nil }, @@ -385,7 +385,7 @@ func TestResolveAdvisorModelOverride(t *testing.T) { getAIProviderByID: func(context.Context, uuid.UUID) (database.AIProvider, error) { return database.AIProvider{ ID: providerID, - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, Enabled: true, }, nil }, @@ -434,7 +434,7 @@ func TestResolveAdvisorModelOverridePromotesAIBridgeErrors(t *testing.T) { }, nil }, getAIProviderByID: func(context.Context, uuid.UUID) (database.AIProvider, error) { - return database.AIProvider{ID: providerID, Type: database.AiProviderTypeOpenai, Name: "primary-openai", Enabled: true}, nil + return database.AIProvider{ID: providerID, Type: database.AIProviderTypeOpenai, Name: "primary-openai", Enabled: true}, nil }, getAIProviderKeysByProviderID: func(context.Context, uuid.UUID) ([]database.AIProviderKey, error) { return []database.AIProviderKey{{ProviderID: providerID, APIKey: "sk-selected"}}, nil diff --git a/coderd/x/chatd/chatd_chainmode_test.go b/coderd/x/chatd/chatd_chainmode_test.go index b81354d1fa..00af33e1fe 100644 --- a/coderd/x/chatd/chatd_chainmode_test.go +++ b/coderd/x/chatd/chatd_chainmode_test.go @@ -321,7 +321,7 @@ func seedAnthropicChatDependencies(t *testing.T, db database.Store, baseURL stri _ = testAPIKeyID(t, db, user.ID) org := dbgen.Organization(t, db, database.Organization{}) dbgen.OrganizationMember(t, db, database.OrganizationMember{UserID: user.ID, OrganizationID: org.ID}) - provider := dbgen.AIProvider(t, db, database.AIProvider{Type: database.AiProviderTypeAnthropic}, func(params *database.InsertAIProviderParams) { + provider := dbgen.AIProvider(t, db, database.AIProvider{Type: database.AIProviderTypeAnthropic}, func(params *database.InsertAIProviderParams) { params.BaseUrl = baseURL }) dbgen.AIProviderKey(t, db, database.AIProviderKey{ProviderID: provider.ID}) diff --git a/coderd/x/chatd/chatd_internal_test.go b/coderd/x/chatd/chatd_internal_test.go index 61864c2894..59cecf4c27 100644 --- a/coderd/x/chatd/chatd_internal_test.go +++ b/coderd/x/chatd/chatd_internal_test.go @@ -182,8 +182,8 @@ func TestResolveUserProviderAPIKeysAndProviderForProviderTypeProviderMatch(t *te providerID := uuid.New() db.EXPECT().GetAIProviders(gomock.Any(), database.GetAIProvidersParams{}).Return([]database.AIProvider{ - {ID: uuid.New(), Type: database.AiProviderTypeAnthropic, Enabled: true}, - {ID: providerID, Type: database.AiProviderTypeOpenai, Enabled: true}, + {ID: uuid.New(), Type: database.AIProviderTypeAnthropic, Enabled: true}, + {ID: providerID, Type: database.AIProviderTypeOpenai, Enabled: true}, }, nil) db.EXPECT().GetAIProviderKeysByProviderID(gomock.Any(), providerID).Return([]database.AIProviderKey{{ ProviderID: providerID, @@ -200,7 +200,7 @@ func TestResolveUserProviderAPIKeysAndProviderForProviderTypeProviderMatch(t *te require.Equal(t, "test-key", keys.APIKey(chattool.ComputerUseProviderOpenAI)) require.NotNil(t, aiProvider) require.Equal(t, providerID, aiProvider.ID) - require.Equal(t, database.AiProviderTypeOpenai, aiProvider.Type) + require.Equal(t, database.AIProviderTypeOpenai, aiProvider.Type) } func TestResolveModelRouteForProviderTypeAIGatewayRequiresProvider(t *testing.T) { @@ -864,7 +864,7 @@ func TestRegenerateChatTitle_PersistsAndBroadcasts(t *testing.T) { providerID := uuid.New() db.EXPECT().GetAIProviders(gomock.Any(), gomock.Any()).Return([]database.AIProvider{{ ID: providerID, - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, Enabled: true, BaseUrl: serverURL, }}, nil) @@ -1030,7 +1030,7 @@ func TestRegenerateChatTitle_PersistsAndBroadcasts_IdleChatReleasesManualLock(t providerID := uuid.New() db.EXPECT().GetAIProviders(gomock.Any(), gomock.Any()).Return([]database.AIProvider{{ ID: providerID, - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, Enabled: true, BaseUrl: serverURL, }}, nil) @@ -1181,7 +1181,7 @@ func TestResolveUserProviderAPIKeys_StripsDisabledFallbackKeys(t *testing.T) { providerID := uuid.New() db.EXPECT().GetAIProviders(gomock.Any(), gomock.Any()).Return([]database.AIProvider{{ ID: providerID, - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, Enabled: true, }}, nil) db.EXPECT().GetAIProviderKeysByProviderIDs(gomock.Any(), []uuid.UUID{providerID}).Return(nil, nil) @@ -1219,7 +1219,7 @@ func TestResolveUserProviderAPIKeys_SelectedAIProviderDoesNotUseDeploymentFallba db.EXPECT().GetAIProviderByID(gomock.Any(), providerID).Return(database.AIProvider{ ID: providerID, - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, Name: "agents-openai", Enabled: true, }, nil) @@ -1258,7 +1258,7 @@ func TestResolveUserProviderAPIKeys_SkipsUserKeyLookupWhenNoProviderAllowsUserKe providerID := uuid.New() db.EXPECT().GetAIProviders(gomock.Any(), gomock.Any()).Return([]database.AIProvider{{ ID: providerID, - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, Enabled: true, }}, nil) db.EXPECT().GetAIProviderKeysByProviderIDs(gomock.Any(), []uuid.UUID{providerID}).Return(nil, nil) diff --git a/coderd/x/chatd/chatd_test.go b/coderd/x/chatd/chatd_test.go index 5422565998..771a252369 100644 --- a/coderd/x/chatd/chatd_test.go +++ b/coderd/x/chatd/chatd_test.go @@ -8698,7 +8698,7 @@ func setOpenAIProviderBaseURL( providers, err := db.GetAIProviders(ctx, database.GetAIProvidersParams{IncludeDisabled: true}) require.NoError(t, err) for _, provider := range providers { - if provider.Type != database.AiProviderTypeOpenai { + if provider.Type != database.AIProviderTypeOpenai { continue } _, err = db.UpdateAIProvider(ctx, database.UpdateAIProviderParams{ @@ -9785,12 +9785,12 @@ func seedAIGatewayOpenAITestDependencies( OrganizationID: org.ID, }) provider := dbgen.AIProvider(t, db, database.AIProvider{ - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, Name: "primary-openai-" + uuid.NewString(), BaseUrl: openAIURL, }) model := dbgen.ChatModelConfig(t, db, database.ChatModelConfig{ - Provider: string(database.AiProviderTypeOpenai), + Provider: string(database.AIProviderTypeOpenai), Model: "gpt-4o-mini", IsDefault: true, AIProviderID: uuid.NullUUID{UUID: provider.ID, Valid: true}, diff --git a/coderd/x/chatd/generation_preparer_internal_test.go b/coderd/x/chatd/generation_preparer_internal_test.go index c3c5ed0b7f..c5fe09bd4c 100644 --- a/coderd/x/chatd/generation_preparer_internal_test.go +++ b/coderd/x/chatd/generation_preparer_internal_test.go @@ -231,7 +231,7 @@ func TestDeriveFinalTurnRunResult(t *testing.T) { }) // A disabled AI provider makes resolveChatModel fail, exercising the // degraded path that still returns the re-derived text and IDs. - provider := insertInternalAIProvider(t, db, database.AiProviderTypeOpenai, "provider-api-key", false) + provider := insertInternalAIProvider(t, db, database.AIProviderTypeOpenai, "provider-api-key", false) modelCfg := dbgen.ChatModelConfig(t, db, database.ChatModelConfig{ Provider: "openai", Model: "gpt-4o-mini", diff --git a/coderd/x/chatd/model_routing_aibridge.go b/coderd/x/chatd/model_routing_aibridge.go index a732da1a95..832cd31a6e 100644 --- a/coderd/x/chatd/model_routing_aibridge.go +++ b/coderd/x/chatd/model_routing_aibridge.go @@ -91,7 +91,7 @@ func (t *aiGatewayRoundTripper) RoundTrip(req *http.Request) (*http.Response, er // OpenRouter-like providers typed as openai, where the provider type // strips the vendor prefix. func ValidateAIGatewayProviderModel(provider database.AIProvider, model string) error { - if provider.Type != database.AiProviderTypeOpenai { + if provider.Type != database.AIProviderTypeOpenai { return nil } if !isSlashNamespacedAIGatewayModel(model) || !isOpenRouterLikeAIGatewayProvider(provider) { @@ -188,10 +188,10 @@ func fantasyConfigForAIBridge(providerType database.AIProviderType) aibridgeFant var fantasyProvider string baseURL := aibridgeLocalBaseURL + "/v1" switch providerType { - case database.AiProviderTypeAnthropic, database.AiProviderTypeBedrock: + case database.AIProviderTypeAnthropic, database.AIProviderTypeBedrock: fantasyProvider = fantasyanthropic.Name baseURL = aibridgeLocalBaseURL - case database.AiProviderTypeOpenai: + case database.AIProviderTypeOpenai: fantasyProvider = fantasyopenai.Name default: fantasyProvider = fantasyopenaicompat.Name @@ -211,7 +211,7 @@ func fantasyConfigForAIBridge(providerType database.AIProviderType) aibridgeFant func aiGatewayRequestFormatForProviderType(providerType database.AIProviderType) aiGatewayRequestFormat { switch providerType { - case database.AiProviderTypeAnthropic, database.AiProviderTypeBedrock: + case database.AIProviderTypeAnthropic, database.AIProviderTypeBedrock: return aiGatewayRequestFormatAnthropic default: return aiGatewayRequestFormatOpenAI diff --git a/coderd/x/chatd/model_routing_internal_test.go b/coderd/x/chatd/model_routing_internal_test.go index 76ede361de..b33aadb4c6 100644 --- a/coderd/x/chatd/model_routing_internal_test.go +++ b/coderd/x/chatd/model_routing_internal_test.go @@ -85,10 +85,10 @@ func TestAIBridgeProviderFormatMapping(t *testing.T) { wantProvider string wantBaseURL string }{ - {name: "OpenAI", providerType: database.AiProviderTypeOpenai, wantProvider: "openai", wantBaseURL: "http://coder-aibridge/v1"}, - {name: "Anthropic", providerType: database.AiProviderTypeAnthropic, wantProvider: "anthropic", wantBaseURL: "http://coder-aibridge"}, - {name: "Bedrock", providerType: database.AiProviderTypeBedrock, wantProvider: "anthropic", wantBaseURL: "http://coder-aibridge"}, - {name: "Google", providerType: database.AiProviderTypeGoogle, wantProvider: "openai-compat", wantBaseURL: "http://coder-aibridge/v1"}, + {name: "OpenAI", providerType: database.AIProviderTypeOpenai, wantProvider: "openai", wantBaseURL: "http://coder-aibridge/v1"}, + {name: "Anthropic", providerType: database.AIProviderTypeAnthropic, wantProvider: "anthropic", wantBaseURL: "http://coder-aibridge"}, + {name: "Bedrock", providerType: database.AIProviderTypeBedrock, wantProvider: "anthropic", wantBaseURL: "http://coder-aibridge"}, + {name: "Google", providerType: database.AIProviderTypeGoogle, wantProvider: "openai-compat", wantBaseURL: "http://coder-aibridge/v1"}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -113,7 +113,7 @@ func TestResolveModelRouteForConfigPreservesBaseURL(t *testing.T) { db.EXPECT().GetAIProviderByID(gomock.Any(), providerID).Return(database.AIProvider{ ID: providerID, - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, Name: "primary-openai", Enabled: true, BaseUrl: baseURL, @@ -141,7 +141,7 @@ func TestAIGatewayProviderAuthForUser(t *testing.T) { ctx := t.Context() ownerID := uuid.New() providerID := uuid.New() - provider := database.AIProvider{ID: providerID, Type: database.AiProviderTypeOpenai, Enabled: true} + provider := database.AIProvider{ID: providerID, Type: database.AIProviderTypeOpenai, Enabled: true} t.Run("OpenAIUserKey", func(t *testing.T) { t.Parallel() @@ -151,7 +151,7 @@ func TestAIGatewayProviderAuthForUser(t *testing.T) { db.EXPECT().GetUserAIProviderKeyByProviderID(gomock.Any(), database.GetUserAIProviderKeyByProviderIDParams{ UserID: ownerID, AIProviderID: providerID, - }).Return(database.UserAiProviderKey{APIKey: "sk-user"}, nil) + }).Return(database.UserAIProviderKey{APIKey: "sk-user"}, nil) server := &Server{db: db, allowBYOK: true} auth, err := server.aiGatewayProviderAuthForUser(ctx, ownerID, provider, aiGatewayRequestFormatOpenAI) @@ -168,7 +168,7 @@ func TestAIGatewayProviderAuthForUser(t *testing.T) { db.EXPECT().GetUserAIProviderKeyByProviderID(gomock.Any(), database.GetUserAIProviderKeyByProviderIDParams{ UserID: ownerID, AIProviderID: providerID, - }).Return(database.UserAiProviderKey{APIKey: "sk-user"}, nil) + }).Return(database.UserAIProviderKey{APIKey: "sk-user"}, nil) server := &Server{db: db, allowBYOK: true} auth, err := server.aiGatewayProviderAuthForUser(ctx, ownerID, provider, aiGatewayRequestFormatAnthropic) @@ -185,7 +185,7 @@ func TestAIGatewayProviderAuthForUser(t *testing.T) { db.EXPECT().GetUserAIProviderKeyByProviderID(gomock.Any(), database.GetUserAIProviderKeyByProviderIDParams{ UserID: ownerID, AIProviderID: providerID, - }).Return(database.UserAiProviderKey{}, sql.ErrNoRows) + }).Return(database.UserAIProviderKey{}, sql.ErrNoRows) server := &Server{db: db, allowBYOK: true} auth, err := server.aiGatewayProviderAuthForUser(ctx, ownerID, provider, aiGatewayRequestFormatOpenAI) @@ -231,7 +231,7 @@ func TestResolveModelRouteForConfigAIGatewayProviderAuth(t *testing.T) { providerID := uuid.New() provider := database.AIProvider{ ID: providerID, - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, Name: "primary-openai", Enabled: true, } @@ -251,7 +251,7 @@ func TestResolveModelRouteForConfigAIGatewayProviderAuth(t *testing.T) { db.EXPECT().GetUserAIProviderKeyByProviderID(gomock.Any(), database.GetUserAIProviderKeyByProviderIDParams{ UserID: ownerID, AIProviderID: providerID, - }).Return(database.UserAiProviderKey{APIKey: "sk-user"}, nil) + }).Return(database.UserAIProviderKey{APIKey: "sk-user"}, nil) server := &Server{db: db, aiGatewayRoutingEnabled: true, allowBYOK: true} route, err := server.resolveModelRouteForConfig(ctx, ownerID, modelConfig, chatprovider.ProviderAPIKeys{}) @@ -296,7 +296,7 @@ func TestAIGatewayModelForwardsProviderAuth(t *testing.T) { path: req.URL.Path, } body := `{"id":"resp_test","object":"response","created_at":0,"status":"completed","model":"gpt-4","output":[{"id":"msg_test","type":"message","role":"assistant","content":[{"type":"output_text","text":"hello"}]}],"usage":{"input_tokens":1,"output_tokens":1,"total_tokens":2}}` - if provider.Type == database.AiProviderTypeAnthropic { + if provider.Type == database.AIProviderTypeAnthropic { body = `{"id":"msg_test","type":"message","role":"assistant","model":"claude-haiku-4-5","content":[{"type":"text","text":"hello"}],"stop_reason":"end_turn","stop_sequence":null,"usage":{"input_tokens":1,"output_tokens":1}}` } return &http.Response{ @@ -318,7 +318,7 @@ func TestAIGatewayModelForwardsProviderAuth(t *testing.T) { t.Parallel() seen := make(chan seenRequest, 1) - provider := aibridgeTestAIProvider(uuid.New(), "primary-openai", database.AiProviderTypeOpenai) + provider := aibridgeTestAIProvider(uuid.New(), "primary-openai", database.AIProviderTypeOpenai) server, route := newServer(t, provider, aiGatewayProviderAuth{ Headers: map[string]string{"Authorization": "Bearer sk-user"}, }, seen) @@ -340,7 +340,7 @@ func TestAIGatewayModelForwardsProviderAuth(t *testing.T) { t.Parallel() seen := make(chan seenRequest, 1) - provider := aibridgeTestAIProvider(uuid.New(), "primary-anthropic", database.AiProviderTypeAnthropic) + provider := aibridgeTestAIProvider(uuid.New(), "primary-anthropic", database.AIProviderTypeAnthropic) server, route := newServer(t, provider, aiGatewayProviderAuth{ Headers: map[string]string{"X-Api-Key": "sk-user"}, }, seen) @@ -361,7 +361,7 @@ func TestAIGatewayModelForwardsProviderAuth(t *testing.T) { t.Parallel() seen := make(chan seenRequest, 1) - provider := aibridgeTestAIProvider(uuid.New(), "primary-openai", database.AiProviderTypeOpenai) + provider := aibridgeTestAIProvider(uuid.New(), "primary-openai", database.AIProviderTypeOpenai) server, route := newServer(t, provider, aiGatewayProviderAuth{}, seen) apiKeyID := uuid.NewString() model, err := server.newModel(t.Context(), aibridgeTestRequest(database.Chat{ID: uuid.New(), OwnerID: uuid.New()}, "gpt-4"), route, modelBuildOptions{ActiveAPIKeyID: apiKeyID}) @@ -595,7 +595,7 @@ func TestAIBridgeRoutingFailClosed(t *testing.T) { providerID := uuid.New() chat := database.Chat{ID: uuid.New(), OwnerID: uuid.New()} - aiProvider := aibridgeTestAIProvider(providerID, "primary-openai", database.AiProviderTypeOpenai) + aiProvider := aibridgeTestAIProvider(providerID, "primary-openai", database.AIProviderTypeOpenai) t.Run("NilFactory", func(t *testing.T) { t.Parallel() @@ -618,7 +618,7 @@ func TestAIBridgeRoutingFailClosed(t *testing.T) { t.Run("MissingProviderName", func(t *testing.T) { t.Parallel() server := &Server{aiGatewayRoutingEnabled: true} - missingNameProvider := aibridgeTestAIProvider(providerID, "", database.AiProviderTypeOpenai) + missingNameProvider := aibridgeTestAIProvider(providerID, "", database.AIProviderTypeOpenai) _, err := server.newModel(t.Context(), aibridgeTestRequest(chat, "gpt-4"), aibridgeTestRoute(missingNameProvider), modelBuildOptions{ActiveAPIKeyID: uuid.NewString()}) require.ErrorContains(t, err, "AI provider name") }) @@ -652,7 +652,7 @@ func TestAIBridgeRoutingFailClosed(t *testing.T) { aiGatewayRoutingEnabled: true, aibridgeTransportFactory: aibridgeTestFactoryPointer(factory), } - provider := aibridgeTestAIProvider(providerID, "openrouter", database.AiProviderTypeOpenai) + provider := aibridgeTestAIProvider(providerID, "openrouter", database.AIProviderTypeOpenai) _, err := server.newModel( t.Context(), aibridgeTestRequest(chat, "anthropic/claude-opus-4.6"), @@ -685,12 +685,12 @@ func TestAIBridgeGatewayProviderTypesPreserveSlashModelID(t *testing.T) { { name: "OpenRouter", providerName: "openrouter", - providerType: database.AiProviderTypeOpenrouter, + providerType: database.AIProviderTypeOpenrouter, }, { name: "OpenAICompat", providerName: "openai-compatible-relay", - providerType: database.AiProviderTypeOpenaiCompat, + providerType: database.AIProviderTypeOpenaiCompat, }, } @@ -814,7 +814,7 @@ func TestAIBridgeComputerUseModelUsesRoute(t *testing.T) { model, debugEnabled, resolvedProvider, resolvedModel, err := server.resolveComputerUseModel( ctx, chat, - aibridgeTestRoute(aibridgeTestAIProvider(providerID, "primary-openai", database.AiProviderTypeOpenai)), + aibridgeTestRoute(aibridgeTestAIProvider(providerID, "primary-openai", database.AIProviderTypeOpenai)), provider, modelProvider, modelName, @@ -862,7 +862,7 @@ func TestAIBridgeDelegatedContextPropagation(t *testing.T) { } ctx := aibridge.WithDelegatedAPIKeyID(t.Context(), "context-key-must-be-ignored") - model, err := server.newModel(ctx, aibridgeTestRequest(chat, "gpt-4"), aibridgeTestRoute(aibridgeTestAIProvider(providerID, "primary-openai", database.AiProviderTypeOpenai)), modelBuildOptions{ActiveAPIKeyID: apiKeyID, RecordHTTP: true}) + model, err := server.newModel(ctx, aibridgeTestRequest(chat, "gpt-4"), aibridgeTestRoute(aibridgeTestAIProvider(providerID, "primary-openai", database.AIProviderTypeOpenai)), modelBuildOptions{ActiveAPIKeyID: apiKeyID, RecordHTTP: true}) require.NoError(t, err) _, err = model.Generate(t.Context(), fantasy.Call{Prompt: []fantasy.Message{{ Role: fantasy.MessageRoleUser, diff --git a/coderd/x/chatd/subagent_internal_test.go b/coderd/x/chatd/subagent_internal_test.go index f575fe2383..176c0d5d57 100644 --- a/coderd/x/chatd/subagent_internal_test.go +++ b/coderd/x/chatd/subagent_internal_test.go @@ -476,7 +476,7 @@ func TestResolveUserProviderAPIKeys_AIProvider(t *testing.T) { server := newInternalTestServer(t, db, ps, chatprovider.ProviderAPIKeys{}) ctx := chatdTestContext(t) user, _, _ := seedInternalChatDeps(t, db) - provider := insertInternalAIProvider(t, db, database.AiProviderTypeOpenai, "provider-api-key", true) + provider := insertInternalAIProvider(t, db, database.AIProviderTypeOpenai, "provider-api-key", true) now := time.Now() _, err := db.UpsertUserAIProviderKey(ctx, database.UpsertUserAIProviderKeyParams{ ID: uuid.New(), @@ -502,7 +502,7 @@ func TestResolveUserProviderAPIKeys_AIProvider(t *testing.T) { server.allowBYOK = false ctx := chatdTestContext(t) user, _, _ := seedInternalChatDeps(t, db) - provider := insertInternalAIProvider(t, db, database.AiProviderTypeOpenai, "provider-api-key", true) + provider := insertInternalAIProvider(t, db, database.AIProviderTypeOpenai, "provider-api-key", true) now := time.Now() _, err := db.UpsertUserAIProviderKey(ctx, database.UpsertUserAIProviderKeyParams{ ID: uuid.New(), @@ -526,7 +526,7 @@ func TestResolveUserProviderAPIKeys_AIProvider(t *testing.T) { server := newInternalTestServer(t, db, ps, chatprovider.ProviderAPIKeys{}) ctx := chatdTestContext(t) user, _, _ := seedInternalChatDeps(t, db) - insertInternalAIProvider(t, db, database.AiProviderTypeAzure, "provider-api-key", true) + insertInternalAIProvider(t, db, database.AIProviderTypeAzure, "provider-api-key", true) keys, err := server.resolveUserProviderAPIKeysForProviderType(ctx, user.ID, "azure") require.NoError(t, err) @@ -540,7 +540,7 @@ func TestResolveUserProviderAPIKeys_AIProvider(t *testing.T) { server := newInternalTestServer(t, db, ps, chatprovider.ProviderAPIKeys{}) ctx := chatdTestContext(t) user, _, _ := seedInternalChatDeps(t, db) - provider := insertInternalAIProvider(t, db, database.AiProviderTypeBedrock, "", true) + provider := insertInternalAIProvider(t, db, database.AIProviderTypeBedrock, "", true) keys, err := server.resolveUserProviderAPIKeys(ctx, user.ID, provider.ID) require.NoError(t, err) @@ -555,8 +555,8 @@ func TestResolveUserProviderAPIKeys_AIProvider(t *testing.T) { server := newInternalTestServer(t, db, ps, chatprovider.ProviderAPIKeys{}) ctx := chatdTestContext(t) user, _, _ := seedInternalChatDeps(t, db) - insertInternalAIProvider(t, db, database.AiProviderTypeOpenai, "first-provider-api-key", true) - insertInternalAIProvider(t, db, database.AiProviderTypeOpenai, "second-provider-api-key", true) + insertInternalAIProvider(t, db, database.AIProviderTypeOpenai, "first-provider-api-key", true) + insertInternalAIProvider(t, db, database.AIProviderTypeOpenai, "second-provider-api-key", true) keys, err := server.resolveUserProviderAPIKeys(ctx, user.ID, uuid.Nil) require.ErrorContains(t, err, "multiple enabled AI providers use provider type") @@ -570,7 +570,7 @@ func TestResolveChatModel_AIProviderDisabled(t *testing.T) { ctx := chatdTestContext(t) db, ps := dbtestutil.NewDB(t) user, org, _ := seedInternalChatDeps(t, db) - provider := insertInternalAIProvider(t, db, database.AiProviderTypeOpenai, "provider-api-key", false) + provider := insertInternalAIProvider(t, db, database.AIProviderTypeOpenai, "provider-api-key", false) modelConfig := dbgen.ChatModelConfig(t, db, database.ChatModelConfig{ Provider: "openai", Model: "gpt-4o-mini", diff --git a/coderd/x/chatd/title_override_internal_test.go b/coderd/x/chatd/title_override_internal_test.go index a6af913c46..4c2d49e9c4 100644 --- a/coderd/x/chatd/title_override_internal_test.go +++ b/coderd/x/chatd/title_override_internal_test.go @@ -253,7 +253,7 @@ func TestMaybeGenerateChatTitle_TitleGenerationOverrideSetUsable(t *testing.T) { }) provider := database.AIProvider{ ID: providerID, - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, Enabled: true, BaseUrl: serverURL, } @@ -365,7 +365,7 @@ func TestMaybeGenerateChatTitle_TitleGenerationOverrideCallFailureSkipsFallback( db.EXPECT().GetChatTitleGenerationModelOverride(gomock.Any()).Return(overrideConfig.ID.String(), nil) db.EXPECT().GetChatModelConfigByID(gomock.Any(), overrideConfig.ID).Return(overrideConfig, nil) - db.EXPECT().GetAIProviders(gomock.Any(), gomock.Any()).Return([]database.AIProvider{{Type: database.AiProviderTypeOpenai, Enabled: true}}, nil) + db.EXPECT().GetAIProviders(gomock.Any(), gomock.Any()).Return([]database.AIProvider{{Type: database.AIProviderTypeOpenai, Enabled: true}}, nil) db.EXPECT().GetAIProviderKeysByProviderIDs(gomock.Any(), []uuid.UUID{uuid.Nil}).Return(nil, nil) generated := &generatedChatTitle{} @@ -446,7 +446,7 @@ func TestResolveManualTitleModel_TitleGenerationOverrideUnsetAIProvider(t *testi }) provider := database.AIProvider{ ID: providerID, - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, Enabled: true, BaseUrl: serverURL, } @@ -521,7 +521,7 @@ func TestResolveManualTitleModel_TitleGenerationOverrideSetUsable(t *testing.T) db.EXPECT().GetChatTitleGenerationModelOverride(gomock.Any()).Return(overrideConfig.ID.String(), nil) db.EXPECT().GetChatModelConfigByID(gomock.Any(), overrideConfig.ID).Return(overrideConfig, nil) - db.EXPECT().GetAIProviders(gomock.Any(), gomock.Any()).Return([]database.AIProvider{{Type: database.AiProviderTypeOpenai, Enabled: true}}, nil) + db.EXPECT().GetAIProviders(gomock.Any(), gomock.Any()).Return([]database.AIProvider{{Type: database.AIProviderTypeOpenai, Enabled: true}}, nil) db.EXPECT().GetAIProviderKeysByProviderIDs(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes() server := titleOverrideTestServer(db, logger) @@ -549,7 +549,7 @@ func TestResolveManualTitleModel_TitleGenerationOverrideMissingCredentials(t *te db.EXPECT().GetChatTitleGenerationModelOverride(gomock.Any()).Return(overrideConfig.ID.String(), nil) db.EXPECT().GetChatModelConfigByID(gomock.Any(), overrideConfig.ID).Return(overrideConfig, nil) - db.EXPECT().GetAIProviders(gomock.Any(), gomock.Any()).Return([]database.AIProvider{{Type: database.AiProviderTypeOpenai, Enabled: true}}, nil) + db.EXPECT().GetAIProviders(gomock.Any(), gomock.Any()).Return([]database.AIProvider{{Type: database.AIProviderTypeOpenai, Enabled: true}}, nil) db.EXPECT().GetAIProviderKeysByProviderIDs(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes() server := titleOverrideTestServer(db, logger) @@ -619,7 +619,7 @@ func TestGenerateManualTitleCandidate_ActiveAPIKeyIDFallback(t *testing.T) { provider := database.AIProvider{ ID: providerID, Name: "primary-openai", - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, Enabled: true, } wantTitle := "Context title" diff --git a/docs/admin/security/audit-logs.md b/docs/admin/security/audit-logs.md index be57d1c762..a41fc4c9a5 100644 --- a/docs/admin/security/audit-logs.md +++ b/docs/admin/security/audit-logs.md @@ -18,13 +18,13 @@ We track the following resources: | AIGatewayKey
create, delete | |
FieldTracked
created_atfalse
hashed_secrettrue
idtrue
last_used_atfalse
nametrue
secret_prefixtrue
| | AIProvider
create, write, delete | |
FieldTracked
base_urltrue
created_atfalse
deletedtrue
display_nametrue
enabledtrue
idtrue
nametrue
settingstrue
settings_key_idfalse
typetrue
updated_atfalse
| | AIProviderKey
create, delete | |
FieldTracked
api_keytrue
api_key_key_idfalse
created_atfalse
idtrue
provider_idtrue
updated_atfalse
| +| AISeatState
create | |
FieldTracked
first_used_attrue
last_event_descriptiontrue
last_event_typetrue
last_used_atfalse
updated_atfalse
user_idtrue
| | APIKey
login, logout, register, create, write, delete | |
FieldTracked
allow_listfalse
created_attrue
expires_attrue
hashed_secretfalse
idfalse
ip_addressfalse
last_usedtrue
lifetime_secondsfalse
login_typefalse
scopesfalse
token_namefalse
updated_atfalse
user_idtrue
| -| AiSeatState
create | |
FieldTracked
first_used_attrue
last_event_descriptiontrue
last_event_typetrue
last_used_atfalse
updated_atfalse
user_idtrue
| | AuditOAuthConvertState
| |
FieldTracked
created_attrue
expires_attrue
from_login_typetrue
to_login_typetrue
user_idtrue
| | Group
create, write, delete | |
FieldTracked
avatar_urltrue
chat_spend_limit_microstrue
display_nametrue
idtrue
memberstrue
nametrue
organization_idfalse
quota_allowancetrue
sourcefalse
| -| AuditableGroupAiBudget
write, delete | |
FieldTracked
created_atfalse
group_idfalse
group_namefalse
spend_limittrue
spend_limit_microsfalse
updated_atfalse
| +| AuditableGroupAIBudget
write, delete | |
FieldTracked
created_atfalse
group_idfalse
group_namefalse
spend_limittrue
spend_limit_microsfalse
updated_atfalse
| | AuditableOrganizationMember
| |
FieldTracked
created_attrue
organization_idfalse
rolestrue
updated_attrue
user_idtrue
usernametrue
| -| AuditableUserAiBudgetOverride
write, delete | |
FieldTracked
created_atfalse
group_idtrue
group_nametrue
spend_limittrue
spend_limit_microsfalse
updated_atfalse
user_idfalse
usernamefalse
| +| AuditableUserAIBudgetOverride
write, delete | |
FieldTracked
created_atfalse
group_idtrue
group_nametrue
spend_limittrue
spend_limit_microsfalse
updated_atfalse
user_idfalse
usernamefalse
| | Chat
create, write | |
FieldTracked
agent_idfalse
archivedtrue
build_idfalse
client_typefalse
context_aggregate_hashfalse
context_dirty_resourcesfalse
context_dirty_sincefalse
context_errorfalse
created_atfalse
dynamic_toolsfalse
generation_attemptfalse
group_acltrue
heartbeat_atfalse
history_versionfalse
idtrue
labelstrue
last_errorfalse
last_injected_contextfalse
last_model_config_idfalse
last_read_message_idfalse
last_turn_summaryfalse
mcp_server_idstrue
modetrue
organization_idfalse
owner_idtrue
owner_namefalse
owner_usernamefalse
parent_chat_idfalse
pin_ordertrue
plan_modefalse
queue_versionfalse
requires_action_deadline_atfalse
retry_statefalse
retry_state_versionfalse
root_chat_idfalse
runner_idfalse
snapshot_versionfalse
started_atfalse
statusfalse
titletrue
updated_atfalse
user_acltrue
worker_idfalse
workspace_idtrue
| | CustomRole
| |
FieldTracked
created_atfalse
display_nametrue
idfalse
is_systemfalse
member_permissionstrue
nametrue
org_permissionstrue
organization_idfalse
site_permissionstrue
updated_atfalse
user_permissionstrue
| | GitSSHKey
create | |
FieldTracked
created_atfalse
private_keytrue
private_key_key_idfalse
public_keytrue
updated_atfalse
user_idtrue
| diff --git a/enterprise/aiseats/tracker.go b/enterprise/aiseats/tracker.go index 30cd8abfb5..f0baa5d09e 100644 --- a/enterprise/aiseats/tracker.go +++ b/enterprise/aiseats/tracker.go @@ -97,13 +97,13 @@ func (t *SeatTracker) RecordUsage(ctx context.Context, userID uuid.UUID, reason if auditor == nil || *auditor == nil { return } - audit.BackgroundAudit[database.AiSeatState](ctx, &audit.BackgroundAuditParams[database.AiSeatState]{ + audit.BackgroundAudit[database.AISeatState](ctx, &audit.BackgroundAuditParams[database.AISeatState]{ Audit: *auditor, Log: t.logger, UserID: userID, Time: now, Action: database.AuditActionCreate, - New: database.AiSeatState{ + New: database.AISeatState{ UserID: userID, FirstUsedAt: now, LastUsedAt: now, diff --git a/enterprise/aiseats/tracker_test.go b/enterprise/aiseats/tracker_test.go index 37e192cd4b..239f7bfe26 100644 --- a/enterprise/aiseats/tracker_test.go +++ b/enterprise/aiseats/tracker_test.go @@ -146,7 +146,7 @@ func TestSeatTrackerDB(t *testing.T) { require.EqualValues(t, 1, count) require.Len(t, a.AuditLogs(), 1) - require.Equal(t, database.ResourceTypeAiSeat, a.AuditLogs()[0].ResourceType) + require.Equal(t, database.ResourceTypeAISeat, a.AuditLogs()[0].ResourceType) }) // Provisionerd also calls RecordUsage via SeatTracker for diff --git a/enterprise/audit/diff_internal_test.go b/enterprise/audit/diff_internal_test.go index a96a5abe23..bca368d860 100644 --- a/enterprise/audit/diff_internal_test.go +++ b/enterprise/audit/diff_internal_test.go @@ -463,7 +463,7 @@ func Test_diff(t *testing.T) { name: "PropertyChange", left: database.AIProvider{ ID: uuid.UUID{1}, - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, Name: "primary-openai", DisplayName: sql.NullString{String: "Primary", Valid: true}, Enabled: true, @@ -471,7 +471,7 @@ func Test_diff(t *testing.T) { }, right: database.AIProvider{ ID: uuid.UUID{1}, - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, Name: "primary-openai", DisplayName: sql.NullString{String: "Renamed", Valid: true}, Enabled: false, diff --git a/enterprise/audit/table.go b/enterprise/audit/table.go index 23a9c4f44b..d509581b63 100644 --- a/enterprise/audit/table.go +++ b/enterprise/audit/table.go @@ -28,12 +28,12 @@ var AuditActionMap = map[string][]codersdk.AuditAction{ "APIKey": {codersdk.AuditActionLogin, codersdk.AuditActionLogout, codersdk.AuditActionRegister, codersdk.AuditActionCreate, codersdk.AuditActionWrite, codersdk.AuditActionDelete}, "License": {codersdk.AuditActionCreate, codersdk.AuditActionDelete}, "Task": {codersdk.AuditActionCreate, codersdk.AuditActionWrite, codersdk.AuditActionDelete}, - "AiSeatState": {codersdk.AuditActionCreate}, + "AISeatState": {codersdk.AuditActionCreate}, "AIProvider": {codersdk.AuditActionCreate, codersdk.AuditActionWrite, codersdk.AuditActionDelete}, "AIProviderKey": {codersdk.AuditActionCreate, codersdk.AuditActionDelete}, "AIGatewayKey": {codersdk.AuditActionCreate, codersdk.AuditActionDelete}, - "AuditableGroupAiBudget": {codersdk.AuditActionWrite, codersdk.AuditActionDelete}, - "AuditableUserAiBudgetOverride": {codersdk.AuditActionWrite, codersdk.AuditActionDelete}, + "AuditableGroupAIBudget": {codersdk.AuditActionWrite, codersdk.AuditActionDelete}, + "AuditableUserAIBudgetOverride": {codersdk.AuditActionWrite, codersdk.AuditActionDelete}, "Chat": {codersdk.AuditActionCreate, codersdk.AuditActionWrite}, // chats get 'archived' by users, not deleted. "UserSecret": {codersdk.AuditActionCreate, codersdk.AuditActionWrite, codersdk.AuditActionDelete}, "UserSkill": {codersdk.AuditActionCreate, codersdk.AuditActionWrite, codersdk.AuditActionDelete}, @@ -225,7 +225,7 @@ var auditableResourcesTypes = map[any]map[string]Action{ "source": ActionIgnore, "chat_spend_limit_micros": ActionTrack, }, - &database.AuditableGroupAiBudget{}: { + &database.AuditableGroupAIBudget{}: { "group_id": ActionIgnore, // Group name is already included in the title. "spend_limit_micros": ActionIgnore, "spend_limit": ActionTrack, // Track spend_limit, which is the human-readable version. @@ -233,7 +233,7 @@ var auditableResourcesTypes = map[any]map[string]Action{ "created_at": ActionIgnore, // Redundant with the audit log's own timestamp. "updated_at": ActionIgnore, // Redundant with the audit log's own timestamp. }, - &database.AuditableUserAiBudgetOverride{}: { + &database.AuditableUserAIBudgetOverride{}: { "user_id": ActionIgnore, // Username is already included in the title. "username": ActionIgnore, // Username is already included in the title. "group_id": ActionTrack, @@ -382,7 +382,7 @@ var auditableResourcesTypes = map[any]map[string]Action{ "field": ActionTrack, "mapping": ActionTrack, }, - &database.AiSeatState{}: { + &database.AISeatState{}: { "user_id": ActionTrack, "first_used_at": ActionTrack, "last_event_type": ActionTrack, diff --git a/enterprise/cli/aibridgeproxyd_internal_test.go b/enterprise/cli/aibridgeproxyd_internal_test.go index 2c8520878b..b6ed0f22c8 100644 --- a/enterprise/cli/aibridgeproxyd_internal_test.go +++ b/enterprise/cli/aibridgeproxyd_internal_test.go @@ -21,7 +21,7 @@ func TestClassifyProviderRow(t *testing.T) { enabledRow := func(name, baseURL string) database.AIProvider { return database.AIProvider{ Name: name, - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, Enabled: true, BaseUrl: baseURL, } @@ -33,7 +33,7 @@ func TestClassifyProviderRow(t *testing.T) { seen := map[string]string{} got := classifyProviderRow(enabledRow("openai", "https://api.openai.com/v1"), seen) assert.Equal(t, "openai", got.Name) - assert.Equal(t, string(database.AiProviderTypeOpenai), got.Type) + assert.Equal(t, string(database.AIProviderTypeOpenai), got.Type) assert.Equal(t, aibridged.ProviderStatusEnabled, got.Status) assert.Equal(t, "api.openai.com", got.Host) assert.NoError(t, got.Err) diff --git a/enterprise/coderd/ai_providers_backfill_test.go b/enterprise/coderd/ai_providers_backfill_test.go index ea385bead3..d349856f6a 100644 --- a/enterprise/coderd/ai_providers_backfill_test.go +++ b/enterprise/coderd/ai_providers_backfill_test.go @@ -37,7 +37,7 @@ func TestBackfillBedrockProviderTypeEncryptedSettings(t *testing.T) { }) require.NoError(t, err) provider := dbgen.AIProvider(t, cryptDB, database.AIProvider{ - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, Settings: sql.NullString{String: string(rawSettings), Valid: true}, }) @@ -46,6 +46,6 @@ func TestBackfillBedrockProviderTypeEncryptedSettings(t *testing.T) { // Verify via raw DB: type is not encrypted so it is directly readable. row, err := rawDB.GetAIProviderByName(ctx, provider.Name) require.NoError(t, err) - require.Equal(t, database.AiProviderTypeBedrock, row.Type, "encrypted legacy row must be promoted") + require.Equal(t, database.AIProviderTypeBedrock, row.Type, "encrypted legacy row must be promoted") require.True(t, row.SettingsKeyID.Valid, "settings must remain encrypted after backfill") } diff --git a/enterprise/coderd/aibridge.go b/enterprise/coderd/aibridge.go index 02a52c1495..d579719211 100644 --- a/enterprise/coderd/aibridge.go +++ b/enterprise/coderd/aibridge.go @@ -575,7 +575,7 @@ func (api *API) upsertGroupAIBudget(rw http.ResponseWriter, r *http.Request) { ctx = r.Context() group = httpmw.GroupParam(r) auditor = api.AGPL.Auditor.Load() - aReq, commitAudit = audit.InitRequest[database.AuditableGroupAiBudget](rw, &audit.RequestParams{ + aReq, commitAudit = audit.InitRequest[database.AuditableGroupAIBudget](rw, &audit.RequestParams{ Audit: *auditor, Log: api.Logger, Request: r, @@ -630,7 +630,7 @@ func (api *API) deleteGroupAIBudget(rw http.ResponseWriter, r *http.Request) { ctx = r.Context() group = httpmw.GroupParam(r) auditor = api.AGPL.Auditor.Load() - aReq, commitAudit = audit.InitRequest[database.AuditableGroupAiBudget](rw, &audit.RequestParams{ + aReq, commitAudit = audit.InitRequest[database.AuditableGroupAIBudget](rw, &audit.RequestParams{ Audit: *auditor, Log: api.Logger, Request: r, @@ -714,7 +714,7 @@ func (api *API) upsertUserAIBudgetOverride(rw http.ResponseWriter, r *http.Reque } auditor := api.AGPL.Auditor.Load() - aReq, commitAudit := audit.InitRequest[database.AuditableUserAiBudgetOverride](rw, &audit.RequestParams{ + aReq, commitAudit := audit.InitRequest[database.AuditableUserAIBudgetOverride](rw, &audit.RequestParams{ Audit: *auditor, Log: api.Logger, Request: r, @@ -809,7 +809,7 @@ func (api *API) deleteUserAIBudgetOverride(rw http.ResponseWriter, r *http.Reque } auditor := api.AGPL.Auditor.Load() - aReq, commitAudit := audit.InitRequest[database.AuditableUserAiBudgetOverride](rw, &audit.RequestParams{ + aReq, commitAudit := audit.InitRequest[database.AuditableUserAIBudgetOverride](rw, &audit.RequestParams{ Audit: *auditor, Log: api.Logger, Request: r, diff --git a/enterprise/coderd/aibridge_test.go b/enterprise/coderd/aibridge_test.go index 64682cd20f..6502cf74a1 100644 --- a/enterprise/coderd/aibridge_test.go +++ b/enterprise/coderd/aibridge_test.go @@ -2208,7 +2208,7 @@ func TestGroupAIBudget(t *testing.T) { rows, err := db.GetAuditLogsOffset( ctx, database.GetAuditLogsOffsetParams{ - ResourceType: string(database.ResourceTypeGroupAiBudget), + ResourceType: string(database.ResourceTypeGroupAIBudget), LimitOpt: 10, }, ) @@ -2220,7 +2220,7 @@ func TestGroupAIBudget(t *testing.T) { require.Equal(t, database.AuditActionWrite, upsertLog.Action) require.Equal(t, group.ID, upsertLog.ResourceID) - require.Equal(t, database.ResourceTypeGroupAiBudget, upsertLog.ResourceType) + require.Equal(t, database.ResourceTypeGroupAIBudget, upsertLog.ResourceType) require.Equal(t, group.Name, upsertLog.ResourceTarget) require.Equal(t, owner.OrganizationID, upsertLog.OrganizationID) @@ -2238,7 +2238,7 @@ func TestGroupAIBudget(t *testing.T) { require.Equal(t, database.AuditActionDelete, deleteLog.Action) require.Equal(t, group.ID, deleteLog.ResourceID) - require.Equal(t, database.ResourceTypeGroupAiBudget, deleteLog.ResourceType) + require.Equal(t, database.ResourceTypeGroupAIBudget, deleteLog.ResourceType) require.Equal(t, group.Name, deleteLog.ResourceTarget) require.Equal(t, owner.OrganizationID, deleteLog.OrganizationID) @@ -2495,7 +2495,7 @@ func TestUserAIBudgetOverride(t *testing.T) { rows, err := db.GetAuditLogsOffset( ctx, database.GetAuditLogsOffsetParams{ - ResourceType: string(database.ResourceTypeUserAiBudgetOverride), + ResourceType: string(database.ResourceTypeUserAIBudgetOverride), LimitOpt: 10, }, ) @@ -2507,7 +2507,7 @@ func TestUserAIBudgetOverride(t *testing.T) { require.Equal(t, database.AuditActionWrite, upsertLog.Action) require.Equal(t, targetUser.ID, upsertLog.ResourceID) - require.Equal(t, database.ResourceTypeUserAiBudgetOverride, upsertLog.ResourceType) + require.Equal(t, database.ResourceTypeUserAIBudgetOverride, upsertLog.ResourceType) require.Equal(t, targetUser.Username, upsertLog.ResourceTarget) require.Equal(t, owner.OrganizationID, upsertLog.OrganizationID) @@ -2531,7 +2531,7 @@ func TestUserAIBudgetOverride(t *testing.T) { require.Equal(t, database.AuditActionDelete, deleteLog.Action) require.Equal(t, targetUser.ID, deleteLog.ResourceID) - require.Equal(t, database.ResourceTypeUserAiBudgetOverride, deleteLog.ResourceType) + require.Equal(t, database.ResourceTypeUserAIBudgetOverride, deleteLog.ResourceType) require.Equal(t, targetUser.Username, deleteLog.ResourceTarget) require.Equal(t, owner.OrganizationID, deleteLog.OrganizationID) @@ -2564,7 +2564,7 @@ func TestUserAIBudgetOverride(t *testing.T) { rows, err := db.GetAuditLogsOffset( ctx, database.GetAuditLogsOffsetParams{ - ResourceType: string(database.ResourceTypeUserAiBudgetOverride), + ResourceType: string(database.ResourceTypeUserAIBudgetOverride), LimitOpt: 10, }, ) @@ -2616,7 +2616,7 @@ func TestUserAIBudgetOverride(t *testing.T) { rows, err := db.GetAuditLogsOffset( ctx, database.GetAuditLogsOffsetParams{ - ResourceType: string(database.ResourceTypeUserAiBudgetOverride), + ResourceType: string(database.ResourceTypeUserAIBudgetOverride), LimitOpt: 10, }, ) @@ -2673,7 +2673,7 @@ func TestUserAIBudgetOverride(t *testing.T) { rows, err := db.GetAuditLogsOffset( ctx, database.GetAuditLogsOffsetParams{ - ResourceType: string(database.ResourceTypeUserAiBudgetOverride), + ResourceType: string(database.ResourceTypeUserAIBudgetOverride), LimitOpt: 10, }, ) diff --git a/enterprise/coderd/aigatewaykeys.go b/enterprise/coderd/aigatewaykeys.go index 0e81f7d7dc..f9ebb13604 100644 --- a/enterprise/coderd/aigatewaykeys.go +++ b/enterprise/coderd/aigatewaykeys.go @@ -87,14 +87,14 @@ func writeKeyInsertError(ctx context.Context, rw http.ResponseWriter, err error) switch { case httpapi.IsUnauthorizedError(err): httpapi.Forbidden(rw) - case database.IsCheckViolation(err, database.CheckAiGatewayKeysNameCheck): + case database.IsCheckViolation(err, database.CheckAIGatewayKeysNameCheck): httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ Message: "Invalid key name.", Validations: []codersdk.ValidationError{ {Field: "name", Detail: nameFormatDetail}, }, }) - case database.IsUniqueViolation(err, database.UniqueAiGatewayKeysNameIndex): + case database.IsUniqueViolation(err, database.UniqueAIGatewayKeysNameIndex): httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ Message: "Key name must be unique.", Validations: []codersdk.ValidationError{ diff --git a/enterprise/dbcrypt/dbcrypt.go b/enterprise/dbcrypt/dbcrypt.go index 38a5cc1429..d8998baddf 100644 --- a/enterprise/dbcrypt/dbcrypt.go +++ b/enterprise/dbcrypt/dbcrypt.go @@ -589,22 +589,22 @@ func (db *dbCrypt) UpdateEncryptedAIProviderKey(ctx context.Context, params data return key, nil } -func (db *dbCrypt) decryptUserAIProviderKey(key *database.UserAiProviderKey) error { +func (db *dbCrypt) decryptUserAIProviderKey(key *database.UserAIProviderKey) error { return db.decryptField(&key.APIKey, key.ApiKeyKeyID) } -func (db *dbCrypt) GetUserAIProviderKeyByProviderID(ctx context.Context, params database.GetUserAIProviderKeyByProviderIDParams) (database.UserAiProviderKey, error) { +func (db *dbCrypt) GetUserAIProviderKeyByProviderID(ctx context.Context, params database.GetUserAIProviderKeyByProviderIDParams) (database.UserAIProviderKey, error) { key, err := db.Store.GetUserAIProviderKeyByProviderID(ctx, params) if err != nil { - return database.UserAiProviderKey{}, err + return database.UserAIProviderKey{}, err } if err := db.decryptUserAIProviderKey(&key); err != nil { - return database.UserAiProviderKey{}, err + return database.UserAIProviderKey{}, err } return key, nil } -func (db *dbCrypt) GetUserAIProviderKeysByUserID(ctx context.Context, userID uuid.UUID) ([]database.UserAiProviderKey, error) { +func (db *dbCrypt) GetUserAIProviderKeysByUserID(ctx context.Context, userID uuid.UUID) ([]database.UserAIProviderKey, error) { keys, err := db.Store.GetUserAIProviderKeysByUserID(ctx, userID) if err != nil { return nil, err @@ -617,7 +617,7 @@ func (db *dbCrypt) GetUserAIProviderKeysByUserID(ctx context.Context, userID uui return keys, nil } -func (db *dbCrypt) GetUserAIProviderKeys(ctx context.Context) ([]database.UserAiProviderKey, error) { +func (db *dbCrypt) GetUserAIProviderKeys(ctx context.Context) ([]database.UserAIProviderKey, error) { keys, err := db.Store.GetUserAIProviderKeys(ctx) if err != nil { return nil, err @@ -630,53 +630,53 @@ func (db *dbCrypt) GetUserAIProviderKeys(ctx context.Context) ([]database.UserAi return keys, nil } -func (db *dbCrypt) UpsertUserAIProviderKey(ctx context.Context, params database.UpsertUserAIProviderKeyParams) (database.UserAiProviderKey, error) { +func (db *dbCrypt) UpsertUserAIProviderKey(ctx context.Context, params database.UpsertUserAIProviderKeyParams) (database.UserAIProviderKey, error) { if strings.TrimSpace(params.APIKey) == "" { params.ApiKeyKeyID = sql.NullString{} } else if err := db.encryptField(¶ms.APIKey, ¶ms.ApiKeyKeyID); err != nil { - return database.UserAiProviderKey{}, err + return database.UserAIProviderKey{}, err } key, err := db.Store.UpsertUserAIProviderKey(ctx, params) if err != nil { - return database.UserAiProviderKey{}, err + return database.UserAIProviderKey{}, err } if err := db.decryptUserAIProviderKey(&key); err != nil { - return database.UserAiProviderKey{}, err + return database.UserAIProviderKey{}, err } return key, nil } -func (db *dbCrypt) UpdateUserAIProviderKey(ctx context.Context, params database.UpdateUserAIProviderKeyParams) (database.UserAiProviderKey, error) { +func (db *dbCrypt) UpdateUserAIProviderKey(ctx context.Context, params database.UpdateUserAIProviderKeyParams) (database.UserAIProviderKey, error) { if strings.TrimSpace(params.APIKey) == "" { params.ApiKeyKeyID = sql.NullString{} } else if err := db.encryptField(¶ms.APIKey, ¶ms.ApiKeyKeyID); err != nil { - return database.UserAiProviderKey{}, err + return database.UserAIProviderKey{}, err } key, err := db.Store.UpdateUserAIProviderKey(ctx, params) if err != nil { - return database.UserAiProviderKey{}, err + return database.UserAIProviderKey{}, err } if err := db.decryptUserAIProviderKey(&key); err != nil { - return database.UserAiProviderKey{}, err + return database.UserAIProviderKey{}, err } return key, nil } -func (db *dbCrypt) UpdateEncryptedUserAIProviderKey(ctx context.Context, params database.UpdateEncryptedUserAIProviderKeyParams) (database.UserAiProviderKey, error) { +func (db *dbCrypt) UpdateEncryptedUserAIProviderKey(ctx context.Context, params database.UpdateEncryptedUserAIProviderKeyParams) (database.UserAIProviderKey, error) { if strings.TrimSpace(params.APIKey) == "" { params.ApiKeyKeyID = sql.NullString{} } else if err := db.encryptField(¶ms.APIKey, ¶ms.ApiKeyKeyID); err != nil { - return database.UserAiProviderKey{}, err + return database.UserAIProviderKey{}, err } key, err := db.Store.UpdateEncryptedUserAIProviderKey(ctx, params) if err != nil { - return database.UserAiProviderKey{}, err + return database.UserAIProviderKey{}, err } if err := db.decryptUserAIProviderKey(&key); err != nil { - return database.UserAiProviderKey{}, err + return database.UserAIProviderKey{}, err } return key, nil } diff --git a/enterprise/dbcrypt/dbcrypt_internal_test.go b/enterprise/dbcrypt/dbcrypt_internal_test.go index 8f2c4b916a..4f7bcfb30a 100644 --- a/enterprise/dbcrypt/dbcrypt_internal_test.go +++ b/enterprise/dbcrypt/dbcrypt_internal_test.go @@ -1127,7 +1127,7 @@ func TestAIProviders(t *testing.T) { t.Helper() provider := dbgen.AIProvider(t, crypt, database.AIProvider{ Name: "anthropic-bedrock", - Type: database.AiProviderTypeAnthropic, + Type: database.AIProviderTypeAnthropic, BaseUrl: "https://bedrock-runtime.us-west-2.amazonaws.com/", Settings: sql.NullString{String: settings, Valid: true}, }) @@ -1237,7 +1237,7 @@ func TestAIProviderKeys(t *testing.T) { t.Helper() provider := dbgen.AIProvider(t, crypt, database.AIProvider{ Name: "openai-test", - Type: database.AiProviderTypeOpenai, + Type: database.AIProviderTypeOpenai, BaseUrl: "https://api.openai.com/v1/", }) key := dbgen.AIProviderKey(t, crypt, database.AIProviderKey{ @@ -1323,7 +1323,7 @@ func TestUserAIProviderKeys(t *testing.T) { t *testing.T, crypt *dbCrypt, ciphers []Cipher, - ) (database.AIProvider, database.UserAiProviderKey) { + ) (database.AIProvider, database.UserAIProviderKey) { t.Helper() user := dbgen.User(t, crypt, database.User{}) provider := dbgen.AIProvider(t, crypt, database.AIProvider{}) @@ -1343,7 +1343,7 @@ func TestUserAIProviderKeys(t *testing.T) { return provider, key } - getRawUserAIProviderKey := func(t *testing.T, store database.Store, userID uuid.UUID, providerID uuid.UUID) database.UserAiProviderKey { + getRawUserAIProviderKey := func(t *testing.T, store database.Store, userID uuid.UUID, providerID uuid.UUID) database.UserAIProviderKey { t.Helper() key, err := store.GetUserAIProviderKeyByProviderID(ctx, database.GetUserAIProviderKeyByProviderIDParams{ UserID: userID, diff --git a/scripts/dbgen/main.go b/scripts/dbgen/main.go index 265503dad5..ae544c961a 100644 --- a/scripts/dbgen/main.go +++ b/scripts/dbgen/main.go @@ -482,6 +482,8 @@ func nameFromSnakeCase(s string) string { ret += "JWT" case "idx": ret += "Index" + case "ai": + ret += "AI" case "api": ret += "API" case "uuid":