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 88aeab60e..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: @@ -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 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) 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/AUTHORS.md b/AUTHORS.md index 95e63459b..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) @@ -215,6 +216,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/acme/acme/challenges.py b/acme/acme/challenges.py index 97e3bed88..b6290f8e7 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -410,7 +410,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/client.py b/acme/acme/client.py index 105e9298f..a7471a4ec 100644 --- a/acme/acme/client.py +++ b/acme/acme/client.py @@ -15,13 +15,20 @@ from typing import Set from typing import Text from typing import Tuple from typing import Union +import warnings import josepy as jose 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 @@ -482,7 +489,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, @@ -500,6 +508,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/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/setup.py b/acme/setup.py index f385bcb92..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.dev0' +version = '1.31.0.dev0' install_requires = [ 'cryptography>=2.5.0', diff --git a/acme/tests/challenges_test.py b/acme/tests/challenges_test.py index f9e886f64..9c68d1668 100644 --- a/acme/tests/challenges_test.py +++ b/acme/tests/challenges_test.py @@ -325,12 +325,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/acme/tests/client_test.py b/acme/tests/client_test.py index 1b00e0b90..c3209685c 100644 --- a/acme/tests/client_test.py +++ b/acme/tests/client_test.py @@ -15,6 +15,7 @@ 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 import messages_test import test_util @@ -410,7 +411,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') @@ -638,7 +638,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) @@ -800,15 +799,16 @@ class ClientNetworkSourceAddressBindingTest(unittest.TestCase): self.source_address = "8.8.8.8" 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) 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 b53798f00..68e5c9a7f 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 diff --git a/acme/tests/messages_test.py b/acme/tests/messages_test.py index cce4e409f..cbff65771 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 diff --git a/certbot-apache/setup.py b/certbot-apache/setup.py index 98beb4eaa..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.dev0' +version = '1.31.0.dev0' install_requires = [ # We specify the minimum acme and certbot version as the current plugin 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-compatibility-test/setup.py b/certbot-compatibility-test/setup.py index b34333f6d..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.dev0' +version = '1.31.0.dev0' install_requires = [ 'certbot', diff --git a/certbot-dns-cloudflare/setup.py b/certbot-dns-cloudflare/setup.py index 150b9f51e..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.dev0' +version = '1.31.0.dev0' install_requires = [ 'cloudflare>=1.5.1', diff --git a/certbot-dns-digitalocean/setup.py b/certbot-dns-digitalocean/setup.py index 1ab16b33f..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.dev0' +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 eb93976d2..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.dev0' +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 dac8dbb28..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.dev0' +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 f5331d023..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.dev0' +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 bde460bdc..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.dev0' +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 4b9f1e53d..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.dev0' +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 5728fc5d7..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.dev0' +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 b84ab62bc..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.dev0' +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 443e2cb25..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.dev0' +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 207d14182..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.dev0' +version = '1.31.0.dev0' install_requires = [ 'dnspython>=1.15.0', 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-dns-route53/setup.py b/certbot-dns-route53/setup.py index d09e7e6e2..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.dev0' +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 60472b280..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.dev0' +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 40809653e..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.dev0' +version = '1.31.0.dev0' install_requires = [ # We specify the minimum acme and certbot version as the current plugin diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index 18b37f396..8c5f65e50 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.31.0 - master ### Added @@ -18,6 +18,35 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). More details about these changes can be found on our GitHub repo. +## 1.30.0 - 2022-09-07 + +### Added + +* + +### Changed + +* `acme.client.ClientBase`, `acme.messages.Authorization.resolved_combinations`, + `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 + 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 + +* + +More details about these changes can be found on our GitHub repo. + ## 1.29.0 - 2022-07-05 ### Added diff --git a/certbot/certbot/__init__.py b/certbot/certbot/__init__.py index 7a59f02f6..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.dev0' +__version__ = '1.31.0.dev0' 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/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] 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/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 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/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 diff --git a/certbot/docs/using.rst b/certbot/docs/using.rst index c43a006fd..0e0da3d5c 100644 --- a/certbot/docs/using.rst +++ b/certbot/docs/using.rst @@ -315,6 +315,8 @@ 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 +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 @@ -335,6 +337,8 @@ 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 +.. _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 @@ -557,6 +561,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``. \ 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 diff --git a/pytest.ini b/pytest.ini index 4489792b9..42853f26b 100644 --- a/pytest.ini +++ b/pytest.ini @@ -13,19 +13,12 @@ # The current warnings being ignored are: # 1) The warning raised when importing certbot.tests.util and the external mock # library is installed. -# 2) The deprecation warning raised when importing deprecated attributes from -# the certbot.display.util module. -# 3) A deprecation warning is raised in dnspython==1.15.0 in the oldest tests for +# 2) A deprecation warning is raised in dnspython==1.15.0 in the oldest tests for # certbot-dns-rfc2136. -# 4) The vendored version of six in botocore causes ImportWarnings in Python -# 3.10+. See https://github.com/boto/botocore/issues/2548. -# 5) 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. +# 3) botocore is currently using deprecated urllib3 functionality. See +# https://github.com/boto/botocore/issues/2744. filterwarnings = error ignore:The external mock module:PendingDeprecationWarning - 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 diff --git a/tools/oldest_constraints.txt b/tools/oldest_constraints.txt index 9853143fe..bbbbc579a 100644 --- a/tools/oldest_constraints.txt +++ b/tools/oldest_constraints.txt @@ -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 diff --git a/tools/pinning/current/pyproject.toml b/tools/pinning/current/pyproject.toml index e8358a926..eb42ecd34 100644 --- a/tools/pinning/current/pyproject.toml +++ b/tools/pinning/current/pyproject.toml @@ -61,18 +61,27 @@ 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 # 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 74b899958..b6aed9dc0 100644 --- a/tools/pinning/oldest/pyproject.toml +++ b/tools/pinning/oldest/pyproject.toml @@ -98,11 +98,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 71ce482b6..e25e7f565 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -7,186 +7,186 @@ # 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 +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.8.1; python_version >= "3.7" and python_version < "3.8"