Compare commits

...

35 Commits

Author SHA1 Message Date
Brad Warren
c4265bd3b2 wait longer? 2024-02-07 12:00:21 -08:00
Brad Warren
226f044a6b boulder only 2024-02-07 11:18:53 -08:00
Brad Warren
be4d9b538f what if we just use the default? 2024-02-07 11:17:47 -08:00
Simon Stier
282df74ee9 add 3rd party certbot-dns-stackit to the docs (#9885) 2024-02-02 08:38:55 -08:00
Alexis
0a565815f9 Docs: Reset requirements.txt path (#9877)
* Reset requirements.txt path

* Add requirements.txt path

* Test config path

* Change docs path

* Amend paths for successful builds

* Place copyright for epub

- Will amend copyright parameter at a later date
2024-02-01 08:27:45 -08:00
ohemorange
d33bbf35c2 Make reconfigure use staging server (#9870)
* Make reconfigure use staging server

* lint and imports

* Unset the account if it's been set in preparation for a dry run

* Add unit tests for checking we switch to staging and don't accidentally modify anything else

* add docstring

* Add test to make sure a requested new account id is saved

* update changelog

* set noninteractive mode for dry run

* error when account or server is set by the user

* switch to checking for changed values in account and server

* recommend using renew instead of certonly for forbidden fields

* change link to renew-reconfiguration
2024-01-26 12:09:20 -08:00
Brad Warren
714a0b348d offer poetry verbosity (#9881) 2024-01-24 16:15:26 -08:00
Alexis
7ca1b8f286 Merge pull request #9876 from certbot/zoraconpatch-yaml-error
Fix YAML Errors in "Formats" section
2024-01-18 10:45:09 -08:00
zoracon
be40e377d9 Move YAML file back and amend paths 2024-01-17 14:51:37 -08:00
zoracon
01cf4bae75 Amend YAML error on reeadthedocs yaml files 2024-01-17 14:46:12 -08:00
Will Greenberg
ef949f9149 Merge pull request #9858 from certbot/zoracon-patch-readthedocs-test
Move .readthedocs.yaml
2024-01-16 14:03:25 -08:00
ohemorange
926d0c7e0f Fix mypy joinpath errors (#9871)
* Fix mypy joinpath errors

* update changelog
2024-01-05 16:35:37 -08:00
Brad Warren
9d8eb6ccfd Add Python 3.12 support (#9852)
* add py312 support

* sed -i "s/\( *'Pro.*3\.1\)1\(',\)/\11\2\n\12\2/" */setup.py

* update pytest.ini comment

* upgrade macos version

* fixup changelog
2023-12-13 10:02:38 -08:00
Alexis
585f70e700 Create .readthedocs.yaml
Test moving config file in attempt to solve build errors
2023-12-07 18:52:05 -08:00
Alexis
21e24264f4 Bump Hardcoded RSA Default in API (#9855)
Rectifies: https://github.com/certbot/certbot/security/advisories/GHSA-pcq2-mjvr-m4jj
2023-12-06 13:00:55 -08:00
Brad Warren
cf78ad3a3d Merge pull request #9853 from certbot/candidate-2.8.0
Candidate 2.8.0
2023-12-05 16:48:55 -08:00
Will Greenberg
dccb92d57f Bump version to 2.9.0 2023-12-05 11:14:39 -08:00
Will Greenberg
f9d31faadc Add contents to certbot/CHANGELOG.md for next version 2023-12-05 11:14:39 -08:00
Will Greenberg
e9225d1cc2 Release 2.8.0 2023-12-05 11:14:38 -08:00
Will Greenberg
3dd1f0eea9 Update changelog for 2.8.0 release 2023-12-05 11:13:52 -08:00
Brad Warren
917e3aba6b add pkg_resources changelog (#9851) 2023-12-05 10:33:49 -08:00
Brad Warren
3833255980 update dependencies (#9848) 2023-12-05 10:33:31 -08:00
Francesco Colista
619654f317 Add support for Alpine Linux (#9834)
Signed-off-by: Francesco Colista <fcolista@alpinelinux.org>
2023-11-22 13:53:31 +01:00
Brad Warren
76f9a33e45 Upgrade the pinned version of pylint (#9839)
* upgrade pylint

* fix upgraded pylint

* downgrade pyopenssl

* remove unneeded ignores

* stop using text

* update sphinx-rtd-theme
2023-11-15 09:52:37 +01:00
Adrien Ferrand
5f67bb99a8 Full cleanup of pkg_resources (#9797)
Fixes #9606

This PRs removes some elements that were related to pkg_resources dependency and its deprecation.
2023-11-13 15:50:32 -08:00
Will Greenberg
d8392bf394 Merge pull request #9832 from certbot/candidate-2.7.4
Update master from 2.7.4 release
2023-11-01 11:36:29 -07:00
Brad Warren
6a89fcbc56 Merge branch 'master' into candidate-2.7.4 2023-11-01 07:50:54 -07:00
Brad Warren
2adaacab82 Bump version to 2.8.0 2023-11-01 06:24:20 -07:00
Brad Warren
2ae810c45a Add contents to certbot/CHANGELOG.md for next version 2023-11-01 06:24:19 -07:00
Brad Warren
b62133e3e1 Release 2.7.4 2023-11-01 06:24:18 -07:00
Brad Warren
a92bb44ff9 Update changelog for 2.7.4 release 2023-11-01 06:23:12 -07:00
Brad Warren
9650c25968 Fix change detection on mutable values (#9829) (#9830)
* handle mutable values

* add unit test

* add changelog entry

* fix typo

(cherry picked from commit c3c29afdca)
2023-11-01 00:10:11 +00:00
Brad Warren
c3c29afdca Fix change detection on mutable values (#9829)
* handle mutable values

* add unit test

* add changelog entry

* fix typo
2023-10-31 16:28:16 -07:00
Brad Warren
dca4ddd3d8 Prep for 2.7.4 (#9823)
* Set the delegated field in Lexicon config to bypass subdomain resolution (#9821)

The Lexicon-based DNS plugins use a mechanism to determine which actual segment of the input domain is actually the DNS zone in which the DNS-01 challenge has to be initiated (eg. `subdomain.domain.com` or `domain.com` for input `subdomain.domain.com`): they tries recursively to configure Lexicon and initiate authentication from the most specific to most generic domain segment, and select the first segment where Lexicon stop erroring out.

This mechanism broke with #9746 because now the plugins call Lexicon client instead of the underlying providers, and the client makes guess on the actual domain requested. Typically for `subdomain.domain.com` it will actually try to authenticate against `domain.com`, and so the mechanism above does not work anymore.

This PR fixes the issue by using the `delegated` field in Lexicon config each time the plugin needs it. This field is designed for this kind of purpose: it will instruct Lexicon what is the actual DNS zone domain instead of guessing it.

I tested the change with one of my OVH account. The expected behavior is re-established and the plugin is able to test `subdomain.domain.com` then `domain.com` as before.

Fixes #9791
Fixes #9818

(cherry picked from commit cf4f07d17e)

* add changelog entry for 9821 (#9822)

(cherry picked from commit 7bb85f8440)

---------

Co-authored-by: Adrien Ferrand <adferrand@users.noreply.github.com>
2023-10-30 10:34:30 -07:00
Will Greenberg
bf5475fa74 Merge pull request #9820 from certbot/2.7.3-update
Update 2.7.x from 2.7.3 release
2023-10-26 14:00:37 -07:00
83 changed files with 504 additions and 292 deletions

View File

@@ -4,18 +4,10 @@ jobs:
- name: IMAGE_NAME
value: ubuntu-22.04
- name: PYTHON_VERSION
value: 3.11
value: 3.12
- group: certbot-common
strategy:
matrix:
linux-py39:
PYTHON_VERSION: 3.9
TOXENV: py39
linux-py310:
PYTHON_VERSION: 3.10
TOXENV: py310
linux-isolated:
TOXENV: 'isolated-{acme,certbot,apache,cloudflare,digitalocean,dnsimple,dnsmadeeasy,gehirn,google,linode,luadns,nsone,ovh,rfc2136,route53,sakuracloud,nginx}'
linux-boulder-v2-integration-certbot-oldest:
PYTHON_VERSION: 3.8
TOXENV: integration-certbot-oldest
@@ -40,18 +32,10 @@ jobs:
PYTHON_VERSION: 3.11
TOXENV: integration
ACME_SERVER: boulder-v2
nginx-compat:
TOXENV: nginx_compat
linux-integration-rfc2136:
IMAGE_NAME: ubuntu-22.04
PYTHON_VERSION: 3.8
TOXENV: integration-dns-rfc2136
le-modification:
IMAGE_NAME: ubuntu-22.04
TOXENV: modification
farmtest-apache2:
PYTHON_VERSION: 3.8
TOXENV: test-farm-apache2
linux-boulder-v2-py312-integration:
PYTHON_VERSION: 3.12
TOXENV: integration
ACME_SERVER: boulder-v2
pool:
vmImage: $(IMAGE_NAME)
steps:

View File

@@ -1,7 +1,7 @@
jobs:
- job: test
variables:
PYTHON_VERSION: 3.11
PYTHON_VERSION: 3.12
strategy:
matrix:
macos-py38-cover:
@@ -12,7 +12,7 @@ jobs:
# See https://github.com/certbot/certbot/pull/9717#issuecomment-1610861794.
PIP_USE_PEP517: "true"
macos-cover:
IMAGE_NAME: macOS-12
IMAGE_NAME: macOS-13
TOXENV: cover
# See explanation under macos-py38-cover.
PIP_USE_PEP517: "true"

View File

@@ -1,6 +1,4 @@
stages:
- stage: TestAndPackage
jobs:
- template: ../jobs/standard-tests-jobs.yml
- template: ../jobs/extended-tests-jobs.yml
- template: ../jobs/packaging-jobs.yml

View File

@@ -69,7 +69,7 @@ ignored-modules=
# CERTBOT COMMENT
# This is needed for pylint to import linter_plugin.py since
# https://github.com/PyCQA/pylint/pull/3396.
init-hook="import pylint.config, os, sys; sys.path.append(os.path.dirname(pylint.config.PYLINTRC))"
init-hook="import pylint.config, os, sys; sys.path.append(os.path.dirname(next(pylint.config.find_default_config_files())))"
# Use multiple processes to speed up Pylint. Specifying 0 will auto-detect the
# number of processors available to use, and will cap the count on Windows to
@@ -266,8 +266,8 @@ valid-metaclass-classmethod-first-arg=cls
[EXCEPTIONS]
# Exceptions that will emit a warning when caught.
overgeneral-exceptions=BaseException,
Exception
overgeneral-exceptions=builtins.BaseException,
builtins.Exception
[FORMAT]
@@ -524,7 +524,7 @@ ignored-classes=optparse.Values,thread._local,_thread._local,argparse.Namespace,
# List of module names for which member attributes should not be checked
# (useful for modules/projects where namespaces are manipulated during runtime
# and thus existing member attributes cannot be deduced by static analysis
ignored-modules=pkg_resources,confargparse,argparse
ignored-modules=confargparse,argparse
# Show a hint with possible names when a member name was not found. The aspect
# of finding the hint is based on edit distance.

View File

@@ -94,6 +94,7 @@ Authors
* [Felix Yan](https://github.com/felixonmars)
* [Filip Ochnik](https://github.com/filipochnik)
* [Florian Klink](https://github.com/flokli)
* [Francesco Colista](https://github.com/fcolista)
* [Francois Marier](https://github.com/fmarier)
* [Frank](https://github.com/Frankkkkk)
* [Frederic BLANC](https://github.com/fblanc)

View File

@@ -14,14 +14,14 @@ build:
# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/conf.py
configuration: acme/docs/conf.py
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
# builder: "dirhtml"
# Fail on all warnings to avoid broken references
fail_on_warning: true
# Optionally build your docs in additional formats such as PDF and ePub
# formats:
formats:
- pdf
- epub
@@ -30,4 +30,4 @@ sphinx:
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: ../tools/requirements.txt
- requirements: acme/readthedocs.org.requirements.txt

View File

@@ -12,7 +12,6 @@ from typing import List
from typing import Mapping
from typing import Optional
from typing import Set
from typing import Text
from typing import Tuple
from typing import Union
@@ -517,7 +516,7 @@ class ClientNetwork:
self.account = account
self.alg = alg
self.verify_ssl = verify_ssl
self._nonces: Set[Text] = set()
self._nonces: Set[str] = set()
self.user_agent = user_agent
self.session = requests.Session()
self._default_timeout = timeout

View File

@@ -29,7 +29,7 @@ class Header(jose.Header):
class Signature(jose.Signature):
"""ACME-specific Signature. Uses ACME-specific Header for customer fields."""
__slots__ = jose.Signature._orig_slots # type: ignore[attr-defined] # pylint: disable=protected-access,no-member
__slots__ = jose.Signature._orig_slots # pylint: disable=protected-access,no-member
# TODO: decoder/encoder should accept cls? Otherwise, subclassing
# JSONObjectWithFields is tricky...
@@ -44,7 +44,7 @@ class Signature(jose.Signature):
class JWS(jose.JWS):
"""ACME-specific JWS. Includes none, url, and kid in protected header."""
signature_cls = Signature
__slots__ = jose.JWS._orig_slots # type: ignore[attr-defined] # pylint: disable=protected-access
__slots__ = jose.JWS._orig_slots # pylint: disable=protected-access
@classmethod
# type: ignore[override] # pylint: disable=arguments-differ

View File

@@ -3,6 +3,6 @@ usage: jws [-h] [--compact] {sign,verify} ...
positional arguments:
{sign,verify}
optional arguments:
options:
-h, --help show this help message and exit
--compact

View File

@@ -3,7 +3,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.8.0.dev0'
version = '2.9.0.dev0'
install_requires = [
'cryptography>=3.2.1',
@@ -55,6 +55,7 @@ setup(
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
],

View File

@@ -257,6 +257,6 @@ def find_ssl_apache_conf(prefix: str) -> str:
"""
file_manager = ExitStack()
atexit.register(file_manager.close)
ref = importlib_resources.files("certbot_apache").joinpath(
"_internal", "tls_configs", "{0}-options-ssl-apache.conf".format(prefix))
ref = (importlib_resources.files("certbot_apache").joinpath("_internal")
.joinpath("tls_configs").joinpath("{0}-options-ssl-apache.conf".format(prefix)))
return str(file_manager.enter_context(importlib_resources.as_file(ref)))

View File

@@ -4,6 +4,7 @@ from typing import Type
from certbot import util
from certbot_apache._internal import configurator
from certbot_apache._internal import override_alpine
from certbot_apache._internal import override_arch
from certbot_apache._internal import override_centos
from certbot_apache._internal import override_darwin
@@ -14,6 +15,7 @@ from certbot_apache._internal import override_suse
from certbot_apache._internal import override_void
OVERRIDE_CLASSES: Dict[str, Type[configurator.ApacheConfigurator]] = {
"alpine": override_alpine.AlpineConfigurator,
"arch": override_arch.ArchConfigurator,
"cloudlinux": override_centos.CentOSConfigurator,
"darwin": override_darwin.DarwinConfigurator,

View File

@@ -0,0 +1,19 @@
""" Distribution specific override class for Alpine Linux """
from certbot_apache._internal import configurator
from certbot_apache._internal.configurator import OsOptions
class AlpineConfigurator(configurator.ApacheConfigurator):
"""Alpine Linux specific ApacheConfigurator override class"""
OS_DEFAULTS = OsOptions(
server_root="/etc/apache2",
vhost_root="/etc/apache2/conf.d",
vhost_files="*.conf",
logs_root="/var/log/apache2",
ctl="apachectl",
version_cmd=['apachectl', '-v'],
restart_cmd=['apachectl', 'graceful'],
conftest_cmd=['apachectl', 'configtest'],
challenge_location="/etc/apache2/conf.d",
)

View File

@@ -1,7 +1,7 @@
from setuptools import find_packages
from setuptools import setup
version = '2.8.0.dev0'
version = '2.9.0.dev0'
install_requires = [
# We specify the minimum acme and certbot version as the current plugin
@@ -43,6 +43,7 @@ setup(
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -32,13 +32,15 @@ def construct_nginx_config(nginx_root: str, nginx_webroot: str, http_port: int,
if not key_path:
file_manager = ExitStack()
atexit.register(file_manager.close)
ref = importlib_resources.files('certbot_integration_tests').joinpath('assets', 'key.pem')
ref = (importlib_resources.files('certbot_integration_tests').joinpath('assets')
.joinpath('key.pem'))
key_path = str(file_manager.enter_context(importlib_resources.as_file(ref)))
if not cert_path:
file_manager = ExitStack()
atexit.register(file_manager.close)
ref = importlib_resources.files('certbot_integration_tests').joinpath('assets', 'cert.pem')
ref = (importlib_resources.files('certbot_integration_tests').joinpath('assets')
.joinpath('cert.pem'))
cert_path = str(file_manager.enter_context(importlib_resources.as_file(ref)))
return '''\

View File

@@ -48,9 +48,8 @@ class IntegrationTestsContext(certbot_context.IntegrationTestsContext):
:yields: Path to credentials file
:rtype: str
"""
src_ref_file = importlib_resources.files('certbot_integration_tests').joinpath(
'assets', 'bind-config', f'rfc2136-credentials-{label}.ini.tpl'
)
src_ref_file = (importlib_resources.files('certbot_integration_tests').joinpath('assets')
.joinpath('bind-config').joinpath(f'rfc2136-credentials-{label}.ini.tpl'))
with importlib_resources.as_file(src_ref_file) as src_file:
with open(src_file, 'r') as f:
contents = f.read().format(

View File

@@ -184,10 +184,6 @@ class ACMEServer:
'--single-branch', '--depth=1', instance_path])
process.wait(MAX_SUBPROCESS_WAIT)
# Allow Boulder to ignore usual limit rate policies, useful for tests.
os.rename(join(instance_path, 'test/rate-limit-policies-b.yml'),
join(instance_path, 'test/rate-limit-policies.yml'))
if self._dns_server:
# Change Boulder config to use the provided DNS server
for suffix in ["", "-remote-a", "-remote-b"]:
@@ -215,7 +211,7 @@ 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)
self.acme_xdist['directory_url'], attempts=600)
if not self._dns_server:
# Configure challtestsrv to answer any A record request with ip of the docker host.

View File

@@ -125,8 +125,8 @@ def generate_test_file_hooks(config_dir: str, hook_probe: str) -> None:
"""
file_manager = contextlib.ExitStack()
atexit.register(file_manager.close)
hook_path_ref = importlib_resources.files('certbot_integration_tests').joinpath(
'assets', 'hook.py')
hook_path_ref = (importlib_resources.files('certbot_integration_tests').joinpath('assets')
.joinpath('hook.py'))
hook_path = str(file_manager.enter_context(importlib_resources.as_file(hook_path_ref)))
for hook_dir in list_renewal_hooks_dirs(config_dir):
@@ -262,9 +262,8 @@ def load_sample_data_path(workspace: str) -> str:
:returns: the path to the loaded sample data directory
:rtype: str
"""
original_ref = importlib_resources.files('certbot_integration_tests').joinpath(
'assets', 'sample-config'
)
original_ref = (importlib_resources.files('certbot_integration_tests').joinpath('assets')
.joinpath('sample-config'))
with importlib_resources.as_file(original_ref) as original:
copied = os.path.join(workspace, 'sample-config')
shutil.copytree(original, copied, symlinks=True)

View File

@@ -45,6 +45,7 @@ setup(
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
],

View File

@@ -75,7 +75,7 @@ def _get_server_root(config: str) -> str:
if os.path.isdir(os.path.join(config, name))]
if len(subdirs) != 1:
errors.Error("Malformed configuration directory {0}".format(config))
raise errors.Error("Malformed configuration directory {0}".format(config))
return os.path.join(config, subdirs[0].rstrip())

View File

@@ -1,7 +1,7 @@
from setuptools import find_packages
from setuptools import setup
version = '2.8.0.dev0'
version = '2.9.0.dev0'
install_requires = [
'certbot',
@@ -29,6 +29,7 @@ setup(
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
],

View File

@@ -14,14 +14,14 @@ build:
# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/conf.py
configuration: certbot-dns-cloudflare/docs/conf.py
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
# builder: "dirhtml"
# Fail on all warnings to avoid broken references
fail_on_warning: true
# Optionally build your docs in additional formats such as PDF and ePub
# formats:
formats:
- pdf
- epub
@@ -30,4 +30,4 @@ sphinx:
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: ../tools/requirements.txt
- requirements: certbot-dns-cloudflare/readthedocs.org.requirements.txt

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.8.0.dev0'
version = '2.9.0.dev0'
install_requires = [
'cloudflare>=1.5.1',
@@ -52,6 +52,7 @@ setup(
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -14,14 +14,14 @@ build:
# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/conf.py
configuration: certbot-dns-digitalocean/docs/conf.py
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
# builder: "dirhtml"
# Fail on all warnings to avoid broken references
fail_on_warning: true
# Optionally build your docs in additional formats such as PDF and ePub
# formats:
formats:
- pdf
- epub
@@ -30,4 +30,4 @@ sphinx:
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: ../tools/requirements.txt
- requirements: certbot-dns-digitalocean/readthedocs.org.requirements.txt

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.8.0.dev0'
version = '2.9.0.dev0'
install_requires = [
'python-digitalocean>=1.11', # 1.15.0 or newer is recommended for TTL support
@@ -52,6 +52,7 @@ setup(
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -14,14 +14,14 @@ build:
# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/conf.py
configuration: certbot-dns-dnsimple/docs/conf.py
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
# builder: "dirhtml"
# Fail on all warnings to avoid broken references
fail_on_warning: true
# Optionally build your docs in additional formats such as PDF and ePub
# formats:
formats:
- pdf
- epub
@@ -30,4 +30,4 @@ sphinx:
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: ../tools/requirements.txt
- requirements: certbot-dns-dnsimple/readthedocs.org.requirements.txt

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.8.0.dev0'
version = '2.9.0.dev0'
install_requires = [
# This version of lexicon is required to address the problem described in
@@ -54,6 +54,7 @@ setup(
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -14,14 +14,14 @@ build:
# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/conf.py
configuration: certbot-dns-dnsmadeeasy/docs/conf.py
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
# builder: "dirhtml"
# Fail on all warnings to avoid broken references
fail_on_warning: true
# Optionally build your docs in additional formats such as PDF and ePub
# formats:
formats:
- pdf
- epub
@@ -30,4 +30,4 @@ sphinx:
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: ../tools/requirements.txt
- requirements: certbot-dns-dnsmadeeasy/readthedocs.org.requirements.txt

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.8.0.dev0'
version = '2.9.0.dev0'
install_requires = [
'dns-lexicon>=3.14.1',
@@ -52,6 +52,7 @@ setup(
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -14,14 +14,14 @@ build:
# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/conf.py
configuration: certbot-dns-gehirn/docs/conf.py
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
# builder: "dirhtml"
# Fail on all warnings to avoid broken references
fail_on_warning: true
# Optionally build your docs in additional formats such as PDF and ePub
# formats:
formats:
- pdf
- epub
@@ -30,4 +30,4 @@ sphinx:
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: ../tools/requirements.txt
- requirements: certbot-dns-gehirn/readthedocs.org.requirements.txt

View File

@@ -1,7 +1,6 @@
"""Tests for certbot_dns_gehirn._internal.dns_gehirn."""
import sys
import unittest
from unittest import mock
import pytest

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.8.0.dev0'
version = '2.9.0.dev0'
install_requires = [
'dns-lexicon>=3.14.1',
@@ -52,6 +52,7 @@ setup(
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -14,14 +14,14 @@ build:
# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/conf.py
configuration: certbot-dns-google/docs/conf.py
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
# builder: "dirhtml"
# Fail on all warnings to avoid broken references
fail_on_warning: true
# Optionally build your docs in additional formats such as PDF and ePub
# formats:
formats:
- pdf
- epub
@@ -30,4 +30,4 @@ sphinx:
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: ../tools/requirements.txt
- requirements: certbot-dns-google/readthedocs.org.requirements.txt

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.8.0.dev0'
version = '2.9.0.dev0'
install_requires = [
'google-api-python-client>=1.6.5',
@@ -53,6 +53,7 @@ setup(
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -14,14 +14,14 @@ build:
# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/conf.py
configuration: certbot-dns-linode/docs/conf.py
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
# builder: "dirhtml"
# Fail on all warnings to avoid broken references
fail_on_warning: true
# Optionally build your docs in additional formats such as PDF and ePub
# formats:
formats:
- pdf
- epub
@@ -30,4 +30,4 @@ sphinx:
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: ../tools/requirements.txt
- requirements: certbot-dns-linode/readthedocs.org.requirements.txt

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.8.0.dev0'
version = '2.9.0.dev0'
install_requires = [
'dns-lexicon>=3.14.1',
@@ -52,6 +52,7 @@ setup(
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -14,14 +14,14 @@ build:
# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/conf.py
configuration: certbot-dns-luadns/docs/conf.py
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
# builder: "dirhtml"
# Fail on all warnings to avoid broken references
fail_on_warning: true
# Optionally build your docs in additional formats such as PDF and ePub
# formats:
formats:
- pdf
- epub
@@ -30,4 +30,4 @@ sphinx:
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: ../tools/requirements.txt
- requirements: certbot-dns-luadns/readthedocs.org.requirements.txt

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.8.0.dev0'
version = '2.9.0.dev0'
install_requires = [
'dns-lexicon>=3.14.1',
@@ -52,6 +52,7 @@ setup(
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -14,14 +14,14 @@ build:
# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/conf.py
configuration: certbot-dns-nsone/docs/conf.py
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
# builder: "dirhtml"
# Fail on all warnings to avoid broken references
fail_on_warning: true
# Optionally build your docs in additional formats such as PDF and ePub
# formats:
formats:
- pdf
- epub
@@ -30,4 +30,4 @@ sphinx:
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: ../tools/requirements.txt
- requirements: certbot-dns-nsone/readthedocs.org.requirements.txt

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.8.0.dev0'
version = '2.9.0.dev0'
install_requires = [
'dns-lexicon>=3.14.1',
@@ -52,6 +52,7 @@ setup(
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -14,14 +14,14 @@ build:
# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/conf.py
configuration: certbot-dns-ovh/docs/conf.py
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
# builder: "dirhtml"
# Fail on all warnings to avoid broken references
fail_on_warning: true
# Optionally build your docs in additional formats such as PDF and ePub
# formats:
formats:
- pdf
- epub
@@ -30,4 +30,4 @@ sphinx:
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: ../tools/requirements.txt
- requirements: certbot-dns-ovh/readthedocs.org.requirements.txt

View File

@@ -22,6 +22,7 @@ class AuthenticatorTest(test_util.TempDirTestCase,
DOMAIN_NOT_FOUND = Exception('Domain example.com not found')
LOGIN_ERROR = HTTPError('403 Client Error: Forbidden for url: https://eu.api.ovh.com/1.0/...', response=Response())
def setUp(self):
super().setUp()

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.8.0.dev0'
version = '2.9.0.dev0'
install_requires = [
'dns-lexicon>=3.15.1',
@@ -52,6 +52,7 @@ setup(
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -14,14 +14,14 @@ build:
# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/conf.py
configuration: certbot-dns-rfc2136/docs/conf.py
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
# builder: "dirhtml"
# Fail on all warnings to avoid broken references
fail_on_warning: true
# Optionally build your docs in additional formats such as PDF and ePub
# formats:
formats:
- pdf
- epub
@@ -30,4 +30,4 @@ sphinx:
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: ../tools/requirements.txt
- requirements: certbot-dns-rfc2136/readthedocs.org.requirements.txt

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.8.0.dev0'
version = '2.9.0.dev0'
install_requires = [
'dnspython>=1.15.0',
@@ -52,6 +52,7 @@ setup(
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -14,14 +14,14 @@ build:
# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/conf.py
configuration: certbot-dns-route53/docs/conf.py
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
# builder: "dirhtml"
# Fail on all warnings to avoid broken references
fail_on_warning: true
# Optionally build your docs in additional formats such as PDF and ePub
# formats:
formats:
- pdf
- epub
@@ -30,4 +30,4 @@ sphinx:
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: ../tools/requirements.txt
- requirements: certbot-dns-route53/readthedocs.org.requirements.txt

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.8.0.dev0'
version = '2.9.0.dev0'
install_requires = [
'boto3>=1.15.15',
@@ -52,6 +52,7 @@ setup(
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -14,14 +14,14 @@ build:
# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/conf.py
configuration: certbot-dns-sakuracloud/docs/conf.py
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
# builder: "dirhtml"
# Fail on all warnings to avoid broken references
fail_on_warning: true
# Optionally build your docs in additional formats such as PDF and ePub
# formats:
formats:
- pdf
- epub
@@ -30,4 +30,4 @@ sphinx:
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: ../tools/requirements.txt
- requirements: certbot-dns-sakuracloud/readthedocs.org.requirements.txt

View File

@@ -4,7 +4,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '2.8.0.dev0'
version = '2.9.0.dev0'
install_requires = [
'dns-lexicon>=3.14.1',
@@ -52,6 +52,7 @@ setup(
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -18,7 +18,6 @@ from typing import Mapping
from typing import Optional
from typing import Sequence
from typing import Set
from typing import Text
from typing import Tuple
from typing import Type
from typing import Union
@@ -172,8 +171,8 @@ class NginxConfigurator(common.Configurator):
file_manager = ExitStack()
atexit.register(file_manager.close)
ref = importlib_resources.files("certbot_nginx").joinpath(
"_internal", "tls_configs", config_filename)
ref = (importlib_resources.files("certbot_nginx").joinpath("_internal")
.joinpath("tls_configs").joinpath(config_filename))
return str(file_manager.enter_context(importlib_resources.as_file(ref)))
@@ -702,7 +701,7 @@ class NginxConfigurator(common.Configurator):
# TODO: generate only once
tmp_dir = os.path.join(self.config.work_dir, "snakeoil")
le_key = crypto_util.generate_key(
key_size=1024, key_dir=tmp_dir, keyname="key.pem",
key_size=2048, key_dir=tmp_dir, keyname="key.pem",
strict_permissions=self.config.strict_permissions)
assert le_key.file is not None
key = OpenSSL.crypto.load_privatekey(
@@ -1275,7 +1274,7 @@ def nginx_restart(nginx_ctl: str, nginx_conf: str, sleep_duration: int) -> None:
"""
try:
reload_output: Text = ""
reload_output: str = ""
with tempfile.TemporaryFile() as out:
proc = subprocess.run([nginx_ctl, "-c", nginx_conf, "-s", "reload"],
env=util.env_no_snap_for_external_calls(),

View File

@@ -1,7 +1,7 @@
from setuptools import find_packages
from setuptools import setup
version = '2.8.0.dev0'
version = '2.9.0.dev0'
install_requires = [
# We specify the minimum acme and certbot version as the current plugin
@@ -41,6 +41,7 @@ setup(
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -14,14 +14,14 @@ build:
# Build documentation in the "docs/" directory with Sphinx
sphinx:
configuration: docs/conf.py
configuration: certbot/docs/conf.py
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
# builder: "dirhtml"
# Fail on all warnings to avoid broken references
fail_on_warning: true
# Optionally build your docs in additional formats such as PDF and ePub
# formats:
formats:
- pdf
- epub
@@ -30,4 +30,4 @@ sphinx:
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
python:
install:
- requirements: ../tools/requirements.txt
- requirements: certbot/readthedocs.org.requirements.txt

View File

@@ -2,18 +2,47 @@
Certbot adheres to [Semantic Versioning](https://semver.org/).
## 2.8.0 - master
## 2.9.0 - master
### Added
* Support for Python 3.12 was added.
### Changed
*
### Fixed
* Updates `joinpath` syntax to only use one addition per call, because the multiple inputs
version was causing mypy errors on Python 3.10.
* Makes the `reconfigure` verb actually use the staging server for the dry run to check the new
configuration.
More details about these changes can be found on our GitHub repo.
## 2.8.0 - 2023-12-05
### Added
* Added support for [Alpine Linux](https://www.alpinelinux.org) distribution when is used the apache plugin
### Changed
* Support for Python 3.7 was removed.
### Fixed
* Stop using the deprecated `pkg_resources` API included in `setuptools`.
More details about these changes can be found on our GitHub repo.
## 2.7.4 - 2023-11-01
### Fixed
* Fixed a bug introduced in version 2.7.0 that caused interactively entered
webroot plugin values to not be saved for renewal.
* Fixed a bug introduced in version 2.7.0 of our Lexicon based DNS plugins that
caused them to fail to find the DNS zone that needs to be modified in some
cases.

View File

@@ -1,4 +1,4 @@
"""Certbot client."""
# version number like 1.2.3a0, must have at least 2 parts, like 1.2
__version__ = '2.8.0.dev0'
__version__ = '2.9.0.dev0'

View File

@@ -36,6 +36,7 @@ from certbot._internal.cli.cli_utils import HelpfulArgumentGroup
from certbot._internal.cli.cli_utils import nonnegative_int
from certbot._internal.cli.cli_utils import parse_preferred_challenges
from certbot._internal.cli.cli_utils import read_file
from certbot._internal.cli.cli_utils import set_test_server_options
from certbot._internal.cli.group_adder import _add_all_groups
from certbot._internal.cli.helpful import HelpfulArgumentParser
from certbot._internal.cli.paths_parser import _paths_parser

View File

@@ -1,6 +1,7 @@
"""Certbot command line util function"""
import argparse
import copy
import glob
import inspect
from typing import Any
from typing import Iterable
@@ -250,3 +251,48 @@ def nonnegative_int(value: str) -> int:
if int_value < 0:
raise argparse.ArgumentTypeError("value must be non-negative")
return int_value
def set_test_server_options(verb: str, config: configuration.NamespaceConfig) -> None:
"""Updates server, break_my_certs, staging, tos, and
register_unsafely_without_email in config as necessary to prepare
to use the test server.
We have --staging/--dry-run; perform sanity check and set config.server
:param str verb: subcommand called
:param config: parsed command line arguments
:type config: configuration.NamespaceConfig
:raises errors.Error: if non-default server is used and --staging is set
:raises errors.Error: if inapplicable verb is used and --dry-run is set
"""
# Flag combinations should produce these results:
# | --staging | --dry-run |
# ------------------------------------------------------------
# | --server acme-v02 | Use staging | Use staging |
# | --server acme-staging-v02 | Use staging | Use staging |
# | --server <other> | Conflict error | Use <other> |
default_servers = (flag_default("server"), constants.STAGING_URI)
if config.staging and config.server not in default_servers:
raise errors.Error("--server value conflicts with --staging")
if config.server == flag_default("server"):
config.server = constants.STAGING_URI
# If the account has already been loaded (such as by calling reconstitute before this),
# clear it so that we don't try to use the prod account on the staging server.
config.account = None
if config.dry_run:
if verb not in ["certonly", "renew", "reconfigure"]:
raise errors.Error("--dry-run currently only works with the "
"'certonly' or 'renew' subcommands (%r)" % verb)
config.break_my_certs = config.staging = True
if glob.glob(os.path.join(config.config_dir, constants.ACCOUNTS_DIR, "*")):
# The user has a prod account, but might not have a staging
# one; we don't want to start trying to perform interactive registration
config.tos = True
config.register_unsafely_without_email = True

View File

@@ -2,7 +2,6 @@
import argparse
import functools
import glob
import sys
from typing import Any
from typing import Dict
@@ -26,11 +25,11 @@ from certbot._internal.cli.cli_utils import add_domains
from certbot._internal.cli.cli_utils import CustomHelpFormatter
from certbot._internal.cli.cli_utils import flag_default
from certbot._internal.cli.cli_utils import HelpfulArgumentGroup
from certbot._internal.cli.cli_utils import set_test_server_options
from certbot._internal.cli.verb_help import VERB_HELP
from certbot._internal.cli.verb_help import VERB_HELP_MAP
from certbot._internal.display import obj as display_obj
from certbot._internal.plugins import disco
from certbot.compat import os
from certbot.configuration import ArgumentSource
from certbot.configuration import NamespaceConfig
@@ -165,6 +164,7 @@ class HelpfulArgumentParser:
def remove_config_file_domains_for_renewal(self, config: NamespaceConfig) -> None:
"""Make "certbot renew" safe if domains are set in cli.ini."""
# Works around https://github.com/certbot/certbot/issues/4096
assert config.argument_sources is not None
if (config.argument_sources['domains'] == ArgumentSource.CONFIG_FILE and
self.verb == "renew"):
config.domains = []
@@ -317,33 +317,10 @@ class HelpfulArgumentParser:
return config
def set_test_server(self, config: NamespaceConfig) -> None:
"""We have --staging/--dry-run; perform sanity check and set config.server"""
# Flag combinations should produce these results:
# | --staging | --dry-run |
# ------------------------------------------------------------
# | --server acme-v02 | Use staging | Use staging |
# | --server acme-staging-v02 | Use staging | Use staging |
# | --server <other> | Conflict error | Use <other> |
default_servers = (flag_default("server"), constants.STAGING_URI)
if config.staging and config.server not in default_servers:
raise errors.Error("--server value conflicts with --staging")
if config.server == flag_default("server"):
config.server = constants.STAGING_URI
if config.dry_run:
if self.verb not in ["certonly", "renew"]:
raise errors.Error("--dry-run currently only works with the "
"'certonly' or 'renew' subcommands (%r)" % self.verb)
config.break_my_certs = config.staging = True
if glob.glob(os.path.join(config.config_dir, constants.ACCOUNTS_DIR, "*")):
# The user has a prod account, but might not have a staging
# one; we don't want to start trying to perform interactive registration
config.tos = True
config.register_unsafely_without_email = True
"""Updates server, break_my_certs, staging, tos, and
register_unsafely_without_email in config as necessary to prepare
to use the test server."""
return set_test_server_options(self.verb, config)
def handle_csr(self, config: NamespaceConfig) -> None:
"""Process a --csr flag."""

View File

@@ -21,7 +21,7 @@ SETUPTOOLS_PLUGINS_ENTRY_POINT = "certbot.plugins"
OLD_SETUPTOOLS_PLUGINS_ENTRY_POINT = "letsencrypt.plugins"
"""Plugins Setuptools entry point before rename."""
CLI_DEFAULTS: Dict[str, Any] = dict( # noqa
CLI_DEFAULTS: Dict[str, Any] = dict( # pylint: disable=use-dict-literal
config_files=[
os.path.join(misc.get_default_folder('config'), 'cli.ini'),
# https://freedesktop.org/wiki/Software/xdg-user-dirs/

View File

@@ -1727,10 +1727,8 @@ def reconfigure(config: configuration.NamespaceConfig,
# to say nothing of the difficulty in explaining what exactly this subcommand can modify
# To make sure that the requested changes work, do a dry run. While setting up the dry run,
# we will set all the needed fields in config, which will then be saved upon success.
config.dry_run = True
# To make sure that the requested changes work, we're going to do a dry run, and only save
# upon success. First, modify the config as the user requested.
if not config.certname:
certname_question = "Which certificate would you like to reconfigure?"
config.certname = cert_manager.get_certnames(
@@ -1772,17 +1770,44 @@ def reconfigure(config: configuration.NamespaceConfig,
if not renewal_candidate:
raise errors.ConfigurationError("Could not load certificate. See logs for errors.")
renewalparams = orig_renewal_conf['renewalparams']
# If server was set but hasn't changed and no account is loaded,
# load the old account because reconstitute won't have
if lineage_config.set_by_user('server') and lineage_config.server == renewalparams['server']\
and lineage_config.account is None:
lineage_config.account = renewalparams['account']
for param in ('account', 'server',):
if getattr(lineage_config, param) != renewalparams.get(param):
msg = ("Using reconfigure to change the ACME account or server is not supported. "
"If you would like to do so, use renew with the --force-renewal flag instead "
"of reconfigure. Note that doing so will count against any rate limits. For "
"more information on this method, see "
"https://certbot.org/renew-reconfiguration")
raise errors.ConfigurationError(msg)
# this is where lineage_config gets fully filled out (e.g. --apache will set auth and installer)
installer, auth = plug_sel.choose_configurator_plugins(lineage_config, plugins, "certonly")
le_client = _init_le_client(lineage_config, auth, installer)
# make a deep copy of lineage_config because we're about to modify it for a test dry run
dry_run_lineage_config = copy.deepcopy(lineage_config)
# we also set noninteractive_mode to more accurately simulate renewal (since `certbot renew`
# implies noninteractive mode) and to avoid prompting the user as changes made to
# dry_run_lineage_config beyond this point will not be applied to the original lineage_config
dry_run_lineage_config.noninteractive_mode = True
dry_run_lineage_config.dry_run = True
cli.set_test_server_options("reconfigure", dry_run_lineage_config)
le_client = _init_le_client(dry_run_lineage_config, auth, installer)
# renews cert as dry run to test that the new values are ok
# at this point, renewal_candidate.configuration has the old values, but will use
# the values from lineage_config when doing the dry run
_get_and_save_cert(le_client, lineage_config, certname=certname,
_get_and_save_cert(le_client, dry_run_lineage_config, certname=certname,
lineage=renewal_candidate)
# this function will update lineage.configuration with the new values, and save it to disk
# use the pre-dry-run version
renewal_candidate.save_new_config_values(lineage_config)
_report_reconfigure_results(renewal_file, orig_renewal_conf)

View File

@@ -207,6 +207,7 @@ class PluginsRegistry(Mapping):
plugin2_dist = other_ep.entry_point.dist
plugin1 = plugin1_dist.name.lower() if plugin1_dist else "unknown"
plugin2 = plugin2_dist.name.lower() if plugin2_dist else "unknown"
# pylint: disable=broad-exception-raised
raise Exception("Duplicate plugin name {0} from {1} and {2}.".format(
plugin_ep.name, plugin1, plugin2))
if issubclass(plugin_ep.plugin_cls, interfaces.Plugin):

View File

@@ -165,17 +165,22 @@ class NamespaceConfigTest(test_util.ConfigTestCase):
def test_set_by_user_exception(self):
from certbot.configuration import NamespaceConfig
# a newly created NamespaceConfig has no argument sources dict, so an
# exception is raised
config = NamespaceConfig(self.config.namespace)
with pytest.raises(RuntimeError):
config.set_by_user('whatever')
# now set an argument sources dict
config.set_argument_sources({})
assert not config.set_by_user('whatever')
def test_set_by_user_mutables(self):
assert not self.config.set_by_user('domains')
self.config.domains.append('example.org')
assert self.config.set_by_user('domains')
if __name__ == '__main__':
sys.exit(pytest.main(sys.argv[1:] + [__file__])) # pragma: no cover

View File

@@ -168,7 +168,7 @@ class MakeKeyTest(unittest.TestCase):
from certbot.crypto_util import make_key
# Do not test larger keys as it takes too long.
OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, make_key(1024))
OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, make_key(2048))
def test_ec(self): # pylint: disable=no-self-use
# ECDSA Key Type Tests
@@ -185,8 +185,8 @@ class MakeKeyTest(unittest.TestCase):
from certbot.crypto_util import make_key
# Try a bad key size for RSA and ECDSA
with pytest.raises(errors.Error, match='Unsupported RSA key length: 512'):
make_key(bits=512, key_type='rsa')
with pytest.raises(errors.Error, match='Unsupported RSA key length: 1024'):
make_key(bits=1024, key_type='rsa')
def test_bad_elliptic_curve_name(self):
from certbot.crypto_util import make_key
@@ -200,7 +200,7 @@ class MakeKeyTest(unittest.TestCase):
with pytest.raises(errors.Error,
match=re.escape('Invalid key_type specified: unf. Use [rsa|ecdsa]')):
OpenSSL.crypto.load_privatekey(
OpenSSL.crypto.FILETYPE_PEM, make_key(1024, key_type='unf'))
OpenSSL.crypto.FILETYPE_PEM, make_key(2048, key_type='unf'))
class VerifyCertSetup(unittest.TestCase):

View File

@@ -563,7 +563,7 @@ class ReconfigureTest(test_util.TempDirTestCase):
# Options used in the renewal process
[renewalparams]
account = ee43634db0aa4e6804f152be39990e6a
server = https://acme-staging-v02.api.letsencrypt.org/directory
server = https://acme-v02.api.letsencrypt.org/directory
authenticator = nginx
installer = nginx
key_type = rsa
@@ -621,6 +621,72 @@ class ReconfigureTest(test_util.TempDirTestCase):
new_config = self._call('--cert-name example.com --apache'.split())
assert new_config['renewalparams']['authenticator'] == 'apache'
def test_only_intended_changes(self):
""" Check that we don't accidentally modify anything that we didn't mean to """
named_mock = mock.Mock()
named_mock.name = 'apache'
self.mocks['pick_installer'].return_value = named_mock
self.mocks['pick_auth'].return_value = named_mock
self.mocks['find_init'].return_value = named_mock
new_config = self._call('--cert-name example.com --apache'.split())
# Undo the changes we made in calling and in testing
new_config['renewalparams']['authenticator'] = 'nginx'
new_config['renewalparams']['installer'] = 'nginx'
del new_config['renewalparams']['config_dir']
new_config['version'] = self.original_config['version']
assert new_config == self.original_config
@mock.patch('certbot._internal.hooks.validate_hooks')
def test_staging_used(self, unused_validate_hooks):
""" Check that we use the staging server for the dry run """
assert self.original_config['renewalparams']['server'] == \
'https://acme-v02.api.letsencrypt.org/directory'
self._call('--cert-name example.com --pre-hook'.split() + ['echo pre'])
assert 'staging' in self.mocks['_init_le_client'].call_args.args[0].server
assert 'staging' in self.mocks['_get_and_save_cert'].call_args.args[1].server
def test_new_account_or_server_errors(self):
""" Check that we error when attempting to change the account id or server,
but not when it's the same
"""
orig_account_id = self.original_config['renewalparams']['account']
orig_server = self.original_config['renewalparams']['server']
# new account
try:
self._call(f'--cert-name example.com --account newaccountid'.split())
except errors.ConfigurationError as err:
assert "Using reconfigure to change the ACME account" in str(err)
# check that config isn't modified
with open(self.renewal_file, 'r') as f:
new_config = configobj.ConfigObj(f, encoding='utf-8', default_encoding='utf-8')
assert new_config['renewalparams']['account'] == orig_account_id
# same account
new_config = self._call(f'--cert-name example.com --account {orig_account_id}'.split())
assert new_config['renewalparams']['account'] == orig_account_id
# new server
try:
self._call(f'--cert-name example.com --server x.com'.split())
except errors.ConfigurationError as err:
assert "Using reconfigure to change the ACME account" in str(err)
# check that config isn't modified
with open(self.renewal_file, 'r') as f:
new_config = configobj.ConfigObj(f, encoding='utf-8', default_encoding='utf-8')
assert new_config['renewalparams']['server'] == orig_server
# same server
new_config = self._call(f'--cert-name example.com --server {orig_server}'.split())
assert new_config['renewalparams']['server'] == orig_server
@mock.patch('certbot._internal.hooks.validate_hooks')
def test_update_hooks(self, unused_validate_hooks):
assert 'pre_hook' not in self.original_config

View File

@@ -66,7 +66,8 @@ class NamespaceConfig:
self.namespace: argparse.Namespace
# Avoid recursion loop because of the delegation defined in __setattr__
object.__setattr__(self, 'namespace', namespace)
object.__setattr__(self, 'argument_sources', None)
object.__setattr__(self, '_argument_sources', None)
object.__setattr__(self, '_previously_accessed_mutables', {})
self.namespace.config_dir = os.path.abspath(self.namespace.config_dir)
self.namespace.work_dir = os.path.abspath(self.namespace.work_dir)
@@ -90,7 +91,7 @@ class NamespaceConfig:
"""
# Avoid recursion loop because of the delegation defined in __setattr__
object.__setattr__(self, 'argument_sources', argument_sources)
object.__setattr__(self, '_argument_sources', argument_sources)
def set_by_user(self, var: str) -> bool:
@@ -145,15 +146,48 @@ class NamespaceConfig:
"""
If an argument_sources dict was set, overwrites an argument's source to
be ArgumentSource.RUNTIME. Used when certbot sets an argument's values
at runtime.
at runtime. This also clears the modified value from
_previously_accessed_mutables since it is no longer needed.
"""
if self.argument_sources is not None:
self.argument_sources[name] = ArgumentSource.RUNTIME
if self._argument_sources is not None:
self._argument_sources[name] = ArgumentSource.RUNTIME
if name in self._previously_accessed_mutables:
del self._previously_accessed_mutables[name]
@property
def argument_sources(self) -> Optional[Dict[str, ArgumentSource]]:
"""Returns _argument_sources after handling any changes to accessed mutable values."""
# We keep values in _previously_accessed_mutables until we've detected a modification to try
# to provide up-to-date information when argument_sources is accessed. Once a mutable object
# has been accessed, it can be modified at any time if a reference to it was kept somewhere
# else.
# We copy _previously_accessed_mutables because _mark_runtime_override modifies it.
for name, prev_value in self._previously_accessed_mutables.copy().items():
current_value = getattr(self.namespace, name)
if current_value != prev_value:
self._mark_runtime_override(name)
return self._argument_sources
# Delegate any attribute not explicitly defined to the underlying namespace object.
#
# If any mutable namespace attributes are explicitly defined in the future, you'll probably want
# to take an approach like the one used in __getattr__ and the argument_sources property.
def __getattr__(self, name: str) -> Any:
return getattr(self.namespace, name)
arg_sources = self.argument_sources
value = getattr(self.namespace, name)
if arg_sources is not None:
# If the requested attribute was already modified at runtime, we don't need to track any
# future changes.
if name not in arg_sources or arg_sources[name] != ArgumentSource.RUNTIME:
# If name is already in _previously_accessed_mutables, we don't need to make a copy
# of it again. If its value was changed, this would have been caught while preparing
# the return value of the property self.argument_sources accessed earlier in this
# function.
if name not in self._previously_accessed_mutables and not _is_immutable(value):
self._previously_accessed_mutables[name] = copy.deepcopy(value)
return value
def __setattr__(self, name: str, value: Any) -> None:
self._mark_runtime_override(name)
@@ -425,9 +459,10 @@ class NamespaceConfig:
# Work around https://bugs.python.org/issue1515 for py26 tests :( :(
new_ns = copy.deepcopy(self.namespace)
new_config = type(self)(new_ns)
if self.set_argument_sources is not None:
new_sources = copy.deepcopy(self.argument_sources)
new_config.set_argument_sources(new_sources)
# Avoid recursion loop because of the delegation defined in __setattr__
object.__setattr__(new_config, '_argument_sources', copy.deepcopy(self.argument_sources))
object.__setattr__(new_config, '_previously_accessed_mutables',
copy.deepcopy(self._previously_accessed_mutables))
return new_config
@@ -450,3 +485,15 @@ def _check_config_sanity(config: NamespaceConfig) -> None:
for domain in config.namespace.domains:
# This may be redundant, but let's be paranoid
util.enforce_domain_sanity(domain)
def _is_immutable(value: Any) -> bool:
"""Is value of an immutable type?"""
if isinstance(value, tuple):
# tuples are only immutable if all contained values are immutable.
return all(_is_immutable(subvalue) for subvalue in value)
for immutable_type in (int, float, complex, str, bytes, bool, frozenset,):
if isinstance(value, immutable_type):
return True
# The last case we consider here is None which is also immutable.
return value is None

View File

@@ -208,11 +208,11 @@ def import_csr_file(csrfile: str, data: bytes) -> Tuple[int, util.CSR, List[str]
return PEM, util.CSR(file=csrfile, data=data_pem, form="pem"), domains
def make_key(bits: int = 1024, key_type: str = "rsa",
def make_key(bits: int = 2048, key_type: str = "rsa",
elliptic_curve: Optional[str] = None) -> bytes:
"""Generate PEM encoded RSA|EC key.
:param int bits: Number of bits if key_type=rsa. At least 1024 for RSA.
:param int bits: Number of bits if key_type=rsa. At least 2048 for RSA.
:param str key_type: The type of key to generate, but be rsa or ecdsa
:param str elliptic_curve: The elliptic curve to use.
@@ -221,7 +221,7 @@ def make_key(bits: int = 1024, key_type: str = "rsa",
:rtype: str
"""
if key_type == 'rsa':
if bits < 1024:
if bits < 2048:
raise errors.Error("Unsupported RSA key length: {}".format(bits))
key = crypto.PKey()

View File

@@ -465,7 +465,7 @@ def dir_setup(test_dir: str, pkg: str) -> Tuple[str, str, str]: # pragma: no co
filesystem.chmod(config_dir, constants.CONFIG_DIRS_MODE)
filesystem.chmod(work_dir, constants.CONFIG_DIRS_MODE)
test_dir_ref = importlib_resources.files(pkg).joinpath("testdata", test_dir)
test_dir_ref = importlib_resources.files(pkg).joinpath("testdata").joinpath(test_dir)
with importlib_resources.as_file(test_dir_ref) as path:
shutil.copytree(
path, os.path.join(temp_dir, test_dir), symlinks=True)

View File

@@ -1,6 +1,7 @@
"""Test utilities."""
import atexit
from contextlib import ExitStack
import copy
from importlib import reload as reload_module
import io
import logging
@@ -403,7 +404,8 @@ class ConfigTestCase(TempDirTestCase):
def setUp(self) -> None:
super().setUp()
self.config = configuration.NamespaceConfig(
mock.MagicMock(**constants.CLI_DEFAULTS),
# We make a copy here so any mutable values from CLI_DEFAULTS do not get modified.
mock.MagicMock(**copy.deepcopy(constants.CLI_DEFAULTS)),
)
self.config.set_argument_sources({})
self.config.namespace.verb = "certonly"

View File

@@ -1,4 +1,4 @@
usage:
usage:
certbot [SUBCOMMAND] [options] [-d DOMAIN] [-d DOMAIN] ...
Certbot can obtain and install HTTPS/TLS/SSL certificates. By default,
@@ -122,7 +122,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/2.7.3 (certbot;
"". (default: CertbotACMEClient/2.8.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,

View File

@@ -69,7 +69,7 @@ master_doc = 'index'
# General information about the project.
project = u'Certbot'
# this is now overridden by the footer.html template
#copyright = u'2014-2018 - The Certbot software and documentation are licensed under the Apache 2.0 license as described at https://eff.org/cb-license.'
copyright = u'2014-2018 - The Certbot software and documentation are licensed under the Apache 2.0 license as described at https://eff.org/cb-license.'
# The version info for the project you're documenting, acts as replacement for
# |version| and |release|, also used in various other places throughout the

View File

@@ -328,8 +328,8 @@ Writing your own plugin
for one example of that.
Certbot client supports dynamic discovery of plugins through the
`setuptools entry points`_ using the `certbot.plugins` group. This
way you can, for example, create a custom implementation of
`importlib.metadata entry points`_ using the `certbot.plugins` group.
This way you can, for example, create a custom implementation of
`~certbot.interfaces.Authenticator` or the
`~certbot.interfaces.Installer` without having to merge it
with the core upstream source code. An example is provided in
@@ -352,8 +352,8 @@ users install it system-wide with `pip install`. Note that this will
only work for users who have Certbot installed from OS packages or via
pip.
.. _`setuptools entry points`:
https://setuptools.readthedocs.io/en/latest/pkg_resources.html#entry-points
.. _`importlib.metadata entry points`:
https://importlib-metadata.readthedocs.io/en/latest/using.html#entry-points
Writing your own plugin snap
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@@ -325,6 +325,7 @@ dns-multi_ Y N DNS authentication of 100+ providers using go-acme/
dns-dnsmanager_ Y N DNS Authentication for dnsmanager.io
standalone-nfq_ Y N HTTP Authentication that works with any webserver (Linux only)
dns-solidserver_ Y N DNS Authentication using SOLIDserver (EfficientIP)
dns-stackit_ Y N DNS Authentication using STACKIT DNS
================== ==== ==== ===============================================================
.. _haproxy: https://github.com/greenhost/certbot-haproxy
@@ -351,6 +352,7 @@ dns-solidserver_ Y N DNS Authentication using SOLIDserver (EfficientIP)
.. _dns-dnsmanager: https://github.com/stayallive/certbot-dns-dnsmanager
.. _standalone-nfq: https://github.com/alexzorin/certbot-standalone-nfq
.. _dns-solidserver: https://gitlab.com/charlyhong/certbot-dns-solidserver
.. _dns-stackit: https://github.com/stackitcloud/certbot-dns-stackit
If you're interested, you can also :ref:`write your own plugin <dev-plugin>`.

View File

@@ -113,6 +113,7 @@ setup(
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
'Topic :: System :: Installation/Setup',

View File

@@ -20,6 +20,7 @@ setup(
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Security',
],

View File

@@ -10,7 +10,6 @@ import os.path
import re
from pylint.checkers import BaseChecker
from pylint.interfaces import IAstroidChecker
# Modules whose file is matching one of these paths can import the os module.
WHITELIST_PATHS = [
@@ -25,7 +24,6 @@ class ForbidStandardOsModule(BaseChecker):
This checker ensures that standard os module (and submodules) is not imported by certbot
modules. Otherwise an 'os-module-forbidden' error will be registered for the faulty lines.
"""
__implements__ = IAstroidChecker
name = 'forbid-os-module'
msgs = {

View File

@@ -21,21 +21,15 @@
# updated.
# 4) Ignore our own PendingDeprecationWarning about update_symlinks soon to be dropped.
# See https://github.com/certbot/certbot/issues/6284.
# 5) Ignore pkg_resources.declare_namespace used in a large number of Google's Python
# libs. e.g. https://github.com/googleapis/google-auth-library-python/issues/1229.
# It is also is used in sphinxcontrib-devhelp 1.0.2 which as of writing this
# is the latest version of that library. See
# https://github.com/sphinx-doc/sphinxcontrib-devhelp/blob/1.0.2/setup.py#L69.
# 6) Ignore DeprecationWarning from using pkg_resources API
# 7) Ignore DeprecationWarning for datetime.utcfromtimestamp() triggered
# when importing the pytz.tzinfo module
# https://github.com/stub42/pytz/issues/105
# 5) Ignore DeprecationWarning for datetime.utcfromtimestamp() triggered
# from dateutil. See https://github.com/dateutil/dateutil/issues/1314.
# 6) Ignoring this allows us to continue to update pyOpenSSL (one of our crypto
# dependencies) until https://github.com/certbot/certbot/issues/9828 is resolved.
filterwarnings =
error
ignore:decodestring\(\) is a deprecated alias:DeprecationWarning:dns
ignore:.*rsyncdir:DeprecationWarning
ignore:'urllib3.contrib.pyopenssl:DeprecationWarning:requests_toolbelt
ignore:update_symlinks is deprecated:PendingDeprecationWarning
ignore:.*declare_namespace\(':DeprecationWarning
ignore:pkg_resources is deprecated as an API:DeprecationWarning
ignore:.*datetime.utcfromtimestamp\(\) is deprecated:DeprecationWarning:pytz.tzinfo
ignore:.*datetime.utcfromtimestamp\(\) is deprecated:DeprecationWarning:dateutil
ignore:X509Extension support in pyOpenSSL is deprecated:DeprecationWarning

View File

@@ -2,12 +2,12 @@
# that script.
apacheconfig==0.3.2 ; python_version >= "3.8" and python_version < "3.9"
asn1crypto==0.24.0 ; python_version >= "3.8" and python_version < "3.9"
astroid==3.0.0 ; python_version >= "3.8" and python_version < "3.9"
astroid==3.0.1 ; python_version >= "3.8" and python_version < "3.9"
beautifulsoup4==4.12.2 ; python_version >= "3.8" and python_version < "3.9"
boto3==1.15.15 ; python_version >= "3.8" and python_version < "3.9"
botocore==1.18.15 ; python_version >= "3.8" and python_version < "3.9"
cachetools==5.3.1 ; python_version >= "3.8" and python_version < "3.9"
certifi==2023.7.22 ; python_version >= "3.8" and python_version < "3.9"
cachetools==5.3.2 ; python_version >= "3.8" and python_version < "3.9"
certifi==2023.11.17 ; python_version >= "3.8" and python_version < "3.9"
cffi==1.12.3 ; python_version >= "3.8" and python_version < "3.9"
chardet==3.0.4 ; python_version >= "3.8" and python_version < "3.9"
cloudflare==1.5.1 ; python_version >= "3.8" and python_version < "3.9"
@@ -22,9 +22,9 @@ distlib==0.3.7 ; python_version >= "3.8" and python_version < "3.9"
distro==1.0.1 ; python_version >= "3.8" and python_version < "3.9"
dns-lexicon==3.15.1 ; python_version >= "3.8" and python_version < "3.9"
dnspython==1.15.0 ; python_version >= "3.8" and python_version < "3.9"
exceptiongroup==1.1.3 ; python_version >= "3.8" and python_version < "3.9"
exceptiongroup==1.2.0 ; python_version >= "3.8" and python_version < "3.9"
execnet==2.0.2 ; python_version >= "3.8" and python_version < "3.9"
filelock==3.12.4 ; python_version >= "3.8" and python_version < "3.9"
filelock==3.13.1 ; python_version >= "3.8" and python_version < "3.9"
funcsigs==0.4 ; python_version >= "3.8" and python_version < "3.9"
future==0.18.3 ; python_version >= "3.8" and python_version < "3.9"
google-api-python-client==1.6.5 ; python_version >= "3.8" and python_version < "3.9"
@@ -32,37 +32,37 @@ google-auth==2.16.0 ; python_version >= "3.8" and python_version < "3.9"
httplib2==0.9.2 ; python_version >= "3.8" and python_version < "3.9"
idna==2.6 ; python_version >= "3.8" and python_version < "3.9"
importlib-metadata==4.6.4 ; python_version >= "3.8" and python_version < "3.9"
importlib-resources==6.1.0 ; python_version >= "3.8" and python_version < "3.9"
importlib-resources==6.1.1 ; python_version >= "3.8" and python_version < "3.9"
iniconfig==2.0.0 ; python_version >= "3.8" and python_version < "3.9"
ipaddress==1.0.16 ; python_version >= "3.8" and python_version < "3.9"
isort==5.12.0 ; python_version >= "3.8" and python_version < "3.9"
jmespath==0.10.0 ; python_version >= "3.8" and python_version < "3.9"
josepy==1.13.0 ; python_version >= "3.8" and python_version < "3.9"
josepy==1.14.0 ; python_version >= "3.8" and python_version < "3.9"
logger==1.4 ; python_version >= "3.8" and python_version < "3.9"
mccabe==0.7.0 ; python_version >= "3.8" and python_version < "3.9"
mypy-extensions==1.0.0 ; python_version >= "3.8" and python_version < "3.9"
mypy==1.6.0 ; python_version >= "3.8" and python_version < "3.9"
mypy==1.7.1 ; python_version >= "3.8" and python_version < "3.9"
ndg-httpsclient==0.3.2 ; python_version >= "3.8" and python_version < "3.9"
oauth2client==4.1.3 ; python_version >= "3.8" and python_version < "3.9"
packaging==23.2 ; python_version >= "3.8" and python_version < "3.9"
parsedatetime==2.4 ; python_version >= "3.8" and python_version < "3.9"
pbr==1.8.0 ; python_version >= "3.8" and python_version < "3.9"
pip==23.2.1 ; python_version >= "3.8" and python_version < "3.9"
platformdirs==3.11.0 ; python_version >= "3.8" and python_version < "3.9"
pip==23.3.1 ; python_version >= "3.8" and python_version < "3.9"
platformdirs==4.0.0 ; python_version >= "3.8" and python_version < "3.9"
pluggy==1.3.0 ; python_version >= "3.8" and python_version < "3.9"
ply==3.4 ; python_version >= "3.8" and python_version < "3.9"
py==1.11.0 ; python_version >= "3.8" and python_version < "3.9"
pyasn1-modules==0.3.0 ; python_version >= "3.8" and python_version < "3.9"
pyasn1==0.4.8 ; python_version >= "3.8" and python_version < "3.9"
pycparser==2.14 ; python_version >= "3.8" and python_version < "3.9"
pylint==3.0.1 ; python_version >= "3.8" and python_version < "3.9"
pylint==3.0.2 ; python_version >= "3.8" and python_version < "3.9"
pyopenssl==17.5.0 ; python_version >= "3.8" and python_version < "3.9"
pyotp==2.9.0 ; python_version >= "3.8" and python_version < "3.9"
pyparsing==2.2.1 ; python_version >= "3.8" and python_version < "3.9"
pyrfc3339==1.0 ; python_version >= "3.8" and python_version < "3.9"
pytest-cov==4.1.0 ; python_version >= "3.8" and python_version < "3.9"
pytest-xdist==3.3.1 ; python_version >= "3.8" and python_version < "3.9"
pytest==7.4.2 ; python_version >= "3.8" and python_version < "3.9"
pytest-xdist==3.5.0 ; python_version >= "3.8" and python_version < "3.9"
pytest==7.4.3 ; python_version >= "3.8" and python_version < "3.9"
python-augeas==0.5.0 ; python_version >= "3.8" and python_version < "3.9"
python-dateutil==2.8.2 ; python_version >= "3.8" and python_version < "3.9"
python-digitalocean==1.11 ; python_version >= "3.8" and python_version < "3.9"
@@ -76,9 +76,9 @@ s3transfer==0.3.7 ; python_version >= "3.8" and python_version < "3.9"
setuptools==41.6.0 ; python_version >= "3.8" and python_version < "3.9"
six==1.11.0 ; python_version >= "3.8" and python_version < "3.9"
soupsieve==2.5 ; python_version >= "3.8" and python_version < "3.9"
tldextract==5.0.0 ; python_version >= "3.8" and python_version < "3.9"
tldextract==5.1.1 ; python_version >= "3.8" and python_version < "3.9"
tomli==2.0.1 ; python_version >= "3.8" and python_version < "3.9"
tomlkit==0.12.1 ; python_version >= "3.8" and python_version < "3.9"
tomlkit==0.12.3 ; python_version >= "3.8" and python_version < "3.9"
tox==1.9.2 ; python_version >= "3.8" and python_version < "3.9"
types-cryptography==3.3.23.2 ; python_version >= "3.8" and python_version < "3.9"
types-httplib2==0.22.0.2 ; python_version >= "3.8" and python_version < "3.9"
@@ -86,14 +86,14 @@ types-pyopenssl==23.0.0.0 ; python_version >= "3.8" and python_version < "3.9"
types-pyrfc3339==1.1.1.5 ; python_version >= "3.8" and python_version < "3.9"
types-python-dateutil==2.8.19.14 ; python_version >= "3.8" and python_version < "3.9"
types-pytz==2023.3.1.1 ; python_version >= "3.8" and python_version < "3.9"
types-pywin32==306.0.0.4 ; python_version >= "3.8" and python_version < "3.9"
types-pywin32==306.0.0.6 ; python_version >= "3.8" and python_version < "3.9"
types-requests==2.31.0.6 ; python_version >= "3.8" and python_version < "3.9"
types-setuptools==68.2.0.0 ; python_version >= "3.8" and python_version < "3.9"
types-setuptools==69.0.0.0 ; python_version >= "3.8" and python_version < "3.9"
types-six==1.16.21.9 ; python_version >= "3.8" and python_version < "3.9"
types-urllib3==1.26.25.14 ; python_version >= "3.8" and python_version < "3.9"
typing-extensions==4.8.0 ; python_version >= "3.8" and python_version < "3.9"
uritemplate==3.0.1 ; python_version >= "3.8" and python_version < "3.9"
urllib3==1.24.2 ; python_version >= "3.8" and python_version < "3.9"
virtualenv==20.24.5 ; python_version >= "3.8" and python_version < "3.9"
virtualenv==20.25.0 ; python_version >= "3.8" and python_version < "3.9"
wheel==0.33.6 ; python_version >= "3.8" and python_version < "3.9"
zipp==3.17.0 ; python_version >= "3.8" and python_version < "3.9"

View File

@@ -13,7 +13,7 @@ set -euo pipefail
# If this script wasn't given a command line argument, print usage and exit.
if [ -z ${1+x} ]; then
echo "Usage:" >&2
echo "$0 PYPROJECT_TOML_DIRECTORY" >&2
echo "$0 PYPROJECT_TOML_DIRECTORY [POETRY_ARGS]" >&2
exit 1
fi
@@ -37,10 +37,14 @@ if [ -f poetry.lock ]; then
rm poetry.lock
fi
echo "If this takes more than a few minutes, you can try running this script again" >&2
echo "with arguments for poetry like -vvv on the command line to help see where" >&2
echo "poetry is getting stuck." >&2
extra_args="${*:2}"
# If you're running this with different Python versions (say to update both our
# "current" and "oldest" pinnings), poetry's cache can become corrupted causing
# poetry to hang indefinitely. --no-cache avoids this.
poetry lock --no-cache >&2
poetry lock --no-cache ${extra_args:+"$extra_args"} >&2
trap 'rm poetry.lock' EXIT
# We need to remove local packages from the output.

View File

@@ -58,7 +58,7 @@ setuptools-rust = "*"
#
# If this pinning is removed, we may still need to add a lower bound for the
# pylint version. See https://github.com/certbot/certbot/pull/9229.
pylint = "2.15.5"
pylint = "3.0.2"
# Bug in poetry, where still installes yanked versions from pypi (source: https://github.com/python-poetry/poetry/issues/2453)
# this version of cryptography introduced a security vulnrability.
@@ -70,11 +70,6 @@ cryptography = "!= 37.0.3"
# https://github.com/python-poetry/poetry-plugin-export/issues/168 is resolved.
poetry = "<1.3.0"
# setuptools 67.5.0 deprecated pkg_resources which we still use. Let's pin it
# back until this is fixed. Doing this work is being tracked by
# https://github.com/certbot/certbot/issues/9606.
setuptools = "<67.5.0"
# Branch 4.x of tox introduces backward incompatibility changes. The tox.ini
# file in the project must be adapted accordingly before moving out of the 3.x
# branch. Once done, the following constraint should become tox >= 4 to keep

View File

@@ -1,6 +1,7 @@
#!/bin/bash
# This script accepts no arguments and automates the process of updating
# Certbot's dependencies including automatically updating the correct file.
# This script automates the process of updating Certbot's dependencies
# including automatically updating the correct file. It is usually run without
# any arguments, but if any are provided, they will be passed to Poetry.
# Dependencies can be pinned to older versions by modifying pyproject.toml in
# the same directory as this file.
set -euo pipefail
@@ -11,7 +12,7 @@ REPO_ROOT="$(git rev-parse --show-toplevel)"
RELATIVE_SCRIPT_PATH="$(realpath --relative-to "$REPO_ROOT" "$WORK_DIR")/$(basename "${BASH_SOURCE[0]}")"
REQUIREMENTS_FILE="$REPO_ROOT/tools/requirements.txt"
PINNINGS=$("${COMMON_DIR}/export-pinned-dependencies.sh" "${WORK_DIR}")
PINNINGS=$("${COMMON_DIR}/export-pinned-dependencies.sh" "${WORK_DIR}" "$@")
cat << EOF > "$REQUIREMENTS_FILE"
# This file was generated by $RELATIVE_SCRIPT_PATH and can be updated using
# that script.

View File

@@ -1,6 +1,7 @@
#!/bin/bash
# This script accepts no arguments and automates the process of updating
# Certbot's dependencies including automatically updating the correct file.
# This script automates the process of updating Certbot's dependencies
# including automatically updating the correct file. It is usually run without
# any arguments, but if any are provided, they will be passed to Poetry.
# Dependencies can be pinned to older versions by modifying pyproject.toml in
# the same directory as this file.
set -euo pipefail
@@ -11,7 +12,7 @@ REPO_ROOT="$(git rev-parse --show-toplevel)"
RELATIVE_SCRIPT_PATH="$(realpath --relative-to "$REPO_ROOT" "$WORK_DIR")/$(basename "${BASH_SOURCE[0]}")"
CONSTRAINTS_FILE="$REPO_ROOT/tools/oldest_constraints.txt"
PINNINGS=$("${COMMON_DIR}/export-pinned-dependencies.sh" "${WORK_DIR}")
PINNINGS=$("${COMMON_DIR}/export-pinned-dependencies.sh" "${WORK_DIR}" "$@")
cat << EOF > "$CONSTRAINTS_FILE"
# This file was generated by $RELATIVE_SCRIPT_PATH and can be updated using
# that script.

View File

@@ -8,57 +8,57 @@
alabaster==0.7.13 ; python_version >= "3.8" and python_version < "4.0"
apacheconfig==0.3.2 ; python_version >= "3.8" and python_version < "4.0"
appnope==0.1.3 ; python_version >= "3.8" and python_version < "4.0" and sys_platform == "darwin"
astroid==2.13.5 ; python_version >= "3.8" and python_version < "4.0"
asttokens==2.4.0 ; python_version >= "3.8" and python_version < "4.0"
astroid==3.0.1 ; python_version >= "3.8" and python_version < "4.0"
asttokens==2.4.1 ; python_version >= "3.8" and python_version < "4.0"
attrs==23.1.0 ; python_version >= "3.8" and python_version < "4.0"
azure-core==1.29.4 ; python_version >= "3.8" and python_version < "4.0"
azure-devops==7.1.0b3 ; python_version >= "3.8" and python_version < "4.0"
babel==2.13.0 ; python_version >= "3.8" and python_version < "4.0"
azure-core==1.29.5 ; python_version >= "3.8" and python_version < "4.0"
azure-devops==7.1.0b4 ; python_version >= "3.8" and python_version < "4.0"
babel==2.13.1 ; python_version >= "3.8" and python_version < "4.0"
backcall==0.2.0 ; python_version >= "3.8" and python_version < "4.0"
bcrypt==4.0.1 ; python_version >= "3.8" and python_version < "4.0"
bcrypt==4.1.1 ; python_version >= "3.8" and python_version < "4.0"
beautifulsoup4==4.12.2 ; python_version >= "3.8" and python_version < "4.0"
boto3==1.28.63 ; python_version >= "3.8" and python_version < "4.0"
botocore==1.31.63 ; python_version >= "3.8" and python_version < "4.0"
boto3==1.33.6 ; python_version >= "3.8" and python_version < "4.0"
botocore==1.33.6 ; python_version >= "3.8" and python_version < "4.0"
cachecontrol==0.12.14 ; python_version >= "3.8" and python_version < "4.0"
cachetools==5.3.1 ; python_version >= "3.8" and python_version < "4.0"
cachetools==5.3.2 ; python_version >= "3.8" and python_version < "4.0"
cachy==0.3.0 ; python_version >= "3.8" and python_version < "4.0"
certifi==2023.7.22 ; python_version >= "3.8" and python_version < "4.0"
certifi==2023.11.17 ; python_version >= "3.8" and python_version < "4.0"
cffi==1.16.0 ; python_version >= "3.8" and python_version < "4.0"
charset-normalizer==3.3.0 ; python_version >= "3.8" and python_version < "4.0"
charset-normalizer==3.3.2 ; python_version >= "3.8" and python_version < "4.0"
cleo==1.0.0a5 ; python_version >= "3.8" and python_version < "4.0"
cloudflare==2.12.4 ; python_version >= "3.8" and python_version < "4.0"
cloudflare==2.14.2 ; python_version >= "3.8" and python_version < "4.0"
colorama==0.4.6 ; python_version >= "3.8" and python_version < "4.0" and sys_platform == "win32" or python_version >= "3.8" and python_version < "4.0" and platform_system == "Windows"
configargparse==1.7 ; python_version >= "3.8" and python_version < "4.0"
configobj==5.0.8 ; python_version >= "3.8" and python_version < "4.0"
coverage==7.3.2 ; python_version >= "3.8" and python_version < "4.0"
crashtest==0.3.1 ; python_version >= "3.8" and python_version < "4.0"
cryptography==41.0.4 ; python_version >= "3.8" and python_version < "4.0"
cryptography==41.0.7 ; python_version >= "3.8" and python_version < "4.0"
cython==0.29.36 ; python_version >= "3.8" and python_version < "4.0"
decorator==5.1.1 ; python_version >= "3.8" and python_version < "4.0"
deprecated==1.2.14 ; python_version >= "3.8" and python_version < "4.0"
dill==0.3.7 ; python_version >= "3.8" and python_version < "4.0"
dill==0.3.7 ; python_version < "4.0" and python_version >= "3.8"
distlib==0.3.7 ; python_version >= "3.8" and python_version < "4.0"
distro==1.8.0 ; python_version >= "3.8" and python_version < "4.0"
dns-lexicon==3.15.1 ; python_version >= "3.8" and python_version < "4.0"
dns-lexicon==3.17.0 ; python_version >= "3.8" and python_version < "4.0"
dnspython==2.4.2 ; python_version >= "3.8" and python_version < "4.0"
docutils==0.18.1 ; python_version >= "3.8" and python_version < "4.0"
docutils==0.20.1 ; python_version >= "3.8" and python_version < "4.0"
dulwich==0.20.50 ; python_version >= "3.8" and python_version < "4.0"
exceptiongroup==1.1.3 ; python_version >= "3.8" and python_version < "3.11"
exceptiongroup==1.2.0 ; python_version >= "3.8" and python_version < "3.11"
execnet==2.0.2 ; python_version >= "3.8" and python_version < "4.0"
executing==2.0.0 ; python_version >= "3.8" and python_version < "4.0"
executing==2.0.1 ; python_version >= "3.8" and python_version < "4.0"
fabric==3.2.2 ; python_version >= "3.8" and python_version < "4.0"
filelock==3.12.4 ; python_version >= "3.8" and python_version < "4.0"
google-api-core==2.12.0 ; python_version >= "3.8" and python_version < "4.0"
google-api-python-client==2.103.0 ; python_version >= "3.8" and python_version < "4.0"
filelock==3.13.1 ; python_version >= "3.8" and python_version < "4.0"
google-api-core==2.14.0 ; python_version >= "3.8" and python_version < "4.0"
google-api-python-client==2.109.0 ; python_version >= "3.8" and python_version < "4.0"
google-auth-httplib2==0.1.1 ; python_version >= "3.8" and python_version < "4.0"
google-auth==2.23.3 ; python_version >= "3.8" and python_version < "4.0"
google-auth==2.24.0 ; python_version >= "3.8" and python_version < "4.0"
googleapis-common-protos==1.61.0 ; python_version >= "3.8" and python_version < "4.0"
html5lib==1.1 ; python_version >= "3.8" and python_version < "4.0"
httplib2==0.22.0 ; python_version >= "3.8" and python_version < "4.0"
idna==3.4 ; python_version >= "3.8" and python_version < "4.0"
idna==3.6 ; python_version >= "3.8" and python_version < "4.0"
imagesize==1.4.1 ; python_version >= "3.8" and python_version < "4.0"
importlib-metadata==4.13.0 ; python_version >= "3.8" and python_version < "4.0"
importlib-resources==6.1.0 ; python_version >= "3.8" and python_version < "4.0"
importlib-resources==6.1.1 ; python_version >= "3.8" and python_version < "4.0"
iniconfig==2.0.0 ; python_version >= "3.8" and python_version < "4.0"
invoke==2.2.0 ; python_version >= "3.8" and python_version < "4.0"
ipdb==0.13.13 ; python_version >= "3.8" and python_version < "4.0"
@@ -70,13 +70,12 @@ jedi==0.19.1 ; python_version >= "3.8" and python_version < "4.0"
jeepney==0.8.0 ; python_version >= "3.8" and python_version < "4.0" and sys_platform == "linux"
jinja2==3.1.2 ; python_version >= "3.8" and python_version < "4.0"
jmespath==1.0.1 ; python_version >= "3.8" and python_version < "4.0"
josepy==1.13.0 ; python_version >= "3.8" and python_version < "4.0"
josepy==1.14.0 ; python_version >= "3.8" and python_version < "4.0"
jsonlines==4.0.0 ; python_version >= "3.8" and python_version < "4.0"
jsonpickle==3.0.2 ; python_version >= "3.8" and python_version < "4.0"
jsonschema-specifications==2023.7.1 ; python_version >= "3.8" and python_version < "4.0"
jsonschema==4.19.1 ; python_version >= "3.8" and python_version < "4.0"
keyring==24.2.0 ; python_version >= "3.8" and python_version < "4.0"
lazy-object-proxy==1.9.0 ; python_version >= "3.8" and python_version < "4.0"
jsonschema-specifications==2023.11.2 ; python_version >= "3.8" and python_version < "4.0"
jsonschema==4.20.0 ; python_version >= "3.8" and python_version < "4.0"
keyring==24.3.0 ; python_version >= "3.8" and python_version < "4.0"
lockfile==0.12.2 ; python_version >= "3.8" and python_version < "4.0"
markdown-it-py==3.0.0 ; python_version >= "3.8" and python_version < "4.0"
markupsafe==2.1.3 ; python_version >= "3.8" and python_version < "4.0"
@@ -87,16 +86,16 @@ more-itertools==10.1.0 ; python_version >= "3.8" and python_version < "4.0"
msgpack==1.0.7 ; python_version >= "3.8" and python_version < "4.0"
msrest==0.7.1 ; python_version >= "3.8" and python_version < "4.0"
mypy-extensions==1.0.0 ; python_version >= "3.8" and python_version < "4.0"
mypy==1.6.0 ; python_version >= "3.8" and python_version < "4.0"
mypy==1.7.1 ; python_version >= "3.8" and python_version < "4.0"
nh3==0.2.14 ; python_version >= "3.8" and python_version < "4.0"
oauthlib==3.2.2 ; python_version >= "3.8" and python_version < "4.0"
packaging==23.2 ; python_version >= "3.8" and python_version < "4.0"
paramiko==3.3.1 ; python_version >= "3.8" and python_version < "4.0"
parsedatetime==2.6 ; python_version >= "3.8" and python_version < "4.0"
parso==0.8.3 ; python_version >= "3.8" and python_version < "4.0"
pexpect==4.8.0 ; python_version >= "3.8" and python_version < "4.0"
pexpect==4.9.0 ; python_version >= "3.8" and python_version < "4.0"
pickleshare==0.7.5 ; python_version >= "3.8" and python_version < "4.0"
pip==23.2.1 ; python_version >= "3.8" and python_version < "4.0"
pip==23.3.1 ; python_version >= "3.8" and python_version < "4.0"
pkginfo==1.9.6 ; python_version >= "3.8" and python_version < "4.0"
pkgutil-resolve-name==1.3.10 ; python_version >= "3.8" and python_version < "3.9"
platformdirs==2.6.2 ; python_version >= "3.8" and python_version < "4.0"
@@ -105,26 +104,26 @@ ply==3.11 ; python_version >= "3.8" and python_version < "4.0"
poetry-core==1.3.2 ; python_version >= "3.8" and python_version < "4.0"
poetry-plugin-export==1.2.0 ; python_version >= "3.8" and python_version < "4.0"
poetry==1.2.2 ; python_version >= "3.8" and python_version < "4.0"
prompt-toolkit==3.0.39 ; python_version >= "3.8" and python_version < "4.0"
protobuf==4.24.4 ; python_version >= "3.8" and python_version < "4.0"
prompt-toolkit==3.0.41 ; python_version >= "3.8" and python_version < "4.0"
protobuf==4.25.1 ; python_version >= "3.8" and python_version < "4.0"
ptyprocess==0.7.0 ; python_version >= "3.8" and python_version < "4.0"
pure-eval==0.2.2 ; python_version >= "3.8" and python_version < "4.0"
py==1.11.0 ; python_version >= "3.8" and python_version < "4.0"
pyasn1-modules==0.3.0 ; python_version >= "3.8" and python_version < "4.0"
pyasn1==0.5.0 ; python_version >= "3.8" and python_version < "4.0"
pyasn1==0.5.1 ; python_version >= "3.8" and python_version < "4.0"
pycparser==2.21 ; python_version >= "3.8" and python_version < "4.0"
pygments==2.16.1 ; python_version >= "3.8" and python_version < "4.0"
pygments==2.17.2 ; python_version >= "3.8" and python_version < "4.0"
pylev==1.4.0 ; python_version >= "3.8" and python_version < "4.0"
pylint==2.15.5 ; python_version >= "3.8" and python_version < "4.0"
pylint==3.0.2 ; python_version >= "3.8" and python_version < "4.0"
pynacl==1.5.0 ; python_version >= "3.8" and python_version < "4.0"
pynsist==2.7 ; python_version >= "3.8" and python_version < "4.0"
pyopenssl==23.2.0 ; python_version >= "3.8" and python_version < "4.0"
pyopenssl==23.3.0 ; python_version >= "3.8" and python_version < "4.0"
pyotp==2.9.0 ; python_version >= "3.8" and python_version < "4.0"
pyparsing==3.1.1 ; python_version >= "3.8" and python_version < "4.0"
pyrfc3339==1.1 ; python_version >= "3.8" and python_version < "4.0"
pytest-cov==4.1.0 ; python_version >= "3.8" and python_version < "4.0"
pytest-xdist==3.3.1 ; python_version >= "3.8" and python_version < "4.0"
pytest==7.4.2 ; python_version >= "3.8" and python_version < "4.0"
pytest-xdist==3.5.0 ; python_version >= "3.8" and python_version < "4.0"
pytest==7.4.3 ; python_version >= "3.8" and python_version < "4.0"
python-augeas==1.1.0 ; python_version >= "3.8" and python_version < "4.0"
python-dateutil==2.8.2 ; python_version >= "3.8" and python_version < "4.0"
python-digitalocean==1.17.0 ; python_version >= "3.8" and python_version < "4.0"
@@ -133,26 +132,26 @@ pywin32-ctypes==0.2.2 ; python_version >= "3.8" and python_version < "4.0" and s
pywin32==306 ; python_version >= "3.8" and python_version < "4.0" and sys_platform == "win32"
pyyaml==6.0.1 ; python_version >= "3.8" and python_version < "4.0"
readme-renderer==42.0 ; python_version >= "3.8" and python_version < "4.0"
referencing==0.30.2 ; python_version >= "3.8" and python_version < "4.0"
referencing==0.31.1 ; python_version >= "3.8" and python_version < "4.0"
requests-download==0.1.2 ; python_version >= "3.8" and python_version < "4.0"
requests-file==1.5.1 ; python_version >= "3.8" and python_version < "4.0"
requests-oauthlib==1.3.1 ; python_version >= "3.8" and python_version < "4.0"
requests-toolbelt==0.9.1 ; python_version >= "3.8" and python_version < "4.0"
requests==2.31.0 ; python_version >= "3.8" and python_version < "4.0"
rfc3986==2.0.0 ; python_version >= "3.8" and python_version < "4.0"
rich==13.6.0 ; python_version >= "3.8" and python_version < "4.0"
rpds-py==0.10.6 ; python_version >= "3.8" and python_version < "4.0"
rich==13.7.0 ; python_version >= "3.8" and python_version < "4.0"
rpds-py==0.13.2 ; python_version >= "3.8" and python_version < "4.0"
rsa==4.9 ; python_version >= "3.8" and python_version < "4"
s3transfer==0.7.0 ; python_version >= "3.8" and python_version < "4.0"
s3transfer==0.8.2 ; python_version >= "3.8" and python_version < "4.0"
secretstorage==3.3.3 ; python_version >= "3.8" and python_version < "4.0" and sys_platform == "linux"
semantic-version==2.10.0 ; python_version >= "3.8" and python_version < "4.0"
setuptools-rust==1.7.0 ; python_version >= "3.8" and python_version < "4.0"
setuptools==67.4.0 ; python_version >= "3.8" and python_version < "4.0"
shellingham==1.5.3 ; python_version >= "3.8" and python_version < "4.0"
setuptools-rust==1.8.1 ; python_version >= "3.8" and python_version < "4.0"
setuptools==69.0.2 ; python_version < "4.0" and python_version >= "3.8"
shellingham==1.5.4 ; python_version >= "3.8" and python_version < "4.0"
six==1.16.0 ; python_version >= "3.8" and python_version < "4.0"
snowballstemmer==2.2.0 ; python_version >= "3.8" and python_version < "4.0"
soupsieve==2.5 ; python_version >= "3.8" and python_version < "4.0"
sphinx-rtd-theme==1.3.0 ; python_version >= "3.8" and python_version < "4.0"
sphinx-rtd-theme==2.0.0 ; python_version >= "3.8" and python_version < "4.0"
sphinx==7.1.2 ; python_version >= "3.8" and python_version < "4.0"
sphinxcontrib-applehelp==1.0.4 ; python_version >= "3.8" and python_version < "4.0"
sphinxcontrib-devhelp==1.0.2 ; python_version >= "3.8" and python_version < "4.0"
@@ -162,30 +161,30 @@ sphinxcontrib-jsmath==1.0.1 ; python_version >= "3.8" and python_version < "4.0"
sphinxcontrib-qthelp==1.0.3 ; python_version >= "3.8" and python_version < "4.0"
sphinxcontrib-serializinghtml==1.1.5 ; python_version >= "3.8" and python_version < "4.0"
stack-data==0.6.3 ; python_version >= "3.8" and python_version < "4.0"
tldextract==5.0.0 ; python_version >= "3.8" and python_version < "4.0"
tldextract==5.1.1 ; python_version >= "3.8" and python_version < "4.0"
tomli==2.0.1 ; python_version >= "3.8" and python_full_version <= "3.11.0a6"
tomlkit==0.12.1 ; python_version >= "3.8" and python_version < "4.0"
tomlkit==0.12.3 ; python_version >= "3.8" and python_version < "4.0"
tox==3.28.0 ; python_version >= "3.8" and python_version < "4.0"
traitlets==5.11.2 ; python_version >= "3.8" and python_version < "4.0"
traitlets==5.14.0 ; python_version >= "3.8" and python_version < "4.0"
twine==4.0.2 ; python_version >= "3.8" and python_version < "4.0"
types-httplib2==0.22.0.2 ; python_version >= "3.8" and python_version < "4.0"
types-pyopenssl==23.2.0.2 ; python_version >= "3.8" and python_version < "4.0"
types-pyopenssl==23.3.0.0 ; python_version >= "3.8" and python_version < "4.0"
types-pyrfc3339==1.1.1.5 ; python_version >= "3.8" and python_version < "4.0"
types-python-dateutil==2.8.19.14 ; python_version >= "3.8" and python_version < "4.0"
types-pytz==2023.3.1.1 ; python_version >= "3.8" and python_version < "4.0"
types-pywin32==306.0.0.4 ; python_version >= "3.8" and python_version < "4.0"
types-pywin32==306.0.0.6 ; python_version >= "3.8" and python_version < "4.0"
types-requests==2.31.0.6 ; python_version >= "3.8" and python_version < "4.0"
types-setuptools==68.2.0.0 ; python_version >= "3.8" and python_version < "4.0"
types-setuptools==69.0.0.0 ; python_version >= "3.8" and python_version < "4.0"
types-six==1.16.21.9 ; python_version >= "3.8" and python_version < "4.0"
types-urllib3==1.26.25.14 ; python_version >= "3.8" and python_version < "4.0"
typing-extensions==4.8.0 ; python_version >= "3.8" and python_version < "4.0"
uritemplate==4.1.1 ; python_version >= "3.8" and python_version < "4.0"
urllib3==1.26.17 ; python_version < "4.0" and python_version >= "3.8"
urllib3==1.26.18 ; python_version < "4.0" and python_version >= "3.8"
virtualenv==20.21.1 ; python_version >= "3.8" and python_version < "4.0"
wcwidth==0.2.8 ; python_version >= "3.8" and python_version < "4.0"
wcwidth==0.2.12 ; python_version >= "3.8" and python_version < "4.0"
webencodings==0.5.1 ; python_version >= "3.8" and python_version < "4.0"
wheel==0.41.2 ; python_version >= "3.8" and python_version < "4.0"
wrapt==1.15.0 ; python_version >= "3.8" and python_version < "4.0"
wheel==0.42.0 ; python_version >= "3.8" and python_version < "4.0"
wrapt==1.16.0 ; python_version >= "3.8" and python_version < "4.0"
xattr==0.9.9 ; python_version >= "3.8" and python_version < "4.0" and sys_platform == "darwin"
yarg==0.1.9 ; python_version >= "3.8" and python_version < "4.0"
zipp==3.17.0 ; python_version >= "3.8" and python_version < "4.0"

View File

@@ -56,10 +56,10 @@ commands =
commands =
{[testenv:py-win]commands} certbot-apache
[testenv:py3{,8,9,10,11}]
[testenv:py3{,8,9,10,11,12}]
commands = {[testenv:py]commands}
[testenv:py3.{8,9,10,11}]
[testenv:py3.{8,9,10,11,12}]
commands = {[testenv:py]commands}
[testenv:oldest]

View File

@@ -22,6 +22,7 @@ setup(
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'Programming Language :: Python :: 3.11',
'Programming Language :: Python :: 3.12',
'Operating System :: Microsoft :: Windows',
'Topic :: Software Development :: Build Tools',
],