Skip to content

Commit 2f6a1ef

Browse files
committed
Validates resource names before storing in inventory
1 parent 07e7070 commit 2f6a1ef

File tree

2 files changed

+59
-3
lines changed

2 files changed

+59
-3
lines changed

pkg/object/objmetadata.go

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121

2222
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
2323
"k8s.io/apimachinery/pkg/runtime/schema"
24+
"k8s.io/apimachinery/pkg/util/validation"
2425
"k8s.io/cli-runtime/pkg/resource"
2526
)
2627

@@ -45,10 +46,15 @@ func CreateObjMetadata(namespace string, name string, gk schema.GroupKind) (*Obj
4546
// Namespace can be empty, but name cannot.
4647
name = strings.TrimSpace(name)
4748
if name == "" {
48-
return nil, fmt.Errorf("empty name for inventory object")
49+
return nil, fmt.Errorf("empty name for object")
50+
}
51+
// Manually validate name, since by the time k8s reports the error
52+
// the invalid name has already been encoded into the inventory object.
53+
if !validateNameChars(name) {
54+
return nil, fmt.Errorf("invalid characters in object name: %s", name)
4955
}
5056
if gk.Empty() {
51-
return nil, fmt.Errorf("empty GroupKind for inventory object")
57+
return nil, fmt.Errorf("empty GroupKind for object")
5258
}
5359

5460
return &ObjMetadata{
@@ -58,6 +64,23 @@ func CreateObjMetadata(namespace string, name string, gk schema.GroupKind) (*Obj
5864
}, nil
5965
}
6066

67+
// validateNameChars returns false if the passed name string contains
68+
// any invalid characters; true otherwise. The allowed characters for
69+
// a Kubernetes resource name are:
70+
//
71+
// Most resource types require a name that can be used as a DNS label name
72+
// as defined in RFC 1123. This means the name must:
73+
//
74+
// * contain no more than 253 characters
75+
// * contain only lowercase alphanumeric characters, '-'
76+
// * start with an alphanumeric character
77+
// * end with an alphanumeric character
78+
//
79+
func validateNameChars(name string) bool {
80+
errs := validation.IsDNS1123Subdomain(name)
81+
return len(errs) == 0
82+
}
83+
6184
// ParseObjMetadata takes a string, splits it into its five fields,
6285
// and returns a pointer to an ObjMetadata struct storing the
6386
// five fields. Example inventory string:

pkg/object/objmetadata_test.go

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,46 @@ func TestCreateObjMetadata(t *testing.T) {
5656
expected: "",
5757
isError: true,
5858
},
59+
// Error with invalid name characters "_".
60+
{
61+
namespace: "test-namespace",
62+
name: "test_name", // Invalid "_" character
63+
gk: schema.GroupKind{
64+
Group: "apps",
65+
Kind: "ReplicaSet",
66+
},
67+
expected: "",
68+
isError: true,
69+
},
70+
// Error name not starting with alphanumeric char
71+
{
72+
namespace: "test-namespace",
73+
name: "-test",
74+
gk: schema.GroupKind{
75+
Group: "apps",
76+
Kind: "ReplicaSet",
77+
},
78+
expected: "",
79+
isError: true,
80+
},
81+
// Error name not ending with alphanumeric char
82+
{
83+
namespace: "test-namespace",
84+
name: "test-",
85+
gk: schema.GroupKind{
86+
Group: "apps",
87+
Kind: "ReplicaSet",
88+
},
89+
expected: "",
90+
isError: true,
91+
},
5992
}
6093

6194
for _, test := range tests {
6295
inv, err := CreateObjMetadata(test.namespace, test.name, test.gk)
6396
if !test.isError {
6497
if err != nil {
65-
t.Errorf("Error creating inventory when it should have worked.")
98+
t.Errorf("Error creating ObjMetadata when it should have worked.")
6699
} else if test.expected != inv.String() {
67100
t.Errorf("Expected inventory (%s) != created inventory(%s)\n", test.expected, inv.String())
68101
}

0 commit comments

Comments
 (0)