fix: label premium features in middleware error (#14360)

Previously, all features were called enterprise in the license check middleware.
This commit is contained in:
Asher
2024-08-19 15:58:41 -08:00
committed by GitHub
parent 4446d61fcd
commit f8f3d8967e
4 changed files with 59 additions and 10 deletions

View File

@ -128,6 +128,17 @@ func (n FeatureName) AlwaysEnable() bool {
}[n]
}
// Enterprise returns true if the feature is an enterprise feature.
func (n FeatureName) Enterprise() bool {
switch n {
// Add all features that should be excluded in the Enterprise feature set.
case FeatureMultipleOrganizations, FeatureCustomRoles:
return false
default:
return true
}
}
// FeatureSet represents a grouping of features. Rather than manually
// assigning features al-la-carte when making a license, a set can be specified.
// 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 {
copy(enterpriseFeatures, FeatureNames)
// Remove the selection
enterpriseFeatures = slices.DeleteFunc(enterpriseFeatures, func(f FeatureName) bool {
switch f {
// Add all features that should be excluded in the Enterprise feature set.
case FeatureMultipleOrganizations, FeatureCustomRoles:
return true
default:
return false
}
return !f.Enterprise()
})
return enterpriseFeatures

View File

@ -488,6 +488,46 @@ func TestPatchOrganizationsByUser(t *testing.T) {
require.Equal(t, displayName, o.DisplayName) // didn't change
require.Equal(t, icon, o.Icon)
})
t.Run("RevokedLicense", func(t *testing.T) {
t.Parallel()
dv := coderdtest.DeploymentValues(t)
dv.Experiments = []string{string(codersdk.ExperimentMultiOrganization)}
client, _ := coderdenttest.New(t, &coderdenttest.Options{
Options: &coderdtest.Options{
DeploymentValues: dv,
},
LicenseOptions: &coderdenttest.LicenseOptions{
Features: license.Features{
codersdk.FeatureMultipleOrganizations: 1,
},
},
})
ctx := testutil.Context(t, testutil.WaitMedium)
const displayName = "New Organization"
o := coderdenttest.CreateOrganization(t, client, coderdenttest.CreateOrganizationOptions{}, func(request *codersdk.CreateOrganizationRequest) {
request.DisplayName = displayName
request.Icon = "/emojis/random.png"
request.Name = "new-org"
})
// Remove the license to block premium functionality.
licenses, err := client.Licenses(ctx)
require.NoError(t, err, "get licenses")
for _, license := range licenses {
// Should be only 1...
err := client.DeleteLicense(ctx, license.ID)
require.NoError(t, err, "delete license")
}
// Verify functionality is lost.
const icon = "/emojis/1f48f-1f3ff.png"
o, err = client.UpdateOrganization(ctx, o.Name, codersdk.UpdateOrganizationRequest{
Icon: ptr.Ref(icon),
})
require.ErrorContains(t, err, "Multiple Organizations is a Premium feature")
})
}
func TestPostOrganizationsByUser(t *testing.T) {

View File

@ -114,7 +114,7 @@ func TestCustomOrganizationRole(t *testing.T) {
role, err := owner.CreateOrganizationRole(ctx, templateAdminCustom(first.OrganizationID))
require.NoError(t, err, "upsert role")
// Remove the license to block enterprise functionality
// Remove the license to block premium functionality
licenses, err := owner.Licenses(ctx)
require.NoError(t, err, "get licenses")
for _, license := range licenses {
@ -125,7 +125,7 @@ func TestCustomOrganizationRole(t *testing.T) {
// Verify functionality is lost
_, err = owner.UpdateOrganizationRole(ctx, templateAdminCustom(first.OrganizationID))
require.ErrorContains(t, err, "Custom Roles is an Enterprise feature")
require.ErrorContains(t, err, "Custom Roles is a Premium feature")
// Assign the custom template admin role
tmplAdmin, _ := coderdtest.CreateAnotherUser(t, owner, first.OrganizationID, rbac.RoleIdentifier{Name: role.Name, OrganizationID: first.OrganizationID})

View File

@ -364,8 +364,12 @@ func (api *API) RequireFeatureMW(feat codersdk.FeatureName) func(http.Handler) h
enabled := api.entitlements.Features[feat].Enabled
api.entitlementsMu.RUnlock()
if !enabled {
licenseType := "a Premium"
if feat.Enterprise() {
licenseType = "an Enterprise"
}
httpapi.Write(r.Context(), rw, http.StatusForbidden, codersdk.Response{
Message: fmt.Sprintf("%s is an Enterprise feature. Contact sales!", feat.Humanize()),
Message: fmt.Sprintf("%s is %s feature. Contact sales!", feat.Humanize(), licenseType),
})
return
}