From 545bf5af56433140e3b6efd89b5b81ca606b6b4a Mon Sep 17 00:00:00 2001 From: Edda Date: Tue, 16 Sep 2025 18:21:05 +0200 Subject: [PATCH 1/3] fix: server certificate timestamps `datetime.now()` returns a `datetime` in the local timezone, but `x509.not_valid_before` expects a `datetime` in UTC (and does not validate this). This causes the self-signed certificate to be not yet valid if the system timezone has a positive offset from UTC. --- tf/runner.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tf/runner.py b/tf/runner.py index baa99c7..fa3a75e 100644 --- a/tf/runner.py +++ b/tf/runner.py @@ -238,7 +238,7 @@ def _self_signed_cert() -> Tuple[bytes, Any]: ) name = x509.Name([x509.NameAttribute(x509.NameOID.COMMON_NAME, "localhost")]) - now = datetime.now() + now = datetime.now(tz.utc) # With subject alternative names certificate = ( From 1582c3f2e2f03f82721a27a2d3e509dc1c754226 Mon Sep 17 00:00:00 2001 From: Edda Date: Tue, 16 Sep 2025 18:26:06 +0200 Subject: [PATCH 2/3] Update CHANGELOG.md --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index a22f49c..142a053 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **Tutorial**: - Added a tutorial to the documentation to help new users get started with writing a provider using `tf`. +### Fixed + +- Fixed the gRPC server self-signed certificate being generated with `not_valid_before` in the future + - This was caused by generating a `datetime` in the local timezone, but `x509` treating it as UTC + ## 1.1.0 ### Added From b0b04afe4596011dc22326c038d3f08a1686ec73 Mon Sep 17 00:00:00 2001 From: Hunter Fernandes Date: Tue, 16 Sep 2025 17:22:56 -0700 Subject: [PATCH 3/3] Fix unset variable reference --- tf/runner.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tf/runner.py b/tf/runner.py index fa3a75e..0a5f63a 100644 --- a/tf/runner.py +++ b/tf/runner.py @@ -197,6 +197,8 @@ def _get_cert_cache_path() -> Path: def _self_signed_cert() -> Tuple[bytes, Any]: """Generate or load cached keypair and cert, return a server credentials object""" # Lazy load expensive cryptography imports + from datetime import timezone + import grpc from cryptography import x509 from cryptography.hazmat.primitives import hashes, serialization @@ -213,10 +215,8 @@ def _self_signed_cert() -> Tuple[bytes, Any]: # Check if certificate is still valid cert_pem = cached["cert_pem"].encode() cert = x509.load_pem_x509_certificate(cert_pem) - # Compare UTC times - from datetime import timezone as tz - if cert.not_valid_after_utc > datetime.now(tz.utc): + if cert.not_valid_after_utc > datetime.now(timezone.utc): # Certificate is still valid, use cached version private_key_pem = cached["key_pem"].encode() cert_chain = base64.b64decode(cached["cert_chain"]) @@ -238,7 +238,7 @@ def _self_signed_cert() -> Tuple[bytes, Any]: ) name = x509.Name([x509.NameAttribute(x509.NameOID.COMMON_NAME, "localhost")]) - now = datetime.now(tz.utc) + now = datetime.now(timezone.utc) # With subject alternative names certificate = (