diff --git a/CHANGELOG.md b/CHANGELOG.md index 59d5dec0e..68e92be14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ ## Release (2026-MM-DD) - `core`: + - [v0.4.0](core/CHANGELOG.md#v040) + - **Feature:** Add `KeyAuth.close()` to stop the background token refresh thread and its worker, so a discarded instance no longer keeps running and requesting tokens - [v0.3.1](core/CHANGELOG.md#v031) - **Fix:** Refresh access tokens five minutes before expiration instead of after, and wait for in-progress refreshes before authorizing requests - `alb`: diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index b41b2470c..e671d6cd4 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -1,3 +1,6 @@ +## v0.4.0 +- **Feature:** Add `KeyAuth.close()` to stop the background token refresh thread and its worker, so a discarded instance (for example after key rotation) no longer keeps running and requesting tokens + ## v0.3.1 - **Fix:** Refresh access tokens five minutes before expiration instead of after, and wait for in-progress refreshes before authorizing requests diff --git a/core/pyproject.toml b/core/pyproject.toml index 0bac65e7b..18350e95b 100644 --- a/core/pyproject.toml +++ b/core/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "stackit-core" -version = "v0.3.1" +version = "v0.4.0" description = "Core functionality for the STACKIT SDK for Python" authors = [{ name = "STACKIT Developer Tools", email = "developer-tools@stackit.cloud" }] requires-python = ">=3.10,<4.0" diff --git a/core/src/stackit/core/auth_methods/key_auth.py b/core/src/stackit/core/auth_methods/key_auth.py index 6f24eaff2..bb6da2c60 100644 --- a/core/src/stackit/core/auth_methods/key_auth.py +++ b/core/src/stackit/core/auth_methods/key_auth.py @@ -54,6 +54,8 @@ class KeyAuth(AuthBase): executor: ThreadPoolExecutor refresh_future: Optional[futures.Future] service_account_key: ServiceAccountKey + _stop: threading.Event + _refresh_thread: Optional[threading.Thread] def __init__( self, @@ -66,6 +68,8 @@ def __init__( self.executor = ThreadPoolExecutor(max_workers=1) self.access_token = None self.refresh_future = None + self._stop = threading.Event() + self._refresh_thread = None self.__create_initial_token() self.__fetch_token_from_endpoint() self.__start_token_refresh_task() @@ -92,6 +96,21 @@ def __call__(self, r: Request) -> Request: r.headers["Authorization"] = f"Bearer {self.access_token}" return r + def close(self) -> None: + """Stop the background token refresh and release its worker. + + Call this when the instance is no longer needed, for example after + replacing it during key rotation in a long-running process. Without it + the refresh thread keeps running and keeps requesting tokens. Safe to + call more than once. + """ + self._stop.set() + self.executor.shutdown(wait=False, cancel_futures=True) + atexit.unregister(self.__shutdown) + thread = self._refresh_thread + if thread is not None and thread is not threading.current_thread(): + thread.join() + def __create_initial_token(self) -> None: payload = { "iss": self.service_account_key.credentials.issuer, @@ -126,8 +145,7 @@ def __fetch_token_from_endpoint(self) -> None: def __start_token_refresh_task(self): def token_refresh_task(): - while True: - time.sleep(self.TOKEN_EXPIRY_CHECK_INTERVAL.total_seconds()) + while not self._stop.wait(self.TOKEN_EXPIRY_CHECK_INTERVAL.total_seconds()): with self.lock: if self.refresh_future is not None and self.refresh_future.done(): self.refresh_future.result() @@ -139,6 +157,7 @@ def token_refresh_task(): thread = threading.Thread(target=token_refresh_task) thread.daemon = True thread.start() + self._refresh_thread = thread def __refresh_token(self): with self.lock: diff --git a/core/tests/core/test_auth.py b/core/tests/core/test_auth.py index d73009f10..903e5755c 100644 --- a/core/tests/core/test_auth.py +++ b/core/tests/core/test_auth.py @@ -2,6 +2,9 @@ from pathlib import Path, PurePath from threading import Event, Lock, Thread +import time +from datetime import timedelta + import pytest import json import jwt @@ -382,3 +385,61 @@ def result(self): assert not call_thread.is_alive() assert request.headers["Authorization"] == f"Bearer {fresh_token}" + + +class TestKeyAuthClose: + """A discarded KeyAuth must be able to stop its background token refresh.""" + + @staticmethod + def _make_auth(service_account_key_file_json, mock_post, access_token): + service_account_key = ServiceAccountKey.model_validate_json(service_account_key_file_json) + service_account_key.credentials.private_key = "test-private-key" + response = Mock() + response.raise_for_status.return_value = None + response.json.return_value = { + "access_token": access_token, + "refresh_token": jwt.encode({"exp": 4102444800}, "secret", algorithm="HS256"), + } + mock_post.return_value = response + return KeyAuth(service_account_key) + + def test_close_stops_the_refresh_thread_and_further_token_requests(self, service_account_key_file_json): + def set_initial_token(auth): + auth.initial_token = "test-initial-token" + + expired = jwt.encode({"exp": 1}, "secret", algorithm="HS256") + with ( + patch.object(KeyAuth, "_KeyAuth__create_initial_token", new=set_initial_token), + patch.object(KeyAuth, "TOKEN_EXPIRY_CHECK_INTERVAL", timedelta(milliseconds=10)), + patch("requests.post") as mock_post, + ): + # An access token that is always expired keeps the refresh loop busy. + auth = self._make_auth(service_account_key_file_json, mock_post, expired) + thread = auth._refresh_thread + assert thread is not None and thread.is_alive() + + auth.close() + + assert not thread.is_alive() + requests_after_close = mock_post.call_count + time.sleep(0.1) # ten refresh intervals + assert mock_post.call_count == requests_after_close + + def test_close_is_idempotent(self, service_account_key_file_json): + def set_initial_token(auth): + auth.initial_token = "test-initial-token" + + valid = jwt.encode({"exp": 4102444800}, "secret", algorithm="HS256") + with ( + patch.object(KeyAuth, "_KeyAuth__create_initial_token", new=set_initial_token), + patch("requests.post") as mock_post, + patch("stackit.core.auth_methods.key_auth.atexit") as mock_atexit, + ): + auth = self._make_auth(service_account_key_file_json, mock_post, valid) + + auth.close() + auth.close() + + assert not auth._refresh_thread.is_alive() + assert auth.executor._shutdown + mock_atexit.unregister.assert_called_with(auth._KeyAuth__shutdown) diff --git a/core/uv.lock b/core/uv.lock index 59c9b39f5..d89822b6a 100644 --- a/core/uv.lock +++ b/core/uv.lock @@ -998,7 +998,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { editable = "." } dependencies = [ { name = "cryptography" }, diff --git a/services/alb/uv.lock b/services/alb/uv.lock index 06a74dd07..dbf2c3466 100644 --- a/services/alb/uv.lock +++ b/services/alb/uv.lock @@ -1071,7 +1071,7 @@ dev = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/albwaf/uv.lock b/services/albwaf/uv.lock index 93afcc31c..3568caa14 100644 --- a/services/albwaf/uv.lock +++ b/services/albwaf/uv.lock @@ -413,7 +413,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1071,7 +1071,7 @@ dev = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/authorization/uv.lock b/services/authorization/uv.lock index 2b11f3ab9..56856106f 100644 --- a/services/authorization/uv.lock +++ b/services/authorization/uv.lock @@ -413,7 +413,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1071,7 +1071,7 @@ dev = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/automation/uv.lock b/services/automation/uv.lock index 51065ddd9..7a95cd302 100644 --- a/services/automation/uv.lock +++ b/services/automation/uv.lock @@ -486,7 +486,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1182,7 +1182,7 @@ dev = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/cdn/uv.lock b/services/cdn/uv.lock index 0fcb8df92..b83bcc386 100644 --- a/services/cdn/uv.lock +++ b/services/cdn/uv.lock @@ -1071,7 +1071,7 @@ dev = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/certificates/uv.lock b/services/certificates/uv.lock index 0e6dcb429..65505ca36 100644 --- a/services/certificates/uv.lock +++ b/services/certificates/uv.lock @@ -1071,7 +1071,7 @@ dev = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/cost/uv.lock b/services/cost/uv.lock index d27805c2f..43480a31b 100644 --- a/services/cost/uv.lock +++ b/services/cost/uv.lock @@ -413,7 +413,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/dns/uv.lock b/services/dns/uv.lock index fae03b903..1af6db30c 100644 --- a/services/dns/uv.lock +++ b/services/dns/uv.lock @@ -413,7 +413,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/dremio/uv.lock b/services/dremio/uv.lock index d2fac65f5..d4114c971 100644 --- a/services/dremio/uv.lock +++ b/services/dremio/uv.lock @@ -489,7 +489,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.12'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1095,7 +1095,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/edge/uv.lock b/services/edge/uv.lock index ea1773bc8..c0c94c01a 100644 --- a/services/edge/uv.lock +++ b/services/edge/uv.lock @@ -413,7 +413,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/git/uv.lock b/services/git/uv.lock index c2bc2b25d..2d3d3cfcf 100644 --- a/services/git/uv.lock +++ b/services/git/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/iaas/uv.lock b/services/iaas/uv.lock index a9d3fddec..80e946d0a 100644 --- a/services/iaas/uv.lock +++ b/services/iaas/uv.lock @@ -413,7 +413,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/intake/uv.lock b/services/intake/uv.lock index 465b0c0e5..cfdce7ae3 100644 --- a/services/intake/uv.lock +++ b/services/intake/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/kms/uv.lock b/services/kms/uv.lock index c0c9b18a6..7d893556c 100644 --- a/services/kms/uv.lock +++ b/services/kms/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/loadbalancer/uv.lock b/services/loadbalancer/uv.lock index 2d8c73a88..616249c95 100644 --- a/services/loadbalancer/uv.lock +++ b/services/loadbalancer/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/logme/uv.lock b/services/logme/uv.lock index c5635e63e..63002023c 100644 --- a/services/logme/uv.lock +++ b/services/logme/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/logs/uv.lock b/services/logs/uv.lock index eef5e301b..f53524b91 100644 --- a/services/logs/uv.lock +++ b/services/logs/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/mariadb/uv.lock b/services/mariadb/uv.lock index 874a51983..1426a7854 100644 --- a/services/mariadb/uv.lock +++ b/services/mariadb/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/modelexperiments/uv.lock b/services/modelexperiments/uv.lock index 628a40716..bc053dbe0 100644 --- a/services/modelexperiments/uv.lock +++ b/services/modelexperiments/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/modelserving/uv.lock b/services/modelserving/uv.lock index 1cde4b8a5..5a9e72650 100644 --- a/services/modelserving/uv.lock +++ b/services/modelserving/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/mongodbflex/uv.lock b/services/mongodbflex/uv.lock index 74e320b9b..fa69e4771 100644 --- a/services/mongodbflex/uv.lock +++ b/services/mongodbflex/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/objectstorage/uv.lock b/services/objectstorage/uv.lock index 12e62cdbd..84aff6e25 100644 --- a/services/objectstorage/uv.lock +++ b/services/objectstorage/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/observability/uv.lock b/services/observability/uv.lock index bc307ea48..5efd5e10b 100644 --- a/services/observability/uv.lock +++ b/services/observability/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/opensearch/uv.lock b/services/opensearch/uv.lock index bdfb41ae5..dc1862818 100644 --- a/services/opensearch/uv.lock +++ b/services/opensearch/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/postgresflex/uv.lock b/services/postgresflex/uv.lock index 8c13cf537..f4936e99d 100644 --- a/services/postgresflex/uv.lock +++ b/services/postgresflex/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/rabbitmq/uv.lock b/services/rabbitmq/uv.lock index 1493eadb5..3c522806d 100644 --- a/services/rabbitmq/uv.lock +++ b/services/rabbitmq/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/redis/uv.lock b/services/redis/uv.lock index 5788a1a0b..66b0fbe07 100644 --- a/services/redis/uv.lock +++ b/services/redis/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/resourcemanager/uv.lock b/services/resourcemanager/uv.lock index 93a9a963b..20d6f311c 100644 --- a/services/resourcemanager/uv.lock +++ b/services/resourcemanager/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/runcommand/uv.lock b/services/runcommand/uv.lock index fe0e11c84..582521303 100644 --- a/services/runcommand/uv.lock +++ b/services/runcommand/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/scf/uv.lock b/services/scf/uv.lock index 7d58434c1..adf8f2adf 100644 --- a/services/scf/uv.lock +++ b/services/scf/uv.lock @@ -413,7 +413,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/secretsmanager/uv.lock b/services/secretsmanager/uv.lock index 1ba485e26..cd45ee1dc 100644 --- a/services/secretsmanager/uv.lock +++ b/services/secretsmanager/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/serverbackup/uv.lock b/services/serverbackup/uv.lock index 01176895e..c80f79760 100644 --- a/services/serverbackup/uv.lock +++ b/services/serverbackup/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/serverupdate/uv.lock b/services/serverupdate/uv.lock index 9329b51f5..5e9c3dabf 100644 --- a/services/serverupdate/uv.lock +++ b/services/serverupdate/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/serviceaccount/uv.lock b/services/serviceaccount/uv.lock index be1b66b7d..755051a52 100644 --- a/services/serviceaccount/uv.lock +++ b/services/serviceaccount/uv.lock @@ -413,7 +413,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/serviceenablement/uv.lock b/services/serviceenablement/uv.lock index 4c0813612..e89cb3377 100644 --- a/services/serviceenablement/uv.lock +++ b/services/serviceenablement/uv.lock @@ -413,7 +413,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/sfs/uv.lock b/services/sfs/uv.lock index 31e0646de..58e368caa 100644 --- a/services/sfs/uv.lock +++ b/services/sfs/uv.lock @@ -413,7 +413,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/ske/uv.lock b/services/ske/uv.lock index 2cec1e4ff..7ad20cec6 100644 --- a/services/ske/uv.lock +++ b/services/ske/uv.lock @@ -413,7 +413,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/sqlserverflex/uv.lock b/services/sqlserverflex/uv.lock index 9b72fe075..1af7b3c60 100644 --- a/services/sqlserverflex/uv.lock +++ b/services/sqlserverflex/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/stackitmarketplace/uv.lock b/services/stackitmarketplace/uv.lock index 19cb79c4a..40507ebc1 100644 --- a/services/stackitmarketplace/uv.lock +++ b/services/stackitmarketplace/uv.lock @@ -413,7 +413,7 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/telemetrylink/uv.lock b/services/telemetrylink/uv.lock index bd093d20c..caf801cc4 100644 --- a/services/telemetrylink/uv.lock +++ b/services/telemetrylink/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/telemetryrouter/uv.lock b/services/telemetryrouter/uv.lock index 80859b4e0..95bfa548c 100644 --- a/services/telemetryrouter/uv.lock +++ b/services/telemetryrouter/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/ufw/uv.lock b/services/ufw/uv.lock index 62a341081..ff8fa3d3e 100644 --- a/services/ufw/uv.lock +++ b/services/ufw/uv.lock @@ -1130,7 +1130,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/valkey/uv.lock b/services/valkey/uv.lock index 90c7f631b..03f7338e3 100644 --- a/services/valkey/uv.lock +++ b/services/valkey/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" }, diff --git a/services/vpn/uv.lock b/services/vpn/uv.lock index 56ec5692a..66b0bbdfb 100644 --- a/services/vpn/uv.lock +++ b/services/vpn/uv.lock @@ -1019,7 +1019,7 @@ wheels = [ [[package]] name = "stackit-core" -version = "0.3.1" +version = "0.4.0" source = { directory = "../../core" } dependencies = [ { name = "cryptography" },