diff --git a/.azure-pipelines/templates/jobs/extended-tests-jobs.yml b/.azure-pipelines/templates/jobs/extended-tests-jobs.yml index 31325ae6c..c5a1fb628 100644 --- a/.azure-pipelines/templates/jobs/extended-tests-jobs.yml +++ b/.azure-pipelines/templates/jobs/extended-tests-jobs.yml @@ -8,12 +8,6 @@ jobs: - group: certbot-common strategy: matrix: - linux-py36: - PYTHON_VERSION: 3.6 - TOXENV: py36 - linux-py37: - PYTHON_VERSION: 3.7 - TOXENV: py37 linux-py38: PYTHON_VERSION: 3.8 TOXENV: py38 @@ -27,17 +21,13 @@ jobs: linux-external-mock: TOXENV: external-mock linux-boulder-v2-integration-certbot-oldest: - PYTHON_VERSION: 3.6 + PYTHON_VERSION: 3.7 TOXENV: integration-certbot-oldest ACME_SERVER: boulder-v2 linux-boulder-v2-integration-nginx-oldest: - PYTHON_VERSION: 3.6 + PYTHON_VERSION: 3.7 TOXENV: integration-nginx-oldest ACME_SERVER: boulder-v2 - linux-boulder-v2-py36-integration: - PYTHON_VERSION: 3.6 - TOXENV: integration - ACME_SERVER: boulder-v2 linux-boulder-v2-py37-integration: PYTHON_VERSION: 3.7 TOXENV: integration diff --git a/.azure-pipelines/templates/jobs/packaging-jobs.yml b/.azure-pipelines/templates/jobs/packaging-jobs.yml index cfd817c8b..8090647a7 100644 --- a/.azure-pipelines/templates/jobs/packaging-jobs.yml +++ b/.azure-pipelines/templates/jobs/packaging-jobs.yml @@ -55,12 +55,12 @@ jobs: displayName: Run integration tests for Docker images - job: installer_build pool: - vmImage: vs2017-win2016 + vmImage: windows-2019 steps: - task: UsePythonVersion@0 inputs: versionSpec: 3.9 - architecture: x86 + architecture: x64 addToPath: true - script: | python -m venv venv @@ -87,17 +87,9 @@ jobs: matrix: win2019: imageName: windows-2019 - win2016: - imageName: vs2017-win2016 pool: vmImage: $(imageName) steps: - - powershell: | - if ($PSVersionTable.PSVersion.Major -ne 5) { - throw "Powershell version is not 5.x" - } - condition: eq(variables['imageName'], 'vs2017-win2016') - displayName: Check Powershell 5.x is used in vs2017-win2016 - task: UsePythonVersion@0 inputs: versionSpec: 3.9 @@ -115,11 +107,11 @@ jobs: PIP_NO_BUILD_ISOLATION: no displayName: Prepare Certbot-CI - script: | - set PATH=%ProgramFiles(x86)%\Certbot\bin;%PATH% - venv\Scripts\python -m pytest certbot-ci\windows_installer_integration_tests --allow-persistent-changes --installer-path $(Build.SourcesDirectory)\bin\certbot-beta-installer-win32.exe + set PATH=%ProgramFiles%\Certbot\bin;%PATH% + venv\Scripts\python -m pytest certbot-ci\windows_installer_integration_tests --allow-persistent-changes --installer-path $(Build.SourcesDirectory)\bin\certbot-beta-installer-win_amd64.exe displayName: Run windows installer integration tests - script: | - set PATH=%ProgramFiles(x86)%\Certbot\bin;%PATH% + set PATH=%ProgramFiles%\Certbot\bin;%PATH% venv\Scripts\python -m pytest certbot-ci\certbot_integration_tests\certbot_tests -n 4 displayName: Run certbot integration tests - job: snaps_build diff --git a/.azure-pipelines/templates/jobs/standard-tests-jobs.yml b/.azure-pipelines/templates/jobs/standard-tests-jobs.yml index 18416fcbb..4deaf4f2b 100644 --- a/.azure-pipelines/templates/jobs/standard-tests-jobs.yml +++ b/.azure-pipelines/templates/jobs/standard-tests-jobs.yml @@ -4,38 +4,38 @@ jobs: PYTHON_VERSION: 3.10 strategy: matrix: - macos-py36-cover: + macos-py37-cover: IMAGE_NAME: macOS-10.15 - PYTHON_VERSION: 3.6 - TOXENV: py36-cover + PYTHON_VERSION: 3.7 + TOXENV: py37-cover macos-py310-cover: IMAGE_NAME: macOS-10.15 PYTHON_VERSION: 3.10 TOXENV: py310-cover - windows-py36: - IMAGE_NAME: vs2017-win2016 - PYTHON_VERSION: 3.6 - TOXENV: py36-win + windows-py37: + IMAGE_NAME: windows-2019 + PYTHON_VERSION: 3.7 + TOXENV: py37-win windows-py39-cover: - IMAGE_NAME: vs2017-win2016 + IMAGE_NAME: windows-2019 PYTHON_VERSION: 3.9 TOXENV: py39-cover-win windows-integration-certbot: - IMAGE_NAME: vs2017-win2016 + IMAGE_NAME: windows-2019 PYTHON_VERSION: 3.9 TOXENV: integration-certbot linux-oldest-tests-1: IMAGE_NAME: ubuntu-18.04 - PYTHON_VERSION: 3.6 + PYTHON_VERSION: 3.7 TOXENV: '{acme,apache,apache-v2,certbot}-oldest' linux-oldest-tests-2: IMAGE_NAME: ubuntu-18.04 - PYTHON_VERSION: 3.6 + PYTHON_VERSION: 3.7 TOXENV: '{dns,nginx}-oldest' - linux-py36: + linux-py37: IMAGE_NAME: ubuntu-18.04 - PYTHON_VERSION: 3.6 - TOXENV: py36 + PYTHON_VERSION: 3.7 + TOXENV: py37 linux-py310-cover: IMAGE_NAME: ubuntu-18.04 PYTHON_VERSION: 3.10 @@ -58,11 +58,9 @@ jobs: TOXENV: apache_compat apacheconftest: IMAGE_NAME: ubuntu-18.04 - PYTHON_VERSION: 3.6 TOXENV: apacheconftest-with-pebble nginxroundtrip: IMAGE_NAME: ubuntu-18.04 - PYTHON_VERSION: 3.6 TOXENV: nginxroundtrip pool: vmImage: $(IMAGE_NAME) diff --git a/.azure-pipelines/templates/stages/changelog-stage.yml b/.azure-pipelines/templates/stages/changelog-stage.yml index 7d089f8d4..524904f17 100644 --- a/.azure-pipelines/templates/stages/changelog-stage.yml +++ b/.azure-pipelines/templates/stages/changelog-stage.yml @@ -3,7 +3,7 @@ stages: jobs: - job: prepare pool: - vmImage: vs2017-win2016 + vmImage: windows-2019 steps: # If we change the output filename from `release_notes.md`, it should also be changed in tools/create_github_release.py - bash: | diff --git a/acme/acme/__init__.py b/acme/acme/__init__.py index b4cbf5e45..8b6ce88c0 100644 --- a/acme/acme/__init__.py +++ b/acme/acme/__init__.py @@ -6,7 +6,6 @@ This module is an implementation of the `ACME protocol`_. """ import sys -import warnings # This code exists to keep backwards compatibility with people using acme.jose # before it became the standalone josepy package. @@ -20,11 +19,3 @@ for mod in list(sys.modules): # preserved (acme.jose.* is josepy.*) if mod == 'josepy' or mod.startswith('josepy.'): sys.modules['acme.' + mod.replace('josepy', 'jose', 1)] = sys.modules[mod] - - -if sys.version_info[:2] == (3, 6): - warnings.warn( - "Python 3.6 support will be dropped in the next release of " - "acme. Please upgrade your Python version.", - PendingDeprecationWarning, - ) # pragma: no cover diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index ce0cf2ed4..9000b370a 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -279,7 +279,7 @@ class DNS01(KeyAuthorizationChallenge): :rtype: str """ - return "{0}.{1}".format(self.LABEL, name) + return f"{self.LABEL}.{name}" @ChallengeResponse.register diff --git a/acme/acme/client.py b/acme/acme/client.py index aacbbc263..2e86ce549 100644 --- a/acme/acme/client.py +++ b/acme/acme/client.py @@ -1142,8 +1142,7 @@ class ClientNetwork: 'response', response_ct) if content_type == cls.JSON_CONTENT_TYPE and jobj is None: - raise errors.ClientError( - 'Unexpected response Content-Type: {0}'.format(response_ct)) + raise errors.ClientError(f'Unexpected response Content-Type: {response_ct}') return response @@ -1196,7 +1195,7 @@ class ClientNetwork: if m is None: raise # pragma: no cover host, path, _err_no, err_msg = m.groups() - raise ValueError("Requesting {0}{1}:{2}".format(host, path, err_msg)) + raise ValueError(f"Requesting {host}{path}:{err_msg}") # If the Content-Type is DER or an Accept header was sent in the # request, the response may not be UTF-8 encoded. In this case, we diff --git a/acme/acme/messages.py b/acme/acme/messages.py index c9704d537..299da68d7 100644 --- a/acme/acme/messages.py +++ b/acme/acme/messages.py @@ -157,12 +157,11 @@ class _Constant(jose.JSONDeSerializable, Hashable): @classmethod def from_json(cls, jobj: str) -> '_Constant': if jobj not in cls.POSSIBLE_NAMES: # pylint: disable=unsupported-membership-test - raise jose.DeserializationError( - '{0} not recognized'.format(cls.__name__)) + raise jose.DeserializationError(f'{cls.__name__} not recognized') return cls.POSSIBLE_NAMES[jobj] def __repr__(self) -> str: - return '{0}({1})'.format(self.__class__.__name__, self.name) + return f'{self.__class__.__name__}({self.name})' def __eq__(self, other: Any) -> bool: return isinstance(other, type(self)) and other.name == self.name diff --git a/acme/acme/mixins.py b/acme/acme/mixins.py index 38551d550..e6e678d60 100644 --- a/acme/acme/mixins.py +++ b/acme/acme/mixins.py @@ -65,4 +65,4 @@ def _safe_jobj_compliance(instance: Any, jobj_method: str, jobj.pop(uncompliant_field, None) return jobj - raise AttributeError('Method {0}() is not implemented.'.format(jobj_method)) # pragma: no cover + raise AttributeError(f'Method {jobj_method}() is not implemented.') # pragma: no cover diff --git a/acme/docs/jws-help.txt b/acme/docs/jws-help.txt index bfd16dff4..34cf5ce23 100644 --- a/acme/docs/jws-help.txt +++ b/acme/docs/jws-help.txt @@ -3,6 +3,6 @@ usage: jws [-h] [--compact] {sign,verify} ... positional arguments: {sign,verify} -options: +optional arguments: -h, --help show this help message and exit --compact diff --git a/acme/setup.py b/acme/setup.py index 60d806b09..e5c50d50a 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -3,17 +3,17 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.24.0.dev0' +version = '1.26.0.dev0' install_requires = [ 'cryptography>=2.5.0', - 'josepy>=1.10.0', + 'josepy>=1.13.0', 'PyOpenSSL>=17.3.0', 'pyrfc3339', - 'pytz', - 'requests>=2.14.2', + 'pytz>=2019.3', + 'requests>=2.20.0', 'requests-toolbelt>=0.3.0', - 'setuptools>=39.0.1', + 'setuptools>=41.6.0', ] docs_extras = [ @@ -35,14 +35,13 @@ setup( author="Certbot Project", author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: Apache Software License', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/certbot-apache/setup.py b/certbot-apache/setup.py index b681e8f14..d2b7d8ec2 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.24.0.dev0' +version = '1.26.0.dev0' install_requires = [ # We specify the minimum acme and certbot version as the current plugin @@ -10,7 +10,7 @@ install_requires = [ f'acme>={version}', f'certbot>={version}', 'python-augeas', - 'setuptools>=39.0.1', + 'setuptools>=41.6.0', ] dev_extras = [ @@ -25,7 +25,7 @@ setup( author="Certbot Project", author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Plugins', @@ -34,7 +34,6 @@ setup( 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/certbot-ci/certbot_integration_tests/certbot_tests/assertions.py b/certbot-ci/certbot_integration_tests/certbot_tests/assertions.py index 92ce8fac8..272084217 100644 --- a/certbot-ci/certbot_integration_tests/certbot_tests/assertions.py +++ b/certbot-ci/certbot_integration_tests/certbot_tests/assertions.py @@ -1,6 +1,7 @@ """This module contains advanced assertions for the certbot integration tests.""" import io import os +from typing import Optional from typing import Type from cryptography.hazmat.backends import default_backend @@ -62,14 +63,26 @@ def assert_hook_execution(probe_path: str, probe_content: str) -> None: assert probe_content in lines +def assert_saved_lineage_option(config_dir: str, lineage: str, + option: str, value: Optional[str] = None) -> None: + """ + Assert that the option of a lineage has been saved. + :param str config_dir: location of the certbot configuration + :param str lineage: lineage domain name + :param str option: the option key + :param value: if desired, the expected option value + """ + with open(os.path.join(config_dir, 'renewal', '{0}.conf'.format(lineage))) as file_h: + assert f"{option} = {value if value else ''}" in file_h.read() + + def assert_saved_renew_hook(config_dir: str, lineage: str) -> None: """ Assert that the renew hook configuration of a lineage has been saved. :param str config_dir: location of the certbot configuration :param str lineage: lineage domain name """ - with open(os.path.join(config_dir, 'renewal', '{0}.conf'.format(lineage))) as file_h: - assert 'renew_hook' in file_h.read() + assert_saved_lineage_option(config_dir, lineage, 'renew_hook') def assert_cert_count_for_lineage(config_dir: str, lineage: str, count: int) -> None: diff --git a/certbot-ci/certbot_integration_tests/certbot_tests/context.py b/certbot-ci/certbot_integration_tests/certbot_tests/context.py index fdef82252..0dc732880 100644 --- a/certbot-ci/certbot_integration_tests/certbot_tests/context.py +++ b/certbot-ci/certbot_integration_tests/certbot_tests/context.py @@ -29,8 +29,8 @@ class IntegrationTestsContext: self.http_01_port = acme_xdist['http_port'][self.worker_id] self.other_port = acme_xdist['other_port'][self.worker_id] # Challtestsrv REST API, that exposes entrypoints to register new DNS entries, - # is listening on challtestsrv_port. - self.challtestsrv_port = acme_xdist['challtestsrv_port'] + # is listening on challtestsrv_url. + self.challtestsrv_url = acme_xdist['challtestsrv_url'] self.workspace = tempfile.mkdtemp() self.config_dir = os.path.join(self.workspace, 'conf') @@ -44,17 +44,17 @@ class IntegrationTestsContext: "assert not os.environ.get('CERTBOT_DOMAIN').startswith('fail'); " "data = {{'host':'_acme-challenge.{{0}}.'.format(os.environ.get('CERTBOT_DOMAIN'))," "'value':os.environ.get('CERTBOT_VALIDATION')}}; " - "request = requests.post('http://localhost:{1}/set-txt', data=json.dumps(data)); " + "request = requests.post('{1}/set-txt', data=json.dumps(data)); " "request.raise_for_status(); " '"' - ).format(sys.executable, self.challtestsrv_port) + ).format(sys.executable, self.challtestsrv_url) self.manual_dns_cleanup_hook = ( '{0} -c "import os; import requests; import json; ' "data = {{'host':'_acme-challenge.{{0}}.'.format(os.environ.get('CERTBOT_DOMAIN'))}}; " - "request = requests.post('http://localhost:{1}/clear-txt', data=json.dumps(data)); " + "request = requests.post('{1}/clear-txt', data=json.dumps(data)); " "request.raise_for_status(); " '"' - ).format(sys.executable, self.challtestsrv_port) + ).format(sys.executable, self.challtestsrv_url) def cleanup(self) -> None: """Cleanup the integration test context.""" diff --git a/certbot-ci/certbot_integration_tests/certbot_tests/test_main.py b/certbot-ci/certbot_integration_tests/certbot_tests/test_main.py index 146ba58bb..4a3395217 100644 --- a/certbot-ci/certbot_integration_tests/certbot_tests/test_main.py +++ b/certbot-ci/certbot_integration_tests/certbot_tests/test_main.py @@ -25,6 +25,7 @@ from certbot_integration_tests.certbot_tests.assertions import assert_equals_gro from certbot_integration_tests.certbot_tests.assertions import assert_equals_world_read_permissions from certbot_integration_tests.certbot_tests.assertions import assert_hook_execution from certbot_integration_tests.certbot_tests.assertions import assert_rsa_key +from certbot_integration_tests.certbot_tests.assertions import assert_saved_lineage_option from certbot_integration_tests.certbot_tests.assertions import assert_saved_renew_hook from certbot_integration_tests.certbot_tests.assertions import assert_world_no_permissions from certbot_integration_tests.certbot_tests.assertions import assert_world_read_permissions @@ -102,6 +103,7 @@ def test_http_01(context: IntegrationTestsContext) -> None: assert_hook_execution(context.hook_probe, 'deploy') assert_saved_renew_hook(context.config_dir, certname) + assert_saved_lineage_option(context.config_dir, certname, 'key_type', 'rsa') def test_manual_http_auth(context: IntegrationTestsContext) -> None: @@ -540,35 +542,47 @@ def test_renew_with_ec_keys(context: IntegrationTestsContext) -> None: '--key-type', 'ecdsa', '--elliptic-curve', 'secp256r1', '--force-renewal', '-d', certname, ]) - key1 = join(context.config_dir, "archive", certname, 'privkey1.pem') assert 200 < os.stat(key1).st_size < 250 # ec keys of 256 bits are ~225 bytes assert_elliptic_key(key1, SECP256R1) assert_cert_count_for_lineage(context.config_dir, certname, 1) + assert_saved_lineage_option(context.config_dir, certname, 'key_type', 'ecdsa') context.certbot(['renew', '--elliptic-curve', 'secp384r1']) - assert_cert_count_for_lineage(context.config_dir, certname, 2) key2 = join(context.config_dir, 'archive', certname, 'privkey2.pem') - assert_elliptic_key(key2, SECP384R1) assert 280 < os.stat(key2).st_size < 320 # ec keys of 384 bits are ~310 bytes + assert_elliptic_key(key2, SECP384R1) - # We expect here that the command will fail because without --key-type specified, - # Certbot must error out to prevent changing an existing certificate key type, - # without explicit user consent (by specifying both --cert-name and --key-type). - with pytest.raises(subprocess.CalledProcessError): - context.certbot([ - 'certonly', - '--force-renewal', - '-d', certname - ]) + # When running non-interactively, if --key-type is unspecified but the default value differs + # to the lineage key type, Certbot should keep the lineage key type. The curve will still + # change to the default value, in order to stay consistent with the behavior of certonly. + context.certbot(['certonly', '--force-renewal', '-d', certname]) + assert_cert_count_for_lineage(context.config_dir, certname, 3) + key3 = join(context.config_dir, 'archive', certname, 'privkey3.pem') + assert 200 < os.stat(key3).st_size < 250 # ec keys of 256 bits are ~225 bytes + assert_elliptic_key(key3, SECP256R1) + + # When running non-interactively, specifying a different --key-type requires user confirmation + # with both --key-type and --cert-name. + with pytest.raises(subprocess.CalledProcessError) as error: + context.certbot(['certonly', '--force-renewal', '-d', certname, + '--key-type', 'rsa']) + assert 'Please provide both --cert-name and --key-type' in error.value.stderr + + context.certbot(['certonly', '--force-renewal', '-d', certname, + '--key-type', 'rsa', '--cert-name', certname]) + assert_cert_count_for_lineage(context.config_dir, certname, 4) + key4 = join(context.config_dir, 'archive', certname, 'privkey4.pem') + assert_rsa_key(key4) # We expect that the previous behavior of requiring both --cert-name and # --key-type to be set to not apply to the renew subcommand. - context.certbot(['renew', '--force-renewal', '--key-type', 'rsa']) - assert_cert_count_for_lineage(context.config_dir, certname, 3) - key3 = join(context.config_dir, 'archive', certname, 'privkey3.pem') - assert_rsa_key(key3) + context.certbot(['renew', '--force-renewal', '--key-type', 'ecdsa']) + assert_cert_count_for_lineage(context.config_dir, certname, 5) + key5 = join(context.config_dir, 'archive', certname, 'privkey5.pem') + assert 200 < os.stat(key5).st_size < 250 # ec keys of 256 bits are ~225 bytes + assert_elliptic_key(key5, SECP256R1) def test_ocsp_must_staple(context: IntegrationTestsContext) -> None: diff --git a/certbot-ci/certbot_integration_tests/utils/acme_server.py b/certbot-ci/certbot_integration_tests/utils/acme_server.py index 00e895656..9e56e3036 100755 --- a/certbot-ci/certbot_integration_tests/utils/acme_server.py +++ b/certbot-ci/certbot_integration_tests/utils/acme_server.py @@ -122,14 +122,16 @@ class ACMEServer: def _construct_acme_xdist(self, acme_server: str, nodes: List[str]) -> None: """Generate and return the acme_xdist dict""" - acme_xdist = {'acme_server': acme_server, 'challtestsrv_port': CHALLTESTSRV_PORT} + acme_xdist: Dict[str, Any] = {'acme_server': acme_server} # Directory and ACME port are set implicitly in the docker-compose.yml # files of Boulder/Pebble. if acme_server == 'pebble': acme_xdist['directory_url'] = PEBBLE_DIRECTORY_URL + acme_xdist['challtestsrv_url'] = PEBBLE_CHALLTESTSRV_URL else: # boulder 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 @@ -182,7 +184,7 @@ class ACMEServer: # Wait for the ACME CA server to be up. print('=> Waiting for pebble instance to respond...') - misc.check_until_timeout(self.acme_xdist['directory_url']) # type: ignore[arg-type] + misc.check_until_timeout(self.acme_xdist['directory_url']) print('=> Finished pebble instance deployment.') @@ -216,12 +218,13 @@ class ACMEServer: # Wait for the ACME CA server to be up. print('=> Waiting for boulder instance to respond...') misc.check_until_timeout( - self.acme_xdist['directory_url'], attempts=300) # type: ignore[arg-type] + self.acme_xdist['directory_url'], attempts=300) if not self._dns_server: # Configure challtestsrv to answer any A record request with ip of the docker host. - response = requests.post('http://localhost:{0}/set-default-ipv4'.format( - CHALLTESTSRV_PORT), json={'ip': '10.77.77.1'} + response = requests.post( + f'{BOULDER_V2_CHALLTESTSRV_URL}/set-default-ipv4', + json={'ip': '10.77.77.1'} ) response.raise_for_status() except BaseException: diff --git a/certbot-ci/certbot_integration_tests/utils/constants.py b/certbot-ci/certbot_integration_tests/utils/constants.py index dd41d670e..a788881ef 100644 --- a/certbot-ci/certbot_integration_tests/utils/constants.py +++ b/certbot-ci/certbot_integration_tests/utils/constants.py @@ -2,8 +2,10 @@ DEFAULT_HTTP_01_PORT = 5002 TLS_ALPN_01_PORT = 5001 CHALLTESTSRV_PORT = 8055 +BOULDER_V2_CHALLTESTSRV_URL = f'http://10.77.77.77:{CHALLTESTSRV_PORT}' BOULDER_V2_DIRECTORY_URL = 'http://localhost:4001/directory' PEBBLE_DIRECTORY_URL = 'https://localhost:14000/dir' PEBBLE_MANAGEMENT_URL = 'https://localhost:15000' +PEBBLE_CHALLTESTSRV_URL = f'http://localhost:{CHALLTESTSRV_PORT}' MOCK_OCSP_SERVER_PORT = 4002 PEBBLE_ALTERNATE_ROOTS = 2 diff --git a/certbot-ci/setup.py b/certbot-ci/setup.py index 769705ad7..4341ef266 100644 --- a/certbot-ci/setup.py +++ b/certbot-ci/setup.py @@ -40,14 +40,13 @@ setup( author="Certbot Project", author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 3 - Alpha', 'Intended Audience :: Developers', 'License :: OSI Approved :: Apache Software License', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/certbot-ci/windows_installer_integration_tests/conftest.py b/certbot-ci/windows_installer_integration_tests/conftest.py index 3332fc923..c0917013d 100644 --- a/certbot-ci/windows_installer_integration_tests/conftest.py +++ b/certbot-ci/windows_installer_integration_tests/conftest.py @@ -20,9 +20,9 @@ def pytest_addoption(parser): """ parser.addoption('--installer-path', default=os.path.join(ROOT_PATH, 'windows-installer', 'build', - 'nsis', 'certbot-beta-installer-win32.exe'), + 'nsis', 'certbot-beta-installer-win_amd64.exe'), help='set the path of the windows installer to use, default to ' - 'CERTBOT_ROOT_PATH\\windows-installer\\build\\nsis\\certbot-beta-installer-win32.exe') # pylint: disable=line-too-long + 'CERTBOT_ROOT_PATH\\windows-installer\\build\\nsis\\certbot-beta-installer-win_amd64.exe') # pylint: disable=line-too-long parser.addoption('--allow-persistent-changes', action='store_true', help='needs to be set, and confirm that the test will make persistent changes on this machine') # pylint: disable=line-too-long diff --git a/certbot-compatibility-test/setup.py b/certbot-compatibility-test/setup.py index d1058486a..bd8d30c10 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.24.0.dev0' +version = '1.26.0.dev0' install_requires = [ 'certbot', @@ -18,14 +18,13 @@ setup( author="Certbot Project", author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 3 - Alpha', 'Intended Audience :: Developers', 'License :: OSI Approved :: Apache Software License', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/certbot-dns-cloudflare/setup.py b/certbot-dns-cloudflare/setup.py index d7383e416..bf3b3a56e 100644 --- a/certbot-dns-cloudflare/setup.py +++ b/certbot-dns-cloudflare/setup.py @@ -4,11 +4,11 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.24.0.dev0' +version = '1.26.0.dev0' install_requires = [ 'cloudflare>=1.5.1', - 'setuptools>=39.0.1', + 'setuptools>=41.6.0', ] if not os.environ.get('SNAP_BUILD'): @@ -38,7 +38,7 @@ setup( author="Certbot Project", author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Plugins', @@ -47,7 +47,6 @@ setup( 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/certbot-dns-cloudxns/setup.py b/certbot-dns-cloudxns/setup.py index 5b6bd3dd5..c9c7df881 100644 --- a/certbot-dns-cloudxns/setup.py +++ b/certbot-dns-cloudxns/setup.py @@ -4,11 +4,11 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.24.0.dev0' +version = '1.26.0.dev0' install_requires = [ 'dns-lexicon>=3.2.1', - 'setuptools>=39.0.1', + 'setuptools>=41.6.0', ] if not os.environ.get('SNAP_BUILD'): @@ -38,7 +38,7 @@ setup( author="Certbot Project", author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Plugins', @@ -47,7 +47,6 @@ setup( 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/certbot-dns-digitalocean/setup.py b/certbot-dns-digitalocean/setup.py index 34c61011a..959c2d80b 100644 --- a/certbot-dns-digitalocean/setup.py +++ b/certbot-dns-digitalocean/setup.py @@ -4,11 +4,11 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.24.0.dev0' +version = '1.26.0.dev0' install_requires = [ 'python-digitalocean>=1.11', # 1.15.0 or newer is recommended for TTL support - 'setuptools>=39.0.1', + 'setuptools>=41.6.0', ] if not os.environ.get('SNAP_BUILD'): @@ -38,7 +38,7 @@ setup( author="Certbot Project", author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Plugins', @@ -47,7 +47,6 @@ setup( 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/certbot-dns-dnsimple/setup.py b/certbot-dns-dnsimple/setup.py index 69b992ba7..88b89a81d 100644 --- a/certbot-dns-dnsimple/setup.py +++ b/certbot-dns-dnsimple/setup.py @@ -4,13 +4,13 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.24.0.dev0' +version = '1.26.0.dev0' install_requires = [ # This version of lexicon is required to address the problem described in # https://github.com/AnalogJ/lexicon/issues/387. 'dns-lexicon>=3.2.1', - 'setuptools>=39.0.1', + 'setuptools>=41.6.0', ] if not os.environ.get('SNAP_BUILD'): @@ -40,7 +40,7 @@ setup( author="Certbot Project", author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Plugins', @@ -49,7 +49,6 @@ setup( 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/certbot-dns-dnsmadeeasy/setup.py b/certbot-dns-dnsmadeeasy/setup.py index 3fb57048d..f6ce96357 100644 --- a/certbot-dns-dnsmadeeasy/setup.py +++ b/certbot-dns-dnsmadeeasy/setup.py @@ -4,11 +4,11 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.24.0.dev0' +version = '1.26.0.dev0' install_requires = [ 'dns-lexicon>=3.2.1', - 'setuptools>=39.0.1', + 'setuptools>=41.6.0', ] if not os.environ.get('SNAP_BUILD'): @@ -38,7 +38,7 @@ setup( author="Certbot Project", author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Plugins', @@ -47,7 +47,6 @@ setup( 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/certbot-dns-gehirn/setup.py b/certbot-dns-gehirn/setup.py index f92f3e24b..fabe50165 100644 --- a/certbot-dns-gehirn/setup.py +++ b/certbot-dns-gehirn/setup.py @@ -4,11 +4,11 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.24.0.dev0' +version = '1.26.0.dev0' install_requires = [ 'dns-lexicon>=3.2.1', - 'setuptools>=39.0.1', + 'setuptools>=41.6.0', ] if not os.environ.get('SNAP_BUILD'): @@ -38,7 +38,7 @@ setup( author="Certbot Project", author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Plugins', @@ -47,7 +47,6 @@ setup( 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/certbot-dns-google/setup.py b/certbot-dns-google/setup.py index 5a8834ff6..f758e5801 100644 --- a/certbot-dns-google/setup.py +++ b/certbot-dns-google/setup.py @@ -4,12 +4,12 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.24.0.dev0' +version = '1.26.0.dev0' install_requires = [ 'google-api-python-client>=1.5.5', 'oauth2client>=4.0', - 'setuptools>=39.0.1', + 'setuptools>=41.6.0', # already a dependency of google-api-python-client, but added for consistency 'httplib2' ] @@ -41,7 +41,7 @@ setup( author="Certbot Project", author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Plugins', @@ -50,7 +50,6 @@ setup( 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/certbot-dns-linode/setup.py b/certbot-dns-linode/setup.py index f1e56a557..b2e584623 100644 --- a/certbot-dns-linode/setup.py +++ b/certbot-dns-linode/setup.py @@ -4,11 +4,11 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.24.0.dev0' +version = '1.26.0.dev0' install_requires = [ 'dns-lexicon>=3.2.1', - 'setuptools>=39.0.1', + 'setuptools>=41.6.0', ] if not os.environ.get('SNAP_BUILD'): @@ -38,7 +38,7 @@ setup( author="Certbot Project", author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Plugins', @@ -47,7 +47,6 @@ setup( 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/certbot-dns-luadns/setup.py b/certbot-dns-luadns/setup.py index 569ccc844..b408bb6fd 100644 --- a/certbot-dns-luadns/setup.py +++ b/certbot-dns-luadns/setup.py @@ -4,11 +4,11 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.24.0.dev0' +version = '1.26.0.dev0' install_requires = [ 'dns-lexicon>=3.2.1', - 'setuptools>=39.0.1', + 'setuptools>=41.6.0', ] if not os.environ.get('SNAP_BUILD'): @@ -38,7 +38,7 @@ setup( author="Certbot Project", author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Plugins', @@ -47,7 +47,6 @@ setup( 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/certbot-dns-nsone/setup.py b/certbot-dns-nsone/setup.py index 4c89cece7..0801be578 100644 --- a/certbot-dns-nsone/setup.py +++ b/certbot-dns-nsone/setup.py @@ -4,11 +4,11 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.24.0.dev0' +version = '1.26.0.dev0' install_requires = [ 'dns-lexicon>=3.2.1', - 'setuptools>=39.0.1', + 'setuptools>=41.6.0', ] if not os.environ.get('SNAP_BUILD'): @@ -38,7 +38,7 @@ setup( author="Certbot Project", author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Plugins', @@ -47,7 +47,6 @@ setup( 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/certbot-dns-ovh/setup.py b/certbot-dns-ovh/setup.py index 455cea9a4..f247cc653 100644 --- a/certbot-dns-ovh/setup.py +++ b/certbot-dns-ovh/setup.py @@ -4,11 +4,11 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.24.0.dev0' +version = '1.26.0.dev0' install_requires = [ 'dns-lexicon>=3.2.1', - 'setuptools>=39.0.1', + 'setuptools>=41.6.0', ] if not os.environ.get('SNAP_BUILD'): @@ -38,7 +38,7 @@ setup( author="Certbot Project", author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Plugins', @@ -47,7 +47,6 @@ setup( 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/certbot-dns-rfc2136/setup.py b/certbot-dns-rfc2136/setup.py index a5a01f518..8cd955a6b 100644 --- a/certbot-dns-rfc2136/setup.py +++ b/certbot-dns-rfc2136/setup.py @@ -4,11 +4,11 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.24.0.dev0' +version = '1.26.0.dev0' install_requires = [ 'dnspython>=1.15.0', - 'setuptools>=39.0.1', + 'setuptools>=41.6.0', ] if not os.environ.get('SNAP_BUILD'): @@ -38,7 +38,7 @@ setup( author="Certbot Project", author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Plugins', @@ -47,7 +47,6 @@ setup( 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/certbot-dns-route53/setup.py b/certbot-dns-route53/setup.py index c225a737b..d08ac2bca 100644 --- a/certbot-dns-route53/setup.py +++ b/certbot-dns-route53/setup.py @@ -4,11 +4,11 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.24.0.dev0' +version = '1.26.0.dev0' install_requires = [ - 'boto3', - 'setuptools>=39.0.1', + 'boto3>=1.15.15', + 'setuptools>=41.6.0', ] if not os.environ.get('SNAP_BUILD'): @@ -38,7 +38,7 @@ setup( author="Certbot Project", author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Plugins', @@ -47,7 +47,6 @@ setup( 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/certbot-dns-sakuracloud/setup.py b/certbot-dns-sakuracloud/setup.py index 8a316aeb3..84f4a763e 100644 --- a/certbot-dns-sakuracloud/setup.py +++ b/certbot-dns-sakuracloud/setup.py @@ -4,11 +4,11 @@ import sys from setuptools import find_packages from setuptools import setup -version = '1.24.0.dev0' +version = '1.26.0.dev0' install_requires = [ 'dns-lexicon>=3.2.1', - 'setuptools>=39.0.1', + 'setuptools>=41.6.0', ] if not os.environ.get('SNAP_BUILD'): @@ -38,7 +38,7 @@ setup( author="Certbot Project", author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Plugins', @@ -47,7 +47,6 @@ setup( 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/certbot-nginx/certbot_nginx/_internal/nginxparser.py b/certbot-nginx/certbot_nginx/_internal/nginxparser.py index 0fdc71dfa..874a544f7 100644 --- a/certbot-nginx/certbot_nginx/_internal/nginxparser.py +++ b/certbot-nginx/certbot_nginx/_internal/nginxparser.py @@ -28,7 +28,7 @@ from pyparsing import White from pyparsing import ZeroOrMore if TYPE_CHECKING: - from typing_extensions import SupportsIndex # typing.SupportsIndex not supported on Python 3.6 + from typing_extensions import SupportsIndex # typing.SupportsIndex not supported on Python 3.7 logger = logging.getLogger(__name__) diff --git a/certbot-nginx/setup.py b/certbot-nginx/setup.py index 77428ba03..94c84513f 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.24.0.dev0' +version = '1.26.0.dev0' install_requires = [ # We specify the minimum acme and certbot version as the current plugin @@ -10,8 +10,8 @@ install_requires = [ f'acme>={version}', f'certbot>={version}', 'PyOpenSSL>=17.3.0', - 'pyparsing>=2.2.0', - 'setuptools>=39.0.1', + 'pyparsing>=2.2.1', + 'setuptools>=41.6.0', ] setup( @@ -22,7 +22,7 @@ setup( author="Certbot Project", author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Plugins', @@ -31,7 +31,6 @@ setup( 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index 9794e8426..32d575a6b 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -2,7 +2,7 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). -## 1.24.0 - master +## 1.26.0 - master ### Added @@ -14,6 +14,55 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). ### Fixed +* + +More details about these changes can be found on our GitHub repo. + +## 1.25.0 - 2022-03-16 + +### Added + +* + +### Changed + +* Dropped 32 bit support for the Windows beta installer +* Windows beta installer is now distributed as "certbot-beta-installer-win_amd64.exe". + Users of the Windows beta should uninstall the old version before running this. +* Added a check whether OCSP stapling is supported by the installer when requesting a + certificate with the `run` subcommand in combination with the `--must-staple` option. + If the installer does not support OCSP and the `--must-staple` option is used, Certbot + will raise an error and quit. +* Certbot and its acme module now depend on josepy>=1.13.0 due to better type annotation + support. + +### Fixed + +* Updated dependencies to use new version of cryptography that uses OpenSSL 1.1.1n, in + response to https://www.openssl.org/news/secadv/20220315.txt. + +More details about these changes can be found on our GitHub repo. + +## 1.24.0 - 2022-03-01 + +### Added + +* When the `--debug-challenges` option is used in combination with `-v`, Certbot + now displays the challenge URLs (for `http-01` challenges) or FQDNs (for + `dns-01` challenges) and their expected return values. +* + +### Changed + +* Support for Python 3.6 was removed. +* All Certbot components now require setuptools>=41.6.0. +* The acme library now requires requests>=2.20.0. +* Certbot and its acme library now require pytz>=2019.3. +* certbot-nginx now requires pyparsing>=2.2.1. +* certbot-dns-route53 now requires boto3>=1.15.15. + +### Fixed + * Nginx plugin now checks included files for the singleton server_names_hash_bucket_size directive. * diff --git a/certbot/README.rst b/certbot/README.rst index 40f6a52ec..1a6e8ff7b 100644 --- a/certbot/README.rst +++ b/certbot/README.rst @@ -10,7 +10,7 @@ Certbot is meant to be run directly on your web server, not on your personal com Certbot is a fully-featured, extensible client for the Let's Encrypt CA (or any other CA that speaks the `ACME -`_ +`_ protocol) that can automate the tasks of obtaining certificates and configuring webservers to use them. This client runs on Unix-based operating systems. diff --git a/certbot/certbot/__init__.py b/certbot/certbot/__init__.py index b40280fab..11f586629 100644 --- a/certbot/certbot/__init__.py +++ b/certbot/certbot/__init__.py @@ -1,13 +1,3 @@ """Certbot client.""" # version number like 1.2.3a0, must have at least 2 parts, like 1.2 -import sys -import warnings - -__version__ = '1.24.0.dev0' - -if sys.version_info[:2] == (3, 6): - warnings.warn( - "Python 3.6 support will be dropped in the next release of " - "certbot. Please upgrade your Python version.", - PendingDeprecationWarning, - ) # pragma: no cover +__version__ = '1.26.0.dev0' diff --git a/certbot/certbot/_internal/account.py b/certbot/certbot/_internal/account.py index 8c45efe21..d8f002948 100644 --- a/certbot/certbot/_internal/account.py +++ b/certbot/certbot/_internal/account.py @@ -226,20 +226,15 @@ class AccountFileStorage(interfaces.AccountStorage): else: self._symlink_to_accounts_dir(prev_server_path, server_path) return prev_loaded_account - raise errors.AccountNotFound( - "Account at %s does not exist" % account_dir_path) + raise errors.AccountNotFound(f"Account at {account_dir_path} does not exist") try: with open(self._regr_path(account_dir_path)) as regr_file: - # TODO: Remove cast when https://github.com/certbot/certbot/pull/9073 is merged. - regr = cast(messages.RegistrationResource, - messages.RegistrationResource.json_loads(regr_file.read())) + regr = messages.RegistrationResource.json_loads(regr_file.read()) with open(self._key_path(account_dir_path)) as key_file: - # TODO: Remove cast when https://github.com/certbot/certbot/pull/9073 is merged. - key = cast(jose.JWK, jose.JWK.json_loads(key_file.read())) + key = jose.JWK.json_loads(key_file.read()) with open(self._metadata_path(account_dir_path)) as metadata_file: - # TODO: Remove cast when https://github.com/certbot/certbot/pull/9073 is merged. - meta = cast(Account.Meta, Account.Meta.json_loads(metadata_file.read())) + meta = Account.Meta.json_loads(metadata_file.read()) except IOError as error: raise errors.AccountStorageError(error) @@ -296,8 +291,7 @@ class AccountFileStorage(interfaces.AccountStorage): """ account_dir_path = self._account_dir_path(account_id) if not os.path.isdir(account_dir_path): - raise errors.AccountNotFound( - "Account at %s does not exist" % account_dir_path) + raise errors.AccountNotFound(f"Account at {account_dir_path} does not exist") # Step 1: Delete account specific links and the directory self._delete_account_dir_for_server_path(account_id, self.config.server_path) diff --git a/certbot/certbot/_internal/auth_handler.py b/certbot/certbot/_internal/auth_handler.py index 16b8dfdbe..979ef0220 100644 --- a/certbot/certbot/_internal/auth_handler.py +++ b/certbot/certbot/_internal/auth_handler.py @@ -88,8 +88,8 @@ class AuthHandler: # If debug is on, wait for user input before starting the verification process. if config.debug_challenges: display_util.notification( - 'Challenges loaded. Press continue to submit to CA. ' - 'Pass "-v" for more info about challenges.', pause=True) + 'Challenges loaded. Press continue to submit to CA.\n' + + self._debug_challenges_msg(achalls, config), pause=True) except errors.AuthorizationError as error: logger.critical('Failure in setting up challenges.') logger.info('Attempting to clean up outstanding challenges...') @@ -324,6 +324,44 @@ class AuthHandler: display_util.notify("".join(msg)) + def _debug_challenges_msg(self, achalls: List[achallenges.AnnotatedChallenge], + config: configuration.NamespaceConfig) -> str: + """Construct message for debug challenges prompt + + :param list achalls: A list of + :class:`certbot.achallenges.AnnotatedChallenge`. + :param certbot.configuration.NamespaceConfig config: current Certbot configuration + :returns: Message containing challenge debug info + :rtype: str + + """ + if config.verbose_count > 0: + msg = [] + http01_achalls = {} + dns01_achalls = {} + for achall in achalls: + if isinstance(achall.chall, challenges.HTTP01): + http01_achalls[achall.chall.uri(achall.domain)] = ( + achall.validation(achall.account_key) + "\n" + ) + if isinstance(achall.chall, challenges.DNS01): + dns01_achalls[achall.validation_domain_name(achall.domain)] = ( + achall.validation(achall.account_key) + "\n" + ) + if http01_achalls: + msg.append("The following URLs should be accessible from the " + "internet and return the value mentioned:\n") + for uri, key_authz in http01_achalls.items(): + msg.append(f"URL: {uri}\nExpected value: {key_authz}") + if dns01_achalls: + msg.append("The following FQDNs should return a TXT resource " + "record with the value mentioned:\n") + for fqdn, key_authz_hash in dns01_achalls.items(): + msg.append(f"FQDN: {fqdn}\nExpected value: {key_authz_hash}") + return "\n" + "\n".join(msg) + else: + return 'Pass "-v" for more info about challenges.' + def challb_to_achall(challb: messages.ChallengeBody, account_key: josepy.JWK, domain: str) -> achallenges.AnnotatedChallenge: @@ -345,8 +383,7 @@ def challb_to_achall(challb: messages.ChallengeBody, account_key: josepy.JWK, challb=challb, domain=domain, account_key=account_key) elif isinstance(chall, challenges.DNS): return achallenges.DNS(challb=challb, domain=domain) - raise errors.Error( - "Received unsupported challenge of type: {0}".format(chall.typ)) + raise errors.Error(f"Received unsupported challenge of type: {chall.typ}") def gen_challenge_path(challbs: List[messages.ChallengeBody], diff --git a/certbot/certbot/_internal/cert_manager.py b/certbot/certbot/_internal/cert_manager.py index 7eeddfa1a..c7205c304 100644 --- a/certbot/certbot/_internal/cert_manager.py +++ b/certbot/certbot/_internal/cert_manager.py @@ -285,7 +285,7 @@ def match_and_check_overlaps(cli_config: configuration.NamespaceConfig, matched: List[str] = _search_lineages(cli_config, find_matches, [], acceptable_matches) if not matched: - raise errors.Error("No match found for cert-path {0}!".format(cli_config.cert_path)) + raise errors.Error(f"No match found for cert-path {cli_config.cert_path}!") elif len(matched) > 1: raise errors.OverlappingMatchFound() return matched @@ -318,26 +318,19 @@ def human_readable_cert_info(config: configuration.NamespaceConfig, cert: storag if diff.days == 1: status = "VALID: 1 day" elif diff.days < 1: - status = "VALID: {0} hour(s)".format(diff.seconds // 3600) + status = f"VALID: {diff.seconds // 3600} hour(s)" else: - status = "VALID: {0} days".format(diff.days) + status = f"VALID: {diff.days} days" valid_string = "{0} ({1})".format(cert.target_expiry, status) serial = format(crypto_util.get_serial_from_cert(cert.cert_path), 'x') - certinfo.append(" Certificate Name: {}\n" - " Serial Number: {}\n" - " Key Type: {}\n" - " Domains: {}\n" - " Expiry Date: {}\n" - " Certificate Path: {}\n" - " Private Key Path: {}".format( - cert.lineagename, - serial, - cert.private_key_type, - " ".join(cert.names()), - valid_string, - cert.fullchain, - cert.privkey)) + certinfo.append(f" Certificate Name: {cert.lineagename}\n" + f" Serial Number: {serial}\n" + f" Key Type: {cert.private_key_type}\n" + f' Domains: {" ".join(cert.names())}\n' + f" Expiry Date: {valid_string}\n" + f" Certificate Path: {cert.fullchain}\n" + f" Private Key Path: {cert.privkey}") return "".join(certinfo) diff --git a/certbot/certbot/_internal/cli/__init__.py b/certbot/certbot/_internal/cli/__init__.py index a69f96666..d11a454b1 100644 --- a/certbot/certbot/_internal/cli/__init__.py +++ b/certbot/certbot/_internal/cli/__init__.py @@ -264,7 +264,9 @@ def prepare_and_parse_args(plugins: plugins_disco.PluginsRegistry, args: List[st [None, "certonly", "run"], "--debug-challenges", action="store_true", default=flag_default("debug_challenges"), help="After setting up challenges, wait for user input before " - "submitting to CA") + "submitting to CA. When used in combination with the `-v` " + "option, the challenge URLs or FQDNs and their expected " + "return values are shown.") helpful.add( "testing", "--no-verify-ssl", action="store_true", help=config_help("no_verify_ssl"), diff --git a/certbot/certbot/_internal/client.py b/certbot/certbot/_internal/client.py index 9688918cd..057b4f059 100644 --- a/certbot/certbot/_internal/client.py +++ b/certbot/certbot/_internal/client.py @@ -271,9 +271,9 @@ def perform_registration(acme: acme_client.ClientV2, config: configuration.Names except messages.Error as e: if e.code in ("invalidEmail", "invalidContact"): if config.noninteractive_mode: - msg = ("The ACME server believes %s is an invalid email address. " + msg = (f"The ACME server believes {config.email} is an invalid email address. " "Please ensure it is a valid email and attempt " - "registration again." % config.email) + "registration again.") raise errors.Error(msg) config.email = display_ops.get_email(invalid=True) return perform_registration(acme, config, tos_cb) diff --git a/certbot/certbot/_internal/display/obj.py b/certbot/certbot/_internal/display/obj.py index 39b737e80..c5c2e388b 100644 --- a/certbot/certbot/_internal/display/obj.py +++ b/certbot/certbot/_internal/display/obj.py @@ -356,16 +356,15 @@ class FileDisplay: """ # Can take either tuples or single items in choices list if choices and isinstance(choices[0], tuple): - choices = ["%s - %s" % (c[0], c[1]) for c in choices] + choices = [f"{c[0]} - {c[1]}" for c in choices] # Write out the message to the user - self.outfile.write( - "{new}{msg}{new}".format(new=os.linesep, msg=message)) + self.outfile.write(f"{os.linesep}{message}{os.linesep}") self.outfile.write(SIDE_FRAME + os.linesep) # Write out the menu choices for i, desc in enumerate(choices, 1): - msg = "{num}: {desc}".format(num=i, desc=desc) + msg = f"{i}: {desc}" self.outfile.write(util.wrap_lines(msg)) # Keep this outside of the textwrap diff --git a/certbot/certbot/_internal/eff.py b/certbot/certbot/_internal/eff.py index 2f3926895..729991e0d 100644 --- a/certbot/certbot/_internal/eff.py +++ b/certbot/certbot/_internal/eff.py @@ -1,6 +1,5 @@ """Subscribes users to the EFF newsletter.""" import logging -from typing import cast from typing import Optional import requests @@ -33,11 +32,9 @@ def prepare_subscription(config: configuration.NamespaceConfig, acc: Account) -> if config.email is None: _report_failure("you didn't provide an e-mail address") else: - # TODO: Remove cast when https://github.com/certbot/certbot/pull/9073 is merged. - acc.meta = cast(Account.Meta, acc.meta.update(register_to_eff=config.email)) + acc.meta = acc.meta.update(register_to_eff=config.email) elif config.email and _want_subscription(): - # TODO: Remove cast when https://github.com/certbot/certbot/pull/9073 is merged. - acc.meta = cast(Account.Meta, acc.meta.update(register_to_eff=config.email)) + acc.meta = acc.meta.update(register_to_eff=config.email) if acc.meta.register_to_eff: storage = AccountFileStorage(config) @@ -56,11 +53,9 @@ def handle_subscription(config: configuration.NamespaceConfig, acc: Optional[Acc if config.dry_run or not acc: return if acc.meta.register_to_eff: - # TODO: Remove cast when https://github.com/certbot/certbot/pull/9073 is merged. - subscribe(cast(str, acc.meta.register_to_eff)) + subscribe(acc.meta.register_to_eff) - # TODO: Remove cast when https://github.com/certbot/certbot/pull/9073 is merged. - acc.meta = cast(Account.Meta, acc.meta.update(register_to_eff=None)) + acc.meta = acc.meta.update(register_to_eff=None) storage = AccountFileStorage(config) storage.update_meta(acc) diff --git a/certbot/certbot/_internal/hooks.py b/certbot/certbot/_internal/hooks.py index 813f7f6bd..76cda466a 100644 --- a/certbot/certbot/_internal/hooks.py +++ b/certbot/certbot/_internal/hooks.py @@ -52,10 +52,11 @@ def validate_hook(shell_cmd: str, hook_name: str) -> None: if not _prog(cmd): path = os.environ["PATH"] if os.path.exists(cmd): - msg = "{1}-hook command {0} exists, but is not executable.".format(cmd, hook_name) + msg = f"{cmd}-hook command {hook_name} exists, but is not executable." else: - msg = "Unable to find {2}-hook command {0} in the PATH.\n(PATH is {1})".format( - cmd, path, hook_name) + msg = ( + f"Unable to find {hook_name}-hook command {cmd} in the PATH.\n(PATH is {path})" + ) raise errors.HookCommandNotFound(msg) diff --git a/certbot/certbot/_internal/main.py b/certbot/certbot/_internal/main.py index f4062efaa..18d819a5c 100644 --- a/certbot/certbot/_internal/main.py +++ b/certbot/certbot/_internal/main.py @@ -156,17 +156,39 @@ def _handle_unexpected_key_type_migration(config: configuration.NamespaceConfig, :param config: Current configuration provided by the client :param cert: Matching certificate that could be renewed """ - if not cli.set_by_cli("key_type") or not cli.set_by_cli("certname"): + new_key_type = config.key_type.upper() + cur_key_type = cert.private_key_type.upper() - new_key_type = config.key_type.upper() - cur_key_type = cert.private_key_type.upper() + if new_key_type == cur_key_type: + return - if new_key_type != cur_key_type: - msg = ('Are you trying to change the key type of the certificate named {0} ' - 'from {1} to {2}? Please provide both --cert-name and --key-type on ' - 'the command line to confirm the change you are trying to make.') - msg = msg.format(cert.lineagename, cur_key_type, new_key_type) - raise errors.Error(msg) + # If both --key-type and --cert-name are provided, we consider the user's intent to + # be unambiguous: to change the key type of this lineage. + is_confirmed_via_cli = cli.set_by_cli("key_type") and cli.set_by_cli("certname") + + # Failing that, we interactively prompt the user to confirm the change. + if is_confirmed_via_cli or display_util.yesno( + f'An {cur_key_type} certificate named {cert.lineagename} already exists. Do you want to ' + f'update its key type to {new_key_type}?', + yes_label='Update key type', no_label='Keep existing key type', + default=False, force_interactive=False, + ): + return + + # If --key-type was set on the CLI but the user did not confirm the key type change using + # one of the two above methods, their intent is ambiguous. Error out. + if cli.set_by_cli("key_type"): + raise errors.Error( + 'Are you trying to change the key type of the certificate named ' + f'{cert.lineagename} from {cur_key_type} to {new_key_type}? Please provide ' + 'both --cert-name and --key-type on the command line to confirm the change ' + 'you are trying to make.' + ) + + # The mismatch between the lineage's key type and config.key_type is caused by Certbot's + # default value. The user is not asking for a key change: keep the key type of the existing + # lineage. + config.key_type = cur_key_type.lower() def _handle_subset_cert_request(config: configuration.NamespaceConfig, @@ -1372,6 +1394,20 @@ def run(config: configuration.NamespaceConfig, except errors.PluginSelectionError as e: return str(e) + if config.must_staple and installer and "staple-ocsp" not in installer.supported_enhancements(): + raise errors.NotSupportedError( + "Must-Staple extension requested, but OCSP stapling is not supported by the selected " + f"installer ({config.installer})\n\n" + "You can either:\n" + " * remove the --must-staple option from the command line and obtain a certificate " + "without the Must-Staple extension, or;\n" + " * use the `certonly` subcommand and manually install the certificate into the " + "intended service (e.g. webserver). You must also then manually enable OCSP stapling, " + "as it is required for certificates with the Must-Staple extension to " + "function properly.\n" + " * choose a different installer plugin (such as --nginx or --apache), if possible." + ) + # Preflight check for enhancement support by the selected installer if not enhancements.are_supported(config, installer): raise errors.NotSupportedError("One ore more of the requested enhancements " @@ -1673,10 +1709,6 @@ def main(cli_args: List[str] = None) -> Optional[Union[str, int]]: zope.component.provideUtility(report, interfaces.IReporter) util.atexit_register(report.print_messages) - if sys.version_info[:2] == (3, 6): - logger.warning("Python 3.6 support will be dropped in the next release " - "of Certbot - please upgrade your Python version.") - with make_displayer(config) as displayer: display_obj.set_display(displayer) diff --git a/certbot/certbot/_internal/renewal.py b/certbot/certbot/_internal/renewal.py index 91a38b11f..4fb2ca00a 100644 --- a/certbot/certbot/_internal/renewal.py +++ b/certbot/certbot/_internal/renewal.py @@ -247,8 +247,7 @@ def _restore_bool(name: str, value: str) -> bool: """ lowercase_value = value.lower() if lowercase_value not in ("true", "false"): - raise errors.Error( - "Expected True or False for {0} but found {1}".format(name, value)) + raise errors.Error(f"Expected True or False for {name} but found {value}") return lowercase_value == "true" @@ -271,7 +270,7 @@ def _restore_int(name: str, value: str) -> int: try: return int(value) except ValueError: - raise errors.Error("Expected a numeric value for {0}".format(name)) + raise errors.Error(f"Expected a numeric value for {name}") def _restore_str(name: str, value: str) -> Optional[str]: @@ -323,8 +322,8 @@ def _avoid_invalidating_lineage(config: configuration.NamespaceConfig, names = ", ".join(lineage.names()) raise errors.Error( "You've asked to renew/replace a seemingly valid certificate with " - "a test certificate (domains: {0}). We will not do that " - "unless you use the --break-my-certs flag!".format(names)) + f"a test certificate (domains: {names}). We will not do that " + "unless you use the --break-my-certs flag!") def renew_cert(config: configuration.NamespaceConfig, domains: Optional[List[str]], @@ -375,7 +374,7 @@ def _renew_describe_results(config: configuration.NamespaceConfig, renew_success notify = display_util.notify notify_error = logger.error - notify('\n{}'.format(display_obj.SIDE_FRAME)) + notify(f'\n{display_obj.SIDE_FRAME}') renewal_noun = "simulated renewal" if config.dry_run else "renewal" @@ -383,19 +382,19 @@ def _renew_describe_results(config: configuration.NamespaceConfig, renew_success notify("The following certificates are not due for renewal yet:") notify(report(renew_skipped, "skipped")) if not renew_successes and not renew_failures: - notify("No {renewal}s were attempted.".format(renewal=renewal_noun)) + notify(f"No {renewal_noun}s were attempted.") if (config.pre_hook is not None or config.renew_hook is not None or config.post_hook is not None): notify("No hooks were run.") elif renew_successes and not renew_failures: - notify("Congratulations, all {renewal}s succeeded: ".format(renewal=renewal_noun)) + notify(f"Congratulations, all {renewal_noun}s succeeded: ") notify(report(renew_successes, "success")) elif renew_failures and not renew_successes: notify_error("All %ss failed. The following certificates could " "not be renewed:", renewal_noun) notify_error(report(renew_failures, "failure")) elif renew_failures and renew_successes: - notify("The following {renewal}s succeeded:".format(renewal=renewal_noun)) + notify(f"The following {renewal_noun}s succeeded:") notify(report(renew_successes, "success") + "\n") notify_error("The following %ss failed:", renewal_noun) notify_error(report(renew_failures, "failure")) @@ -508,8 +507,8 @@ def handle_renewal_request(config: configuration.NamespaceConfig) -> None: renew_skipped, parse_failures) if renew_failures or parse_failures: - raise errors.Error("{0} renew failure(s), {1} parse failure(s)".format( - len(renew_failures), len(parse_failures))) + raise errors.Error( + f"{len(renew_failures)} renew failure(s), {len(parse_failures)} parse failure(s)") # Windows installer integration tests rely on handle_renewal_request behavior here. # If the text below changes, these tests will need to be updated accordingly. @@ -526,4 +525,4 @@ def _update_renewal_params_from_key(key_path: str, config: configuration.Namespa config.key_type = 'ecdsa' config.elliptic_curve = key.curve.name else: - raise errors.Error('Key at {0} is of an unsupported type: {1}.'.format(key_path, type(key))) + raise errors.Error(f'Key at {key_path} is of an unsupported type: {type(key)}.') diff --git a/certbot/certbot/_internal/snap_config.py b/certbot/certbot/_internal/snap_config.py index f006c8be1..dd3a6399c 100644 --- a/certbot/certbot/_internal/snap_config.py +++ b/certbot/certbot/_internal/snap_config.py @@ -54,7 +54,8 @@ def prepare_env(cli_args: List[str]) -> List[str]: session.mount('http://snapd/', _SnapdAdapter()) try: - response = session.get('http://snapd/v2/connections?snap=certbot&interface=content') + response = session.get('http://snapd/v2/connections?snap=certbot&interface=content', + timeout=30.0) response.raise_for_status() except RequestException as e: if isinstance(e, HTTPError) and e.response.status_code == 404: diff --git a/certbot/certbot/_internal/storage.py b/certbot/certbot/_internal/storage.py index 5dd3e565b..567073acf 100644 --- a/certbot/certbot/_internal/storage.py +++ b/certbot/certbot/_internal/storage.py @@ -60,10 +60,10 @@ def renewal_conf_files(config: configuration.NamespaceConfig) -> List[str]: def renewal_file_for_certname(config: configuration.NamespaceConfig, certname: str) -> str: """Return /path/to/certname.conf in the renewal conf directory""" - path = os.path.join(config.renewal_configs_dir, "{0}.conf".format(certname)) + path = os.path.join(config.renewal_configs_dir, f"{certname}.conf") if not os.path.exists(path): - raise errors.CertStorageError("No certificate found with name {0} (expected " - "{1}).".format(certname, path)) + raise errors.CertStorageError( + f"No certificate found with name {certname} (expected {path}).") return path @@ -298,6 +298,11 @@ def relevant_values(all_values: Mapping[str, Any]) -> Dict[str, Any]: # and behavioral consistency when versions of Certbot with different # server defaults are used. rv["server"] = all_values["server"] + + # Save key type to help with forward compatibility on Certbot's transition + # from RSA to ECDSA certificates by default. + rv["key_type"] = all_values["key_type"] + return rv @@ -1174,7 +1179,7 @@ class RenewableCert(interfaces.RenewableCert): if os.path.islink(old_privkey): old_privkey = filesystem.readlink(old_privkey) else: - old_privkey = "privkey{0}.pem".format(prior_version) + old_privkey = f"privkey{prior_version}.pem" logger.debug("Writing symlink to old private key, %s.", old_privkey) os.symlink(old_privkey, target["privkey"]) else: diff --git a/certbot/certbot/configuration.py b/certbot/certbot/configuration.py index 1a72cbce7..ebeb8e98c 100644 --- a/certbot/certbot/configuration.py +++ b/certbot/certbot/configuration.py @@ -120,7 +120,7 @@ class NamespaceConfig: @property def must_staple(self) -> bool: - """Adds the OCSP Must Staple extension to the certificate. + """Adds the OCSP Must-Staple extension to the certificate. Autoconfigures OCSP Stapling for supported setups (Apache version >= 2.3.3 ). diff --git a/certbot/certbot/crypto_util.py b/certbot/certbot/crypto_util.py index ef86c5e46..f45bf3505 100644 --- a/certbot/certbot/crypto_util.py +++ b/certbot/certbot/crypto_util.py @@ -143,7 +143,7 @@ def generate_csr(privkey: util.Key, names: Union[List[str], Set[str]], path: str :type privkey: :class:`certbot.util.Key` :param set names: `str` names to include in the CSR :param str path: Certificate save directory. - :param bool must_staple: If true, include the TLS Feature extension "OCSP Must Staple" + :param bool must_staple: If true, include the TLS Feature extension "OCSP Must-Staple" :param bool strict_permissions: If true and path exists, an exception is raised if the directory doesn't have 0755 permissions or isn't owned by the current user. diff --git a/certbot/certbot/reverter.py b/certbot/certbot/reverter.py index 69a8ac83f..0c22b3e49 100644 --- a/certbot/certbot/reverter.py +++ b/certbot/certbot/reverter.py @@ -241,8 +241,7 @@ class Reverter: except (IOError, OSError): # This file is required in all checkpoints. logger.error("Unable to recover files from %s", cp_dir) - raise errors.ReverterError( - "Unable to recover files from %s" % cp_dir) + raise errors.ReverterError(f"Unable to recover files from {cp_dir}") # Remove any newly added files if they exist self._remove_contained_files(os.path.join(cp_dir, "NEW_FILES")) @@ -295,9 +294,7 @@ class Reverter: # Verify no save_file is in protected_files for filename in protected_files: if filename in save_files: - raise errors.ReverterError( - "Attempting to overwrite challenge " - "file - %s" % filename) + raise errors.ReverterError(f"Attempting to overwrite challenge file - {filename}") def register_file_creation(self, temporary: bool, *files: str) -> None: r"""Register the creation of all files during certbot execution. diff --git a/certbot/docs/cli-help.txt b/certbot/docs/cli-help.txt index 2c37daf8e..78be10237 100644 --- a/certbot/docs/cli-help.txt +++ b/certbot/docs/cli-help.txt @@ -35,7 +35,7 @@ manage your account: --agree-tos Agree to the ACME server's Subscriber Agreement -m EMAIL Email address for important account notifications -options: +optional arguments: -h, --help show this help message and exit -c CONFIG_FILE, --config CONFIG_FILE path to config file (default: /etc/letsencrypt/cli.ini @@ -97,7 +97,9 @@ options: necessary to accurately simulate renewal. --deploy- hook commands are not called. (default: False) --debug-challenges After setting up challenges, wait for user input - before submitting to CA (default: False) + before submitting to CA. When used in combination with + the `-v` option, the challenge URLs or FQDNs and their + expected return values are shown. (default: False) --preferred-chain PREFERRED_CHAIN Set the preferred certificate chain. If the CA offers multiple certificate chains, prefer the chain whose @@ -124,7 +126,7 @@ options: 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.23.0 (certbot; + "". (default: CertbotACMEClient/1.25.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, @@ -192,7 +194,7 @@ security: rsa) --elliptic-curve N The SECG elliptic curve name to use. Please see RFC 8446 for supported values. (default: secp256r1) - --must-staple Adds the OCSP Must Staple extension to the + --must-staple Adds the OCSP Must-Staple extension to the certificate. Autoconfigures OCSP Stapling for supported setups (Apache version >= 2.3.3 ). (default: False) diff --git a/certbot/docs/install.rst b/certbot/docs/install.rst index 4a678749a..413038c02 100644 --- a/certbot/docs/install.rst +++ b/certbot/docs/install.rst @@ -12,12 +12,15 @@ Get Certbot System Requirements =================== -- Python 3.6+ +- Python 3.7+ - UNIX-like operating system - Root access - Port 80 Open -.. Note:: The Apache plugin currently requires an OS with augeas version 1.0; currently it supports modern OSes based on Debian, Ubuntu, Fedora, SUSE, Gentoo and Darwin. +.. Note:: To run without root privileges, but for most users who want to avoid running an ACME client as root, either letsencrypt-nosudo or simp_le are more appropriate choices. + +.. Note:: The Apache plugin currently requires an OS with augeas version 1.0; currently `it supports `_ +modern OSes based on Debian, Ubuntu, Fedora, SUSE, Gentoo and Darwin. Installation diff --git a/certbot/docs/using.rst b/certbot/docs/using.rst index 07406c356..0087c230d 100644 --- a/certbot/docs/using.rst +++ b/certbot/docs/using.rst @@ -91,9 +91,9 @@ with ``--preferred-challenges``. There are also many third-party-plugins_ available. Below we describe in more detail the circumstances in which each plugin can be used, and how to use it. -.. _challenges: https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-7 -.. _http-01: https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-7.2 -.. _dns-01: https://tools.ietf.org/html/draft-ietf-acme-acme-03#section-7.4 +.. _challenges: https://datatracker.ietf.org/doc/html/rfc8555#section-8 +.. _http-01: https://datatracker.ietf.org/doc/html/rfc8555#section-8.3 +.. _dns-01: https://datatracker.ietf.org/doc/html/rfc8555#section-8.4 Apache ------ diff --git a/certbot/setup.py b/certbot/setup.py index 0fb00c058..092e88135 100644 --- a/certbot/setup.py +++ b/certbot/setup.py @@ -8,7 +8,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -min_setuptools_version='39.0.1' +min_setuptools_version='41.6.0' # This conditional isn't necessary, but it provides better error messages to # people who try to install this package with older versions of setuptools. if parse_version(setuptools_version) < parse_version(min_setuptools_version): @@ -52,10 +52,10 @@ install_requires = [ 'configobj>=5.0.6', 'cryptography>=2.5.0', 'distro>=1.0.1', - 'josepy>=1.9.0', + 'josepy>=1.13.0', 'parsedatetime>=2.4', 'pyrfc3339', - 'pytz', + 'pytz>=2019.3', # This dependency needs to be added using environment markers to avoid its # installation on Linux. 'pywin32>=300 ; sys_platform == "win32"', @@ -101,7 +101,7 @@ test_extras = [ 'types-setuptools', 'types-six', # typing-extensions is required to import typing.Protocol and make the mypy checks - # pass (along with pylint about non-existent objects) on Python 3.6 & 3.7 + # pass (along with pylint about non-existent objects) on Python 3.7 'typing-extensions', 'wheel', ] @@ -118,7 +118,7 @@ setup( author="Certbot Project", author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Console', @@ -128,7 +128,6 @@ setup( 'Operating System :: POSIX :: Linux', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/certbot/tests/auth_handler_test.py b/certbot/tests/auth_handler_test.py index a94259a79..e13dfbfe5 100644 --- a/certbot/tests/auth_handler_test.py +++ b/certbot/tests/auth_handler_test.py @@ -3,6 +3,7 @@ import functools import logging import unittest +from josepy import b64encode try: import mock except ImportError: # pragma: no cover @@ -72,13 +73,13 @@ class HandleAuthorizationsTest(unittest.TestCase): with mock.patch("zope.component.provideUtility"): display_obj.set_display(self.mock_display) - self.mock_auth = mock.MagicMock(name="ApacheConfigurator") + self.mock_auth = mock.MagicMock(name="Authenticator") self.mock_auth.get_chall_pref.return_value = [challenges.HTTP01] self.mock_auth.perform.side_effect = gen_auth_resp - self.mock_account = mock.Mock(key=util.Key("file_path", "PEM")) + self.mock_account = mock.MagicMock() self.mock_net = mock.MagicMock(spec=acme_client.ClientV2) self.mock_net.acme_version = 1 self.mock_net.retry_after.side_effect = acme_client.ClientV2.retry_after @@ -190,16 +191,56 @@ class HandleAuthorizationsTest(unittest.TestCase): self._test_name3_http_01_3_common(combos=False) def test_debug_challenges(self): - config = mock.Mock(debug_challenges=True) + config = mock.Mock(debug_challenges=True, verbose_count=0) authzrs = [gen_dom_authzr(domain="0", challs=acme_util.CHALLENGES)] mock_order = mock.MagicMock(authorizations=authzrs) + account_key_thumbprint = b"foobarbaz" + self.mock_account.key.thumbprint.return_value = account_key_thumbprint + self.mock_net.poll.side_effect = _gen_mock_on_poll() self.handler.handle_authorizations(mock_order, config) self.assertEqual(self.mock_net.answer_challenge.call_count, 1) self.assertEqual(self.mock_display.notification.call_count, 1) + self.assertIn('Pass "-v" for more info', + self.mock_display.notification.call_args[0][0]) + self.assertNotIn(f"http://{authzrs[0].body.identifier.value}/.well-known/acme-challenge/" + + b64encode(authzrs[0].body.challenges[0].chall.token).decode(), + self.mock_display.notification.call_args[0][0]) + self.assertNotIn(b64encode(account_key_thumbprint).decode(), + self.mock_display.notification.call_args[0][0]) + + def test_debug_challenges_verbose(self): + config = mock.Mock(debug_challenges=True, verbose_count=1) + authzrs = [gen_dom_authzr(domain="0", challs=[acme_util.HTTP01]), + gen_dom_authzr(domain="1", challs=[acme_util.DNS01])] + mock_order = mock.MagicMock(authorizations=authzrs) + + account_key_thumbprint = b"foobarbaz" + self.mock_account.key.thumbprint.return_value = account_key_thumbprint + + self.mock_net.poll.side_effect = _gen_mock_on_poll() + + self.mock_auth.get_chall_pref.return_value = [challenges.HTTP01, + challenges.DNS01] + + self.handler.handle_authorizations(mock_order, config) + + self.assertEqual(self.mock_net.answer_challenge.call_count, 2) + self.assertEqual(self.mock_display.notification.call_count, 1) + self.assertNotIn('Pass "-v" for more info', + self.mock_display.notification.call_args[0][0]) + self.assertIn(f"http://{authzrs[0].body.identifier.value}/.well-known/acme-challenge/" + + b64encode(authzrs[0].body.challenges[0].chall.token).decode(), + self.mock_display.notification.call_args[0][0]) + self.assertIn(b64encode(account_key_thumbprint).decode(), + self.mock_display.notification.call_args[0][0]) + self.assertIn(f"_acme-challenge.{authzrs[1].body.identifier.value}", + self.mock_display.notification.call_args[0][0]) + self.assertIn(authzrs[1].body.challenges[0].validation(self.mock_account.key), + self.mock_display.notification.call_args[0][0]) def test_perform_failure(self): authzrs = [gen_dom_authzr(domain="0", challs=acme_util.CHALLENGES)] diff --git a/certbot/tests/main_test.py b/certbot/tests/main_test.py index 3813e4d50..c29f4d758 100644 --- a/certbot/tests/main_test.py +++ b/certbot/tests/main_test.py @@ -70,30 +70,50 @@ class TestHandleCerts(unittest.TestCase): self.assertEqual(ret, ("renew", mock_lineage)) self.assertTrue(mock_handle_migration.called) + @mock.patch("certbot._internal.main.display_util.yesno") @mock.patch("certbot._internal.main.cli.set_by_cli") - def test_handle_unexpected_key_type_migration(self, mock_set): + def test_handle_unexpected_key_type_migration(self, mock_set, mock_yesno): config = mock.Mock() - config.key_type = "rsa" cert = mock.Mock() - cert.private_key_type = "ecdsa" + # If the key types do not differ, it should be a no-op. + config.key_type = "rsa" + cert.private_key_type = "rsa" + main._handle_unexpected_key_type_migration(config, cert) + mock_yesno.assert_not_called() + self.assertEqual(config.key_type, cert.private_key_type) + + # If the user confirms the change interactively, the key change should proceed silently. + cert.private_key_type = "ecdsa" + mock_yesno.return_value = True + main._handle_unexpected_key_type_migration(config, cert) + self.assertEqual(mock_set.call_count, 2) + self.assertEqual(config.key_type, "rsa") + + # User does not interactively confirm the key type change. + mock_yesno.return_value = False + + # If --key-type and --cert-name are both set, the key type change should proceed silently. mock_set.return_value = True main._handle_unexpected_key_type_migration(config, cert) + self.assertEqual(config.key_type, "rsa") + # If neither --key-type nor --cert-name are set, Certbot should keep the old key type. mock_set.return_value = False - with self.assertRaises(errors.Error) as raised: - main._handle_unexpected_key_type_migration(config, cert) - self.assertIn("Please provide both --cert-name and --key-type", str(raised.exception)) + main._handle_unexpected_key_type_migration(config, cert) + self.assertEqual(config.key_type, "ecdsa") + # If --key-type is set and --cert-name isn't, Certbot should error. + config.key_type = "rsa" mock_set.side_effect = lambda var: var != "certname" with self.assertRaises(errors.Error) as raised: main._handle_unexpected_key_type_migration(config, cert) self.assertIn("Please provide both --cert-name and --key-type", str(raised.exception)) + # If --key-type is not set, Certbot should keep the old key type. mock_set.side_effect = lambda var: var != "key_type" - with self.assertRaises(errors.Error) as raised: - main._handle_unexpected_key_type_migration(config, cert) - self.assertIn("Please provide both --cert-name and --key-type", str(raised.exception)) + main._handle_unexpected_key_type_migration(config, cert) + self.assertEqual(config.key_type, "ecdsa") class RunTest(test_util.ConfigTestCase): @@ -177,6 +197,15 @@ class RunTest(test_util.ConfigTestCase): # The final success message shouldn't be shown self.mock_success_installation.assert_not_called() + @mock.patch('certbot._internal.main.plug_sel.choose_configurator_plugins') + def test_run_must_staple_not_supported(self, mock_choose): + mock_choose.return_value = (null.Installer(self.config, "null"), None) + plugins = disco.PluginsRegistry.find_all() + self.config.must_staple = True + self.assertRaises(errors.NotSupportedError, + main.run, + self.config, plugins) + class CertonlyTest(unittest.TestCase): """Tests for certbot._internal.main.certonly.""" diff --git a/certbot/tests/storage_test.py b/certbot/tests/storage_test.py index aa5910f1e..5be3c3037 100644 --- a/certbot/tests/storage_test.py +++ b/certbot/tests/storage_test.py @@ -39,7 +39,7 @@ class RelevantValuesTest(unittest.TestCase): """Tests for certbot._internal.storage.relevant_values.""" def setUp(self): - self.values = {"server": "example.org"} + self.values = {"server": "example.org", "key_type": "rsa"} def _call(self, *args, **kwargs): from certbot._internal.storage import relevant_values diff --git a/letstest/setup.py b/letstest/setup.py index 6f0e9bb49..4f05c8754 100644 --- a/letstest/setup.py +++ b/letstest/setup.py @@ -9,14 +9,13 @@ setup( author='Certbot Project', author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'License :: OSI Approved :: Apache Software License', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/pytest.ini b/pytest.ini index ea1593808..92a403451 100644 --- a/pytest.ini +++ b/pytest.ini @@ -27,8 +27,6 @@ # 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. -# 8) Ignore our own PendingDeprecationWarning about Python 3.6 soon to be dropped. -# See https://github.com/certbot/certbot/pull/9160. filterwarnings = error ignore:The external mock module:PendingDeprecationWarning @@ -38,4 +36,3 @@ filterwarnings = ignore:decodestring\(\) is a deprecated alias:DeprecationWarning:dns ignore:_SixMetaPathImporter.:ImportWarning ignore:ssl.PROTOCOL_TLS:DeprecationWarning:botocore - ignore:Python 3.6 support will be dropped:PendingDeprecationWarning diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index b3f1349e0..88a884c6d 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -80,6 +80,10 @@ parts: - python3-dev - cargo build-environment: + # We set this environment variable while building to try and increase the + # stability of fetching the rust crates needed to build the cryptography + # library. + - CARGO_NET_GIT_FETCH_WITH_CLI: "true" - SNAPCRAFT_PYTHON_VENV_ARGS: --upgrade # Constraints are passed through the environment variable PIP_CONSTRAINTS instead of using the # parts.[part_name].constraints option available in snapcraft.yaml when the Python plugin is diff --git a/tools/docker/core/Dockerfile b/tools/docker/core/Dockerfile index 14bd3323a..fc0912752 100644 --- a/tools/docker/core/Dockerfile +++ b/tools/docker/core/Dockerfile @@ -26,6 +26,10 @@ RUN apk add --no-cache --virtual .certbot-deps \ ca-certificates \ binutils +# We set this environment variable and install git while building to try and +# increase the stability of fetching the rust crates needed to build the +# cryptography library +ARG CARGO_NET_GIT_FETCH_WITH_CLI=true # Install certbot from sources RUN apk add --no-cache --virtual .build-deps \ gcc \ @@ -35,6 +39,7 @@ RUN apk add --no-cache --virtual .build-deps \ libffi-dev \ python3-dev \ cargo \ + git \ && python tools/pipstrap.py \ && python tools/pip_install.py --no-cache-dir \ --editable src/acme \ diff --git a/tools/finish_release.py b/tools/finish_release.py index 097551057..aa224e38f 100755 --- a/tools/finish_release.py +++ b/tools/finish_release.py @@ -135,7 +135,7 @@ def create_github_release(github_access_token, tempdir, version): # Upload windows installer to release print("Uploading windows installer") - release.upload_asset(tempdir + '/windows-installer/certbot-beta-installer-win32.exe') + release.upload_asset(tempdir + '/windows-installer/certbot-beta-installer-win_amd64.exe') release.update_release(release.title, release.body, draft=False) diff --git a/tools/oldest_constraints.txt b/tools/oldest_constraints.txt index a3ffc16ab..ef7b117c3 100644 --- a/tools/oldest_constraints.txt +++ b/tools/oldest_constraints.txt @@ -2,116 +2,115 @@ # that script. apacheconfig==0.3.2 asn1crypto==0.24.0 -astroid==2.9.0; python_version >= "3.6" and python_version < "4.0" -atomicwrites==1.4.0; python_version >= "3.6" and python_full_version < "3.0.0" and sys_platform == "win32" or sys_platform == "win32" and python_version >= "3.6" and python_full_version >= "3.4.0" -attrs==21.4.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" -bcrypt==3.2.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" -boto3==1.4.7 -botocore==1.7.41 -cached-property==1.5.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" +astroid==2.9.3; python_version >= "3.7" +atomicwrites==1.4.0; sys_platform == "win32" and python_version >= "3.7" +attrs==21.4.0; python_version >= "3.7" +bcrypt==3.2.0; python_version >= "3.7" +boto3==1.15.15 +botocore==1.18.15 +cached-property==1.5.2; python_version >= "3.7" +certifi==2021.10.8; python_version >= "3.7" cffi==1.9.1 -chardet==2.2.1 +chardet==3.0.4 cloudflare==1.5.1 -colorama==0.4.4; python_version >= "3.6" and python_full_version < "3.0.0" and sys_platform == "win32" or python_full_version >= "3.5.0" and python_version >= "3.6" and sys_platform == "win32" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" and sys_platform == "win32" or python_version >= "3.6" and python_version < "4.0" and sys_platform == "win32" and python_full_version >= "3.5.0" +colorama==0.4.4; sys_platform == "win32" and python_version >= "3.7" configargparse==0.10.0 configobj==5.0.6 -coverage==6.2; python_version >= "3.6" or python_version >= "3.6" -cryptography==3.2.1; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.5.0") -cython==0.29.26; (python_version >= "2.6" and python_full_version < "3.0.0") or (python_full_version >= "3.3.0") -distlib==0.3.4; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" +coverage==6.3.2; python_version >= "3.7" +cryptography==3.2.1 +cython==0.29.28 +distlib==0.3.4; python_version >= "3.7" distro==1.0.1 dns-lexicon==3.2.1 dnspython==1.15.0 -docker-compose==1.24.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" -docker-pycreds==0.4.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" -docker==3.7.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" -dockerpty==0.4.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" -docopt==0.6.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" -docutils==0.18.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" -execnet==1.9.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" -filelock==3.4.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" or python_version >= "3.6" +docker-compose==1.25.5; 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" +execnet==1.9.0; python_version >= "3.7" +filelock==3.6.0; python_version >= "3.7" funcsigs==0.4 -future==0.18.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6" +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.8.3; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.8" or python_version >= "3.6" and python_full_version >= "3.5.0" and python_version < "3.8" or python_version < "3.8" and python_version >= "3.6" -importlib-resources==5.4.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.7" or python_version >= "3.6" and python_full_version >= "3.5.0" and python_version < "3.7" -iniconfig==1.1.1; python_version >= "3.6" +importlib-metadata==4.11.2; python_version < "3.8" and python_version >= "3.7" +iniconfig==1.1.1; python_version >= "3.7" ipaddress==1.0.16 -isort==5.8.0; python_version >= "3.6" and python_version < "4.0" -jmespath==0.10.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6" -josepy==1.12.0; python_version >= "3.6" -jsonschema==2.6.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" -lazy-object-proxy==1.7.1; python_version >= "3.6" and python_version < "4.0" -logger==1.4; python_version >= "3.6" -mccabe==0.6.1; python_version >= "3.6" and python_version < "4.0" +isort==5.10.1; python_version >= "3.7" and python_version < "4.0" +jmespath==0.10.0; python_version >= "3.7" +josepy==1.13.0; python_version >= "3.7" +jsonschema==3.2.0; python_version >= "3.7" +lazy-object-proxy==1.7.1; python_version >= "3.7" +logger==1.4; python_version >= "3.7" +mccabe==0.6.1; python_version >= "3.7" mock==1.0.1 -mypy-extensions==0.4.3; python_version >= "3.6" -mypy==0.931; python_version >= "3.6" +mypy-extensions==0.4.3; python_version >= "3.7" +mypy==0.940; python_version >= "3.7" ndg-httpsclient==0.3.2 oauth2client==4.0.0 -packaging==21.3; python_version >= "3.6" -paramiko==2.9.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" +packaging==21.3; python_version >= "3.7" +paramiko==2.10.1; python_version >= "3.7" parsedatetime==2.4 pbr==1.8.0 -pip==21.3.1; python_version >= "3.6" -platformdirs==2.4.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" or python_version >= "3.6" and python_version < "4.0" -pluggy==1.0.0; python_version >= "3.6" +pip==22.0.4; python_version >= "3.7" +platformdirs==2.5.1; python_version >= "3.7" +pluggy==1.0.0; python_version >= "3.7" ply==3.4 -py==1.11.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" -pyasn1-modules==0.0.10; python_version >= "3.6" +py==1.11.0; python_version >= "3.7" +pyasn1-modules==0.0.10; python_version >= "3.7" pyasn1==0.1.9 pycparser==2.14 -pylint==2.12.0; python_version >= "3.6" and python_version < "4.0" -pynacl==1.5.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" +pylint==2.12.2 +pylint==2.12.2; python_version >= "3.7" +pynacl==1.5.0; python_version >= "3.7" pyopenssl==17.3.0 -pyparsing==2.2.0 -pypiwin32==223; sys_platform == "win32" and python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6") +pyparsing==2.2.1 +pypiwin32==223; sys_platform == "win32" and python_version >= "3.7" pyrfc3339==1.0 -pytest-cov==3.0.0; python_version >= "3.6" or python_version >= "3.6" -pytest-forked==1.4.0; python_version >= "3.6" -pytest-xdist==2.5.0; python_version >= "3.6" or python_version >= "3.6" -pytest==6.2.5; python_version >= "3.6" or python_version >= "3.6" +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" +pytest==7.0.1; python_version >= "3.7" python-augeas==0.5.0 -python-dateutil==2.8.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6" +python-dateutil==2.8.2; python_version >= "3.7" python-digitalocean==1.11 -pytz==2012c -pywin32==303; sys_platform == "win32" and python_version >= "3.6" or sys_platform == "win32" and python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6") -pyyaml==3.13; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" or python_version >= "3.6" -requests-file==1.5.1; python_version >= "3.6" -requests-toolbelt==0.9.1; python_version >= "3.6" -requests==2.14.2 -rsa==4.8; python_version >= "3.6" and python_version < "4" -s3transfer==0.1.13; python_version >= "3.6" -setuptools==39.0.1; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.3.0") +pytz==2019.3 +pywin32==303; sys_platform == "win32" and python_version >= "3.7" +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" +s3transfer==0.3.7; python_version >= "3.7" +setuptools==41.6.0 six==1.11.0 -texttable==0.9.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" -tldextract==3.1.2; python_version >= "3.6" -toml==0.10.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.3.0" -tomli==1.2.3; python_version >= "3.6" -tox==1.9.2; python_version >= "3.6" -typed-ast==1.5.1; python_version >= "3.6" and python_version < "3.8" or implementation_name == "cpython" and python_version < "3.8" and python_version >= "3.6" -types-cryptography==3.3.14; python_version >= "3.6" -types-enum34==1.1.7; python_version >= "3.6" -types-ipaddress==1.0.7; python_version >= "3.6" -types-mock==4.0.8; python_version >= "3.6" -types-pyopenssl==21.0.3; python_version >= "3.6" -types-pyrfc3339==1.1.1; python_version >= "3.6" -types-python-dateutil==2.8.7; python_version >= "3.6" -types-pytz==2021.3.4; python_version >= "3.6" -types-requests==2.27.7; python_version >= "3.6" -types-setuptools==57.4.7; python_version >= "3.6" -types-six==1.16.10; python_version >= "3.6" -types-urllib3==1.26.7; python_version >= "3.6" -typing-extensions==4.0.1; python_version >= "3.6" or python_version >= "3.6" and python_version < "3.10" or python_version < "3.8" and python_version >= "3.6" -uritemplate==3.0.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" -urllib3==1.10.2 -virtualenv==20.13.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" -websocket-client==0.59.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" -wheel==0.33.6; (python_version >= "2.7" and python_full_version < "3.0.0") or (python_full_version >= "3.4.0") -wrapt==1.13.3; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.5.0" -zipp==3.6.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.7" or python_version >= "3.6" and python_full_version >= "3.5.0" and python_version < "3.7" or python_version < "3.8" and python_version >= "3.6" +texttable==1.6.4; python_version >= "3.7" +tldextract==3.2.0; python_version >= "3.7" +toml==0.10.2; python_version >= "3.7" +tomli==2.0.1; python_version >= "3.7" +tox==1.9.2; 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" +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" +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.11; 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.10; python_version >= "3.7" +typing-extensions==4.1.1; 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.13.3; 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.13.3; python_version >= "3.7" +zipp==3.7.0; 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 2a2e2b826..c09f89806 100644 --- a/tools/pinning/current/pyproject.toml +++ b/tools/pinning/current/pyproject.toml @@ -6,7 +6,7 @@ authors = ["Certbot Project"] license = "Apache License 2.0" [tool.poetry.dependencies] -python = "^3.6" +python = "^3.7" # Local dependencies # Any local packages that have dependencies on other local packages must be @@ -69,11 +69,11 @@ poetry = ">=1.2.0a1" # point, it's probably worth enumerating and pinning them (and recursing to # THEIR build dependencies) as well. setuptools-rust = "*" -# Library traitlets is a transitive dependency of ipdb (traitlets -> ipython -> ipdb). -# Version 5.x is incompatible with Python 3.6 but for some reasons, poetry fails to -# add the appropriate marker and allows this version to be installed under Python 3.6. -# We add a pinning to not create a set of requirements incompatible with Python 3.6. -traitlets = "<5" +# 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" [tool.poetry.dev-dependencies] diff --git a/tools/pinning/oldest/pyproject.toml b/tools/pinning/oldest/pyproject.toml index 601b4d185..230410b5d 100644 --- a/tools/pinning/oldest/pyproject.toml +++ b/tools/pinning/oldest/pyproject.toml @@ -10,7 +10,7 @@ license = "Apache License 2.0" [tool.poetry.dependencies] # The Python version here should be kept in sync with the one used in our # oldest tests in tox.ini. -python = "3.6" +python = "3.7" # Local dependencies # Any local packages that have dependencies on other local packages must be @@ -37,27 +37,20 @@ certbot = {path = "../../../certbot", extras = ["test"]} acme = {path = "../../../acme", extras = ["test"]} # Oldest dependencies -# We specify the oldest versions of our dependencies that we keep -# support for below. We should only update these packages as needed to make use -# of features in newer versions of our dependencies. Keeping compatibility with -# older packages makes it much easier for OS maintainers to update their -# Certbot packages if needed or desired. -# -# When updating these dependencies, we should try to update them no further -# than the oldest version of the dependency found in CentOS/RHEL 8 + EPEL (or -# newer versions of CentOS/RHEL + EPEL) as our Certbot packages there see -# frequent updates. If the dependency being updated is a direct dependency of -# one of our own packages, the minimum required version of that dependency -# should be updated in our setup.py files as well to communicate this -# information to our users. +# We specify the oldest versions of our dependencies that we keep support for +# below. These dependencies can be updated as desired to simplify or improve +# Certbot or its development. If the dependency being updated is a direct +# dependency of one of our own packages, the minimum required version of that +# dependency should be updated in our setup.py files as well to communicate +# this information to our users. ConfigArgParse = "0.10.0" apacheconfig = "0.3.2" asn1crypto = "0.24.0" -boto3 = "1.4.7" -botocore = "1.7.41" +boto3 = "1.15.15" +botocore = "1.18.15" cffi = "1.9.1" -chardet = "2.2.1" +chardet = "3.0.4" cloudflare = "1.5.1" configobj = "5.0.6" cryptography = "3.2.1" @@ -79,14 +72,14 @@ pyOpenSSL = "17.3.0" pyRFC3339 = "1.0" pyasn1 = "0.1.9" pycparser = "2.14" -pyparsing = "2.2.0" +pyparsing = "2.2.1" python-augeas = "0.5.0" python-digitalocean = "1.11" -pytz = "2012rc0" -requests = "2.14.2" -setuptools = "39.0.1" +pytz = "2019.3" +requests = "2.20.0" +setuptools = "41.6.0" six = "1.11.0" -urllib3 = "1.10.2" +urllib3 = "1.24.2" # Package names containing "." need to be quoted. "zope.component" = "4.1.0" "zope.event" = "4.0.3" @@ -111,6 +104,12 @@ 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" + [tool.poetry.dev-dependencies] [build-system] diff --git a/tools/requirements.txt b/tools/requirements.txt index c8f3076ff..d57f3a600 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -5,198 +5,192 @@ # requirements.txt so that is scanned by GitHub. See # https://docs.github.com/en/github/visualizing-repository-data-with-graphs/about-the-dependency-graph#supported-package-ecosystems # for more info. -alabaster==0.7.12; python_version >= "3.6" -apacheconfig==0.3.2; python_version >= "3.6" -appdirs==1.4.4; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0" -appnope==0.1.2; python_version == "3.6" and sys_platform == "darwin" or python_version >= "3.7" and sys_platform == "darwin" -astroid==2.9.0; python_version >= "3.6" and python_version < "4.0" -atomicwrites==1.4.0; python_version >= "3.6" and python_full_version < "3.0.0" and sys_platform == "win32" or sys_platform == "win32" and python_version >= "3.6" and python_full_version >= "3.4.0" -attrs==21.4.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" -awscli==1.22.52; python_version >= "3.6" -azure-devops==6.0.0b4; python_version >= "3.6" -babel==2.9.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" -backcall==0.2.0; python_version == "3.6" or python_version >= "3.7" -bcrypt==3.2.0; python_version >= "3.6" -beautifulsoup4==4.10.0; python_full_version > "3.0.0" and python_version >= "3.6" or python_version >= "3.6" and python_version < "4.0" and python_full_version > "3.0.0" -bleach==4.1.0; python_version >= "3.6" -boto3==1.20.52; python_version >= "3.6" -botocore==1.23.52; python_version >= "3.6" -cachecontrol==0.12.10; python_version >= "3.6" and python_version < "4.0" -cached-property==1.5.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" -cachetools==4.2.4; python_version >= "3.5" and python_version < "4.0" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6") -cachy==0.3.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0" -certifi==2021.10.8; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" or python_version >= "3.6" -cffi==1.15.0; python_version >= "3.6" or python_version >= "3.6" -charset-normalizer==2.0.11; python_full_version >= "3.6.0" and python_version >= "3.6" -cleo==1.0.0a4; python_version >= "3.6" and python_version < "4.0" -cloudflare==2.8.15; python_version >= "3.6" -colorama==0.4.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" or python_version >= "3.6" and python_full_version < "3.0.0" and sys_platform == "win32" or python_full_version >= "3.5.0" and python_version >= "3.6" and sys_platform == "win32" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" and sys_platform == "win32" or python_version >= "3.6" and python_version < "4.0" and sys_platform == "win32" and python_full_version >= "3.5.0" or python_version >= "3.6" and python_full_version < "3.0.0" and platform_system == "Windows" or python_version >= "3.6" and python_full_version >= "3.5.0" and platform_system == "Windows" or python_version == "3.6" and python_full_version < "3.0.0" and sys_platform == "win32" or python_version == "3.6" and sys_platform == "win32" and python_full_version >= "3.5.0" or python_version >= "3.7" and python_full_version < "3.0.0" and sys_platform == "win32" or python_version >= "3.7" and sys_platform == "win32" and python_full_version >= "3.5.0" -configargparse==1.5.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" -configobj==5.0.6; python_version >= "3.6" -coverage==6.2; python_version >= "3.6" or python_version >= "3.6" -crashtest==0.3.1; python_version >= "3.6" and python_version < "4.0" -cryptography==36.0.1; python_version >= "3.6" and python_version < "4.0" or python_version >= "3.6" or python_version >= "3.6" and python_version < "4.0" and sys_platform == "linux" -cython==0.29.27; (python_version >= "2.6" and python_full_version < "3.0.0") or (python_full_version >= "3.3.0") -dataclasses==0.8; python_version >= "3.6" and python_version < "3.7" -decorator==5.1.1; python_version == "3.6" or python_version > "3.6" or python_version >= "3.5" or python_version >= "3.7" -deprecated==1.2.13; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" -distlib==0.3.4; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0" or python_version >= "3.6" -distro==1.6.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" or python_version >= "3.6" -dns-lexicon==3.8.5; python_version >= "3.6" and python_version < "4.0" -dnspython==2.2.0; python_version >= "3.6" and python_version < "4.0" -docker-compose==1.26.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" -docker==4.2.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" -dockerpty==0.4.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" -docopt==0.6.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" -docutils==0.15.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6" or python_version >= "3.6" and python_full_version >= "3.4.0" -entrypoints==0.3; python_version >= "3.6" and python_version < "4.0" -execnet==1.9.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" -fabric==2.6.0; python_version >= "3.6" -filelock==3.4.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0" or python_version >= "3.6" and python_version < "4.0" -google-api-core==2.5.0; python_version >= "3.6" -google-api-python-client==2.37.0; python_version >= "3.6" -google-auth-httplib2==0.1.0; python_version >= "3.6" -google-auth==2.6.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" -googleapis-common-protos==1.54.0; python_version >= "3.6" -html5lib==1.1; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.5.0" -httplib2==0.20.4; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" -idna==3.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" or python_version >= "3.6" and python_version < "4.0" -imagesize==1.3.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" -importlib-metadata==1.7.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.8" or python_version >= "3.6" and python_version < "3.8" and python_full_version >= "3.5.0" -importlib-resources==5.4.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.7" or python_version >= "3.6" and python_version < "3.7" and python_full_version >= "3.4.0" -iniconfig==1.1.1; python_version >= "3.6" -invoke==1.6.0; python_version >= "3.6" -ipdb==0.13.9; python_version >= "3.6" -ipython-genutils==0.2.0 -ipython==7.16.3; python_version == "3.6" -ipython==7.31.1; python_version >= "3.7" -isodate==0.6.1; python_version >= "3.6" -isort==5.8.0; python_version >= "3.6" and python_version < "4.0" -jedi==0.17.2; python_version == "3.6" and python_full_version < "3.0.0" or python_version == "3.6" and python_full_version >= "3.5.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" -jeepney==0.7.1; python_version >= "3.6" and python_version < "4.0" and sys_platform == "linux" -jinja2==3.0.3; python_version >= "3.6" or python_version >= "3.6" -jmespath==0.10.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6" -josepy==1.12.0; python_version >= "3.6" -jsonlines==3.0.0; python_version >= "3.6" -jsonpickle==2.1.0; python_version >= "3.6" -jsonschema==3.2.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" -keyring==22.3.0; python_version >= "3.6" and python_version < "4.0" or python_version >= "3.6" -lazy-object-proxy==1.7.1; python_version >= "3.6" and python_version < "4.0" +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" +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" +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" +configobj==5.0.6; python_version >= "3.7" +coverage==6.3.2; python_version >= "3.7" or 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") +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" +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" +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" +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" +iniconfig==1.1.1; python_version >= "3.7" +invoke==1.6.0; python_version >= "3.7" +ipdb==0.13.9; python_version >= "3.7" +ipython==7.32.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" +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" +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" +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" lockfile==0.12.2 -markupsafe==2.0.1; python_version >= "3.6" +markupsafe==2.1.1; python_version >= "3.7" matplotlib-inline==0.1.3; python_version >= "3.7" -mccabe==0.6.1; python_version >= "3.6" and python_version < "4.0" +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.6" and python_version < "4.0" -msrest==0.6.21; python_version >= "3.6" -mypy-extensions==0.4.3; python_version >= "3.6" -mypy==0.931; python_version >= "3.6" -oauth2client==4.1.3; python_version >= "3.6" -oauthlib==3.2.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" -packaging==20.9; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0" or python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" or python_version >= "3.6" and python_full_version >= "3.5.0" -paramiko==2.9.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" or python_version >= "3.6" -parsedatetime==2.6; python_version >= "3.6" -parso==0.7.1; python_version == "3.6" and python_full_version < "3.0.0" or python_version == "3.6" and python_full_version >= "3.5.0" -pathlib2==2.3.7.post1; python_version >= "3.6" -pexpect==4.8.0; python_version >= "3.6" and python_version < "4.0" or python_version == "3.6" and sys_platform != "win32" or python_version >= "3.7" and sys_platform != "win32" -pickleshare==0.7.5; python_version == "3.6" or python_version >= "3.7" -pip==21.3.1; python_version >= "3.6" -pkginfo==1.8.2; python_version >= "3.6" and python_version < "4.0" or python_version >= "3.6" -platformdirs==2.4.0; python_version >= "3.6" and python_version < "4.0" -pluggy==1.0.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" or python_version >= "3.6" -ply==3.11; python_version >= "3.6" -poetry-core==1.1.0a6; python_version >= "3.6" and python_version < "4.0" +msgpack==1.0.3; 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" +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" +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" +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.3; python_version == "3.6" or python_version >= "3.7" -protobuf==3.19.4; python_version >= "3.6" -ptyprocess==0.7.0; python_version >= "3.6" and python_version < "4.0" -py==1.11.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" -pyasn1-modules==0.2.8; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" or python_version >= "3.6" -pyasn1==0.4.8; python_version >= "3.6" and python_version < "4" or python_version >= "3.6" -pycparser==2.21; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" -pygithub==1.55; python_version >= "3.6" -pygments==2.11.2; python_version >= "3.6" or python_version == "3.6" or python_version >= "3.7" -pyjwt==2.3.0; python_version >= "3.6" -pylev==1.4.0; python_version >= "3.6" and python_version < "4.0" -pylint==2.12.0; python_version >= "3.6" and python_version < "4.0" -pynacl==1.5.0; python_version >= "3.6" or python_version >= "3.6" -pynsist==2.7; python_version >= "3.6" -pyopenssl==22.0.0; python_version >= "3.6" -pyparsing==3.0.7; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" or python_version >= "3.6" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" 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.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6") -pyrfc3339==1.1; python_version >= "3.6" -pyrsistent==0.18.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" -pytest-cov==3.0.0; python_version >= "3.6" or python_version >= "3.6" -pytest-forked==1.4.0; python_version >= "3.6" -pytest-xdist==2.5.0; python_version >= "3.6" or python_version >= "3.6" -pytest==7.0.0; python_version >= "3.6" or python_version >= "3.6" -python-augeas==1.1.0; python_version >= "3.6" -python-dateutil==2.8.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" and python_version >= "3.6" -python-digitalocean==1.17.0; python_version >= "3.6" -python-dotenv==0.19.2; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" -pytz==2021.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" or python_version >= "3.6" -pywin32-ctypes==0.2.0; python_version >= "3.6" and python_version < "4.0" and sys_platform == "win32" -pywin32==303; sys_platform == "win32" and python_version >= "3.6" or sys_platform == "win32" and python_version >= "3.6" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6") -pyyaml==5.4.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.6.0" -readme-renderer==32.0; python_version >= "3.6" -requests-download==0.1.2; python_version >= "3.6" -requests-file==1.5.1; python_version >= "3.6" and python_version < "4.0" -requests-oauthlib==1.3.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" -requests-toolbelt==0.9.1; python_version >= "3.6" and python_version < "4.0" or python_version >= "3.6" or python_version >= "3.6" -requests==2.27.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.6.0" -rfc3986==1.5.0; python_version >= "3.6" -rsa==4.7.2; python_version >= "3.6" and python_version < "4" or python_version >= "3.5" and python_version < "4" and (python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version >= "3.6") -s3transfer==0.5.1; python_version >= "3.6" -secretstorage==3.3.1; python_version >= "3.6" and python_version < "4.0" and sys_platform == "linux" +prompt-toolkit==3.0.28; python_version >= "3.7" and python_full_version >= "3.6.2" +protobuf==3.19.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" +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" +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") +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" +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" +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-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" +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" +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" +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==59.6.0; python_version >= "3.6" or python_version >= "3.6" or python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" or python_full_version >= "3.4.0" and python_version >= "3.6" or python_version == "3.6" or python_version >= "3.7" or python_version >= "3.6" and python_version < "4.0" -shellingham==1.4.0; python_version >= "3.6" and python_version < "4.0" -six==1.16.0; python_version >= "2.7" and python_full_version < "3.0.0" or python_full_version >= "3.3.0" or python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" or python_full_version >= "3.3.0" and python_version >= "3.6" or python_version >= "3.6" and python_full_version >= "3.5.0" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.5.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0" or python_full_version >= "3.6.0" and python_version >= "3.6" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.3.0" or python_version == "3.6" and python_full_version < "3.0.0" or python_version == "3.6" and python_full_version >= "3.3.0" -snowballstemmer==2.2.0; python_version >= "3.6" -soupsieve==2.3.1; python_full_version > "3.0.0" and python_version >= "3.6" -sphinx-rtd-theme==1.0.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" -sphinx==4.3.2; python_version >= "3.6" or python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" -sphinxcontrib-applehelp==1.0.2; python_version >= "3.6" -sphinxcontrib-devhelp==1.0.2; python_version >= "3.6" -sphinxcontrib-htmlhelp==2.0.0; python_version >= "3.6" -sphinxcontrib-jsmath==1.0.1; python_version >= "3.6" -sphinxcontrib-qthelp==1.0.3; python_version >= "3.6" -sphinxcontrib-serializinghtml==1.1.5; python_version >= "3.6" -texttable==1.6.4; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" -tldextract==3.1.2; python_version >= "3.6" and python_version < "4.0" -toml==0.10.2; python_version == "3.6" and python_full_version < "3.0.0" or python_version > "3.6" and python_full_version < "3.0.0" or python_version == "3.6" and python_full_version >= "3.3.0" or python_version > "3.6" and python_full_version >= "3.3.0" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.3.0" or python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" -tomli==1.2.3; python_version >= "3.6" or python_version >= "3.6" -tomlkit==0.9.2; python_version >= "3.6" and python_version < "4.0" -tox==3.24.5; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" -tqdm==4.62.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.4.0" -traitlets==4.3.3 -twine==3.3.0; python_version >= "3.6" -typed-ast==1.5.2; python_version >= "3.6" and python_version < "3.8" or implementation_name == "cpython" and python_version < "3.8" and python_version >= "3.6" -types-cryptography==3.3.15; python_version >= "3.6" -types-enum34==1.1.8; python_version >= "3.6" -types-ipaddress==1.0.8; python_version >= "3.6" -types-mock==4.0.10; python_version >= "3.6" -types-pyopenssl==22.0.0; python_version >= "3.6" -types-pyrfc3339==1.1.1; python_version >= "3.6" -types-python-dateutil==2.8.9; python_version >= "3.6" -types-pytz==2021.3.4; python_version >= "3.6" -types-requests==2.27.9; python_version >= "3.6" -types-setuptools==57.4.9; python_version >= "3.6" -types-six==1.16.10; python_version >= "3.6" -types-urllib3==1.26.9; python_version >= "3.6" -typing-extensions==4.0.1; python_version >= "3.6" or python_version >= "3.6" or python_version >= "3.6" and python_version < "3.10" or python_version < "3.8" and python_version >= "3.6" -uritemplate==4.1.1; python_version >= "3.6" -urllib3==1.26.8; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.6.0" and python_version < "4" and python_version >= "3.6" or python_full_version >= "3.5.0" and python_version < "4" and python_version >= "3.6" -virtualenv==20.4.4; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.4.0" or python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" -wcwidth==0.2.5; python_version == "3.6" -webencodings==0.5.1; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.5.0" or python_version >= "3.6" -websocket-client==0.59.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.4.0" and python_version >= "3.6" or python_full_version >= "3.5.0" and python_version >= "3.6" -wheel==0.37.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" -wrapt==1.13.3; python_version >= "3.6" and python_full_version < "3.0.0" or python_version >= "3.6" and python_full_version >= "3.5.0" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "4.0" or python_version >= "3.6" and python_version < "4.0" and python_full_version >= "3.5.0" -yarg==0.1.9; python_version >= "3.6" -zipp==3.6.0; python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.8" or python_version >= "3.6" and python_version < "3.8" and python_full_version >= "3.5.0" or python_version >= "3.6" and python_full_version < "3.0.0" and python_version < "3.7" or python_version >= "3.6" and python_version < "3.7" and python_full_version >= "3.4.0" -zope.component==5.0.1; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" -zope.event==4.5.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" -zope.hookable==5.1.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and python_version >= "3.6" -zope.interface==5.4.0; python_version >= "3.6" and python_full_version < "3.0.0" or python_full_version >= "3.5.0" and 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" +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" +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" +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" +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" +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" +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" +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" diff --git a/tools/snap/generate_dnsplugins_snapcraft.sh b/tools/snap/generate_dnsplugins_snapcraft.sh index 139c8b0d3..efa647366 100755 --- a/tools/snap/generate_dnsplugins_snapcraft.sh +++ b/tools/snap/generate_dnsplugins_snapcraft.sh @@ -27,6 +27,10 @@ parts: snapcraftctl pull snapcraftctl set-version \`grep ^version \$SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"\` build-environment: + # We set this environment variable while building to try and increase the + # stability of fetching the rust crates needed to build the cryptography + # library. + - CARGO_NET_GIT_FETCH_WITH_CLI: "true" # Constraints are passed through the environment variable PIP_CONSTRAINTS instead of using the # parts.[part_name].constraints option available in snapcraft.yaml when the Python plugin is # used. This is done to let these constraints be applied not only on the certbot package diff --git a/tools/venv.py b/tools/venv.py index bd1250eed..2aa5b0a2d 100755 --- a/tools/venv.py +++ b/tools/venv.py @@ -69,7 +69,7 @@ def find_python_executable() -> str: * Windows Python launcher 'py' executable in PATH if available Incompatible python versions for Certbot will be evicted (e.g. Python 3 - versions less than 3.6). + versions less than 3.7). :rtype: str :return: the relevant python executable path @@ -118,7 +118,7 @@ def _check_version(version_str): version = (int(search.group(1)), int(search.group(2))) - if version >= (3, 6): + if version >= (3, 7): return True print('Incompatible python version for Certbot found: {0}'.format(version_str)) diff --git a/tox.ini b/tox.ini index 25396d3dd..8965b6055 100644 --- a/tox.ini +++ b/tox.ini @@ -26,8 +26,8 @@ source_paths = acme/acme certbot/certbot certbot-apache/certbot_apache certbot-c passenv = CERTBOT_NO_PIN platform = - win: win32 - posix: ^(?!.*win32).*$ + win: win64 + posix: ^(?!.*win64).*$ commands_pre = python {toxinidir}/tools/pipstrap.py commands = !cover-win: {[base]install_and_test} {[base]win_all_packages} @@ -51,7 +51,7 @@ setenv = # # This version should be kept in sync with the one declared in # tools/pinning/oldest/pyproject.toml. -basepython = python3.6 +basepython = python3.7 commands = {[testenv]commands} setenv = diff --git a/windows-installer/setup.py b/windows-installer/setup.py index 3d16a49f8..3729052a0 100644 --- a/windows-installer/setup.py +++ b/windows-installer/setup.py @@ -11,14 +11,13 @@ setup( author="Certbot Project", author_email='certbot-dev@eff.org', license='Apache License 2.0', - python_requires='>=3.6', + python_requires='>=3.7', classifiers=[ 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'License :: OSI Approved :: Apache Software License', 'Programming Language :: Python', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', diff --git a/windows-installer/windows_installer/construct.py b/windows-installer/windows_installer/construct.py index e9036f08c..85af4ca94 100644 --- a/windows-installer/windows_installer/construct.py +++ b/windows-installer/windows_installer/construct.py @@ -8,7 +8,7 @@ import sys import time PYTHON_VERSION = (3, 9, 7) -PYTHON_BITNESS = 32 +PYTHON_BITNESS = 64 NSIS_VERSION = '3.06.1' @@ -94,7 +94,7 @@ def _generate_pynsist_config(repo_path, build_path): certbot_version = subprocess.check_output([sys.executable, '-c', 'import certbot; print(certbot.__version__)'], universal_newlines=True, cwd=certbot_pkg_path).strip() - # If we change the installer name from `certbot-beta-installer-win32.exe`, it should + # If we change the installer name from `certbot-beta-installer-win_amd64.exe`, it should # also be changed in tools/create_github_release.py with open(installer_cfg_path, 'w') as file_h: file_h.write('''\