Merge branch 'master' into fix-cryptography-ocsp

This commit is contained in:
Adrien Ferrand 2019-02-17 17:30:17 +01:00
commit 391d2f8f14
50 changed files with 520 additions and 427 deletions

View file

@ -2,7 +2,34 @@
Certbot adheres to [Semantic Versioning](https://semver.org/).
## 0.31.0 - master
## 0.32.0 - master
### Added
*
### Changed
* Certbot and its acme module now depend on josepy>=1.1.0 to avoid printing the
warnings described at https://github.com/certbot/josepy/issues/13.
* Apache plugin now respects CERTBOT_DOCS environment variable when adding
command line defaults.
### Fixed
*
Despite us having broken lockstep, we are continuing to release new versions of
all Certbot components during releases for the time being, however, the only
package with changes other than its version number was:
* acme
* certbot
* certbot-apache
More details about these changes can be found on our GitHub repo.
## 0.31.0 - 2019-02-07
### Added

View file

@ -739,8 +739,7 @@ class ClientV2(ClientBase):
if body.error is not None:
raise errors.IssuanceError(body.error)
if body.certificate is not None:
certificate_response = self._post_as_get(body.certificate,
content_type=DER_CONTENT_TYPE).text
certificate_response = self._post_as_get(body.certificate).text
return orderr.update(body=body, fullchain_pem=certificate_response)
raise errors.TimeoutError()

View file

@ -3,7 +3,7 @@ from setuptools import find_packages
from setuptools.command.test import test as TestCommand
import sys
version = '0.31.0.dev0'
version = '0.32.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [
@ -11,7 +11,9 @@ install_requires = [
# rsa_recover_prime_factors (>=0.8)
'cryptography>=1.2.3',
# formerly known as acme.jose:
'josepy>=1.0.0',
# 1.1.0+ is required to avoid the warnings described at
# https://github.com/certbot/josepy/issues/13.
'josepy>=1.1.0',
# Connection.set_tlsext_host_name (>=0.13)
'mock',
'PyOpenSSL>=0.13.1',

View file

@ -92,6 +92,11 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
"""
description = "Apache Web Server plugin"
if os.environ.get("CERTBOT_DOCS") == "1":
description += ( # pragma: no cover
" (Please note that the default values of the Apache plugin options"
" change depending on the operating system Certbot is run on.)"
)
OS_DEFAULTS = dict(
server_root="/etc/apache2",
@ -141,28 +146,36 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator):
# When adding, modifying or deleting command line arguments, be sure to
# include the changes in the list used in method _prepare_options() to
# ensure consistent behavior.
add("enmod", default=cls.OS_DEFAULTS["enmod"],
# Respect CERTBOT_DOCS environment variable and use default values from
# base class regardless of the underlying distribution (overrides).
if os.environ.get("CERTBOT_DOCS") == "1":
DEFAULTS = ApacheConfigurator.OS_DEFAULTS
else:
# cls.OS_DEFAULTS can be distribution specific, see override classes
DEFAULTS = cls.OS_DEFAULTS
add("enmod", default=DEFAULTS["enmod"],
help="Path to the Apache 'a2enmod' binary")
add("dismod", default=cls.OS_DEFAULTS["dismod"],
add("dismod", default=DEFAULTS["dismod"],
help="Path to the Apache 'a2dismod' binary")
add("le-vhost-ext", default=cls.OS_DEFAULTS["le_vhost_ext"],
add("le-vhost-ext", default=DEFAULTS["le_vhost_ext"],
help="SSL vhost configuration extension")
add("server-root", default=cls.OS_DEFAULTS["server_root"],
add("server-root", default=DEFAULTS["server_root"],
help="Apache server root directory")
add("vhost-root", default=None,
help="Apache server VirtualHost configuration root")
add("logs-root", default=cls.OS_DEFAULTS["logs_root"],
add("logs-root", default=DEFAULTS["logs_root"],
help="Apache server logs directory")
add("challenge-location",
default=cls.OS_DEFAULTS["challenge_location"],
default=DEFAULTS["challenge_location"],
help="Directory path for challenge configuration")
add("handle-modules", default=cls.OS_DEFAULTS["handle_modules"],
add("handle-modules", default=DEFAULTS["handle_modules"],
help="Let installer handle enabling required modules for you " +
"(Only Ubuntu/Debian currently)")
add("handle-sites", default=cls.OS_DEFAULTS["handle_sites"],
add("handle-sites", default=DEFAULTS["handle_sites"],
help="Let installer handle enabling sites for you " +
"(Only Ubuntu/Debian currently)")
add("ctl", default=cls.OS_DEFAULTS["ctl"],
add("ctl", default=DEFAULTS["ctl"],
help="Full path to Apache control script")
util.add_deprecated_argument(
add, argument_name="init-script", nargs=1)

View file

@ -115,6 +115,37 @@ class MultipleVhostsTest(util.ApacheTest):
# Weak test..
ApacheConfigurator.add_parser_arguments(mock.MagicMock())
def test_docs_parser_arguments(self):
os.environ["CERTBOT_DOCS"] = "1"
from certbot_apache.configurator import ApacheConfigurator
mock_add = mock.MagicMock()
ApacheConfigurator.add_parser_arguments(mock_add)
parserargs = ["server_root", "enmod", "dismod", "le_vhost_ext",
"vhost_root", "logs_root", "challenge_location",
"handle_modules", "handle_sites", "ctl"]
exp = dict()
for k in ApacheConfigurator.OS_DEFAULTS:
if k in parserargs:
exp[k.replace("_", "-")] = ApacheConfigurator.OS_DEFAULTS[k]
# Special cases
exp["vhost-root"] = None
exp["init-script"] = None
found = set()
for call in mock_add.call_args_list:
# init-script is a special case: deprecated argument
if call[0][0] != "init-script":
self.assertEqual(exp[call[0][0]], call[1]['default'])
found.add(call[0][0])
# Make sure that all (and only) the expected values exist
self.assertEqual(len(mock_add.call_args_list), len(found))
for e in exp:
self.assertTrue(e in found)
del os.environ["CERTBOT_DOCS"]
def test_add_parser_arguments_all_configurators(self): # pylint: disable=no-self-use
from certbot_apache.entrypoint import OVERRIDE_CLASSES
for cls in OVERRIDE_CLASSES.values():

View file

@ -2,7 +2,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.31.0.dev0'
version = '0.32.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View file

@ -31,7 +31,7 @@ if [ -z "$VENV_PATH" ]; then
fi
VENV_BIN="$VENV_PATH/bin"
BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
LE_AUTO_VERSION="0.30.2"
LE_AUTO_VERSION="0.31.0"
BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates
@ -333,63 +333,11 @@ BootstrapDebCommon() {
fi
augeas_pkg="libaugeas0 augeas-lenses"
AUGVERSION=`LC_ALL=C apt-cache show --no-all-versions libaugeas0 | grep ^Version: | cut -d" " -f2`
if [ "$ASSUME_YES" = 1 ]; then
YES_FLAG="-y"
fi
AddBackportRepo() {
# ARGS:
BACKPORT_NAME="$1"
BACKPORT_SOURCELINE="$2"
say "To use the Apache Certbot plugin, augeas needs to be installed from $BACKPORT_NAME."
if ! grep -v -e ' *#' /etc/apt/sources.list | grep -q "$BACKPORT_NAME" ; then
# This can theoretically error if sources.list.d is empty, but in that case we don't care.
if ! grep -v -e ' *#' /etc/apt/sources.list.d/* 2>/dev/null | grep -q "$BACKPORT_NAME"; then
if [ "$ASSUME_YES" = 1 ]; then
/bin/echo -n "Installing augeas from $BACKPORT_NAME in 3 seconds..."
sleep 1s
/bin/echo -ne "\e[0K\rInstalling augeas from $BACKPORT_NAME in 2 seconds..."
sleep 1s
/bin/echo -e "\e[0K\rInstalling augeas from $BACKPORT_NAME in 1 second ..."
sleep 1s
add_backports=1
else
read -p "Would you like to enable the $BACKPORT_NAME repository [Y/n]? " response
case $response in
[yY][eE][sS]|[yY]|"")
add_backports=1;;
*)
add_backports=0;;
esac
fi
if [ "$add_backports" = 1 ]; then
sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list"
apt-get $QUIET_FLAG update
fi
fi
fi
if [ "$add_backports" != 0 ]; then
apt-get install $QUIET_FLAG $YES_FLAG --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg
augeas_pkg=
fi
}
if dpkg --compare-versions 1.0 gt "$AUGVERSION" ; then
if lsb_release -a | grep -q wheezy ; then
AddBackportRepo wheezy-backports "deb http://http.debian.net/debian wheezy-backports main"
elif lsb_release -a | grep -q precise ; then
# XXX add ARM case
AddBackportRepo precise-backports "deb http://archive.ubuntu.com/ubuntu precise-backports main restricted universe multiverse"
else
echo "No libaugeas0 version is available that's new enough to run the"
echo "Certbot apache plugin..."
fi
# XXX add a case for ubuntu PPAs
fi
apt-get install $QUIET_FLAG $YES_FLAG --no-install-recommends \
python \
python-dev \
@ -1140,9 +1088,9 @@ parsedatetime==2.1 \
pbr==1.8.1 \
--hash=sha256:46c8db75ae75a056bd1cc07fa21734fe2e603d11a07833ecc1eeb74c35c72e0c \
--hash=sha256:e2127626a91e6c885db89668976db31020f0af2da728924b56480fc7ccf09649
pyOpenSSL==16.2.0 \
--hash=sha256:26ca380ddf272f7556e48064bbcd5bd71f83dfc144f3583501c7ddbd9434ee17 \
--hash=sha256:7779a3bbb74e79db234af6a08775568c6769b5821faecf6e2f4143edb227516e
pyOpenSSL==18.0.0 \
--hash=sha256:26ff56a6b5ecaf3a2a59f132681e2a80afcc76b4f902f612f518f92c2a1bf854 \
--hash=sha256:6488f1423b00f73b7ad5167885312bb0ce410d3312eb212393795b53c8caa580
pyparsing==2.1.8 \
--hash=sha256:2f0f5ceb14eccd5aef809d6382e87df22ca1da583c79f6db01675ce7d7f49c18 \
--hash=sha256:03a4869b9f3493807ee1f1cb405e6d576a1a2ca4d81a982677c0c1ad6177c56b \
@ -1232,18 +1180,18 @@ letsencrypt==0.7.0 \
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
certbot==0.30.2 \
--hash=sha256:e411b72fa86eec1018e6de28e649e8c9c71191a7431dcc77f207b57ca9484c11 \
--hash=sha256:534487cb552ced8e47948ba3d2e7ca12c3a439133fc609485012b1a02fc7776e
acme==0.30.2 \
--hash=sha256:68982576492dfa99c7e2be0fce4371adc9344740b05420ce0ab53238d2bb9b3b \
--hash=sha256:295a5b7fce9f908e6e5cff8c40be1a3daf3e1ebabd2e139a4c87274e68eeb8f2
certbot-apache==0.30.2 \
--hash=sha256:3b7fa4e59772da7c9975ef2a49ceff157c9d7cb31eb9475928b5986d89701a3a \
--hash=sha256:32fa915a8a51810fdfe828ac1361da4425c231d7384891e49e6338e4741464b2
certbot-nginx==0.30.2 \
--hash=sha256:7dc785f6f0c0c57b19cea8d98f9ea8feef53945613967b52c9348c81327010e2 \
--hash=sha256:6ba4dd772d0c7cdfb3383ca325b35639e01ac9e142e4baa6445cd85c7fb59552
certbot==0.31.0 \
--hash=sha256:1a1b4b2675daf5266cc2cf2a44ded44de1d83e9541ffa078913c0e4c3231a1c4 \
--hash=sha256:0c3196f80a102c0f9d82d566ba859efe3b70e9ed4670520224c844fafd930473
acme==0.31.0 \
--hash=sha256:a0c851f6b7845a0faa3a47a3e871440eed9ec11b4ab949de0dc4a0fb1201cd24 \
--hash=sha256:7e5c2d01986e0f34ca08fee58981892704c82c48435dcd3592b424c312d8b2bf
certbot-apache==0.31.0 \
--hash=sha256:740bb55dd71723a21eebabb16e6ee5d8883f8b8f8cf6956dd1d4873e0cccae21 \
--hash=sha256:cc4b840b2a439a63e2dce809272c3c3cd4b1aeefc4053cd188935135be137edd
certbot-nginx==0.31.0 \
--hash=sha256:7a1ffda9d93dc7c2aaf89452ce190250de8932e624d31ebba8e4fa7d950025c5 \
--hash=sha256:d450d75650384f74baccb7673c89e2f52468afa478ed354eb6d4b99aa33bf865
UNLIKELY_EOF
# -------------------------------------------------------------------------

View file

@ -4,7 +4,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.31.0.dev0'
version = '0.32.0.dev0'
install_requires = [
'certbot',

View file

@ -2,7 +2,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.31.0.dev0'
version = '0.32.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View file

@ -1,2 +1,2 @@
-e acme[dev]
-e .[dev]
acme[dev]==0.31.0
certbot[dev]==0.31.0

View file

@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.31.0.dev0'
version = '0.32.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.31.0.dev0',
'certbot>=0.31.0.dev0',
'acme>=0.31.0',
'certbot>=0.31.0',
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
'mock',
'setuptools',

View file

@ -2,7 +2,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.31.0.dev0'
version = '0.32.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View file

@ -1,2 +1,2 @@
-e acme[dev]
-e .[dev]
acme[dev]==0.31.0
certbot[dev]==0.31.0

View file

@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.31.0.dev0'
version = '0.32.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.31.0.dev0',
'certbot>=0.31.0.dev0',
'acme>=0.31.0',
'certbot>=0.31.0',
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
'mock',
'setuptools',

View file

@ -1,2 +1,2 @@
-e acme[dev]
-e .[dev]
acme[dev]==0.31.0
certbot[dev]==0.31.0

View file

@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.31.0.dev0'
version = '0.32.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.31.0.dev0',
'certbot>=0.31.0.dev0',
'acme>=0.31.0',
'certbot>=0.31.0',
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
'mock',
'setuptools',

View file

@ -1,2 +1,2 @@
-e acme[dev]
-e .[dev]
acme[dev]==0.31.0
certbot[dev]==0.31.0

View file

@ -2,12 +2,12 @@ from setuptools import setup
from setuptools import find_packages
version = '0.31.0.dev0'
version = '0.32.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [
'acme>=0.31.0.dev0',
'certbot>=0.31.0.dev0',
'acme>=0.31.0',
'certbot>=0.31.0',
'dns-lexicon>=2.1.22',
'mock',
'setuptools',

View file

@ -2,7 +2,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.31.0.dev0'
version = '0.32.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View file

@ -1,2 +1,2 @@
-e acme[dev]
-e .[dev]
acme[dev]==0.31.0
certbot[dev]==0.31.0

View file

@ -1,12 +1,12 @@
from setuptools import setup
from setuptools import find_packages
version = '0.31.0.dev0'
version = '0.32.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [
'acme>=0.31.0.dev0',
'certbot>=0.31.0.dev0',
'acme>=0.31.0',
'certbot>=0.31.0',
'dns-lexicon>=2.2.1',
'mock',
'setuptools',

View file

@ -1,2 +1,2 @@
-e acme[dev]
-e .[dev]
acme[dev]==0.31.0
certbot[dev]==0.31.0

View file

@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.31.0.dev0'
version = '0.32.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.31.0.dev0',
'certbot>=0.31.0.dev0',
'acme>=0.31.0',
'certbot>=0.31.0',
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
'mock',
'setuptools',

View file

@ -1,2 +1,2 @@
-e acme[dev]
-e .[dev]
acme[dev]==0.31.0
certbot[dev]==0.31.0

View file

@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.31.0.dev0'
version = '0.32.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.31.0.dev0',
'certbot>=0.31.0.dev0',
'acme>=0.31.0',
'certbot>=0.31.0',
'dns-lexicon>=2.2.1', # Support for >1 TXT record per name
'mock',
'setuptools',

View file

@ -1,3 +1,3 @@
-e acme[dev]
-e .[dev]
acme[dev]==0.31.0
certbot[dev]==0.31.0
dns-lexicon==2.7.14

View file

@ -2,13 +2,13 @@ from setuptools import setup
from setuptools import find_packages
version = '0.31.0.dev0'
version = '0.32.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.31.0.dev0',
'certbot>=0.31.0.dev0',
'acme>=0.31.0',
'certbot>=0.31.0',
'dns-lexicon>=2.7.14', # Correct proxy use on OVH provider
'mock',
'setuptools',

View file

@ -2,7 +2,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.31.0.dev0'
version = '0.32.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View file

@ -1,7 +1,7 @@
from setuptools import setup
from setuptools import find_packages
version = '0.31.0.dev0'
version = '0.32.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View file

@ -1,2 +1,2 @@
-e acme[dev]
-e .[dev]
acme[dev]==0.31.0
certbot[dev]==0.31.0

View file

@ -2,12 +2,12 @@ from setuptools import setup
from setuptools import find_packages
version = '0.31.0.dev0'
version = '0.32.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [
'acme>=0.31.0.dev0',
'certbot>=0.31.0.dev0',
'acme>=0.31.0',
'certbot>=0.31.0',
'dns-lexicon>=2.1.23',
'mock',
'setuptools',

View file

@ -2,7 +2,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.31.0.dev0'
version = '0.32.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View file

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

View file

@ -13,13 +13,6 @@ import stat
from certbot import errors
try:
# Linux specific
import fcntl # pylint: disable=import-error
except ImportError:
# Windows specific
import msvcrt # pylint: disable=import-error
UNPRIVILEGED_SUBCOMMANDS_ALLOWED = [
'certificates', 'enhance', 'revoke', 'delete',
'register', 'unregister', 'config_changes', 'plugins']
@ -118,55 +111,6 @@ def readline_with_timeout(timeout, prompt):
return sys.stdin.readline()
def lock_file(fd):
"""
Lock the file linked to the specified file descriptor.
:param int fd: The file descriptor of the file to lock.
"""
if 'fcntl' in sys.modules:
# Linux specific
fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
else:
# Windows specific
msvcrt.locking(fd, msvcrt.LK_NBLCK, 1)
def release_locked_file(fd, path):
"""
Remove, close, and release a lock file specified by its file descriptor and its path.
:param int fd: The file descriptor of the lock file.
:param str path: The path of the lock file.
"""
# Linux specific
#
# It is important the lock file is removed before it's released,
# otherwise:
#
# process A: open lock file
# process B: release lock file
# process A: lock file
# process A: check device and inode
# process B: delete file
# process C: open and lock a different file at the same path
try:
os.remove(path)
except OSError as err:
if err.errno == errno.EACCES:
# Windows specific
# We will not be able to remove a file before closing it.
# To avoid race conditions described for Linux, we will not delete the lockfile,
# just close it to be reused on the next Certbot call.
pass
else:
raise
finally:
os.close(fd)
def compare_file_modes(mode1, mode2):
"""Return true if the two modes can be considered as equals for this platform"""
if os.name != 'nt':

View file

@ -1,15 +1,23 @@
"""Implements file locks for locking files and directories in UNIX."""
"""Implements file locks compatible with Linux and Windows for locking files and directories."""
import errno
import logging
import os
try:
import fcntl # pylint: disable=import-error
except ImportError:
import msvcrt # pylint: disable=import-error
POSIX_MODE = False
else:
POSIX_MODE = True
from certbot import compat
from certbot import errors
from acme.magic_typing import Optional, Callable # pylint: disable=unused-import, no-name-in-module
logger = logging.getLogger(__name__)
def lock_dir(dir_path):
# type: (str) -> LockFile
"""Place a lock file on the directory at dir_path.
The lock file is placed in the root of dir_path with the name
@ -27,34 +35,99 @@ def lock_dir(dir_path):
class LockFile(object):
"""A UNIX lock file.
This lock file is released when the locked file is closed or the
process exits. It cannot be used to provide synchronization between
threads. It is based on the lock_file package by Martin Horcicka.
"""
Platform independent file lock system.
LockFile accepts a parameter, the path to a file acting as a lock. Once the LockFile,
instance is created, the associated file is 'locked from the point of view of the OS,
meaning that if another instance of Certbot try at the same time to acquire the same lock,
it will raise an Exception. Calling release method will release the lock, and make it
available to every other instance.
Upon exit, Certbot will also release all the locks.
This allows us to protect a file or directory from being concurrently accessed
or modified by two Certbot instances.
LockFile is platform independent: it will proceed to the appropriate OS lock mechanism
depending on Linux or Windows.
"""
def __init__(self, path):
"""Initialize and acquire the lock file.
:param str path: path to the file to lock
:raises errors.LockError: if unable to acquire the lock
# type: (str) -> None
"""
Create a LockFile instance on the given file path, and acquire lock.
:param str path: the path to the file that will hold a lock
"""
super(LockFile, self).__init__()
self._path = path
self._fd = None
mechanism = _UnixLockMechanism if POSIX_MODE else _WindowsLockMechanism
self._lock_mechanism = mechanism(path)
self.acquire()
def __repr__(self):
# type: () -> str
repr_str = '{0}({1}) <'.format(self.__class__.__name__, self._path)
if self.is_locked():
repr_str += 'acquired>'
else:
repr_str += 'released>'
return repr_str
def acquire(self):
"""Acquire the lock file.
:raises errors.LockError: if lock is already held
:raises OSError: if unable to open or stat the lock file
# type: () -> None
"""
Acquire the lock on the file, forbidding any other Certbot instance to acquire it.
:raises errors.LockError: if unable to acquire the lock
"""
self._lock_mechanism.acquire()
def release(self):
# type: () -> None
"""
Release the lock on the file, allowing any other Certbot instance to acquire it.
"""
self._lock_mechanism.release()
def is_locked(self):
# type: () -> bool
"""
Check if the file is currently locked.
:return: True if the file is locked, False otherwise
"""
return self._lock_mechanism.is_locked()
class _BaseLockMechanism(object):
def __init__(self, path):
# type: (str) -> None
"""
Create a lock file mechanism for Unix.
:param str path: the path to the lock file
"""
self._path = path
self._fd = None # type: Optional[int]
def is_locked(self):
# type: () -> bool
"""Check if lock file is currently locked.
:return: True if the lock file is locked
:rtype: bool
"""
return self._fd is not None
def acquire(self): # pylint: disable=missing-docstring
pass # pragma: no cover
def release(self): # pylint: disable=missing-docstring
pass # pragma: no cover
class _UnixLockMechanism(_BaseLockMechanism):
"""
A UNIX lock file mechanism.
This lock file is released when the locked file is closed or the
process exits. It cannot be used to provide synchronization between
threads. It is based on the lock_file package by Martin Horcicka.
"""
def acquire(self):
# type: () -> None
"""Acquire the lock."""
while self._fd is None:
# Open the file
fd = os.open(self._path, os.O_CREAT | os.O_WRONLY, 0o600)
@ -68,33 +141,29 @@ class LockFile(object):
os.close(fd)
def _try_lock(self, fd):
"""Try to acquire the lock file without blocking.
# type: (int) -> None
"""
Try to acquire the lock file without blocking.
:param int fd: file descriptor of the opened file to lock
"""
try:
compat.lock_file(fd)
fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError as err:
if err.errno in (errno.EACCES, errno.EAGAIN):
logger.debug(
"A lock on %s is held by another process.", self._path)
raise errors.LockError(
"Another instance of Certbot is already running.")
logger.debug('A lock on %s is held by another process.', self._path)
raise errors.LockError('Another instance of Certbot is already running.')
raise
def _lock_success(self, fd):
"""Did we successfully grab the lock?
# type: (int) -> bool
"""
Did we successfully grab the lock?
Because this class deletes the locked file when the lock is
released, it is possible another process removed and recreated
the file between us opening the file and acquiring the lock.
:param int fd: file descriptor of the opened file to lock
:returns: True if the lock was successfully acquired
:rtype: bool
"""
try:
stat1 = os.stat(self._path)
@ -108,17 +177,75 @@ class LockFile(object):
# the same device and inode, they're the same file.
return stat1.st_dev == stat2.st_dev and stat1.st_ino == stat2.st_ino
def __repr__(self):
repr_str = '{0}({1}) <'.format(self.__class__.__name__, self._path)
if self._fd is None:
repr_str += 'released>'
else:
repr_str += 'acquired>'
return repr_str
def release(self):
# type: () -> None
"""Remove, close, and release the lock file."""
# It is important the lock file is removed before it's released,
# otherwise:
#
# process A: open lock file
# process B: release lock file
# process A: lock file
# process A: check device and inode
# process B: delete file
# process C: open and lock a different file at the same path
try:
os.remove(self._path)
finally:
# Following check is done to make mypy happy: it ensure that self._fd, marked
# as Optional[int] is effectively int to make it compatible with os.close signature.
if self._fd is None: # pragma: no cover
raise TypeError('Error, self._fd is None.')
try:
os.close(self._fd)
finally:
self._fd = None
class _WindowsLockMechanism(_BaseLockMechanism):
"""
A Windows lock file mechanism.
By default on Windows, acquiring a file handler gives exclusive access to the process
and results in an effective lock. However, it is possible to explicitly acquire the
file handler in shared access in terms of read and write, and this is done by os.open
and io.open in Python. So an explicit lock needs to be done through the call of
msvcrt.locking, that will lock the first byte of the file. In theory, it is also
possible to access a file in shared delete access, allowing other processes to delete an
opened file. But this needs also to be done explicitly by all processes using the Windows
low level APIs, and Python does not do it. As of Python 3.7 and below, Python developers
state that deleting a file opened by a process from another process is not possible with
os.open and io.open.
Consequently, mscvrt.locking is sufficient to obtain an effective lock, and the race
condition encountered on Linux is not possible on Windows, leading to a simpler workflow.
"""
def acquire(self):
"""Acquire the lock"""
open_mode = os.O_RDWR | os.O_CREAT | os.O_TRUNC
fd = os.open(self._path, open_mode, 0o600)
try:
msvcrt.locking(fd, msvcrt.LK_NBLCK, 1)
except (IOError, OSError) as err:
os.close(fd)
# Anything except EACCES is unexpected. Raise directly the error in that case.
if err.errno != errno.EACCES:
raise
logger.debug('A lock on %s is held by another process.', self._path)
raise errors.LockError('Another instance of Certbot is already running.')
self._fd = fd
def release(self):
"""Remove, close, and release the lock file."""
"""Release the lock."""
try:
compat.release_locked_file(self._fd, self._path)
msvcrt.locking(self._fd, msvcrt.LK_UNLCK, 1)
os.close(self._fd)
try:
os.remove(self._path)
except OSError as e:
# If the lock file cannot be removed, it is not a big deal.
# Likely another instance is acquiring the lock we just released.
logger.debug(str(e))
finally:
self._fd = None

View file

@ -3,6 +3,12 @@ import functools
import multiprocessing
import os
import unittest
try:
import fcntl # pylint: disable=import-error,unused-import
except ImportError:
POSIX_MODE = False
else:
POSIX_MODE = True
import mock
@ -10,7 +16,6 @@ from certbot import errors
from certbot.tests import util as test_util
@test_util.broken_on_windows
class LockDirTest(test_util.TempDirTestCase):
"""Tests for certbot.lock.lock_dir."""
@classmethod
@ -25,7 +30,6 @@ class LockDirTest(test_util.TempDirTestCase):
test_util.lock_and_call(assert_raises, lock_path)
@test_util.broken_on_windows
class LockFileTest(test_util.TempDirTestCase):
"""Tests for certbot.lock.LockFile."""
@classmethod
@ -71,6 +75,8 @@ class LockFileTest(test_util.TempDirTestCase):
self.assertTrue(lock_file.__class__.__name__ in lock_repr)
self.assertTrue(self.lock_path in lock_repr)
@test_util.skip_on_windows(
'Race conditions on lock are specific to the non-blocking file access approach on Linux.')
def test_race(self):
should_delete = [True, False]
stat = os.stat
@ -91,27 +97,36 @@ class LockFileTest(test_util.TempDirTestCase):
lock_file.release()
self.assertFalse(os.path.exists(self.lock_path))
@mock.patch('certbot.compat.fcntl.lockf')
def test_unexpected_lockf_err(self, mock_lockf):
def test_unexpected_lockf_or_locking_err(self):
if POSIX_MODE:
mocked_function = 'certbot.lock.fcntl.lockf'
else:
mocked_function = 'certbot.lock.msvcrt.locking'
msg = 'hi there'
mock_lockf.side_effect = IOError(msg)
try:
self._call(self.lock_path)
except IOError as err:
self.assertTrue(msg in str(err))
else: # pragma: no cover
self.fail('IOError not raised')
with mock.patch(mocked_function) as mock_lock:
mock_lock.side_effect = IOError(msg)
try:
self._call(self.lock_path)
except IOError as err:
self.assertTrue(msg in str(err))
else: # pragma: no cover
self.fail('IOError not raised')
@mock.patch('certbot.lock.os.stat')
def test_unexpected_stat_err(self, mock_stat):
def test_unexpected_os_err(self):
if POSIX_MODE:
mock_function = 'certbot.lock.os.stat'
else:
mock_function = 'certbot.lock.msvcrt.locking'
# The only expected errno are ENOENT and EACCES in lock module.
msg = 'hi there'
mock_stat.side_effect = OSError(msg)
try:
self._call(self.lock_path)
except OSError as err:
self.assertTrue(msg in str(err))
else: # pragma: no cover
self.fail('OSError not raised')
with mock.patch(mock_function) as mock_os:
mock_os.side_effect = OSError(msg)
try:
self._call(self.lock_path)
except OSError as err:
self.assertTrue(msg in str(err))
else: # pragma: no cover
self.fail('OSError not raised')
if __name__ == "__main__":

View file

@ -3,7 +3,6 @@
.. warning:: This module is not part of the public API.
"""
import multiprocessing
import os
import pkg_resources
import shutil
@ -11,6 +10,8 @@ import tempfile
import unittest
import sys
import warnings
import subprocess
import time
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization
@ -23,8 +24,8 @@ from six.moves import reload_module # pylint: disable=import-error
from certbot import constants
from certbot import interfaces
from certbot import storage
from certbot import util
from certbot import configuration
from certbot import util
from certbot.display import util as display_util
@ -211,7 +212,7 @@ class FreezableMock(object):
"""
def __init__(self, frozen=False, func=None, return_value=mock.sentinel.DEFAULT):
self._frozen_set = set() if frozen else set(('freeze',))
self._frozen_set = set() if frozen else {'freeze', }
self._func = func
self._mock = mock.MagicMock()
if return_value != mock.sentinel.DEFAULT:
@ -340,6 +341,7 @@ class TempDirTestCase(unittest.TestCase):
warnings.warn(message)
shutil.rmtree(self.tempdir, onerror=onerror_handler)
class ConfigTestCase(TempDirTestCase):
"""Test class which sets up a NamespaceConfig object.
@ -358,47 +360,58 @@ class ConfigTestCase(TempDirTestCase):
self.config.chain_path = constants.CLI_DEFAULTS['auth_chain_path']
self.config.server = "https://example.com"
def lock_and_call(func, lock_path):
"""Grab a lock for lock_path and call func.
:param callable func: object to call after acquiring the lock
:param str lock_path: path to file or directory to lock
def lock_and_call(callback, path_to_lock):
"""Grab a lock on path_to_lock from a foreign process and call the callback.
:param callable callback: object to call after acquiring the lock
:param str path_to_lock: path to file or directory to lock
"""
# Reload module to reset internal _LOCKS dictionary
script = """\
import os
import sys
import time
from certbot import lock
path_to_lock = sys.argv[1]
trigger = sys.argv[2]
if os.path.isdir(path_to_lock):
my_lock = lock.lock_dir(path_to_lock)
else:
my_lock = lock.LockFile(path_to_lock)
try:
open(trigger, 'w').close()
while os.path.exists(trigger):
time.sleep(1)
finally:
my_lock.release()
"""
# Reload certbot.util module to reset internal _LOCKS dictionary.
reload_module(util)
# start child and wait for it to grab the lock
cv = multiprocessing.Condition()
cv.acquire()
child_args = (cv, lock_path,)
child = multiprocessing.Process(target=hold_lock, args=child_args)
child.start()
cv.wait()
workspace = tempfile.mkdtemp()
try:
tmp_script = os.path.join(workspace, 'test_script.py')
with open(tmp_script, 'w') as file_handle:
file_handle.write(script)
# call func and terminate the child
func()
cv.notify()
cv.release()
child.join()
assert child.exitcode == 0
# Trigger file is used to coordinate current process and its subprocess.
trigger = os.path.join(workspace, 'trigger')
process = subprocess.Popen([sys.executable, tmp_script, path_to_lock, trigger])
try:
# Poll and wait for the lock to be acquired, spotted by the trigger file creation.
while not os.path.exists(trigger):
time.sleep(1)
# Then execute the callback.
callback()
finally:
# This will trigger the lock release in subprocess.
os.remove(trigger)
process.communicate()
assert process.returncode == 0
finally:
shutil.rmtree(workspace)
def hold_lock(cv, lock_path): # pragma: no cover
"""Acquire a file lock at lock_path and wait to release it.
:param multiprocessing.Condition cv: condition for synchronization
:param str lock_path: path to the file lock
"""
from certbot import lock
if os.path.isdir(lock_path):
my_lock = lock.lock_dir(lock_path)
else:
my_lock = lock.LockFile(lock_path)
cv.acquire()
cv.notify()
cv.wait()
my_lock.release()
def skip_on_windows(reason):
"""Decorator to skip permanently a test on Windows. A reason is required."""
@ -407,6 +420,7 @@ def skip_on_windows(reason):
return unittest.skipIf(sys.platform == 'win32', reason)(function)
return wrapper
def broken_on_windows(function):
"""Decorator to skip temporarily a broken test on Windows."""
reason = 'Test is broken and ignored on windows but should be fixed.'
@ -415,9 +429,10 @@ def broken_on_windows(function):
and os.environ.get('SKIP_BROKEN_TESTS_ON_WINDOWS', 'true') == 'true',
reason)(function)
def temp_join(path):
"""
Return the given path joined to the tempdir path for the current platform
Eg.: 'cert' => /tmp/cert (Linux) or 'C:\\Users\\currentuser\\AppData\\Temp\\cert' (Windows)
"""
return os.path.join(tempfile.gettempdir(), path)
return os.path.join(tempfile.gettempdir(), path)

View file

@ -2,7 +2,6 @@
import argparse
import errno
import os
import shutil
import unittest
import mock
@ -88,7 +87,6 @@ class LockDirUntilExit(test_util.TempDirTestCase):
import certbot.util
reload_module(certbot.util)
@test_util.broken_on_windows
@mock.patch('certbot.util.logger')
@mock.patch('certbot.util.atexit_register')
def test_it(self, mock_register, mock_logger):
@ -100,11 +98,15 @@ class LockDirUntilExit(test_util.TempDirTestCase):
self.assertEqual(mock_register.call_count, 1)
registered_func = mock_register.call_args[0][0]
shutil.rmtree(subdir)
registered_func() # exception not raised
# logger.debug is only called once because the second call
# to lock subdir was ignored because it was already locked
self.assertEqual(mock_logger.debug.call_count, 1)
from certbot import util
# Despite lock_dir_until_exit has been called twice to subdir, its lock should have been
# added only once. So we expect to have two lock references: for self.tempdir and subdir
self.assertTrue(len(util._LOCKS) == 2) # pylint: disable=protected-access
registered_func() # Exception should not be raised
# Logically, logger.debug, that would be invoked in case of unlock failure,
# should never been called.
self.assertEqual(mock_logger.debug.call_count, 0)
class SetUpCoreDirTest(test_util.TempDirTestCase):

View file

@ -113,7 +113,7 @@ optional arguments:
case, and to know when to deprecate support for past
Python versions and flags. If you wish to hide this
information from the Let's Encrypt server, set this to
"". (default: CertbotACMEClient/0.30.2
"". (default: CertbotACMEClient/0.31.0
(certbot(-auto); OS_NAME OS_VERSION) Authenticator/XXX
Installer/YYY (SUBCOMMAND; flags: FLAGS)
Py/major.minor.patchlevel). The flags encoded in the
@ -351,8 +351,9 @@ revoke:
Specify reason for revoking certificate. (default:
unspecified)
--delete-after-revoke
Delete certificates after revoking them. (default:
None)
Delete certificates after revoking them, along with
all previous and later versions of those certificates.
(default: None)
--no-delete-after-revoke
Do not delete certificates after revoking them. This
option should be used with caution because the 'renew'
@ -479,10 +480,9 @@ apache:
Apache Web Server plugin
--apache-enmod APACHE_ENMOD
Path to the Apache 'a2enmod' binary (default: a2enmod)
Path to the Apache 'a2enmod' binary (default: None)
--apache-dismod APACHE_DISMOD
Path to the Apache 'a2dismod' binary (default:
a2dismod)
Path to the Apache 'a2dismod' binary (default: None)
--apache-le-vhost-ext APACHE_LE_VHOST_EXT
SSL vhost configuration extension (default: -le-
ssl.conf)
@ -496,16 +496,16 @@ apache:
/var/log/apache2)
--apache-challenge-location APACHE_CHALLENGE_LOCATION
Directory path for challenge configuration (default:
/etc/apache2)
/etc/apache2/other)
--apache-handle-modules APACHE_HANDLE_MODULES
Let installer handle enabling required modules for you
(Only Ubuntu/Debian currently) (default: True)
(Only Ubuntu/Debian currently) (default: False)
--apache-handle-sites APACHE_HANDLE_SITES
Let installer handle enabling sites for you (Only
Ubuntu/Debian currently) (default: True)
Ubuntu/Debian currently) (default: False)
--apache-ctl APACHE_CTL
Full path to Apache control script (default:
apache2ctl)
apachectl)
dns-cloudflare:
Obtain certificates using a DNS TXT record (if you are using Cloudflare

View file

@ -31,7 +31,7 @@ if [ -z "$VENV_PATH" ]; then
fi
VENV_BIN="$VENV_PATH/bin"
BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
LE_AUTO_VERSION="0.30.2"
LE_AUTO_VERSION="0.31.0"
BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates
@ -333,63 +333,11 @@ BootstrapDebCommon() {
fi
augeas_pkg="libaugeas0 augeas-lenses"
AUGVERSION=`LC_ALL=C apt-cache show --no-all-versions libaugeas0 | grep ^Version: | cut -d" " -f2`
if [ "$ASSUME_YES" = 1 ]; then
YES_FLAG="-y"
fi
AddBackportRepo() {
# ARGS:
BACKPORT_NAME="$1"
BACKPORT_SOURCELINE="$2"
say "To use the Apache Certbot plugin, augeas needs to be installed from $BACKPORT_NAME."
if ! grep -v -e ' *#' /etc/apt/sources.list | grep -q "$BACKPORT_NAME" ; then
# This can theoretically error if sources.list.d is empty, but in that case we don't care.
if ! grep -v -e ' *#' /etc/apt/sources.list.d/* 2>/dev/null | grep -q "$BACKPORT_NAME"; then
if [ "$ASSUME_YES" = 1 ]; then
/bin/echo -n "Installing augeas from $BACKPORT_NAME in 3 seconds..."
sleep 1s
/bin/echo -ne "\e[0K\rInstalling augeas from $BACKPORT_NAME in 2 seconds..."
sleep 1s
/bin/echo -e "\e[0K\rInstalling augeas from $BACKPORT_NAME in 1 second ..."
sleep 1s
add_backports=1
else
read -p "Would you like to enable the $BACKPORT_NAME repository [Y/n]? " response
case $response in
[yY][eE][sS]|[yY]|"")
add_backports=1;;
*)
add_backports=0;;
esac
fi
if [ "$add_backports" = 1 ]; then
sh -c "echo $BACKPORT_SOURCELINE >> /etc/apt/sources.list.d/$BACKPORT_NAME.list"
apt-get $QUIET_FLAG update
fi
fi
fi
if [ "$add_backports" != 0 ]; then
apt-get install $QUIET_FLAG $YES_FLAG --no-install-recommends -t "$BACKPORT_NAME" $augeas_pkg
augeas_pkg=
fi
}
if dpkg --compare-versions 1.0 gt "$AUGVERSION" ; then
if lsb_release -a | grep -q wheezy ; then
AddBackportRepo wheezy-backports "deb http://http.debian.net/debian wheezy-backports main"
elif lsb_release -a | grep -q precise ; then
# XXX add ARM case
AddBackportRepo precise-backports "deb http://archive.ubuntu.com/ubuntu precise-backports main restricted universe multiverse"
else
echo "No libaugeas0 version is available that's new enough to run the"
echo "Certbot apache plugin..."
fi
# XXX add a case for ubuntu PPAs
fi
apt-get install $QUIET_FLAG $YES_FLAG --no-install-recommends \
python \
python-dev \
@ -1140,9 +1088,9 @@ parsedatetime==2.1 \
pbr==1.8.1 \
--hash=sha256:46c8db75ae75a056bd1cc07fa21734fe2e603d11a07833ecc1eeb74c35c72e0c \
--hash=sha256:e2127626a91e6c885db89668976db31020f0af2da728924b56480fc7ccf09649
pyOpenSSL==16.2.0 \
--hash=sha256:26ca380ddf272f7556e48064bbcd5bd71f83dfc144f3583501c7ddbd9434ee17 \
--hash=sha256:7779a3bbb74e79db234af6a08775568c6769b5821faecf6e2f4143edb227516e
pyOpenSSL==18.0.0 \
--hash=sha256:26ff56a6b5ecaf3a2a59f132681e2a80afcc76b4f902f612f518f92c2a1bf854 \
--hash=sha256:6488f1423b00f73b7ad5167885312bb0ce410d3312eb212393795b53c8caa580
pyparsing==2.1.8 \
--hash=sha256:2f0f5ceb14eccd5aef809d6382e87df22ca1da583c79f6db01675ce7d7f49c18 \
--hash=sha256:03a4869b9f3493807ee1f1cb405e6d576a1a2ca4d81a982677c0c1ad6177c56b \
@ -1232,18 +1180,18 @@ letsencrypt==0.7.0 \
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
certbot==0.30.2 \
--hash=sha256:e411b72fa86eec1018e6de28e649e8c9c71191a7431dcc77f207b57ca9484c11 \
--hash=sha256:534487cb552ced8e47948ba3d2e7ca12c3a439133fc609485012b1a02fc7776e
acme==0.30.2 \
--hash=sha256:68982576492dfa99c7e2be0fce4371adc9344740b05420ce0ab53238d2bb9b3b \
--hash=sha256:295a5b7fce9f908e6e5cff8c40be1a3daf3e1ebabd2e139a4c87274e68eeb8f2
certbot-apache==0.30.2 \
--hash=sha256:3b7fa4e59772da7c9975ef2a49ceff157c9d7cb31eb9475928b5986d89701a3a \
--hash=sha256:32fa915a8a51810fdfe828ac1361da4425c231d7384891e49e6338e4741464b2
certbot-nginx==0.30.2 \
--hash=sha256:7dc785f6f0c0c57b19cea8d98f9ea8feef53945613967b52c9348c81327010e2 \
--hash=sha256:6ba4dd772d0c7cdfb3383ca325b35639e01ac9e142e4baa6445cd85c7fb59552
certbot==0.31.0 \
--hash=sha256:1a1b4b2675daf5266cc2cf2a44ded44de1d83e9541ffa078913c0e4c3231a1c4 \
--hash=sha256:0c3196f80a102c0f9d82d566ba859efe3b70e9ed4670520224c844fafd930473
acme==0.31.0 \
--hash=sha256:a0c851f6b7845a0faa3a47a3e871440eed9ec11b4ab949de0dc4a0fb1201cd24 \
--hash=sha256:7e5c2d01986e0f34ca08fee58981892704c82c48435dcd3592b424c312d8b2bf
certbot-apache==0.31.0 \
--hash=sha256:740bb55dd71723a21eebabb16e6ee5d8883f8b8f8cf6956dd1d4873e0cccae21 \
--hash=sha256:cc4b840b2a439a63e2dce809272c3c3cd4b1aeefc4053cd188935135be137edd
certbot-nginx==0.31.0 \
--hash=sha256:7a1ffda9d93dc7c2aaf89452ce190250de8932e624d31ebba8e4fa7d950025c5 \
--hash=sha256:d450d75650384f74baccb7673c89e2f52468afa478ed354eb6d4b99aa33bf865
UNLIKELY_EOF
# -------------------------------------------------------------------------

View file

@ -1,11 +1,11 @@
-----BEGIN PGP SIGNATURE-----
iQEzBAABCAAdFiEEos+1H6J1pyhiNOeyTRfJlc2XdfIFAlxLcw8ACgkQTRfJlc2X
dfK35gf+PoxtrJJIjvybNqd3lb8HOg2ntIVmXcYJGuuUo6m09fzai+XI6cOm5Dpu
l2D5OrbLqmez8tYkCkEWHV0OfwyVWw+m8T3sXlcrv14eA1RfgMnZ+cmmlpDskzHU
EOtaXo1/IkLDwBRrsl8IUbwD2XxbjuLsA2Sevoa59NlfTXJUApfAzohl3epRiJjB
gugdqcsfjRRAqQqOz+iJCKBCWSTIrr/g6Y9aZu9V93t/WDSLRFjehxO1GQrLnCnX
17JGlr0/AXd67jOKS1OWmORPPAFfLIXezUMtgrz5hE7T5UviaUu9ySV8UCxq1N79
cfSBb/HIUxZ0wf1CkTUMRFQpA7cGtw==
=cNcT
iQEzBAABCAAdFiEEos+1H6J1pyhiNOeyTRfJlc2XdfIFAlxcop8ACgkQTRfJlc2X
dfIbZwf/faKu7IjLi0qFQ+kw8zaAnV47JDgfWqbR5GSdwWPqld+QyHlcRfPgwYma
fKj9+g/FvPNPSfjHRRCoFrYvpZ4lZ+f4HPN9+OjydfM77rdDhVDwzs8dbKIk02yU
0IEJhXj5Q9hF3TSDZcyXAJdBU1lz51ohtVIXelMBPmzhYPCZF47iE9/k9pApQi86
RTji7hxPcF/n7mzXrbyTvk+kDxSdDlE0Eg9syK7XaFDBTa2lqgG8wTnMPVqhc/hm
WM/uwkzbYarjy05ffV1kM683nP0rECnHlYT38pYcT2puw2kn/QthwR5j/jB/DWSc
94Kw7BeMH651V8EaNwYIiouylnVH3A==
=U+Qh
-----END PGP SIGNATURE-----

View file

@ -31,7 +31,7 @@ if [ -z "$VENV_PATH" ]; then
fi
VENV_BIN="$VENV_PATH/bin"
BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
LE_AUTO_VERSION="0.31.0.dev0"
LE_AUTO_VERSION="0.32.0.dev0"
BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates
@ -1180,18 +1180,18 @@ letsencrypt==0.7.0 \
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
certbot==0.30.2 \
--hash=sha256:e411b72fa86eec1018e6de28e649e8c9c71191a7431dcc77f207b57ca9484c11 \
--hash=sha256:534487cb552ced8e47948ba3d2e7ca12c3a439133fc609485012b1a02fc7776e
acme==0.30.2 \
--hash=sha256:68982576492dfa99c7e2be0fce4371adc9344740b05420ce0ab53238d2bb9b3b \
--hash=sha256:295a5b7fce9f908e6e5cff8c40be1a3daf3e1ebabd2e139a4c87274e68eeb8f2
certbot-apache==0.30.2 \
--hash=sha256:3b7fa4e59772da7c9975ef2a49ceff157c9d7cb31eb9475928b5986d89701a3a \
--hash=sha256:32fa915a8a51810fdfe828ac1361da4425c231d7384891e49e6338e4741464b2
certbot-nginx==0.30.2 \
--hash=sha256:7dc785f6f0c0c57b19cea8d98f9ea8feef53945613967b52c9348c81327010e2 \
--hash=sha256:6ba4dd772d0c7cdfb3383ca325b35639e01ac9e142e4baa6445cd85c7fb59552
certbot==0.31.0 \
--hash=sha256:1a1b4b2675daf5266cc2cf2a44ded44de1d83e9541ffa078913c0e4c3231a1c4 \
--hash=sha256:0c3196f80a102c0f9d82d566ba859efe3b70e9ed4670520224c844fafd930473
acme==0.31.0 \
--hash=sha256:a0c851f6b7845a0faa3a47a3e871440eed9ec11b4ab949de0dc4a0fb1201cd24 \
--hash=sha256:7e5c2d01986e0f34ca08fee58981892704c82c48435dcd3592b424c312d8b2bf
certbot-apache==0.31.0 \
--hash=sha256:740bb55dd71723a21eebabb16e6ee5d8883f8b8f8cf6956dd1d4873e0cccae21 \
--hash=sha256:cc4b840b2a439a63e2dce809272c3c3cd4b1aeefc4053cd188935135be137edd
certbot-nginx==0.31.0 \
--hash=sha256:7a1ffda9d93dc7c2aaf89452ce190250de8932e624d31ebba8e4fa7d950025c5 \
--hash=sha256:d450d75650384f74baccb7673c89e2f52468afa478ed354eb6d4b99aa33bf865
UNLIKELY_EOF
# -------------------------------------------------------------------------

View file

@ -1,12 +1,12 @@
certbot==0.30.2 \
--hash=sha256:e411b72fa86eec1018e6de28e649e8c9c71191a7431dcc77f207b57ca9484c11 \
--hash=sha256:534487cb552ced8e47948ba3d2e7ca12c3a439133fc609485012b1a02fc7776e
acme==0.30.2 \
--hash=sha256:68982576492dfa99c7e2be0fce4371adc9344740b05420ce0ab53238d2bb9b3b \
--hash=sha256:295a5b7fce9f908e6e5cff8c40be1a3daf3e1ebabd2e139a4c87274e68eeb8f2
certbot-apache==0.30.2 \
--hash=sha256:3b7fa4e59772da7c9975ef2a49ceff157c9d7cb31eb9475928b5986d89701a3a \
--hash=sha256:32fa915a8a51810fdfe828ac1361da4425c231d7384891e49e6338e4741464b2
certbot-nginx==0.30.2 \
--hash=sha256:7dc785f6f0c0c57b19cea8d98f9ea8feef53945613967b52c9348c81327010e2 \
--hash=sha256:6ba4dd772d0c7cdfb3383ca325b35639e01ac9e142e4baa6445cd85c7fb59552
certbot==0.31.0 \
--hash=sha256:1a1b4b2675daf5266cc2cf2a44ded44de1d83e9541ffa078913c0e4c3231a1c4 \
--hash=sha256:0c3196f80a102c0f9d82d566ba859efe3b70e9ed4670520224c844fafd930473
acme==0.31.0 \
--hash=sha256:a0c851f6b7845a0faa3a47a3e871440eed9ec11b4ab949de0dc4a0fb1201cd24 \
--hash=sha256:7e5c2d01986e0f34ca08fee58981892704c82c48435dcd3592b424c312d8b2bf
certbot-apache==0.31.0 \
--hash=sha256:740bb55dd71723a21eebabb16e6ee5d8883f8b8f8cf6956dd1d4873e0cccae21 \
--hash=sha256:cc4b840b2a439a63e2dce809272c3c3cd4b1aeefc4053cd188935135be137edd
certbot-nginx==0.31.0 \
--hash=sha256:7a1ffda9d93dc7c2aaf89452ce190250de8932e624d31ebba8e4fa7d950025c5 \
--hash=sha256:d450d75650384f74baccb7673c89e2f52468afa478ed354eb6d4b99aa33bf865

View file

@ -38,7 +38,9 @@ install_requires = [
'ConfigArgParse>=0.9.3',
'configobj',
'cryptography>=1.2.3', # load_pem_x509_certificate
'josepy',
# 1.1.0+ is required to avoid the warnings described at
# https://github.com/certbot/josepy/issues/13.
'josepy>=1.1.0',
'mock',
'parsedatetime>=1.3', # Calendar.parseDT
'pyrfc3339',

View file

@ -23,7 +23,7 @@ fi
# started failing on newer distros with newer versions of OpenSSL.
INITIAL_VERSION="0.17.0"
git checkout -f "v$INITIAL_VERSION" letsencrypt-auto
if ! ./letsencrypt-auto -v --debug --version --no-self-upgrade 2>&1 | grep "$INITIAL_VERSION" ; then
if ! ./letsencrypt-auto -v --debug --version --no-self-upgrade 2>&1 | tail -n1 | grep "^certbot $INITIAL_VERSION$" ; then
echo initial installation appeared to fail
exit 1
fi
@ -85,7 +85,7 @@ if [ $(python -V 2>&1 | cut -d" " -f 2 | cut -d. -f1,2 | sed 's/\.//') -eq 26 ];
fi
# Create a 2nd venv at the new path to ensure we properly handle this case
export VENV_PATH="/opt/eff.org/certbot/venv"
if ! sudo -E ./letsencrypt-auto -v --debug --version --no-self-upgrade 2>&1 | grep "$INITIAL_VERSION" ; then
if ! sudo -E ./letsencrypt-auto -v --debug --version --no-self-upgrade 2>&1 | tail -n1 | grep "^certbot $INITIAL_VERSION$" ; then
echo second installation appeared to fail
exit 1
fi
@ -98,7 +98,7 @@ if ./letsencrypt-auto -v --debug --version | grep "WARNING: couldn't find Python
fi
EXPECTED_VERSION=$(grep -m1 LE_AUTO_VERSION certbot-auto | cut -d\" -f2)
if ! /opt/eff.org/certbot/venv/bin/letsencrypt --version 2>&1 | grep "$EXPECTED_VERSION" ; then
if ! /opt/eff.org/certbot/venv/bin/letsencrypt --version 2>&1 | tail -n1 | grep "^certbot $EXPECTED_VERSION$" ; then
echo upgrade appeared to fail
exit 1
fi

View file

@ -12,6 +12,8 @@ export VENV_ARGS="-p $PYTHON"
# setup venv
tools/_venv_common.py --requirement letsencrypt-auto-source/pieces/dependency-requirements.txt
. ./venv/bin/activate
# pytest is needed to run tests on some of our packages so we install a pinned version here.
tools/pip_install.py pytest
# build sdists
for pkg_dir in acme . $PLUGINS; do

View file

@ -1,18 +1,20 @@
#!/bin/sh -xe
LE_AUTO="letsencrypt/letsencrypt-auto-source/letsencrypt-auto"
REPO_ROOT="letsencrypt"
LE_AUTO="$REPO_ROOT/letsencrypt-auto-source/letsencrypt-auto"
LE_AUTO="$LE_AUTO --debug --no-self-upgrade --non-interactive"
MODULES="acme certbot certbot_apache certbot_nginx"
PIP_INSTALL="$REPO_ROOT/tools/pip_install.py"
VENV_NAME=venv
# *-auto respects VENV_PATH
$LE_AUTO --os-packages-only
LE_AUTO_SUDO="" VENV_PATH="$VENV_NAME" $LE_AUTO --no-bootstrap --version
. $VENV_NAME/bin/activate
"$PIP_INSTALL" pytest
# change to an empty directory to ensure CWD doesn't affect tests
cd $(mktemp -d)
pip install pytest==3.2.5
for module in $MODULES ; do
echo testing $module

View file

@ -2,7 +2,7 @@
# Download and run Pebble instance for integration testing
set -xe
PEBBLE_VERSION=2018-11-02
PEBBLE_VERSION=v1.0.1
# We reuse the same GOPATH-style directory than for Boulder.
# Pebble does not need it, but it will make the installation consistent with Boulder's one.
@ -13,15 +13,32 @@ mkdir -p ${PEBBLEPATH}
cat << UNLIKELY_EOF > "$PEBBLEPATH/docker-compose.yml"
version: '3'
services:
pebble:
image: letsencrypt/pebble:${PEBBLE_VERSION}
command: pebble -strict ${PEBBLE_STRICT:-false} -dnsserver 10.77.77.1
ports:
- 14000:14000
environment:
pebble:
image: letsencrypt/pebble:${PEBBLE_VERSION}
command: pebble -dnsserver 10.30.50.3:8053
environment:
- PEBBLE_VA_NOSLEEP=1
ports:
- 14000:14000
networks:
acmenet:
ipv4_address: 10.30.50.2
challtestsrv:
image: letsencrypt/pebble-challtestsrv:${PEBBLE_VERSION}
command: pebble-challtestsrv -defaultIPv6 "" -defaultIPv4 10.30.50.1
ports:
- 8055:8055
networks:
acmenet:
ipv4_address: 10.30.50.3
networks:
acmenet:
driver: bridge
ipam:
driver: default
config:
- subnet: 10.30.50.0/24
UNLIKELY_EOF
docker-compose -f "$PEBBLEPATH/docker-compose.yml" up -d pebble

View file

@ -166,7 +166,6 @@ passenv =
HOME
GOPATH
PEBBLEPATH
PEBBLE_STRICT
setenv =
SERVER=https://localhost:14000/dir