Skip to content

Commit f8f3d89

Browse files
authored
fix: label premium features in middleware error (#14360)
Previously, all features were called enterprise in the license check middleware.
1 parent 4446d61 commit f8f3d89

File tree

4 files changed

+59
-10
lines changed

4 files changed

+59
-10
lines changed

codersdk/deployment.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,17 @@ func (n FeatureName) AlwaysEnable() bool {
128128
}[n]
129129
}
130130

131+
// Enterprise returns true if the feature is an enterprise feature.
132+
func (n FeatureName) Enterprise() bool {
133+
switch n {
134+
// Add all features that should be excluded in the Enterprise feature set.
135+
case FeatureMultipleOrganizations, FeatureCustomRoles:
136+
return false
137+
default:
138+
return true
139+
}
140+
}
141+
131142
// FeatureSet represents a grouping of features. Rather than manually
132143
// assigning features al-la-carte when making a license, a set can be specified.
133144
// Sets are dynamic in the sense a feature can be added to a set, granting the
@@ -152,13 +163,7 @@ func (set FeatureSet) Features() []FeatureName {
152163
copy(enterpriseFeatures, FeatureNames)
153164
// Remove the selection
154165
enterpriseFeatures = slices.DeleteFunc(enterpriseFeatures, func(f FeatureName) bool {
155-
switch f {
156-
// Add all features that should be excluded in the Enterprise feature set.
157-
case FeatureMultipleOrganizations, FeatureCustomRoles:
158-
return true
159-
default:
160-
return false
161-
}
166+
return !f.Enterprise()
162167
})
163168

164169
return enterpriseFeatures

enterprise/coderd/organizations_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,46 @@ func TestPatchOrganizationsByUser(t *testing.T) {
488488
require.Equal(t, displayName, o.DisplayName) // didn't change
489489
require.Equal(t, icon, o.Icon)
490490
})
491+
492+
t.Run("RevokedLicense", func(t *testing.T) {
493+
t.Parallel()
494+
dv := coderdtest.DeploymentValues(t)
495+
dv.Experiments = []string{string(codersdk.ExperimentMultiOrganization)}
496+
client, _ := coderdenttest.New(t, &coderdenttest.Options{
497+
Options: &coderdtest.Options{
498+
DeploymentValues: dv,
499+
},
500+
LicenseOptions: &coderdenttest.LicenseOptions{
501+
Features: license.Features{
502+
codersdk.FeatureMultipleOrganizations: 1,
503+
},
504+
},
505+
})
506+
ctx := testutil.Context(t, testutil.WaitMedium)
507+
508+
const displayName = "New Organization"
509+
o := coderdenttest.CreateOrganization(t, client, coderdenttest.CreateOrganizationOptions{}, func(request *codersdk.CreateOrganizationRequest) {
510+
request.DisplayName = displayName
511+
request.Icon = "/emojis/random.png"
512+
request.Name = "new-org"
513+
})
514+
515+
// Remove the license to block premium functionality.
516+
licenses, err := client.Licenses(ctx)
517+
require.NoError(t, err, "get licenses")
518+
for _, license := range licenses {
519+
// Should be only 1...
520+
err := client.DeleteLicense(ctx, license.ID)
521+
require.NoError(t, err, "delete license")
522+
}
523+
524+
// Verify functionality is lost.
525+
const icon = "/emojis/1f48f-1f3ff.png"
526+
o, err = client.UpdateOrganization(ctx, o.Name, codersdk.UpdateOrganizationRequest{
527+
Icon: ptr.Ref(icon),
528+
})
529+
require.ErrorContains(t, err, "Multiple Organizations is a Premium feature")
530+
})
491531
}
492532

493533
func TestPostOrganizationsByUser(t *testing.T) {

enterprise/coderd/roles_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ func TestCustomOrganizationRole(t *testing.T) {
114114
role, err := owner.CreateOrganizationRole(ctx, templateAdminCustom(first.OrganizationID))
115115
require.NoError(t, err, "upsert role")
116116

117-
// Remove the license to block enterprise functionality
117+
// Remove the license to block premium functionality
118118
licenses, err := owner.Licenses(ctx)
119119
require.NoError(t, err, "get licenses")
120120
for _, license := range licenses {
@@ -125,7 +125,7 @@ func TestCustomOrganizationRole(t *testing.T) {
125125

126126
// Verify functionality is lost
127127
_, err = owner.UpdateOrganizationRole(ctx, templateAdminCustom(first.OrganizationID))
128-
require.ErrorContains(t, err, "Custom Roles is an Enterprise feature")
128+
require.ErrorContains(t, err, "Custom Roles is a Premium feature")
129129

130130
// Assign the custom template admin role
131131
tmplAdmin, _ := coderdtest.CreateAnotherUser(t, owner, first.OrganizationID, rbac.RoleIdentifier{Name: role.Name, OrganizationID: first.OrganizationID})

enterprise/coderd/templates.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,8 +364,12 @@ func (api *API) RequireFeatureMW(feat codersdk.FeatureName) func(http.Handler) h
364364
enabled := api.entitlements.Features[feat].Enabled
365365
api.entitlementsMu.RUnlock()
366366
if !enabled {
367+
licenseType := "a Premium"
368+
if feat.Enterprise() {
369+
licenseType = "an Enterprise"
370+
}
367371
httpapi.Write(r.Context(), rw, http.StatusForbidden, codersdk.Response{
368-
Message: fmt.Sprintf("%s is an Enterprise feature. Contact sales!", feat.Humanize()),
372+
Message: fmt.Sprintf("%s is %s feature. Contact sales!", feat.Humanize(), licenseType),
369373
})
370374
return
371375
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy