Skip to content

Commit 79090a2

Browse files
Copilotpiraz
authored andcommitted
fix: Switch not_valid_after to not_valid_after_utc
Co-authored-by: szepeviktor <952007+szepeviktor@users.noreply.github.com> Refs: #137
1 parent c7a7957 commit 79090a2

File tree

3 files changed

+82
-2
lines changed

3 files changed

+82
-2
lines changed

automatoes/issue.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ def issue(server, paths, account, domains, key_size, key_file=None,
188188
certificate = load_pem_certificate(certificates[0])
189189

190190
# Print some neat info
191-
print(" Expires: {}".format(certificate.not_valid_after.strftime(
191+
print(" Expires: {}".format(certificate.not_valid_after_utc.strftime(
192192
EXPIRATION_FORMAT)))
193193
print(" SHA256: {}".format(binascii.hexlify(
194194
certificate.fingerprint(SHA256())).decode('ascii')))

tests/issue_test.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#!/usr/bin/env python
2+
#
3+
# Copyright 2019-2025 Flavio Garcia
4+
# Copyright 2016-2017 Veeti Paananen under MIT License
5+
#
6+
# Licensed under the Apache License, Version 2.0 (the "License");
7+
# you may not use this file except in compliance with the License.
8+
# You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
18+
import unittest
19+
from unittest.mock import patch, MagicMock
20+
from cryptography import x509
21+
from cryptography.hazmat.primitives import serialization, hashes
22+
from cryptography.hazmat.primitives.asymmetric import rsa
23+
import datetime
24+
import warnings
25+
26+
from automatoes.issue import EXPIRATION_FORMAT
27+
28+
29+
class IssueTestCase(unittest.TestCase):
30+
31+
def test_certificate_expiration_uses_utc_property(self):
32+
"""Test that certificate expiration formatting uses not_valid_after_utc."""
33+
# Generate a test certificate
34+
private_key = rsa.generate_private_key(
35+
public_exponent=65537,
36+
key_size=2048,
37+
)
38+
39+
subject = issuer = x509.Name([
40+
x509.NameAttribute(x509.NameOID.COUNTRY_NAME, 'US'),
41+
x509.NameAttribute(x509.NameOID.COMMON_NAME, 'test.example.com'),
42+
])
43+
44+
# Create expiration date in UTC
45+
expiration_date = datetime.datetime(2025, 12, 31, 23, 59, 59, tzinfo=datetime.timezone.utc)
46+
47+
cert = x509.CertificateBuilder().subject_name(
48+
subject
49+
).issuer_name(
50+
issuer
51+
).public_key(
52+
private_key.public_key()
53+
).serial_number(
54+
x509.random_serial_number()
55+
).not_valid_before(
56+
datetime.datetime.now()
57+
).not_valid_after(
58+
expiration_date
59+
).sign(private_key, hashes.SHA256())
60+
61+
# Test that not_valid_after_utc returns UTC-aware datetime
62+
self.assertIsNotNone(cert.not_valid_after_utc)
63+
self.assertIsNotNone(cert.not_valid_after_utc.tzinfo)
64+
65+
# Test that formatting works correctly with not_valid_after_utc
66+
formatted_expiration = cert.not_valid_after_utc.strftime(EXPIRATION_FORMAT)
67+
self.assertEqual(formatted_expiration, "2025-12-31")
68+
69+
# Test that not_valid_after (deprecated) produces warnings
70+
with warnings.catch_warnings(record=True) as w:
71+
warnings.simplefilter("always")
72+
_ = cert.not_valid_after
73+
# Check that a deprecation warning was issued
74+
self.assertTrue(len(w) > 0)
75+
self.assertTrue(any("deprecated" in str(warning.message).lower() for warning in w))
76+
77+
78+
if __name__ == "__main__":
79+
unittest.main()

tests/runtests.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@
1515
# limitations under the License.
1616

1717
import unittest
18-
from tests import crypto_test
18+
from tests import crypto_test, issue_test
1919

2020

2121
def suite():
2222
testLoader = unittest.TestLoader()
2323
alltests = unittest.TestSuite()
2424
alltests.addTests(testLoader.loadTestsFromModule(crypto_test))
25+
alltests.addTests(testLoader.loadTestsFromModule(issue_test))
2526
return alltests
2627

2728

0 commit comments

Comments
 (0)