Dashboard Tags: Validate max length (#116047)
This commit is contained in:
@@ -389,6 +389,11 @@ func (b *DashboardsAPIBuilder) validateCreate(ctx context.Context, a admission.A
|
||||
return apierrors.NewBadRequest(err.Error())
|
||||
}
|
||||
|
||||
// Validate tags
|
||||
if err := validateDashboardTags(dashObj); err != nil {
|
||||
return apierrors.NewBadRequest(err.Error())
|
||||
}
|
||||
|
||||
id, err := identity.GetRequester(ctx)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error getting requester: %w", err)
|
||||
@@ -459,6 +464,11 @@ func (b *DashboardsAPIBuilder) validateUpdate(ctx context.Context, a admission.A
|
||||
return apierrors.NewBadRequest(err.Error())
|
||||
}
|
||||
|
||||
// Validate tags
|
||||
if err := validateDashboardTags(newDashObj); err != nil {
|
||||
return apierrors.NewBadRequest(err.Error())
|
||||
}
|
||||
|
||||
// Validate folder existence if specified and changed
|
||||
if !a.IsDryRun() && newAccessor.GetFolder() != oldAccessor.GetFolder() && newAccessor.GetFolder() != "" {
|
||||
id, err := identity.GetRequester(ctx)
|
||||
@@ -556,6 +566,32 @@ func getDashboardProperties(obj runtime.Object) (string, string, error) {
|
||||
return title, refresh, nil
|
||||
}
|
||||
|
||||
// validateDashboardTags validates that all dashboard tags are within the maximum length
|
||||
func validateDashboardTags(obj runtime.Object) error {
|
||||
var tags []string
|
||||
|
||||
switch d := obj.(type) {
|
||||
case *dashv0.Dashboard:
|
||||
tags = d.Spec.GetNestedStringSlice("tags")
|
||||
case *dashv1.Dashboard:
|
||||
tags = d.Spec.GetNestedStringSlice("tags")
|
||||
case *dashv2alpha1.Dashboard:
|
||||
tags = d.Spec.Tags
|
||||
case *dashv2beta1.Dashboard:
|
||||
tags = d.Spec.Tags
|
||||
default:
|
||||
return fmt.Errorf("unsupported dashboard version: %T", obj)
|
||||
}
|
||||
|
||||
for _, tag := range tags {
|
||||
if len(tag) > 50 {
|
||||
return dashboards.ErrDashboardTagTooLong
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *DashboardsAPIBuilder) UpdateAPIGroupInfo(apiGroupInfo *genericapiserver.APIGroupInfo, opts builder.APIGroupOptions) error {
|
||||
storageOpts := apistore.StorageOptions{
|
||||
EnableFolderSupport: true,
|
||||
|
||||
@@ -542,6 +542,9 @@ func (d *dashboardStore) saveDashboard(ctx context.Context, sess *db.Session, cm
|
||||
tags := dash.GetTags()
|
||||
if len(tags) > 0 {
|
||||
for _, tag := range tags {
|
||||
if len(tag) > 50 {
|
||||
return nil, dashboards.ErrDashboardTagTooLong
|
||||
}
|
||||
if _, err := sess.Insert(dashboardTag{DashboardId: dash.ID, Term: tag, OrgID: dash.OrgID, DashboardUID: dash.UID}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -79,6 +79,11 @@ var (
|
||||
Reason: "message too long, max 500 characters",
|
||||
StatusCode: 400,
|
||||
}
|
||||
ErrDashboardTagTooLong = dashboardaccess.DashboardErr{
|
||||
Reason: "dashboard tag too long, max 50 characters",
|
||||
StatusCode: 400,
|
||||
Status: "tag-too-long",
|
||||
}
|
||||
ErrDashboardCannotSaveProvisionedDashboard = dashboardaccess.DashboardErr{
|
||||
Reason: "Cannot save provisioned dashboard",
|
||||
StatusCode: 400,
|
||||
|
||||
@@ -393,6 +393,66 @@ func runDashboardValidationTests(t *testing.T, ctx TestContext) {
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Dashboard tag validations", func(t *testing.T) {
|
||||
t.Run("reject dashboard with tag over 50 characters on creation", func(t *testing.T) {
|
||||
dashObj := createDashboardObject(t, "Dashboard with Long Tag", "", 0)
|
||||
meta, _ := utils.MetaAccessor(dashObj)
|
||||
spec, _ := meta.GetSpec()
|
||||
specMap := spec.(map[string]interface{})
|
||||
specMap["tags"] = []string{"this-is-a-very-long-tag-that-exceeds-fifty-characters-limit"}
|
||||
_ = meta.SetSpec(specMap)
|
||||
_, err := adminClient.Resource.Create(context.Background(), dashObj, v1.CreateOptions{})
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "tag too long")
|
||||
})
|
||||
|
||||
t.Run("reject dashboard update with tag over 50 characters", func(t *testing.T) {
|
||||
dash, err := createDashboard(t, adminClient, "Valid Dashboard", nil, nil, ctx.Helper)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, dash)
|
||||
meta, _ := utils.MetaAccessor(dash)
|
||||
spec, _ := meta.GetSpec()
|
||||
specMap := spec.(map[string]interface{})
|
||||
specMap["tags"] = []string{"this-is-a-very-long-tag-that-exceeds-fifty-characters-limit"}
|
||||
_ = meta.SetSpec(specMap)
|
||||
_, err = adminClient.Resource.Update(context.Background(), dash, v1.UpdateOptions{})
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "tag too long")
|
||||
err = adminClient.Resource.Delete(context.Background(), dash.GetName(), v1.DeleteOptions{})
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("accept dashboard with tag at 50 characters", func(t *testing.T) {
|
||||
dashObj := createDashboardObject(t, "Dashboard with Valid Tag", "", 0)
|
||||
meta, _ := utils.MetaAccessor(dashObj)
|
||||
spec, _ := meta.GetSpec()
|
||||
specMap := spec.(map[string]interface{})
|
||||
specMap["tags"] = []string{"this-tag-is-exactly-fifty-characters-long-12345"}
|
||||
_ = meta.SetSpec(specMap)
|
||||
createdDash, err := adminClient.Resource.Create(context.Background(), dashObj, v1.CreateOptions{})
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, createdDash)
|
||||
err = adminClient.Resource.Delete(context.Background(), createdDash.GetName(), v1.DeleteOptions{})
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("reject dashboard with multiple tags where one exceeds limit", func(t *testing.T) {
|
||||
dashObj := createDashboardObject(t, "Dashboard with Mixed Tags", "", 0)
|
||||
meta, _ := utils.MetaAccessor(dashObj)
|
||||
spec, _ := meta.GetSpec()
|
||||
specMap := spec.(map[string]interface{})
|
||||
specMap["tags"] = []string{
|
||||
"valid-tag",
|
||||
"another-valid-tag",
|
||||
"this-is-a-very-long-tag-that-exceeds-fifty-characters-limit",
|
||||
}
|
||||
_ = meta.SetSpec(specMap)
|
||||
_, err := adminClient.Resource.Create(context.Background(), dashObj, v1.CreateOptions{})
|
||||
require.Error(t, err)
|
||||
require.Contains(t, err.Error(), "tag too long")
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Dashboard folder validations", func(t *testing.T) {
|
||||
// Test non-existent folder UID
|
||||
t.Run("reject dashboard with non-existent folder UID", func(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user