certapi 1.1.6__tar.gz → 1.1.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. {certapi-1.1.6/src/certapi.egg-info → certapi-1.1.7}/PKG-INFO +2 -2
  2. {certapi-1.1.6 → certapi-1.1.7}/setup.py +2 -2
  3. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/client/renewal_manager.py +15 -12
  4. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/issuers/AcmeCertIssuer.py +1 -1
  5. {certapi-1.1.6 → certapi-1.1.7/src/certapi.egg-info}/PKG-INFO +2 -2
  6. certapi-1.1.7/src/certapi.egg-info/requires.txt +2 -0
  7. {certapi-1.1.6 → certapi-1.1.7}/tests/test_renewal_manager.py +16 -3
  8. certapi-1.1.6/src/certapi.egg-info/requires.txt +0 -2
  9. {certapi-1.1.6 → certapi-1.1.7}/MANIFEST.in +0 -0
  10. {certapi-1.1.6 → certapi-1.1.7}/README.md +0 -0
  11. {certapi-1.1.6 → certapi-1.1.7}/pyproject.toml +0 -0
  12. {certapi-1.1.6 → certapi-1.1.7}/setup.cfg +0 -0
  13. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/__init__.py +0 -0
  14. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/acme/Acme.py +0 -0
  15. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/acme/AcmeError.py +0 -0
  16. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/acme/Challenge.py +0 -0
  17. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/acme/Order.py +0 -0
  18. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/acme/__init__.py +0 -0
  19. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/acme/http.py +0 -0
  20. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/challenge_solver/ChallengeSolver.py +0 -0
  21. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/challenge_solver/FileSystemChallengeSolver.py +0 -0
  22. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/challenge_solver/InmemoryChallengeSolver.py +0 -0
  23. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/challenge_solver/__init__.py +0 -0
  24. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/challenge_solver/dns/__init__.py +0 -0
  25. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/challenge_solver/dns/cloudflare/__init__.py +0 -0
  26. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/challenge_solver/dns/cloudflare/cloudflare_challenge_solver.py +0 -0
  27. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/challenge_solver/dns/cloudflare/cloudflare_client.py +0 -0
  28. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/challenge_solver/dns/digitalocean/__init__.py +0 -0
  29. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/challenge_solver/dns/digitalocean/digitalocean_challenge_solver.py +0 -0
  30. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/challenge_solver/dns/digitalocean/digitalocean_client.py +0 -0
  31. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/cli.py +0 -0
  32. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/client/__init__.py +0 -0
  33. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/client/cert_manager_client.py +0 -0
  34. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/crypto/__init__.py +0 -0
  35. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/crypto/crypto.py +0 -0
  36. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/crypto/crypto_classes.py +0 -0
  37. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/domain_batching.py +0 -0
  38. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/errors.py +0 -0
  39. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/http/HttpClientBase.py +0 -0
  40. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/http/__init__.py +0 -0
  41. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/http/types.py +0 -0
  42. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/issuers/SelfCertIssuer.py +0 -0
  43. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/issuers/__init__.py +0 -0
  44. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/issuers/abstract_certissuer.py +0 -0
  45. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/keystore/FileSystemKeyStore.py +0 -0
  46. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/keystore/KeyStore.py +0 -0
  47. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/keystore/PostgresqlKeyStore.py +0 -0
  48. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/keystore/RemoteKeyStore.py +0 -0
  49. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/keystore/SqliteKeyStore.py +0 -0
  50. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/keystore/__init__.py +0 -0
  51. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/manager/__init__.py +0 -0
  52. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/manager/acme_cert_manager.py +0 -0
  53. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/server/__init__.py +0 -0
  54. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/server/api.py +0 -0
  55. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/server/cert_api.py +0 -0
  56. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/server/key_api.py +0 -0
  57. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/util.py +0 -0
  58. {certapi-1.1.6 → certapi-1.1.7}/src/certapi/utils.py +0 -0
  59. {certapi-1.1.6 → certapi-1.1.7}/src/certapi.egg-info/SOURCES.txt +0 -0
  60. {certapi-1.1.6 → certapi-1.1.7}/src/certapi.egg-info/dependency_links.txt +0 -0
  61. {certapi-1.1.6 → certapi-1.1.7}/src/certapi.egg-info/entry_points.txt +0 -0
  62. {certapi-1.1.6 → certapi-1.1.7}/src/certapi.egg-info/top_level.txt +0 -0
  63. {certapi-1.1.6 → certapi-1.1.7}/tests/test_acme_cert_manager_batching.py +0 -0
  64. {certapi-1.1.6 → certapi-1.1.7}/tests/test_acme_error_handling.py +0 -0
  65. {certapi-1.1.6 → certapi-1.1.7}/tests/test_cert_issuer_generic.py +0 -0
  66. {certapi-1.1.6 → certapi-1.1.7}/tests/test_certs_with_key_types.py +0 -0
  67. {certapi-1.1.6 → certapi-1.1.7}/tests/test_cli.py +0 -0
  68. {certapi-1.1.6 → certapi-1.1.7}/tests/test_domain_batching_boulder_cases.py +0 -0
  69. {certapi-1.1.6 → certapi-1.1.7}/tests/test_http_error_handling.py +0 -0
  70. {certapi-1.1.6 → certapi-1.1.7}/tests/test_keystores.py +0 -0
  71. {certapi-1.1.6 → certapi-1.1.7}/tests/test_obtain_interface.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: certapi
3
- Version: 1.1.6
3
+ Version: 1.1.7
4
4
  Summary: Python Package for managing keys, request SSL certificates from ACME.
5
5
  Home-page: https://github.com/mesudip/certapi
6
6
  Author: Sudip Bhattarai
@@ -10,7 +10,7 @@ Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Operating System :: OS Independent
11
11
  Requires-Python: >=3.6
12
12
  Description-Content-Type: text/markdown
13
- Requires-Dist: cryptography
13
+ Requires-Dist: cryptography>=39.0.0
14
14
  Requires-Dist: requests
15
15
  Dynamic: author
16
16
  Dynamic: author-email
@@ -2,11 +2,11 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="certapi",
5
- version="1.1.6",
5
+ version="1.1.7",
6
6
  packages=find_packages(where="src"),
7
7
  package_dir={"": "src"},
8
8
  install_requires=[
9
- "cryptography",
9
+ "cryptography>=39.0.0",
10
10
  "requests",
11
11
  ],
12
12
  include_package_data=True,
@@ -419,8 +419,8 @@ class RenewalManager:
419
419
  if (expiry - now).total_seconds() < due_window:
420
420
  due_domains.append(domain)
421
421
 
422
- for domain in due_domains:
423
- self._renew_domain(domain, now)
422
+ if due_domains:
423
+ self._renew_domains(due_domains, now)
424
424
 
425
425
  return len(due_domains)
426
426
 
@@ -463,10 +463,12 @@ class RenewalManager:
463
463
  self._cache[domain] = expiry
464
464
  self._lock.notify_all()
465
465
 
466
- def _renew_domain(self, domain: str, now: datetime):
467
- domain_had_cached_entry = False
466
+ def _renew_domains(self, domains: List[str], now: datetime):
467
+ domains_with_cached_entries = []
468
468
  with self._lock:
469
- domain_had_cached_entry = domain in self._cache
469
+ for domain in domains:
470
+ if domain in self._cache:
471
+ domains_with_cached_entries.append(domain)
470
472
 
471
473
  try:
472
474
  renew_threshold_days = self.cert_min_renew_threshold_secs // (24 * 3600)
@@ -475,7 +477,7 @@ class RenewalManager:
475
477
  "expiry_days": self.expiry_days,
476
478
  "renew_threshold_days": renew_threshold_days,
477
479
  "skip_failing": False,
478
- "batch_domains": self.batch_domains,
480
+ "batch_domains": True,
479
481
  "self_verify": self.self_verify,
480
482
  "country": self.country,
481
483
  "state": self.state,
@@ -485,7 +487,7 @@ class RenewalManager:
485
487
  }
486
488
  res = self._call_certificate_backend(
487
489
  self.cert_manager_client.obtain,
488
- [domain],
490
+ domains,
489
491
  obtain_options,
490
492
  )
491
493
  if res is None:
@@ -493,11 +495,12 @@ class RenewalManager:
493
495
  self._update_expiry_cache(res.issued + res.existing)
494
496
  except Exception as e:
495
497
  self._set_error(e)
496
- self._add_to_blacklist(domain, now)
497
- if domain_had_cached_entry or self._has_local_certificate(domain):
498
- self._schedule_existing_certificate_retry(domain, now)
499
- else:
500
- self._register_self_signed(domain)
498
+ for domain in domains:
499
+ self._add_to_blacklist(domain, now)
500
+ if domain in domains_with_cached_entries or self._has_local_certificate(domain):
501
+ self._schedule_existing_certificate_retry(domain, now)
502
+ else:
503
+ self._register_self_signed(domain)
501
504
 
502
505
  def _schedule_existing_certificate_retry(self, domain: str, now: datetime):
503
506
  retry_interval_seconds = min(self.renew_retry_interval_seconds, 24 * 3600)
@@ -95,7 +95,7 @@ class AcmeCertIssuer(CertIssuer):
95
95
  return order.get_certificate()
96
96
  return None
97
97
  elif order.status == "processing":
98
- return obtain_cert()
98
+ return obtain_cert(count - 1)
99
99
  return None # TODO: error throwing here
100
100
 
101
101
  return obtain_cert()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: certapi
3
- Version: 1.1.6
3
+ Version: 1.1.7
4
4
  Summary: Python Package for managing keys, request SSL certificates from ACME.
5
5
  Home-page: https://github.com/mesudip/certapi
6
6
  Author: Sudip Bhattarai
@@ -10,7 +10,7 @@ Classifier: License :: OSI Approved :: MIT License
10
10
  Classifier: Operating System :: OS Independent
11
11
  Requires-Python: >=3.6
12
12
  Description-Content-Type: text/markdown
13
- Requires-Dist: cryptography
13
+ Requires-Dist: cryptography>=39.0.0
14
14
  Requires-Dist: requests
15
15
  Dynamic: author
16
16
  Dynamic: author-email
@@ -0,0 +1,2 @@
1
+ cryptography>=39.0.0
2
+ requests
@@ -25,7 +25,7 @@ class DummyClient:
25
25
 
26
26
  def obtain(self, hosts, **kwargs):
27
27
  host = hosts[0] if isinstance(hosts, list) else hosts
28
- self.calls.append({"host": host, "kwargs": kwargs})
28
+ self.calls.append({"host": host, "hosts": hosts, "kwargs": kwargs})
29
29
  handler = self._handlers.get(host)
30
30
  if handler is None:
31
31
  return CertificateResponse()
@@ -47,12 +47,12 @@ class DummyClientWithObtain(DummyClient):
47
47
 
48
48
  def obtain(self, hosts, **kwargs):
49
49
  host = hosts[0] if isinstance(hosts, list) else hosts
50
- self.obtain_calls.append({"host": host, "kwargs": kwargs})
50
+ self.obtain_calls.append({"host": host, "hosts": hosts, "kwargs": kwargs})
51
51
  return super().obtain(hosts, **kwargs)
52
52
 
53
53
  def issue_certificate(self, hosts, **kwargs):
54
54
  host = hosts[0] if isinstance(hosts, list) else hosts
55
- self.issue_calls.append({"host": host, "kwargs": kwargs})
55
+ self.issue_calls.append({"host": host, "hosts": hosts, "kwargs": kwargs})
56
56
  return super().obtain(hosts, **kwargs)
57
57
 
58
58
 
@@ -702,3 +702,16 @@ def test_stop_does_not_wait_for_hung_remote_request_thread():
702
702
 
703
703
  assert not mgr._thread.is_alive()
704
704
  release.set()
705
+
706
+
707
+ def test_renewal_manager_batches_due_domains():
708
+ now = datetime(2026, 1, 1, tzinfo=UTC)
709
+ client = DummyClientWithObtain()
710
+ client.set_handler("domain1.com", CertificateResponse())
711
+
712
+ mgr = RenewalManager(client, renew_threshold_days=30, clock_fn=lambda: now, batch_domains=True)
713
+ mgr.update_watch_domains(["domain1.com", "domain2.com"])
714
+
715
+ assert len(client.obtain_calls) == 1
716
+ assert "domain1.com" in client.obtain_calls[0]["hosts"]
717
+ assert "domain2.com" in client.obtain_calls[0]["hosts"]
@@ -1,2 +0,0 @@
1
- cryptography
2
- requests
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes