From b82693d4cce173c55597374f8160667a0c803cb0 Mon Sep 17 00:00:00 2001 From: Kacper Sawicki Date: Fri, 23 Jan 2026 16:58:12 +0100 Subject: [PATCH] feat(codersdk): revert "remove AI Bridge entitlement from Premium license" (#21653) Reverts coder/coder#21540 --- codersdk/deployment.go | 8 +++---- codersdk/deployment_test.go | 6 ++--- enterprise/coderd/license/license.go | 13 ---------- enterprise/coderd/license/license_test.go | 29 +++-------------------- 4 files changed, 10 insertions(+), 46 deletions(-) diff --git a/codersdk/deployment.go b/codersdk/deployment.go index 74204aeb2a..90915b13b3 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -170,8 +170,7 @@ func (n FeatureName) AlwaysEnable() bool { func (n FeatureName) Enterprise() bool { switch n { // Add all features that should be excluded in the Enterprise feature set. - // AI Bridge is a separate add-on. - case FeatureMultipleOrganizations, FeatureCustomRoles, FeatureAIBridge: + case FeatureMultipleOrganizations, FeatureCustomRoles: return false default: return true @@ -225,10 +224,11 @@ func (set FeatureSet) Features() []FeatureName { case FeatureSetPremium: premiumFeatures := make([]FeatureName, len(FeatureNames)) copy(premiumFeatures, FeatureNames) - // Remove features that use limits and AI Bridge (now a separate add-on). + // Remove the selection premiumFeatures = slices.DeleteFunc(premiumFeatures, func(f FeatureName) bool { - return f.UsesLimit() || f == FeatureAIBridge + return f.UsesLimit() }) + // FeatureSetPremium is just all features. return premiumFeatures } // By default, return an empty set. diff --git a/codersdk/deployment_test.go b/codersdk/deployment_test.go index d5f61d0659..3590e5455c 100644 --- a/codersdk/deployment_test.go +++ b/codersdk/deployment_test.go @@ -623,16 +623,16 @@ func TestPremiumSuperSet(t *testing.T) { // Premium ⊃ Enterprise require.Subset(t, premium.Features(), enterprise.Features(), "premium should be a superset of enterprise. If this fails, update the premium feature set to include all enterprise features.") - // Premium = All Features EXCEPT usage limit features and AI Bridge (add-on). + // Premium = All Features EXCEPT usage limit features expectedPremiumFeatures := []codersdk.FeatureName{} for _, feature := range codersdk.FeatureNames { - if feature.UsesLimit() || feature == codersdk.FeatureAIBridge { + if feature.UsesLimit() { continue } expectedPremiumFeatures = append(expectedPremiumFeatures, feature) } require.NotEmpty(t, expectedPremiumFeatures, "expectedPremiumFeatures should not be empty") - require.ElementsMatch(t, premium.Features(), expectedPremiumFeatures, "premium should contain all features except usage limit features and AI Bridge") + require.ElementsMatch(t, premium.Features(), expectedPremiumFeatures, "premium should contain all features except usage limit features") // This check exists because if you misuse the slices.Delete, you can end up // with zero'd values. diff --git a/enterprise/coderd/license/license.go b/enterprise/coderd/license/license.go index c02e82b99c..3cf23823d2 100644 --- a/enterprise/coderd/license/license.go +++ b/enterprise/coderd/license/license.go @@ -548,15 +548,6 @@ func LicensesEntitlements( featureArguments.ActiveUserCount, *userLimit.Limit)) } - // AI Bridge has a custom warning message as it moved to a separate add-on. - aiBridge := entitlements.Features[codersdk.FeatureAIBridge] - if aiBridge.Enabled && aiBridge.Entitlement != codersdk.EntitlementEntitled { - entitlements.Warnings = append(entitlements.Warnings, - "AI Bridge has reached General Availability and your Coder deployment is not entitled "+ - "to run this feature. Contact your account team (https://coder.com/contact) for "+ - "information around getting a license with AI Bridge.") - } - // Add a warning for every feature that is enabled but not entitled or // is in a grace period. for _, featureName := range codersdk.FeatureNames { @@ -576,10 +567,6 @@ func LicensesEntitlements( if featureName == codersdk.FeatureManagedAgentLimit { continue } - // AI Bridge has a custom warning message as it moved to a separate add-on. - if featureName == codersdk.FeatureAIBridge { - continue - } feature := entitlements.Features[featureName] if !feature.Enabled { diff --git a/enterprise/coderd/license/license_test.go b/enterprise/coderd/license/license_test.go index ca12b97752..6c53fb3d89 100644 --- a/enterprise/coderd/license/license_test.go +++ b/enterprise/coderd/license/license_test.go @@ -25,10 +25,6 @@ func TestEntitlements(t *testing.T) { t.Parallel() all := make(map[codersdk.FeatureName]bool) for _, n := range codersdk.FeatureNames { - // AI Bridge is a separate add-on, not included in standard feature sets. - if n == codersdk.FeatureAIBridge { - continue - } all[n] = true } @@ -370,9 +366,9 @@ func TestEntitlements(t *testing.T) { require.True(t, entitlements.HasLicense) require.False(t, entitlements.Trial) for _, featureName := range codersdk.FeatureNames { - if featureName == codersdk.FeatureUserLimit || featureName == codersdk.FeatureHighAvailability || featureName == codersdk.FeatureMultipleExternalAuth || featureName == codersdk.FeatureManagedAgentLimit || featureName == codersdk.FeatureAIBridge { + if featureName == codersdk.FeatureUserLimit || featureName == codersdk.FeatureHighAvailability || featureName == codersdk.FeatureMultipleExternalAuth || featureName == codersdk.FeatureManagedAgentLimit { // These fields don't generate warnings when not entitled unless - // a limit is breached, or have custom warning messages. + // a limit is breached. continue } niceName := featureName.Humanize() @@ -802,25 +798,6 @@ func TestEntitlements(t *testing.T) { require.Equal(t, "You have multiple External Auth Providers configured but your license is expired. Reduce to one.", entitlements.Warnings[0]) }) - t.Run("AIBridgeEnabledNotEntitled", func(t *testing.T) { - t.Parallel() - db, _ := dbtestutil.NewDB(t) - db.InsertLicense(context.Background(), database.InsertLicenseParams{ - Exp: time.Now().Add(time.Hour), - JWT: coderdenttest.GenerateLicense(t, coderdenttest.LicenseOptions{ - Features: license.Features{ - codersdk.FeatureAuditLog: 1, // Some feature but not AI Bridge. - }, - }), - }) - entitlements, err := license.Entitlements(context.Background(), db, 1, 1, coderdenttest.Keys, map[codersdk.FeatureName]bool{ - codersdk.FeatureAIBridge: true, // Enabled but not entitled. - }) - require.NoError(t, err) - require.True(t, entitlements.HasLicense) - require.Contains(t, entitlements.Warnings, "AI Bridge has reached General Availability and your Coder deployment is not entitled to run this feature. Contact your account team (https://coder.com/contact) for information around getting a license with AI Bridge.") - }) - t.Run("ManagedAgentLimitHasValue", func(t *testing.T) { t.Parallel() @@ -915,7 +892,7 @@ func TestLicenseEntitlements(t *testing.T) { codersdk.FeatureAccessControl: true, codersdk.FeatureControlSharedPorts: true, codersdk.FeatureWorkspaceExternalAgent: true, - // FeatureAIBridge is intentionally not included as it's a separate add-on. + codersdk.FeatureAIBridge: true, } legacyLicense := func() *coderdenttest.LicenseOptions {