From 6d6924dcd2434f71cd81f4344175c88794579471 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 5 Oct 2016 18:16:03 -0700 Subject: [PATCH 01/13] fix requirements.txt surgery in response to shipping certbot-nginx (#3585) --- tools/release.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/release.sh b/tools/release.sh index 7747b0e2b..f5c78da27 100755 --- a/tools/release.sh +++ b/tools/release.sh @@ -176,7 +176,7 @@ if ! wc -l /tmp/hashes.$$ | grep -qE "^\s*12 " ; then fi # perform hideous surgery on requirements.txt... -head -n -9 letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt > /tmp/req.$$ +head -n -12 letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt > /tmp/req.$$ cat /tmp/hashes.$$ >> /tmp/req.$$ cp /tmp/req.$$ letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt From c6f7d740a07866c948fdfe91036305c7cac34de4 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 6 Oct 2016 14:14:43 -0700 Subject: [PATCH 02/13] Make --quiet reduce the logging level (#3593) * reduce logging level and ignore verbose flags in quiet mode * Simplify setup_logging parameters The extra parameters were there in the past when the letsencrypt-renewer was a separate executable that also used this function. This is cruft that can be removed. * Add basic tests for setup_logging --- certbot/constants.py | 3 +++ certbot/main.py | 20 +++++++++++++------ certbot/tests/main_test.py | 40 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/certbot/constants.py b/certbot/constants.py index ae998e15a..117301380 100644 --- a/certbot/constants.py +++ b/certbot/constants.py @@ -37,6 +37,9 @@ STAGING_URI = "https://acme-staging.api.letsencrypt.org/directory" """Defaults for CLI flags and `.IConfig` attributes.""" +QUIET_LOGGING_LEVEL = logging.WARNING +"""Logging level to use in quiet mode.""" + RENEWER_DEFAULTS = dict( renewer_enabled="yes", renew_before_expiry="30 days", diff --git a/certbot/main.py b/certbot/main.py index dd497d14d..35008fd62 100644 --- a/certbot/main.py +++ b/certbot/main.py @@ -625,14 +625,22 @@ def _cli_log_handler(config, level, fmt): return handler -def setup_logging(config, cli_handler_factory, logfile): - """Setup logging.""" - file_fmt = "%(asctime)s:%(levelname)s:%(name)s:%(message)s" +def setup_logging(config): + """Sets up logging to logfiles and the terminal. + + :param certbot.interface.IConfig config: Configuration object + + """ cli_fmt = "%(message)s" - level = -config.verbose_count * 10 + file_fmt = "%(asctime)s:%(levelname)s:%(name)s:%(message)s" + logfile = "letsencrypt.log" + if config.quiet: + level = constants.QUIET_LOGGING_LEVEL + else: + level = -config.verbose_count * 10 file_handler, log_file_path = setup_log_file_handler( config, logfile=logfile, fmt=file_fmt) - cli_handler = cli_handler_factory(config, level, cli_fmt) + cli_handler = _cli_log_handler(config, level, cli_fmt) # TODO: use fileConfig? @@ -738,7 +746,7 @@ def main(cli_args=sys.argv[1:]): os.geteuid(), config.strict_permissions) # Setup logging ASAP, otherwise "No handlers could be found for # logger ..." TODO: this should be done before plugins discovery - setup_logging(config, _cli_log_handler, logfile='letsencrypt.log') + setup_logging(config) cli.possible_deprecation_warning(config) logger.debug("certbot version: %s", certbot.__version__) diff --git a/certbot/tests/main_test.py b/certbot/tests/main_test.py index fab1065c5..f7a6c5896 100644 --- a/certbot/tests/main_test.py +++ b/certbot/tests/main_test.py @@ -7,8 +7,11 @@ import unittest import mock from certbot import cli +from certbot import colored_logging +from certbot import constants from certbot import configuration from certbot import errors +from certbot import log from certbot.plugins import disco as plugins_disco class MainTest(unittest.TestCase): @@ -80,6 +83,43 @@ class SetupLogFileHandlerTest(unittest.TestCase): self.config, "test.log", "%s") +class SetupLoggingTest(unittest.TestCase): + """Tests for certbot.main.setup_logging.""" + + def setUp(self): + self.config = mock.Mock( + logs_dir=tempfile.mkdtemp(), + noninteractive_mode=False, quiet=False, text_mode=False, + verbose_count=constants.CLI_DEFAULTS['verbose_count']) + + def tearDown(self): + shutil.rmtree(self.config.logs_dir) + + @classmethod + def _call(cls, *args, **kwargs): + from certbot.main import setup_logging + return setup_logging(*args, **kwargs) + + @mock.patch('certbot.main.logging.getLogger') + def test_defaults(self, mock_get_logger): + self._call(self.config) + + cli_handler = mock_get_logger().addHandler.call_args_list[0][0][0] + self.assertEqual(cli_handler.level, -self.config.verbose_count * 10) + self.assertTrue( + isinstance(cli_handler, log.DialogHandler)) + + @mock.patch('certbot.main.logging.getLogger') + def test_quiet_mode(self, mock_get_logger): + self.config.quiet = self.config.noninteractive_mode = True + self._call(self.config) + + cli_handler = mock_get_logger().addHandler.call_args_list[0][0][0] + self.assertEqual(cli_handler.level, constants.QUIET_LOGGING_LEVEL) + self.assertTrue( + isinstance(cli_handler, colored_logging.StreamHandler)) + + class MakeOrVerifyCoreDirTest(unittest.TestCase): """Tests for certbot.main.make_or_verify_core_dir.""" From eeac01c776d78b612d8b639b3dffc451964ddc82 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 6 Oct 2016 14:56:27 -0700 Subject: [PATCH 03/13] Release 0.9.1 --- acme/setup.py | 2 +- certbot-apache/setup.py | 2 +- certbot-auto | 26 +++++++++--------- certbot-compatibility-test/setup.py | 2 +- certbot-nginx/setup.py | 2 +- certbot/__init__.py | 2 +- docs/cli-help.txt | 18 ++++++------ letsencrypt-auto | 26 +++++++++--------- letsencrypt-auto-source/certbot-auto.asc | 14 +++++----- letsencrypt-auto-source/letsencrypt-auto | 26 +++++++++--------- letsencrypt-auto-source/letsencrypt-auto.sig | Bin 256 -> 256 bytes .../pieces/letsencrypt-auto-requirements.txt | 24 ++++++++-------- 12 files changed, 72 insertions(+), 72 deletions(-) diff --git a/acme/setup.py b/acme/setup.py index 2b32f7e28..4bdfdefa0 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.10.0.dev0' +version = '0.9.1' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-apache/setup.py b/certbot-apache/setup.py index 2b4ac8563..fdfdae395 100644 --- a/certbot-apache/setup.py +++ b/certbot-apache/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.10.0.dev0' +version = '0.9.1' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-auto b/certbot-auto index 27fcde319..eb627032f 100755 --- a/certbot-auto +++ b/certbot-auto @@ -19,7 +19,7 @@ XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} VENV_NAME="letsencrypt" VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} VENV_BIN="$VENV_PATH/bin" -LE_AUTO_VERSION="0.9.0" +LE_AUTO_VERSION="0.9.1" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -761,18 +761,18 @@ letsencrypt==0.7.0 \ # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. -acme==0.9.0 \ - --hash=sha256:6d98bdec5fd9171e368a39cb2458d2d62599e52e2899650684379dba03f09d96 \ - --hash=sha256:fca3e57e5155ee0e80852e1b13a9d76a302728b78a9a1c2c38cb77d699aab7c5 -certbot==0.9.0 \ - --hash=sha256:08652503bb94f0863c2c2d53d37fc48966b080a70f578f980b05eee11bea7eaf \ - --hash=sha256:8dd4d3e2de2b2392fd8f41e73434dae737653bc41a54ce4a273768519a5ab61e -certbot-apache==0.9.0 \ - --hash=sha256:10e3096ff27adf6e75aff7722ada963f1337ef455f203495c025e883d8f816e2 \ - --hash=sha256:fd8bb3e7d36c64a5841083bed447250e110d458323b51d8a210b8f0b18e28c9a -certbot-nginx==0.9.0 \ - --hash=sha256:edbb7c1164225af770af6aea42496b575b5c115afa4d9ab7b1e587b3e6d0c92b \ - --hash=sha256:2f18504832b13f11e07dc87df758a7c5c68e24341628eb334ff7a5976a384717 +acme==0.9.1 \ + --hash=sha256:83e6188d5f149678b77ff3c8f8f94983f3c448490ffa634c7e9f2e93e7351fb0 \ + --hash=sha256:0effd08d144eedbfeb7dd784e9c8673ef3138cf48d35c8c33a1dd5bee9fd8207 +certbot==0.9.1 \ + --hash=sha256:88237a4f6d337d40185a644407f9c7adb6eab87c43b8bf56c1edc02ce82a9d81 \ + --hash=sha256:180354a3e95610ff8ba7f344011f2fcba1186d8efb7b25867266f47048e1e2f7 +certbot-apache==0.9.1 \ + --hash=sha256:cb9931294d44a1d6d44eaa2e92cb30daf6f2e0f29f6e7f00849709f0dd408b40 \ + --hash=sha256:1c09a6b4d087748f2aa143b0a7ced321458c3dd7ca70a80674f867b8b0e3cd6c +certbot-nginx==0.9.1 \ + --hash=sha256:3bd59a4f63a989eb31c04775107139bf45c2373a6f0b7bea4a3a1362da5c2ae7 \ + --hash=sha256:22f277846ccf5c8787cac2b35a7897780f05f4022de02d8b4b731c2cd957354c UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/certbot-compatibility-test/setup.py b/certbot-compatibility-test/setup.py index 32e5935fb..9b4a7854d 100644 --- a/certbot-compatibility-test/setup.py +++ b/certbot-compatibility-test/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.10.0.dev0' +version = '0.9.1' install_requires = [ 'certbot', diff --git a/certbot-nginx/setup.py b/certbot-nginx/setup.py index 4c39d37c2..c434caef2 100644 --- a/certbot-nginx/setup.py +++ b/certbot-nginx/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.10.0.dev0' +version = '0.9.1' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot/__init__.py b/certbot/__init__.py index 45892e269..0b082669f 100644 --- a/certbot/__init__.py +++ b/certbot/__init__.py @@ -1,4 +1,4 @@ """Certbot client.""" # version number like 1.2.3a0, must have at least 2 parts, like 1.2 -__version__ = '0.10.0.dev0' +__version__ = '0.9.1' diff --git a/docs/cli-help.txt b/docs/cli-help.txt index f7340c48b..7e321f407 100644 --- a/docs/cli-help.txt +++ b/docs/cli-help.txt @@ -307,15 +307,6 @@ plugins: --webroot Obtain certs by placing files in a webroot directory. (default: False) -nginx: - Nginx Web Server plugin - Alpha - - --nginx-server-root NGINX_SERVER_ROOT - Nginx server root directory. (default: /etc/nginx) - --nginx-ctl NGINX_CTL - Path to the 'nginx' binary, used for 'configtest' and - retrieving nginx version number. (default: nginx) - standalone: Spin up a temporary webserver @@ -328,6 +319,15 @@ manual: Automatically allows public IP logging. (default: False) +nginx: + Nginx Web Server plugin - Alpha + + --nginx-server-root NGINX_SERVER_ROOT + Nginx server root directory. (default: /etc/nginx) + --nginx-ctl NGINX_CTL + Path to the 'nginx' binary, used for 'configtest' and + retrieving nginx version number. (default: nginx) + webroot: Place files in webroot directory diff --git a/letsencrypt-auto b/letsencrypt-auto index 27fcde319..eb627032f 100755 --- a/letsencrypt-auto +++ b/letsencrypt-auto @@ -19,7 +19,7 @@ XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} VENV_NAME="letsencrypt" VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} VENV_BIN="$VENV_PATH/bin" -LE_AUTO_VERSION="0.9.0" +LE_AUTO_VERSION="0.9.1" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -761,18 +761,18 @@ letsencrypt==0.7.0 \ # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. -acme==0.9.0 \ - --hash=sha256:6d98bdec5fd9171e368a39cb2458d2d62599e52e2899650684379dba03f09d96 \ - --hash=sha256:fca3e57e5155ee0e80852e1b13a9d76a302728b78a9a1c2c38cb77d699aab7c5 -certbot==0.9.0 \ - --hash=sha256:08652503bb94f0863c2c2d53d37fc48966b080a70f578f980b05eee11bea7eaf \ - --hash=sha256:8dd4d3e2de2b2392fd8f41e73434dae737653bc41a54ce4a273768519a5ab61e -certbot-apache==0.9.0 \ - --hash=sha256:10e3096ff27adf6e75aff7722ada963f1337ef455f203495c025e883d8f816e2 \ - --hash=sha256:fd8bb3e7d36c64a5841083bed447250e110d458323b51d8a210b8f0b18e28c9a -certbot-nginx==0.9.0 \ - --hash=sha256:edbb7c1164225af770af6aea42496b575b5c115afa4d9ab7b1e587b3e6d0c92b \ - --hash=sha256:2f18504832b13f11e07dc87df758a7c5c68e24341628eb334ff7a5976a384717 +acme==0.9.1 \ + --hash=sha256:83e6188d5f149678b77ff3c8f8f94983f3c448490ffa634c7e9f2e93e7351fb0 \ + --hash=sha256:0effd08d144eedbfeb7dd784e9c8673ef3138cf48d35c8c33a1dd5bee9fd8207 +certbot==0.9.1 \ + --hash=sha256:88237a4f6d337d40185a644407f9c7adb6eab87c43b8bf56c1edc02ce82a9d81 \ + --hash=sha256:180354a3e95610ff8ba7f344011f2fcba1186d8efb7b25867266f47048e1e2f7 +certbot-apache==0.9.1 \ + --hash=sha256:cb9931294d44a1d6d44eaa2e92cb30daf6f2e0f29f6e7f00849709f0dd408b40 \ + --hash=sha256:1c09a6b4d087748f2aa143b0a7ced321458c3dd7ca70a80674f867b8b0e3cd6c +certbot-nginx==0.9.1 \ + --hash=sha256:3bd59a4f63a989eb31c04775107139bf45c2373a6f0b7bea4a3a1362da5c2ae7 \ + --hash=sha256:22f277846ccf5c8787cac2b35a7897780f05f4022de02d8b4b731c2cd957354c UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/letsencrypt-auto-source/certbot-auto.asc b/letsencrypt-auto-source/certbot-auto.asc index ed1adc5d0..71a54bde5 100644 --- a/letsencrypt-auto-source/certbot-auto.asc +++ b/letsencrypt-auto-source/certbot-auto.asc @@ -1,11 +1,11 @@ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 -iQEcBAABAgAGBQJX9ENHAAoJEE0XyZXNl3XyFzIH/ibJU3UOKdHWeHEq+MBCqqaN -1oJJ7kGUpnvE+jqXpfuvKjchQjj8369ht9KW9CLXbyZycHBLYkaqYznZ69e/0Xg7 -BDs3XNGxOxVrOE4nZngqyUa3vwuT5fjq55fhUJtKaYHuKb2hkkcs0GneDt0UfTMR -orw0OSII5OouR6CyP6I3nnyyEkt/o4Hpt0nXyf7Q+vLh1+7ljjf3FhFd52D/kfxa -i1XoiHq5WdXnnqDDS3RQj+0KAPLm31rfM3kN201+HIxamtRJaPPX+v3iXkATtKGf -CiB/PD/ZSAS6priPThhwj3bRId2zE+PQDha0TE18qHyaGvCACG8uTAIWGoQimWY= -=KF0F +iQEcBAABAgAGBQJX9shpAAoJEE0XyZXNl3XyeAUH/0928PysUZlLCQRpw3GPJnr0 +WgE1duULRfDKOdyoj8cIABEcxyK+rASyBju57Hx80Zuai9x4XSHJK7k9BXrZrU5k +KHZWbaNOKLN+C7/HTSOqGwalGTLglRJLZMwcj4rs8jtftg6GiWXvtnWuwqoiZJe4 +sCdddm2gu4D2VLp/QpBU6Gepuls4PmtB7SzwRUC6SAkWf5ntwJ4mq65bwKLcTPaZ +oRKoswo+eyiosH2SVVgiyAz7U96t2gxfK2pNoTdCUQGjuRaD6P2yBCdJA5h4L2l2 +W+/31zJpw/TgFErWpNuNYYoMh8cswaWXDNMUscsuduQ9KPLhSHQQ9JZ5f4w+9PM= +=Zhq9 -----END PGP SIGNATURE----- diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index ee9f11272..eb627032f 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -19,7 +19,7 @@ XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} VENV_NAME="letsencrypt" VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} VENV_BIN="$VENV_PATH/bin" -LE_AUTO_VERSION="0.10.0.dev0" +LE_AUTO_VERSION="0.9.1" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -761,18 +761,18 @@ letsencrypt==0.7.0 \ # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. -acme==0.9.0 \ - --hash=sha256:6d98bdec5fd9171e368a39cb2458d2d62599e52e2899650684379dba03f09d96 \ - --hash=sha256:fca3e57e5155ee0e80852e1b13a9d76a302728b78a9a1c2c38cb77d699aab7c5 -certbot==0.9.0 \ - --hash=sha256:08652503bb94f0863c2c2d53d37fc48966b080a70f578f980b05eee11bea7eaf \ - --hash=sha256:8dd4d3e2de2b2392fd8f41e73434dae737653bc41a54ce4a273768519a5ab61e -certbot-apache==0.9.0 \ - --hash=sha256:10e3096ff27adf6e75aff7722ada963f1337ef455f203495c025e883d8f816e2 \ - --hash=sha256:fd8bb3e7d36c64a5841083bed447250e110d458323b51d8a210b8f0b18e28c9a -certbot-nginx==0.9.0 \ - --hash=sha256:edbb7c1164225af770af6aea42496b575b5c115afa4d9ab7b1e587b3e6d0c92b \ - --hash=sha256:2f18504832b13f11e07dc87df758a7c5c68e24341628eb334ff7a5976a384717 +acme==0.9.1 \ + --hash=sha256:83e6188d5f149678b77ff3c8f8f94983f3c448490ffa634c7e9f2e93e7351fb0 \ + --hash=sha256:0effd08d144eedbfeb7dd784e9c8673ef3138cf48d35c8c33a1dd5bee9fd8207 +certbot==0.9.1 \ + --hash=sha256:88237a4f6d337d40185a644407f9c7adb6eab87c43b8bf56c1edc02ce82a9d81 \ + --hash=sha256:180354a3e95610ff8ba7f344011f2fcba1186d8efb7b25867266f47048e1e2f7 +certbot-apache==0.9.1 \ + --hash=sha256:cb9931294d44a1d6d44eaa2e92cb30daf6f2e0f29f6e7f00849709f0dd408b40 \ + --hash=sha256:1c09a6b4d087748f2aa143b0a7ced321458c3dd7ca70a80674f867b8b0e3cd6c +certbot-nginx==0.9.1 \ + --hash=sha256:3bd59a4f63a989eb31c04775107139bf45c2373a6f0b7bea4a3a1362da5c2ae7 \ + --hash=sha256:22f277846ccf5c8787cac2b35a7897780f05f4022de02d8b4b731c2cd957354c UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/letsencrypt-auto-source/letsencrypt-auto.sig b/letsencrypt-auto-source/letsencrypt-auto.sig index fd3a3ba8a33de8890dd2a652d10aeb2f1feeb87c..80ec36e19ad2a8967d36cd409347726b08cdf0d7 100644 GIT binary patch literal 256 zcmV+b0ssCA_-8=flSy<6Fl!QgcZZkvQ*|qkSu6D;yM{EED_69C0x#H)Ik$m9EG-?> zJ3eBlvyacp^nP0-VmT^Zaulp4$n|jriq$Ob}(z zpw0!bJ9aW}0B10DLIlQqBO4)Zzq~}P(8Gy> zOJ-LGt+9ha9gA_+N&zB_*dQCAcZuH1rAyFRt%Wy7h=IbIZCNaoc2Y#3;ujwk>17~k zNj{XBj~F04jH>;gmA%0h(}GM?Ju Date: Fri, 7 Oct 2016 00:18:05 -0700 Subject: [PATCH 04/13] Document the Nginx plugin release (#3588) * Document the Nginx plugin release * Tweak * Remove mrueg nginx instructions for now? * Shipped -> included * keep order of plugin descriptions consistent with the table --- docs/using.rst | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index 18dca071a..4604fd78f 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -179,21 +179,6 @@ want to use the Apache plugin, it has to be installed separately: emerge -av app-crypt/letsencrypt emerge -av app-crypt/letsencrypt-apache -Currently, only the Apache plugin is included in Portage. However, if you -Warning! -You can use Layman to add the mrueg overlay which does include a package for the -Certbot Nginx plugin, however, this plugin is known to be buggy and should only -be used with caution after creating a backup up your Nginx configuration. -We strongly recommend you use the app-crypt/letsencrypt package instead until -the Nginx plugin is ready. - -.. code-block:: shell - - emerge -av app-portage/layman - layman -S - layman -a mrueg - emerge -av app-crypt/letsencrypt-nginx - When using the Apache plugin, you will run into a "cannot find a cert or key directive" error if you're sporting the default Gentoo ``httpd.conf``. You can fix this by commenting out two lines in ``/etc/apache2/httpd.conf`` @@ -272,13 +257,14 @@ apache_ Y Y | Automates obtaining and installing a cert with Apache 2. | Debian-based distributions with ``libaugeas0`` 1.0+. webroot_ Y N | Obtains a cert by writing to the webroot directory of an http-01_ (80) | already running webserver. +nginx_ Y Y | Automates obtaining and installing a cert with Nginx. Alpha tls-sni-01_ (443) + | release shipped with Certbot 0.9.0. standalone_ Y N | Uses a "standalone" webserver to obtain a cert. Requires http-01_ (80) or | port 80 or 443 to be available. This is useful on systems tls-sni-01_ (443) | with no webserver, or when direct integration with the local | webserver is not supported or not desired. manual_ Y N | Helps you obtain a cert by giving you instructions to perform http-01_ (80) or | domain validation yourself. dns-01_ (53) -nginx_ Y Y | Very experimental and not included in certbot-auto_. tls-sni-01_ (443) =========== ==== ==== =============================================================== ============================= Under the hood, plugins use one of several ACME protocol "Challenges_" to @@ -349,6 +335,19 @@ your webserver configuration, you might need to modify the configuration to ensure that files inside ``/.well-known/acme-challenge`` are served by the webserver. +Nginx +----- + +The Nginx plugin has been distributed with Cerbot since version 0.9.0 and should +work for most configurations. Because it is alpha code, we recommend backing up Nginx +configurations before using it (though you can also revert changes to +configurations with ``certbot --nginx rollback``). You can use it by providing +the ``--nginx`` flag on the commandline. + +:: + + certbot --nginx + Standalone ---------- @@ -378,15 +377,6 @@ the UI, you can use the plugin to obtain a cert by specifying to copy and paste commands into another terminal session, which may be on a different computer. -Nginx ------ - -In the future, if you're running Nginx you will hopefully be able to use this -plugin to automatically obtain and install your certificate. The Nginx plugin is -still experimental, however, and is not installed with certbot-auto_. If -installed, you can select this plugin on the command line by including -``--nginx``. - .. _third-party-plugins: Third-party plugins From 9d1a0b1d315ccf776c47569edf348c5ab478ac34 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 10 Oct 2016 13:17:49 -0700 Subject: [PATCH 05/13] Create symlinks at runtime and don't use relative paths (#3600) * Create symlinks at runtime in cli_test.py * use test_util.vector_path rather than hardcoding path * Reference #2716 in comment about too many lines in cli.py --- certbot/tests/cli_test.py | 65 ++++++++++++++----- .../testdata/live/sample-renewal/cert.pem | 1 - .../testdata/live/sample-renewal/chain.pem | 1 - .../live/sample-renewal/fullchain.pem | 1 - .../testdata/live/sample-renewal/privkey.pem | 1 - .../cert1.pem | 0 .../chain1.pem | 0 .../fullchain1.pem | 0 .../privkey1.pem | 0 .../testdata/sample-renewal-ancient.conf | 8 +-- 10 files changed, 52 insertions(+), 25 deletions(-) delete mode 120000 certbot/tests/testdata/live/sample-renewal/cert.pem delete mode 120000 certbot/tests/testdata/live/sample-renewal/chain.pem delete mode 120000 certbot/tests/testdata/live/sample-renewal/fullchain.pem delete mode 120000 certbot/tests/testdata/live/sample-renewal/privkey.pem rename certbot/tests/testdata/{archive/sample-renewal => sample-archive}/cert1.pem (100%) rename certbot/tests/testdata/{archive/sample-renewal => sample-archive}/chain1.pem (100%) rename certbot/tests/testdata/{archive/sample-renewal => sample-archive}/fullchain1.pem (100%) rename certbot/tests/testdata/{archive/sample-renewal => sample-archive}/privkey1.pem (100%) diff --git a/certbot/tests/cli_test.py b/certbot/tests/cli_test.py index 39a54258a..fde634c4c 100644 --- a/certbot/tests/cli_test.py +++ b/certbot/tests/cli_test.py @@ -1,4 +1,7 @@ """Tests for certbot.cli.""" +# Many tests in this file should be moved into +# main_test.py and renewal_test.py. See #2716. +# pylint: disable=too-many-lines from __future__ import print_function import argparse @@ -575,7 +578,7 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods def _test_renewal_common(self, due_for_renewal, extra_args, log_out=None, args=None, should_renew=True, error_expected=False): # pylint: disable=too-many-locals,too-many-arguments - cert_path = 'certbot/tests/testdata/cert.pem' + cert_path = test_util.vector_path('cert.pem') chain_path = '/etc/letsencrypt/live/foo.bar/fullchain.pem' mock_lineage = mock.MagicMock(cert=cert_path, fullchain=chain_path) mock_lineage.should_autorenew.return_value = due_for_renewal @@ -651,32 +654,60 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods self._test_renewal_common(False, ['-tvv', '--debug', '--keep'], log_out="not yet due", should_renew=False) - def _dump_log(self): with open(os.path.join(self.logs_dir, "letsencrypt.log")) as lf: print("Logs:") print(lf.read()) + def _make_lineage(self, testfile): + """Creates a lineage defined by testfile. - def _make_test_renewal_conf(self, testfile): + This creates the archive, live, and renewal directories if + necessary and creates a simple lineage. + + :param str testfile: configuration file to base the lineage on + + :returns: path to the renewal conf file for the created lineage + :rtype: str + + """ + lineage_name = testfile[:-len('.conf')] + + conf_dir = os.path.join( + self.config_dir, constants.RENEWAL_CONFIGS_DIR) + archive_dir = os.path.join( + self.config_dir, constants.ARCHIVE_DIR, lineage_name) + live_dir = os.path.join( + self.config_dir, constants.LIVE_DIR, lineage_name) + + for directory in (archive_dir, conf_dir, live_dir,): + if not os.path.exists(directory): + os.makedirs(directory) + + sample_archive = test_util.vector_path('sample-archive') + for kind in os.listdir(sample_archive): + shutil.copyfile(os.path.join(sample_archive, kind), + os.path.join(archive_dir, kind)) + + for kind in storage.ALL_FOUR: + os.symlink(os.path.join(archive_dir, '{0}1.pem'.format(kind)), + os.path.join(live_dir, '{0}.pem'.format(kind))) + + conf_path = os.path.join(self.config_dir, conf_dir, testfile) with open(test_util.vector_path(testfile)) as src: - # put the correct path for cert.pem, chain.pem etc in the renewal conf - renewal_conf = src.read().replace("MAGICDIR", test_util.vector_path()) - rd = os.path.join(self.config_dir, "renewal") - if not os.path.exists(rd): - os.makedirs(rd) - rc = os.path.join(rd, "sample-renewal.conf") - with open(rc, "w") as dest: - dest.write(renewal_conf) - return rc + with open(conf_path, 'w') as dst: + dst.writelines( + line.replace('MAGICDIR', self.config_dir) for line in src) + + return conf_path def test_renew_verb(self): - self._make_test_renewal_conf('sample-renewal.conf') + self._make_lineage('sample-renewal.conf') args = ["renew", "--dry-run", "-tvv"] self._test_renewal_common(True, [], args=args, should_renew=True) def test_quiet_renew(self): - self._make_test_renewal_conf('sample-renewal.conf') + self._make_lineage('sample-renewal.conf') args = ["renew", "--dry-run"] _, _, stdout = self._test_renewal_common(True, [], args=args, should_renew=True) out = stdout.getvalue() @@ -688,13 +719,13 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods self.assertEqual("", out) def test_renew_hook_validation(self): - self._make_test_renewal_conf('sample-renewal.conf') + self._make_lineage('sample-renewal.conf') args = ["renew", "--dry-run", "--post-hook=no-such-command"] self._test_renewal_common(True, [], args=args, should_renew=False, error_expected=True) def test_renew_no_hook_validation(self): - self._make_test_renewal_conf('sample-renewal.conf') + self._make_lineage('sample-renewal.conf') args = ["renew", "--dry-run", "--post-hook=no-such-command", "--disable-hook-validation"] self._test_renewal_common(True, [], args=args, should_renew=True, @@ -703,7 +734,7 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods @mock.patch("certbot.cli.set_by_cli") def test_ancient_webroot_renewal_conf(self, mock_set_by_cli): mock_set_by_cli.return_value = False - rc_path = self._make_test_renewal_conf('sample-renewal-ancient.conf') + rc_path = self._make_lineage('sample-renewal-ancient.conf') args = mock.MagicMock(account=None, email=None, webroot_path=None) config = configuration.NamespaceConfig(args) lineage = storage.RenewableCert(rc_path, diff --git a/certbot/tests/testdata/live/sample-renewal/cert.pem b/certbot/tests/testdata/live/sample-renewal/cert.pem deleted file mode 120000 index e06effe40..000000000 --- a/certbot/tests/testdata/live/sample-renewal/cert.pem +++ /dev/null @@ -1 +0,0 @@ -../../archive/sample-renewal/cert1.pem \ No newline at end of file diff --git a/certbot/tests/testdata/live/sample-renewal/chain.pem b/certbot/tests/testdata/live/sample-renewal/chain.pem deleted file mode 120000 index 71f665f29..000000000 --- a/certbot/tests/testdata/live/sample-renewal/chain.pem +++ /dev/null @@ -1 +0,0 @@ -../../archive/sample-renewal/chain1.pem \ No newline at end of file diff --git a/certbot/tests/testdata/live/sample-renewal/fullchain.pem b/certbot/tests/testdata/live/sample-renewal/fullchain.pem deleted file mode 120000 index 0f06f077d..000000000 --- a/certbot/tests/testdata/live/sample-renewal/fullchain.pem +++ /dev/null @@ -1 +0,0 @@ -../../archive/sample-renewal/fullchain1.pem \ No newline at end of file diff --git a/certbot/tests/testdata/live/sample-renewal/privkey.pem b/certbot/tests/testdata/live/sample-renewal/privkey.pem deleted file mode 120000 index 5187eda6b..000000000 --- a/certbot/tests/testdata/live/sample-renewal/privkey.pem +++ /dev/null @@ -1 +0,0 @@ -../../archive/sample-renewal/privkey1.pem \ No newline at end of file diff --git a/certbot/tests/testdata/archive/sample-renewal/cert1.pem b/certbot/tests/testdata/sample-archive/cert1.pem similarity index 100% rename from certbot/tests/testdata/archive/sample-renewal/cert1.pem rename to certbot/tests/testdata/sample-archive/cert1.pem diff --git a/certbot/tests/testdata/archive/sample-renewal/chain1.pem b/certbot/tests/testdata/sample-archive/chain1.pem similarity index 100% rename from certbot/tests/testdata/archive/sample-renewal/chain1.pem rename to certbot/tests/testdata/sample-archive/chain1.pem diff --git a/certbot/tests/testdata/archive/sample-renewal/fullchain1.pem b/certbot/tests/testdata/sample-archive/fullchain1.pem similarity index 100% rename from certbot/tests/testdata/archive/sample-renewal/fullchain1.pem rename to certbot/tests/testdata/sample-archive/fullchain1.pem diff --git a/certbot/tests/testdata/archive/sample-renewal/privkey1.pem b/certbot/tests/testdata/sample-archive/privkey1.pem similarity index 100% rename from certbot/tests/testdata/archive/sample-renewal/privkey1.pem rename to certbot/tests/testdata/sample-archive/privkey1.pem diff --git a/certbot/tests/testdata/sample-renewal-ancient.conf b/certbot/tests/testdata/sample-renewal-ancient.conf index dd3075b8e..333bcaa18 100644 --- a/certbot/tests/testdata/sample-renewal-ancient.conf +++ b/certbot/tests/testdata/sample-renewal-ancient.conf @@ -1,7 +1,7 @@ -cert = MAGICDIR/live/sample-renewal/cert.pem -privkey = MAGICDIR/live/sample-renewal/privkey.pem -chain = MAGICDIR/live/sample-renewal/chain.pem -fullchain = MAGICDIR/live/sample-renewal/fullchain.pem +cert = MAGICDIR/live/sample-renewal-ancient/cert.pem +privkey = MAGICDIR/live/sample-renewal-ancient/privkey.pem +chain = MAGICDIR/live/sample-renewal-ancient/chain.pem +fullchain = MAGICDIR/live/sample-renewal-ancient/fullchain.pem renew_before_expiry = 1 year # Options and defaults used in the renewal process From e6686fbdb5ffe72bc19d64e81f52283b295cc99e Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Mon, 10 Oct 2016 18:36:58 -0700 Subject: [PATCH 06/13] Update Where Are My Certs section. (#3419) * Update Where Are My Certs section. This combines the `cert.pem` and `chain.pem` sections into a single paragraph, making it clearer that they are closely connected. It also adds text indicating that they are less common and moves them below the section for `fullchain.pem`. * Update "Getting Help" section. * Add link to document missing intermediate. * Remove incorrect line about ordering. Also remove "(as the filename suggests)," and clarify file ordering in the fullchain.pem section. --- docs/using.rst | 63 +++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 32 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index 4604fd78f..d18d118cf 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -587,43 +587,41 @@ The following files are available: This is what Apache needs for `SSLCertificateKeyFile `_, - and nginx for `ssl_certificate_key + and Nginx for `ssl_certificate_key `_. -``cert.pem`` - Server certificate only. - - This is what Apache < 2.4.8 needs for `SSLCertificateFile - `_. - -``chain.pem`` - All certificates that need to be served by the browser **excluding** - server certificate, i.e. root and intermediate certificates only. - - This is what Apache < 2.4.8 needs for `SSLCertificateChainFile - `_, - and what nginx >= 1.3.7 needs for `ssl_trusted_certificate - `_. - ``fullchain.pem`` - All certificates, **including** server certificate. This is - concatenation of ``cert.pem`` and ``chain.pem``. + All certificates, **including** server certificate (aka leaf certificate or + end-entity certificate). The server certificate is the first one in this file, + followed by any intermediates. This is what Apache >= 2.4.8 needs for `SSLCertificateFile `_, - and what nginx needs for `ssl_certificate + and what Nginx needs for `ssl_certificate `_. +``cert.pem`` and ``chain.pem`` (less common) + ``cert.pem`` contains the server certificate by itself, and + ``chain.pem`` contains the additional intermediate certificate or + certificates that web browsers will need in order to validate the + server certificate. If you provide one of these files to your web + server, you **must** provide both of them, or some browsers will show + "This Connection is Untrusted" errors for your site, `some of the time + `_. -For both chain files, all certificates are ordered from root (primary -certificate) towards leaf. + Apache < 2.4.8 needs these for `SSLCertificateFile + `_. + and `SSLCertificateChainFile + `_, + respectively. -Please note, that **you must use** either ``chain.pem`` or -``fullchain.pem``. In case of webservers, using only ``cert.pem``, -will cause nasty errors served through the browsers! + If you're using OCSP stapling with Nginx >= 1.3.7, ``chain.pem`` should be + provided as the `ssl_trusted_certificate + `_ + to validate OCSP responses. -.. note:: All files are PEM-encoded (as the filename suffix - suggests). If you need other format, such as DER or PFX, then you +.. note:: All files are PEM-encoded. + If you need other format, such as DER or PFX, then you could convert using ``openssl``. You can automate that with ``--renew-hook`` if you're using automatic renewal_. @@ -653,14 +651,15 @@ By default, the following locations are searched: Getting help ============ -If you're having problems you can chat with us on `IRC (#certbot @ -OFTC) `_ or at -`IRC (#letsencrypt @ freenode) `_ -or get support on the Let's Encrypt `forums `_. +If you're having problems, we recommend posting on the Let's Encrypt +`Community Forum `_. + +You can also chat with us on IRC: `(#certbot @ +OFTC) `_ or +`(#letsencrypt @ freenode) `_. If you find a bug in the software, please do report it in our `issue -tracker -`_. Remember to +tracker `_. Remember to give us as much information as possible: - copy and paste exact command line used and the output (though mind From 54b36269cef419faac3413b23bf476a08edb2da3 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 10 Oct 2016 18:44:39 -0700 Subject: [PATCH 07/13] Only verify required ports are available (#3608) * only verify port is available when you actually need it * refactor code to create achalls * Test port checks are based on achall * test that only the port for the requested challenge is checked in standalone --- certbot/plugins/standalone.py | 37 +++++++++++++++++++----------- certbot/plugins/standalone_test.py | 30 +++++++++++++++--------- tests/boulder-integration.sh | 13 +++++++++-- tests/integration/_common.sh | 8 ++++--- 4 files changed, 58 insertions(+), 30 deletions(-) diff --git a/certbot/plugins/standalone.py b/certbot/plugins/standalone.py index 0195b2726..e8c11a416 100644 --- a/certbot/plugins/standalone.py +++ b/certbot/plugins/standalone.py @@ -194,15 +194,6 @@ class Authenticator(common.Plugin): return [challenges.Challenge.TYPES[name] for name in self.conf("supported-challenges").split(",")] - @property - def _necessary_ports(self): - necessary_ports = set() - if challenges.HTTP01 in self.supported_challenges: - necessary_ports.add(self.config.http01_port) - if challenges.TLSSNI01 in self.supported_challenges: - necessary_ports.add(self.config.tls_sni_01_port) - return necessary_ports - def more_info(self): # pylint: disable=missing-docstring return("This authenticator creates its own ephemeral TCP listener " "on the necessary port in order to respond to incoming " @@ -217,12 +208,30 @@ class Authenticator(common.Plugin): # pylint: disable=unused-argument,missing-docstring return self.supported_challenges - def perform(self, achalls): # pylint: disable=missing-docstring - renewer = self.config.verb == "renew" - if any(util.already_listening(port, renewer) for port in self._necessary_ports): + def _verify_ports_are_available(self, achalls): + """Confirm the ports are available to solve all achalls. + + :param list achalls: list of + :class:`~certbot.achallenges.AnnotatedChallenge` + + :raises .errors.MisconfigurationError: if required port is + unavailable + + """ + ports = [] + if any(isinstance(ac.chall, challenges.HTTP01) for ac in achalls): + ports.append(self.config.http01_port) + if any(isinstance(ac.chall, challenges.TLSSNI01) for ac in achalls): + ports.append(self.config.tls_sni_01_port) + + renewer = (self.config.verb == "renew") + + if any(util.already_listening(port, renewer) for port in ports): raise errors.MisconfigurationError( - "At least one of the (possibly) required ports is " - "already taken.") + "At least one of the required ports is already taken.") + + def perform(self, achalls): # pylint: disable=missing-docstring + self._verify_ports_are_available(achalls) try: return self.perform2(achalls) diff --git a/certbot/plugins/standalone_test.py b/certbot/plugins/standalone_test.py index 1dfa3950a..56f842f68 100644 --- a/certbot/plugins/standalone_test.py +++ b/certbot/plugins/standalone_test.py @@ -137,20 +137,33 @@ class AuthenticatorTest(unittest.TestCase): self.assertEqual(self.auth.get_chall_pref(domain=None), [challenges.TLSSNI01]) + @classmethod + def _get_achalls(cls): + domain = b'localhost' + key = jose.JWK.load(test_util.load_vector('rsa512_key.pem')) + http_01 = achallenges.KeyAuthorizationAnnotatedChallenge( + challb=acme_util.HTTP01_P, domain=domain, account_key=key) + tls_sni_01 = achallenges.KeyAuthorizationAnnotatedChallenge( + challb=acme_util.TLSSNI01_P, domain=domain, account_key=key) + + return [http_01, tls_sni_01] + @mock.patch("certbot.plugins.standalone.util") def test_perform_already_listening(self, mock_util): - for chall, port in ((challenges.TLSSNI01.typ, 1234), - (challenges.HTTP01.typ, 4321)): + http_01, tls_sni_01 = self._get_achalls() + + for achall, port in ((http_01, self.config.http01_port,), + (tls_sni_01, self.config.tls_sni_01_port)): mock_util.already_listening.return_value = True - self.config.standalone_supported_challenges = chall self.assertRaises( - errors.MisconfigurationError, self.auth.perform, []) + errors.MisconfigurationError, self.auth.perform, [achall]) mock_util.already_listening.assert_called_once_with(port, False) mock_util.already_listening.reset_mock() @mock.patch("certbot.plugins.standalone.zope.component.getUtility") def test_perform(self, unused_mock_get_utility): - achalls = [1, 2, 3] + achalls = self._get_achalls() + self.auth.perform2 = mock.Mock(return_value=mock.sentinel.responses) self.assertEqual(mock.sentinel.responses, self.auth.perform(achalls)) self.auth.perform2.assert_called_once_with(achalls) @@ -181,12 +194,7 @@ class AuthenticatorTest(unittest.TestCase): socket.errno.ENOTCONN, []) def test_perform2(self): - domain = b'localhost' - key = jose.JWK.load(test_util.load_vector('rsa512_key.pem')) - http_01 = achallenges.KeyAuthorizationAnnotatedChallenge( - challb=acme_util.HTTP01_P, domain=domain, account_key=key) - tls_sni_01 = achallenges.KeyAuthorizationAnnotatedChallenge( - challb=acme_util.TLSSNI01_P, domain=domain, account_key=key) + http_01, tls_sni_01 = self._get_achalls() self.auth.servers = mock.MagicMock() diff --git a/tests/boulder-integration.sh b/tests/boulder-integration.sh index ab8fde5f6..a70f13f8e 100755 --- a/tests/boulder-integration.sh +++ b/tests/boulder-integration.sh @@ -33,8 +33,17 @@ common() { "$@" } -common --domains le1.wtf --standalone-supported-challenges tls-sni-01 auth -common --domains le2.wtf --standalone-supported-challenges http-01 run +# We start a server listening on the port for the +# unrequested challenge to prevent regressions in #3601. +python -m SimpleHTTPServer $http_01_port & +python_server_pid=$! +common --domains le1.wtf --preferred-challenges tls-sni-01 auth +kill $python_server_pid +python -m SimpleHTTPServer $tls_sni_01_port & +python_server_pid=$! +common --domains le2.wtf --preferred-challenges http-01 run +kill $python_server_pid + common -a manual -d le.wtf auth --rsa-key-size 4096 export CSR_PATH="${root}/csr.der" KEY_PATH="${root}/key.pem" \ diff --git a/tests/integration/_common.sh b/tests/integration/_common.sh index 8992a18c0..935d44994 100755 --- a/tests/integration/_common.sh +++ b/tests/integration/_common.sh @@ -9,7 +9,9 @@ then fi store_flags="--config-dir $root/conf --work-dir $root/work" store_flags="$store_flags --logs-dir $root/logs" -export root store_flags +tls_sni_01_port=5001 +http_01_port=5002 +export root store_flags tls_sni_01_port http_01_port certbot_test () { certbot_test_no_force_renew \ @@ -21,8 +23,8 @@ certbot_test_no_force_renew () { certbot \ --server "${SERVER:-http://localhost:4000/directory}" \ --no-verify-ssl \ - --tls-sni-01-port 5001 \ - --http-01-port 5002 \ + --tls-sni-01-port $tls_sni_01_port \ + --http-01-port $http_01_port \ --manual-test-mode \ $store_flags \ --non-interactive \ From 4d6bf49393d3d219ade57dc492443e0ec08bec4e Mon Sep 17 00:00:00 2001 From: Erica Portnoy Date: Mon, 10 Oct 2016 19:04:35 -0700 Subject: [PATCH 08/13] Mark parsed Nginx addresses as listening sslishly when an ssl on directive is included in the server block. (#3607) --- certbot-nginx/certbot_nginx/parser.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/certbot-nginx/certbot_nginx/parser.py b/certbot-nginx/certbot_nginx/parser.py index a9ef21f2e..6203b5f71 100644 --- a/certbot-nginx/certbot_nginx/parser.py +++ b/certbot-nginx/certbot_nginx/parser.py @@ -473,6 +473,8 @@ def parse_server(server): 'ssl': False, 'names': set()} + apply_ssl_to_all_addrs = False + for directive in server: if not directive: continue @@ -486,6 +488,11 @@ def parse_server(server): _get_servernames(directive[1])) elif directive[0] == 'ssl' and directive[1] == 'on': parsed_server['ssl'] = True + apply_ssl_to_all_addrs = True + + if apply_ssl_to_all_addrs: + for addr in parsed_server['addrs']: + addr.ssl = True return parsed_server From 20ac4aebaf58459e26a8533db02c54d19926d2ad Mon Sep 17 00:00:00 2001 From: Erica Portnoy Date: Tue, 11 Oct 2016 12:22:58 -0700 Subject: [PATCH 09/13] Match psutil port open checking behavior to that of socket test, and update tests. (#3589) * Match psutil port open checking behavior to that of socket test, and update tests. * Update docstring --- certbot/plugins/standalone_test.py | 24 +++++++++++++++++------- certbot/plugins/util.py | 3 ++- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/certbot/plugins/standalone_test.py b/certbot/plugins/standalone_test.py index 56f842f68..cb82ae7d8 100644 --- a/certbot/plugins/standalone_test.py +++ b/certbot/plugins/standalone_test.py @@ -106,13 +106,22 @@ class SupportedChallengesValidatorTest(unittest.TestCase): self.assertEqual("tls-sni-01,http-01", self._call("dvsni,http-01")) +def get_open_port(): + """Gets an open port number from the OS.""" + open_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) + open_socket.bind(("", 0)) + port = open_socket.getsockname()[1] + open_socket.close() + return port + class AuthenticatorTest(unittest.TestCase): """Tests for certbot.plugins.standalone.Authenticator.""" def setUp(self): from certbot.plugins.standalone import Authenticator + self.config = mock.MagicMock( - tls_sni_01_port=1234, http01_port=4321, + tls_sni_01_port=get_open_port(), http01_port=get_open_port(), standalone_supported_challenges="tls-sni-01,http-01") self.auth = Authenticator(self.config, name="standalone") @@ -170,15 +179,16 @@ class AuthenticatorTest(unittest.TestCase): @mock.patch("certbot.plugins.standalone.zope.component.getUtility") def _test_perform_bind_errors(self, errno, achalls, mock_get_utility): + port = get_open_port() def _perform2(unused_achalls): - raise errors.StandaloneBindError(mock.Mock(errno=errno), 1234) + raise errors.StandaloneBindError(mock.Mock(errno=errno), port) self.auth.perform2 = mock.MagicMock(side_effect=_perform2) self.auth.perform(achalls) mock_get_utility.assert_called_once_with(interfaces.IDisplay) notification = mock_get_utility.return_value.notification self.assertEqual(1, notification.call_count) - self.assertTrue("1234" in notification.call_args[0][0]) + self.assertTrue(str(port) in notification.call_args[0][0]) def test_perform_eacces(self): # pylint: disable=no-value-for-parameter @@ -210,12 +220,12 @@ class AuthenticatorTest(unittest.TestCase): self.assertTrue(isinstance(responses[1], challenges.TLSSNI01Response)) self.assertEqual(self.auth.servers.run.mock_calls, [ - mock.call(4321, challenges.HTTP01), - mock.call(1234, challenges.TLSSNI01), + mock.call(self.config.http01_port, challenges.HTTP01), + mock.call(self.config.tls_sni_01_port, challenges.TLSSNI01), ]) self.assertEqual(self.auth.served, { - "server1234": set([tls_sni_01]), - "server4321": set([http_01]), + "server" + str(self.config.tls_sni_01_port): set([tls_sni_01]), + "server" + str(self.config.http01_port): set([http_01]), }) self.assertEqual(1, len(self.auth.http_01_resources)) self.assertEqual(1, len(self.auth.certs)) diff --git a/certbot/plugins/util.py b/certbot/plugins/util.py index b97ca1afd..0d0526fb9 100644 --- a/certbot/plugins/util.py +++ b/certbot/plugins/util.py @@ -123,7 +123,8 @@ def already_listening_psutil(port, renewer=False): return False listeners = [conn.pid for conn in net_connections - if conn.status == 'LISTEN' and + if (conn.status == 'LISTEN' or + conn.status == 'TIME_WAIT') and conn.type == socket.SOCK_STREAM and conn.laddr[1] == port] try: From 052be6d4bae07ea401e0ee4cd72a2862b9be5f46 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 11 Oct 2016 17:50:11 -0700 Subject: [PATCH 10/13] Check version requirements on optional dependencies (#3618) * Add and test activate function to acme. This function can be used to check if our optional dependencies are available and they meet our version requirements. * use activate in dns_resolver * use activate in dns_available() in challenges_test * Use activate in dns_resolver_test * Use activate in certbot.plugins.util_test * Use acme.util.activate for psutil * Better testing and handling of missing deps * Factored out *_available() code into a common function * Delayed exception caused from using acme.dns_resolver without dnspython until the function is called. This makes both production and testing code simpler. * Make a common subclass for already_listening tests * Simplify mocking of USE_PSUTIL in tests --- acme/acme/challenges.py | 7 +-- acme/acme/challenges_test.py | 27 +++++------- acme/acme/dns_resolver.py | 19 ++++++++- acme/acme/dns_resolver_test.py | 49 ++++++++++----------- acme/acme/test_util.py | 16 +++++++ acme/acme/util.py | 18 ++++++++ acme/acme/util_test.py | 18 ++++++++ certbot/plugins/util.py | 10 ++++- certbot/plugins/util_test.py | 78 ++++++++++++---------------------- certbot/tests/test_util.py | 16 +++++++ 10 files changed, 157 insertions(+), 101 deletions(-) diff --git a/acme/acme/challenges.py b/acme/acme/challenges.py index 4ebd37bf9..9f9cc05b8 100644 --- a/acme/acme/challenges.py +++ b/acme/acme/challenges.py @@ -9,6 +9,7 @@ from cryptography.hazmat.primitives import hashes import OpenSSL import requests +from acme import dns_resolver from acme import errors from acme import crypto_util from acme import fields @@ -232,11 +233,11 @@ class DNS01Response(KeyAuthorizationChallengeResponse): logger.debug("Verifying %s at %s...", chall.typ, validation_domain_name) try: - from acme import dns_resolver - except ImportError: # pragma: no cover + txt_records = dns_resolver.txt_records_for_name( + validation_domain_name) + except errors.DependencyError: raise errors.DependencyError("Local validation for 'dns-01' " "challenges requires 'dnspython'") - txt_records = dns_resolver.txt_records_for_name(validation_domain_name) exists = validation in txt_records if not exists: logger.debug("Key authorization from response (%r) doesn't match " diff --git a/acme/acme/challenges_test.py b/acme/acme/challenges_test.py index dfd40ebdb..5ac07abdd 100644 --- a/acme/acme/challenges_test.py +++ b/acme/acme/challenges_test.py @@ -10,6 +10,7 @@ from six.moves.urllib import parse as urllib_parse # pylint: disable=import-err from acme import errors from acme import jose from acme import test_util +from acme.dns_resolver import DNS_REQUIREMENT CERT = test_util.load_comparable_cert('cert.pem') KEY = jose.JWKRSA(key=test_util.load_rsa_private_key('rsa512_key.pem')) @@ -76,20 +77,6 @@ class KeyAuthorizationChallengeResponseTest(unittest.TestCase): self.assertFalse(response.verify(self.chall, KEY.public_key())) -def dns_available(): - """Checks if dns can be imported. - - :rtype: bool - :returns: ``True`` if dns can be imported, otherwise, ``False`` - - """ - try: - import dns # pylint: disable=unused-variable - except ImportError: # pragma: no cover - return False - return True # pragma: no cover - - class DNS01ResponseTest(unittest.TestCase): # pylint: disable=too-many-instance-attributes @@ -122,7 +109,13 @@ class DNS01ResponseTest(unittest.TestCase): key2 = jose.JWKRSA.load(test_util.load_vector('rsa256_key.pem')) self.response.simple_verify(self.chall, "local", key2.public_key()) - @test_util.skip_unless(dns_available(), + @mock.patch('acme.dns_resolver.DNS_AVAILABLE', False) + def test_simple_verify_without_dns(self): + self.assertRaises( + errors.DependencyError, self.response.simple_verify, + self.chall, 'local', KEY.public_key()) + + @test_util.skip_unless(test_util.requirement_available(DNS_REQUIREMENT), "optional dependency dnspython is not available") def test_simple_verify_good_validation(self): # pragma: no cover with mock.patch(self.records_for_name_path) as mock_resolver: @@ -133,7 +126,7 @@ class DNS01ResponseTest(unittest.TestCase): mock_resolver.assert_called_once_with( self.chall.validation_domain_name("local")) - @test_util.skip_unless(dns_available(), + @test_util.skip_unless(test_util.requirement_available(DNS_REQUIREMENT), "optional dependency dnspython is not available") def test_simple_verify_good_validation_multitxts(self): # pragma: no cover with mock.patch(self.records_for_name_path) as mock_resolver: @@ -144,7 +137,7 @@ class DNS01ResponseTest(unittest.TestCase): mock_resolver.assert_called_once_with( self.chall.validation_domain_name("local")) - @test_util.skip_unless(dns_available(), + @test_util.skip_unless(test_util.requirement_available(DNS_REQUIREMENT), "optional dependency dnspython is not available") def test_simple_verify_bad_validation(self): # pragma: no cover with mock.patch(self.records_for_name_path) as mock_resolver: diff --git a/acme/acme/dns_resolver.py b/acme/acme/dns_resolver.py index f551c6095..2677d92ad 100644 --- a/acme/acme/dns_resolver.py +++ b/acme/acme/dns_resolver.py @@ -3,8 +3,20 @@ Required only for local validation of 'dns-01' challenges. """ import logging -import dns.resolver -import dns.exception +from acme import errors +from acme import util + +DNS_REQUIREMENT = 'dnspython>=1.12' + +try: + util.activate(DNS_REQUIREMENT) + # pragma: no cover + import dns.exception + import dns.resolver + DNS_AVAILABLE = True +except errors.DependencyError: # pragma: no cover + DNS_AVAILABLE = False + logger = logging.getLogger(__name__) @@ -18,6 +30,9 @@ def txt_records_for_name(name): :rtype: list of unicode """ + if not DNS_AVAILABLE: + raise errors.DependencyError( + '{0} is required to use this function'.format(DNS_REQUIREMENT)) try: dns_response = dns.resolver.query(name, 'TXT') except dns.resolver.NXDOMAIN as error: diff --git a/acme/acme/dns_resolver_test.py b/acme/acme/dns_resolver_test.py index 03f1b3a93..2e2edd0e7 100644 --- a/acme/acme/dns_resolver_test.py +++ b/acme/acme/dns_resolver_test.py @@ -1,17 +1,16 @@ """Tests for acme.dns_resolver.""" -import sys import unittest import mock +from six.moves import reload_module # pylint: disable=import-error +from acme import errors from acme import test_util +from acme.dns_resolver import DNS_REQUIREMENT -try: +if test_util.requirement_available(DNS_REQUIREMENT): import dns - DNS_AVAILABLE = True # pragma: no cover -except ImportError: # pragma: no cover - DNS_AVAILABLE = False def create_txt_response(name, txt_records): @@ -25,15 +24,18 @@ def create_txt_response(name, txt_records): return dns.rrset.from_text_list(name, 60, "IN", "TXT", txt_records) -@test_util.skip_unless(DNS_AVAILABLE, - "optional dependency dnspython is not available") -class DnsResolverTestWithDns(unittest.TestCase): - """Tests for acme.dns_resolver when dns is available.""" +class TxtRecordsForNameTest(unittest.TestCase): + """Tests for acme.dns_resolver.txt_records_for_name.""" @classmethod - def _call(cls, name): - from acme import dns_resolver - return dns_resolver.txt_records_for_name(name) + def _call(cls, *args, **kwargs): + from acme.dns_resolver import txt_records_for_name + return txt_records_for_name(*args, **kwargs) + +@test_util.skip_unless(test_util.requirement_available(DNS_REQUIREMENT), + "optional dependency dnspython is not available") +class TxtRecordsForNameWithDnsTest(TxtRecordsForNameTest): + """Tests for acme.dns_resolver.txt_records_for_name with dns.""" @mock.patch("acme.dns_resolver.dns.resolver.query") def test_txt_records_for_name_with_single_response(self, mock_dns): mock_dns.return_value = create_txt_response('name', ['response']) @@ -56,24 +58,19 @@ class DnsResolverTestWithDns(unittest.TestCase): self.assertEquals([], self._call('name')) -class DnsResolverTestWithoutDns(unittest.TestCase): - """Tests for acme.dns_resolver when dns is unavailable.""" +class TxtRecordsForNameWithoutDnsTest(TxtRecordsForNameTest): + """Tests for acme.dns_resolver.txt_records_for_name without dns.""" def setUp(self): - self.dns_module = sys.modules['dns'] if 'dns' in sys.modules else None - - if DNS_AVAILABLE: - sys.modules['dns'] = None # pragma: no cover + from acme import dns_resolver + dns_resolver.DNS_AVAILABLE = False def tearDown(self): - if self.dns_module is not None: - sys.modules['dns'] = self.dns_module # pragma: no cover + from acme import dns_resolver + reload_module(dns_resolver) - @classmethod - def _import_dns(cls): - import dns as failed_dns_import # pylint: disable=unused-variable - - def test_import_error_is_raised(self): - self.assertRaises(ImportError, self._import_dns) + def test_exception_raised(self): + self.assertRaises( + errors.DependencyError, self._call, "example.org") if __name__ == '__main__': diff --git a/acme/acme/test_util.py b/acme/acme/test_util.py index 0f5763682..ba968511f 100644 --- a/acme/acme/test_util.py +++ b/acme/acme/test_util.py @@ -11,7 +11,9 @@ from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization import OpenSSL +from acme import errors from acme import jose +from acme import util def vector_path(*names): @@ -76,6 +78,20 @@ def load_pyopenssl_private_key(*names): return OpenSSL.crypto.load_privatekey(loader, load_vector(*names)) +def requirement_available(requirement): + """Checks if requirement can be imported. + + :rtype: bool + :returns: ``True`` iff requirement can be imported + + """ + try: + util.activate(requirement) + except errors.DependencyError: # pragma: no cover + return False + return True # pragma: no cover + + def skip_unless(condition, reason): # pragma: no cover """Skip tests unless a condition holds. diff --git a/acme/acme/util.py b/acme/acme/util.py index 1fff89a9e..ac445b271 100644 --- a/acme/acme/util.py +++ b/acme/acme/util.py @@ -1,7 +1,25 @@ """ACME utilities.""" +import pkg_resources import six +from acme import errors + def map_keys(dikt, func): """Map dictionary keys.""" return dict((func(key), value) for key, value in six.iteritems(dikt)) + + +def activate(requirement): + """Make requirement importable. + + :param str requirement: the distribution and version to activate + + :raises acme.errors.DependencyError: if cannot activate requirement + + """ + try: + for distro in pkg_resources.require(requirement): # pylint: disable=not-callable + distro.activate() + except (pkg_resources.DistributionNotFound, pkg_resources.VersionConflict): + raise errors.DependencyError('{0} is unavailable'.format(requirement)) diff --git a/acme/acme/util_test.py b/acme/acme/util_test.py index 00aa8b02d..ba6465409 100644 --- a/acme/acme/util_test.py +++ b/acme/acme/util_test.py @@ -1,6 +1,8 @@ """Tests for acme.util.""" import unittest +from acme import errors + class MapKeysTest(unittest.TestCase): """Tests for acme.util.map_keys.""" @@ -12,5 +14,21 @@ class MapKeysTest(unittest.TestCase): self.assertEqual({2: 2, 4: 4}, map_keys({1: 2, 3: 4}, lambda x: x + 1)) +class ActivateTest(unittest.TestCase): + """Tests for acme.util.activate.""" + + @classmethod + def _call(cls, *args, **kwargs): + from acme.util import activate + return activate(*args, **kwargs) + + def test_failure(self): + self.assertRaises(errors.DependencyError, self._call, 'acme>99.0.0') + + def test_success(self): + self._call('acme') + import acme as unused_acme + + if __name__ == '__main__': unittest.main() # pragma: no cover diff --git a/certbot/plugins/util.py b/certbot/plugins/util.py index 0d0526fb9..915b531c5 100644 --- a/certbot/plugins/util.py +++ b/certbot/plugins/util.py @@ -5,13 +5,19 @@ import socket import zope.component +from acme import errors as acme_errors +from acme import util as acme_util + from certbot import interfaces from certbot import util +PSUTIL_REQUIREMENT = "psutil>=2.2.1" + try: - import psutil + acme_util.activate(PSUTIL_REQUIREMENT) + import psutil # pragma: no cover USE_PSUTIL = True -except ImportError: +except acme_errors.DependencyError: # pragma: no cover USE_PSUTIL = False logger = logging.getLogger(__name__) diff --git a/certbot/plugins/util_test.py b/certbot/plugins/util_test.py index 71fb2a023..f8ffede86 100644 --- a/certbot/plugins/util_test.py +++ b/certbot/plugins/util_test.py @@ -1,11 +1,11 @@ """Tests for certbot.plugins.util.""" import os +import socket import unittest -import sys import mock -from six.moves import reload_module # pylint: disable=import-error +from certbot.plugins.util import PSUTIL_REQUIREMENT from certbot.tests import test_util @@ -34,71 +34,47 @@ class PathSurgeryTest(unittest.TestCase): self.assertTrue("/tmp" in os.environ["PATH"]) -class AlreadyListeningTestNoPsutil(unittest.TestCase): +class AlreadyListeningTest(unittest.TestCase): + """Tests for certbot.plugins.already_listening.""" + @classmethod + def _call(cls, *args, **kwargs): + from certbot.plugins.util import already_listening + return already_listening(*args, **kwargs) + + +class AlreadyListeningTestNoPsutil(AlreadyListeningTest): """Tests for certbot.plugins.already_listening when psutil is not available""" - def setUp(self): - import certbot.plugins.util - # Ensure we get importerror - self.psutil = None - if "psutil" in sys.modules: - self.psutil = sys.modules['psutil'] - sys.modules['psutil'] = None - # Reload hackery to ensure getting non-psutil version - # loaded to memory - reload_module(certbot.plugins.util) - - def tearDown(self): - # Need to reload the module to ensure - # getting back to normal - import certbot.plugins.util - sys.modules["psutil"] = self.psutil - reload_module(certbot.plugins.util) + @classmethod + def _call(cls, *args, **kwargs): + with mock.patch("certbot.plugins.util.USE_PSUTIL", False): + return super( + AlreadyListeningTestNoPsutil, cls)._call(*args, **kwargs) @mock.patch("certbot.plugins.util.zope.component.getUtility") def test_ports_available(self, mock_getutil): - import certbot.plugins.util as plugins_util # Ensure we don't get error with mock.patch("socket.socket.bind"): - self.assertFalse(plugins_util.already_listening(80)) - self.assertFalse(plugins_util.already_listening(80, True)) + self.assertFalse(self._call(80)) + self.assertFalse(self._call(80, True)) self.assertEqual(mock_getutil.call_count, 0) @mock.patch("certbot.plugins.util.zope.component.getUtility") def test_ports_blocked(self, mock_getutil): - sys.modules["psutil"] = None - import certbot.plugins.util as plugins_util - import socket - with mock.patch("socket.socket.bind", side_effect=socket.error): - self.assertTrue(plugins_util.already_listening(80)) - self.assertTrue(plugins_util.already_listening(80, True)) - with mock.patch("socket.socket", side_effect=socket.error): - self.assertFalse(plugins_util.already_listening(80)) + with mock.patch("certbot.plugins.util.socket.socket.bind") as mock_bind: + mock_bind.side_effect = socket.error + self.assertTrue(self._call(80)) + self.assertTrue(self._call(80, True)) + with mock.patch("certbot.plugins.util.socket.socket") as mock_socket: + mock_socket.side_effect = socket.error + self.assertFalse(self._call(80)) self.assertEqual(mock_getutil.call_count, 2) -def psutil_available(): - """Checks if psutil can be imported. - - :rtype: bool - :returns: ``True`` if psutil can be imported, otherwise, ``False`` - - """ - try: - import psutil # pylint: disable=unused-variable - except ImportError: - return False - return True - - -@test_util.skip_unless(psutil_available(), +@test_util.skip_unless(test_util.requirement_available(PSUTIL_REQUIREMENT), "optional dependency psutil is not available") -class AlreadyListeningTestPsutil(unittest.TestCase): +class AlreadyListeningTestPsutil(AlreadyListeningTest): """Tests for certbot.plugins.already_listening.""" - def _call(self, *args, **kwargs): - from certbot.plugins.util import already_listening - return already_listening(*args, **kwargs) - @mock.patch("certbot.plugins.util.psutil.net_connections") @mock.patch("certbot.plugins.util.psutil.Process") @mock.patch("certbot.plugins.util.zope.component.getUtility") diff --git a/certbot/tests/test_util.py b/certbot/tests/test_util.py index 0f5763682..ba968511f 100644 --- a/certbot/tests/test_util.py +++ b/certbot/tests/test_util.py @@ -11,7 +11,9 @@ from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives import serialization import OpenSSL +from acme import errors from acme import jose +from acme import util def vector_path(*names): @@ -76,6 +78,20 @@ def load_pyopenssl_private_key(*names): return OpenSSL.crypto.load_privatekey(loader, load_vector(*names)) +def requirement_available(requirement): + """Checks if requirement can be imported. + + :rtype: bool + :returns: ``True`` iff requirement can be imported + + """ + try: + util.activate(requirement) + except errors.DependencyError: # pragma: no cover + return False + return True # pragma: no cover + + def skip_unless(condition, reason): # pragma: no cover """Skip tests unless a condition holds. From 1b65244d0d51c3fe4dd757782d098e67eca1672f Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 11 Oct 2016 19:15:11 -0700 Subject: [PATCH 11/13] Don't run nosetests from the root of our repo (#3620) --- tools/release.sh | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/release.sh b/tools/release.sh index f5c78da27..57985d7a4 100755 --- a/tools/release.sh +++ b/tools/release.sh @@ -148,20 +148,22 @@ cd ~- # get a snapshot of the CLI help for the docs certbot --help all > docs/cli-help.txt +cd .. # freeze before installing anything else, so that we know end-user KGS # make sure "twine upload" doesn't catch "kgs" -if [ -d ../kgs ] ; then +if [ -d kgs ] ; then echo Deleting old kgs... - rm -rf ../kgs + rm -rf kgs fi -mkdir ../kgs -kgs="../kgs/$version" +mkdir kgs +kgs="kgs/$version" pip freeze | tee $kgs pip install nose for module in certbot $subpkgs_modules ; do echo testing $module nosetests $module done +cd ~- # pin pip hashes of the things we just built for pkg in acme certbot certbot-apache certbot-nginx ; do @@ -215,7 +217,6 @@ echo gpg -U $RELEASE_GPG_KEY --detach-sign --armor $name.$rev.tar.xz cd ~- echo "New root: $root" -echo "KGS is at $root/kgs" echo "Test commands (in the letstest repo):" echo 'python multitester.py targets.yaml $AWS_KEY $USERNAME scripts/test_leauto_upgrades.sh --alt_pip $YOUR_PIP_REPO --branch public-beta' echo 'python multitester.py targets.yaml $AWK_KEY $USERNAME scripts/test_letsencrypt_auto_certonly_standalone.sh --branch candidate-0.1.1' From 6f808b6c082ce45fb0eec6ffa9018df668d334d7 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 12 Oct 2016 16:12:29 -0700 Subject: [PATCH 12/13] Release 0.9.2 --- acme/setup.py | 2 +- certbot-apache/setup.py | 2 +- certbot-auto | 26 +++++++++--------- certbot-compatibility-test/setup.py | 2 +- certbot-nginx/setup.py | 2 +- certbot/__init__.py | 2 +- letsencrypt-auto | 26 +++++++++--------- letsencrypt-auto-source/certbot-auto.asc | 14 +++++----- letsencrypt-auto-source/letsencrypt-auto | 26 +++++++++--------- letsencrypt-auto-source/letsencrypt-auto.sig | Bin 256 -> 256 bytes .../pieces/letsencrypt-auto-requirements.txt | 24 ++++++++-------- 11 files changed, 63 insertions(+), 63 deletions(-) diff --git a/acme/setup.py b/acme/setup.py index 4bdfdefa0..9e84d3bcf 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.9.1' +version = '0.9.2' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-apache/setup.py b/certbot-apache/setup.py index fdfdae395..2733e0398 100644 --- a/certbot-apache/setup.py +++ b/certbot-apache/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.9.1' +version = '0.9.2' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-auto b/certbot-auto index eb627032f..22342d9d2 100755 --- a/certbot-auto +++ b/certbot-auto @@ -19,7 +19,7 @@ XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} VENV_NAME="letsencrypt" VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} VENV_BIN="$VENV_PATH/bin" -LE_AUTO_VERSION="0.9.1" +LE_AUTO_VERSION="0.9.2" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -761,18 +761,18 @@ letsencrypt==0.7.0 \ # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. -acme==0.9.1 \ - --hash=sha256:83e6188d5f149678b77ff3c8f8f94983f3c448490ffa634c7e9f2e93e7351fb0 \ - --hash=sha256:0effd08d144eedbfeb7dd784e9c8673ef3138cf48d35c8c33a1dd5bee9fd8207 -certbot==0.9.1 \ - --hash=sha256:88237a4f6d337d40185a644407f9c7adb6eab87c43b8bf56c1edc02ce82a9d81 \ - --hash=sha256:180354a3e95610ff8ba7f344011f2fcba1186d8efb7b25867266f47048e1e2f7 -certbot-apache==0.9.1 \ - --hash=sha256:cb9931294d44a1d6d44eaa2e92cb30daf6f2e0f29f6e7f00849709f0dd408b40 \ - --hash=sha256:1c09a6b4d087748f2aa143b0a7ced321458c3dd7ca70a80674f867b8b0e3cd6c -certbot-nginx==0.9.1 \ - --hash=sha256:3bd59a4f63a989eb31c04775107139bf45c2373a6f0b7bea4a3a1362da5c2ae7 \ - --hash=sha256:22f277846ccf5c8787cac2b35a7897780f05f4022de02d8b4b731c2cd957354c +acme==0.9.2 \ + --hash=sha256:730412573abf1ee64930d4e1233f02c12d9f7718bc43f127d7f16601ca134f45 \ + --hash=sha256:263d019b6bedd630d669442fad79bc62b4699b69fdb95a49a812fcf8e5bc82b4 +certbot==0.9.2 \ + --hash=sha256:ea096d3eb208798c04a3172fc8025fd4e4203940eac3d765c13546adc10ca28f \ + --hash=sha256:b2576bfe1295b2daab3d589ab9fcbd4d7a6928e85cea31a5e6b008e4d9a16869 +certbot-apache==0.9.2 \ + --hash=sha256:9a20fdbfd76bba5d8219c75c597eb1f576a1629f32fc201c77877871b7164c68 \ + --hash=sha256:92e504c5881b06e0abdc36020cfe57b3f7230e199c03e7da6728380af64e6c67 +certbot-nginx==0.9.2 \ + --hash=sha256:7883391110f05f9884cf62eb641bf1ae38cda07d91e631f9b44397a0d466304d \ + --hash=sha256:d6f7e66543a20991ef8ce11a37f926d00a9bbf5de61fe36bd6566e90c8b33b2f UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/certbot-compatibility-test/setup.py b/certbot-compatibility-test/setup.py index 9b4a7854d..d715c1533 100644 --- a/certbot-compatibility-test/setup.py +++ b/certbot-compatibility-test/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.9.1' +version = '0.9.2' install_requires = [ 'certbot', diff --git a/certbot-nginx/setup.py b/certbot-nginx/setup.py index c434caef2..147bd8fce 100644 --- a/certbot-nginx/setup.py +++ b/certbot-nginx/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.9.1' +version = '0.9.2' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot/__init__.py b/certbot/__init__.py index 0b082669f..5c571afab 100644 --- a/certbot/__init__.py +++ b/certbot/__init__.py @@ -1,4 +1,4 @@ """Certbot client.""" # version number like 1.2.3a0, must have at least 2 parts, like 1.2 -__version__ = '0.9.1' +__version__ = '0.9.2' diff --git a/letsencrypt-auto b/letsencrypt-auto index eb627032f..22342d9d2 100755 --- a/letsencrypt-auto +++ b/letsencrypt-auto @@ -19,7 +19,7 @@ XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} VENV_NAME="letsencrypt" VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} VENV_BIN="$VENV_PATH/bin" -LE_AUTO_VERSION="0.9.1" +LE_AUTO_VERSION="0.9.2" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -761,18 +761,18 @@ letsencrypt==0.7.0 \ # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. -acme==0.9.1 \ - --hash=sha256:83e6188d5f149678b77ff3c8f8f94983f3c448490ffa634c7e9f2e93e7351fb0 \ - --hash=sha256:0effd08d144eedbfeb7dd784e9c8673ef3138cf48d35c8c33a1dd5bee9fd8207 -certbot==0.9.1 \ - --hash=sha256:88237a4f6d337d40185a644407f9c7adb6eab87c43b8bf56c1edc02ce82a9d81 \ - --hash=sha256:180354a3e95610ff8ba7f344011f2fcba1186d8efb7b25867266f47048e1e2f7 -certbot-apache==0.9.1 \ - --hash=sha256:cb9931294d44a1d6d44eaa2e92cb30daf6f2e0f29f6e7f00849709f0dd408b40 \ - --hash=sha256:1c09a6b4d087748f2aa143b0a7ced321458c3dd7ca70a80674f867b8b0e3cd6c -certbot-nginx==0.9.1 \ - --hash=sha256:3bd59a4f63a989eb31c04775107139bf45c2373a6f0b7bea4a3a1362da5c2ae7 \ - --hash=sha256:22f277846ccf5c8787cac2b35a7897780f05f4022de02d8b4b731c2cd957354c +acme==0.9.2 \ + --hash=sha256:730412573abf1ee64930d4e1233f02c12d9f7718bc43f127d7f16601ca134f45 \ + --hash=sha256:263d019b6bedd630d669442fad79bc62b4699b69fdb95a49a812fcf8e5bc82b4 +certbot==0.9.2 \ + --hash=sha256:ea096d3eb208798c04a3172fc8025fd4e4203940eac3d765c13546adc10ca28f \ + --hash=sha256:b2576bfe1295b2daab3d589ab9fcbd4d7a6928e85cea31a5e6b008e4d9a16869 +certbot-apache==0.9.2 \ + --hash=sha256:9a20fdbfd76bba5d8219c75c597eb1f576a1629f32fc201c77877871b7164c68 \ + --hash=sha256:92e504c5881b06e0abdc36020cfe57b3f7230e199c03e7da6728380af64e6c67 +certbot-nginx==0.9.2 \ + --hash=sha256:7883391110f05f9884cf62eb641bf1ae38cda07d91e631f9b44397a0d466304d \ + --hash=sha256:d6f7e66543a20991ef8ce11a37f926d00a9bbf5de61fe36bd6566e90c8b33b2f UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/letsencrypt-auto-source/certbot-auto.asc b/letsencrypt-auto-source/certbot-auto.asc index 71a54bde5..9ab7f4eac 100644 --- a/letsencrypt-auto-source/certbot-auto.asc +++ b/letsencrypt-auto-source/certbot-auto.asc @@ -1,11 +1,11 @@ -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 -iQEcBAABAgAGBQJX9shpAAoJEE0XyZXNl3XyeAUH/0928PysUZlLCQRpw3GPJnr0 -WgE1duULRfDKOdyoj8cIABEcxyK+rASyBju57Hx80Zuai9x4XSHJK7k9BXrZrU5k -KHZWbaNOKLN+C7/HTSOqGwalGTLglRJLZMwcj4rs8jtftg6GiWXvtnWuwqoiZJe4 -sCdddm2gu4D2VLp/QpBU6Gepuls4PmtB7SzwRUC6SAkWf5ntwJ4mq65bwKLcTPaZ -oRKoswo+eyiosH2SVVgiyAz7U96t2gxfK2pNoTdCUQGjuRaD6P2yBCdJA5h4L2l2 -W+/31zJpw/TgFErWpNuNYYoMh8cswaWXDNMUscsuduQ9KPLhSHQQ9JZ5f4w+9PM= -=Zhq9 +iQEcBAABAgAGBQJX/sM7AAoJEE0XyZXNl3XypJgIAJ2MsRr2BVq/ISAqpoGVEdTH +q2yp8xfOSnirYUvfYV9ZuwId06FlfC+9n2k0mT+byvl1HR4WFgX6f5//B17vTHCO +AnbxQIJ21SetzkR7XCKtW3A2GWs++4740diiv3Yrgn5VQkMWAJoy6k0NFgnED75R +cZsZPAYjX8zjCu4LKSrs6PuuNSA1Wj2E/q5fRN1/nFTP5uZhb+RrjT1RKo5i+pP9 +AjS96M8Dgw8ftPmtCkaK8f2btEQF2tDGbHPCrxiBbwMLKtrnAX+wwvkAYYjPqGlU +brF0+fZQ5spyJ8kqjBirLrCZ+kDmc7n7oKhlYluzLpx4cBYdV3CHeVZA6XG91Ag= +=MUCn -----END PGP SIGNATURE----- diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index eb627032f..22342d9d2 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -19,7 +19,7 @@ XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} VENV_NAME="letsencrypt" VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} VENV_BIN="$VENV_PATH/bin" -LE_AUTO_VERSION="0.9.1" +LE_AUTO_VERSION="0.9.2" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -761,18 +761,18 @@ letsencrypt==0.7.0 \ # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. -acme==0.9.1 \ - --hash=sha256:83e6188d5f149678b77ff3c8f8f94983f3c448490ffa634c7e9f2e93e7351fb0 \ - --hash=sha256:0effd08d144eedbfeb7dd784e9c8673ef3138cf48d35c8c33a1dd5bee9fd8207 -certbot==0.9.1 \ - --hash=sha256:88237a4f6d337d40185a644407f9c7adb6eab87c43b8bf56c1edc02ce82a9d81 \ - --hash=sha256:180354a3e95610ff8ba7f344011f2fcba1186d8efb7b25867266f47048e1e2f7 -certbot-apache==0.9.1 \ - --hash=sha256:cb9931294d44a1d6d44eaa2e92cb30daf6f2e0f29f6e7f00849709f0dd408b40 \ - --hash=sha256:1c09a6b4d087748f2aa143b0a7ced321458c3dd7ca70a80674f867b8b0e3cd6c -certbot-nginx==0.9.1 \ - --hash=sha256:3bd59a4f63a989eb31c04775107139bf45c2373a6f0b7bea4a3a1362da5c2ae7 \ - --hash=sha256:22f277846ccf5c8787cac2b35a7897780f05f4022de02d8b4b731c2cd957354c +acme==0.9.2 \ + --hash=sha256:730412573abf1ee64930d4e1233f02c12d9f7718bc43f127d7f16601ca134f45 \ + --hash=sha256:263d019b6bedd630d669442fad79bc62b4699b69fdb95a49a812fcf8e5bc82b4 +certbot==0.9.2 \ + --hash=sha256:ea096d3eb208798c04a3172fc8025fd4e4203940eac3d765c13546adc10ca28f \ + --hash=sha256:b2576bfe1295b2daab3d589ab9fcbd4d7a6928e85cea31a5e6b008e4d9a16869 +certbot-apache==0.9.2 \ + --hash=sha256:9a20fdbfd76bba5d8219c75c597eb1f576a1629f32fc201c77877871b7164c68 \ + --hash=sha256:92e504c5881b06e0abdc36020cfe57b3f7230e199c03e7da6728380af64e6c67 +certbot-nginx==0.9.2 \ + --hash=sha256:7883391110f05f9884cf62eb641bf1ae38cda07d91e631f9b44397a0d466304d \ + --hash=sha256:d6f7e66543a20991ef8ce11a37f926d00a9bbf5de61fe36bd6566e90c8b33b2f UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/letsencrypt-auto-source/letsencrypt-auto.sig b/letsencrypt-auto-source/letsencrypt-auto.sig index 80ec36e19ad2a8967d36cd409347726b08cdf0d7..4502c0195e9112f9e03a43c114680311917f395d 100644 GIT binary patch literal 256 zcmV+b0ssD7gd74~0IXvTSIAEi?JkusNAIoWu;kj87jg>TkokV&`NlD@Q00LjK||p@ z$CH!-_QznaqJ~6tcQYV`gn1;ZoW!}Mz8rV^f0lO~RxXgfmgSy3BYE2~O3qL?sF;h@ znb7Z=4kAV3ttTfHKc>0+Ivd(q%2O@`_ING0r*yClWU;K+FBTcmps1$5+;(G&cYsQ> zEm39J{-+C&rY}47LoP)~LzCyNe!_wjoLcv$8pb@&)nCR8ELcGH&xft!BhoVD@^EW8 z_BSbot`FNq(mPEpyIY$7manyW03fP^!+99Dj2Pk{L3ZU&5kbdXoR!DpSogzNm9Rq& G%NvQv?0=^K literal 256 zcmV+b0ssCA_-8=flSy<6Fl!QgcZZkvQ*|qkSu6D;yM{EED_69C0x#H)Ik$m9EG-?> zJ3eBlvyacp^n Date: Wed, 12 Oct 2016 16:12:35 -0700 Subject: [PATCH 13/13] Bump version to 0.10.0 --- acme/setup.py | 2 +- certbot-apache/setup.py | 2 +- certbot-compatibility-test/setup.py | 2 +- certbot-nginx/setup.py | 2 +- certbot/__init__.py | 2 +- letsencrypt-auto-source/letsencrypt-auto | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/acme/setup.py b/acme/setup.py index 9e84d3bcf..2b32f7e28 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.9.2' +version = '0.10.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-apache/setup.py b/certbot-apache/setup.py index 2733e0398..2b4ac8563 100644 --- a/certbot-apache/setup.py +++ b/certbot-apache/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.9.2' +version = '0.10.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-compatibility-test/setup.py b/certbot-compatibility-test/setup.py index d715c1533..32e5935fb 100644 --- a/certbot-compatibility-test/setup.py +++ b/certbot-compatibility-test/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.9.2' +version = '0.10.0.dev0' install_requires = [ 'certbot', diff --git a/certbot-nginx/setup.py b/certbot-nginx/setup.py index 147bd8fce..4c39d37c2 100644 --- a/certbot-nginx/setup.py +++ b/certbot-nginx/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.9.2' +version = '0.10.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot/__init__.py b/certbot/__init__.py index 5c571afab..45892e269 100644 --- a/certbot/__init__.py +++ b/certbot/__init__.py @@ -1,4 +1,4 @@ """Certbot client.""" # version number like 1.2.3a0, must have at least 2 parts, like 1.2 -__version__ = '0.9.2' +__version__ = '0.10.0.dev0' diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 22342d9d2..e95fdc357 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -19,7 +19,7 @@ XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} VENV_NAME="letsencrypt" VENV_PATH=${VENV_PATH:-"$XDG_DATA_HOME/$VENV_NAME"} VENV_BIN="$VENV_PATH/bin" -LE_AUTO_VERSION="0.9.2" +LE_AUTO_VERSION="0.10.0.dev0" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates