From f82530d8c0b8744081b2c2ea838c355906247a09 Mon Sep 17 00:00:00 2001 From: alexzorin Date: Tue, 26 Jul 2022 06:43:49 +1000 Subject: [PATCH 01/18] letstest: replace ubuntu 21.10 with 22.04 (#9364) as ubuntu 21.10 is now EOL --- letstest/targets/targets.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/letstest/targets/targets.yaml b/letstest/targets/targets.yaml index 1812b3645..a11452f32 100644 --- a/letstest/targets/targets.yaml +++ b/letstest/targets/targets.yaml @@ -6,8 +6,8 @@ targets: #----------------------------------------------------------------------------- #Ubuntu - - ami: ami-0c2d5393cb5b518f6 - name: ubuntu21.10 + - ami: ami-051dcca84f1edfff1 + name: ubuntu22.04 type: ubuntu virt: hvm user: ubuntu From 495b97aafe3d4b2f7c9f7919df401cc20bd4ba50 Mon Sep 17 00:00:00 2001 From: Preston Locke Date: Tue, 26 Jul 2022 18:03:53 -0500 Subject: [PATCH 02/18] Clarify in docs that deletion does not revoke (#9348) * Clarify in docs that deletion does not revoke * Add myself to AUTHORS.md * Move new paragraph below first note and change its wording --- AUTHORS.md | 1 + certbot/docs/using.rst | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/AUTHORS.md b/AUTHORS.md index 95e63459b..64f60a278 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -215,6 +215,7 @@ Authors * [Pierre Jaury](https://github.com/kaiyou) * [Piotr Kasprzyk](https://github.com/kwadrat) * [Prayag Verma](https://github.com/pra85) +* [Preston Locke](https://github.com/Preston12321) * [Rasesh Patel](https://github.com/raspat1) * [Reinaldo de Souza Jr](https://github.com/juniorz) * [Remi Rampin](https://github.com/remram44) diff --git a/certbot/docs/using.rst b/certbot/docs/using.rst index c4f55bc02..38aaf4ff4 100644 --- a/certbot/docs/using.rst +++ b/certbot/docs/using.rst @@ -558,6 +558,11 @@ If you need to delete a certificate, use the ``delete`` subcommand. .. note:: Read this and the `Safely deleting certificates`_ sections carefully. This is an irreversible operation and must be done with care. +Certbot does not automatically revoke a certificate before deleting it. If you're no longer using a certificate and don't +plan to use it anywhere else, you may want to follow the instructions in `Revoking certificates`_ instead. Generally, there's +no need to revoke a certificate if its private key has not been compromised, but you may still receive expiration emails +from Let's Encrypt unless you revoke. + .. note:: Do not manually delete certificate files from inside ``/etc/letsencrypt/``. Always use the ``delete`` subcommand. A certificate may be deleted by providing its name with ``--cert-name``. \ From e9e7a69c7bb5cdac8215692d4bda9a661c0189c1 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 28 Jul 2022 13:28:36 -0700 Subject: [PATCH 03/18] Update Azure Docker docs (#9363) * describe docker access token more * Remove extra spaces Co-authored-by: ohemorange Co-authored-by: ohemorange --- .../templates/stages/deploy-stage.yml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/.azure-pipelines/templates/stages/deploy-stage.yml b/.azure-pipelines/templates/stages/deploy-stage.yml index 88aeab60e..424ffed10 100644 --- a/.azure-pipelines/templates/stages/deploy-stage.yml +++ b/.azure-pipelines/templates/stages/deploy-stage.yml @@ -96,11 +96,16 @@ stages: # which was created by following the instructions at # https://docs.microsoft.com/en-us/azure/devops/pipelines/library/service-endpoints?view=azure-devops&tabs=yaml#sep-docreg. # The name given to this service account must match the value - # given to containerRegistry below. "Grant access to all - # pipelines" should also be checked. To revoke these - # credentials, we can change the password on the certbotbot - # Docker Hub account or remove the account from the - # Certbot organization on Docker Hub. + # given to containerRegistry below. The authentication used when + # creating this service account was a personal access token + # rather than a password to bypass 2FA. When Brad set this up, + # Azure Pipelines failed to verify the credentials with an error + # like "access is forbidden with a JWT issued from a personal + # access token", but after saving them without verification, the + # access token worked when the pipeline actually ran. "Grant + # access to all pipelines" should also be checked on the service + # account. The access token can be deleted on Docker Hub if + # these credentials need to be revoked. containerRegistry: docker-hub displayName: Login to Docker Hub - bash: set -e && tools/docker/deploy.sh $(dockerTag) $DOCKER_ARCH From 42a4d30267c731b80fe73c1d38add046d0bd0899 Mon Sep 17 00:00:00 2001 From: alexzorin Date: Fri, 29 Jul 2022 10:26:12 +1000 Subject: [PATCH 04/18] deps: remove pyjwt dependency (#9337) * deps: remove pyjwt dependency * pinning: strip extras from dependencies `poetry export` outputs in requirements.txt format, which is now apparently producing "dep[extra]==...". We are using this output as the constraints file for pip and pip's new resolver does not permit extras in the constraints file. This change filters out the extras specifiers. * repin current dependencies * fix new pylint complaints * silence lint about distutils.version We have already deprecated the function and it'll be removed in 2.0. * docs: set sphinx language to 'en' this is emitting a warning and failing the build * Revert "pinning: strip extras from dependencies" This reverts commit 11268fd23160ac53fd8dad7a2ff15e453678e159. * pin poetry back to avoid extras issue * repin * fix new mypy complaints in acme/ --- acme/acme/challenges.py | 2 +- acme/acme/crypto_util.py | 20 +- acme/acme/standalone.py | 17 +- acme/tests/challenges_test.py | 4 +- .../certbot_tests/assertions.py | 4 +- .../utils/acme_server.py | 15 +- .../_internal/dns_route53.py | 3 +- certbot/certbot/_internal/lock.py | 6 +- certbot/certbot/achallenges.py | 4 +- certbot/certbot/plugins/dns_test_common.py | 2 - .../plugins/dns_test_common_lexicon.py | 1 - certbot/certbot/util.py | 4 +- certbot/docs/conf.py | 2 +- tools/pinning/current/pyproject.toml | 9 +- tools/requirements.txt | 275 +++++++++--------- 15 files changed, 188 insertions(+), 180 deletions(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index 9000b370a..91c3e6f24 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -408,7 +408,7 @@ class TLSALPN01Response(KeyAuthorizationChallengeResponse): """ ID_PE_ACME_IDENTIFIER_V1 = b"1.3.6.1.5.5.7.1.30.1" - ACME_TLS_1_PROTOCOL = "acme-tls/1" + ACME_TLS_1_PROTOCOL = b"acme-tls/1" @property def h(self) -> bytes: diff --git a/acme/acme/crypto_util.py b/acme/acme/crypto_util.py index 956366469..754f70e46 100644 --- a/acme/acme/crypto_util.py +++ b/acme/acme/crypto_util.py @@ -11,6 +11,7 @@ from typing import Callable from typing import List from typing import Mapping from typing import Optional +from typing import Sequence from typing import Set from typing import Tuple from typing import Union @@ -39,7 +40,9 @@ class _DefaultCertSelection: def __call__(self, connection: SSL.Connection) -> Optional[Tuple[crypto.PKey, crypto.X509]]: server_name = connection.get_servername() - return self.certs.get(server_name, None) + if server_name: + return self.certs.get(server_name, None) + return None # pragma: no cover class SSLSocket: # pylint: disable=too-few-public-methods @@ -60,7 +63,8 @@ class SSLSocket: # pylint: disable=too-few-public-methods method: int = _DEFAULT_SSL_METHOD, alpn_selection: Optional[Callable[[SSL.Connection, List[bytes]], bytes]] = None, cert_selection: Optional[Callable[[SSL.Connection], - Tuple[crypto.PKey, crypto.X509]]] = None + Optional[Tuple[crypto.PKey, + crypto.X509]]]] = None ) -> None: self.sock = sock self.alpn_selection = alpn_selection @@ -71,8 +75,8 @@ class SSLSocket: # pylint: disable=too-few-public-methods raise ValueError("Both cert_selection and certs specified.") actual_cert_selection: Union[_DefaultCertSelection, Optional[Callable[[SSL.Connection], - Tuple[crypto.PKey, - crypto.X509]]]] = cert_selection + Optional[Tuple[crypto.PKey, + crypto.X509]]]]] = cert_selection if actual_cert_selection is None: actual_cert_selection = _DefaultCertSelection(certs if certs else {}) self.cert_selection = actual_cert_selection @@ -157,7 +161,7 @@ class SSLSocket: # pylint: disable=too-few-public-methods def probe_sni(name: bytes, host: bytes, port: int = 443, timeout: int = 300, # pylint: disable=too-many-arguments method: int = _DEFAULT_SSL_METHOD, source_address: Tuple[str, int] = ('', 0), - alpn_protocols: Optional[List[str]] = None) -> crypto.X509: + alpn_protocols: Optional[Sequence[bytes]] = None) -> crypto.X509: """Probe SNI server for SSL certificate. :param bytes name: Byte string to send as the server name in the @@ -170,7 +174,7 @@ def probe_sni(name: bytes, host: bytes, port: int = 443, timeout: int = 300, # of source interface). See `socket.creation_connection` for more info. Available only in Python 2.7+. :param alpn_protocols: Protocols to request using ALPN. - :type alpn_protocols: `list` of `str` + :type alpn_protocols: `Sequence` of `bytes` :raises acme.errors.Error: In case of any problems. @@ -207,7 +211,9 @@ def probe_sni(name: bytes, host: bytes, port: int = 443, timeout: int = 300, # client_ssl.shutdown() except SSL.Error as error: raise errors.Error(error) - return client_ssl.get_peer_certificate() + cert = client_ssl.get_peer_certificate() + assert cert # Appease mypy. We would have crashed out by now if there was no certificate. + return cert def make_csr(private_key_pem: bytes, domains: Optional[Union[Set[str], List[str]]] = None, diff --git a/acme/acme/standalone.py b/acme/acme/standalone.py index a23f6d603..62174813f 100644 --- a/acme/acme/standalone.py +++ b/acme/acme/standalone.py @@ -46,10 +46,12 @@ class TLSServer(socketserver.TCPServer): method=self.method)) def _cert_selection(self, connection: SSL.Connection - ) -> Tuple[crypto.PKey, crypto.X509]: # pragma: no cover + ) -> Optional[Tuple[crypto.PKey, crypto.X509]]: # pragma: no cover """Callback selecting certificate for connection.""" server_name = connection.get_servername() - return self.certs.get(server_name, None) + if server_name: + return self.certs.get(server_name, None) + return None def server_bind(self) -> None: self._wrap_sock() @@ -151,7 +153,7 @@ class TLSALPN01Server(TLSServer, ACMEServerMixin): def __init__(self, server_address: Tuple[str, int], certs: List[Tuple[crypto.PKey, crypto.X509]], - challenge_certs: Mapping[str, Tuple[crypto.PKey, crypto.X509]], + challenge_certs: Mapping[bytes, Tuple[crypto.PKey, crypto.X509]], ipv6: bool = False) -> None: # We don't need to implement a request handler here because the work # (including logging) is being done by wrapped socket set up in the @@ -161,7 +163,8 @@ class TLSALPN01Server(TLSServer, ACMEServerMixin): ipv6=ipv6) self.challenge_certs = challenge_certs - def _cert_selection(self, connection: SSL.Connection) -> Tuple[crypto.PKey, crypto.X509]: + def _cert_selection(self, connection: SSL.Connection) -> Optional[Tuple[crypto.PKey, + crypto.X509]]: # TODO: We would like to serve challenge cert only if asked for it via # ALPN. To do this, we need to retrieve the list of protos from client # hello, but this is currently impossible with openssl [0], and ALPN @@ -170,8 +173,10 @@ class TLSALPN01Server(TLSServer, ACMEServerMixin): # handshake in alpn_selection() if ALPN protos are not what we expect. # [0] https://github.com/openssl/openssl/issues/4952 server_name = connection.get_servername() - logger.debug("Serving challenge cert for server name %s", server_name) - return self.challenge_certs[server_name] + if server_name: + logger.debug("Serving challenge cert for server name %s", server_name) + return self.challenge_certs[server_name] + return None # pragma: no cover def _alpn_selection(self, _connection: SSL.Connection, alpn_protos: List[bytes]) -> bytes: """Callback to select alpn protocol.""" diff --git a/acme/tests/challenges_test.py b/acme/tests/challenges_test.py index d7815a6c3..36cd1e376 100644 --- a/acme/tests/challenges_test.py +++ b/acme/tests/challenges_test.py @@ -328,12 +328,12 @@ class TLSALPN01ResponseTest(unittest.TestCase): mock_gethostbyname.assert_called_once_with('foo.com') mock_probe_sni.assert_called_once_with( host=b'127.0.0.1', port=self.response.PORT, name=b'foo.com', - alpn_protocols=['acme-tls/1']) + alpn_protocols=[b'acme-tls/1']) self.response.probe_cert('foo.com', host='8.8.8.8') mock_probe_sni.assert_called_with( host=b'8.8.8.8', port=mock.ANY, name=b'foo.com', - alpn_protocols=['acme-tls/1']) + alpn_protocols=[b'acme-tls/1']) @mock.patch('acme.challenges.TLSALPN01Response.probe_cert') def test_simple_verify_false_on_probe_error(self, mock_probe_cert): diff --git a/certbot-ci/certbot_integration_tests/certbot_tests/assertions.py b/certbot-ci/certbot_integration_tests/certbot_tests/assertions.py index 3650f64f0..3563b30af 100644 --- a/certbot-ci/certbot_integration_tests/certbot_tests/assertions.py +++ b/certbot-ci/certbot_integration_tests/certbot_tests/assertions.py @@ -125,7 +125,7 @@ def assert_equals_world_read_permissions(file1: str, file2: str) -> None: mode_file1 = os.stat(file1).st_mode & 0o004 mode_file2 = os.stat(file2).st_mode & 0o004 else: - everybody = win32security.ConvertStringSidToSid(EVERYBODY_SID) + everybody = win32security.ConvertStringSidToSid(EVERYBODY_SID) # pylint: disable=used-before-assignment security1 = win32security.GetFileSecurity(file1, win32security.DACL_SECURITY_INFORMATION) dacl1 = security1.GetSecurityDescriptorDacl() @@ -135,7 +135,7 @@ def assert_equals_world_read_permissions(file1: str, file2: str) -> None: 'TrusteeType': win32security.TRUSTEE_IS_USER, 'Identifier': everybody, }) - mode_file1 = mode_file1 & ntsecuritycon.FILE_GENERIC_READ + mode_file1 = mode_file1 & ntsecuritycon.FILE_GENERIC_READ # pylint: disable=used-before-assignment security2 = win32security.GetFileSecurity(file2, win32security.DACL_SECURITY_INFORMATION) dacl2 = security2.GetSecurityDescriptorDacl() diff --git a/certbot-ci/certbot_integration_tests/utils/acme_server.py b/certbot-ci/certbot_integration_tests/utils/acme_server.py index 9e56e3036..8994d0ef0 100755 --- a/certbot-ci/certbot_integration_tests/utils/acme_server.py +++ b/certbot-ci/certbot_integration_tests/utils/acme_server.py @@ -133,18 +133,9 @@ class ACMEServer: acme_xdist['directory_url'] = BOULDER_V2_DIRECTORY_URL acme_xdist['challtestsrv_url'] = BOULDER_V2_CHALLTESTSRV_URL - acme_xdist['http_port'] = { - node: port for (node, port) in # pylint: disable=unnecessary-comprehension - zip(nodes, range(5200, 5200 + len(nodes))) - } - acme_xdist['https_port'] = { - node: port for (node, port) in # pylint: disable=unnecessary-comprehension - zip(nodes, range(5100, 5100 + len(nodes))) - } - acme_xdist['other_port'] = { - node: port for (node, port) in # pylint: disable=unnecessary-comprehension - zip(nodes, range(5300, 5300 + len(nodes))) - } + acme_xdist['http_port'] = dict(zip(nodes, range(5200, 5200 + len(nodes)))) + acme_xdist['https_port'] = dict(zip(nodes, range(5100, 5100 + len(nodes)))) + acme_xdist['other_port'] = dict(zip(nodes, range(5300, 5300 + len(nodes)))) self.acme_xdist = acme_xdist diff --git a/certbot-dns-route53/certbot_dns_route53/_internal/dns_route53.py b/certbot-dns-route53/certbot_dns_route53/_internal/dns_route53.py index cbe22271f..fc2fe5821 100644 --- a/certbot-dns-route53/certbot_dns_route53/_internal/dns_route53.py +++ b/certbot-dns-route53/certbot_dns_route53/_internal/dns_route53.py @@ -38,7 +38,8 @@ class Authenticator(dns_common.DNSAuthenticator): def __init__(self, *args: Any, **kwargs: Any) -> None: super().__init__(*args, **kwargs) self.r53 = boto3.client("route53") - self._resource_records: DefaultDict[str, List[Dict[str, str]]] = collections.defaultdict(list) + self._resource_records: DefaultDict[str, List[Dict[str, str]]] = \ + collections.defaultdict(list) def more_info(self) -> str: return "Solve a DNS01 challenge using AWS Route53" diff --git a/certbot/certbot/_internal/lock.py b/certbot/certbot/_internal/lock.py index 95c44856f..960be4346 100644 --- a/certbot/certbot/_internal/lock.py +++ b/certbot/certbot/_internal/lock.py @@ -194,7 +194,7 @@ class _WindowsLockMechanism(_BaseLockMechanism): low level APIs, and Python does not do it. As of Python 3.7 and below, Python developers state that deleting a file opened by a process from another process is not possible with os.open and io.open. - Consequently, mscvrt.locking is sufficient to obtain an effective lock, and the race + Consequently, msvcrt.locking is sufficient to obtain an effective lock, and the race condition encountered on Linux is not possible on Windows, leading to a simpler workflow. """ def acquire(self) -> None: @@ -209,7 +209,7 @@ class _WindowsLockMechanism(_BaseLockMechanism): # This "type: ignore" is currently needed because msvcrt methods # are only defined on Windows. See # https://github.com/python/typeshed/blob/16ae4c61201cd8b96b8b22cdfb2ab9e89ba5bcf2/stdlib/msvcrt.pyi. - msvcrt.locking(fd, msvcrt.LK_NBLCK, 1) # type: ignore + msvcrt.locking(fd, msvcrt.LK_NBLCK, 1) # type: ignore # pylint: disable=used-before-assignment except (IOError, OSError) as err: if fd: os.close(fd) @@ -229,7 +229,7 @@ class _WindowsLockMechanism(_BaseLockMechanism): # This "type: ignore" is currently needed because msvcrt methods # are only defined on Windows. See # https://github.com/python/typeshed/blob/16ae4c61201cd8b96b8b22cdfb2ab9e89ba5bcf2/stdlib/msvcrt.pyi. - msvcrt.locking(self._fd, msvcrt.LK_UNLCK, 1) # type: ignore + msvcrt.locking(self._fd, msvcrt.LK_UNLCK, 1) # type: ignore # pylint: disable=used-before-assignment os.close(self._fd) try: diff --git a/certbot/certbot/achallenges.py b/certbot/certbot/achallenges.py index 73666825c..081fa1c46 100644 --- a/certbot/certbot/achallenges.py +++ b/certbot/certbot/achallenges.py @@ -47,7 +47,7 @@ class AnnotatedChallenge(jose.ImmutableMap): class KeyAuthorizationAnnotatedChallenge(AnnotatedChallenge): """Client annotated `KeyAuthorizationChallenge` challenge.""" - __slots__ = ('challb', 'domain', 'account_key') + __slots__ = ('challb', 'domain', 'account_key') # pylint: disable=redefined-slots-in-subclass def response_and_validation(self, *args: Any, **kwargs: Any) -> Any: """Generate response and validation.""" @@ -57,5 +57,5 @@ class KeyAuthorizationAnnotatedChallenge(AnnotatedChallenge): class DNS(AnnotatedChallenge): """Client annotated "dns" ACME challenge.""" - __slots__ = ('challb', 'domain') + __slots__ = ('challb', 'domain') # pylint: disable=redefined-slots-in-subclass acme_type = challenges.DNS diff --git a/certbot/certbot/plugins/dns_test_common.py b/certbot/certbot/plugins/dns_test_common.py index ae8a69b79..a2ab84dcb 100644 --- a/certbot/certbot/plugins/dns_test_common.py +++ b/certbot/certbot/plugins/dns_test_common.py @@ -38,14 +38,12 @@ class _AuthenticatorCallableTestCase(Protocol): See https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertTrue """ - ... def assertEqual(self, *unused_args: Any) -> None: """ See https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertEqual """ - ... class BaseAuthenticatorTest: diff --git a/certbot/certbot/plugins/dns_test_common_lexicon.py b/certbot/certbot/plugins/dns_test_common_lexicon.py index 7d844d133..01f4c6d61 100644 --- a/certbot/certbot/plugins/dns_test_common_lexicon.py +++ b/certbot/certbot/plugins/dns_test_common_lexicon.py @@ -57,7 +57,6 @@ class _LexiconAwareTestCase(Protocol): See https://docs.python.org/3/library/unittest.html#unittest.TestCase.assertRaises """ - ... # These classes are intended to be subclassed/mixed in, so not all members are defined. diff --git a/certbot/certbot/util.py b/certbot/certbot/util.py index 242dfef5a..9a6c5de78 100644 --- a/certbot/certbot/util.py +++ b/certbot/certbot/util.py @@ -34,7 +34,7 @@ if _USE_DISTRO: import distro if TYPE_CHECKING: - import distutils.version + import distutils.version # pylint: disable=deprecated-module logger = logging.getLogger(__name__) @@ -624,7 +624,7 @@ def get_strict_version(normalized: str) -> "distutils.version.StrictVersion": "removed in a future release.", DeprecationWarning) with warnings.catch_warnings(): warnings.simplefilter("ignore", DeprecationWarning) - import distutils.version + import distutils.version # pylint: disable=deprecated-module # strict version ending with "a" and a number designates a pre-release return distutils.version.StrictVersion(normalized.replace(".dev", "a")) diff --git a/certbot/docs/conf.py b/certbot/docs/conf.py index 08bb3705a..de9e287fc 100644 --- a/certbot/docs/conf.py +++ b/certbot/docs/conf.py @@ -84,7 +84,7 @@ release = meta['version'] # # This is also used if you do content translation via gettext catalogs. # Usually you set "language" from the command line for these cases. -language = None +language = 'en' # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: diff --git a/tools/pinning/current/pyproject.toml b/tools/pinning/current/pyproject.toml index b5959bc20..95b236c10 100644 --- a/tools/pinning/current/pyproject.toml +++ b/tools/pinning/current/pyproject.toml @@ -62,7 +62,14 @@ mock = "*" # https://github.com/python-poetry/poetry/issues/1584. This version is required # here in addition to certbot/setup.py because otherwise the pre-release # version of poetry will not be installed. -poetry = ">=1.2.0a1" +# +# Additionally, newer versions of poetry/poetry-core include package extras +# (e.g. "docker[ssh]") in its `poetry export` output which is valid for +# requirements files, but not constraints files. We are currently using that +# output as constraints so let's also pin back poetry and poetry-core until we +# have a better workaround. +poetry = "1.2.0a2" +poetry-core = "1.1.0a7" # setuptools-rust is a build dependency of cryptography, and since we don't have # a great way of pinning build dependencies, we simply list it here to ensure a # working version. Note: if build dependencies of setuptools-rust break at some diff --git a/tools/requirements.txt b/tools/requirements.txt index d57f3a600..0bc823444 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -7,190 +7,191 @@ # for more info. alabaster==0.7.12; python_version >= "3.7" apacheconfig==0.3.2; python_version >= "3.7" -appdirs==1.4.4; python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.4.0" -appnope==0.1.2; python_version >= "3.7" and sys_platform == "darwin" -astroid==2.9.3; python_version >= "3.7" and python_full_version >= "3.6.2" -atomicwrites==1.4.0; python_version >= "3.7" and python_full_version < "3.0.0" and sys_platform == "win32" or sys_platform == "win32" and python_version >= "3.7" and python_full_version >= "3.4.0" -attrs==21.4.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.7" -awscli==1.22.75; python_version >= "3.6" +appdirs==1.4.4; python_version >= "3.7" and python_version < "4.0" +appnope==0.1.3; python_version >= "3.7" and sys_platform == "darwin" +astroid==2.11.7; python_version >= "3.7" +atomicwrites==1.4.1; sys_platform == "win32" and python_version >= "3.7" +attrs==22.1.0; python_version >= "3.7" +awscli==1.25.40 +awscli==1.25.40; python_version >= "3.7" azure-devops==6.0.0b4; python_version >= "3.7" -babel==2.9.1; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version >= "3.4.0" +babel==2.10.3; python_version >= "3.7" backcall==0.2.0; python_version >= "3.7" -bcrypt==3.2.0; python_version >= "3.7" -beautifulsoup4==4.10.0; python_full_version > "3.0.0" and python_version >= "3.7" or python_version >= "3.7" and python_version < "4.0" and python_full_version > "3.0.0" -bleach==4.1.0; python_version >= "3.7" -boto3==1.21.20; python_version >= "3.7" -botocore==1.24.20; python_version >= "3.7" -cachecontrol==0.12.10; python_version >= "3.7" and python_version < "4.0" -cached-property==1.5.2; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.7" -cachetools==5.0.0; python_version >= "3.7" and python_version < "4.0" and (python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.7") -cachy==0.3.0; python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.4.0" -certifi==2021.10.8; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.7" or python_version >= "3.7" -cffi==1.15.0; python_version >= "3.7" or python_version >= "3.7" -charset-normalizer==2.0.12; python_full_version >= "3.6.0" and python_version >= "3.7" -cleo==1.0.0a4; python_version >= "3.7" and python_version < "4.0" -cloudflare==2.8.15; python_version >= "3.7" -colorama==0.4.3; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.7" or sys_platform == "win32" and python_full_version >= "3.6.2" and python_version >= "3.7" or python_version >= "3.7" and python_full_version < "3.0.0" and sys_platform == "win32" or python_full_version >= "3.5.0" and python_version >= "3.7" and sys_platform == "win32" or python_version >= "3.7" and python_full_version < "3.0.0" and platform_system == "Windows" or python_version >= "3.7" and python_full_version >= "3.5.0" and platform_system == "Windows" -configargparse==1.5.3; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.7" +bcrypt==3.2.2; python_version >= "3.7" +beautifulsoup4==4.11.1; python_version >= "3.7" +bleach==5.0.1; python_version >= "3.7" +boto3==1.24.40; python_version >= "3.7" +botocore==1.27.40; python_version >= "3.7" +cachecontrol==0.12.11; python_version >= "3.7" and python_version < "4.0" +cached-property==1.5.2; python_version >= "3.7" +cachetools==5.2.0; python_version >= "3.7" and python_version < "4.0" +cachy==0.3.0; python_version >= "3.7" and python_version < "4.0" +certifi==2022.6.15; python_version >= "3.7" and python_version < "4" or python_version >= "3.7" +cffi==1.15.1; python_version >= "3.7" +charset-normalizer==2.1.0; python_version >= "3.7" and python_version < "4" +cleo==1.0.0a5; python_version >= "3.7" and python_version < "4.0" +cloudflare==2.9.11; python_version >= "3.7" +colorama==0.4.4; python_version >= "3.7" +configargparse==1.5.3; python_version >= "3.7" configobj==5.0.6; python_version >= "3.7" -coverage==6.3.2; python_version >= "3.7" or python_version >= "3.7" +coverage==6.4.2; python_version >= "3.7" crashtest==0.3.1; python_version >= "3.7" and python_version < "4.0" -cryptography==36.0.2; python_version >= "3.7" and python_version < "4.0" or python_version >= "3.7" or python_version >= "3.7" and python_version < "4.0" and sys_platform == "linux" -cython==0.29.28; (python_version >= "2.6" and python_full_version < "3.0.0") or (python_full_version >= "3.3.0") +cryptography==37.0.4 +cryptography==37.0.4; python_version >= "3.7" +cython==0.29.31 decorator==5.1.1; python_version >= "3.7" -deprecated==1.2.13; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version >= "3.4.0" -distlib==0.3.4; python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.4.0" or python_version >= "3.7" -distro==1.7.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.7" or python_version >= "3.7" -dns-lexicon==3.9.4; python_version >= "3.7" and python_version < "4.0" +dill==0.3.5.1; python_version >= "3.7" +distlib==0.3.5; python_version >= "3.7" +distro==1.7.0; python_version >= "3.7" +dns-lexicon==3.11.1; python_version >= "3.7" and python_version < "4.0" dnspython==2.2.1; python_version >= "3.7" and python_version < "4.0" -docker-compose==1.26.2; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.7" -docker==4.2.2; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.7" -dockerpty==0.4.1; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.7" -docopt==0.6.2; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.7" -docutils==0.15.2; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.7" or python_version >= "3.7" and python_full_version >= "3.4.0" +docker-compose==1.26.2; python_version >= "3.7" +docker==4.2.2; python_version >= "3.7" +dockerpty==0.4.1; python_version >= "3.7" +docopt==0.6.2; python_version >= "3.7" +docutils==0.16; python_version >= "3.7" entrypoints==0.3; python_version >= "3.7" and python_version < "4.0" -execnet==1.9.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.7" -fabric==2.6.0; python_version >= "3.7" -filelock==3.6.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version >= "3.5.0" or python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.4.0" or python_version >= "3.7" and python_version < "4.0" -google-api-core==2.7.1; python_version >= "3.7" -google-api-python-client==2.41.0; python_version >= "3.7" +execnet==1.9.0; python_version >= "3.7" +fabric==2.7.1; python_version >= "3.7" +filelock==3.7.1; python_version >= "3.7" or python_version >= "3.7" and python_version < "4.0" +google-api-core==2.8.2; python_version >= "3.7" +google-api-python-client==2.55.0; python_version >= "3.7" google-auth-httplib2==0.1.0; python_version >= "3.7" -google-auth==2.6.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.7" -googleapis-common-protos==1.55.0; python_version >= "3.7" -html5lib==1.1; python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.5.0" -httplib2==0.20.4; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.7" -idna==3.3; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.7" or python_version >= "3.7" and python_version < "4.0" -imagesize==1.3.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version >= "3.4.0" -importlib-metadata==1.7.0; python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "3.8" or python_version >= "3.7" and python_version < "3.8" and python_full_version >= "3.5.0" +google-auth==2.9.1; python_version >= "3.7" +googleapis-common-protos==1.56.4; python_version >= "3.7" +html5lib==1.1; python_version >= "3.7" and python_version < "4.0" +httplib2==0.20.4; python_version >= "3.7" +idna==3.3; python_version >= "3.7" and python_version < "4" or python_version >= "3.7" and python_version < "4.0" +imagesize==1.4.1; python_version >= "3.7" +importlib-metadata==1.7.0; python_version >= "3.7" and python_version < "3.8" iniconfig==1.1.1; python_version >= "3.7" -invoke==1.6.0; python_version >= "3.7" +invoke==1.7.1; python_version >= "3.7" ipdb==0.13.9; python_version >= "3.7" -ipython==7.32.0; python_version >= "3.7" +ipython==7.34.0; python_version >= "3.7" isodate==0.6.1; python_version >= "3.7" -isort==5.10.1; python_full_version >= "3.6.2" and python_version < "4.0" and python_version >= "3.7" +isort==5.10.1; python_version >= "3.7" and python_version < "4.0" jedi==0.18.1; python_version >= "3.7" -jeepney==0.7.1; python_version >= "3.7" and python_version < "4.0" and sys_platform == "linux" -jinja2==3.0.3; python_version >= "3.7" or python_version >= "3.7" -jmespath==0.10.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.7" +jeepney==0.8.0; python_version >= "3.7" and python_version < "4.0" and sys_platform == "linux" +jinja2==3.1.2; python_version >= "3.7" +jmespath==1.0.1; python_version >= "3.7" josepy==1.13.0; python_version >= "3.7" -jsonlines==3.0.0; python_version >= "3.7" -jsonpickle==2.1.0; python_version >= "3.7" -jsonschema==3.2.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.7" +jsonlines==3.1.0; python_version >= "3.7" +jsonpickle==2.2.0; python_version >= "3.7" +jsonschema==3.2.0; python_version >= "3.7" keyring==22.3.0; python_version >= "3.7" and python_version < "4.0" or python_version >= "3.7" -lazy-object-proxy==1.7.1; python_version >= "3.7" and python_full_version >= "3.6.2" +lazy-object-proxy==1.7.1; python_version >= "3.7" lockfile==0.12.2 markupsafe==2.1.1; python_version >= "3.7" matplotlib-inline==0.1.3; python_version >= "3.7" -mccabe==0.6.1; python_version >= "3.7" and python_full_version >= "3.6.2" -mock==4.0.3; python_version >= "3.6" -msgpack==1.0.3; python_version >= "3.7" and python_version < "4.0" +mccabe==0.7.0; python_version >= "3.7" +mock==4.0.3 +msgpack==1.0.4; python_version >= "3.7" and python_version < "4.0" msrest==0.6.21; python_version >= "3.7" mypy-extensions==0.4.3; python_version >= "3.7" -mypy==0.941; python_version >= "3.7" +mypy==0.971; python_version >= "3.7" oauth2client==4.1.3; python_version >= "3.7" -oauthlib==3.2.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version >= "3.4.0" -packaging==20.9; python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.4.0" or python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.7" or python_version >= "3.7" and python_full_version >= "3.5.0" -paramiko==2.10.2; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.7" or python_version >= "3.7" +oauthlib==3.2.0; python_version >= "3.7" +packaging==20.9; python_version >= "3.7" +paramiko==2.11.0; python_version >= "3.7" parsedatetime==2.6; python_version >= "3.7" parso==0.8.3; python_version >= "3.7" pathlib2==2.3.7.post1; python_version >= "3.7" pexpect==4.8.0; python_version >= "3.7" and python_version < "4.0" or python_version >= "3.7" and sys_platform != "win32" pickleshare==0.7.5; python_version >= "3.7" -pip==22.0.4; python_version >= "3.7" -pkginfo==1.8.2; python_version >= "3.7" and python_version < "4.0" or python_version >= "3.7" -platformdirs==2.5.1; python_version >= "3.7" and python_full_version >= "3.6.2" -pluggy==1.0.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version >= "3.5.0" or python_version >= "3.7" +pip==22.2.1; python_version >= "3.7" +pkginfo==1.8.3; python_version >= "3.7" and python_version < "4.0" or python_version >= "3.7" +platformdirs==2.5.2; python_version >= "3.7" +pluggy==1.0.0; python_version >= "3.7" ply==3.11; python_version >= "3.7" -poetry-core==1.1.0a7; python_version >= "3.7" and python_version < "4.0" -poetry==1.2.0a2; python_version >= "3.6" and python_version < "4.0" -prompt-toolkit==3.0.28; python_version >= "3.7" and python_full_version >= "3.6.2" -protobuf==3.19.4; python_version >= "3.7" +poetry-core==1.1.0a7 +poetry==1.2.0a2 +prompt-toolkit==3.0.30; python_version >= "3.7" +protobuf==4.21.4; python_version >= "3.7" ptyprocess==0.7.0; python_version >= "3.7" and python_version < "4.0" -py==1.11.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.7" -pyasn1-modules==0.2.8; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.7" or python_version >= "3.7" -pyasn1==0.4.8; python_version >= "3.7" and python_version < "4" or python_version >= "3.7" -pycparser==2.21; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.7" -pygithub==1.55; python_version >= "3.7" -pygments==2.11.2; python_version >= "3.7" -pyjwt==2.3.0; python_version >= "3.7" +py==1.11.0; python_version >= "3.7" +pyasn1-modules==0.2.8; python_version >= "3.7" +pyasn1==0.4.8; python_version >= "3.7" +pycparser==2.21; python_version >= "3.7" +pygments==2.12.0; python_version >= "3.7" pylev==1.4.0; python_version >= "3.7" and python_version < "4.0" -pylint==2.12.2; python_full_version >= "3.6.2" -pynacl==1.5.0; python_version >= "3.7" or python_version >= "3.7" +pylint==2.13.9 +pylint==2.13.9; python_version >= "3.7" +pynacl==1.5.0; python_version >= "3.7" pynsist==2.7; python_version >= "3.7" pyopenssl==22.0.0; python_version >= "3.7" -pyparsing==3.0.7; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.7" or python_version >= "3.7" or python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.4.0" -pypiwin32==223; sys_platform == "win32" and python_version >= "3.6" and (python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.7") +pyparsing==3.0.9; python_version >= "3.7" +pypiwin32==223; sys_platform == "win32" and python_version >= "3.7" pyrfc3339==1.1; python_version >= "3.7" -pyrsistent==0.18.1; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.7" -pytest-cov==3.0.0; python_version >= "3.7" or python_version >= "3.7" +pyrsistent==0.18.1; python_version >= "3.7" +pytest-cov==3.0.0; python_version >= "3.7" pytest-forked==1.4.0; python_version >= "3.7" -pytest-xdist==2.5.0; python_version >= "3.7" or python_version >= "3.7" -pytest==7.1.0; python_version >= "3.7" or python_version >= "3.7" +pytest-xdist==2.5.0; python_version >= "3.7" +pytest==7.1.2; python_version >= "3.7" python-augeas==1.1.0; python_version >= "3.7" -python-dateutil==2.8.2; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.7" +python-dateutil==2.8.2; python_version >= "3.7" python-digitalocean==1.17.0; python_version >= "3.7" -python-dotenv==0.19.2; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.7" -pytz==2021.3; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version >= "3.4.0" or python_version >= "3.7" +python-dotenv==0.20.0; python_version >= "3.7" +pytz==2022.1; python_version >= "3.7" pywin32-ctypes==0.2.0; python_version >= "3.7" and python_version < "4.0" and sys_platform == "win32" -pywin32==303; sys_platform == "win32" and python_version >= "3.7" or sys_platform == "win32" and python_version >= "3.6" and (python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.7") -pyyaml==5.4.1; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.7" or python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.6.0" -readme-renderer==34.0; python_version >= "3.7" +pywin32==304; sys_platform == "win32" and python_version >= "3.7" +pyyaml==5.4.1; python_version >= "3.7" +readme-renderer==35.0; python_version >= "3.7" requests-download==0.1.2; python_version >= "3.7" requests-file==1.5.1; python_version >= "3.7" and python_version < "4.0" -requests-oauthlib==1.3.1; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version >= "3.4.0" -requests-toolbelt==0.9.1; python_version >= "3.7" and python_version < "4.0" or python_version >= "3.7" or python_version >= "3.7" -requests==2.27.1; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.7" or python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.6.0" +requests-oauthlib==1.3.1; python_version >= "3.7" +requests-toolbelt==0.9.1; python_version >= "3.7" +requests==2.28.1; python_version >= "3.7" and python_version < "4" rfc3986==2.0.0; python_version >= "3.7" -rsa==4.7.2; python_version >= "3.7" and python_version < "4" or python_version >= "3.5" and python_version < "4" and (python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.7") -s3transfer==0.5.2; python_version >= "3.7" -secretstorage==3.3.1; python_version >= "3.7" and python_version < "4.0" and sys_platform == "linux" -semantic-version==2.9.0; python_version >= "3.6" -setuptools-rust==1.1.2; python_version >= "3.6" -setuptools==60.9.3; python_version >= "3.7" or python_version >= "3.7" or python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.7" or python_version >= "3.7" and python_full_version >= "3.6.2" or python_full_version >= "3.4.0" and python_version >= "3.7" +rsa==4.7.2; python_version >= "3.7" and python_version < "4" +s3transfer==0.6.0; python_version >= "3.7" +secretstorage==3.3.2; python_version >= "3.7" and python_version < "4.0" and sys_platform == "linux" +semantic-version==2.10.0; python_version >= "3.7" +setuptools-rust==1.4.1 +setuptools==63.2.0; python_version >= "3.7" shellingham==1.4.0; python_version >= "3.7" and python_version < "4.0" -six==1.16.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.7" or python_full_version >= "3.3.0" and python_version >= "3.7" or python_version >= "3.7" and python_full_version >= "3.5.0" or python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.5.0" or python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.4.0" or python_full_version >= "3.6.0" and python_version >= "3.7" or python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.3.0" +six==1.16.0; python_version >= "3.7" snowballstemmer==2.2.0; python_version >= "3.7" -soupsieve==2.3.1; python_full_version > "3.0.0" and python_version >= "3.7" -sphinx-rtd-theme==1.0.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version >= "3.4.0" -sphinx==4.3.2; python_version >= "3.7" or python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version >= "3.4.0" +soupsieve==2.3.2.post1; python_version >= "3.7" +sphinx-rtd-theme==1.0.0; python_version >= "3.7" +sphinx==4.3.2; python_version >= "3.7" sphinxcontrib-applehelp==1.0.2; python_version >= "3.7" sphinxcontrib-devhelp==1.0.2; python_version >= "3.7" sphinxcontrib-htmlhelp==2.0.0; python_version >= "3.7" sphinxcontrib-jsmath==1.0.1; python_version >= "3.7" sphinxcontrib-qthelp==1.0.3; python_version >= "3.7" sphinxcontrib-serializinghtml==1.1.5; python_version >= "3.7" -texttable==1.6.4; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.7" -tldextract==3.2.0; python_version >= "3.7" and python_version < "4.0" -toml==0.10.2; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version >= "3.3.0" or python_version >= "3.7" and python_full_version >= "3.6.2" or python_version >= "3.7" and python_full_version >= "3.5.0" -tomli==2.0.1; python_version >= "3.7" or python_version >= "3.7" -tomlkit==0.10.0; python_version >= "3.7" and python_version < "4.0" -tox==3.24.5; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version >= "3.5.0" -tqdm==4.63.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version >= "3.4.0" -traitlets==5.1.1; python_version >= "3.7" +texttable==1.6.4; python_version >= "3.7" +tldextract==3.3.1; python_version >= "3.7" and python_version < "4.0" +toml==0.10.2; python_version >= "3.7" +tomli==2.0.1; python_version < "3.11" and python_version >= "3.7" or python_full_version <= "3.11.0a6" and python_version >= "3.7" or python_version >= "3.7" +tomlkit==0.11.1; python_version >= "3.7" and python_version < "4.0" +tox==3.25.1; python_version >= "3.7" +tqdm==4.64.0; python_version >= "3.7" +traitlets==5.3.0; python_version >= "3.7" twine==3.3.0; python_version >= "3.7" -typed-ast==1.5.2; python_version >= "3.7" and python_version < "3.8" or implementation_name == "cpython" and python_version < "3.8" and python_version >= "3.7" and python_full_version >= "3.6.2" -types-cryptography==3.3.18; python_version >= "3.7" -types-mock==4.0.11; python_version >= "3.7" -types-pyopenssl==22.0.0; python_version >= "3.7" +typed-ast==1.5.4; python_version >= "3.7" and python_version < "3.8" or implementation_name == "cpython" and python_version < "3.8" and python_version >= "3.7" +types-cryptography==3.3.21; python_version >= "3.7" +types-mock==4.0.15; python_version >= "3.7" +types-pyopenssl==22.0.9; python_version >= "3.7" types-pyrfc3339==1.1.1; python_version >= "3.7" -types-python-dateutil==2.8.9; python_version >= "3.7" -types-pytz==2021.3.5; python_version >= "3.7" -types-requests==2.27.12; python_version >= "3.7" -types-setuptools==57.4.10; python_version >= "3.7" -types-six==1.16.12; python_version >= "3.7" -types-urllib3==1.26.11; python_version >= "3.7" -typing-extensions==4.1.1; python_version >= "3.7" or python_version >= "3.6" or python_version < "3.10" and python_full_version >= "3.6.2" and python_version >= "3.7" or python_version < "3.8" and python_version >= "3.7" +types-python-dateutil==2.8.19; python_version >= "3.7" +types-pytz==2022.1.2; python_version >= "3.7" +types-requests==2.28.5; python_version >= "3.7" +types-setuptools==63.2.2; python_version >= "3.7" +types-six==1.16.18; python_version >= "3.7" +types-urllib3==1.26.17; python_version >= "3.7" +typing-extensions==4.3.0; python_version >= "3.7" or python_version < "3.10" and python_version >= "3.7" or python_version < "3.8" and python_version >= "3.7" uritemplate==4.1.1; python_version >= "3.7" -urllib3==1.26.8; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version < "4" and python_version >= "3.7" or python_full_version >= "3.5.0" and python_version < "4" and python_version >= "3.7" -virtualenv==20.4.4; python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.4.0" or python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version >= "3.5.0" -wcwidth==0.2.5; python_version >= "3.7" and python_full_version >= "3.6.2" -webencodings==0.5.1; python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.7" and python_version < "4.0" and python_full_version >= "3.5.0" or python_version >= "3.7" -websocket-client==0.59.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.7" or python_full_version >= "3.5.0" and python_version >= "3.7" -wheel==0.37.1; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version >= "3.5.0" -wrapt==1.13.3; python_version >= "3.7" and python_full_version < "3.0.0" or python_version >= "3.7" and python_full_version >= "3.5.0" or python_version >= "3.7" and python_full_version >= "3.6.2" +urllib3==1.26.11; python_version >= "3.7" and python_version < "4" +virtualenv==20.4.4; python_version >= "3.7" and python_version < "4.0" or python_version >= "3.7" +wcwidth==0.2.5; python_version >= "3.7" +webencodings==0.5.1; python_version >= "3.7" and python_version < "4.0" or python_version >= "3.7" +websocket-client==0.59.0; python_version >= "3.7" +wheel==0.37.1; python_version >= "3.7" +wrapt==1.14.1; python_version >= "3.7" yarg==0.1.9; python_version >= "3.7" -zipp==3.7.0; python_version >= "3.7" and python_full_version < "3.0.0" and python_version < "3.8" or python_version >= "3.7" and python_version < "3.8" and python_full_version >= "3.5.0" -zope.component==5.0.1; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.7" -zope.event==4.5.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.7" -zope.hookable==5.1.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.7" -zope.interface==5.4.0; python_version >= "3.7" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.7" +zipp==3.8.1; python_version >= "3.7" and python_version < "3.8" +zope.component==5.0.1; python_version >= "3.7" +zope.event==4.5.0; python_version >= "3.7" +zope.hookable==5.1.0; python_version >= "3.7" +zope.interface==5.4.0; python_version >= "3.7" From b73f3e2b16ce83836e4dbf3e7cfdc7acd2b318a2 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 28 Jul 2022 19:58:47 -0700 Subject: [PATCH 05/18] pin back pylint (#9368) --- tools/oldest_constraints.txt | 43 ++++++++++++++-------------- tools/pinning/current/pyproject.toml | 12 ++++---- tools/pinning/oldest/pyproject.toml | 12 ++++---- tools/requirements.txt | 1 - 4 files changed, 35 insertions(+), 33 deletions(-) diff --git a/tools/oldest_constraints.txt b/tools/oldest_constraints.txt index 90ec56a34..16dfbb758 100644 --- a/tools/oldest_constraints.txt +++ b/tools/oldest_constraints.txt @@ -2,9 +2,9 @@ # that script. apacheconfig==0.3.2 asn1crypto==0.24.0 -astroid==2.11.6; python_version >= "3.7" -atomicwrites==1.4.0; sys_platform == "win32" and python_version >= "3.7" -attrs==21.4.0; python_version >= "3.7" +astroid==2.11.7; python_version >= "3.7" +atomicwrites==1.4.1; sys_platform == "win32" and python_version >= "3.7" +attrs==22.1.0; python_version >= "3.7" bcrypt==3.2.2; python_version >= "3.7" boto3==1.15.15 botocore==1.18.15 @@ -16,11 +16,11 @@ cloudflare==1.5.1 colorama==0.4.5; sys_platform == "win32" and python_version >= "3.7" configargparse==0.10.0 configobj==5.0.6 -coverage==6.4.1; python_version >= "3.7" +coverage==6.4.2; python_version >= "3.7" cryptography==3.2.1 -cython==0.29.30 +cython==0.29.31 dill==0.3.5.1; python_version >= "3.7" -distlib==0.3.4; python_version >= "3.7" +distlib==0.3.5; python_version >= "3.7" distro==1.0.1 dns-lexicon==3.2.1 dnspython==1.15.0 @@ -35,7 +35,7 @@ future==0.18.2; python_version >= "3.7" google-api-python-client==1.5.5 httplib2==0.9.2 idna==2.6 -importlib-metadata==4.11.4; python_version < "3.8" and python_version >= "3.7" +importlib-metadata==4.12.0; python_version < "3.8" and python_version >= "3.7" iniconfig==1.1.1; python_version >= "3.7" ipaddress==1.0.16 isort==5.10.1; python_version >= "3.7" and python_version < "4.0" @@ -47,14 +47,14 @@ logger==1.4; python_version >= "3.7" mccabe==0.7.0; python_version >= "3.7" mock==1.0.1 mypy-extensions==0.4.3; python_version >= "3.7" -mypy==0.961; python_version >= "3.7" +mypy==0.971; python_version >= "3.7" ndg-httpsclient==0.3.2 oauth2client==4.0.0 packaging==21.3; python_version >= "3.7" paramiko==2.11.0; python_version >= "3.7" parsedatetime==2.4 pbr==1.8.0 -pip==22.1.2; python_version >= "3.7" +pip==22.2.1; python_version >= "3.7" platformdirs==2.5.2; python_version >= "3.7" pluggy==1.0.0; python_version >= "3.7" ply==3.4 @@ -63,7 +63,6 @@ pyasn1-modules==0.0.10; python_version >= "3.7" pyasn1==0.1.9 pycparser==2.14 pylint==2.13.9 -pylint==2.13.9; python_version >= "3.7" pynacl==1.5.0; python_version >= "3.7" pyopenssl==17.5.0 pyparsing==2.2.1 @@ -83,34 +82,34 @@ pyyaml==5.4.1; python_version >= "3.7" requests-file==1.5.1; python_version >= "3.7" requests-toolbelt==0.9.1; python_version >= "3.7" requests==2.20.0 -rsa==4.8; python_version >= "3.7" and python_version < "4" +rsa==4.9; python_version >= "3.7" and python_version < "4" s3transfer==0.3.7; python_version >= "3.7" setuptools==41.6.0 six==1.11.0 texttable==1.6.4; python_version >= "3.7" -tldextract==3.3.0; python_version >= "3.7" +tldextract==3.3.1; python_version >= "3.7" tomli==2.0.1; python_version < "3.11" and python_version >= "3.7" or python_full_version <= "3.11.0a6" and python_version >= "3.7" or python_version >= "3.7" tox==1.9.2; python_version >= "3.7" typed-ast==1.5.4; python_version >= "3.7" and python_version < "3.8" or implementation_name == "cpython" and python_version < "3.8" and python_version >= "3.7" types-cryptography==3.3.21; python_version >= "3.7" types-mock==4.0.15; python_version >= "3.7" -types-pyopenssl==22.0.3; python_version >= "3.7" +types-pyopenssl==22.0.9; python_version >= "3.7" types-pyrfc3339==1.1.1; python_version >= "3.7" -types-python-dateutil==2.8.17; python_version >= "3.7" -types-pytz==2022.1.0; python_version >= "3.7" -types-requests==2.27.31; python_version >= "3.7" -types-setuptools==57.4.17; python_version >= "3.7" -types-six==1.16.16; python_version >= "3.7" -types-urllib3==1.26.15; python_version >= "3.7" -typing-extensions==4.2.0; python_version >= "3.7" or python_version < "3.10" and python_version >= "3.7" or python_version < "3.8" and python_version >= "3.7" +types-python-dateutil==2.8.19; python_version >= "3.7" +types-pytz==2022.1.2; python_version >= "3.7" +types-requests==2.28.5; python_version >= "3.7" +types-setuptools==63.2.2; python_version >= "3.7" +types-six==1.16.18; python_version >= "3.7" +types-urllib3==1.26.17; python_version >= "3.7" +typing-extensions==4.3.0; python_version >= "3.7" or python_version < "3.10" and python_version >= "3.7" or python_version < "3.8" and python_version >= "3.7" uritemplate==3.0.1; python_version >= "3.7" urllib3==1.24.2 -virtualenv==20.14.1; python_version >= "3.7" +virtualenv==20.16.2; python_version >= "3.7" websocket-client==0.59.0; python_version >= "3.7" wheel==0.33.6 wheel==0.33.6; python_version >= "3.7" wrapt==1.14.1; python_version >= "3.7" -zipp==3.8.0; python_version < "3.8" and python_version >= "3.7" +zipp==3.8.1; python_version < "3.8" and python_version >= "3.7" zope.component==4.1.0 zope.event==4.0.3 zope.hookable==4.0.4 diff --git a/tools/pinning/current/pyproject.toml b/tools/pinning/current/pyproject.toml index 95b236c10..99294c96e 100644 --- a/tools/pinning/current/pyproject.toml +++ b/tools/pinning/current/pyproject.toml @@ -76,11 +76,13 @@ poetry-core = "1.1.0a7" # point, it's probably worth enumerating and pinning them (and recursing to # THEIR build dependencies) as well. setuptools-rust = "*" -# A bad python_requires constraint in pylint 2.6.2 can sometimes crash poetry -# before it has finished resolving. No newer releases have the same issue. Remove -# this once we can upgrade to a release of Poetry containing this commit: -# https://github.com/python-poetry/poetry-core/commit/4e1f2ab582d1fef0033c0d3f35a3f2f2365a4bc9 -pylint = ">2.6.2" +# pylint often adds new checks that we need to conform our code to when +# upgrading our dependencies. To help control when this needs to be done, we +# pin pylint to a compatible version here. +# +# If this pinning is removed, we may still need to add a lower bound for the +# pylint version. See https://github.com/certbot/certbot/pull/9229. +pylint = "2.13.9" # Bug in poetry, where still installes yanked versions from pypi (source: https://github.com/python-poetry/poetry/issues/2453) # this version of cryptography introduced a security vulnrability. diff --git a/tools/pinning/oldest/pyproject.toml b/tools/pinning/oldest/pyproject.toml index 5585a39f4..3a49b12ed 100644 --- a/tools/pinning/oldest/pyproject.toml +++ b/tools/pinning/oldest/pyproject.toml @@ -104,11 +104,13 @@ cython = "*" # wheel 0.34.0 is buggy). wheel = "<0.34.0" -# A bad python_requires constraint in pylint 2.6.2 can sometimes crash poetry -# before it has finished resolving. No newer releases have the same issue. Remove -# this once we can upgrade to a release of Poetry containing this commit: -# https://github.com/python-poetry/poetry-core/commit/4e1f2ab582d1fef0033c0d3f35a3f2f2365a4bc9 -pylint = ">2.6.2" +# pylint often adds new checks that we need to conform our code to when +# upgrading our dependencies. To help control when this needs to be done, we +# pin pylint to a compatible version here. +# +# If this pinning is removed, we may still need to add a lower bound for the +# pylint version. See https://github.com/certbot/certbot/pull/9229. +pylint = "2.13.9" [tool.poetry.dev-dependencies] diff --git a/tools/requirements.txt b/tools/requirements.txt index 0bc823444..8dc4f0a93 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -115,7 +115,6 @@ pycparser==2.21; python_version >= "3.7" pygments==2.12.0; python_version >= "3.7" pylev==1.4.0; python_version >= "3.7" and python_version < "4.0" pylint==2.13.9 -pylint==2.13.9; python_version >= "3.7" pynacl==1.5.0; python_version >= "3.7" pynsist==2.7; python_version >= "3.7" pyopenssl==22.0.0; python_version >= "3.7" From 1b79c077a69a168e1d62bb8227db30551535a060 Mon Sep 17 00:00:00 2001 From: Gusmanov Timur Date: Sat, 30 Jul 2022 01:01:01 +0600 Subject: [PATCH 06/18] add dns-yandexcloud authentication plugin to third-party plugins (#9371) --- certbot/docs/using.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/certbot/docs/using.rst b/certbot/docs/using.rst index 38aaf4ff4..980457141 100644 --- a/certbot/docs/using.rst +++ b/certbot/docs/using.rst @@ -316,6 +316,7 @@ dns-lightsail_ Y N DNS Authentication using Amazon Lightsail DNS API dns-inwx_ Y Y DNS Authentication for INWX through the XML API dns-azure_ Y N DNS Authentication using Azure DNS dns-godaddy_ Y N DNS Authentication using Godaddy DNS +dns-yandexcloud_ Y N DNS Authentication using Yandex Cloud DNS njalla_ Y N DNS Authentication for njalla DuckDNS_ Y N DNS Authentication for DuckDNS Porkbun_ Y N DNS Authentication for Porkbun @@ -336,6 +337,7 @@ Infomaniak_ Y N DNS Authentication using Infomaniak Domains API .. _dns-inwx: https://github.com/oGGy990/certbot-dns-inwx/ .. _dns-azure: https://github.com/binkhq/certbot-dns-azure .. _dns-godaddy: https://github.com/miigotu/certbot-dns-godaddy +.. _dns-yandexcloud: https://github.com/PykupeJIbc/certbot-dns-yandexcloud .. _njalla: https://github.com/chaptergy/certbot-dns-njalla .. _DuckDNS: https://github.com/infinityofspace/certbot_dns_duckdns .. _Porkbun: https://github.com/infinityofspace/certbot_dns_porkbun From 94bbb4c44c20bb71cf743b8de4652ab2bdea93c1 Mon Sep 17 00:00:00 2001 From: "Matthew W. Thomas" Date: Fri, 12 Aug 2022 16:03:08 -0500 Subject: [PATCH 07/18] docs: add BunnyDNS to list of 3rd-party plugins (#9375) * docs: add BunnyDNS to list of 3rd-party plugins You can find the plugin here: https://github.com/mwt/certbot-dns-bunny It's for [BunnyDNS](https://bunny.net/dns/). * Update AUTHORS.md --- AUTHORS.md | 1 + certbot/docs/using.rst | 2 ++ 2 files changed, 3 insertions(+) diff --git a/AUTHORS.md b/AUTHORS.md index 64f60a278..f8708dde1 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -178,6 +178,7 @@ Authors * [Mathieu Leduc-Hamel](https://github.com/mlhamel) * [Matt Bostock](https://github.com/mattbostock) * [Matthew Ames](https://github.com/SuperMatt) +* [Matthew W. Thomas](https://github.com/mwt) * [Michael Schumacher](https://github.com/schumaml) * [Michael Strache](https://github.com/Jarodiv) * [Michael Sverdlin](https://github.com/sveder) diff --git a/certbot/docs/using.rst b/certbot/docs/using.rst index 980457141..c0510da4a 100644 --- a/certbot/docs/using.rst +++ b/certbot/docs/using.rst @@ -317,6 +317,7 @@ dns-inwx_ Y Y DNS Authentication for INWX through the XML API dns-azure_ Y N DNS Authentication using Azure DNS dns-godaddy_ Y N DNS Authentication using Godaddy DNS dns-yandexcloud_ Y N DNS Authentication using Yandex Cloud DNS +dns-bunny_ Y N DNS Authentication using BunnyDNS njalla_ Y N DNS Authentication for njalla DuckDNS_ Y N DNS Authentication for DuckDNS Porkbun_ Y N DNS Authentication for Porkbun @@ -338,6 +339,7 @@ Infomaniak_ Y N DNS Authentication using Infomaniak Domains API .. _dns-azure: https://github.com/binkhq/certbot-dns-azure .. _dns-godaddy: https://github.com/miigotu/certbot-dns-godaddy .. _dns-yandexcloud: https://github.com/PykupeJIbc/certbot-dns-yandexcloud +.. _dns-bunny: https://github.com/mwt/certbot-dns-bunny .. _njalla: https://github.com/chaptergy/certbot-dns-njalla .. _DuckDNS: https://github.com/infinityofspace/certbot_dns_duckdns .. _Porkbun: https://github.com/infinityofspace/certbot_dns_porkbun From cb632c376f17dfd75306020a17248f3c33c1ab2f Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 16 Aug 2022 16:01:51 -0700 Subject: [PATCH 08/18] encourage words before code (#9377) --- .github/pull_request_template.md | 1 + certbot/docs/contributing.rst | 3 +++ 2 files changed, 4 insertions(+) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 53298291b..1d8b498ac 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,5 +1,6 @@ ## Pull Request Checklist +- [ ] The Certbot team has recently expressed interest in reviewing a PR for this. If not, this PR may be closed due our limited resources and need to prioritize how we spend them. - [ ] If the change being made is to a [distributed component](https://certbot.eff.org/docs/contributing.html#code-components-and-layout), edit the `master` section of `certbot/CHANGELOG.md` to include a description of the change being made. - [ ] Add or update any documentation as needed to support the changes in this PR. - [ ] Include your name in `AUTHORS.md` if you like. diff --git a/certbot/docs/contributing.rst b/certbot/docs/contributing.rst index ac8488e08..c32bdc170 100644 --- a/certbot/docs/contributing.rst +++ b/certbot/docs/contributing.rst @@ -500,6 +500,9 @@ Submitting a pull request Steps: +0. We recommend you talk with us in a GitHub issue or :ref:`Mattermost ` before writing a pull request to ensure the changes you're making is + something we have the time and interest to review. 1. Write your code! When doing this, you should add :ref:`mypy type annotations ` for any functions you add or modify. You can check that you've done this correctly by running ``tox -e mypy`` on a machine that has From a81d58fa6e3ce451682529947edfd807dcd56b7b Mon Sep 17 00:00:00 2001 From: alexzorin Date: Sat, 27 Aug 2022 07:25:37 +1000 Subject: [PATCH 09/18] deprecate certbot-dns-cloudxns (#9367) --- certbot-dns-cloudxns/certbot_dns_cloudxns/__init__.py | 7 +++++++ .../certbot_dns_cloudxns/_internal/dns_cloudxns.py | 6 ++++++ certbot-dns-cloudxns/tests/dns_cloudxns_test.py | 5 ++++- certbot/CHANGELOG.md | 3 ++- 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/certbot-dns-cloudxns/certbot_dns_cloudxns/__init__.py b/certbot-dns-cloudxns/certbot_dns_cloudxns/__init__.py index 0d098445c..0ba512ee4 100644 --- a/certbot-dns-cloudxns/certbot_dns_cloudxns/__init__.py +++ b/certbot-dns-cloudxns/certbot_dns_cloudxns/__init__.py @@ -1,4 +1,11 @@ """ +.. danger:: + The certbot-dns-cloudxns plugin is deprecated and will be removed in the next major + release of Certbot. The CloudXNS DNS service is defunct and we recommend uninstalling + the plugin. + +---------- + The `~certbot_dns_cloudxns.dns_cloudxns` plugin automates the process of completing a ``dns-01`` challenge (`~acme.challenges.DNS01`) by creating, and subsequently removing, TXT records using the CloudXNS API. diff --git a/certbot-dns-cloudxns/certbot_dns_cloudxns/_internal/dns_cloudxns.py b/certbot-dns-cloudxns/certbot_dns_cloudxns/_internal/dns_cloudxns.py index 15cdf8aa8..743e8567e 100644 --- a/certbot-dns-cloudxns/certbot_dns_cloudxns/_internal/dns_cloudxns.py +++ b/certbot-dns-cloudxns/certbot_dns_cloudxns/_internal/dns_cloudxns.py @@ -3,6 +3,7 @@ import logging from typing import Any from typing import Callable from typing import Optional +import warnings from lexicon.providers import cloudxns from requests import HTTPError @@ -27,6 +28,11 @@ class Authenticator(dns_common.DNSAuthenticator): ttl = 60 def __init__(self, *args: Any, **kwargs: Any) -> None: + warnings.warn( + "The CloudXNS authenticator is deprecated and will be removed in the " + "next major release of Certbot. The CloudXNS DNS service is defunct and " + "we recommend removing the plugin." + ) super().__init__(*args, **kwargs) self.credentials: Optional[CredentialsConfiguration] = None diff --git a/certbot-dns-cloudxns/tests/dns_cloudxns_test.py b/certbot-dns-cloudxns/tests/dns_cloudxns_test.py index 81dea5ca4..62cb2c28b 100644 --- a/certbot-dns-cloudxns/tests/dns_cloudxns_test.py +++ b/certbot-dns-cloudxns/tests/dns_cloudxns_test.py @@ -8,6 +8,7 @@ except ImportError: # pragma: no cover from unittest import mock # type: ignore from requests.exceptions import HTTPError from requests.exceptions import RequestException +import warnings from certbot.compat import os from certbot.plugins import dns_test_common @@ -36,7 +37,9 @@ class AuthenticatorTest(test_util.TempDirTestCase, self.config = mock.MagicMock(cloudxns_credentials=path, cloudxns_propagation_seconds=0) # don't wait during tests - self.auth = Authenticator(self.config, "cloudxns") + with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=UserWarning) + self.auth = Authenticator(self.config, "cloudxns") self.mock_client = mock.MagicMock() # _get_cloudxns_client | pylint: disable=protected-access diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index 18b37f396..8a46f71ba 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -10,7 +10,8 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). ### Changed -* +* The `certbot-dns-cloudxns` plugin is now deprecated and will be removed in the + next major release of Certbot. ### Fixed From 012314d946b4e2bd9b60053166f42ff9617ffba6 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 29 Aug 2022 17:28:47 -0700 Subject: [PATCH 10/18] Deprecate source address (#9389) * deprecate source_address * filter warnings * fix route53 tests * test warning * update docstring --- acme/acme/client.py | 13 +++++++++++-- acme/tests/client_test.py | 5 ++++- certbot/CHANGELOG.md | 2 ++ pytest.ini | 10 +++------- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/acme/acme/client.py b/acme/acme/client.py index e1dc9040f..dbb2a23f1 100644 --- a/acme/acme/client.py +++ b/acme/acme/client.py @@ -32,7 +32,13 @@ import OpenSSL import requests from requests.adapters import HTTPAdapter from requests.utils import parse_header_links -from requests_toolbelt.adapters.source import SourceAddressAdapter +# We're capturing the warnings described at +# https://github.com/requests/toolbelt/issues/331 until we can remove this +# dependency in Certbot 2.0. +with warnings.catch_warnings(): + warnings.filterwarnings("ignore", "'urllib3.contrib.pyopenssl", + DeprecationWarning) + from requests_toolbelt.adapters.source import SourceAddressAdapter from acme import challenges from acme import crypto_util @@ -1031,7 +1037,8 @@ class ClientNetwork: :param bool verify_ssl: Whether to verify certificates on SSL connections. :param str user_agent: String to send as User-Agent header. :param float timeout: Timeout for requests. - :param source_address: Optional source address to bind to when making requests. + :param source_address: Optional source address to bind to when making + requests. (deprecated since 1.30.0) :type source_address: str or tuple(str, int) """ def __init__(self, key: jose.JWK, account: Optional[messages.RegistrationResource] = None, @@ -1049,6 +1056,8 @@ class ClientNetwork: adapter = HTTPAdapter() if source_address is not None: + warnings.warn("Support for source_address is deprecated and will be " + "removed soon.", DeprecationWarning, stacklevel=2) adapter = SourceAddressAdapter(source_address) self.session.mount("http://", adapter) diff --git a/acme/tests/client_test.py b/acme/tests/client_test.py index 7ce28b4fe..1d9aa27fe 100644 --- a/acme/tests/client_test.py +++ b/acme/tests/client_test.py @@ -1343,7 +1343,10 @@ class ClientNetworkSourceAddressBindingTest(unittest.TestCase): def test_source_address_set(self): from acme.client import ClientNetwork - net = ClientNetwork(key=None, alg=None, source_address=self.source_address) + with mock.patch('warnings.warn') as mock_warn: + net = ClientNetwork(key=None, alg=None, source_address=self.source_address) + mock_warn.assert_called_once() + self.assertIn('source_address', mock_warn.call_args[0][0]) for adapter in net.session.adapters.values(): self.assertIn(self.source_address, adapter.source_address) diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index 8a46f71ba..90df55e53 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -12,6 +12,8 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). * The `certbot-dns-cloudxns` plugin is now deprecated and will be removed in the next major release of Certbot. +* The `source_address` argument for `acme.client.ClientNetwork` is deprecated + and support for it will be removed in the next major release. ### Fixed diff --git a/pytest.ini b/pytest.ini index 92a403451..9e8fb5c7b 100644 --- a/pytest.ini +++ b/pytest.ini @@ -22,11 +22,8 @@ # the certbot.display.util module. # 5) A deprecation warning is raised in dnspython==1.15.0 in the oldest tests for # certbot-dns-rfc2136. -# 6) The vendored version of six in botocore causes ImportWarnings in Python -# 3.10+. See https://github.com/boto/botocore/issues/2548. -# 7) botocore's default TLS settings raise deprecation warnings in Python -# 3.10+, but their values are sane from a security perspective. See -# https://github.com/boto/botocore/issues/2550. +# 6) botocore is currently using deprecated urllib3 functionality. See +# https://github.com/boto/botocore/issues/2744. filterwarnings = error ignore:The external mock module:PendingDeprecationWarning @@ -34,5 +31,4 @@ filterwarnings = ignore:.*attribute in certbot.interfaces module is deprecated:DeprecationWarning ignore:.*attribute in certbot.display.util module is deprecated:DeprecationWarning ignore:decodestring\(\) is a deprecated alias:DeprecationWarning:dns - ignore:_SixMetaPathImporter.:ImportWarning - ignore:ssl.PROTOCOL_TLS:DeprecationWarning:botocore + ignore:'urllib3.contrib.pyopenssl:DeprecationWarning:botocore From f9d148be56929813af739670474e489db0936a56 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 29 Aug 2022 23:39:48 -0700 Subject: [PATCH 11/18] Upgrade CI OS (#9391) * upgrade ubuntu * upgrade macos * use python3 --- .../templates/jobs/extended-tests-jobs.yml | 6 ++--- .../templates/jobs/packaging-jobs.yml | 10 ++++---- .../templates/jobs/standard-tests-jobs.yml | 24 +++++++++---------- .../templates/stages/deploy-stage.yml | 4 ++-- .../templates/steps/tox-steps.yml | 8 +++---- 5 files changed, 26 insertions(+), 26 deletions(-) diff --git a/.azure-pipelines/templates/jobs/extended-tests-jobs.yml b/.azure-pipelines/templates/jobs/extended-tests-jobs.yml index c5a1fb628..7c586ee5b 100644 --- a/.azure-pipelines/templates/jobs/extended-tests-jobs.yml +++ b/.azure-pipelines/templates/jobs/extended-tests-jobs.yml @@ -2,7 +2,7 @@ jobs: - job: extended_test variables: - name: IMAGE_NAME - value: ubuntu-18.04 + value: ubuntu-22.04 - name: PYTHON_VERSION value: 3.10 - group: certbot-common @@ -47,13 +47,13 @@ jobs: nginx-compat: TOXENV: nginx_compat linux-integration-rfc2136: - IMAGE_NAME: ubuntu-18.04 + IMAGE_NAME: ubuntu-22.04 PYTHON_VERSION: 3.8 TOXENV: integration-dns-rfc2136 docker-dev: TOXENV: docker_dev le-modification: - IMAGE_NAME: ubuntu-18.04 + IMAGE_NAME: ubuntu-22.04 TOXENV: modification farmtest-apache2: PYTHON_VERSION: 3.8 diff --git a/.azure-pipelines/templates/jobs/packaging-jobs.yml b/.azure-pipelines/templates/jobs/packaging-jobs.yml index 5545e559d..c5dcf16dd 100644 --- a/.azure-pipelines/templates/jobs/packaging-jobs.yml +++ b/.azure-pipelines/templates/jobs/packaging-jobs.yml @@ -1,7 +1,7 @@ jobs: - job: docker_build pool: - vmImage: ubuntu-18.04 + vmImage: ubuntu-22.04 strategy: matrix: amd64: @@ -37,7 +37,7 @@ jobs: - job: docker_run dependsOn: docker_build pool: - vmImage: ubuntu-18.04 + vmImage: ubuntu-22.04 steps: - task: DownloadPipelineArtifact@2 inputs: @@ -116,7 +116,7 @@ jobs: displayName: Run certbot integration tests - job: snaps_build pool: - vmImage: ubuntu-18.04 + vmImage: ubuntu-22.04 strategy: matrix: amd64: @@ -164,7 +164,7 @@ jobs: - job: snap_run dependsOn: snaps_build pool: - vmImage: ubuntu-18.04 + vmImage: ubuntu-22.04 steps: - task: UsePythonVersion@0 inputs: @@ -194,7 +194,7 @@ jobs: - job: snap_dns_run dependsOn: snaps_build pool: - vmImage: ubuntu-18.04 + vmImage: ubuntu-22.04 steps: - script: | set -e diff --git a/.azure-pipelines/templates/jobs/standard-tests-jobs.yml b/.azure-pipelines/templates/jobs/standard-tests-jobs.yml index 4deaf4f2b..cf5e20c0b 100644 --- a/.azure-pipelines/templates/jobs/standard-tests-jobs.yml +++ b/.azure-pipelines/templates/jobs/standard-tests-jobs.yml @@ -5,11 +5,11 @@ jobs: strategy: matrix: macos-py37-cover: - IMAGE_NAME: macOS-10.15 + IMAGE_NAME: macOS-12 PYTHON_VERSION: 3.7 TOXENV: py37-cover macos-py310-cover: - IMAGE_NAME: macOS-10.15 + IMAGE_NAME: macOS-12 PYTHON_VERSION: 3.10 TOXENV: py310-cover windows-py37: @@ -25,42 +25,42 @@ jobs: PYTHON_VERSION: 3.9 TOXENV: integration-certbot linux-oldest-tests-1: - IMAGE_NAME: ubuntu-18.04 + IMAGE_NAME: ubuntu-22.04 PYTHON_VERSION: 3.7 TOXENV: '{acme,apache,apache-v2,certbot}-oldest' linux-oldest-tests-2: - IMAGE_NAME: ubuntu-18.04 + IMAGE_NAME: ubuntu-22.04 PYTHON_VERSION: 3.7 TOXENV: '{dns,nginx}-oldest' linux-py37: - IMAGE_NAME: ubuntu-18.04 + IMAGE_NAME: ubuntu-22.04 PYTHON_VERSION: 3.7 TOXENV: py37 linux-py310-cover: - IMAGE_NAME: ubuntu-18.04 + IMAGE_NAME: ubuntu-22.04 PYTHON_VERSION: 3.10 TOXENV: py310-cover linux-py310-lint: - IMAGE_NAME: ubuntu-18.04 + IMAGE_NAME: ubuntu-22.04 PYTHON_VERSION: 3.10 TOXENV: lint-posix linux-py310-mypy: - IMAGE_NAME: ubuntu-18.04 + IMAGE_NAME: ubuntu-22.04 PYTHON_VERSION: 3.10 TOXENV: mypy-posix linux-integration: - IMAGE_NAME: ubuntu-18.04 + IMAGE_NAME: ubuntu-22.04 PYTHON_VERSION: 3.8 TOXENV: integration ACME_SERVER: pebble apache-compat: - IMAGE_NAME: ubuntu-18.04 + IMAGE_NAME: ubuntu-22.04 TOXENV: apache_compat apacheconftest: - IMAGE_NAME: ubuntu-18.04 + IMAGE_NAME: ubuntu-22.04 TOXENV: apacheconftest-with-pebble nginxroundtrip: - IMAGE_NAME: ubuntu-18.04 + IMAGE_NAME: ubuntu-22.04 TOXENV: nginxroundtrip pool: vmImage: $(IMAGE_NAME) diff --git a/.azure-pipelines/templates/stages/deploy-stage.yml b/.azure-pipelines/templates/stages/deploy-stage.yml index 424ffed10..8144f4bee 100644 --- a/.azure-pipelines/templates/stages/deploy-stage.yml +++ b/.azure-pipelines/templates/stages/deploy-stage.yml @@ -35,7 +35,7 @@ stages: # more info. - job: publish_snap pool: - vmImage: ubuntu-18.04 + vmImage: ubuntu-22.04 variables: - group: certbot-common strategy: @@ -71,7 +71,7 @@ stages: displayName: Publish to Snap store - job: publish_docker pool: - vmImage: ubuntu-18.04 + vmImage: ubuntu-22.04 strategy: matrix: amd64: diff --git a/.azure-pipelines/templates/steps/tox-steps.yml b/.azure-pipelines/templates/steps/tox-steps.yml index 3e5fb995d..fbda960a5 100644 --- a/.azure-pipelines/templates/steps/tox-steps.yml +++ b/.azure-pipelines/templates/steps/tox-steps.yml @@ -12,7 +12,7 @@ steps: set -e sudo apt-get update sudo apt-get install -y --no-install-recommends \ - python-dev \ + python3-dev \ gcc \ libaugeas0 \ libssl-dev \ @@ -36,8 +36,8 @@ steps: # problems with its lack of real dependency resolution. - bash: | set -e - python tools/pipstrap.py - python tools/pip_install.py -I tox virtualenv + python3 tools/pipstrap.py + python3 tools/pip_install.py -I tox virtualenv displayName: Install runtime dependencies - task: DownloadSecureFile@1 name: testFarmPem @@ -49,7 +49,7 @@ steps: export TARGET_BRANCH="`echo "${BUILD_SOURCEBRANCH}" | sed -E 's!refs/(heads|tags)/!!g'`" [ -z "${SYSTEM_PULLREQUEST_TARGETBRANCH}" ] || export TARGET_BRANCH="${SYSTEM_PULLREQUEST_TARGETBRANCH}" env - python -m tox + python3 -m tox env: AWS_ACCESS_KEY_ID: $(AWS_ACCESS_KEY_ID) AWS_SECRET_ACCESS_KEY: $(AWS_SECRET_ACCESS_KEY) From f7e61edcb2ea3195c9889c407a08e6dffb7f60dc Mon Sep 17 00:00:00 2001 From: alexzorin Date: Wed, 31 Aug 2022 07:41:53 +1000 Subject: [PATCH 12/18] deprecate more attributes in acme (#9369) * deprecate more attributes in acme * Deprecate .Authorization.combinations by renaming the field and deprecating in getters/setters * Silence deprecation warnings from our own imports of acme.mixins Co-authored-by: Brad Warren --- acme/acme/challenges.py | 8 ++++++-- acme/acme/client.py | 9 +++++++-- acme/acme/messages.py | 45 +++++++++++++++++++++++++++++++++++++---- acme/acme/mixins.py | 4 ++++ certbot/CHANGELOG.md | 3 +++ pytest.ini | 6 ++++++ 6 files changed, 67 insertions(+), 8 deletions(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index 91c3e6f24..534a60aad 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -14,6 +14,7 @@ from typing import Tuple from typing import Type from typing import TypeVar from typing import Union +import warnings from cryptography.hazmat.primitives import hashes import josepy as jose @@ -24,8 +25,11 @@ import requests from acme import crypto_util from acme import errors from acme import fields -from acme.mixins import ResourceMixin -from acme.mixins import TypeMixin + +with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + from acme.mixins import ResourceMixin + from acme.mixins import TypeMixin logger = logging.getLogger(__name__) diff --git a/acme/acme/client.py b/acme/acme/client.py index dbb2a23f1..be4c2e457 100644 --- a/acme/acme/client.py +++ b/acme/acme/client.py @@ -45,7 +45,9 @@ from acme import crypto_util from acme import errors from acme import jws from acme import messages -from acme.mixins import VersionedLEACMEMixin +with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + from acme.mixins import VersionedLEACMEMixin logger = logging.getLogger(__name__) @@ -57,6 +59,9 @@ DER_CONTENT_TYPE = 'application/pkix-cert' class ClientBase: """ACME client base object. + .. deprecated:: 1.30.0 + Use `ClientV2` instead. + :ivar messages.Directory directory: :ivar .ClientNetwork net: Client network. :ivar int acme_version: ACME protocol version. 1 or 2. @@ -1312,7 +1317,7 @@ class _ClientDeprecationModule: self.__dict__['_module'] = module def __getattr__(self, attr: str) -> Any: - if attr in ('Client', 'BackwardsCompatibleClientV2'): + if attr in ('Client', 'ClientBase', 'BackwardsCompatibleClientV2'): warnings.warn('The {0} attribute in acme.client is deprecated ' 'and will be removed soon.'.format(attr), DeprecationWarning, stacklevel=2) diff --git a/acme/acme/messages.py b/acme/acme/messages.py index 9b9ef5de2..fbb7738d0 100644 --- a/acme/acme/messages.py +++ b/acme/acme/messages.py @@ -14,6 +14,7 @@ from typing import Type from typing import TYPE_CHECKING from typing import TypeVar from typing import Union +import warnings import josepy as jose @@ -22,7 +23,9 @@ from acme import errors from acme import fields from acme import jws from acme import util -from acme.mixins import ResourceMixin +with warnings.catch_warnings(): + warnings.filterwarnings("ignore", category=DeprecationWarning) + from acme.mixins import ResourceMixin if TYPE_CHECKING: from typing_extensions import Protocol # pragma: no cover @@ -573,14 +576,14 @@ class Authorization(ResourceBody): :ivar acme.messages.Identifier identifier: :ivar list challenges: `list` of `.ChallengeBody` :ivar tuple combinations: Challenge combinations (`tuple` of `tuple` - of `int`, as opposed to `list` of `list` from the spec). + of `int`, as opposed to `list` of `list` from the spec). (deprecated since 1.30.0) :ivar acme.messages.Status status: :ivar datetime.datetime expires: """ identifier: Identifier = jose.field('identifier', decoder=Identifier.from_json, omitempty=True) challenges: List[ChallengeBody] = jose.field('challenges', omitempty=True) - combinations: Tuple[Tuple[int, ...], ...] = jose.field('combinations', omitempty=True) + _combinations: Tuple[Tuple[int, ...], ...] = jose.field('combinations', omitempty=True) status: Status = jose.field('status', omitempty=True, decoder=Status.from_json) # TODO: 'expires' is allowed for Authorization Resources in @@ -590,15 +593,49 @@ class Authorization(ResourceBody): expires: datetime.datetime = fields.rfc3339('expires', omitempty=True) wildcard: bool = jose.field('wildcard', omitempty=True) + # combinations is temporarily renamed to _combinations during its deprecation + # period. See https://github.com/certbot/certbot/pull/9369#issuecomment-1199849262. + def __init__(self, **kwargs: Any) -> None: + if 'combinations' in kwargs: + kwargs['_combinations'] = kwargs.pop('combinations') + super().__init__(**kwargs) + # Mypy does not understand the josepy magic happening here, and falsely claims # that challenge is redefined. Let's ignore the type check here. @challenges.decoder # type: ignore def challenges(value: List[Dict[str, Any]]) -> Tuple[ChallengeBody, ...]: # type: ignore[misc] # pylint: disable=no-self-argument,missing-function-docstring return tuple(ChallengeBody.from_json(chall) for chall in value) + @property + def combinations(self) -> Tuple[Tuple[int, ...], ...]: + """Challenge combinations. + (`tuple` of `tuple` of `int`, as opposed to `list` of `list` from the spec). + + .. deprecated: 1.30.0 + + """ + warnings.warn( + "acme.messages.Authorization.combinations is deprecated and will be " + "removed in a future release.", DeprecationWarning) + return self._combinations + + @combinations.setter + def combinations(self, combos: Tuple[Tuple[int, ...], ...]) -> None: # pragma: no cover + warnings.warn( + "acme.messages.Authorization.combinations is deprecated and will be " + "removed in a future release.", DeprecationWarning) + self._combinations = combos + @property def resolved_combinations(self) -> Tuple[Tuple[ChallengeBody, ...], ...]: - """Combinations with challenges instead of indices.""" + """Combinations with challenges instead of indices. + + .. deprecated: 1.30.0 + + """ + warnings.warn( + "acme.messages.Authorization.resolved_combinations is deprecated and will be " + "removed in a future release.", DeprecationWarning) return tuple(tuple(self.challenges[idx] for idx in combo) for combo in self.combinations) # pylint: disable=not-an-iterable diff --git a/acme/acme/mixins.py b/acme/acme/mixins.py index e6e678d60..4c52957a5 100644 --- a/acme/acme/mixins.py +++ b/acme/acme/mixins.py @@ -1,6 +1,10 @@ """Useful mixins for Challenge and Resource objects""" from typing import Any from typing import Dict +import warnings + +warnings.warn(f'The module {__name__} is deprecated and will be removed in a future release', + DeprecationWarning, stacklevel=2) class VersionedLEACMEMixin: diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index 90df55e53..04b25e98d 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -10,6 +10,9 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). ### Changed +* `acme.client.ClientBase`, `acme.messages.Authorization.resolved_combinations`, + `acme.messages.Authorization.combinations` and `acme.mixins` are deprecated and + will be removed in a future release. * The `certbot-dns-cloudxns` plugin is now deprecated and will be removed in the next major release of Certbot. * The `source_address` argument for `acme.client.ClientNetwork` is deprecated diff --git a/pytest.ini b/pytest.ini index 9e8fb5c7b..78710566b 100644 --- a/pytest.ini +++ b/pytest.ini @@ -24,6 +24,9 @@ # certbot-dns-rfc2136. # 6) botocore is currently using deprecated urllib3 functionality. See # https://github.com/boto/botocore/issues/2744. +# 7) ACMEv1 deprecations in acme.client which will be resolved by Certbot 2.0. +# 8) acme.mixins deprecation in acme.client which will be resolved by Certbot 2.0. +# 9) acme.messages.Authorization.combinations which will be resolved by Certbot 2.0. filterwarnings = error ignore:The external mock module:PendingDeprecationWarning @@ -32,3 +35,6 @@ filterwarnings = ignore:.*attribute in certbot.display.util module is deprecated:DeprecationWarning ignore:decodestring\(\) is a deprecated alias:DeprecationWarning:dns ignore:'urllib3.contrib.pyopenssl:DeprecationWarning:botocore + ignore:.*attribute in acme.client is deprecated:DeprecationWarning + ignore:.*acme.mixins is deprecated:DeprecationWarning + ignore:.*Authorization.combinations is deprecated:DeprecationWarning From c20d40ddbafb8db9e38cf5ec41b0ec187cc06686 Mon Sep 17 00:00:00 2001 From: alexzorin Date: Fri, 2 Sep 2022 23:55:04 +1000 Subject: [PATCH 13/18] acme: further deprecations (#9395) * acme: deprecate acme.fields.Resource and .resource * acme: deprecate .messages.OLD_ERROR_PREFIX * acme: deprecate .messages.Directory.register * acme: clean up deprecations * dont use unscoped filterwarnings * change deprecation approach for acme.fields * warn on non-string keys in acme.messages.Directory * remove leaked filterwarnings in BackwardsCompatibleClientV2Test * remove non-string lookups of acme.messages.Directory --- acme/acme/challenges.py | 4 +- acme/acme/client.py | 4 +- acme/acme/fields.py | 51 +++++++++- acme/acme/messages.py | 180 +++++++++++++++++++++++------------- acme/tests/client_test.py | 31 ++++--- acme/tests/fields_test.py | 7 +- acme/tests/messages_test.py | 17 ++-- certbot/CHANGELOG.md | 10 +- 8 files changed, 211 insertions(+), 93 deletions(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index 534a60aad..194f19e47 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -56,7 +56,9 @@ class ChallengeResponse(ResourceMixin, TypeMixin, jose.TypedJSONObjectWithFields """ACME challenge response.""" TYPES: Dict[str, Type['ChallengeResponse']] = {} resource_type = 'challenge' - resource: str = fields.resource(resource_type) + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', 'resource attribute in acme.fields', DeprecationWarning) + resource: str = fields.resource(resource_type) class UnrecognizedChallenge(Challenge): diff --git a/acme/acme/client.py b/acme/acme/client.py index be4c2e457..7d21b0fad 100644 --- a/acme/acme/client.py +++ b/acme/acme/client.py @@ -306,7 +306,7 @@ class Client(ClientBase): """ new_reg = messages.NewRegistration() if new_reg is None else new_reg - response = self._post(self.directory[new_reg], new_reg) + response = self._post(self.directory['new-reg'], new_reg) # TODO: handle errors assert response.status_code == http_client.CREATED @@ -612,7 +612,7 @@ class Client(ClientBase): :raises .ClientError: If revocation is unsuccessful. """ - self._revoke(cert, rsn, self.directory[messages.Revocation]) + self._revoke(cert, rsn, self.directory['revoke-cert']) class ClientV2(ClientBase): diff --git a/acme/acme/fields.py b/acme/acme/fields.py index 191231df2..8a1dc8462 100644 --- a/acme/acme/fields.py +++ b/acme/acme/fields.py @@ -1,8 +1,12 @@ """ACME JSON fields.""" import datetime -from typing import Any - import logging +import sys +from types import ModuleType +from typing import Any +from typing import cast +from typing import List +import warnings import josepy as jose import pyrfc3339 @@ -52,7 +56,11 @@ class RFC3339Field(jose.Field): class Resource(jose.Field): - """Resource MITM field.""" + """Resource MITM field. + + .. deprecated: 1.30.0 + + """ def __init__(self, resource_type: str, *args: Any, **kwargs: Any) -> None: self.resource_type = resource_type @@ -78,5 +86,40 @@ def rfc3339(json_name: str, omitempty: bool = False) -> Any: def resource(resource_type: str) -> Any: - """Generates a type-friendly Resource field.""" + """Generates a type-friendly Resource field. + + .. deprecated: 1.30.0 + + """ return Resource(resource_type) + + +# This class takes a similar approach to the cryptography project to deprecate attributes +# in public modules. See the _ModuleWithDeprecation class here: +# https://github.com/pyca/cryptography/blob/91105952739442a74582d3e62b3d2111365b0dc7/src/cryptography/utils.py#L129 +class _FieldsDeprecationModule: # pragma: no cover + """ + Internal class delegating to a module, and displaying warnings when + module attributes deprecated in acme.fields are accessed. + """ + def __init__(self, module: ModuleType) -> None: + self.__dict__['_module'] = module + + def __getattr__(self, attr: str) -> None: + if attr in ('Resource', 'resource'): + warnings.warn('{0} attribute in acme.fields module is deprecated ' + 'and will be removed soon.'.format(attr), + DeprecationWarning, stacklevel=2) + return getattr(self._module, attr) + + def __setattr__(self, attr: str, value: Any) -> None: + setattr(self._module, attr, value) + + def __delattr__(self, attr: str) -> None: + delattr(self._module, attr) + + def __dir__(self) -> List[str]: + return ['_module'] + dir(self._module) + + +sys.modules[__name__] = cast(ModuleType, _FieldsDeprecationModule(sys.modules[__name__])) diff --git a/acme/acme/messages.py b/acme/acme/messages.py index fbb7738d0..cdefcfa4f 100644 --- a/acme/acme/messages.py +++ b/acme/acme/messages.py @@ -2,7 +2,9 @@ import datetime from collections.abc import Hashable import json +from types import ModuleType from typing import Any +from typing import cast from typing import Dict from typing import Iterator from typing import List @@ -14,6 +16,7 @@ from typing import Type from typing import TYPE_CHECKING from typing import TypeVar from typing import Union +import sys import warnings import josepy as jose @@ -24,7 +27,7 @@ from acme import fields from acme import jws from acme import util with warnings.catch_warnings(): - warnings.filterwarnings("ignore", category=DeprecationWarning) + warnings.filterwarnings("ignore", ".*acme.mixins", category=DeprecationWarning) from acme.mixins import ResourceMixin if TYPE_CHECKING: @@ -277,6 +280,10 @@ class Directory(jose.JSONDeSerializable): def register(cls, resource_body_cls: Type[GenericHasResourceType]) -> Type[GenericHasResourceType]: """Register resource.""" + warnings.warn( + "acme.messages.Directory.register is deprecated and will be removed in the next " + "major release of Certbot", DeprecationWarning, stacklevel=2 + ) resource_type = resource_body_cls.resource_type assert resource_type not in cls._REGISTERED_TYPES cls._REGISTERED_TYPES[resource_type] = resource_body_cls @@ -295,6 +302,12 @@ class Directory(jose.JSONDeSerializable): raise AttributeError(str(error)) def __getitem__(self, name: Union[str, HasResourceType, Type[HasResourceType]]) -> Any: + if not isinstance(name, str): + warnings.warn( + "Looking up acme.messages.Directory resources by non-string keys is deprecated " + "and will be removed in the next major release of Certbot", + DeprecationWarning, stacklevel=2 + ) try: return self._jobj[self._canon_key(name)] except KeyError: @@ -462,19 +475,6 @@ class Registration(ResourceBody): return self._filter_contact(self.email_prefix) -@Directory.register -class NewRegistration(ResourceMixin, Registration): - """New registration.""" - resource_type = 'new-reg' - resource: str = fields.resource(resource_type) - - -class UpdateRegistration(ResourceMixin, Registration): - """Update registration.""" - resource_type = 'reg' - resource: str = fields.resource(resource_type) - - class RegistrationResource(ResourceWithURI): """Registration Resource. @@ -616,14 +616,14 @@ class Authorization(ResourceBody): """ warnings.warn( "acme.messages.Authorization.combinations is deprecated and will be " - "removed in a future release.", DeprecationWarning) + "removed in a future release.", DeprecationWarning, stacklevel=2) return self._combinations @combinations.setter def combinations(self, combos: Tuple[Tuple[int, ...], ...]) -> None: # pragma: no cover warnings.warn( "acme.messages.Authorization.combinations is deprecated and will be " - "removed in a future release.", DeprecationWarning) + "removed in a future release.", DeprecationWarning, stacklevel=2) self._combinations = combos @property @@ -635,22 +635,11 @@ class Authorization(ResourceBody): """ warnings.warn( "acme.messages.Authorization.resolved_combinations is deprecated and will be " - "removed in a future release.", DeprecationWarning) - return tuple(tuple(self.challenges[idx] for idx in combo) - for combo in self.combinations) # pylint: disable=not-an-iterable - - -@Directory.register -class NewAuthorization(ResourceMixin, Authorization): - """New authorization.""" - resource_type = 'new-authz' - resource: str = fields.resource(resource_type) - - -class UpdateAuthorization(ResourceMixin, Authorization): - """Update authorization.""" - resource_type = 'authz' - resource: str = fields.resource(resource_type) + "removed in a future release.", DeprecationWarning, stacklevel=2) + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', '.*combinations', DeprecationWarning) + return tuple(tuple(self.challenges[idx] for idx in combo) + for combo in self.combinations) # pylint: disable=not-an-iterable class AuthorizationResource(ResourceWithURI): @@ -664,19 +653,6 @@ class AuthorizationResource(ResourceWithURI): new_cert_uri: str = jose.field('new_cert_uri', omitempty=True) -@Directory.register -class CertificateRequest(ResourceMixin, jose.JSONObjectWithFields): - """ACME new-cert request. - - :ivar jose.ComparableX509 csr: - `OpenSSL.crypto.X509Req` wrapped in `.ComparableX509` - - """ - resource_type = 'new-cert' - resource: str = fields.resource(resource_type) - csr: jose.ComparableX509 = jose.field('csr', decoder=jose.decode_csr, encoder=jose.encode_csr) - - class CertificateResource(ResourceWithURI): """Certificate Resource. @@ -690,21 +666,6 @@ class CertificateResource(ResourceWithURI): authzrs: Tuple[AuthorizationResource, ...] = jose.field('authzrs') -@Directory.register -class Revocation(ResourceMixin, jose.JSONObjectWithFields): - """Revocation message. - - :ivar jose.ComparableX509 certificate: `OpenSSL.crypto.X509` wrapped in - `jose.ComparableX509` - - """ - resource_type = 'revoke-cert' - resource: str = fields.resource(resource_type) - certificate: jose.ComparableX509 = jose.field( - 'certificate', decoder=jose.decode_cert, encoder=jose.encode_cert) - reason: int = jose.field('reason') - - class Order(ResourceBody): """Order Resource Body. @@ -756,7 +717,98 @@ class OrderResource(ResourceWithURI): omitempty=True) -@Directory.register -class NewOrder(Order): - """New order.""" - resource_type = 'new-order' +with warnings.catch_warnings(): + warnings.filterwarnings("ignore", "acme.messages.Directory.register", DeprecationWarning) + warnings.filterwarnings("ignore", "resource attribute in acme.fields", DeprecationWarning) + + @Directory.register + class NewOrder(Order): + """New order.""" + resource_type = 'new-order' + + + @Directory.register + class Revocation(ResourceMixin, jose.JSONObjectWithFields): + """Revocation message. + + :ivar jose.ComparableX509 certificate: `OpenSSL.crypto.X509` wrapped in + `jose.ComparableX509` + + """ + resource_type = 'revoke-cert' + resource: str = fields.resource(resource_type) + certificate: jose.ComparableX509 = jose.field( + 'certificate', decoder=jose.decode_cert, encoder=jose.encode_cert) + reason: int = jose.field('reason') + + + @Directory.register + class CertificateRequest(ResourceMixin, jose.JSONObjectWithFields): + """ACME new-cert request. + + :ivar jose.ComparableX509 csr: + `OpenSSL.crypto.X509Req` wrapped in `.ComparableX509` + + """ + resource_type = 'new-cert' + resource: str = fields.resource(resource_type) + csr: jose.ComparableX509 = jose.field('csr', decoder=jose.decode_csr, + encoder=jose.encode_csr) + + + @Directory.register + class NewAuthorization(ResourceMixin, Authorization): + """New authorization.""" + resource_type = 'new-authz' + resource: str = fields.resource(resource_type) + + + class UpdateAuthorization(ResourceMixin, Authorization): + """Update authorization.""" + resource_type = 'authz' + resource: str = fields.resource(resource_type) + + + @Directory.register + class NewRegistration(ResourceMixin, Registration): + """New registration.""" + resource_type = 'new-reg' + resource: str = fields.resource(resource_type) + + + class UpdateRegistration(ResourceMixin, Registration): + """Update registration.""" + resource_type = 'reg' + resource: str = fields.resource(resource_type) + + +# This class takes a similar approach to the cryptography project to deprecate attributes +# in public modules. See the _ModuleWithDeprecation class here: +# https://github.com/pyca/cryptography/blob/91105952739442a74582d3e62b3d2111365b0dc7/src/cryptography/utils.py#L129 +class _MessagesDeprecationModule: # pragma: no cover + """ + Internal class delegating to a module, and displaying warnings when + module attributes deprecated in acme.messages are accessed. + """ + def __init__(self, module: ModuleType) -> None: + self.__dict__['_module'] = module + + def __getattr__(self, attr: str) -> None: + if attr == 'OLD_ERROR_PREFIX': + warnings.warn('{0} attribute in acme.messages module is deprecated ' + 'and will be removed soon.'.format(attr), + DeprecationWarning, stacklevel=2) + return getattr(self._module, attr) + + def __setattr__(self, attr: str, value: Any) -> None: + setattr(self._module, attr, value) + + def __delattr__(self, attr: str) -> None: + delattr(self._module, attr) + + def __dir__(self) -> List[str]: + return ['_module'] + dir(self._module) + + +# Patching ourselves to warn about acme.messages.OLD_ERROR_PREFIX deprecation and planned removal. +sys.modules[__name__] = cast(ModuleType, _MessagesDeprecationModule(sys.modules[__name__])) diff --git a/acme/tests/client_test.py b/acme/tests/client_test.py index 1d9aa27fe..e717f734a 100644 --- a/acme/tests/client_test.py +++ b/acme/tests/client_test.py @@ -3,11 +3,11 @@ import copy import datetime import http.client as http_client -import ipaddress import json import unittest from typing import Dict from unittest import mock +import warnings import josepy as jose import OpenSSL @@ -17,9 +17,17 @@ from acme import challenges from acme import errors from acme import jws as acme_jws from acme import messages +from acme.client import ClientNetwork +from acme.client import ClientV2 from acme.mixins import VersionedLEACMEMixin import messages_test import test_util +# Remove the following in Certbot 2.0: +with warnings.catch_warnings(): + warnings.filterwarnings('ignore', '.* in acme.client', DeprecationWarning) + from acme.client import BackwardsCompatibleClientV2 + from acme.client import Client + CERT_DER = test_util.load_vector('cert.der') CERT_SAN_PEM = test_util.load_vector('cert-san.pem') @@ -87,12 +95,17 @@ class ClientTestBase(unittest.TestCase): # Reason code for revocation self.rsn = 1 - class BackwardsCompatibleClientV2Test(ClientTestBase): """Tests for acme.client.BackwardsCompatibleClientV2.""" def setUp(self): super().setUp() + + # For some reason, required to suppress warnings on mock.patch('acme.client.Client') + self.warning_cap = warnings.catch_warnings() + self.warning_cap.__enter__() + warnings.filterwarnings('ignore', '.*acme.client', DeprecationWarning) + # contains a loaded cert self.certr = messages.CertificateResource( body=messages_test.CERT) @@ -114,15 +127,17 @@ class BackwardsCompatibleClientV2Test(ClientTestBase): self.orderr = messages.OrderResource( csr_pem=CSR_SAN_PEM) + def tearDown(self) -> None: + self.warning_cap.__exit__() + return super().tearDown() + def _init(self): uri = 'http://www.letsencrypt-demo.org/directory' - from acme.client import BackwardsCompatibleClientV2 return BackwardsCompatibleClientV2(net=self.net, key=KEY, server=uri) def test_init_downloads_directory(self): uri = 'http://www.letsencrypt-demo.org/directory' - from acme.client import BackwardsCompatibleClientV2 BackwardsCompatibleClientV2(net=self.net, key=KEY, server=uri) self.net.get.assert_called_once_with(uri) @@ -336,13 +351,11 @@ class ClientTest(ClientTestBase): uri='https://www.letsencrypt-demo.org/acme/cert/1', cert_chain_uri='https://www.letsencrypt-demo.org/ca') - from acme.client import Client self.client = Client( directory=self.directory, key=KEY, alg=jose.RS256, net=self.net) def test_init_downloads_directory(self): uri = 'http://www.letsencrypt-demo.org/directory' - from acme.client import Client self.client = Client( directory=uri, key=KEY, alg=jose.RS256, net=self.net) self.net.get.assert_called_once_with(uri) @@ -351,7 +364,6 @@ class ClientTest(ClientTestBase): def test_init_without_net(self, mock_net): mock_net.return_value = mock.sentinel.net alg = jose.RS256 - from acme.client import Client self.client = Client( directory=self.directory, key=KEY, alg=alg) mock_net.called_once_with(KEY, alg=alg, verify_ssl=True) @@ -723,7 +735,6 @@ class ClientV2Test(ClientTestBase): self.directory = DIRECTORY_V2 - from acme.client import ClientV2 self.client = ClientV2(self.directory, self.net) self.new_reg = self.new_reg.update(terms_of_service_agreed=True) @@ -948,7 +959,6 @@ class ClientNetworkTest(unittest.TestCase): self.verify_ssl = mock.MagicMock() self.wrap_in_jws = mock.MagicMock(return_value=mock.sentinel.wrapped) - from acme.client import ClientNetwork self.net = ClientNetwork( key=KEY, alg=jose.RS256, verify_ssl=self.verify_ssl, user_agent='acme-python-test') @@ -1179,7 +1189,6 @@ class ClientNetworkWithMockedResponseTest(unittest.TestCase): """Tests for acme.client.ClientNetwork which mock out response.""" def setUp(self): - from acme.client import ClientNetwork self.net = ClientNetwork(key=None, alg=None) self.response = mock.MagicMock(ok=True, status_code=http_client.OK) @@ -1342,7 +1351,6 @@ class ClientNetworkSourceAddressBindingTest(unittest.TestCase): self.source_address = "8.8.8.8" def test_source_address_set(self): - from acme.client import ClientNetwork with mock.patch('warnings.warn') as mock_warn: net = ClientNetwork(key=None, alg=None, source_address=self.source_address) mock_warn.assert_called_once() @@ -1353,7 +1361,6 @@ class ClientNetworkSourceAddressBindingTest(unittest.TestCase): def test_behavior_assumption(self): """This is a test that guardrails the HTTPAdapter behavior so that if the default for a Session() changes, the assumptions here aren't violated silently.""" - from acme.client import ClientNetwork # Source address not specified, so the default adapter type should be bound -- this # test should fail if the default adapter type is changed by requests net = ClientNetwork(key=None, alg=None) diff --git a/acme/tests/fields_test.py b/acme/tests/fields_test.py index 4cc167f9c..76b215342 100644 --- a/acme/tests/fields_test.py +++ b/acme/tests/fields_test.py @@ -1,6 +1,7 @@ """Tests for acme.fields.""" import datetime import unittest +import warnings import josepy as jose import pytz @@ -58,8 +59,10 @@ class ResourceTest(unittest.TestCase): """Tests for acme.fields.Resource.""" def setUp(self): - from acme.fields import Resource - self.field = Resource('x') + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', '.*Resource', DeprecationWarning) + from acme.fields import Resource + self.field = Resource('x') def test_decode_good(self): self.assertEqual('x', self.field.decode('x')) diff --git a/acme/tests/messages_test.py b/acme/tests/messages_test.py index cf7e7629a..782955fb4 100644 --- a/acme/tests/messages_test.py +++ b/acme/tests/messages_test.py @@ -2,6 +2,7 @@ from typing import Dict import unittest from unittest import mock +import warnings import josepy as jose @@ -150,8 +151,10 @@ class DirectoryTest(unittest.TestCase): def test_getitem(self): self.assertEqual('reg', self.dir['new-reg']) from acme.messages import NewRegistration - self.assertEqual('reg', self.dir[NewRegistration]) - self.assertEqual('reg', self.dir[NewRegistration()]) + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', '.* non-string keys', DeprecationWarning) + self.assertEqual('reg', self.dir[NewRegistration]) + self.assertEqual('reg', self.dir[NewRegistration()]) def test_getitem_fails_with_key_error(self): self.assertRaises(KeyError, self.dir.__getitem__, 'foo') @@ -407,10 +410,12 @@ class AuthorizationTest(unittest.TestCase): hash(Authorization.from_json(self.jobj_from)) def test_resolved_combinations(self): - self.assertEqual(self.authz.resolved_combinations, ( - (self.challbs[0],), - (self.challbs[1],), - )) + with warnings.catch_warnings(): + warnings.filterwarnings('ignore', '.*resolved_combinations', DeprecationWarning) + self.assertEqual(self.authz.resolved_combinations, ( + (self.challbs[0],), + (self.challbs[1],), + )) class AuthorizationResourceTest(unittest.TestCase): diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index 04b25e98d..22c2ffdba 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -11,8 +11,14 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). ### Changed * `acme.client.ClientBase`, `acme.messages.Authorization.resolved_combinations`, - `acme.messages.Authorization.combinations` and `acme.mixins` are deprecated and - will be removed in a future release. + `acme.messages.Authorization.combinations`, `acme.mixins`, `acme.fields.resource`, + and `acme.fields.Resource` are deprecated and will be removed in a future release. +* `acme.messages.OLD_ERROR_PREFIX` (`urn:acme:error:`) is deprecated and support for + the old ACME error prefix in Certbot will be removed in the next major release of + Certbot. +* `acme.messages.Directory.register` is deprecated and will be removed in the next + major release of Certbot. Furthermore, `.Directory` will only support lookups + by the exact resource name string in the ACME directory (e.g. `directory['newOrder']`). * The `certbot-dns-cloudxns` plugin is now deprecated and will be removed in the next major release of Certbot. * The `source_address` argument for `acme.client.ClientNetwork` is deprecated From 20ca9288d5c55f47a9dbbafe3b9fe4157308cb77 Mon Sep 17 00:00:00 2001 From: Will Greenberg Date: Tue, 6 Sep 2022 19:55:58 -0700 Subject: [PATCH 14/18] Add UI text recommending multi-domain certs (#9393) * Suggest multi-domain certs in domain selection menu * Update changelog * lint: fix long line Co-authored-by: Alex Zorin --- certbot/CHANGELOG.md | 1 + certbot/certbot/display/ops.py | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index 22c2ffdba..06a415777 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -23,6 +23,7 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). next major release of Certbot. * The `source_address` argument for `acme.client.ClientNetwork` is deprecated and support for it will be removed in the next major release. +* Add UI text suggesting users create certs for multiple domains, when possible ### Fixed diff --git a/certbot/certbot/display/ops.py b/certbot/certbot/display/ops.py index f07093b55..d5b2c2420 100644 --- a/certbot/certbot/display/ops.py +++ b/certbot/certbot/display/ops.py @@ -181,7 +181,10 @@ def _filter_names(names: Iterable[str], if override_question: question = override_question else: - question = "Which names would you like to activate HTTPS for?" + question = ( + "Which names would you like to activate HTTPS for?\n" + "We recommend selecting either all domains, or all domains in a VirtualHost/server " + "block.") code, names = display_util.checklist( question, tags=sorted_names, cli_flag="--domains", force_interactive=True) return code, [str(s) for s in names] From c68d4d638994f47e08fb82652ec0493beb265b35 Mon Sep 17 00:00:00 2001 From: Will Greenberg Date: Wed, 7 Sep 2022 11:08:15 -0700 Subject: [PATCH 15/18] Update changelog for 1.30.0 release --- certbot/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index 06a415777..2e3da5f17 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -2,7 +2,7 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). -## 1.30.0 - master +## 1.30.0 - 2022-09-07 ### Added From 667b73687952ed7b6bf1a1f64d34a288f141fb31 Mon Sep 17 00:00:00 2001 From: Will Greenberg Date: Wed, 7 Sep 2022 11:09:11 -0700 Subject: [PATCH 16/18] Release 1.30.0 --- acme/setup.py | 2 +- certbot-apache/setup.py | 2 +- certbot-compatibility-test/setup.py | 2 +- certbot-dns-cloudflare/setup.py | 2 +- certbot-dns-cloudxns/setup.py | 2 +- certbot-dns-digitalocean/setup.py | 2 +- certbot-dns-dnsimple/setup.py | 2 +- certbot-dns-dnsmadeeasy/setup.py | 2 +- certbot-dns-gehirn/setup.py | 2 +- certbot-dns-google/setup.py | 2 +- certbot-dns-linode/setup.py | 2 +- certbot-dns-luadns/setup.py | 2 +- certbot-dns-nsone/setup.py | 2 +- certbot-dns-ovh/setup.py | 2 +- certbot-dns-rfc2136/setup.py | 2 +- certbot-dns-route53/setup.py | 2 +- certbot-dns-sakuracloud/setup.py | 2 +- certbot-nginx/setup.py | 2 +- certbot/certbot/__init__.py | 2 +- certbot/docs/cli-help.txt | 6 ++++-- 20 files changed, 23 insertions(+), 21 deletions(-) diff --git a/acme/setup.py b/acme/setup.py index f385bcb92..609f34cf8 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -3,7 +3,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0.dev0' +version = '1.30.0' install_requires = [ 'cryptography>=2.5.0', diff --git a/certbot-apache/setup.py b/certbot-apache/setup.py index 98beb4eaa..5b5f1aeae 100644 --- a/certbot-apache/setup.py +++ b/certbot-apache/setup.py @@ -1,7 +1,7 @@ from setuptools import find_packages from setuptools import setup -version = '1.30.0.dev0' +version = '1.30.0' install_requires = [ # We specify the minimum acme and certbot version as the current plugin diff --git a/certbot-compatibility-test/setup.py b/certbot-compatibility-test/setup.py index b34333f6d..fea435842 100644 --- a/certbot-compatibility-test/setup.py +++ b/certbot-compatibility-test/setup.py @@ -1,7 +1,7 @@ from setuptools import find_packages from setuptools import setup -version = '1.30.0.dev0' +version = '1.30.0' install_requires = [ 'certbot', diff --git a/certbot-dns-cloudflare/setup.py b/certbot-dns-cloudflare/setup.py index 150b9f51e..fa6617fbe 100644 --- a/certbot-dns-cloudflare/setup.py +++ b/certbot-dns-cloudflare/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0.dev0' +version = '1.30.0' install_requires = [ 'cloudflare>=1.5.1', diff --git a/certbot-dns-cloudxns/setup.py b/certbot-dns-cloudxns/setup.py index acb3dd4cc..daf743441 100644 --- a/certbot-dns-cloudxns/setup.py +++ b/certbot-dns-cloudxns/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0.dev0' +version = '1.30.0' install_requires = [ 'dns-lexicon>=3.2.1', diff --git a/certbot-dns-digitalocean/setup.py b/certbot-dns-digitalocean/setup.py index 1ab16b33f..ab7ba9c0d 100644 --- a/certbot-dns-digitalocean/setup.py +++ b/certbot-dns-digitalocean/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0.dev0' +version = '1.30.0' install_requires = [ 'python-digitalocean>=1.11', # 1.15.0 or newer is recommended for TTL support diff --git a/certbot-dns-dnsimple/setup.py b/certbot-dns-dnsimple/setup.py index eb93976d2..c9ac23e5e 100644 --- a/certbot-dns-dnsimple/setup.py +++ b/certbot-dns-dnsimple/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0.dev0' +version = '1.30.0' install_requires = [ # This version of lexicon is required to address the problem described in diff --git a/certbot-dns-dnsmadeeasy/setup.py b/certbot-dns-dnsmadeeasy/setup.py index dac8dbb28..bb297be5a 100644 --- a/certbot-dns-dnsmadeeasy/setup.py +++ b/certbot-dns-dnsmadeeasy/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0.dev0' +version = '1.30.0' install_requires = [ 'dns-lexicon>=3.2.1', diff --git a/certbot-dns-gehirn/setup.py b/certbot-dns-gehirn/setup.py index f5331d023..36e74a68d 100644 --- a/certbot-dns-gehirn/setup.py +++ b/certbot-dns-gehirn/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0.dev0' +version = '1.30.0' install_requires = [ 'dns-lexicon>=3.2.1', diff --git a/certbot-dns-google/setup.py b/certbot-dns-google/setup.py index bde460bdc..7e07216ac 100644 --- a/certbot-dns-google/setup.py +++ b/certbot-dns-google/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0.dev0' +version = '1.30.0' install_requires = [ 'google-api-python-client>=1.5.5', diff --git a/certbot-dns-linode/setup.py b/certbot-dns-linode/setup.py index 4b9f1e53d..8cc4b147e 100644 --- a/certbot-dns-linode/setup.py +++ b/certbot-dns-linode/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0.dev0' +version = '1.30.0' install_requires = [ 'dns-lexicon>=3.2.1', diff --git a/certbot-dns-luadns/setup.py b/certbot-dns-luadns/setup.py index 5728fc5d7..27c9b9615 100644 --- a/certbot-dns-luadns/setup.py +++ b/certbot-dns-luadns/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0.dev0' +version = '1.30.0' install_requires = [ 'dns-lexicon>=3.2.1', diff --git a/certbot-dns-nsone/setup.py b/certbot-dns-nsone/setup.py index b84ab62bc..7b858a1aa 100644 --- a/certbot-dns-nsone/setup.py +++ b/certbot-dns-nsone/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0.dev0' +version = '1.30.0' install_requires = [ 'dns-lexicon>=3.2.1', diff --git a/certbot-dns-ovh/setup.py b/certbot-dns-ovh/setup.py index 443e2cb25..a73604645 100644 --- a/certbot-dns-ovh/setup.py +++ b/certbot-dns-ovh/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0.dev0' +version = '1.30.0' install_requires = [ 'dns-lexicon>=3.2.1', diff --git a/certbot-dns-rfc2136/setup.py b/certbot-dns-rfc2136/setup.py index 207d14182..0b2615d84 100644 --- a/certbot-dns-rfc2136/setup.py +++ b/certbot-dns-rfc2136/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0.dev0' +version = '1.30.0' install_requires = [ 'dnspython>=1.15.0', diff --git a/certbot-dns-route53/setup.py b/certbot-dns-route53/setup.py index d09e7e6e2..b030b8ef0 100644 --- a/certbot-dns-route53/setup.py +++ b/certbot-dns-route53/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0.dev0' +version = '1.30.0' install_requires = [ 'boto3>=1.15.15', diff --git a/certbot-dns-sakuracloud/setup.py b/certbot-dns-sakuracloud/setup.py index 60472b280..36acec428 100644 --- a/certbot-dns-sakuracloud/setup.py +++ b/certbot-dns-sakuracloud/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0.dev0' +version = '1.30.0' install_requires = [ 'dns-lexicon>=3.2.1', diff --git a/certbot-nginx/setup.py b/certbot-nginx/setup.py index 40809653e..593e083ea 100644 --- a/certbot-nginx/setup.py +++ b/certbot-nginx/setup.py @@ -1,7 +1,7 @@ from setuptools import find_packages from setuptools import setup -version = '1.30.0.dev0' +version = '1.30.0' install_requires = [ # We specify the minimum acme and certbot version as the current plugin diff --git a/certbot/certbot/__init__.py b/certbot/certbot/__init__.py index 7a59f02f6..e557e206e 100644 --- a/certbot/certbot/__init__.py +++ b/certbot/certbot/__init__.py @@ -1,3 +1,3 @@ """Certbot client.""" # version number like 1.2.3a0, must have at least 2 parts, like 1.2 -__version__ = '1.30.0.dev0' +__version__ = '1.30.0' diff --git a/certbot/docs/cli-help.txt b/certbot/docs/cli-help.txt index ca3ba8a4a..8592825f2 100644 --- a/certbot/docs/cli-help.txt +++ b/certbot/docs/cli-help.txt @@ -126,7 +126,7 @@ optional arguments: case, and to know when to deprecate support for past Python versions and flags. If you wish to hide this information from the Let's Encrypt server, set this to - "". (default: CertbotACMEClient/1.29.0 (certbot; + "". (default: CertbotACMEClient/1.30.0 (certbot; OS_NAME OS_VERSION) Authenticator/XXX Installer/YYY (SUBCOMMAND; flags: FLAGS) Py/major.minor.patchlevel). The flags encoded in the user agent are: --duplicate, @@ -236,7 +236,9 @@ testing: (default: False) --debug Show tracebacks in case of errors (default: False) --no-verify-ssl Disable verification of the ACME server's certificate. - (default: False) + The root certificates trusted by Certbot can be + overriden by setting the REQUESTS_CA_BUNDLE + environment variable. (default: False) --http-01-port HTTP01_PORT Port used in the http-01 challenge. This only affects the port Certbot listens on. A conforming ACME server From 0b284125d21649e14d572dca37c78384b2f5f1ef Mon Sep 17 00:00:00 2001 From: Will Greenberg Date: Wed, 7 Sep 2022 11:09:12 -0700 Subject: [PATCH 17/18] Add contents to certbot/CHANGELOG.md for next version --- certbot/CHANGELOG.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index 2e3da5f17..8c5f65e50 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -2,6 +2,22 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). +## 1.31.0 - master + +### Added + +* + +### Changed + +* + +### Fixed + +* + +More details about these changes can be found on our GitHub repo. + ## 1.30.0 - 2022-09-07 ### Added From 614eaf68986362b27e76d9bbe092df9afe9affd3 Mon Sep 17 00:00:00 2001 From: Will Greenberg Date: Wed, 7 Sep 2022 11:09:12 -0700 Subject: [PATCH 18/18] Bump version to 1.31.0 --- acme/setup.py | 2 +- certbot-apache/setup.py | 2 +- certbot-compatibility-test/setup.py | 2 +- certbot-dns-cloudflare/setup.py | 2 +- certbot-dns-cloudxns/setup.py | 2 +- certbot-dns-digitalocean/setup.py | 2 +- certbot-dns-dnsimple/setup.py | 2 +- certbot-dns-dnsmadeeasy/setup.py | 2 +- certbot-dns-gehirn/setup.py | 2 +- certbot-dns-google/setup.py | 2 +- certbot-dns-linode/setup.py | 2 +- certbot-dns-luadns/setup.py | 2 +- certbot-dns-nsone/setup.py | 2 +- certbot-dns-ovh/setup.py | 2 +- certbot-dns-rfc2136/setup.py | 2 +- certbot-dns-route53/setup.py | 2 +- certbot-dns-sakuracloud/setup.py | 2 +- certbot-nginx/setup.py | 2 +- certbot/certbot/__init__.py | 2 +- 19 files changed, 19 insertions(+), 19 deletions(-) diff --git a/acme/setup.py b/acme/setup.py index 609f34cf8..5d88564dd 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -3,7 +3,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0' +version = '1.31.0.dev0' install_requires = [ 'cryptography>=2.5.0', diff --git a/certbot-apache/setup.py b/certbot-apache/setup.py index 5b5f1aeae..425f85db7 100644 --- a/certbot-apache/setup.py +++ b/certbot-apache/setup.py @@ -1,7 +1,7 @@ from setuptools import find_packages from setuptools import setup -version = '1.30.0' +version = '1.31.0.dev0' install_requires = [ # We specify the minimum acme and certbot version as the current plugin diff --git a/certbot-compatibility-test/setup.py b/certbot-compatibility-test/setup.py index fea435842..f5c1291ea 100644 --- a/certbot-compatibility-test/setup.py +++ b/certbot-compatibility-test/setup.py @@ -1,7 +1,7 @@ from setuptools import find_packages from setuptools import setup -version = '1.30.0' +version = '1.31.0.dev0' install_requires = [ 'certbot', diff --git a/certbot-dns-cloudflare/setup.py b/certbot-dns-cloudflare/setup.py index fa6617fbe..3efbb1494 100644 --- a/certbot-dns-cloudflare/setup.py +++ b/certbot-dns-cloudflare/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0' +version = '1.31.0.dev0' install_requires = [ 'cloudflare>=1.5.1', diff --git a/certbot-dns-cloudxns/setup.py b/certbot-dns-cloudxns/setup.py index daf743441..3f298d9be 100644 --- a/certbot-dns-cloudxns/setup.py +++ b/certbot-dns-cloudxns/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0' +version = '1.31.0.dev0' install_requires = [ 'dns-lexicon>=3.2.1', diff --git a/certbot-dns-digitalocean/setup.py b/certbot-dns-digitalocean/setup.py index ab7ba9c0d..9b4196133 100644 --- a/certbot-dns-digitalocean/setup.py +++ b/certbot-dns-digitalocean/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0' +version = '1.31.0.dev0' install_requires = [ 'python-digitalocean>=1.11', # 1.15.0 or newer is recommended for TTL support diff --git a/certbot-dns-dnsimple/setup.py b/certbot-dns-dnsimple/setup.py index c9ac23e5e..dfc3e529f 100644 --- a/certbot-dns-dnsimple/setup.py +++ b/certbot-dns-dnsimple/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0' +version = '1.31.0.dev0' install_requires = [ # This version of lexicon is required to address the problem described in diff --git a/certbot-dns-dnsmadeeasy/setup.py b/certbot-dns-dnsmadeeasy/setup.py index bb297be5a..276a94ca9 100644 --- a/certbot-dns-dnsmadeeasy/setup.py +++ b/certbot-dns-dnsmadeeasy/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0' +version = '1.31.0.dev0' install_requires = [ 'dns-lexicon>=3.2.1', diff --git a/certbot-dns-gehirn/setup.py b/certbot-dns-gehirn/setup.py index 36e74a68d..c9247f341 100644 --- a/certbot-dns-gehirn/setup.py +++ b/certbot-dns-gehirn/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0' +version = '1.31.0.dev0' install_requires = [ 'dns-lexicon>=3.2.1', diff --git a/certbot-dns-google/setup.py b/certbot-dns-google/setup.py index 7e07216ac..d5a6acc94 100644 --- a/certbot-dns-google/setup.py +++ b/certbot-dns-google/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0' +version = '1.31.0.dev0' install_requires = [ 'google-api-python-client>=1.5.5', diff --git a/certbot-dns-linode/setup.py b/certbot-dns-linode/setup.py index 8cc4b147e..03f3f3bc2 100644 --- a/certbot-dns-linode/setup.py +++ b/certbot-dns-linode/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0' +version = '1.31.0.dev0' install_requires = [ 'dns-lexicon>=3.2.1', diff --git a/certbot-dns-luadns/setup.py b/certbot-dns-luadns/setup.py index 27c9b9615..224181566 100644 --- a/certbot-dns-luadns/setup.py +++ b/certbot-dns-luadns/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0' +version = '1.31.0.dev0' install_requires = [ 'dns-lexicon>=3.2.1', diff --git a/certbot-dns-nsone/setup.py b/certbot-dns-nsone/setup.py index 7b858a1aa..b89b64e01 100644 --- a/certbot-dns-nsone/setup.py +++ b/certbot-dns-nsone/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0' +version = '1.31.0.dev0' install_requires = [ 'dns-lexicon>=3.2.1', diff --git a/certbot-dns-ovh/setup.py b/certbot-dns-ovh/setup.py index a73604645..70c3d6fbe 100644 --- a/certbot-dns-ovh/setup.py +++ b/certbot-dns-ovh/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0' +version = '1.31.0.dev0' install_requires = [ 'dns-lexicon>=3.2.1', diff --git a/certbot-dns-rfc2136/setup.py b/certbot-dns-rfc2136/setup.py index 0b2615d84..01a026d61 100644 --- a/certbot-dns-rfc2136/setup.py +++ b/certbot-dns-rfc2136/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0' +version = '1.31.0.dev0' install_requires = [ 'dnspython>=1.15.0', diff --git a/certbot-dns-route53/setup.py b/certbot-dns-route53/setup.py index b030b8ef0..ed4cc0a11 100644 --- a/certbot-dns-route53/setup.py +++ b/certbot-dns-route53/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0' +version = '1.31.0.dev0' install_requires = [ 'boto3>=1.15.15', diff --git a/certbot-dns-sakuracloud/setup.py b/certbot-dns-sakuracloud/setup.py index 36acec428..10a606b4c 100644 --- a/certbot-dns-sakuracloud/setup.py +++ b/certbot-dns-sakuracloud/setup.py @@ -4,7 +4,7 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.30.0' +version = '1.31.0.dev0' install_requires = [ 'dns-lexicon>=3.2.1', diff --git a/certbot-nginx/setup.py b/certbot-nginx/setup.py index 593e083ea..4a4d57509 100644 --- a/certbot-nginx/setup.py +++ b/certbot-nginx/setup.py @@ -1,7 +1,7 @@ from setuptools import find_packages from setuptools import setup -version = '1.30.0' +version = '1.31.0.dev0' install_requires = [ # We specify the minimum acme and certbot version as the current plugin diff --git a/certbot/certbot/__init__.py b/certbot/certbot/__init__.py index e557e206e..27b94a930 100644 --- a/certbot/certbot/__init__.py +++ b/certbot/certbot/__init__.py @@ -1,3 +1,3 @@ """Certbot client.""" # version number like 1.2.3a0, must have at least 2 parts, like 1.2 -__version__ = '1.30.0' +__version__ = '1.31.0.dev0'