Skip to content

Commit 2d1995b

Browse files
feat: add func to shorten strings, deprecate old hash funcs
1 parent a6ab513 commit 2d1995b

File tree

3 files changed

+70
-1
lines changed

3 files changed

+70
-1
lines changed

pkg/controller/hash.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ import (
1313
)
1414

1515
var (
16-
ErrInvalidNames = errors.New("list of names must not be empty and contain at least one non-empty string")
16+
ErrInvalidNames = errors.New("list of names must not be empty and contain at least one non-empty string")
17+
ErrMaxLenTooSmall = errors.New("maxLen must be greater than 10")
1718
)
1819

1920
// Version8UUID creates a new UUID (version 8) from a byte slice. Returns an error if the slice does not have a length of 16. The bytes are copied from the slice.
@@ -64,6 +65,7 @@ func validateIDs(names []string) error {
6465

6566
// K8sNameUUIDUnsafe works like K8sNameUUID, but panics instead of returning an error.
6667
// This should only be used in places where the input is guaranteed to be valid.
68+
// Deprecated: Use NameHashSHAKE128Base32 instead.
6769
func K8sNameUUIDUnsafe(names ...string) string {
6870
uuid, err := K8sNameUUID(names...)
6971
if err != nil {
@@ -74,6 +76,7 @@ func K8sNameUUIDUnsafe(names ...string) string {
7476

7577
// K8sObjectUUID takes a client object and computes a hash out of the namespace and name, which is then formatted as a version 8 UUID.
7678
// An empty namespace will be replaced by "default".
79+
// Deprecated: Use ObjectHashSHAKE128Base32 instead.
7780
func K8sObjectUUID(obj client.Object) (string, error) {
7881
name, namespace := obj.GetName(), obj.GetNamespace()
7982
if namespace == "" {
@@ -84,6 +87,7 @@ func K8sObjectUUID(obj client.Object) (string, error) {
8487

8588
// K8sObjectUUIDUnsafe works like K8sObjectUUID, but panics instead of returning an error.
8689
// This should only be used in places where the input is guaranteed to be valid.
90+
// Deprecated: Use ObjectHashSHAKE128Base32 instead.
8791
func K8sObjectUUIDUnsafe(obj client.Object) string {
8892
uuid, err := K8sObjectUUID(obj)
8993
if err != nil {
@@ -113,3 +117,21 @@ func ObjectHashSHAKE128Base32(obj client.Object) string {
113117
}
114118
return NameHashSHAKE128Base32(namespace, name)
115119
}
120+
121+
// ShortenToXCharacters shortens the input string if it exceeds maxLen.
122+
// It uses NameHashSHAKE128Base32 to generate a hash which will replace the last few characters.
123+
func ShortenToXCharacters(input string, maxLen int) (string, error) {
124+
if len(input) <= maxLen {
125+
return input, nil
126+
}
127+
128+
hash := NameHashSHAKE128Base32(input)
129+
suffix := fmt.Sprintf("--%s", hash)
130+
trimLength := maxLen - len(suffix)
131+
132+
if trimLength <= 0 {
133+
return "", ErrMaxLenTooSmall
134+
}
135+
136+
return input[:trimLength] + suffix, nil
137+
}

pkg/controller/hash_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,3 +189,49 @@ func Test_ObjectHashSHAKE128Base32(t *testing.T) {
189189
})
190190
}
191191
}
192+
193+
func Test_ShortenToXCharacters(t *testing.T) {
194+
testCases := []struct {
195+
desc string
196+
input string
197+
maxLen int
198+
expected string
199+
expectedErr error
200+
}{
201+
{
202+
desc: "short string",
203+
input: "short",
204+
expected: "short",
205+
maxLen: 100,
206+
},
207+
{
208+
desc: "short string to trim",
209+
input: "short1234567",
210+
expected: "s--j5gore3p",
211+
maxLen: 11,
212+
},
213+
{
214+
desc: "maxLen too small",
215+
input: "shorter1234",
216+
maxLen: 10,
217+
expectedErr: ErrMaxLenTooSmall,
218+
},
219+
{
220+
desc: "long string",
221+
input: "this-is-a-very-a-very-a-very-long-string-that-is-over-63-characters",
222+
expected: "this-is-a-very-a-very-a-very-long-string-that-is-over--6reoyp5o",
223+
maxLen: 63,
224+
},
225+
}
226+
for _, tC := range testCases {
227+
t.Run(tC.desc, func(t *testing.T) {
228+
actual, err := ShortenToXCharacters(tC.input, tC.maxLen)
229+
if tC.expectedErr == nil {
230+
assert.Equal(t, tC.expected, actual)
231+
assert.LessOrEqual(t, len(actual), tC.maxLen)
232+
} else {
233+
assert.Equal(t, tC.expectedErr, err)
234+
}
235+
})
236+
}
237+
}

pkg/controller/utils.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const (
1515

1616
// K8sNameHash takes any number of string arguments and computes a hash out of it, which is then base32-encoded to be a valid DNS1123Subdomain k8s resource name
1717
// The arguments are joined with '/' before being hashed.
18+
// Deprecated: Use NameHashSHAKE128Base32 instead.
1819
func K8sNameHash(ids ...string) string {
1920
name := strings.Join(ids, "/")
2021
// since we are not worried about length-extension attacks (in fact we are not even using hashing for

0 commit comments

Comments
 (0)