1
0
mirror of https://github.com/certbot/certbot.git synced 2026-01-26 07:41:33 +03:00

Merge pull request #7321 from certbot/fix-apache-parser-v2-cover

Fix apache-parser-v2 tests
This commit is contained in:
Joona Hoikkala
2019-08-13 15:28:24 +03:00
committed by GitHub
74 changed files with 725 additions and 360 deletions

View File

@@ -162,6 +162,7 @@ Authors
* [Michael Schumacher](https://github.com/schumaml)
* [Michael Strache](https://github.com/Jarodiv)
* [Michael Sverdlin](https://github.com/sveder)
* [Michael Watters](https://github.com/blackknight36)
* [Michal Moravec](https://github.com/https://github.com/Majkl578)
* [Michal Papis](https://github.com/mpapis)
* [Minn Soe](https://github.com/MinnSoe)

View File

@@ -2,7 +2,34 @@
Certbot adheres to [Semantic Versioning](https://semver.org/).
## 0.37.0 - master
## 0.38.0 - master
### Added
*
### Changed
* If Certbot fails to rollback your server configuration, the error message
links to the Let's Encrypt forum. Change the link to the Help category now
that the Server category has been closed.
### Fixed
*
More details about these changes can be found on our GitHub repo.
## 0.37.1 - 2019-08-08
### Fixed
* Stop disabling TLS session tickets in Apache as it caused TLS failures on
some systems.
More details about these changes can be found on our GitHub repo.
## 0.37.0 - 2019-08-07
### Added
@@ -11,11 +38,12 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).
### Changed
*
* Follow updated Mozilla recommendations for Nginx ssl_protocols, ssl_ciphers,
and ssl_prefer_server_ciphers
### Fixed
*
* Fix certbot-auto failures on RHEL 8.
More details about these changes can be found on our GitHub repo.

View File

@@ -3,7 +3,7 @@ from setuptools import find_packages
from setuptools.command.test import test as TestCommand
import sys
version = '0.37.0.dev0'
version = '0.38.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [

View File

@@ -4,6 +4,7 @@ environment:
matrix:
- TOXENV: py35
- TOXENV: py37-cover
- TOXENV: integration-certbot
branches:
only:
@@ -24,14 +25,16 @@ init:
install:
# Use Python 3.7 by default
- "SET PATH=C:\\Python37;C:\\Python37\\Scripts;%PATH%"
- SET PATH=C:\\Python37;C:\\Python37\\Scripts;%PATH%
# Using 4 processes is proven to be the most efficient integration tests config for AppVeyor
- IF %TOXENV%==integration-certbot SET PYTEST_ADDOPTS=--numprocesses=4
# Check env
- "python --version"
- python --version
# Upgrade pip to avoid warnings
- "python -m pip install --upgrade pip"
- python -m pip install --upgrade pip
# Ready to install tox and coverage
# tools/pip_install.py is used to pin packages to a known working version.
- "python tools\\pip_install.py tox codecov"
- python tools\\pip_install.py tox codecov
build: off

View File

@@ -5,4 +5,3 @@ recursive-include certbot_apache/tests/testdata *
include certbot_apache/centos-options-ssl-apache.conf
include certbot_apache/options-ssl-apache.conf
recursive-include certbot_apache/augeas_lens *.aug
recursive-include certbot_apache/tls_configs *.conf

View File

@@ -1,8 +1,6 @@
""" Utility functions for certbot-apache plugin """
import binascii
import pkg_resources
from certbot import util
from certbot.compat import os
@@ -107,15 +105,3 @@ def parse_define_file(filepath, varname):
def unique_id():
""" Returns an unique id to be used as a VirtualHost identifier"""
return binascii.hexlify(os.urandom(16)).decode("utf-8")
def find_ssl_apache_conf(prefix):
"""
Find a TLS Apache config file in the dedicated storage.
:param str prefix: prefix of the TLS Apache config file to find
:return: the path the TLS Apache config file
:rtype: str
"""
return pkg_resources.resource_filename(
"certbot_apache",
os.path.join("tls_configs", "{0}-options-ssl-apache.conf".format(prefix)))

View File

@@ -10,10 +10,16 @@ SSLEngine on
SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
SSLHonorCipherOrder on
SSLSessionTickets off
SSLOptions +StrictRequire
# Add vhost name to log entries:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined
LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common
#CustomLog /var/log/apache2/access.log vhost_combined
#LogLevel warn
#ErrorLog /var/log/apache2/error.log
# Always ensure Cookies have "Secure" set (JAH 2012/1)
#Header edit Set-Cookie (?i)^(.*)(;\s*secure)??((\s*;)?(.*)) "$1; Secure$3$4"

View File

@@ -9,6 +9,7 @@ import time
from collections import defaultdict
import pkg_resources
import six
import zope.component
@@ -109,24 +110,14 @@ class ApacheConfigurator(common.Installer):
handle_modules=False,
handle_sites=False,
challenge_location="/etc/apache2",
MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
"certbot_apache", "options-ssl-apache.conf")
)
def option(self, key):
"""Get a value from options"""
return self.options.get(key)
def pick_apache_config(self):
"""
Pick the appropriate TLS Apache configuration file for current version of Apache and OS.
:return: the path to the TLS Apache configuration file to use
:rtype: str
"""
# Disabling TLS session tickets is supported by Apache 2.4.11+.
# So for old versions of Apache we pick a configuration without this option.
if self.version < (2, 4, 11):
return apache_util.find_ssl_apache_conf("old")
return apache_util.find_ssl_apache_conf("current")
def _prepare_options(self):
"""
Set the values possibly changed by command line parameters to
@@ -2348,9 +2339,8 @@ class ApacheConfigurator(common.Installer):
# XXX if we ever try to enforce a local privilege boundary (eg, running
# certbot for unprivileged users via setuid), this function will need
# to be modified.
apache_config_path = self.pick_apache_config()
return common.install_version_controlled_file(
options_ssl, options_ssl_digest, apache_config_path, constants.ALL_SSL_OPTIONS_HASHES)
return common.install_version_controlled_file(options_ssl, options_ssl_digest,
self.option("MOD_SSL_CONF_SRC"), constants.ALL_SSL_OPTIONS_HASHES)
def enable_autohsts(self, _unused_lineage, domains):
"""

View File

@@ -11,10 +11,16 @@ SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
SSLHonorCipherOrder on
SSLCompression off
SSLSessionTickets off
SSLOptions +StrictRequire
# Add vhost name to log entries:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined
LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common
#CustomLog /var/log/apache2/access.log vhost_combined
#LogLevel warn
#ErrorLog /var/log/apache2/error.log
# Always ensure Cookies have "Secure" set (JAH 2012/1)
#Header edit Set-Cookie (?i)^(.*)(;\s*secure)??((\s*;)?(.*)) "$1; Secure$3$4"

View File

@@ -1,4 +1,6 @@
""" Distribution specific override class for Arch Linux """
import pkg_resources
import zope.interface
from certbot import interfaces
@@ -24,4 +26,6 @@ class ArchConfigurator(configurator.ApacheConfigurator):
handle_modules=False,
handle_sites=False,
challenge_location="/etc/httpd/conf",
MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
"certbot_apache", "options-ssl-apache.conf")
)

View File

@@ -1,6 +1,7 @@
""" Distribution specific override class for CentOS family (RHEL, Fedora) """
import logging
import pkg_resources
import zope.interface
from certbot import errors
@@ -38,6 +39,8 @@ class CentOSConfigurator(configurator.ApacheConfigurator):
handle_modules=False,
handle_sites=False,
challenge_location="/etc/httpd/conf.d",
MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
"certbot_apache", "centos-options-ssl-apache.conf")
)
def config_test(self):
@@ -72,18 +75,6 @@ class CentOSConfigurator(configurator.ApacheConfigurator):
# Finish with actual config check to see if systemctl restart helped
super(CentOSConfigurator, self).config_test()
def pick_apache_config(self):
"""
Pick the appropriate TLS Apache configuration file for current version of Apache and OS.
:return: the path to the TLS Apache configuration file to use
:rtype: str
"""
# Disabling TLS session tickets is supported by Apache 2.4.11+.
# So for old versions of Apache we pick a configuration without this option.
if self.version < (2, 4, 11):
return apache_util.find_ssl_apache_conf("centos-old")
return apache_util.find_ssl_apache_conf("centos-current")
def _prepare_options(self):
"""
Override the options dictionary initialization in order to support

View File

@@ -1,4 +1,6 @@
""" Distribution specific override class for macOS """
import pkg_resources
import zope.interface
from certbot import interfaces
@@ -24,4 +26,6 @@ class DarwinConfigurator(configurator.ApacheConfigurator):
handle_modules=False,
handle_sites=False,
challenge_location="/etc/apache2/other",
MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
"certbot_apache", "options-ssl-apache.conf")
)

View File

@@ -1,6 +1,7 @@
""" Distribution specific override class for Debian family (Ubuntu/Debian) """
import logging
import pkg_resources
import zope.interface
from certbot import errors
@@ -34,6 +35,8 @@ class DebianConfigurator(configurator.ApacheConfigurator):
handle_modules=True,
handle_sites=True,
challenge_location="/etc/apache2",
MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
"certbot_apache", "options-ssl-apache.conf")
)
def enable_site(self, vhost):

View File

@@ -1,4 +1,5 @@
""" Distribution specific override class for Fedora 29+ """
import pkg_resources
import zope.interface
from certbot import errors
@@ -30,6 +31,9 @@ class FedoraConfigurator(configurator.ApacheConfigurator):
handle_modules=False,
handle_sites=False,
challenge_location="/etc/httpd/conf.d",
MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
# TODO: eventually newest version of Fedora will need their own config
"certbot_apache", "centos-options-ssl-apache.conf")
)
def config_test(self):

View File

@@ -1,4 +1,6 @@
""" Distribution specific override class for Gentoo Linux """
import pkg_resources
import zope.interface
from certbot import interfaces
@@ -27,6 +29,8 @@ class GentooConfigurator(configurator.ApacheConfigurator):
handle_modules=False,
handle_sites=False,
challenge_location="/etc/apache2/vhosts.d",
MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
"certbot_apache", "options-ssl-apache.conf")
)
def _prepare_options(self):

View File

@@ -1,4 +1,6 @@
""" Distribution specific override class for OpenSUSE """
import pkg_resources
import zope.interface
from certbot import interfaces
@@ -24,4 +26,6 @@ class OpenSUSEConfigurator(configurator.ApacheConfigurator):
handle_modules=False,
handle_sites=False,
challenge_location="/etc/apache2/vhosts.d",
MOD_SSL_CONF_SRC=pkg_resources.resource_filename(
"certbot_apache", "options-ssl-apache.conf")
)

View File

@@ -190,13 +190,6 @@ class MultipleVhostsTestCentOS(util.ApacheTest):
errors.SubprocessError]
self.assertRaises(errors.MisconfigurationError, self.config.restart)
def test_pick_correct_tls_config(self):
self.config.version = (2, 4, 10)
self.assertTrue('centos-old' in self.config.pick_apache_config())
self.config.version = (2, 4, 11)
self.assertTrue('centos-current' in self.config.pick_apache_config())
if __name__ == "__main__":
unittest.main() # pragma: no cover

View File

@@ -1706,7 +1706,7 @@ class InstallSslOptionsConfTest(util.ApacheTest):
self.config.updated_mod_ssl_conf_digest)
def _current_ssl_options_hash(self):
return crypto_util.sha256sum(self.config.pick_apache_config())
return crypto_util.sha256sum(self.config.option("MOD_SSL_CONF_SRC"))
def _assert_current_file(self):
self.assertTrue(os.path.isfile(self.config.mod_ssl_conf))
@@ -1742,7 +1742,7 @@ class InstallSslOptionsConfTest(util.ApacheTest):
self.assertFalse(mock_logger.warning.called)
self.assertTrue(os.path.isfile(self.config.mod_ssl_conf))
self.assertEqual(crypto_util.sha256sum(
self.config.pick_apache_config()),
self.config.option("MOD_SSL_CONF_SRC")),
self._current_ssl_options_hash())
self.assertNotEqual(crypto_util.sha256sum(self.config.mod_ssl_conf),
self._current_ssl_options_hash())
@@ -1758,31 +1758,18 @@ class InstallSslOptionsConfTest(util.ApacheTest):
"%s has been manually modified; updated file "
"saved to %s. We recommend updating %s for security purposes.")
self.assertEqual(crypto_util.sha256sum(
self.config.pick_apache_config()),
self.config.option("MOD_SSL_CONF_SRC")),
self._current_ssl_options_hash())
# only print warning once
with mock.patch("certbot.plugins.common.logger") as mock_logger:
self._call()
self.assertFalse(mock_logger.warning.called)
def test_ssl_config_files_hash_in_all_hashes(self):
"""
It is really critical that all TLS Apache config files have their SHA256 hash registered in
constants.ALL_SSL_OPTIONS_HASHES. Otherwise Certbot will mistakenly assume that the config
file has been manually edited by the user, and will refuse to update it.
This test ensures that all necessary hashes are present.
"""
def test_current_file_hash_in_all_hashes(self):
from certbot_apache.constants import ALL_SSL_OPTIONS_HASHES
import pkg_resources
tls_configs_dir = pkg_resources.resource_filename("certbot_apache", "tls_configs")
all_files = [os.path.join(tls_configs_dir, name) for name in os.listdir(tls_configs_dir)
if name.endswith('options-ssl-apache.conf')]
self.assertTrue(all_files)
for one_file in all_files:
file_hash = crypto_util.sha256sum(one_file)
self.assertTrue(file_hash in ALL_SSL_OPTIONS_HASHES,
"Constants.ALL_SSL_OPTIONS_HASHES must be appended with the sha256 "
"hash of {0} when it is updated.".format(one_file))
self.assertTrue(self._current_ssl_options_hash() in ALL_SSL_OPTIONS_HASHES,
"Constants.ALL_SSL_OPTIONS_HASHES must be appended"
" with the sha256 hash of self.config.mod_ssl_conf when it is updated.")
if __name__ == "__main__":

View File

@@ -1,18 +0,0 @@
# This file contains important security parameters. If you modify this file
# manually, Certbot will be unable to automatically provide future security
# updates. Instead, Certbot will print and log an error message with a path to
# the up-to-date file that you will need to refer to when manually updating
# this file.
SSLEngine on
# Intermediate configuration, tweak to your needs
SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
SSLHonorCipherOrder on
SSLOptions +StrictRequire
# Add vhost name to log entries:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined
LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common

View File

@@ -1,19 +0,0 @@
# This file contains important security parameters. If you modify this file
# manually, Certbot will be unable to automatically provide future security
# updates. Instead, Certbot will print and log an error message with a path to
# the up-to-date file that you will need to refer to when manually updating
# this file.
SSLEngine on
# Intermediate configuration, tweak to your needs
SSLProtocol all -SSLv2 -SSLv3
SSLCipherSuite ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS
SSLHonorCipherOrder on
SSLCompression off
SSLOptions +StrictRequire
# Add vhost name to log entries:
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined
LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common

View File

@@ -1,3 +1,3 @@
# Remember to update setup.py to match the package versions below.
acme[dev]==0.29.0
-e .[dev]
certbot[dev]==0.37.0

View File

@@ -4,13 +4,13 @@ from setuptools.command.test import test as TestCommand
import sys
version = '0.37.0.dev0'
version = '0.38.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.
install_requires = [
'acme>=0.29.0',
'certbot>=0.37.0.dev0',
'certbot>=0.37.0',
'mock',
'python-augeas',
'setuptools',

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.36.0"
LE_AUTO_VERSION="0.37.1"
BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates
@@ -755,13 +755,31 @@ elif [ -f /etc/redhat-release ]; then
prev_le_python="$LE_PYTHON"
unset LE_PYTHON
DeterminePythonVersion "NOCRASH"
# Starting to Fedora 29, python2 is on a deprecation path. Let's move to python3 then.
RPM_DIST_NAME=`(. /etc/os-release 2> /dev/null && echo $ID) || echo "unknown"`
RPM_DIST_VERSION=0
if [ "$RPM_DIST_NAME" = "fedora" ]; then
RPM_DIST_VERSION=`(. /etc/os-release 2> /dev/null && echo $VERSION_ID) || echo "0"`
# Set RPM_DIST_VERSION to VERSION_ID from /etc/os-release after splitting on
# '.' characters (e.g. "8.0" becomes "8"). If the command exits with an
# error, RPM_DIST_VERSION is set to "unknown".
RPM_DIST_VERSION=$( (. /etc/os-release 2> /dev/null && echo "$VERSION_ID") | cut -d '.' -f1 || echo "unknown")
# If RPM_DIST_VERSION is an empty string or it contains any nonnumeric
# characters, the value is unexpected so we set RPM_DIST_VERSION to 0.
if [ -z "$RPM_DIST_VERSION" ] || [ -n "$(echo "$RPM_DIST_VERSION" | tr -d '[0-9]')" ]; then
RPM_DIST_VERSION=0
fi
# Starting to Fedora 29, python2 is on a deprecation path. Let's move to python3 then.
# RHEL 8 also uses python3 by default.
if [ "$RPM_DIST_NAME" = "fedora" -a "$RPM_DIST_VERSION" -ge 29 -o "$PYVER" -eq 26 ]; then
RPM_USE_PYTHON_3=1
elif [ "$RPM_DIST_NAME" = "rhel" -a "$RPM_DIST_VERSION" -ge 8 ]; then
RPM_USE_PYTHON_3=1
else
RPM_USE_PYTHON_3=0
fi
if [ "$RPM_USE_PYTHON_3" = 1 ]; then
Bootstrap() {
BootstrapMessage "RedHat-based OSes that will use Python3"
BootstrapRpmPython3
@@ -775,6 +793,7 @@ elif [ -f /etc/redhat-release ]; then
}
BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION"
fi
LE_PYTHON="$prev_le_python"
elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then
Bootstrap() {
@@ -1314,18 +1333,18 @@ letsencrypt==0.7.0 \
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
certbot==0.36.0 \
--hash=sha256:486cee6c4861762fe4a94b4f44f7d227034d026d1a8d7ba2911ef4e86a737613 \
--hash=sha256:bf6745b823644cdca8461150455aeb67d417f87f80b9ec774c716e9587ef20a2
acme==0.36.0 \
--hash=sha256:5570c8e87383fbc733224fd0f7d164313b67dd9c21deafe9ddc8e769441f0c86 \
--hash=sha256:0461ee3c882d865e98e624561843dc135fa1a1412b15603d7ebfbb392de6a668
certbot-apache==0.36.0 \
--hash=sha256:2537f7fb67a38b6d1ed5ee79f6a799090ca609695ac3799bb840b2fb677ac98d \
--hash=sha256:458d20a3e9e8a88563d3deb0bbe38752bd2b80100f0e5854e4069390c1b4e5cd
certbot-nginx==0.36.0 \
--hash=sha256:4303b54adf2030671c54bb3964c1f43aec0f677045e0cdb6d4fb931268d08310 \
--hash=sha256:4c34e6114dd8204b6667f101579dd9ab2b38fef0dd5a15702585edcb2aefb322
certbot==0.37.1 \
--hash=sha256:84dbdad204327b8d8ef9ab5b040f2be1e427a9f7e087affcc9a6051ea1b03fe7 \
--hash=sha256:aace73e63b0c11cdb4b0bd33e1780c1fbe0ce5669dc72e80c3aa9500145daf16
acme==0.37.1 \
--hash=sha256:83a4f6f3c5eb6a85233d5ba87714b426f2d096df58d711f8a2fc4071eb3fd3fc \
--hash=sha256:c069a761990751f7c4bf51d2e87ae10319bf460de6629d2908c9fa6f69e97111
certbot-apache==0.37.1 \
--hash=sha256:3ea832408877b12b3a60d17e8b2ee3387364f8c3023ac267161c25b99087cd42 \
--hash=sha256:e46c2644451101c0e216aa1f525a577cc903efaf871e0e4da277224a4439040c
certbot-nginx==0.37.1 \
--hash=sha256:1f9af389d26f06634e2eefaace3354e7679dabb4295e1d55d05a4ee7e23a64bd \
--hash=sha256:02a7ec15bd388d0f0e94a34c86a8f8d618ec7d5ffde0c206039bb4c46b294ce4
UNLIKELY_EOF
# -------------------------------------------------------------------------

View File

@@ -0,0 +1,11 @@
#!/usr/bin/env python
import sys
import os
hook_script_type = os.path.basename(os.path.dirname(sys.argv[1]))
if hook_script_type == 'deploy' and ('RENEWED_DOMAINS' not in os.environ or 'RENEWED_LINEAGE' not in os.environ):
sys.stderr.write('Environment variables not properly set!\n')
sys.exit(1)
with open(sys.argv[2], 'a') as file_h:
file_h.write(hook_script_type + '\n')

View File

@@ -1,6 +1,17 @@
"""This module contains advanced assertions for the certbot integration tests."""
import os
import grp
try:
import grp
POSIX_MODE = True
except ImportError:
import win32api
import win32security
import ntsecuritycon
POSIX_MODE = False
EVERYBODY_SID = 'S-1-1-0'
SYSTEM_SID = 'S-1-5-18'
ADMINS_SID = 'S-1-5-32-544'
def assert_hook_execution(probe_path, probe_content):
@@ -10,9 +21,10 @@ def assert_hook_execution(probe_path, probe_content):
:param probe_content: content expected when the hook is executed
"""
with open(probe_path, 'r') as file:
lines = file.readlines()
data = file.read()
assert '{0}{1}'.format(probe_content, os.linesep) in lines
lines = [line.strip() for line in data.splitlines()]
assert probe_content in lines
def assert_saved_renew_hook(config_dir, lineage):
@@ -38,16 +50,51 @@ def assert_cert_count_for_lineage(config_dir, lineage, count):
assert len(certs) == count
def assert_equals_permissions(file1, file2, mask):
def assert_equals_group_permissions(file1, file2):
"""
Assert that permissions on two files are identical in respect to a given umask.
Assert that two files have the same permissions for group owner.
:param file1: first file path to compare
:param file2: second file path to compare
:param mask: 3-octal representation of a POSIX umask under which the two files mode
should match (eg. 0o074 will test RWX on group and R on world)
"""
mode_file1 = os.stat(file1).st_mode & mask
mode_file2 = os.stat(file2).st_mode & mask
# On Windows there is no group, so this assertion does nothing on this platform
if POSIX_MODE:
mode_file1 = os.stat(file1).st_mode & 0o070
mode_file2 = os.stat(file2).st_mode & 0o070
assert mode_file1 == mode_file2
def assert_equals_world_read_permissions(file1, file2):
"""
Assert that two files have the same read permissions for everyone.
:param file1: first file path to compare
:param file2: second file path to compare
"""
if POSIX_MODE:
mode_file1 = os.stat(file1).st_mode & 0o004
mode_file2 = os.stat(file2).st_mode & 0o004
else:
everybody = win32security.ConvertStringSidToSid(EVERYBODY_SID)
security1 = win32security.GetFileSecurity(file1, win32security.DACL_SECURITY_INFORMATION)
dacl1 = security1.GetSecurityDescriptorDacl()
mode_file1 = dacl1.GetEffectiveRightsFromAcl({
'TrusteeForm': win32security.TRUSTEE_IS_SID,
'TrusteeType': win32security.TRUSTEE_IS_USER,
'Identifier': everybody,
})
mode_file1 = mode_file1 & ntsecuritycon.FILE_GENERIC_READ
security2 = win32security.GetFileSecurity(file2, win32security.DACL_SECURITY_INFORMATION)
dacl2 = security2.GetSecurityDescriptorDacl()
mode_file2 = dacl2.GetEffectiveRightsFromAcl({
'TrusteeForm': win32security.TRUSTEE_IS_SID,
'TrusteeType': win32security.TRUSTEE_IS_USER,
'Identifier': everybody,
})
mode_file2 = mode_file2 & ntsecuritycon.FILE_GENERIC_READ
assert mode_file1 == mode_file2
@@ -57,20 +104,57 @@ def assert_equals_group_owner(file1, file2):
Assert that two files have the same group owner.
:param file1: first file path to compare
:param file2: second file path to compare
:return:
"""
group_owner_file1 = grp.getgrgid(os.stat(file1).st_gid)[0]
group_owner_file2 = grp.getgrgid(os.stat(file2).st_gid)[0]
# On Windows there is no group, so this assertion does nothing on this platform
if POSIX_MODE:
group_owner_file1 = grp.getgrgid(os.stat(file1).st_gid)[0]
group_owner_file2 = grp.getgrgid(os.stat(file2).st_gid)[0]
assert group_owner_file1 == group_owner_file2
assert group_owner_file1 == group_owner_file2
def assert_world_permissions(file, mode):
def assert_world_no_permissions(file):
"""
Assert that a file has the expected world permission.
:param file: file path to check
:param mode: world permissions mode expected
Assert that the given file is not world-readable.
:param file: path of the file to check
"""
mode_file_all = os.stat(file).st_mode & 0o007
if POSIX_MODE:
mode_file_all = os.stat(file).st_mode & 0o007
assert mode_file_all == 0
else:
security = win32security.GetFileSecurity(file, win32security.DACL_SECURITY_INFORMATION)
dacl = security.GetSecurityDescriptorDacl()
mode = dacl.GetEffectiveRightsFromAcl({
'TrusteeForm': win32security.TRUSTEE_IS_SID,
'TrusteeType': win32security.TRUSTEE_IS_USER,
'Identifier': win32security.ConvertStringSidToSid(EVERYBODY_SID),
})
assert mode_file_all == mode
assert not mode
def assert_world_read_permissions(file):
"""
Assert that the given file is world-readable, but not world-writable or world-executable.
:param file: path of the file to check
"""
if POSIX_MODE:
mode_file_all = os.stat(file).st_mode & 0o007
assert mode_file_all == 4
else:
security = win32security.GetFileSecurity(file, win32security.DACL_SECURITY_INFORMATION)
dacl = security.GetSecurityDescriptorDacl()
mode = dacl.GetEffectiveRightsFromAcl({
'TrusteeForm': win32security.TRUSTEE_IS_SID,
'TrusteeType': win32security.TRUSTEE_IS_USER,
'Identifier': win32security.ConvertStringSidToSid(EVERYBODY_SID),
})
assert not mode & ntsecuritycon.FILE_GENERIC_WRITE
assert not mode & ntsecuritycon.FILE_GENERIC_EXECUTE
assert mode & ntsecuritycon.FILE_GENERIC_READ == ntsecuritycon.FILE_GENERIC_READ
def _get_current_user():
account_name = win32api.GetUserNameEx(win32api.NameSamCompatible)
return win32security.LookupAccountName(None, account_name)[0]

View File

@@ -1,10 +1,11 @@
"""Module to handle the context of integration tests."""
import logging
import os
import shutil
import sys
import tempfile
from certbot_integration_tests.utils import misc, certbot_call
from certbot_integration_tests.utils import certbot_call
class IntegrationTestsContext(object):
@@ -19,7 +20,7 @@ class IntegrationTestsContext(object):
self.worker_id = 'primary'
acme_xdist = request.config.acme_xdist
self.acme_server =acme_xdist['acme_server']
self.acme_server = acme_xdist['acme_server']
self.directory_url = acme_xdist['directory_url']
self.tls_alpn_01_port = acme_xdist['https_port'][self.worker_id]
self.http_01_port = acme_xdist['http_port'][self.worker_id]
@@ -30,7 +31,10 @@ class IntegrationTestsContext(object):
self.workspace = tempfile.mkdtemp()
self.config_dir = os.path.join(self.workspace, 'conf')
self.hook_probe = tempfile.mkstemp(dir=self.workspace)[1]
probe = tempfile.mkstemp(dir=self.workspace)
os.close(probe[0])
self.hook_probe = probe[1]
self.manual_dns_auth_hook = (
'{0} -c "import os; import requests; import json; '

View File

@@ -11,8 +11,11 @@ from os.path import join, exists
import pytest
from certbot_integration_tests.certbot_tests import context as certbot_context
from certbot_integration_tests.certbot_tests.assertions import (
assert_hook_execution, assert_saved_renew_hook, assert_cert_count_for_lineage,
assert_world_permissions, assert_equals_group_owner, assert_equals_permissions,
assert_hook_execution, assert_saved_renew_hook,
assert_cert_count_for_lineage,
assert_world_no_permissions, assert_world_read_permissions,
assert_equals_group_owner, assert_equals_group_permissions, assert_equals_world_read_permissions,
EVERYBODY_SID
)
from certbot_integration_tests.utils import misc
@@ -84,9 +87,9 @@ def test_http_01(context):
context.certbot([
'--domains', certname, '--preferred-challenges', 'http-01', 'run',
'--cert-name', certname,
'--pre-hook', 'echo wtf.pre >> "{0}"'.format(context.hook_probe),
'--post-hook', 'echo wtf.post >> "{0}"'.format(context.hook_probe),
'--deploy-hook', 'echo deploy >> "{0}"'.format(context.hook_probe)
'--pre-hook', misc.echo('wtf_pre', context.hook_probe),
'--post-hook', misc.echo('wtf_post', context.hook_probe),
'--deploy-hook', misc.echo('deploy', context.hook_probe),
])
assert_hook_execution(context.hook_probe, 'deploy')
@@ -104,9 +107,9 @@ def test_manual_http_auth(context):
'--cert-name', certname,
'--manual-auth-hook', scripts[0],
'--manual-cleanup-hook', scripts[1],
'--pre-hook', 'echo wtf.pre >> "{0}"'.format(context.hook_probe),
'--post-hook', 'echo wtf.post >> "{0}"'.format(context.hook_probe),
'--renew-hook', 'echo renew >> "{0}"'.format(context.hook_probe)
'--pre-hook', misc.echo('wtf_pre', context.hook_probe),
'--post-hook', misc.echo('wtf_post', context.hook_probe),
'--renew-hook', misc.echo('renew', context.hook_probe),
])
with pytest.raises(AssertionError):
@@ -122,9 +125,9 @@ def test_manual_dns_auth(context):
'run', '--cert-name', certname,
'--manual-auth-hook', context.manual_dns_auth_hook,
'--manual-cleanup-hook', context.manual_dns_cleanup_hook,
'--pre-hook', 'echo wtf.pre >> "{0}"'.format(context.hook_probe),
'--post-hook', 'echo wtf.post >> "{0}"'.format(context.hook_probe),
'--renew-hook', 'echo renew >> "{0}"'.format(context.hook_probe)
'--pre-hook', misc.echo('wtf_pre', context.hook_probe),
'--post-hook', misc.echo('wtf_post', context.hook_probe),
'--renew-hook', misc.echo('renew', context.hook_probe),
])
with pytest.raises(AssertionError):
@@ -173,21 +176,19 @@ def test_renew_files_permissions(context):
certname = context.get_domain('renew')
context.certbot(['-d', certname])
privkey1 = join(context.config_dir, 'archive', certname, 'privkey1.pem')
privkey2 = join(context.config_dir, 'archive', certname, 'privkey2.pem')
assert_cert_count_for_lineage(context.config_dir, certname, 1)
assert_world_permissions(
join(context.config_dir, 'archive', certname, 'privkey1.pem'), 0)
assert_world_no_permissions(privkey1)
context.certbot(['renew'])
assert_cert_count_for_lineage(context.config_dir, certname, 2)
assert_world_permissions(
join(context.config_dir, 'archive', certname, 'privkey2.pem'), 0)
assert_equals_group_owner(
join(context.config_dir, 'archive', certname, 'privkey1.pem'),
join(context.config_dir, 'archive', certname, 'privkey2.pem'))
assert_equals_permissions(
join(context.config_dir, 'archive', certname, 'privkey1.pem'),
join(context.config_dir, 'archive', certname, 'privkey2.pem'), 0o074)
assert_world_no_permissions(privkey2)
assert_equals_group_owner(privkey1, privkey2)
assert_equals_world_read_permissions(privkey1, privkey2)
assert_equals_group_permissions(privkey1, privkey2)
def test_renew_with_hook_scripts(context):
@@ -211,15 +212,35 @@ def test_renew_files_propagate_permissions(context):
assert_cert_count_for_lineage(context.config_dir, certname, 1)
os.chmod(join(context.config_dir, 'archive', certname, 'privkey1.pem'), 0o444)
privkey1 = join(context.config_dir, 'archive', certname, 'privkey1.pem')
privkey2 = join(context.config_dir, 'archive', certname, 'privkey2.pem')
if os.name != 'nt':
os.chmod(privkey1, 0o444)
else:
import win32security
import ntsecuritycon
# Get the current DACL of the private key
security = win32security.GetFileSecurity(privkey1, win32security.DACL_SECURITY_INFORMATION)
dacl = security.GetSecurityDescriptorDacl()
# Create a read permission for Everybody group
everybody = win32security.ConvertStringSidToSid(EVERYBODY_SID)
dacl.AddAccessAllowedAce(win32security.ACL_REVISION, ntsecuritycon.FILE_GENERIC_READ, everybody)
# Apply the updated DACL to the private key
security.SetSecurityDescriptorDacl(1, dacl, 0)
win32security.SetFileSecurity(privkey1, win32security.DACL_SECURITY_INFORMATION, security)
context.certbot(['renew'])
assert_cert_count_for_lineage(context.config_dir, certname, 2)
assert_world_permissions(
join(context.config_dir, 'archive', certname, 'privkey2.pem'), 4)
assert_equals_permissions(
join(context.config_dir, 'archive', certname, 'privkey1.pem'),
join(context.config_dir, 'archive', certname, 'privkey2.pem'), 0o074)
if os.name != 'nt':
# On Linux, read world permissions + all group permissions will be copied from the previous private key
assert_world_read_permissions(privkey2)
assert_equals_world_read_permissions(privkey1, privkey2)
assert_equals_group_permissions(privkey1, privkey2)
else:
# On Windows, world will never have any permissions, and group permission is irrelevant for this platform
assert_world_no_permissions(privkey2)
def test_graceful_renew_it_is_not_time(context):
@@ -229,7 +250,7 @@ def test_graceful_renew_it_is_not_time(context):
assert_cert_count_for_lineage(context.config_dir, certname, 1)
context.certbot(['renew', '--deploy-hook', 'echo deploy >> "{0}"'.format(context.hook_probe)],
context.certbot(['renew', '--deploy-hook', misc.echo('deploy', context.hook_probe)],
force_renew=False)
assert_cert_count_for_lineage(context.config_dir, certname, 1)
@@ -250,7 +271,7 @@ def test_graceful_renew_it_is_time(context):
with open(join(context.config_dir, 'renewal', '{0}.conf'.format(certname)), 'w') as file:
file.writelines(lines)
context.certbot(['renew', '--deploy-hook', 'echo deploy >> "{0}"'.format(context.hook_probe)],
context.certbot(['renew', '--deploy-hook', misc.echo('deploy', context.hook_probe)],
force_renew=False)
assert_cert_count_for_lineage(context.config_dir, certname, 2)
@@ -317,9 +338,9 @@ def test_renew_hook_override(context):
context.certbot([
'certonly', '-d', certname,
'--preferred-challenges', 'http-01',
'--pre-hook', 'echo pre >> "{0}"'.format(context.hook_probe),
'--post-hook', 'echo post >> "{0}"'.format(context.hook_probe),
'--deploy-hook', 'echo deploy >> "{0}"'.format(context.hook_probe)
'--pre-hook', misc.echo('pre', context.hook_probe),
'--post-hook', misc.echo('post', context.hook_probe),
'--deploy-hook', misc.echo('deploy', context.hook_probe),
])
assert_hook_execution(context.hook_probe, 'pre')
@@ -330,14 +351,14 @@ def test_renew_hook_override(context):
open(context.hook_probe, 'w').close()
context.certbot([
'renew', '--cert-name', certname,
'--pre-hook', 'echo pre-override >> "{0}"'.format(context.hook_probe),
'--post-hook', 'echo post-override >> "{0}"'.format(context.hook_probe),
'--deploy-hook', 'echo deploy-override >> "{0}"'.format(context.hook_probe)
'--pre-hook', misc.echo('pre_override', context.hook_probe),
'--post-hook', misc.echo('post_override', context.hook_probe),
'--deploy-hook', misc.echo('deploy_override', context.hook_probe),
])
assert_hook_execution(context.hook_probe, 'pre-override')
assert_hook_execution(context.hook_probe, 'post-override')
assert_hook_execution(context.hook_probe, 'deploy-override')
assert_hook_execution(context.hook_probe, 'pre_override')
assert_hook_execution(context.hook_probe, 'post_override')
assert_hook_execution(context.hook_probe, 'deploy_override')
with pytest.raises(AssertionError):
assert_hook_execution(context.hook_probe, 'pre')
with pytest.raises(AssertionError):
@@ -349,11 +370,11 @@ def test_renew_hook_override(context):
open(context.hook_probe, 'w').close()
context.certbot(['renew', '--cert-name', certname])
assert_hook_execution(context.hook_probe, 'pre-override')
assert_hook_execution(context.hook_probe, 'post-override')
assert_hook_execution(context.hook_probe, 'deploy-override')
assert_hook_execution(context.hook_probe, 'pre_override')
assert_hook_execution(context.hook_probe, 'post_override')
assert_hook_execution(context.hook_probe, 'deploy_override')
def test_invalid_domain_with_dns_challenge(context):
"""Test certificate issuance failure with DNS-01 challenge."""
# Manual dns auth hooks from misc are designed to fail if the domain contains 'fail-*'.
@@ -512,7 +533,7 @@ def test_revoke_multiple_lineages(context):
data = file.read()
data = re.sub('archive_dir = .*\n',
'archive_dir = {0}\n'.format(join(context.config_dir, 'archive', cert1)),
'archive_dir = {0}\n'.format(join(context.config_dir, 'archive', cert1).replace('\\', '\\\\')),
data)
with open(join(context.config_dir, 'renewal', '{0}.conf'.format(cert2)), 'w') as file:
@@ -555,11 +576,9 @@ def test_ocsp_status_stale(context):
def test_ocsp_status_live(context):
"""Test retrieval of OCSP statuses for live config"""
if context.acme_server == 'pebble':
pytest.skip('Pebble does not support OCSP status requests.')
cert = context.get_domain('ocsp-check')
# OSCP 1: Check live certificate OCSP status (VALID)
cert = context.get_domain('ocsp-check')
context.certbot(['--domains', cert])
output = context.certbot(['certificates'])

View File

@@ -134,6 +134,13 @@ class ACMEServer(object):
[challtestsrv_path, '-management', ':{0}'.format(CHALLTESTSRV_PORT), '-defaultIPv6', '""',
'-defaultIPv4', '127.0.0.1', '-http01', '""', '-tlsalpn01', '""', '-https01', '""'])
# pebble_ocsp_server is imported here and not at the top of module in order to avoid a useless
# ImportError, in the case where cryptography dependency is too old to support ocsp, but
# Boulder is used instead of Pebble, so pebble_ocsp_server is not used. This is the typical
# situation of integration-certbot-oldest tox testenv.
from certbot_integration_tests.utils import pebble_ocsp_server
self._launch_process([sys.executable, pebble_ocsp_server.__file__])
# Wait for the ACME CA server to be up.
print('=> Waiting for pebble instance to respond...')
misc.check_until_timeout(self.acme_xdist['directory_url'])

View File

@@ -5,3 +5,5 @@ CHALLTESTSRV_PORT = 8055
BOULDER_V1_DIRECTORY_URL = 'http://localhost:4000/directory'
BOULDER_V2_DIRECTORY_URL = 'http://localhost:4001/directory'
PEBBLE_DIRECTORY_URL = 'https://localhost:14000/dir'
PEBBLE_MANAGEMENT_URL = 'https://localhost:15000'
MOCK_OCSP_SERVER_PORT = 4002

View File

@@ -3,9 +3,11 @@ Misc module contains stateless functions that could be used during pytest execut
or outside during setup/teardown of the integration tests environment.
"""
import contextlib
import logging
import errno
import multiprocessing
import os
import re
import shutil
import stat
import subprocess
@@ -23,7 +25,6 @@ from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.serialization import Encoding, PrivateFormat, NoEncryption
from six.moves import socketserver, SimpleHTTPServer
RSA_KEY_TYPE = 'rsa'
ECDSA_KEY_TYPE = 'ecdsa'
@@ -63,6 +64,10 @@ class GracefulTCPServer(socketserver.TCPServer):
allow_reuse_address = True
def _run_server(port):
GracefulTCPServer(('', port), SimpleHTTPServer.SimpleHTTPRequestHandler).serve_forever()
@contextlib.contextmanager
def create_http_server(port):
"""
@@ -75,10 +80,7 @@ def create_http_server(port):
current_cwd = os.getcwd()
webroot = tempfile.mkdtemp()
def run():
GracefulTCPServer(('', port), SimpleHTTPServer.SimpleHTTPRequestHandler).serve_forever()
process = multiprocessing.Process(target=run)
process = multiprocessing.Process(target=_run_server, args=(port,))
try:
# SimpleHTTPServer is designed to serve files from the current working directory at the
@@ -120,15 +122,9 @@ def generate_test_file_hooks(config_dir, hook_probe):
:param str config_dir: current certbot config directory
:param hook_probe: path to the hook probe to test hook scripts execution
"""
if sys.platform == 'win32':
extension = 'bat'
else:
extension = 'sh'
hook_path = pkg_resources.resource_filename('certbot_integration_tests', 'assets/hook.py')
renewal_hooks_dirs = list_renewal_hooks_dirs(config_dir)
renewal_deploy_hook_path = os.path.join(renewal_hooks_dirs[1], 'hook.sh')
for hook_dir in renewal_hooks_dirs:
for hook_dir in list_renewal_hooks_dirs(config_dir):
# We want an equivalent of bash `chmod -p $HOOK_DIR, that does not fail if one folder of
# the hierarchy already exists. It is not the case of os.makedirs. Python 3 has an
# optional parameter `exists_ok` to not fail on existing dir, but Python 2.7 does not.
@@ -138,26 +134,25 @@ def generate_test_file_hooks(config_dir, hook_probe):
except OSError as error:
if error.errno != errno.EEXIST:
raise
hook_path = os.path.join(hook_dir, 'hook.{0}'.format(extension))
if extension == 'sh':
data = '''\
#!/bin/bash -xe
if [ "$0" = "{0}" ]; then
if [ -z "$RENEWED_DOMAINS" -o -z "$RENEWED_LINEAGE" ]; then
echo "Environment variables not properly set!" >&2
exit 1
fi
fi
echo $(basename $(dirname "$0")) >> "{1}"\
'''.format(renewal_deploy_hook_path, hook_probe)
else:
# TODO: Write the equivalent bat file for Windows
data = '''\
'''
with open(hook_path, 'w') as file:
file.write(data)
os.chmod(hook_path, os.stat(hook_path).st_mode | stat.S_IEXEC)
if os.name != 'nt':
entrypoint_script_path = os.path.join(hook_dir, 'entrypoint.sh')
entrypoint_script = '''\
#!/usr/bin/env bash
set -e
"{0}" "{1}" "{2}" "{3}"
'''.format(sys.executable, hook_path, entrypoint_script_path, hook_probe)
else:
entrypoint_script_path = os.path.join(hook_dir, 'entrypoint.bat')
entrypoint_script = '''\
@echo off
"{0}" "{1}" "{2}" "{3}"
'''.format(sys.executable, hook_path, entrypoint_script_path, hook_probe)
with open(entrypoint_script_path, 'w') as file_h:
file_h.write(entrypoint_script)
os.chmod(entrypoint_script_path, os.stat(entrypoint_script_path).st_mode | stat.S_IEXEC)
@contextlib.contextmanager
@@ -194,7 +189,7 @@ for _ in range(0, 10):
except requests.exceptions.ConnectionError:
pass
raise ValueError('Error, url did not respond after 10 attempts: {{0}}'.format(url))
'''.format(http_server_root, http_port))
'''.format(http_server_root.replace('\\', '\\\\'), http_port))
os.chmod(auth_script_path, 0o755)
cleanup_script_path = os.path.join(tempdir, 'cleanup.py')
@@ -205,7 +200,7 @@ import os
import shutil
well_known = os.path.join('{0}', '.well-known')
shutil.rmtree(well_known)
'''.format(http_server_root))
'''.format(http_server_root.replace('\\', '\\\\')))
os.chmod(cleanup_script_path, 0o755)
yield ('{0} {1}'.format(sys.executable, auth_script_path),
@@ -288,4 +283,32 @@ def load_sample_data_path(workspace):
original = pkg_resources.resource_filename('certbot_integration_tests', 'assets/sample-config')
copied = os.path.join(workspace, 'sample-config')
shutil.copytree(original, copied, symlinks=True)
if os.name == 'nt':
# Fix the symlinks on Windows since GIT is not creating them upon checkout
for lineage in ['a.encryption-example.com', 'b.encryption-example.com']:
current_live = os.path.join(copied, 'live', lineage)
for name in os.listdir(current_live):
if name != 'README':
current_file = os.path.join(current_live, name)
with open(current_file) as file_h:
src = file_h.read()
os.unlink(current_file)
os.symlink(os.path.join(current_live, src), current_file)
return copied
def echo(keyword, path=None):
"""
Generate a platform independent executable command
that echoes the given keyword into the given file.
:param keyword: the keyword to echo (must be a single keyword)
:param path: path to the file were keyword is echoed
:return: the executable command
"""
if not re.match(r'^\w+$', keyword):
raise ValueError('Error, keyword `{0}` is not a single keyword.'
.format(keyword))
return '{0} -c "from __future__ import print_function; print(\'{1}\')"{2}'.format(
os.path.basename(sys.executable), keyword, ' >> "{0}"'.format(path) if path else '')

View File

@@ -1,19 +1,18 @@
import json
import platform
import os
import stat
import pkg_resources
import requests
PEBBLE_VERSION = 'v2.1.0'
from certbot_integration_tests.utils.constants import MOCK_OCSP_SERVER_PORT
PEBBLE_VERSION = 'v2.2.1'
ASSETS_PATH = pkg_resources.resource_filename('certbot_integration_tests', 'assets')
def fetch(workspace):
suffix = '{0}-{1}{2}'.format(platform.system().lower(),
platform.machine().lower().replace('x86_64', 'amd64'),
'.exe' if platform.system() == 'Windows' else '')
suffix = 'linux-amd64' if os.name != 'nt' else 'windows-amd64.exe'
pebble_path = _fetch_asset('pebble', suffix)
challtestsrv_path = _fetch_asset('pebble-challtestsrv', suffix)
@@ -42,10 +41,12 @@ def _build_pebble_config(workspace):
file_h.write(json.dumps({
'pebble': {
'listenAddress': '0.0.0.0:14000',
'managementListenAddress': '0.0.0.0:15000',
'certificate': os.path.join(ASSETS_PATH, 'cert.pem'),
'privateKey': os.path.join(ASSETS_PATH, 'key.pem'),
'httpPort': 5002,
'tlsPort': 5001,
'ocspResponderURL': 'http://127.0.0.1:{0}'.format(MOCK_OCSP_SERVER_PORT),
},
}))

View File

@@ -0,0 +1,71 @@
#!/usr/bin/env python
"""
This runnable module interfaces itself with the Pebble management interface in order
to serve a mock OCSP responder during integration tests against Pebble.
"""
import datetime
import re
import requests
from dateutil import parser
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import serialization, hashes
from cryptography import x509
from cryptography.x509 import ocsp
from six.moves import BaseHTTPServer
from certbot_integration_tests.utils.misc import GracefulTCPServer
from certbot_integration_tests.utils.constants import MOCK_OCSP_SERVER_PORT, PEBBLE_MANAGEMENT_URL
class _ProxyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
def do_POST(self):
request = requests.get(PEBBLE_MANAGEMENT_URL + '/intermediate-keys/0', verify=False)
issuer_key = serialization.load_pem_private_key(request.content, None, default_backend())
request = requests.get(PEBBLE_MANAGEMENT_URL + '/intermediates/0', verify=False)
issuer_cert = x509.load_pem_x509_certificate(request.content, default_backend())
try:
content_len = int(self.headers.getheader('content-length', 0))
except AttributeError:
content_len = int(self.headers.get('Content-Length'))
ocsp_request = ocsp.load_der_ocsp_request(self.rfile.read(content_len))
response = requests.get('{0}/cert-status-by-serial/{1}'.format(
PEBBLE_MANAGEMENT_URL, str(hex(ocsp_request.serial_number)).replace('0x', '')), verify=False)
if not response.ok:
ocsp_response = ocsp.OCSPResponseBuilder.build_unsuccessful(ocsp.OCSPResponseStatus.UNAUTHORIZED)
else:
data = response.json()
now = datetime.datetime.utcnow()
cert = x509.load_pem_x509_certificate(data['Certificate'].encode(), default_backend())
if data['Status'] != 'Revoked':
ocsp_status, revocation_time, revocation_reason = ocsp.OCSPCertStatus.GOOD, None, None
else:
ocsp_status, revocation_reason = ocsp.OCSPCertStatus.REVOKED, x509.ReasonFlags.unspecified
revoked_at = re.sub(r'( \+\d{4}).*$', r'\1', data['RevokedAt']) # "... +0000 UTC" => "+0000"
revocation_time = parser.parse(revoked_at)
ocsp_response = ocsp.OCSPResponseBuilder().add_response(
cert=cert, issuer=issuer_cert, algorithm=hashes.SHA1(),
cert_status=ocsp_status,
this_update=now, next_update=now + datetime.timedelta(hours=1),
revocation_time=revocation_time, revocation_reason=revocation_reason
).responder_id(
ocsp.OCSPResponderEncoding.NAME, issuer_cert
).sign(issuer_key, hashes.SHA256())
self.send_response(200)
self.end_headers()
self.wfile.write(ocsp_response.public_bytes(serialization.Encoding.DER))
if __name__ == '__main__':
try:
GracefulTCPServer(('', MOCK_OCSP_SERVER_PORT), _ProxyHandler).serve_forever()
except KeyboardInterrupt:
pass

View File

@@ -1,5 +1,7 @@
from setuptools import setup
from setuptools import find_packages
import sys
from distutils.version import StrictVersion
from setuptools import setup, find_packages, __version__ as setuptools_version
version = '0.32.0.dev0'
@@ -11,11 +13,23 @@ install_requires = [
'pytest',
'pytest-cov',
'pytest-xdist',
'python-dateutil',
'pyyaml',
'requests',
'six',
]
# Add pywin32 on Windows platforms to handle low-level system calls.
# This dependency needs to be added using environment markers to avoid its installation on Linux.
# However environment markers are supported only with setuptools >= 36.2.
# So this dependency is not added for old Linux distributions with old setuptools,
# in order to allow these systems to build certbot from sources.
if StrictVersion(setuptools_version) >= StrictVersion('36.2'):
install_requires.append("pywin32>=224 ; sys_platform == 'win32'")
elif 'bdist_wheel' in sys.argv[1:]:
raise RuntimeError('Error, you are trying to build certbot wheels using an old version '
'of setuptools. Version 36.2+ of setuptools is required.')
setup(
name='certbot-ci',
version=version,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -2,7 +2,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.37.0.dev0'
version = '0.38.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [

View File

@@ -2,7 +2,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.37.0.dev0'
version = '0.38.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.37.0.dev0'
version = '0.38.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [

View File

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

View File

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

View File

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

View File

@@ -2,7 +2,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.37.0.dev0'
version = '0.38.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.37.0.dev0'
version = '0.38.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View File

@@ -2,7 +2,7 @@ from setuptools import setup
from setuptools import find_packages
version = '0.37.0.dev0'
version = '0.38.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [

View File

@@ -2,5 +2,4 @@ include LICENSE.txt
include README.rst
recursive-include docs *
recursive-include certbot_nginx/tests/testdata *
include certbot_nginx/options-ssl-nginx.conf
include certbot_nginx/options-ssl-nginx-old.conf
recursive-include certbot_nginx/tls_configs *.conf

View File

@@ -127,7 +127,10 @@ class NginxConfigurator(common.Installer):
config_filename = "options-ssl-nginx.conf"
if self.version < (1, 5, 9):
config_filename = "options-ssl-nginx-old.conf"
return pkg_resources.resource_filename("certbot_nginx", config_filename)
elif self.version < (1, 13, 0):
config_filename = "options-ssl-nginx-tls12-only.conf"
return pkg_resources.resource_filename(
"certbot_nginx", os.path.join("tls_configs", config_filename))
@property
def mod_ssl_conf(self):

View File

@@ -23,10 +23,17 @@ UPDATED_MOD_SSL_CONF_DIGEST = ".updated-options-ssl-nginx-conf-digest.txt"
"""Name of the hash of the updated or informed mod_ssl_conf as saved in `IConfig.config_dir`."""
SSL_OPTIONS_HASHES_NEW = [
'108c4555058a087496a3893aea5d9e1cee0f20a3085d44a52dc1a66522299ac3',
]
"""SHA256 hashes of the contents of versions of MOD_SSL_CONF_SRC for nginx >= 1.13.0"""
SSL_OPTIONS_HASHES_MEDIUM = [
'63e2bddebb174a05c9d8a7cf2adf72f7af04349ba59a1a925fe447f73b2f1abf',
'2901debc7ecbc10917edd9084c05464c9c5930b463677571eaf8c94bffd11ae2',
'30baca73ed9a5b0e9a69ea40e30482241d8b1a7343aa79b49dc5d7db0bf53b6c',
]
"""SHA256 hashes of the contents of versions of MOD_SSL_CONF_SRC for nginx >= 1.5.9"""
"""SHA256 hashes of the contents of versions of MOD_SSL_CONF_SRC for nginx >= 1.5.9
and nginx < 1.13.0"""
ALL_SSL_OPTIONS_HASHES = [
'0f81093a1465e3d4eaa8b0c14e77b2a2e93568b0fc1351c2b87893a95f0de87c',
@@ -36,7 +43,8 @@ ALL_SSL_OPTIONS_HASHES = [
'394732f2bbe3e5e637c3fb5c6e980a1f1b90b01e2e8d6b7cff41dde16e2a756d',
'4b16fec2bcbcd8a2f3296d886f17f9953ffdcc0af54582452ca1e52f5f776f16',
'c052ffff0ad683f43bffe105f7c606b339536163490930e2632a335c8d191cc4',
] + SSL_OPTIONS_HASHES_NEW
'02329eb19930af73c54b3632b3165d84571383b8c8c73361df940cb3894dd426',
] + SSL_OPTIONS_HASHES_MEDIUM + SSL_OPTIONS_HASHES_NEW
"""SHA256 hashes of the contents of all versions of MOD_SSL_CONF_SRC"""
def os_constant(key):

View File

@@ -1,13 +0,0 @@
# This file contains important security parameters. If you modify this file
# manually, Certbot will be unable to automatically provide future security
# updates. Instead, Certbot will print and log an error message with a path to
# the up-to-date file that you will need to refer to when manually updating
# this file.
ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS";

View File

@@ -1,14 +0,0 @@
# This file contains important security parameters. If you modify this file
# manually, Certbot will be unable to automatically provide future security
# updates. Instead, Certbot will print and log an error message with a path to
# the up-to-date file that you will need to refer to when manually updating
# this file.
ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_session_tickets off;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
ssl_ciphers "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS";

View File

@@ -963,13 +963,40 @@ class InstallSslOptionsConfTest(util.NginxTest):
"Constants.ALL_SSL_OPTIONS_HASHES must be appended"
" with the sha256 hash of self.config.mod_ssl_conf when it is updated.")
def test_old_nginx_version_uses_old_config(self):
def test_ssl_config_files_hash_in_all_hashes(self):
"""
It is really critical that all TLS Nginx config files have their SHA256 hash registered in
constants.ALL_SSL_OPTIONS_HASHES. Otherwise Certbot will mistakenly assume that the config
file has been manually edited by the user, and will refuse to update it.
This test ensures that all necessary hashes are present.
"""
from certbot_nginx.constants import ALL_SSL_OPTIONS_HASHES
import pkg_resources
all_files = [
pkg_resources.resource_filename("certbot_nginx", os.path.join("tls_configs", x))
for x in ("options-ssl-nginx.conf",
"options-ssl-nginx-old.conf",
"options-ssl-nginx-tls12-only.conf")
]
self.assertTrue(all_files)
for one_file in all_files:
file_hash = crypto_util.sha256sum(one_file)
self.assertTrue(file_hash in ALL_SSL_OPTIONS_HASHES,
"Constants.ALL_SSL_OPTIONS_HASHES must be appended with the sha256 "
"hash of {0} when it is updated.".format(one_file))
def test_nginx_version_uses_correct_config(self):
self.config.version = (1, 5, 8)
self.assertEqual(os.path.basename(self.config.mod_ssl_conf_src),
"options-ssl-nginx-old.conf")
self._call()
self._assert_current_file()
self.config.version = (1, 5, 9)
self.assertEqual(os.path.basename(self.config.mod_ssl_conf_src),
"options-ssl-nginx-tls12-only.conf")
self._call()
self._assert_current_file()
self.config.version = (1, 13, 0)
self.assertEqual(os.path.basename(self.config.mod_ssl_conf_src),
"options-ssl-nginx.conf")

View File

@@ -0,0 +1,13 @@
# This file contains important security parameters. If you modify this file
# manually, Certbot will be unable to automatically provide future security
# updates. Instead, Certbot will print and log an error message with a path to
# the up-to-date file that you will need to refer to when manually updating
# this file.
ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers off;
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";

View File

@@ -0,0 +1,14 @@
# This file contains important security parameters. If you modify this file
# manually, Certbot will be unable to automatically provide future security
# updates. Instead, Certbot will print and log an error message with a path to
# the up-to-date file that you will need to refer to when manually updating
# this file.
ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_session_tickets off;
ssl_protocols TLSv1.2;
ssl_prefer_server_ciphers off;
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";

View File

@@ -0,0 +1,14 @@
# This file contains important security parameters. If you modify this file
# manually, Certbot will be unable to automatically provide future security
# updates. Instead, Certbot will print and log an error message with a path to
# the up-to-date file that you will need to refer to when manually updating
# this file.
ssl_session_cache shared:le_nginx_SSL:10m;
ssl_session_timeout 1440m;
ssl_session_tickets off;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers off;
ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";

View File

@@ -4,7 +4,7 @@ from setuptools.command.test import test as TestCommand
import sys
version = '0.37.0.dev0'
version = '0.38.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.37.0.dev0'
__version__ = '0.38.0.dev0'

View File

@@ -624,7 +624,7 @@ class Client(object):
reporter.add_message(
"An error occurred and we failed to restore your config and "
"restart your server. Please post to "
"https://community.letsencrypt.org/c/server-config "
"https://community.letsencrypt.org/c/help "
"with details about your configuration and this error you received.",
reporter.HIGH_PRIORITY)
raise

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.36.0
"". (default: CertbotACMEClient/0.37.1
(certbot(-auto); OS_NAME OS_VERSION) Authenticator/XXX
Installer/YYY (SUBCOMMAND; flags: FLAGS)
Py/major.minor.patchlevel). The flags encoded in the

View File

@@ -114,9 +114,9 @@ Once you are done with your code changes, and the tests in ``foo_test.py`` pass,
run all of the unittests for Certbot with ``tox -e py27`` (this uses Python
2.7).
Once all the unittests pass, check for sufficient test coverage using
``tox -e cover``, and then check for code style with ``tox -e lint`` (all files)
or ``pylint --rcfile=.pylintrc path/to/file.py`` (single file at a time).
Once all the unittests pass, check for sufficient test coverage using ``tox -e
py27-cover``, and then check for code style with ``tox -e lint`` (all files) or
``pylint --rcfile=.pylintrc path/to/file.py`` (single file at a time).
Once all of the above is successful, you may run the full test suite using
``tox --skip-missing-interpreters``. We recommend running the commands above

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.36.0"
LE_AUTO_VERSION="0.37.1"
BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates
@@ -755,13 +755,31 @@ elif [ -f /etc/redhat-release ]; then
prev_le_python="$LE_PYTHON"
unset LE_PYTHON
DeterminePythonVersion "NOCRASH"
# Starting to Fedora 29, python2 is on a deprecation path. Let's move to python3 then.
RPM_DIST_NAME=`(. /etc/os-release 2> /dev/null && echo $ID) || echo "unknown"`
RPM_DIST_VERSION=0
if [ "$RPM_DIST_NAME" = "fedora" ]; then
RPM_DIST_VERSION=`(. /etc/os-release 2> /dev/null && echo $VERSION_ID) || echo "0"`
# Set RPM_DIST_VERSION to VERSION_ID from /etc/os-release after splitting on
# '.' characters (e.g. "8.0" becomes "8"). If the command exits with an
# error, RPM_DIST_VERSION is set to "unknown".
RPM_DIST_VERSION=$( (. /etc/os-release 2> /dev/null && echo "$VERSION_ID") | cut -d '.' -f1 || echo "unknown")
# If RPM_DIST_VERSION is an empty string or it contains any nonnumeric
# characters, the value is unexpected so we set RPM_DIST_VERSION to 0.
if [ -z "$RPM_DIST_VERSION" ] || [ -n "$(echo "$RPM_DIST_VERSION" | tr -d '[0-9]')" ]; then
RPM_DIST_VERSION=0
fi
# Starting to Fedora 29, python2 is on a deprecation path. Let's move to python3 then.
# RHEL 8 also uses python3 by default.
if [ "$RPM_DIST_NAME" = "fedora" -a "$RPM_DIST_VERSION" -ge 29 -o "$PYVER" -eq 26 ]; then
RPM_USE_PYTHON_3=1
elif [ "$RPM_DIST_NAME" = "rhel" -a "$RPM_DIST_VERSION" -ge 8 ]; then
RPM_USE_PYTHON_3=1
else
RPM_USE_PYTHON_3=0
fi
if [ "$RPM_USE_PYTHON_3" = 1 ]; then
Bootstrap() {
BootstrapMessage "RedHat-based OSes that will use Python3"
BootstrapRpmPython3
@@ -775,6 +793,7 @@ elif [ -f /etc/redhat-release ]; then
}
BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION"
fi
LE_PYTHON="$prev_le_python"
elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then
Bootstrap() {
@@ -1314,18 +1333,18 @@ letsencrypt==0.7.0 \
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
certbot==0.36.0 \
--hash=sha256:486cee6c4861762fe4a94b4f44f7d227034d026d1a8d7ba2911ef4e86a737613 \
--hash=sha256:bf6745b823644cdca8461150455aeb67d417f87f80b9ec774c716e9587ef20a2
acme==0.36.0 \
--hash=sha256:5570c8e87383fbc733224fd0f7d164313b67dd9c21deafe9ddc8e769441f0c86 \
--hash=sha256:0461ee3c882d865e98e624561843dc135fa1a1412b15603d7ebfbb392de6a668
certbot-apache==0.36.0 \
--hash=sha256:2537f7fb67a38b6d1ed5ee79f6a799090ca609695ac3799bb840b2fb677ac98d \
--hash=sha256:458d20a3e9e8a88563d3deb0bbe38752bd2b80100f0e5854e4069390c1b4e5cd
certbot-nginx==0.36.0 \
--hash=sha256:4303b54adf2030671c54bb3964c1f43aec0f677045e0cdb6d4fb931268d08310 \
--hash=sha256:4c34e6114dd8204b6667f101579dd9ab2b38fef0dd5a15702585edcb2aefb322
certbot==0.37.1 \
--hash=sha256:84dbdad204327b8d8ef9ab5b040f2be1e427a9f7e087affcc9a6051ea1b03fe7 \
--hash=sha256:aace73e63b0c11cdb4b0bd33e1780c1fbe0ce5669dc72e80c3aa9500145daf16
acme==0.37.1 \
--hash=sha256:83a4f6f3c5eb6a85233d5ba87714b426f2d096df58d711f8a2fc4071eb3fd3fc \
--hash=sha256:c069a761990751f7c4bf51d2e87ae10319bf460de6629d2908c9fa6f69e97111
certbot-apache==0.37.1 \
--hash=sha256:3ea832408877b12b3a60d17e8b2ee3387364f8c3023ac267161c25b99087cd42 \
--hash=sha256:e46c2644451101c0e216aa1f525a577cc903efaf871e0e4da277224a4439040c
certbot-nginx==0.37.1 \
--hash=sha256:1f9af389d26f06634e2eefaace3354e7679dabb4295e1d55d05a4ee7e23a64bd \
--hash=sha256:02a7ec15bd388d0f0e94a34c86a8f8d618ec7d5ffde0c206039bb4c46b294ce4
UNLIKELY_EOF
# -------------------------------------------------------------------------

View File

@@ -1,11 +1,11 @@
-----BEGIN PGP SIGNATURE-----
iQEzBAABCAAdFiEEos+1H6J1pyhiNOeyTRfJlc2XdfIFAl0njnkACgkQTRfJlc2X
dfIqjwf/XBEzOEtwi84v97jZjHi9bqeFBzAt+n6YXleKySk8anxFMFmFIvrc2w/U
eyskpn0mmJDX2LjaXcsJji+l5yAWbm3p8M2J2toaPI2TLznhM6+uEWP62BHJiQYi
1ORBJYATSfLxA541CwXXW3VTYDu+CLq0w1nr5mHg1Y20ZFBrPIlt04mkh9o70fD4
qv6MsMXKZxglhH1ORyLMVn5Jze22awmJ944pP8aI54ZEkTl2XT9DsZt3QpZ1muOy
IRg6sU86ukgWK66zWjTyd1AOddDL2OY3+U7JachFd5eb7dnnaCGeZhCjfVide7a3
Fk8NrXwlrpKKJYkbqDfRkT4Pba47VQ==
=gf1k
iQEzBAABCAAdFiEEos+1H6J1pyhiNOeyTRfJlc2XdfIFAl1Mt7UACgkQTRfJlc2X
dfIALggAhyS29bqwp7L2u31uJalZbZQzK2jb86+YyxYzJ/TNAOVHghZNrF7krXAV
GCYEV6SXNHlScAtv7eIVbMcbiaSh/+6/1K3HsPBNP/7nR2sTZ/AOSQNPKdgUia5E
jypTdGYcOiQBCqyP0yDKFXIKxJFOP63tIvidfuT0rBcyusrJ/QPJs6uhKLggOiFv
9kNgZQsOhE3LpA9Yaqf0lsbKhA154c2Q662JiGCzQ2AST36bdzNEwsUeVoTbJda3
o3qN5kg+mWZNrc9qgYjDA3gXxepNGxjXmFasJc1k1uVx9gxYhEO+/WC1UKMQJR1O
Y/7Qrv3sR3KJ/Q/guhEB4jTKOnvXvw==
=+61j
-----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.37.0.dev0"
LE_AUTO_VERSION="0.38.0.dev0"
BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates
@@ -755,13 +755,31 @@ elif [ -f /etc/redhat-release ]; then
prev_le_python="$LE_PYTHON"
unset LE_PYTHON
DeterminePythonVersion "NOCRASH"
# Starting to Fedora 29, python2 is on a deprecation path. Let's move to python3 then.
RPM_DIST_NAME=`(. /etc/os-release 2> /dev/null && echo $ID) || echo "unknown"`
RPM_DIST_VERSION=0
if [ "$RPM_DIST_NAME" = "fedora" ]; then
RPM_DIST_VERSION=`(. /etc/os-release 2> /dev/null && echo $VERSION_ID) || echo "0"`
# Set RPM_DIST_VERSION to VERSION_ID from /etc/os-release after splitting on
# '.' characters (e.g. "8.0" becomes "8"). If the command exits with an
# error, RPM_DIST_VERSION is set to "unknown".
RPM_DIST_VERSION=$( (. /etc/os-release 2> /dev/null && echo "$VERSION_ID") | cut -d '.' -f1 || echo "unknown")
# If RPM_DIST_VERSION is an empty string or it contains any nonnumeric
# characters, the value is unexpected so we set RPM_DIST_VERSION to 0.
if [ -z "$RPM_DIST_VERSION" ] || [ -n "$(echo "$RPM_DIST_VERSION" | tr -d '[0-9]')" ]; then
RPM_DIST_VERSION=0
fi
# Starting to Fedora 29, python2 is on a deprecation path. Let's move to python3 then.
# RHEL 8 also uses python3 by default.
if [ "$RPM_DIST_NAME" = "fedora" -a "$RPM_DIST_VERSION" -ge 29 -o "$PYVER" -eq 26 ]; then
RPM_USE_PYTHON_3=1
elif [ "$RPM_DIST_NAME" = "rhel" -a "$RPM_DIST_VERSION" -ge 8 ]; then
RPM_USE_PYTHON_3=1
else
RPM_USE_PYTHON_3=0
fi
if [ "$RPM_USE_PYTHON_3" = 1 ]; then
Bootstrap() {
BootstrapMessage "RedHat-based OSes that will use Python3"
BootstrapRpmPython3
@@ -775,6 +793,7 @@ elif [ -f /etc/redhat-release ]; then
}
BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION"
fi
LE_PYTHON="$prev_le_python"
elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then
Bootstrap() {
@@ -1314,18 +1333,18 @@ letsencrypt==0.7.0 \
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
certbot==0.36.0 \
--hash=sha256:486cee6c4861762fe4a94b4f44f7d227034d026d1a8d7ba2911ef4e86a737613 \
--hash=sha256:bf6745b823644cdca8461150455aeb67d417f87f80b9ec774c716e9587ef20a2
acme==0.36.0 \
--hash=sha256:5570c8e87383fbc733224fd0f7d164313b67dd9c21deafe9ddc8e769441f0c86 \
--hash=sha256:0461ee3c882d865e98e624561843dc135fa1a1412b15603d7ebfbb392de6a668
certbot-apache==0.36.0 \
--hash=sha256:2537f7fb67a38b6d1ed5ee79f6a799090ca609695ac3799bb840b2fb677ac98d \
--hash=sha256:458d20a3e9e8a88563d3deb0bbe38752bd2b80100f0e5854e4069390c1b4e5cd
certbot-nginx==0.36.0 \
--hash=sha256:4303b54adf2030671c54bb3964c1f43aec0f677045e0cdb6d4fb931268d08310 \
--hash=sha256:4c34e6114dd8204b6667f101579dd9ab2b38fef0dd5a15702585edcb2aefb322
certbot==0.37.1 \
--hash=sha256:84dbdad204327b8d8ef9ab5b040f2be1e427a9f7e087affcc9a6051ea1b03fe7 \
--hash=sha256:aace73e63b0c11cdb4b0bd33e1780c1fbe0ce5669dc72e80c3aa9500145daf16
acme==0.37.1 \
--hash=sha256:83a4f6f3c5eb6a85233d5ba87714b426f2d096df58d711f8a2fc4071eb3fd3fc \
--hash=sha256:c069a761990751f7c4bf51d2e87ae10319bf460de6629d2908c9fa6f69e97111
certbot-apache==0.37.1 \
--hash=sha256:3ea832408877b12b3a60d17e8b2ee3387364f8c3023ac267161c25b99087cd42 \
--hash=sha256:e46c2644451101c0e216aa1f525a577cc903efaf871e0e4da277224a4439040c
certbot-nginx==0.37.1 \
--hash=sha256:1f9af389d26f06634e2eefaace3354e7679dabb4295e1d55d05a4ee7e23a64bd \
--hash=sha256:02a7ec15bd388d0f0e94a34c86a8f8d618ec7d5ffde0c206039bb4c46b294ce4
UNLIKELY_EOF
# -------------------------------------------------------------------------

View File

@@ -330,13 +330,31 @@ elif [ -f /etc/redhat-release ]; then
prev_le_python="$LE_PYTHON"
unset LE_PYTHON
DeterminePythonVersion "NOCRASH"
# Starting to Fedora 29, python2 is on a deprecation path. Let's move to python3 then.
RPM_DIST_NAME=`(. /etc/os-release 2> /dev/null && echo $ID) || echo "unknown"`
RPM_DIST_VERSION=0
if [ "$RPM_DIST_NAME" = "fedora" ]; then
RPM_DIST_VERSION=`(. /etc/os-release 2> /dev/null && echo $VERSION_ID) || echo "0"`
# Set RPM_DIST_VERSION to VERSION_ID from /etc/os-release after splitting on
# '.' characters (e.g. "8.0" becomes "8"). If the command exits with an
# error, RPM_DIST_VERSION is set to "unknown".
RPM_DIST_VERSION=$( (. /etc/os-release 2> /dev/null && echo "$VERSION_ID") | cut -d '.' -f1 || echo "unknown")
# If RPM_DIST_VERSION is an empty string or it contains any nonnumeric
# characters, the value is unexpected so we set RPM_DIST_VERSION to 0.
if [ -z "$RPM_DIST_VERSION" ] || [ -n "$(echo "$RPM_DIST_VERSION" | tr -d '[0-9]')" ]; then
RPM_DIST_VERSION=0
fi
# Starting to Fedora 29, python2 is on a deprecation path. Let's move to python3 then.
# RHEL 8 also uses python3 by default.
if [ "$RPM_DIST_NAME" = "fedora" -a "$RPM_DIST_VERSION" -ge 29 -o "$PYVER" -eq 26 ]; then
RPM_USE_PYTHON_3=1
elif [ "$RPM_DIST_NAME" = "rhel" -a "$RPM_DIST_VERSION" -ge 8 ]; then
RPM_USE_PYTHON_3=1
else
RPM_USE_PYTHON_3=0
fi
if [ "$RPM_USE_PYTHON_3" = 1 ]; then
Bootstrap() {
BootstrapMessage "RedHat-based OSes that will use Python3"
BootstrapRpmPython3
@@ -350,6 +368,7 @@ elif [ -f /etc/redhat-release ]; then
}
BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION"
fi
LE_PYTHON="$prev_le_python"
elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then
Bootstrap() {

View File

@@ -1,12 +1,12 @@
certbot==0.36.0 \
--hash=sha256:486cee6c4861762fe4a94b4f44f7d227034d026d1a8d7ba2911ef4e86a737613 \
--hash=sha256:bf6745b823644cdca8461150455aeb67d417f87f80b9ec774c716e9587ef20a2
acme==0.36.0 \
--hash=sha256:5570c8e87383fbc733224fd0f7d164313b67dd9c21deafe9ddc8e769441f0c86 \
--hash=sha256:0461ee3c882d865e98e624561843dc135fa1a1412b15603d7ebfbb392de6a668
certbot-apache==0.36.0 \
--hash=sha256:2537f7fb67a38b6d1ed5ee79f6a799090ca609695ac3799bb840b2fb677ac98d \
--hash=sha256:458d20a3e9e8a88563d3deb0bbe38752bd2b80100f0e5854e4069390c1b4e5cd
certbot-nginx==0.36.0 \
--hash=sha256:4303b54adf2030671c54bb3964c1f43aec0f677045e0cdb6d4fb931268d08310 \
--hash=sha256:4c34e6114dd8204b6667f101579dd9ab2b38fef0dd5a15702585edcb2aefb322
certbot==0.37.1 \
--hash=sha256:84dbdad204327b8d8ef9ab5b040f2be1e427a9f7e087affcc9a6051ea1b03fe7 \
--hash=sha256:aace73e63b0c11cdb4b0bd33e1780c1fbe0ce5669dc72e80c3aa9500145daf16
acme==0.37.1 \
--hash=sha256:83a4f6f3c5eb6a85233d5ba87714b426f2d096df58d711f8a2fc4071eb3fd3fc \
--hash=sha256:c069a761990751f7c4bf51d2e87ae10319bf460de6629d2908c9fa6f69e97111
certbot-apache==0.37.1 \
--hash=sha256:3ea832408877b12b3a60d17e8b2ee3387364f8c3023ac267161c25b99087cd42 \
--hash=sha256:e46c2644451101c0e216aa1f525a577cc903efaf871e0e4da277224a4439040c
certbot-nginx==0.37.1 \
--hash=sha256:1f9af389d26f06634e2eefaace3354e7679dabb4295e1d55d05a4ee7e23a64bd \
--hash=sha256:02a7ec15bd388d0f0e94a34c86a8f8d618ec7d5ffde0c206039bb4c46b294ce4

View File

@@ -59,7 +59,7 @@ install_requires = [
# So this dependency is not added for old Linux distributions with old setuptools,
# in order to allow these systems to build certbot from sources.
if StrictVersion(setuptools_version) >= StrictVersion('36.2'):
install_requires.append("pywin32 ; sys_platform == 'win32'")
install_requires.append("pywin32>=224 ; sys_platform == 'win32'")
elif 'bdist_wheel' in sys.argv[1:]:
raise RuntimeError('Error, you are trying to build certbot wheels using an old version '
'of setuptools. Version 36.2+ of setuptools is required.')

View File

@@ -26,6 +26,17 @@ else
# 0.33.x is the oldest version of letsencrypt-auto that works on Fedora 29+.
INITIAL_VERSION="0.33.1"
fi
# If we're on RHEL 8, the initial version of certbot-auto will fail until we do
# a release including https://github.com/certbot/certbot/pull/7240 and update
# INITIAL_VERSION above to use a version containing this fix. This works around
# the problem for now so we can successfully run tests on RHEL 8.
RPM_DIST_NAME=`(. /etc/os-release 2> /dev/null && echo $ID) || echo "unknown"`
RPM_DIST_VERSION=`(. /etc/os-release 2> /dev/null && echo $VERSION_ID) | cut -d '.' -f1 || echo "0"`
if [ "$RPM_DIST_NAME" = "rhel" -a "$RPM_DIST_VERSION" -ge 8 ]; then
sudo yum install python3-virtualenv -y
fi
git checkout -f "v$INITIAL_VERSION" letsencrypt-auto
if ! ./letsencrypt-auto -v --debug --version --no-self-upgrade 2>&1 | tail -n1 | grep "^certbot $INITIAL_VERSION$" ; then
echo initial installation appeared to fail

View File

@@ -1,7 +1,7 @@
#!/bin/sh -xe
cd letsencrypt
./certbot-auto --install-only -n --debug
letsencrypt-auto-source/letsencrypt-auto --install-only -n --debug
PLUGINS="certbot-apache certbot-nginx"
PYTHON_MAJOR_VERSION=$(/opt/eff.org/certbot/venv/bin/python --version 2>&1 | cut -d" " -f 2 | cut -d. -f1)

View File

@@ -45,6 +45,11 @@ targets:
type: centos
virt: hvm
user: ec2-user
- ami: ami-0c322300a1dd5dc79
name: RHEL8
type: centos
virt: hvm
user: ec2-user
- ami: ami-00bbc6858140f19ed
name: fedora30
type: centos

View File

@@ -61,6 +61,7 @@ pytest-sugar==0.9.2
pytest-rerunfailures==4.2
python-dateutil==2.6.1
python-digitalocean==1.11
pywin32==224
PyYAML==3.13
repoze.sphinx.autointerface==0.8
requests-file==1.4.2

View File

@@ -232,6 +232,15 @@ commands =
coverage report --include 'certbot-nginx/*' --show-missing --fail-under=74
passenv = DOCKER_*
[testenv:integration-certbot]
commands =
{[base]pip_install} acme . certbot-ci
pytest certbot-ci/certbot_integration_tests/certbot_tests \
--acme-server={env:ACME_SERVER:pebble} \
--cov=acme --cov=certbot --cov-report= \
--cov-config=certbot-ci/certbot_integration_tests/.coveragerc
coverage report --include 'certbot/*' --show-missing --fail-under=62
[testenv:integration-certbot-oldest]
commands =
{[base]pip_install} .