From 4fa71288e60d6b829aa228c51abba0a61fc5aaa3 Mon Sep 17 00:00:00 2001 From: Sergey Vasilyev Date: Tue, 28 Apr 2020 12:57:52 +0200 Subject: [PATCH] Force annotations to end strictly with alphanumeric characters --- kopf/storage/progress.py | 5 +++-- tests/persistence/test_annotations_hashing.py | 16 ++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/kopf/storage/progress.py b/kopf/storage/progress.py index 22abd3d3..e5c9aa8b 100644 --- a/kopf/storage/progress.py +++ b/kopf/storage/progress.py @@ -232,13 +232,14 @@ def make_key(self, key: Union[str, handlers.HandlerId], max_length: int = 63) -> # K8s has a limitation of 63 chars per annotation/label key. # Force it to 63 chars by replacing the tail with a consistent hash (with full alphabet). + # Force it to end with alnums instead of altchars or trailing chars (K8s requirement). prefix = f'{self.prefix}/' if self.prefix else '' if len(safe_key) <= max_length - len(prefix): suffix = '' else: digest = hashlib.blake2b(safe_key.encode('utf-8'), digest_size=4).digest() - alnums = base64.b64encode(digest, altchars=b'-.').replace(b'=', b'-').decode('ascii') - suffix = f'-{alnums}' + alnums = base64.b64encode(digest, altchars=b'-.').decode('ascii') + suffix = f'-{alnums}'.rstrip('=-.') full_key = f'{prefix}{safe_key[:max_length - len(prefix) - len(suffix)]}{suffix}' return full_key diff --git a/tests/persistence/test_annotations_hashing.py b/tests/persistence/test_annotations_hashing.py index 11e76a41..98e3be2f 100644 --- a/tests/persistence/test_annotations_hashing.py +++ b/tests/persistence/test_annotations_hashing.py @@ -32,19 +32,19 @@ # The suffix itself (if appended) takes 9, so it is 30 left. The same math for no prefix. ['my-operator.example.com', 'x', 'my-operator.example.com/x'], ['my-operator.example.com', 'x' * 39, 'my-operator.example.com/' + 'x' * 39], - ['my-operator.example.com', 'x' * 40, 'my-operator.example.com/' + 'x' * 30 + '-tEokcg--'], - ['my-operator.example.com', 'y' * 40, 'my-operator.example.com/' + 'y' * 30 + '-VZlvhw--'], - ['my-operator.example.com', 'z' * 40, 'my-operator.example.com/' + 'z' * 30 + '-LlPQyA--'], + ['my-operator.example.com', 'x' * 40, 'my-operator.example.com/' + 'x' * 30 + 'xx-tEokcg'], + ['my-operator.example.com', 'y' * 40, 'my-operator.example.com/' + 'y' * 30 + 'yy-VZlvhw'], + ['my-operator.example.com', 'z' * 40, 'my-operator.example.com/' + 'z' * 30 + 'zz-LlPQyA'], [None, 'x', 'x'], [None, 'x' * 63, 'x' * 63], - [None, 'x' * 64, 'x' * 54 + '-SItAqA--'], - [None, 'y' * 64, 'y' * 54 + '-0d251g--'], - [None, 'z' * 64, 'z' * 54 + '-E7wvIA--'], + [None, 'x' * 64, 'x' * 54 + 'xx-SItAqA'], # base64: SItAqA== + [None, 'y' * 64, 'y' * 54 + 'yy-0d251g'], # base64: 0d251g== + [None, 'z' * 64, 'z' * 54 + 'zz-E7wvIA'], # base64: E7wvIA== # For special chars in base64 encoding ("+" and "/"), which are not compatible with K8s. # The numbers are found empirically so that both "/" and "+" are found in the base64'ed digest. - ['my-operator.example.com', 'fn' * 323, 'my-operator.example.com/' + 'fn' * 15 + '-Az-r.g--'], - [None, 'fn' * 323, 'fn' * 27 + '-Az-r.g--'], + ['my-operator.example.com', 'fn' * 323, 'my-operator.example.com/' + 'fn' * 15 + 'fn-Az-r.g'], + [None, 'fn' * 323, 'fn' * 27 + 'fn-Az-r.g'], # base64: Az-r.g== ])