From c932740dc5d09d7a7c3f9d66d13044a8aa35713e Mon Sep 17 00:00:00 2001 From: Aleksei Sviridkin Date: Wed, 11 Feb 2026 13:24:16 +0300 Subject: [PATCH] refactor(api): remove global ObjectMeta name patching from OpenAPI Remove patchObjectMetaNameValidation and patchObjectMetaNameValidationV2 functions that were modifying the global ObjectMeta schema. This patching affected ALL resources served by the API server, not just Application resources. Backend validation in Create() is sufficient for enforcing name constraints. Co-Authored-By: Claude Signed-off-by: Aleksei Sviridkin --- pkg/cmd/server/openapi.go | 38 --------------- pkg/cmd/server/openapi_test.go | 87 ---------------------------------- 2 files changed, 125 deletions(-) delete mode 100644 pkg/cmd/server/openapi_test.go diff --git a/pkg/cmd/server/openapi.go b/pkg/cmd/server/openapi.go index 4d89d1fd..b52aa989 100644 --- a/pkg/cmd/server/openapi.go +++ b/pkg/cmd/server/openapi.go @@ -20,40 +20,8 @@ const ( baseStatusRef = apiPrefix + ".ApplicationStatus" smp = "application/strategic-merge-patch+json" - // objectMetaRef is the OpenAPI reference for Kubernetes ObjectMeta. - objectMetaRef = "k8s.io/apimachinery/pkg/apis/meta/v1.ObjectMeta" - // applicationNamePattern is DNS-1035 regex for Application names. - applicationNamePattern = `^[a-z]([-a-z0-9]*[a-z0-9])?$` ) -// patchObjectMetaNameValidation adds DNS-1035 validation to metadata.name. -// This ensures UI form validation matches backend validation. -func patchObjectMetaNameValidation(schemas map[string]*spec.Schema) { - objMeta, ok := schemas[objectMetaRef] - if !ok || objMeta == nil { - return - } - - if name, ok := objMeta.Properties["name"]; ok { - name.Pattern = applicationNamePattern - objMeta.Properties["name"] = name - } -} - -// patchObjectMetaNameValidationV2 adds DNS-1035 validation for Swagger v2. -func patchObjectMetaNameValidationV2(defs map[string]spec.Schema) { - objMeta, ok := defs[objectMetaRef] - if !ok { - return - } - - if name, ok := objMeta.Properties["name"]; ok { - name.Pattern = applicationNamePattern - objMeta.Properties["name"] = name - } - defs[objectMetaRef] = objMeta -} - // deepCopySchema clones *spec.Schema via JSON-marshal/unmarshal. func deepCopySchema(in *spec.Schema) *spec.Schema { if in == nil { @@ -295,9 +263,6 @@ func buildPostProcessV3(kindSchemas map[string]string) func(*spec3.OpenAPI) (*sp } } - // Add name validation to ObjectMeta for UI form validation - patchObjectMetaNameValidation(doc.Components.Schemas) - // Rewrite all $ref in the document out, err := rewriteDocRefs(doc) if err != nil { @@ -379,9 +344,6 @@ func buildPostProcessV2(kindSchemas map[string]string) func(*spec.Swagger) (*spe return sw, fmt.Errorf("base Application* schemas not found") } - // Add name validation to ObjectMeta for UI form validation - patchObjectMetaNameValidationV2(defs) - for kind, raw := range kindSchemas { ref := apiPrefix + "." + kind statusRef := ref + "Status" diff --git a/pkg/cmd/server/openapi_test.go b/pkg/cmd/server/openapi_test.go deleted file mode 100644 index 626581ca..00000000 --- a/pkg/cmd/server/openapi_test.go +++ /dev/null @@ -1,87 +0,0 @@ -/* -Copyright 2024 The Cozystack Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package server - -import ( - "testing" - - "k8s.io/kube-openapi/pkg/validation/spec" -) - -func TestPatchObjectMetaNameValidation(t *testing.T) { - tests := []struct { - name string - schemas map[string]*spec.Schema - wantPattern string - }{ - { - name: "patches ObjectMeta name field", - schemas: map[string]*spec.Schema{ - objectMetaRef: { - SchemaProps: spec.SchemaProps{ - Properties: map[string]spec.Schema{ - "name": {SchemaProps: spec.SchemaProps{Type: []string{"string"}}}, - }, - }, - }, - }, - wantPattern: applicationNamePattern, - }, - { - name: "no panic when ObjectMeta missing", - schemas: map[string]*spec.Schema{}, - wantPattern: "", - }, - { - name: "no panic when name field missing", - schemas: map[string]*spec.Schema{ - objectMetaRef: { - SchemaProps: spec.SchemaProps{ - Properties: map[string]spec.Schema{}, - }, - }, - }, - wantPattern: "", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - patchObjectMetaNameValidation(tt.schemas) - - objMeta, ok := tt.schemas[objectMetaRef] - if !ok { - if tt.wantPattern != "" { - t.Error("expected ObjectMeta to exist") - } - return - } - - name, ok := objMeta.Properties["name"] - if !ok { - if tt.wantPattern != "" { - t.Error("expected name field to exist") - } - return - } - - if name.Pattern != tt.wantPattern { - t.Errorf("Pattern = %q, want %q", name.Pattern, tt.wantPattern) - } - }) - } -}