From 21187b7c1bc7eed2c84e3a5925cfdc32393c1b58 Mon Sep 17 00:00:00 2001 From: Luca Olivetti Date: Fri, 4 Dec 2015 16:10:43 +0100 Subject: [PATCH 01/72] mageia bootstrap --- bootstrap/_mageia_common.sh | 24 ++++++++++++++++++++++++ letsencrypt-auto | 3 +++ 2 files changed, 27 insertions(+) create mode 100755 bootstrap/_mageia_common.sh diff --git a/bootstrap/_mageia_common.sh b/bootstrap/_mageia_common.sh new file mode 100755 index 000000000..9a4606c9d --- /dev/null +++ b/bootstrap/_mageia_common.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +# Tested on mageia 5 x86_64 +if ! urpmi --force \ + python \ + libpython-devel \ + python-virtualenv +then + echo "Could not install Python dependencies. Aborting bootstrap!" + exit 1 +fi + +if ! urpmi --force \ + git \ + gcc \ + cdialog \ + python-augeas \ + libopenssl-devel \ + libffi-devel \ + rootcerts +then + echo "Could not install additional dependencies. Aborting bootstrap!" + exit 1 +fi diff --git a/letsencrypt-auto b/letsencrypt-auto index 44c71883c..13a966a87 100755 --- a/letsencrypt-auto +++ b/letsencrypt-auto @@ -122,6 +122,9 @@ then if [ -f /etc/debian_version ] ; then echo "Bootstrapping dependencies for Debian-based OSes..." $SUDO $BOOTSTRAP/_deb_common.sh + elif [ -f /etc/mageia-release ] ; then + echo "Bootstrapping dependencies for mageia..." + $SUDO $BOOTSTRAP/_mageia_common.sh elif [ -f /etc/redhat-release ] ; then echo "Bootstrapping dependencies for RedHat-based OSes..." $SUDO $BOOTSTRAP/_rpm_common.sh From b7c00a889a607add72823aa20ccf4874a585a8eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torsten=20B=C3=B6gershausen?= Date: Sun, 10 Jan 2016 18:31:49 +0100 Subject: [PATCH 02/72] .gitattributes: EOL=LF overrides auto The line * text=auto eol=lf in .gitattributes does not work as expected: setting eol=lf overrides text=auto, and works as * eol=lf or * text eol=lf This is not what is intended, as binary files like *.gz go through a CRLF -> LF conversion at commit time. Use * crlf=auto instead (which is even understood by older Git versions, which are still in use) --- .gitattributes | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.gitattributes b/.gitattributes index 5eee84cce..2a18bd183 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,7 +1,15 @@ -* text=auto eol=lf +#Default, normalize CRLF into LF in non-binary files +# Files identified as binary by Git are not changed +* crlf=auto # special files +*.sh crlf=input +*.py crlf=input + *.bat text eol=crlf + +*.der binary +*.gz binary *.jpeg binary *.jpg binary *.png binary From 63c79f98ca44453c3fe68c37ddcacb5b7bed938c Mon Sep 17 00:00:00 2001 From: Marius Gedminas Date: Wed, 18 May 2016 10:59:58 +0300 Subject: [PATCH 03/72] Remove dangling footnote This footnote has no references! --- docs/using.rst | 7 ------- 1 file changed, 7 deletions(-) diff --git a/docs/using.rst b/docs/using.rst index 12ea3ea11..e81aca16a 100644 --- a/docs/using.rst +++ b/docs/using.rst @@ -552,10 +552,3 @@ Beyond the methods discussed here, other methods may be possible, such as installing Certbot directly with pip from PyPI or downloading a ZIP archive from GitHub may be technically possible but are not presently recommended or supported. - - -.. rubric:: Footnotes - -.. [#venv] By using this virtualized Python environment (`virtualenv - `_) we don't pollute the main - OS space with packages from PyPI! From 12a356298c6217e5b9934262742ebed04c1ddfec Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Wed, 25 May 2016 20:34:38 +0200 Subject: [PATCH 04/72] Displaying DialogError details correctly --- certbot/main.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/certbot/main.py b/certbot/main.py index fa5d43b72..b5407370a 100644 --- a/certbot/main.py +++ b/certbot/main.py @@ -623,7 +623,11 @@ def _handle_exception(exc_type, exc_value, trace, config): # Here we're passing a client or ACME error out to the client at the shell # Tell the user a bit about what happened, without overwhelming # them with a full traceback - err = traceback.format_exception_only(exc_type, exc_value)[0] + from dialog import DialogError + if issubclass(exc_type, DialogError): + err = exc_value.complete_message() + else: + err = traceback.format_exception_only(exc_type, exc_value)[0] # Typical error from the ACME module: # acme.messages.Error: urn:acme:error:malformed :: The request message was # malformed :: Error creating new registration :: Validation of contact From 4a8f71277c51d8cb26970f98bdbbc8ee67396397 Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Fri, 20 May 2016 21:25:44 +0200 Subject: [PATCH 05/72] Limiting tox envlist to really needed tests --- docs/contributing.rst | 3 +++ tox.ini | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/contributing.rst b/docs/contributing.rst index 3318ec103..9ceb0fbdd 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -71,6 +71,9 @@ The following tools are there to help you: experimental, non-production Apache2 install on them. ``tox -e apacheconftest`` can be used to run those specific Apache conf tests. +- ``tox --skip-missing-interpreters`` runs tox while ignoring missing versions + of Python needed for running the tests. + - ``tox -e py27``, ``tox -e py26`` etc, run unit tests for specific Python versions. diff --git a/tox.ini b/tox.ini index 5c88dfd21..4067bada9 100644 --- a/tox.ini +++ b/tox.ini @@ -4,7 +4,7 @@ [tox] skipsdist = true -envlist = py{26,27,33,34,35},py{26,27}-oldest,cover,lint +envlist = py{26,33,34,35},cover,lint # nosetest -v => more verbose output, allows to detect busy waiting # loops, especially on Travis From 928ea2f5cb7edf22d77ff3bc4bbca1b36c92b7cd Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Sat, 28 May 2016 02:18:49 +0200 Subject: [PATCH 06/72] Fixing minute problems with code --- certbot/main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/certbot/main.py b/certbot/main.py index 235d7c3ff..9c8849cfe 100644 --- a/certbot/main.py +++ b/certbot/main.py @@ -1,6 +1,7 @@ """Certbot main entry point.""" from __future__ import print_function import atexit +import dialog import functools import logging.handlers import os @@ -623,8 +624,7 @@ def _handle_exception(exc_type, exc_value, trace, config): # Here we're passing a client or ACME error out to the client at the shell # Tell the user a bit about what happened, without overwhelming # them with a full traceback - from dialog import DialogError - if issubclass(exc_type, DialogError): + if issubclass(exc_type, dialog.error): err = exc_value.complete_message() else: err = traceback.format_exception_only(exc_type, exc_value)[0] From d21f8fa657cf4fbea47da47f1dc0bb5e1c9e594a Mon Sep 17 00:00:00 2001 From: Marius Gedminas Date: Fri, 20 May 2016 08:50:00 +0300 Subject: [PATCH 07/72] Add --disable-hook-validation As discussed in #3020. --- certbot/cli.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/certbot/cli.py b/certbot/cli.py index bcb7785c5..f3decec05 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -356,7 +356,8 @@ class HelpfulArgumentParser(object): " {0} conflicts with dialog_mode").format(arg) ) - hooks.validate_hooks(parsed_args) + if parsed_args.validate_hooks: + hooks.validate_hooks(parsed_args) return parsed_args @@ -792,6 +793,14 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): "For this command, the shell variable $RENEWED_LINEAGE will point to the" "config live subdirectory containing the new certs and keys; the shell variable " "$RENEWED_DOMAINS will contain a space-delimited list of renewed cert domains") + helpful.add( + "renew", "--disable-hook-validation", + action='store_false', dest='validate_hooks', default=True, + help="Ordinarily the commands specified for --pre-hook/--post-hook/--renew-hook" + " will be checked for validity, to see if the programs being run are in the $PATH," + " so that mistakes can be caught early, even when the hooks aren't being run just yet." + " The validation is rather simplistic and fails if you use more advanced" + " shell constructs, so you can use this switch to disable it.") helpful.add_deprecated_argument("--agree-dev-preview", 0) From dcadcf8d42c6911a1c35fcd08590f693a68c8fef Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 2 Jun 2016 13:50:30 -0700 Subject: [PATCH 08/72] Release 0.8.0 --- acme/setup.py | 2 +- certbot-apache/setup.py | 2 +- certbot-auto | 29 ++++++++---------- certbot-compatibility-test/setup.py | 2 +- certbot-nginx/setup.py | 2 +- certbot/__init__.py | 2 +- docs/cli-help.txt | 6 ++++ letsencrypt-auto | 29 ++++++++---------- letsencrypt-auto-source/certbot-auto.asc | 14 ++++----- letsencrypt-auto-source/letsencrypt-auto | 20 ++++++------ letsencrypt-auto-source/letsencrypt-auto.sig | Bin 256 -> 256 bytes .../pieces/letsencrypt-auto-requirements.txt | 18 +++++------ 12 files changed, 63 insertions(+), 63 deletions(-) diff --git a/acme/setup.py b/acme/setup.py index c25cb5c00..cf3aa4df1 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.8.0.dev0' +version = '0.8.0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-apache/setup.py b/certbot-apache/setup.py index 2a4716db7..d85b33f3c 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.8.0.dev0' +version = '0.8.0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-auto b/certbot-auto index 5fbef43b1..2de5ff48f 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.7.0" +LE_AUTO_VERSION="0.8.0" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -713,24 +713,21 @@ zope.interface==4.1.3 \ mock==1.0.1 \ --hash=sha256:b839dd2d9c117c701430c149956918a423a9863b48b09c90e30a6013e7d2f44f \ --hash=sha256:8f83080daa249d036cbccfb8ae5cc6ff007b88d6d937521371afabe7b19badbc - -# THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. - -acme==0.7.0 \ - --hash=sha256:6e61dba343806ad4cb27af84628152abc9e83a0fa24be6065587d2b46f340d7a \ - --hash=sha256:9f75a1947978402026b741bdee8a18fc5a1cfd539b78e523b7e5f279bf18eeb9 -certbot==0.7.0 \ - --hash=sha256:55604e43d231ac226edefed8dc110d792052095c3d75ad0e4a228ae0989fe5fd \ - --hash=sha256:ad5083d75e16d1ab806802d3a32f34973b6d7adaf083aee87e07a6c1359efe88 -certbot-apache==0.7.0 \ - --hash=sha256:5ab5ed9b2af6c7db9495ce1491122798e9d0764e3df8f0843d11d89690bf7f88 \ - --hash=sha256:1ddbfaf01bcb0b05c0dcc8b2ebd37637f080cf798151e8140c20c9f5fe7bae75 letsencrypt==0.7.0 \ --hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \ --hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9 -letsencrypt-apache==0.7.0 \ - --hash=sha256:10445980a6afc810325ea22a56e269229999120848f6c0b323b00275696b5c80 \ - --hash=sha256:3f4656088a18e4efea7cd7eb4965e14e8d901f3b64f4691e79cafd0bb91890f0 + +# THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. + +acme==0.8.0 \ + --hash=sha256:8561d590e496afb41a8ff2dac389199661d9cd785b1636ae08325771511189af \ + --hash=sha256:dfa86b547628b231f275c7e0efc7a09bec5dfaec866f89f5c5b59b78c14564da +certbot==0.8.0 \ + --hash=sha256:395c5840ff6b75aa51ee6449c86d016c14c5f65a71281e7bcef5feecac6a3293 \ + --hash=sha256:3c3c70b484fb3243a166515adc81ae0401c5d687a2763c75b40df9d8241a4314 +certbot-apache==0.8.0 \ + --hash=sha256:f4d4fc962ecc19646f6745d49c62a265d26e5b2df3acf34ef4865351594156e3 \ + --hash=sha256:cfb211debbcb0d0645c88d7e8bb38c591fca263bfdb5337242c023956055e268 UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/certbot-compatibility-test/setup.py b/certbot-compatibility-test/setup.py index 8d2bd925d..15a2af6e2 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.8.0.dev0' +version = '0.8.0' install_requires = [ 'certbot=={0}'.format(version), diff --git a/certbot-nginx/setup.py b/certbot-nginx/setup.py index bb8b3414e..a710739f9 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.8.0.dev0' +version = '0.8.0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot/__init__.py b/certbot/__init__.py index dc0e2764d..98971584a 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.8.0.dev0' +__version__ = '0.8.0' diff --git a/docs/cli-help.txt b/docs/cli-help.txt index 4026f1cc8..b25326148 100644 --- a/docs/cli-help.txt +++ b/docs/cli-help.txt @@ -10,6 +10,7 @@ cert. Major SUBCOMMANDS are: install Install a previously obtained cert in a server renew Renew previously obtained certs that are near expiry revoke Revoke a previously obtained certificate + register Perform tasks related to registering with the CA rollback Rollback server configuration changes made during install config_changes Show changes made to server config during installation plugins Display information about installed plugins @@ -53,6 +54,11 @@ optional arguments: to the Subscriber Agreement will still affect you, and will be effective 14 days after posting an update to the web site. (default: False) + --update-registration + With the register verb, indicates that details + associated with an existing registration, such as the + e-mail address, should be updated, rather than + registering a new account. (default: False) -m EMAIL, --email EMAIL Email used for registration and recovery contact. (default: None) diff --git a/letsencrypt-auto b/letsencrypt-auto index 5fbef43b1..2de5ff48f 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.7.0" +LE_AUTO_VERSION="0.8.0" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -713,24 +713,21 @@ zope.interface==4.1.3 \ mock==1.0.1 \ --hash=sha256:b839dd2d9c117c701430c149956918a423a9863b48b09c90e30a6013e7d2f44f \ --hash=sha256:8f83080daa249d036cbccfb8ae5cc6ff007b88d6d937521371afabe7b19badbc - -# THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. - -acme==0.7.0 \ - --hash=sha256:6e61dba343806ad4cb27af84628152abc9e83a0fa24be6065587d2b46f340d7a \ - --hash=sha256:9f75a1947978402026b741bdee8a18fc5a1cfd539b78e523b7e5f279bf18eeb9 -certbot==0.7.0 \ - --hash=sha256:55604e43d231ac226edefed8dc110d792052095c3d75ad0e4a228ae0989fe5fd \ - --hash=sha256:ad5083d75e16d1ab806802d3a32f34973b6d7adaf083aee87e07a6c1359efe88 -certbot-apache==0.7.0 \ - --hash=sha256:5ab5ed9b2af6c7db9495ce1491122798e9d0764e3df8f0843d11d89690bf7f88 \ - --hash=sha256:1ddbfaf01bcb0b05c0dcc8b2ebd37637f080cf798151e8140c20c9f5fe7bae75 letsencrypt==0.7.0 \ --hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \ --hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9 -letsencrypt-apache==0.7.0 \ - --hash=sha256:10445980a6afc810325ea22a56e269229999120848f6c0b323b00275696b5c80 \ - --hash=sha256:3f4656088a18e4efea7cd7eb4965e14e8d901f3b64f4691e79cafd0bb91890f0 + +# THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. + +acme==0.8.0 \ + --hash=sha256:8561d590e496afb41a8ff2dac389199661d9cd785b1636ae08325771511189af \ + --hash=sha256:dfa86b547628b231f275c7e0efc7a09bec5dfaec866f89f5c5b59b78c14564da +certbot==0.8.0 \ + --hash=sha256:395c5840ff6b75aa51ee6449c86d016c14c5f65a71281e7bcef5feecac6a3293 \ + --hash=sha256:3c3c70b484fb3243a166515adc81ae0401c5d687a2763c75b40df9d8241a4314 +certbot-apache==0.8.0 \ + --hash=sha256:f4d4fc962ecc19646f6745d49c62a265d26e5b2df3acf34ef4865351594156e3 \ + --hash=sha256:cfb211debbcb0d0645c88d7e8bb38c591fca263bfdb5337242c023956055e268 UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/letsencrypt-auto-source/certbot-auto.asc b/letsencrypt-auto-source/certbot-auto.asc index 454cbe598..0255229b0 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 -iQEcBAABAgAGBQJXSK5DAAoJEE0XyZXNl3Xyyb4H/Ahy9/8ADDaN5V/O/6kl6gE5 -amQfm8T10EUD8APnNWYrYKBYruDBVvH0KiEcuAEs7q4xE5BaQatlobSnsHfv4AWW -TwInk2lRxYZ++MwwQf3DrqMK5QKfcoVnViZsRpZ8gHMLzsJllRm7R5eaTewO2ViM -KM+yDB3UsquLUvE4d3/hgBl2mXAUwsxLeFreZayvpoTcX2ARnzbtKqMaIBYDYWcx -DewWtDsPrhKFpb2DY06S6JLmEttysUgv+hbKlaVO0yZ8cCUehkzBIGYoeS4chOLq -fonNCzB8u3RtnLEFiPIy0N+A592jbLsqqUkxjammaJq3lH7nitduMLnpvGKt4yc= -=ex1J +iQEcBAABAgAGBQJXUJvwAAoJEE0XyZXNl3XyvKsH/3qn7Xa/GQx3HvB6Io/Csn/E +v1nbUg5RPwvrTyyol8BJ6UrHiJw+gTbUgCAnBkZ7DYKaC8AQmQXVRcWXNALMMTzB +6LpBXjQQ2xrBYamGj70N7KnTM1QmxI96GUQouiHMJVugV4uihKJDjtR8/f2JWKok +ZSox6E4LqC45HzqLWiOqc13TrHbti32Mo8DyC63PBnSwMnypGLK6XcqM0L9Re62W +smoKu1VWKwWZYRYXIQr0dvK4JmVTrIsdASdZkhTC/vc8y4tGkdN0DcF2EHzci6OA +Tx0W+Ao+HM1ZcaaH3BJ1y3kYfT+mlt6o4OaK3UB/wtUzMmVih7l1UeiNkVL0oYk= +=t3L6 -----END PGP SIGNATURE----- diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 1992c9d47..2de5ff48f 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.8.0.dev0" +LE_AUTO_VERSION="0.8.0" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -719,15 +719,15 @@ letsencrypt==0.7.0 \ # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. -acme==0.7.0 \ - --hash=sha256:6e61dba343806ad4cb27af84628152abc9e83a0fa24be6065587d2b46f340d7a \ - --hash=sha256:9f75a1947978402026b741bdee8a18fc5a1cfd539b78e523b7e5f279bf18eeb9 -certbot==0.7.0 \ - --hash=sha256:55604e43d231ac226edefed8dc110d792052095c3d75ad0e4a228ae0989fe5fd \ - --hash=sha256:ad5083d75e16d1ab806802d3a32f34973b6d7adaf083aee87e07a6c1359efe88 -certbot-apache==0.7.0 \ - --hash=sha256:5ab5ed9b2af6c7db9495ce1491122798e9d0764e3df8f0843d11d89690bf7f88 \ - --hash=sha256:1ddbfaf01bcb0b05c0dcc8b2ebd37637f080cf798151e8140c20c9f5fe7bae75 +acme==0.8.0 \ + --hash=sha256:8561d590e496afb41a8ff2dac389199661d9cd785b1636ae08325771511189af \ + --hash=sha256:dfa86b547628b231f275c7e0efc7a09bec5dfaec866f89f5c5b59b78c14564da +certbot==0.8.0 \ + --hash=sha256:395c5840ff6b75aa51ee6449c86d016c14c5f65a71281e7bcef5feecac6a3293 \ + --hash=sha256:3c3c70b484fb3243a166515adc81ae0401c5d687a2763c75b40df9d8241a4314 +certbot-apache==0.8.0 \ + --hash=sha256:f4d4fc962ecc19646f6745d49c62a265d26e5b2df3acf34ef4865351594156e3 \ + --hash=sha256:cfb211debbcb0d0645c88d7e8bb38c591fca263bfdb5337242c023956055e268 UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/letsencrypt-auto-source/letsencrypt-auto.sig b/letsencrypt-auto-source/letsencrypt-auto.sig index e7e6546a25178083f007351bbba85fda56c87bb2..f024577a34a42779e39755635eca4daf6f46ac2a 100644 GIT binary patch literal 256 zcmV+b0ssE80bqRH{`qI)8kxNPxBYvrI}8PM??lS5W%Vrx#G#77ah$EmwK78hzI8fL zpFoy+Z$Ff?%2R#7_m4mldi$VK+OCedjDk7*K$j_4-%~DH(I7GKai+aBwofiSx4Q27 z;SV#~5cO^_zi`sHUA566Xqu@Q&d>p~uV#$A5kiL^Wt5QWl@grCRt$tN>*5-L&1i=@?vr?8a-~$mStKTr+dwJTPqN4;)GA0wY_jCnH7Wesi1I|l7M@y GRi#to9)G0( literal 256 zcmV+b0ssD(3r1$c09~FFRL*(rn=D5xr$W>4tf{yJ0Yd>ifFOs3`#iS_w(uP+p(fG& zTEmPXK+5%ZpiHyaPtmN4i1xvJn%fgm9b2nF4!4kuT8ov;Uq`~S8bQzaVDw Date: Thu, 2 Jun 2016 13:50:37 -0700 Subject: [PATCH 09/72] Bump version to 0.9.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 cf3aa4df1..ed133e128 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.8.0' +version = '0.9.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 d85b33f3c..e3dbe4563 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.8.0' +version = '0.9.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 15a2af6e2..fe2c0c9d0 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.8.0' +version = '0.9.0.dev0' install_requires = [ 'certbot=={0}'.format(version), diff --git a/certbot-nginx/setup.py b/certbot-nginx/setup.py index a710739f9..62c705b4c 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.8.0' +version = '0.9.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot/__init__.py b/certbot/__init__.py index 98971584a..34358a5d9 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.8.0' +__version__ = '0.9.0.dev0' diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 2de5ff48f..89d345062 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.8.0" +LE_AUTO_VERSION="0.9.0.dev0" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates From 76a939ceb3c37419e4e9eccde29c558ae332ad56 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 2 Jun 2016 16:00:19 -0700 Subject: [PATCH 10/72] Exit if cannot bootstrap --- letsencrypt-auto-source/letsencrypt-auto.template | 1 + 1 file changed, 1 insertion(+) diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index 43d8bc7e1..07f52147b 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -197,6 +197,7 @@ Bootstrap() { echo "You will need to bootstrap, configure virtualenv, and run pip install manually." echo "Please see https://letsencrypt.readthedocs.org/en/latest/contributing.html#prerequisites" echo "for more info." + exit 1 fi } From c9bdc19851f2bae586c27663747723535fe19a51 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 2 Jun 2016 16:03:15 -0700 Subject: [PATCH 11/72] Build letsencrypt-auto --- letsencrypt-auto-source/letsencrypt-auto | 1 + 1 file changed, 1 insertion(+) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 1992c9d47..a5d699995 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -500,6 +500,7 @@ Bootstrap() { echo "You will need to bootstrap, configure virtualenv, and run pip install manually." echo "Please see https://letsencrypt.readthedocs.org/en/latest/contributing.html#prerequisites" echo "for more info." + exit 1 fi } From 6a0c6c85fb7028fdc3793325d40681b7c34f777f Mon Sep 17 00:00:00 2001 From: bmw Date: Thu, 2 Jun 2016 16:42:55 -0700 Subject: [PATCH 12/72] Revert "Use --force-reinstall to fix bad virtualenv package" --- tools/_venv_common.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/_venv_common.sh b/tools/_venv_common.sh index dc6ca3dd2..a121af82d 100755 --- a/tools/_venv_common.sh +++ b/tools/_venv_common.sh @@ -18,8 +18,7 @@ virtualenv --no-site-packages $VENV_NAME $VENV_ARGS # Separately install setuptools and pip to make sure following # invocations use latest pip install -U setuptools -# --force-reinstall used to fix broken pip installation on some systems -pip install --force-reinstall -U pip +pip install -U pip pip install "$@" set +x From 6b7a76442e282e7d926c27cc405dcf10a999652f Mon Sep 17 00:00:00 2001 From: Felix Yan Date: Thu, 2 Jun 2016 23:04:14 -0500 Subject: [PATCH 13/72] Update letsencrypt-auto for Arch's new package name --- letsencrypt-auto-source/letsencrypt-auto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 1992c9d47..871c64d0c 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -476,7 +476,7 @@ Bootstrap() { BootstrapArchCommon else echo "Please use pacman to install letsencrypt packages:" - echo "# pacman -S letsencrypt letsencrypt-apache" + echo "# pacman -S certbot certbot-apache" echo echo "If you would like to use the virtualenv way, please run the script again with the" echo "--debug flag." From f5c8a63c1896919056f8a7b7dd53eae0252afacb Mon Sep 17 00:00:00 2001 From: Marius Gedminas Date: Fri, 3 Jun 2016 09:44:12 +0300 Subject: [PATCH 14/72] Tests for --disable-hook-validation --- certbot/tests/cli_test.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/certbot/tests/cli_test.py b/certbot/tests/cli_test.py index 671da16f0..adbde1d3e 100644 --- a/certbot/tests/cli_test.py +++ b/certbot/tests/cli_test.py @@ -651,6 +651,18 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods out = stdout.getvalue() self.assertEqual("", out) + def test_renew_hook_validation(self): + self._make_test_renewal_conf('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') + args = ["renew", "--dry-run", "--post-hook=no-such-command", + "--disable-hook-validation"] + self._test_renewal_common(True, [], args=args, should_renew=True, + error_expected=False) @mock.patch("certbot.cli.set_by_cli") def test_ancient_webroot_renewal_conf(self, mock_set_by_cli): From 2815361e6381a12dd50e5c0fa88bbd6ec3b8775e Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 3 Jun 2016 11:12:49 -0700 Subject: [PATCH 15/72] Update the template as well --- letsencrypt-auto-source/letsencrypt-auto.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index 43d8bc7e1..73d819b4a 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -173,7 +173,7 @@ Bootstrap() { BootstrapArchCommon else echo "Please use pacman to install letsencrypt packages:" - echo "# pacman -S letsencrypt letsencrypt-apache" + echo "# pacman -S certbot certbot-apache" echo echo "If you would like to use the virtualenv way, please run the script again with the" echo "--debug flag." From 81cda2903a11b660a88b4b346dd4d9870b9e8260 Mon Sep 17 00:00:00 2001 From: Seth Schoen Date: Fri, 3 Jun 2016 15:30:20 -0700 Subject: [PATCH 16/72] Attempt at putting everything inside Docker --- .../configurators/apache/a2dismod.sh | 14 -- .../configurators/apache/a2enmod.sh | 18 --- .../configurators/apache/apache24.py | 63 -------- .../configurators/apache/common.py | 150 +----------------- .../configurators/common.py | 83 +--------- .../certbot_compatibility_test/test_driver.py | 4 +- .../certbot_compatibility_test/util.py | 10 -- 7 files changed, 5 insertions(+), 337 deletions(-) delete mode 100755 certbot-compatibility-test/certbot_compatibility_test/configurators/apache/a2dismod.sh delete mode 100755 certbot-compatibility-test/certbot_compatibility_test/configurators/apache/a2enmod.sh delete mode 100644 certbot-compatibility-test/certbot_compatibility_test/configurators/apache/apache24.py diff --git a/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/a2dismod.sh b/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/a2dismod.sh deleted file mode 100755 index ca96e216f..000000000 --- a/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/a2dismod.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -# An extremely simplified version of `a2enmod` for disabling modules in the -# httpd docker image. First argument is the server_root and the second is the -# module to be disabled. - -apache_confdir=$1 -module=$2 - -sed -i "/.*"$module".*/d" "$apache_confdir/test.conf" -enabled_conf="$apache_confdir/mods-enabled/"$module".conf" -if [ -e "$enabled_conf" ] -then - rm $enabled_conf -fi diff --git a/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/a2enmod.sh b/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/a2enmod.sh deleted file mode 100755 index 4da9288a2..000000000 --- a/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/a2enmod.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -# An extremely simplified version of `a2enmod` for enabling modules in the -# httpd docker image. First argument is the Apache ServerRoot which should be -# an absolute path. The second is the module to be enabled, such as `ssl`. - -confdir=$1 -module=$2 - -echo "LoadModule ${module}_module " \ - "/usr/local/apache2/modules/mod_${module}.so" >> "${confdir}/test.conf" -availbase="/mods-available/${module}.conf" -availconf=$confdir$availbase -enabldir="$confdir/mods-enabled" -enablconf="$enabldir/${module}.conf" -if [ -e $availconf -a -d $enabldir -a ! -e $enablconf ] -then - ln -s "..$availbase" $enablconf -fi diff --git a/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/apache24.py b/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/apache24.py deleted file mode 100644 index 927c329ef..000000000 --- a/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/apache24.py +++ /dev/null @@ -1,63 +0,0 @@ -"""Proxies ApacheConfigurator for Apache 2.4 tests""" - -import zope.interface - -from certbot_compatibility_test import errors -from certbot_compatibility_test import interfaces -from certbot_compatibility_test.configurators.apache import common as apache_common - - -# The docker image doesn't actually have the watchdog module, but unless the -# config uses mod_heartbeat or mod_heartmonitor (which aren't installed and -# therefore the config won't be loaded), I believe this isn't a problem -# http://httpd.apache.org/docs/2.4/mod/mod_watchdog.html -STATIC_MODULES = set(["core", "so", "http", "mpm_event", "watchdog"]) - - -SHARED_MODULES = { - "log_config", "logio", "version", "unixd", "access_compat", "actions", - "alias", "allowmethods", "auth_basic", "auth_digest", "auth_form", - "authn_anon", "authn_core", "authn_dbd", "authn_dbm", "authn_file", - "authn_socache", "authnz_ldap", "authz_core", "authz_dbd", "authz_dbm", - "authz_groupfile", "authz_host", "authz_owner", "authz_user", "autoindex", - "buffer", "cache", "cache_disk", "cache_socache", "cgid", "dav", "dav_fs", - "dbd", "deflate", "dir", "dumpio", "env", "expires", "ext_filter", - "file_cache", "filter", "headers", "include", "info", "lbmethod_bybusyness", - "lbmethod_byrequests", "lbmethod_bytraffic", "lbmethod_heartbeat", "ldap", - "log_debug", "macro", "mime", "negotiation", "proxy", "proxy_ajp", - "proxy_balancer", "proxy_connect", "proxy_express", "proxy_fcgi", - "proxy_ftp", "proxy_http", "proxy_scgi", "proxy_wstunnel", "ratelimit", - "remoteip", "reqtimeout", "request", "rewrite", "sed", "session", - "session_cookie", "session_crypto", "session_dbd", "setenvif", - "slotmem_shm", "socache_dbm", "socache_memcache", "socache_shmcb", - "speling", "ssl", "status", "substitute", "unique_id", "userdir", - "vhost_alias"} - - -@zope.interface.implementer(interfaces.IConfiguratorProxy) -class Proxy(apache_common.Proxy): - """Wraps the ApacheConfigurator for Apache 2.4 tests""" - - def __init__(self, args): - """Initializes the plugin with the given command line args""" - super(Proxy, self).__init__(args) - # Running init isn't ideal, but the Docker container needs to survive - # Apache restarts - self.start_docker("bradmw/apache2.4", "init") - - def preprocess_config(self, server_root): - """Prepares the configuration for use in the Docker""" - super(Proxy, self).preprocess_config(server_root) - if self.version[1] != 4: - raise errors.Error("Apache version not 2.4") - - with open(self.test_conf, "a") as f: - for module in self.modules: - if module not in STATIC_MODULES: - if module in SHARED_MODULES: - f.write( - "LoadModule {0}_module /usr/local/apache2/modules/" - "mod_{0}.so\n".format(module)) - else: - raise errors.Error( - "Unsupported module {0}".format(module)) diff --git a/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py b/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py index 9148666fc..7af0ee20e 100644 --- a/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py +++ b/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py @@ -29,58 +29,9 @@ class Proxy(configurators_common.Proxy): super(Proxy, self).__init__(args) self.le_config.apache_le_vhost_ext = "-le-ssl.conf" - self._setup_mock() - self.modules = self.server_root = self.test_conf = self.version = None self._apache_configurator = self._all_names = self._test_names = None - def _setup_mock(self): - """Replaces specific modules with mock.MagicMock""" - mock_subprocess = mock.MagicMock() - mock_subprocess.check_call = self.check_call - mock_subprocess.Popen = self.popen - - mock.patch( - "certbot_apache.configurator.subprocess", - mock_subprocess).start() - mock.patch( - "certbot_apache.parser.subprocess", - mock_subprocess).start() - mock.patch( - "certbot.util.subprocess", - mock_subprocess).start() - mock.patch( - "certbot_apache.configurator.util.exe_exists", - _is_apache_command).start() - - patch = mock.patch( - "certbot_apache.configurator.display_ops.select_vhost") - mock_display = patch.start() - mock_display.side_effect = le_errors.PluginError( - "Unable to determine vhost") - - def check_call(self, command, *args, **kwargs): - """If command is an Apache command, command is executed in the - running docker image. Otherwise, subprocess.check_call is used. - - """ - if _is_apache_command(command): - command = _modify_command(command) - return super(Proxy, self).check_call(command, *args, **kwargs) - else: - return subprocess.check_call(command, *args, **kwargs) - - def popen(self, command, *args, **kwargs): - """If command is an Apache command, command is executed in the - running docker image. Otherwise, subprocess.Popen is used. - - """ - if _is_apache_command(command): - command = _modify_command(command) - return super(Proxy, self).popen(command, *args, **kwargs) - else: - return subprocess.Popen(command, *args, **kwargs) - def __getattr__(self, name): """Wraps the Apache Configurator methods""" method = getattr(self._apache_configurator, name, None) @@ -91,28 +42,19 @@ class Proxy(configurators_common.Proxy): def load_config(self): """Loads the next configuration for the plugin to test""" - if hasattr(self.le_config, "apache_init_script"): - try: - self.check_call([self.le_config.apache_init_script, "stop"]) - except errors.Error: - raise errors.Error( - "Failed to stop previous apache config from running") config = super(Proxy, self).load_config() - self.modules = _get_modules(config) - self.version = _get_version(config) self._all_names, self._test_names = _get_names(config) server_root = _get_server_root(config) with open(os.path.join(config, "config_file")) as f: config_file = os.path.join(server_root, f.readline().rstrip()) - self.test_conf = _create_test_conf(server_root, config_file) self.preprocess_config(server_root) self._prepare_configurator(server_root, config_file) try: - self.check_call("apachectl -d {0} -f {1} -k start".format( + subprocess.check_call("apachectl -d {0} -f {1} -k start".format( server_root, config_file)) except errors.Error: raise errors.Error( @@ -121,34 +63,9 @@ class Proxy(configurators_common.Proxy): return config - def preprocess_config(self, server_root): - # pylint: disable=anomalous-backslash-in-string, no-self-use - """Prepares the configuration for use in the Docker""" - - find = subprocess.Popen( - ["find", server_root, "-type", "f"], - stdout=subprocess.PIPE) - subprocess.check_call([ - "xargs", "sed", "-e", "s/DocumentRoot.*/DocumentRoot " - "\/usr\/local\/apache2\/htdocs/I", - "-e", "s/SSLPassPhraseDialog.*/SSLPassPhraseDialog builtin/I", - "-e", "s/TypesConfig.*/TypesConfig " - "\/usr\/local\/apache2\/conf\/mime.types/I", - "-e", "s/LoadModule/#LoadModule/I", - "-e", "s/SSLCertificateFile.*/SSLCertificateFile " - "\/usr\/local\/apache2\/conf\/empty_cert.pem/I", - "-e", "s/SSLCertificateKeyFile.*/SSLCertificateKeyFile " - "\/usr\/local\/apache2\/conf\/rsa1024_key2.pem/I", - "-i"], stdin=find.stdout) - def _prepare_configurator(self, server_root, config_file): """Prepares the Apache plugin for testing""" self.le_config.apache_server_root = server_root - self.le_config.apache_ctl = "apachectl -d {0} -f {1}".format( - server_root, config_file) - self.le_config.apache_enmod = "a2enmod.sh {0}".format(server_root) - self.le_config.apache_dismod = "a2dismod.sh {0}".format(server_root) - self.le_config.apache_init_script = self.le_config.apache_ctl + " -k" self._apache_configurator = configurator.ApacheConfigurator( config=configuration.NamespaceConfig(self.le_config), @@ -158,7 +75,6 @@ class Proxy(configurators_common.Proxy): def cleanup_from_tests(self): """Performs any necessary cleanup from running plugin tests""" super(Proxy, self).cleanup_from_tests() - mock.patch.stopall() def get_all_names_answer(self): """Returns the set of domain names that the plugin should find""" @@ -183,39 +99,6 @@ class Proxy(configurators_common.Proxy): domain, cert_path, key_path, chain_path, fullchain_path) -def _is_apache_command(command): - """Returns true if command is an Apache command""" - if isinstance(command, list): - command = command[0] - - for apache_command in APACHE_COMMANDS: - if command.startswith(apache_command): - return True - - return False - - -def _modify_command(command): - """Modifies command so configtest works inside the docker image""" - if isinstance(command, list): - for i in xrange(len(command)): - if command[i] == "configtest": - command[i] = "-t" - else: - command = command.replace("configtest", "-t") - - return command - - -def _create_test_conf(server_root, apache_config): - """Creates a test config file and adds it to the Apache config""" - test_conf = os.path.join(server_root, "test.conf") - open(test_conf, "w").close() - subprocess.check_call( - ["sed", "-i", "1iInclude test.conf", apache_config]) - return test_conf - - def _get_server_root(config): """Returns the server root directory in config""" subdirs = [ @@ -251,34 +134,3 @@ def _get_names(config): words[1].find(".") != -1): all_names.add(words[1]) return all_names, non_ip_names - - -def _get_modules(config): - """Returns the list of modules found in module_list""" - modules = [] - with open(os.path.join(config, "modules")) as f: - for line in f: - # Modules list is indented, everything else is headers/footers - if line[0].isspace(): - words = line.split() - # Modules redundantly end in "_module" which we can discard - modules.append(words[0][:-7]) - - return modules - - -def _get_version(config): - """Return version of Apache Server. - - Version is returned as tuple. (ie. 2.4.7 = (2, 4, 7)). Code taken from - the Apache plugin. - - """ - with open(os.path.join(config, "version")) as f: - # Should be on first line of input - matches = APACHE_VERSION_REGEX.findall(f.readline()) - - if len(matches) != 1: - raise errors.Error("Unable to find Apache version") - - return tuple([int(i) for i in matches[0].split(".")]) diff --git a/certbot-compatibility-test/certbot_compatibility_test/configurators/common.py b/certbot-compatibility-test/certbot_compatibility_test/configurators/common.py index 4657883a3..4592eca39 100644 --- a/certbot-compatibility-test/certbot_compatibility_test/configurators/common.py +++ b/certbot-compatibility-test/certbot_compatibility_test/configurators/common.py @@ -4,8 +4,6 @@ import os import shutil import tempfile -import docker - from certbot import constants from certbot_compatibility_test import errors from certbot_compatibility_test import util @@ -18,20 +16,9 @@ class Proxy(object): # pylint: disable=too-many-instance-attributes """A common base for compatibility test configurators""" - _NOT_ADDED_ARGS = True - @classmethod def add_parser_arguments(cls, parser): """Adds command line arguments needed by the plugin""" - if Proxy._NOT_ADDED_ARGS: - group = parser.add_argument_group("docker") - group.add_argument( - "--docker-url", default="unix://var/run/docker.sock", - help="URL of the docker server") - group.add_argument( - "--no-remove", action="store_true", - help="do not delete container on program exit") - Proxy._NOT_ADDED_ARGS = False def __init__(self, args): """Initializes the plugin with the given command line args""" @@ -43,10 +30,8 @@ class Proxy(object): for config in os.listdir(config_dir)] self.args = args - self._docker_client = docker.Client( - base_url=self.args.docker_url, version="auto") - self.http_port, self.https_port = util.get_two_free_ports() - self._container_id = None + self.http_port = 80 + self.https_port = 443 def has_more_configs(self): """Returns true if there are more configs to test""" @@ -54,9 +39,6 @@ class Proxy(object): def cleanup_from_tests(self): """Performs any necessary cleanup from running plugin tests""" - self._docker_client.stop(self._container_id, 0) - if not self.args.no_remove: - self._docker_client.remove_container(self._container_id) def load_config(self): """Returns the next config directory to be tested""" @@ -65,67 +47,6 @@ class Proxy(object): os.makedirs(backup) return self._configs.pop() - def start_docker(self, image_name, command): - """Creates and runs a Docker container with the specified image""" - logger.warning("Pulling Docker image. This may take a minute.") - for line in self._docker_client.pull(image_name, stream=True): - logger.debug(line) - - host_config = docker.utils.create_host_config( - binds={self._temp_dir: {"bind": self._temp_dir, "mode": "rw"}}, - port_bindings={ - 80: ("127.0.0.1", self.http_port), - 443: ("127.0.0.1", self.https_port)},) - container = self._docker_client.create_container( - image_name, command, ports=[80, 443], volumes=self._temp_dir, - host_config=host_config) - if container["Warnings"]: - logger.warning(container["Warnings"]) - self._container_id = container["Id"] - self._docker_client.start(self._container_id) - - def check_call(self, command, *args, **kwargs): - # pylint: disable=unused-argument - """Simulates a call to check_call but executes the command in the - running docker image - - """ - if self.popen(command).returncode: - raise errors.Error( - "{0} exited with a nonzero value".format(command)) - - def popen(self, command, *args, **kwargs): - # pylint: disable=unused-argument - """Simulates a call to Popen but executes the command in the - running docker image - - """ - class SimplePopen(object): - # pylint: disable=too-few-public-methods - """Simplified Popen object""" - def __init__(self, returncode, output): - self.returncode = returncode - self._stdout = output - self._stderr = output - - def communicate(self): - """Returns stdout and stderr""" - return self._stdout, self._stderr - - if isinstance(command, list): - command = " ".join(command) - - returncode, output = self.execute_in_docker(command) - return SimplePopen(returncode, output) - - def execute_in_docker(self, command): - """Executes command inside the running docker image""" - logger.debug("Executing '%s'", command) - exec_id = self._docker_client.exec_create(self._container_id, command) - output = self._docker_client.exec_start(exec_id) - returncode = self._docker_client.exec_inspect(exec_id)["ExitCode"] - return returncode, output - def copy_certs_and_keys(self, cert_path, key_path, chain_path=None): """Copies certs and keys into the temporary directory""" cert_and_key_dir = os.path.join(self._temp_dir, "certs_and_keys") diff --git a/certbot-compatibility-test/certbot_compatibility_test/test_driver.py b/certbot-compatibility-test/certbot_compatibility_test/test_driver.py index 6823dfdab..ad5755d60 100644 --- a/certbot-compatibility-test/certbot_compatibility_test/test_driver.py +++ b/certbot-compatibility-test/certbot_compatibility_test/test_driver.py @@ -25,8 +25,8 @@ from certbot_compatibility_test.configurators.apache import apache24 DESCRIPTION = """ -Tests Certbot plugins against different server configuratons. It is -assumed that Docker is already installed. If no test types is specified, all +Tests Certbot plugins against different server configurations. It is +assumed that Docker is already installed. If no test type is specified, all tests that the plugin supports are performed. """ diff --git a/certbot-compatibility-test/certbot_compatibility_test/util.py b/certbot-compatibility-test/certbot_compatibility_test/util.py index cbce4fb56..570bf1a9e 100644 --- a/certbot-compatibility-test/certbot_compatibility_test/util.py +++ b/certbot-compatibility-test/certbot_compatibility_test/util.py @@ -52,13 +52,3 @@ def extract_configs(configs, parent_dir): raise errors.Error("Unknown configurations file type") return config_dir - - -def get_two_free_ports(): - """Returns two free ports to use for the tests""" - with contextlib.closing(socket.socket()) as sock1: - with contextlib.closing(socket.socket()) as sock2: - sock1.bind(("", 0)) - sock2.bind(("", 0)) - - return sock1.getsockname()[1], sock2.getsockname()[1] From c79924b7712e2bd770b4c1afec2b2ebb21e32a07 Mon Sep 17 00:00:00 2001 From: Seth Schoen Date: Fri, 3 Jun 2016 16:35:10 -0700 Subject: [PATCH 17/72] Work in progress on removing_proxy --- .../configurators/apache/common.py | 15 +++++++++++++-- .../certbot_compatibility_test/test_driver.py | 7 ++++--- certbot-compatibility-test/setup.py | 5 ++--- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py b/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py index 7af0ee20e..696ef976a 100644 --- a/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py +++ b/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py @@ -9,6 +9,7 @@ import zope.interface from certbot import configuration from certbot import errors as le_errors from certbot_apache import configurator +from certbot_apache import constants from certbot_compatibility_test import errors from certbot_compatibility_test import interfaces from certbot_compatibility_test import util @@ -31,6 +32,11 @@ class Proxy(configurators_common.Proxy): self.modules = self.server_root = self.test_conf = self.version = None self._apache_configurator = self._all_names = self._test_names = None + patch = mock.patch( + "certbot_apache.configurator.display_ops.select_vhost") + mock_display = patch.start() + mock_display.side_effect = le_errors.PluginError( + "Unable to determine vhost") def __getattr__(self, name): """Wraps the Apache Configurator methods""" @@ -50,12 +56,11 @@ class Proxy(configurators_common.Proxy): with open(os.path.join(config, "config_file")) as f: config_file = os.path.join(server_root, f.readline().rstrip()) - self.preprocess_config(server_root) self._prepare_configurator(server_root, config_file) try: subprocess.check_call("apachectl -d {0} -f {1} -k start".format( - server_root, config_file)) + server_root, config_file).split()) except errors.Error: raise errors.Error( "Apache failed to load {0} before tests started".format( @@ -65,8 +70,13 @@ class Proxy(configurators_common.Proxy): def _prepare_configurator(self, server_root, config_file): """Prepares the Apache plugin for testing""" + for k in constants.CLI_DEFAULTS_DEBIAN.keys(): + setattr(self.le_config, "apache_" + k, constants.os_constant(k)) self.le_config.apache_server_root = server_root + # An alias + self.le_config.apache_handle_modules = self.le_config.apache_handle_mods + self._apache_configurator = configurator.ApacheConfigurator( config=configuration.NamespaceConfig(self.le_config), name="apache") @@ -75,6 +85,7 @@ class Proxy(configurators_common.Proxy): def cleanup_from_tests(self): """Performs any necessary cleanup from running plugin tests""" super(Proxy, self).cleanup_from_tests() + mock.patch.stopall() def get_all_names_answer(self): """Returns the set of domain names that the plugin should find""" diff --git a/certbot-compatibility-test/certbot_compatibility_test/test_driver.py b/certbot-compatibility-test/certbot_compatibility_test/test_driver.py index ad5755d60..ce9f590d5 100644 --- a/certbot-compatibility-test/certbot_compatibility_test/test_driver.py +++ b/certbot-compatibility-test/certbot_compatibility_test/test_driver.py @@ -21,7 +21,7 @@ from certbot_compatibility_test import errors from certbot_compatibility_test import util from certbot_compatibility_test import validator -from certbot_compatibility_test.configurators.apache import apache24 +from certbot_compatibility_test.configurators.apache import common DESCRIPTION = """ @@ -31,7 +31,7 @@ tests that the plugin supports are performed. """ -PLUGINS = {"apache": apache24.Proxy} +PLUGINS = {"apache": common.Proxy} logger = logging.getLogger(__name__) @@ -47,6 +47,8 @@ def test_authenticator(plugin, config, temp_dir): "challenge types") return False + import ipdb + ipdb.set_trace() try: responses = plugin.perform(achalls) except le_errors.Error as error: @@ -341,7 +343,6 @@ def main(): temp_dir = tempfile.mkdtemp() plugin = PLUGINS[args.plugin](args) try: - plugin.execute_in_docker("mkdir -p /var/log/apache2") while plugin.has_more_configs(): success = True diff --git a/certbot-compatibility-test/setup.py b/certbot-compatibility-test/setup.py index 8d2bd925d..07dfa1684 100644 --- a/certbot-compatibility-test/setup.py +++ b/certbot-compatibility-test/setup.py @@ -7,9 +7,8 @@ from setuptools import find_packages version = '0.8.0.dev0' install_requires = [ - 'certbot=={0}'.format(version), - 'certbot-apache=={0}'.format(version), - 'docker-py', + 'certbot', + 'certbot-apache', 'requests', 'zope.interface', ] From 91cd19158e4f080a5f013b2c8af772f9d7004157 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Sat, 4 Jun 2016 22:53:51 -0700 Subject: [PATCH 18/72] Improve user experience for linting. Don't run pep8 for directories that we don't actually enforce pep8 on. Install dependencies with -q. Don't print reports, they make it hard to find the actual errors. Remove deprecated fields from acme .pylintrc, they cause unnecessary messages about deprecation. --- acme/.pylintrc | 6 ------ pep8.travis.sh | 12 ------------ tox.ini | 14 +++++++------- 3 files changed, 7 insertions(+), 25 deletions(-) diff --git a/acme/.pylintrc b/acme/.pylintrc index d0d150631..06bb2a01f 100644 --- a/acme/.pylintrc +++ b/acme/.pylintrc @@ -21,12 +21,6 @@ persistent=yes # usually to register additional checkers. load-plugins=linter_plugin -# DEPRECATED -include-ids=no - -# DEPRECATED -symbols=no - # Use multiple processes to speed up Pylint. jobs=1 diff --git a/pep8.travis.sh b/pep8.travis.sh index c13547a78..cadea8489 100755 --- a/pep8.travis.sh +++ b/pep8.travis.sh @@ -2,16 +2,4 @@ set -e # Fail fast -# PEP8 is not ignored in ACME pep8 --config=acme/.pep8 acme - -pep8 \ - setup.py \ - certbot \ - certbot-apache \ - certbot-nginx \ - certbot-compatibility-test \ - letshelp-certbot \ - || echo "PEP8 checking failed, but it's ignored in Travis" - -# echo exits with 0 diff --git a/tox.ini b/tox.ini index 5c88dfd21..cb625ba8d 100644 --- a/tox.ini +++ b/tox.ini @@ -64,14 +64,14 @@ basepython = python2.7 # duplicate code checking; if one of the commands fails, others will # continue, but tox return code will reflect previous error commands = - pip install -e acme[dev] -e .[dev] -e certbot-apache -e certbot-nginx -e certbot-compatibility-test -e letshelp-certbot + pip install -q -e acme[dev] -e .[dev] -e certbot-apache -e certbot-nginx -e certbot-compatibility-test -e letshelp-certbot ./pep8.travis.sh - pylint --rcfile=.pylintrc certbot - pylint --rcfile=acme/.pylintrc acme/acme - pylint --rcfile=.pylintrc certbot-apache/certbot_apache - pylint --rcfile=.pylintrc certbot-nginx/certbot_nginx - pylint --rcfile=.pylintrc certbot-compatibility-test/certbot_compatibility_test - pylint --rcfile=.pylintrc letshelp-certbot/letshelp_certbot + pylint --reports=n --rcfile=.pylintrc certbot + pylint --reports=n --rcfile=acme/.pylintrc acme/acme + pylint --reports=n --rcfile=.pylintrc certbot-apache/certbot_apache + pylint --reports=n --rcfile=.pylintrc certbot-nginx/certbot_nginx + pylint --reports=n --rcfile=.pylintrc certbot-compatibility-test/certbot_compatibility_test + pylint --reports=n --rcfile=.pylintrc letshelp-certbot/letshelp_certbot [testenv:apacheconftest] #basepython = python2.7 From 08ccc64cd1dc0c852ad4189bbc37aa451e7a611c Mon Sep 17 00:00:00 2001 From: Joona Hoikkala Date: Mon, 6 Jun 2016 12:04:44 +0300 Subject: [PATCH 19/72] Initialize augeas in a new method --- certbot-apache/certbot_apache/augeas_configurator.py | 4 +++- certbot-apache/certbot_apache/configurator.py | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/certbot-apache/certbot_apache/augeas_configurator.py b/certbot-apache/certbot_apache/augeas_configurator.py index 12753541c..820a58438 100644 --- a/certbot-apache/certbot_apache/augeas_configurator.py +++ b/certbot-apache/certbot_apache/augeas_configurator.py @@ -1,7 +1,6 @@ """Class of Augeas Configurators.""" import logging -import augeas from certbot import errors from certbot import reverter @@ -29,6 +28,9 @@ class AugeasConfigurator(common.Plugin): def __init__(self, *args, **kwargs): super(AugeasConfigurator, self).__init__(*args, **kwargs) + def init_augeas(self): + """ Initialize the actual Augeas instance """ + import augeas self.aug = augeas.Augeas( # specify a directory to load our preferred lens from loadpath=constants.AUGEAS_LENS_DIR, diff --git a/certbot-apache/certbot_apache/configurator.py b/certbot-apache/certbot_apache/configurator.py index e4c06ba7e..9caa4a764 100644 --- a/certbot-apache/certbot_apache/configurator.py +++ b/certbot-apache/certbot_apache/configurator.py @@ -150,6 +150,12 @@ class ApacheConfigurator(augeas_configurator.AugeasConfigurator): :raises .errors.PluginError: If there is any other error """ + # Perform the actual Augeas initialization to be able to react + try: + self.init_augeas() + except ImportError: + raise errors.NoInstallationError("Problem in Augeas installation") + # Verify Apache is installed if not util.exe_exists(constants.os_constant("restart_cmd")[0]): raise errors.NoInstallationError From 7239361342e0001cfc8ad958250564e50e8bd0cb Mon Sep 17 00:00:00 2001 From: Joona Hoikkala Date: Mon, 6 Jun 2016 12:36:54 +0300 Subject: [PATCH 20/72] Test coverage for NoInstallationError --- certbot-apache/certbot_apache/tests/configurator_test.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/certbot-apache/certbot_apache/tests/configurator_test.py b/certbot-apache/certbot_apache/tests/configurator_test.py index a2e39de47..57344bbb6 100644 --- a/certbot-apache/certbot_apache/tests/configurator_test.py +++ b/certbot-apache/certbot_apache/tests/configurator_test.py @@ -55,6 +55,14 @@ class MultipleVhostsTest(util.ApacheTest): self.assertRaises( errors.NoInstallationError, self.config.prepare) + @mock.patch("certbot_apache.augeas_configurator.AugeasConfigurator.init_augeas") + def test_prepare_no_augeas(self, mock_init_augeas): + def side_effect_error(*args, **kwargs): + raise ImportError + mock_init_augeas.side_effect = side_effect_error + self.assertRaises( + errors.NoInstallationError, self.config.prepare) + @mock.patch("certbot_apache.parser.ApacheParser") @mock.patch("certbot_apache.configurator.util.exe_exists") def test_prepare_version(self, mock_exe_exists, _): From e2631322839e4a3b5117fb4581da72fa4c2eddc5 Mon Sep 17 00:00:00 2001 From: Joona Hoikkala Date: Mon, 6 Jun 2016 12:44:49 +0300 Subject: [PATCH 21/72] Refactor and lint fixes --- .../certbot_apache/augeas_configurator.py | 20 +++++++++++-------- .../certbot_apache/tests/configurator_test.py | 4 +++- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/certbot-apache/certbot_apache/augeas_configurator.py b/certbot-apache/certbot_apache/augeas_configurator.py index 820a58438..478efb099 100644 --- a/certbot-apache/certbot_apache/augeas_configurator.py +++ b/certbot-apache/certbot_apache/augeas_configurator.py @@ -28,6 +28,18 @@ class AugeasConfigurator(common.Plugin): def __init__(self, *args, **kwargs): super(AugeasConfigurator, self).__init__(*args, **kwargs) + # Placeholder for augeas + self.aug = None + + self.save_notes = "" + + # See if any temporary changes need to be recovered + # This needs to occur before VirtualHost objects are setup... + # because this will change the underlying configuration and potential + # vhosts + self.reverter = reverter.Reverter(self.config) + self.recovery_routine() + def init_augeas(self): """ Initialize the actual Augeas instance """ import augeas @@ -37,14 +49,6 @@ class AugeasConfigurator(common.Plugin): # Do not save backup (we do it ourselves), do not load # anything by default flags=(augeas.Augeas.NONE | augeas.Augeas.NO_MODL_AUTOLOAD)) - self.save_notes = "" - - # See if any temporary changes need to be recovered - # This needs to occur before VirtualHost objects are setup... - # because this will change the underlying configuration and potential - # vhosts - self.reverter = reverter.Reverter(self.config) - self.recovery_routine() def check_parsing_errors(self, lens): """Verify Augeas can parse all of the lens files. diff --git a/certbot-apache/certbot_apache/tests/configurator_test.py b/certbot-apache/certbot_apache/tests/configurator_test.py index 57344bbb6..e5c09fd1d 100644 --- a/certbot-apache/certbot_apache/tests/configurator_test.py +++ b/certbot-apache/certbot_apache/tests/configurator_test.py @@ -57,7 +57,9 @@ class MultipleVhostsTest(util.ApacheTest): @mock.patch("certbot_apache.augeas_configurator.AugeasConfigurator.init_augeas") def test_prepare_no_augeas(self, mock_init_augeas): - def side_effect_error(*args, **kwargs): + """ Test augeas initialization ImportError """ + def side_effect_error(): + """ Side effect error for the test """ raise ImportError mock_init_augeas.side_effect = side_effect_error self.assertRaises( From 1f6e999153be1347d92eef884a297966c0e15801 Mon Sep 17 00:00:00 2001 From: Joona Hoikkala Date: Mon, 6 Jun 2016 13:10:34 +0300 Subject: [PATCH 22/72] Move recovery_routine() to augeas init --- certbot-apache/certbot_apache/augeas_configurator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot-apache/certbot_apache/augeas_configurator.py b/certbot-apache/certbot_apache/augeas_configurator.py index 478efb099..6999120d6 100644 --- a/certbot-apache/certbot_apache/augeas_configurator.py +++ b/certbot-apache/certbot_apache/augeas_configurator.py @@ -38,7 +38,6 @@ class AugeasConfigurator(common.Plugin): # because this will change the underlying configuration and potential # vhosts self.reverter = reverter.Reverter(self.config) - self.recovery_routine() def init_augeas(self): """ Initialize the actual Augeas instance """ @@ -49,6 +48,7 @@ class AugeasConfigurator(common.Plugin): # Do not save backup (we do it ourselves), do not load # anything by default flags=(augeas.Augeas.NONE | augeas.Augeas.NO_MODL_AUTOLOAD)) + self.recovery_routine() def check_parsing_errors(self, lens): """Verify Augeas can parse all of the lens files. From 78ea886a79c3dc3b1c75a5d5eb3dca5abbd15219 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 6 Jun 2016 11:49:36 -0700 Subject: [PATCH 23/72] Fix deploy cert and TLSSNI check --- .../certbot_compatibility_test/test_driver.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/certbot-compatibility-test/certbot_compatibility_test/test_driver.py b/certbot-compatibility-test/certbot_compatibility_test/test_driver.py index ce9f590d5..885eacd92 100644 --- a/certbot-compatibility-test/certbot_compatibility_test/test_driver.py +++ b/certbot-compatibility-test/certbot_compatibility_test/test_driver.py @@ -47,8 +47,6 @@ def test_authenticator(plugin, config, temp_dir): "challenge types") return False - import ipdb - ipdb.set_trace() try: responses = plugin.perform(achalls) except le_errors.Error as error: @@ -63,7 +61,7 @@ def test_authenticator(plugin, config, temp_dir): "Plugin failed to complete %s for %s in %s", type(achalls[i]), achalls[i].domain, config) success = False - elif isinstance(responses[i], challenges.TLSSNI01): + elif isinstance(responses[i], challenges.TLSSNI01Response): verify = functools.partial(responses[i].simple_verify, achalls[i], achalls[i].domain, util.JWK.public_key(), @@ -144,7 +142,7 @@ def test_deploy_cert(plugin, temp_dir, domains): for domain in domains: try: - plugin.deploy_cert(domain, cert_path, util.KEY_PATH) + plugin.deploy_cert(domain, cert_path, util.KEY_PATH, cert_path) except le_errors.Error as error: logger.error("Plugin failed to deploy ceritificate for %s:", domain) logger.exception(error) From 1d3fbe945de27894578fdc79878b4ce5032edaa2 Mon Sep 17 00:00:00 2001 From: Seth Schoen Date: Mon, 6 Jun 2016 12:01:55 -0700 Subject: [PATCH 24/72] Copy config into /etc/apache2 --- .../configurators/apache/common.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py b/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py index 696ef976a..af27f7ed5 100644 --- a/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py +++ b/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py @@ -53,14 +53,15 @@ class Proxy(configurators_common.Proxy): self._all_names, self._test_names = _get_names(config) server_root = _get_server_root(config) - with open(os.path.join(config, "config_file")) as f: - config_file = os.path.join(server_root, f.readline().rstrip()) + # with open(os.path.join(config, "config_file")) as f: + # config_file = os.path.join(server_root, f.readline().rstrip()) + shutil.rmtree("/etc/apache2") + shutil.copytree(server_root, "/etc/apache2", symlinks=True) - self._prepare_configurator(server_root, config_file) + self._prepare_configurator() try: - subprocess.check_call("apachectl -d {0} -f {1} -k start".format( - server_root, config_file).split()) + subprocess.check_call("apachectl -k start".split()) except errors.Error: raise errors.Error( "Apache failed to load {0} before tests started".format( @@ -68,11 +69,10 @@ class Proxy(configurators_common.Proxy): return config - def _prepare_configurator(self, server_root, config_file): + def _prepare_configurator(self): """Prepares the Apache plugin for testing""" for k in constants.CLI_DEFAULTS_DEBIAN.keys(): setattr(self.le_config, "apache_" + k, constants.os_constant(k)) - self.le_config.apache_server_root = server_root # An alias self.le_config.apache_handle_modules = self.le_config.apache_handle_mods From e0bb04fd2550701d5b553a1f1516fd17a096d611 Mon Sep 17 00:00:00 2001 From: Seth Schoen Date: Mon, 6 Jun 2016 12:02:53 -0700 Subject: [PATCH 25/72] Forgot to import shutil --- .../certbot_compatibility_test/configurators/apache/common.py | 1 + 1 file changed, 1 insertion(+) diff --git a/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py b/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py index af27f7ed5..918db5f47 100644 --- a/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py +++ b/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py @@ -1,6 +1,7 @@ """Provides a common base for Apache proxies""" import re import os +import shutil import subprocess import mock From e1f4e22c6d5e158eb213745af571cba29dde3e86 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 6 Jun 2016 12:09:17 -0700 Subject: [PATCH 26/72] Unwrap achall --- .../certbot_compatibility_test/test_driver.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot-compatibility-test/certbot_compatibility_test/test_driver.py b/certbot-compatibility-test/certbot_compatibility_test/test_driver.py index 885eacd92..165791684 100644 --- a/certbot-compatibility-test/certbot_compatibility_test/test_driver.py +++ b/certbot-compatibility-test/certbot_compatibility_test/test_driver.py @@ -62,7 +62,7 @@ def test_authenticator(plugin, config, temp_dir): type(achalls[i]), achalls[i].domain, config) success = False elif isinstance(responses[i], challenges.TLSSNI01Response): - verify = functools.partial(responses[i].simple_verify, achalls[i], + verify = functools.partial(responses[i].simple_verify, achalls[i].chall, achalls[i].domain, util.JWK.public_key(), host="127.0.0.1", From 111ca657d86e0caf31dbc81f83037a021fd22131 Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Mon, 6 Jun 2016 21:17:02 +0200 Subject: [PATCH 27/72] Adding testing --- certbot/tests/cli_test.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/certbot/tests/cli_test.py b/certbot/tests/cli_test.py index 4ae69e69d..06aba4ab3 100644 --- a/certbot/tests/cli_test.py +++ b/certbot/tests/cli_test.py @@ -882,6 +882,15 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods mock_sys.exit.assert_called_with(''.join( traceback.format_exception_only(KeyboardInterrupt, interrupt))) + # Test dialog errors + + import dialog + exception = dialog.error(message="test message") + main._handle_exception( + dialog.DialogError, exc_value=exception, trace=None, config=None) + error_msg = mock_sys.exit.call_args_list[-1][0][0] + self.assertTrue("test message" in error_msg) + def test_read_file(self): rel_test_path = os.path.relpath(os.path.join(self.tmp_dir, 'foo')) self.assertRaises( From 144dbdd90b0637777163597e338c4872c890e6e3 Mon Sep 17 00:00:00 2001 From: Seth Schoen Date: Mon, 6 Jun 2016 12:23:15 -0700 Subject: [PATCH 28/72] Explain whether tests succeeded or failed overall --- .../certbot_compatibility_test/test_driver.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/certbot-compatibility-test/certbot_compatibility_test/test_driver.py b/certbot-compatibility-test/certbot_compatibility_test/test_driver.py index 165791684..fae2ed2c7 100644 --- a/certbot-compatibility-test/certbot_compatibility_test/test_driver.py +++ b/certbot-compatibility-test/certbot_compatibility_test/test_driver.py @@ -7,6 +7,7 @@ import os import shutil import tempfile import time +import sys import OpenSSL @@ -341,6 +342,7 @@ def main(): temp_dir = tempfile.mkdtemp() plugin = PLUGINS[args.plugin](args) try: + overall_success = True while plugin.has_more_configs(): success = True @@ -359,10 +361,18 @@ def main(): if success: logger.info("All tests on %s succeeded", config) else: + overall_success = False logger.error("Tests on %s failed", config) finally: plugin.cleanup_from_tests() + if overall_success: + logger.warn("All compatibility tests succeeded") + sys.exit(0) + else: + logger.warn("One or more compatibility tests failed") + sys.exit(1) + if __name__ == "__main__": main() From 8723bded727a9901314187427ab0e07fbd43b586 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 6 Jun 2016 14:17:11 -0700 Subject: [PATCH 29/72] Add extra saves for apache plugin --- .../certbot_compatibility_test/test_driver.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/certbot-compatibility-test/certbot_compatibility_test/test_driver.py b/certbot-compatibility-test/certbot_compatibility_test/test_driver.py index fae2ed2c7..38abffb18 100644 --- a/certbot-compatibility-test/certbot_compatibility_test/test_driver.py +++ b/certbot-compatibility-test/certbot_compatibility_test/test_driver.py @@ -144,6 +144,7 @@ def test_deploy_cert(plugin, temp_dir, domains): for domain in domains: try: plugin.deploy_cert(domain, cert_path, util.KEY_PATH, cert_path) + plugin.save() # Needed by the Apache plugin except le_errors.Error as error: logger.error("Plugin failed to deploy ceritificate for %s:", domain) logger.exception(error) @@ -178,6 +179,7 @@ def test_enhancements(plugin, domains): for domain in domains: try: plugin.enhance(domain, "redirect") + plugin.save() # Needed by the Apache plugin except le_errors.PluginError as error: # Don't immediately fail because a redirect may already be enabled logger.warning("Plugin failed to enable redirect for %s:", domain) From 1c1816fb4a49e97b99300d50be00df5f41bb508d Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 6 Jun 2016 14:35:28 -0700 Subject: [PATCH 30/72] Update tarball --- .../testdata/configs.tar.gz | Bin 101287 -> 100286 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/certbot-compatibility-test/certbot_compatibility_test/testdata/configs.tar.gz b/certbot-compatibility-test/certbot_compatibility_test/testdata/configs.tar.gz index 7323acf747643887d8883f3ef74437d811032b2d..05f7f4f9bc54975c0f575ebd80613c9e419dc3b2 100644 GIT binary patch literal 100286 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

>+7bOwi=X@0cTd z;qgQe42DFI^hT4dRi+TLpt4?)6?k^!gFA`tZr~9#w6D2glwl2jpFiL?u_*3e&pH;_ zidpCKMW)<4a_>qT*bhGfjQub6m|t2X9*e~@tom=xeM&y5BX^r+$`3rey`mralQgf`QSto_i!ZCo{DibTLFZifkJ zQMFIbcJiPW_eZaGu&gqw_g3&}PBHBjxH?WF5QucxE}-G?EU~EUX9r7h89pY3^~Fj} zbI!nE@~;S5rAZOxSVYCGZOm+t*~6Db^o}45n#7^(ly*4Ng*6l19Ns4KPK2gw6}1&B z*qJ^AYp*5Y-2)BSMGMi!h>Lul7dnJL%#?M9wc&3>@+VrP4LgkF4m>f2 z;S4?wHkl_EcnB*_vL1-Hi!jmmC~&h*3S9gADTg$afYcpi&UYI2wk!Rd1$1eut*TDx zL7Z(KGSF6Hj+s-so79)~r8SL1wCNx%DdVDdXQc3c3@)iD^-e;YD8hZyu`3jL$LuAD zF?eAN=TSIohmC)`8zMUuDuVB%yJ%^s6&J6dz~_SR5h;WL9KOjr5Oor?!!c=-#|*%l8IZ{~UHU^oIR|?W9B_XaIxPFLZ2w!l#@cjvoop8#!YSU#Jgjtl%-ijt6?N1-W&WTT0cN-{o5(!ZzRb-M1SOmN2C8*kT?3$h zX>+gOlck{f^Osz}Z5epIU3Vcr1gjLX_)7){4tf0&qqP>-k>s8jTcHLB201UKOgs** z*5aN>w(|42SH!8s=#G=jWv67X2}fruNS;#^la^eKS&U#iPGGRNbuwXjTEoE482>~z z(P5~?{A15V4Dj~w{S6rC*`AdMEJxuw2**2g(vNGW0EiKm5J6?AOC>ORM`7#)Xu$X$ z=D!ib_2@!;W8dY-@by>?KgkP~5sp@q5W(LfQl@T5XrXvfd;9gMCbN#gs&S{2!e{HR zt!0lr7tdt(H-j35Z>WeVUL_(3tfVW?^9#>`SA6n=ZSm5Uw`AJ^F`~Y7zJhPwho_3! zka{k^4t`kI95xfUg15b>qsByRA3h~D6HS8cZE|38gwIEW-{y=8XGey@ujL8XIrVXj z75VZ~;%~$`Pb{JH?Ci<6kp8P8om zjooCANc_>AlzfG;eJC%a5>tv2$9wY3Y9jBn+O-6(geg?G_=d@O0Qhz9 zxil~{e&kc>pz?)IS{JO^FEh~Om<|x7CA+s>?o_mL@hsbKuy%Hd3-1u-nn_cq>ch*u}xyh=Nx3;C)~g!K{| z5xO-v;havSg;RHpG_}-*t^a3hqB;)R-`A89W4ysP(+lxn4mTpJO$8Jz8-RL7xKjrK z7tzs)3Zt*21-7w0m?E6qPmf1$;g6GLiTH_1PXl=x9NWG%ZxM2&G_Tx^R9SF=X9j)4 zt%8>Ya^d?{)9B?$ACS1^HHOaz7f@Yj=lquN6)k1`s`fai%8E>mY=Hm@E{D@YPb6he zqXt913v9JwwwKUSF+U4O*akAs5ptypZ2s{LqxmJUk4k&H_3Mohuj@6>AwB~ufHeba zts2sM3uk{;8TM9`uSZXJq$_q>{Fsr`ZCjrdrK`?kOfkW6?xK*UTEwtnuQ?tVt#TbEq`-7~{4I)qgWA1u`ILx7Lr3 z|D!4|9yms+s_`cH&)~&#KGxL}DJw^ZV7{MSv+iNu_U~asNbhfCKV&HTl;lYz%QXML z1#zZq;}0~fO;V0=-CS;=ymkaEsX5v?^Gddv*69V! zOj#BnuUthIMKz%5VFHNP;^k}9`^LhEh^S_QJqJdlOkAc}-A_BP0R!;CyEGI``Fc=A zF6C1@!PfV6-n+LR7NCcvr={X(u~`~|IMjMLb=DgFsw=I@5ObKr(=C*4MX2QY;!pkk zt+BkD+)K4nF)bsVT%g>i66YQPL&Wl6IIb4+S=r=9)`Dg@Oz4Cg`Q%%9pS%_U=Za&5 z!R`gRv2$uRi{3U2yh?QvmhKEzZ-$+y1D~0@F0Lns4R}sH5Quw11qC#ByZg4e`42|e zJqEe?!AW@);QbN$f-Vtos=l?eFt=ehud%G$<|M`+B63}?2l(-c^y|z`Jv1p0*&ou0 zNVUC~;Ok9}9=+MUz*Y9Q8HcI5_xn7EIBdi}Ey5$5wmDS8hk_lI-nJb>cmezc@B#ym z(=oRWj~96yXIsvS;5I^6M1z;V-CRz2+_=49u?tn8#w;%!1-F0W)8aH5e}T})RF-g^ zqmMW7mJBixQbgxwiu2Fq9zChu3X$&s-BwdVPx}!+dX>gA$ZXEKbkScz7P%_S6Ycu? zLm)F|^O3iq!Q?g7g%G z01RzATw>%T5khJ}h>Wcu(tQ6cf-hJ)`n*vmihb)RzH(b#T|}MT5alEsDhfZ#vn@3b zBhNxBO6%N8I&i~g6>vS2zx^xG5raLJ;yRrxb}LPbSVB-R#WCWZ(ZfaxONdQA%d(Fs zZS%2z365mmu%U_VmWjg45_8}z2CS0aqm4ML#(c!C!pQ?VnKCU%d~o=d_V$w&jQjJWF)g+FVWBUms0eX$Pjq%+xv0Cu;GSt#J1qiM%;!-s&3w-W!*6Ih<O<%9)T!r5(t?>g?UDWRYNyRF^Cr>Q9YSL}J4`1f_9Hs6 zWtd<*%dHyT0;7NYv#5Hc1l|q{t;hCTF1ETbo-7+Lqc3fV7dtN6_c7r#I)@)r4qx`2 z(kV)$+KM&0WzjUgVQ=&hLIKhd-GSg9y|Sh246o8bWs~Wmd?c92XRLGM*msTRrG9G$ z?T5p6qO^7iFb*D9-lPr~a18B+b0f5$Uyq9Y1KgiJ#Y13&4nC{ zWMjlnZ{yLZHTf;%JO8uQv1l6D4vgtHJF)X5)h#jTs8qP5_PAVC{Mwi+UwiZvjM0^e zd!r=^_~ie?6ZQ35{HtAmksq z`YN=8TM<1_JYn$hY$3NTHwVg+BomBNdz5v+)4u36au*yZKYP+Fh4VF#?cw_Ism4fK z1b%$hxz6BC<2j!_Fdwk%SL=~dC?v?CI-tS#%@cL&YcSj}(778_PoUZ01Qx1E)T4S- zVQ%bs3MeS}y?9@LnQpxy$MW3TactN+eYktVbbXR5aQ#H)>x_?nCyv5dnd`W`h}+^I zRx13sOF*@ZAHiYD!bNyaP%pG}tixjl>FUKIy*X<8lU)G8nYusKgW}a9QT!Q1rH9^w z@IPkj|Cqe66H>q4u%RjrXFB{m!X-`7Ti(E>lpHAeTHI%!#niA#N2rRmh!PS!Ia~j# zu5j)Wy}puX|Any=+=-J%KoX{Q_Jo_M&H9BT;&!(;4#KU=hG;IYWrL>S`*h6d=Vq5e z->YMLTnp?Q`tQ3$hel%y9gEy27mU&in zZ%Z~G^zLX|s<-}Yf$cAZqtkdok;lmV86MNPQ?T1lEd;J8UEkw>+Kl};>7TNw*KN%B zpku}ZdYA2qo^`Lk55+pZ4eLtT7rEi#c$F8F;Qvhpbd+T>Y?P+Fae{47!g4*>@rClR zR8z|y-u&{X7epCw@Pih!N4{GuYf2g#bAdB(r0EJQ&lxK!?MQ_FL=PpMye7DLhQ8R- zHqc~u@Bqp=vbIS#jgN0eDAIp5DnD9WaqSn@GB~^xm2}x#mr@s189T?2;`Q*+`!*l+ zcze8TzDs=S3POK?f7)%S6(aHm2=eyCKuWYAG$Jf7*?CllpH)j0Hs69xy`wN4veS=8 za9y7%3uL>;KK^*|2U3MXpFaf5+Y`?;c0>>^JM7zgh3H14cE2$TuCNB%?)9@j{^EY~ z(>cI+p;}0uq~@@!rtd@E(^&;?Kzs;3a-Fu4?>Nvudcp(62SwJ+g{KaEL1%Yg9YgK@w(#C{MGm? zF3;wJ=`e7uXa6myn{`NQ9k|(V!2;BR`d|OoK(i?~vICRGw&#XH;CBGacP%(sWzLV> z84*uubp!^%wl!{C)xZ zX+-$nXvIQ%R4{b?u8qV%jrJ_y|9LEb25K}9#Qf~i1ORLQPn8hRo%v<_TXz@u0Y4u| z2lhXK%jW`Xi+mx!8#fs;fGfetY6?K}Pa&i(f7>{%%r3gSK-a||LmX_Lm8Zb5_gfon z!~HKQjo9b^r!e{!kjSMyFm?<0o(p*dO#QEHop-=PLvPHN;oWy9@Bi>K)CC%ze(r|c z3jJRI)d!)c?oQ2jz~E2m{{l7)`FTP7@YNyv_JyDOfBKK-0_p6!<|_lW^xOV_dJBPe zSt1(VLXkY*7#rEHZt#aKOt2L^`MJ8g8YEW&98DQ1@-*-v`#}l_<#AP>d*~5x-^IYP1R_A8okb4aDZH&tU#{ZZOvKW zrL>Ns6l3W{#?EQ$JA9AY~! zKaU_;O(k4%I-z|UT)&PtCJ{f>l^fTX0a=|A>OH_o6mFl7l;}HQJWub&TkpLO z7_dMV+Ki2!@go0=#1!ydlJo#6-IxmcXkb8ym`U^Jhz0Tzrqq~>@S!OAwuHOoXdx8U zZ3FjTGZn5~{NjBd_3sR{a9=(w~62kG5XAiTGr(&3^9>IFOXZr6rTQXunPXP7kZL~ z&tgQ-E4nc(Ewf})7NuH1Asw1@9{*U>OlAtWP6Yzd3d}easibaUzh#ikg5C7d;m6 zPex^`M`qNF(G-glC>)qyw`e8a zCx$#48(VTxz}JK&zwttlzIo)K;#DzBm{MK5%qpH{d!wwq!)FJ9ycgq_u7BJxiN59y zY2KFNND!Jgz%q*);wH6r1FNYFGI$VADP>&NZOMwF%t?Z>FM{E<_ljF194+LpD~W)K z0>dA7i3_RH8ji+W!j2{C?E;Md=~c%J8s<^^pb*vqfO7*KOT_v>v^#h3tV2 zt!Hu96&@Vvh&cYYr2p{1D~PaL%&>0Q=)zes$yf?y%~?st^xna^h-U=8X$hiy7c+bc zv<{vtoVc2jh0Xcoo~5nT9mOKk;w1iA6R>951AB$^8@GpL3%p8{#Kzq|l4E_)6(sr1 z_hRu@s$uwI$^VPQVzxs{{n3tlO5aMk&hnuM55Wz4o!ya6N85nxFeGmKcxc|q4KM-oU*%N~2FvUK% zC+dBMW0Z*rhKjuiPdU`H;Kd4Ax`aLs4)2z+>5s(O=igkcgZXK`_3I`+V1};YK`p4N z{|HnOk@Duawdq|jZ7<3WkIMekvLqCvhxYcylvbhVfj`@JD}9C4s`}Iu@$&LRHgQZE zN#+A(5?Atr-9&3S|C!U7jCYe5(zjnh1B*oF*h+E1FTHlgHUFT#NWUGJe~A{Vgo6Sp zdxRo^rQ?2t(A{GSG)N~y<=sxu57IBr4@Hyia!bGIsACy!&yE6rgw&7j^9Y0yQZ8&~oH-0rcd*AGzO_*JZT#}cns*JR zY+!F%U?}5HOG+YOH-iPkhu(PSN0NLfBjhiNqf!}*Ts*c8%~JQXju5P~Gt}K^f~Ot` zb0i{urI3FM6y70HC0rQHJlO}&_m7@yVxS9#AfkqrCH@1QlYuIIzz3oY#>V6Wrb+;Y zv_XBBci*L~ee44&4Gz16Y(Xf?hE!}oz0wO=w=Js;zAf9GO6`iYuq(H)+%SgzR=Vj* zp;cH--W9t$2~}p2gG9=|_q7kzFIvG%5HTByvT+}%0d-boDUb{Dl@GTb+a9Lrk zU7KBa9Q5QL^lZ!P`>hi3Pg#khnly+oErS$tI7d`-1g(Nd-`$$ur?UHd6xu(C+gIC^}I_OI$_Wz&l>N)hv zj-fJNtjh<9rlxB{&p-8*F{V@X+yX#X)4P=J(C<-0rllCRq7OS2i8LW+34#tb{hGJA zEH^Gr^p9Z>ey@ATC#2qP*`94=40Nv{+=-g;w;BreZ!U!4q-Zk8@e|nP10Cq87W;i1 z!bBNia^oU3yM5@B;W-h9qIoK!oxm@@4Xf&HOoWpdXpqafrgI)GU#Ee!OO(Go@Jih+ zhC&5bA}CdyV>`b^4yhS!?%qY2Xr2xL`+oIGGW8*%Oj}X#&bf;xR?9Xoy!~U9e<-Ap zDgOFDN8=LIBxiyaHYDKr=lEd9eY#5cIxp`0R)J@Ukf=8h+2}1rRN*{=EU$E~<}v)I zSsJiuBck)yQIFxQv%X-gTou6o*LcwcaA4iw#2N=rHQYVKh1(qMF z(zUDFRqFT;fnCTGF2wC_B+;*P{^=dKkufs}p|3l!hWSz@@b$$*!O*_0T!a;m*gLX< zJI4kvIC~MNBDXg3yTml0I9{{#e`}%bp;ElF6Syj5rqqYny}8Ka&4HIGxS`v4b|SgZ z@QbaB5-)xSI~R|B8QWIh(1Q)F?t9}e>D~ni^uvXhE}6ySGpF&gCMY+!u<HyG<8h=FX_~RVHc08Qvj(MlGCB1(gD8H-Lj0IS0vRR!GIl5 z_rsKyU-x|M5gKIy`1}K8dz~tqC9X!ZPXu1^$a~<(R~S&4k&1?+hAjsEZq^lzs#aIQC0q`W1*T@Db{HrTC1Rr62&1o5%KmwLx!->7?!OuvaS5Y|W}YuXn;`8g zgU8JW_APxe)@{3_Pf$uh(4_~Pqc})BA&woy{5F@i?6}awz#jZM2nw&oJd4s)-Vg(& ziY{qmW>B*I4tR|GR1>X+&B-SucOy4yQ-eaH?-%KKN5=$9QV)~&V_|Gy+Ggp`h6aaM zv%c|^Y(6Ob;HOPUy-9P9X?Z2LX~F$3zHR$2*!gl>A5-@-g{d9 zES>HeI`QniU)$)!7CBrUlx9crDB2EW5?pB=1P%;;@qH=r``jH&hdxB$m=6Gl;p(n{ z-`1Z*8b3d~^#EWamHAa*&`fz&Z-k&o)<$jm%7$+5m=NTHG7KZPZE!m4EGCOnmL0ci8?IO8s|IVa8|; zm8XNnF%6hdmj!a=4<4+>+uDrLI=p5)0=K>k3C&i%01;^`z*aNHSIQ(k>~;vR;Of4g zM!t^OXN@mL#x>xl>le}}2e6TZVGT&uBXo#CY(Ud4{B~KX`UxmC{XvZK@$qVa(Vha< z)B$U4S_gog8EM=9A5C8w7Dv-Wivdsg+RE&>gl| za|bjPBEV2M#Uk#UbmsJd&l)7Khes-ZVEmZ-SPB$q)XjQ^IDBI42N=^7>OdA> z=hgs|*WcBUx_F`iEh|5tU)fUS6X+8o2oRICaz^Yi(Rlnh>3FH$X7*J^EAV^FskcL%b+Crl^~Kpu}1XeZwl^IPrX4A zuL-DR>HNF6`97SITB{CFolgfA<2WHX^gkH|V)clcggxTQ=3s2mPZ*$P-WL^*(kBoF z;|(5iOQATo<`>OY;N* z`pEjUjzJ}iDfRIC@H^u7Q9$Gg0$x9xI|OXxuAwm*G`|cM+EPSNS+wEyMX~W&GIez! zMXzL;iX@$+y+RL;W%E_ZQ0atMzX1f*gU8;aDR8(o(pnq%UX^J=7+&?6mLqkWCTi8O zGqL&RPC%n|>eXwp23+|pLPBDz-V?0wM7{KF(uhGlwNY?Bkd-_he2e5hQ{A($sDxed z0Yf;uNsO17d0}6kyVl_6z&GbrQ={C&p*Uu#UwD?*=cY>bhCPPX{hpRcg=YR0MK``A z35E;uA8r^~rxqYK@(qg9_3mV2=<&<{RndfVrO_n5_C8F4Q)na&9jiSeV|`=RZBRQeHcLc07{46L!ddjfS$sy3EELYYrn}^NW8^O`lkL3 zeY@exd}i@&WOcHQ?a!>~bJFc2zO;>;k^wngeS>7eBd2xE7zJmNu_Grd`wE>3OV?j+ zOy&SX^28`jZptxez1tR8Ju7X3wItuBTQRlxZ@tSvz${4l366`&=zJnYlH9A`91s`x zcwk4*$q0*O_TEb9ck!LPWAE__i<^aXFt!K;Bld_ly2xSIIE1U#i_S`%T&v+@BxhVw zTHC-A)ya;W3kF5(u`*oT<*+K}k!igxrd`4&6x_{~piyKufO932GZ?-}Qfik+E1(=` zpe}VE5rEmBtbi6>q&{vuA*(qCB1`{bvcKjmvJ`;HDsC7hnx0oYf=ek zfO*GkLqo@Tz?Uz5skGd5bb4v)(6bjxarxYjEz}lKb!(4bO~!T*Lw7|oFFfXI=K(OL zC)Gj{)=yZ2;WaRG52IQ)YJyA(ZLWNvwj^YGiJ`oQ8G6;1qxZ-^Iix_qycq_-BHFhX zP>`=-{{ypg7}3jwe-z}Vm4W;PIBM(!v>4b2C_0wqX9&bRXh68NGk~cG2K4X`I96(IvE$#Zaf1Lw?O*&Ux{TPBnQaKJp!hWtj?iV z+Bw%1rR9j}Q{v^dP3jcw?|Cd~o*Z4P^?9yaa~3$l!pX-p-giFVF9=vbC8DD})kFQx zDWFgd<07CpWS#-o{Hh0dL9zJQn>unc&ga@=sUX4toslJwpxON*TbT(wV9Hb!teX@N>_YI?v3(jV@71O#;D+Eel!Q9!~i=;#Q@d%gxdy)Gx;(eyj^<@q{(dlgjm+W z9Fpz<6knKoK;N@ry+@zd3AH2PJ5CCW-_>n6aQ3x7vC#E*LqdizUtYj#9COdI{uO(G zQH>d}eCz>$lxxpm4jZ%2xR>AW`AB9`@3;9P;@H%2l}!cr;7MXWGkwLc`xlv*r&bsa zyZ^k5Uk1sm+UNJtVGtYiC&o;RZYpjVqXiSZEyOG38nFzF<;&sxNjCFmvoV7Jow3<( zFMcFuMLUEg-VFZ-?Fe3^JMPrSv6eW?$Yp#?mYm1qqIpP-P;VJfBUuBSA{`7=w=dh< zFOqMUJVb>+A(Q`P&=e{#5SjNuHHE;Y)zb}#LAwgbxqBhyg%c=w+}^(GKY`^aS9@Uz z04;?3R5Eb?4HFEJAv?z<$(w014 zZC&+`0-!Gy$^ z?*T*^JOO-;l>B(y9(m|yzdB^n2L!u7o@|`0GPb`gSwKMgZr1DK8xh_9d3sp#nKfMa zoepXa`;mKA=1{HMku&K9Hkzm3qh*`8FTbv%%P9{%PK<-LHXjk;2T7eOW_0qS6apYd zdlCQ;j{(ZWTae((25cBj9+tyJbsy|CBaJmxeDO37%i-DeNb@PI6$HqzWEVTz-^QXp zfL@edZ9zKlr*h$Hxq-`<>(X=(wVecvJG4GM_FvfUfz5!QwTBOYa;@W5%(|`5UX4dz z3_RI8y%*q==KLmig>mcT1{@DnnSB9Ve&@GmEzdf%wER_`RQ`KegLS0V(QC$Ti352q zV;+Vg8@&hCoock^@3GXRftvl-QH{od_KYeEAo4wA4SZD_2e4E|X}o|%K)}UoXe`%l zdEoX~wq^a^h0H?%;YcrcjIj>aCO@rFV0#A!s%g9U&$3cLhzrJ{0!?A}oBvoB=>!SA zDm6L=WX*hYDEolJZCLLP6x6W03vQQi0vv7|>sx1idmaOeh=ue%(1x?y6SX70^Arp} za-o!RYMC@iE=B!r{7=;OAEAq$-UH6Q>e<+rH;GoO1Vkt*Q;xCk64HUOuq=GOsrU$4c8$$OG z6J@<5`olryXzgFx@x$n-YW|9T&-0F*jJ>p^9POnt?EO)W_#6H!>}%dfPa*Q4ZAR|n zib~z`F!~7Eug@$Vg_yP@{)#~bA_j49dIL(N#%=uU^|dq0{d@xT-w|sP znwp05rypb$zb`kw_PmQEJSZor$L-F@9`Hx4yJy?T$-3aK6}Cbw5Xy@~d3)-!;U)La z?Z#ot6dM8bKM^B?-QsEDq z7}eok8S${OjPfuIk-{Hv_TNALzxik9@F+P8v*QvXi^ojU72`tZwzqRF@RiFRrKtT9sXbeqbHR|Dd_WKtqx%O zDZ8@~2@hI^tT1Sb;b=_&!GV&@!@t?-Ln@U`&=ZDBTEEq~2r1*d<}tGLSX$8=jwI_8Mj52r*U&kwP$%cu3&Kk5zQ zDp^d@EA{A3HzbE5%*;uq&H8DVaSv2o>X*8&v+t7z?~@)HYgn3VI!k=a>wNY_&Y2_5 znJ=sib!-hiRbEC-`bWG-l`+H3etSDlrfSn~9sAt0X1CwG3~$a-)oBzFm%@=PdAHSMAjxN@`#9h4)aXF%B}gm4L- zEt{sLwGyEB$ye1em(Y|(bQAD9cH&FYsHBPM^ZQ^efzC!*XZEK^>do$_2E{uu=rMuk9e9tx zW${Jf8g@$W*~H}!T#t0zYQJ5$2R4o28cl%B6}Dr5PY-1S$iZW|0unl)0`p!6dgWcW zTh#)l*!p$qqFz{Vb`xEUM~A%U(Zt8;%0*9S!a6ZaI26M!LsjKy({F#WNqg>=mR)QR%Cqlz zrVFV5xHU%TDw?&mIH#xm_TGZYD6q@?dnTMw{o;^zdymiw#jv5M7+BqDDy5}dP)`R! zxK6xpm+wPfcC0+X=LsR0K0TIgQzBx)H&PC7^Tnf?B>Ya_WmPK71IirGaq-j43NYd; zWk2TUl2dx zn)1A`+^m-5{H-fG;?w?e*T5NTnl%V#SMxF5`}pn;NRq4v%ljQfy=}h=X(Vo75)oAh zn0#*(aDqwwiqD$6U?F(;5U~pTW*1ncPT%H%Eq^5heB1-KD8WfFf^I?miakKnfN96^ z-K*k44&-f}Hcj2QRd0un@1TSZNAWYLzuno%&pQ+d>ZcV+5Z+YWG&qKxUJxRM#sp_9A|cyG zt*Nq{n^mv*K?^$D?UeyjhZgL32XBM%t@$0@}Lvlpmar|v~@N77z&@sglRtO zScsB zHl>Xx^kbaE+*3$TKJ$~d3%RM(6=Bss%$cx?k#5guGPh+xP)1CWZzj(%H4Fz{gU_b z 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 literal 101287 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

>PD40$S_DOkt_8cFeaIjOMKd6SRvO4frMW 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 YDNSigQ<~D0rhMh{f548beE?_+0L2q{f&c&j From 5f8964a6a854ba3f1afd002b3062f52d0eea2aee Mon Sep 17 00:00:00 2001 From: Seth Schoen Date: Mon, 6 Jun 2016 14:48:49 -0700 Subject: [PATCH 31/72] Fix typo --- .../certbot_compatibility_test/configurators/apache/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py b/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py index 918db5f47..ed3d9d67a 100644 --- a/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py +++ b/certbot-compatibility-test/certbot_compatibility_test/configurators/apache/common.py @@ -118,7 +118,7 @@ def _get_server_root(config): if os.path.isdir(os.path.join(config, name))] if len(subdirs) != 1: - errors.Error("Malformed configuration directiory {0}".format(config)) + errors.Error("Malformed configuration directory {0}".format(config)) return os.path.join(config, subdirs[0].rstrip()) From e826de5db70823594d2c9c286a953de5fc656c11 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 6 Jun 2016 14:52:30 -0700 Subject: [PATCH 32/72] Don't change line endings on a tarball --- .gitattributes | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitattributes b/.gitattributes index 5eee84cce..8c41b686e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,3 +5,4 @@ *.jpeg binary *.jpg binary *.png binary +*.gz binary From ce378cec216d73c8f20ee3d34981089a1d842829 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 6 Jun 2016 14:53:12 -0700 Subject: [PATCH 33/72] Try updating tarball again --- .../testdata/configs.tar.gz | Bin 100286 -> 100288 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/certbot-compatibility-test/certbot_compatibility_test/testdata/configs.tar.gz b/certbot-compatibility-test/certbot_compatibility_test/testdata/configs.tar.gz index 05f7f4f9bc54975c0f575ebd80613c9e419dc3b2..9b819d0c7b2d8178d3aad1bb25aeb32a4efae76c 100644 GIT binary patch delta 31 lcmdnj&vu}njZMCrgJIK$jcg)vjJ%trCjhE{3hDp= delta 27 jcmX@m&$h3hjZMCrgJH+(jcg)vo2BLA7H+QE?{)$JjvETn From 8aa1d85991daa33dc22172f4535ed65606299a85 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 7 Jun 2016 16:25:08 -0700 Subject: [PATCH 34/72] Move mageia bootstrap script --- .../pieces/bootstrappers/mageia_common.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename bootstrap/_mageia_common.sh => letsencrypt-auto-source/pieces/bootstrappers/mageia_common.sh (100%) diff --git a/bootstrap/_mageia_common.sh b/letsencrypt-auto-source/pieces/bootstrappers/mageia_common.sh similarity index 100% rename from bootstrap/_mageia_common.sh rename to letsencrypt-auto-source/pieces/bootstrappers/mageia_common.sh From 1c363716a086ec4dfb3b0c3143e915a75efd106f Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 7 Jun 2016 16:33:04 -0700 Subject: [PATCH 35/72] Wrap mageia bootstrap script in bash function --- .../pieces/bootstrappers/mageia_common.sh | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) mode change 100755 => 100644 letsencrypt-auto-source/pieces/bootstrappers/mageia_common.sh diff --git a/letsencrypt-auto-source/pieces/bootstrappers/mageia_common.sh b/letsencrypt-auto-source/pieces/bootstrappers/mageia_common.sh old mode 100755 new mode 100644 index 9a4606c9d..d6651574a --- a/letsencrypt-auto-source/pieces/bootstrappers/mageia_common.sh +++ b/letsencrypt-auto-source/pieces/bootstrappers/mageia_common.sh @@ -1,24 +1,23 @@ -#!/bin/sh +BootstrapMageiaCommon() { + if ! $SUDO urpmi --force \ + python \ + libpython-devel \ + python-virtualenv + then + echo "Could not install Python dependencies. Aborting bootstrap!" + exit 1 + fi -# Tested on mageia 5 x86_64 -if ! urpmi --force \ - python \ - libpython-devel \ - python-virtualenv -then - echo "Could not install Python dependencies. Aborting bootstrap!" - exit 1 -fi - -if ! urpmi --force \ - git \ - gcc \ - cdialog \ - python-augeas \ - libopenssl-devel \ - libffi-devel \ - rootcerts -then - echo "Could not install additional dependencies. Aborting bootstrap!" - exit 1 -fi + if ! $SUDO urpmi --force \ + git \ + gcc \ + cdialog \ + python-augeas \ + libopenssl-devel \ + libffi-devel \ + rootcerts + then + echo "Could not install additional dependencies. Aborting bootstrap!" + exit 1 + fi +} From e51c16d666655c2c2405ea604c5aee76bf5eb4ca Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 7 Jun 2016 17:24:56 -0700 Subject: [PATCH 36/72] Update letsencrypt-auto changes for the new format --- letsencrypt-auto-source/letsencrypt-auto | 27 +++++++++++++++++++ .../letsencrypt-auto.template | 4 +++ 2 files changed, 31 insertions(+) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 1992c9d47..eef0c957d 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -458,12 +458,39 @@ BootstrapSmartOS() { pkgin -y install 'gcc49' 'py27-augeas' 'py27-virtualenv' } +BootstrapMageiaCommon() { + if ! $SUDO urpmi --force \ + python \ + libpython-devel \ + python-virtualenv + then + echo "Could not install Python dependencies. Aborting bootstrap!" + exit 1 + fi + + if ! $SUDO urpmi --force \ + git \ + gcc \ + cdialog \ + python-augeas \ + libopenssl-devel \ + libffi-devel \ + rootcerts + then + echo "Could not install additional dependencies. Aborting bootstrap!" + exit 1 + fi +} + # Install required OS packages: Bootstrap() { if [ -f /etc/debian_version ]; then echo "Bootstrapping dependencies for Debian-based OSes..." BootstrapDebCommon + elif [ -f /etc/mageia-release ] ; then + # Mageia has both /etc/mageia-release and /etc/redhat-release + ExperimentalBootstrap "Mageia" BootstrapMageiaCommon elif [ -f /etc/redhat-release ]; then echo "Bootstrapping dependencies for RedHat-based OSes..." BootstrapRpmCommon diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index 43d8bc7e1..4d15d281d 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -155,12 +155,16 @@ DeterminePythonVersion() { {{ bootstrappers/free_bsd.sh }} {{ bootstrappers/mac.sh }} {{ bootstrappers/smartos.sh }} +{{ bootstrappers/mageia_common.sh }} # Install required OS packages: Bootstrap() { if [ -f /etc/debian_version ]; then echo "Bootstrapping dependencies for Debian-based OSes..." BootstrapDebCommon + elif [ -f /etc/mageia-release ] ; then + # Mageia has both /etc/mageia-release and /etc/redhat-release + ExperimentalBootstrap "Mageia" BootstrapMageiaCommon elif [ -f /etc/redhat-release ]; then echo "Bootstrapping dependencies for RedHat-based OSes..." BootstrapRpmCommon From 96dd662e558da73d178dd4fef0f14a5f1dc67975 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 8 Jun 2016 14:35:59 -0700 Subject: [PATCH 37/72] Delint certbot-compatibility-test --- .../certbot_compatibility_test/configurators/common.py | 1 - certbot-compatibility-test/certbot_compatibility_test/util.py | 2 -- 2 files changed, 3 deletions(-) diff --git a/certbot-compatibility-test/certbot_compatibility_test/configurators/common.py b/certbot-compatibility-test/certbot_compatibility_test/configurators/common.py index 4592eca39..03128cc86 100644 --- a/certbot-compatibility-test/certbot_compatibility_test/configurators/common.py +++ b/certbot-compatibility-test/certbot_compatibility_test/configurators/common.py @@ -5,7 +5,6 @@ import shutil import tempfile from certbot import constants -from certbot_compatibility_test import errors from certbot_compatibility_test import util diff --git a/certbot-compatibility-test/certbot_compatibility_test/util.py b/certbot-compatibility-test/certbot_compatibility_test/util.py index 570bf1a9e..af951aa6a 100644 --- a/certbot-compatibility-test/certbot_compatibility_test/util.py +++ b/certbot-compatibility-test/certbot_compatibility_test/util.py @@ -1,11 +1,9 @@ """Utility functions for Certbot plugin tests.""" import argparse import copy -import contextlib import os import re import shutil -import socket import tarfile from acme import jose From a0be028340acf1de55426a48ee4e89994f5a4166 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 8 Jun 2016 16:49:08 -0700 Subject: [PATCH 38/72] Add _get_names_from_cert_or_req --- certbot/crypto_util.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/certbot/crypto_util.py b/certbot/crypto_util.py index 6b1b8426c..8640fec1e 100644 --- a/certbot/crypto_util.py +++ b/certbot/crypto_util.py @@ -296,6 +296,18 @@ def get_sans_from_csr(csr, typ=OpenSSL.crypto.FILETYPE_PEM): csr, OpenSSL.crypto.load_certificate_request, typ) +def _get_names_from_cert_or_req(cert_or_req, load_func, typ): + loaded_cert_or_req = _load_cert_or_req(cert_or_req, load_func, typ) + subject = loaded_cert_or_req.get_subject().CN + # pylint: disable=protected-access + sans = acme_crypto_util._pyopenssl_cert_or_req_san(loaded_cert_or_req) + + if subject is None: + return sans + else: + return [subject] + [d for d in sans if d != subject] + + def get_names_from_csr(csr, typ=OpenSSL.crypto.FILETYPE_PEM): """Get a list of domains from a CSR, including the CN if it is set. From ac581951b3926c590ce930230a315d31e91ed0b2 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 8 Jun 2016 16:50:34 -0700 Subject: [PATCH 39/72] Have get_names_from_csr use _get_names_from_cert_or_req --- certbot/crypto_util.py | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/certbot/crypto_util.py b/certbot/crypto_util.py index 8640fec1e..e8047f086 100644 --- a/certbot/crypto_util.py +++ b/certbot/crypto_util.py @@ -318,13 +318,8 @@ def get_names_from_csr(csr, typ=OpenSSL.crypto.FILETYPE_PEM): :rtype: list """ - loaded_csr = _load_cert_or_req( + return _get_names_from_cert_or_req( csr, OpenSSL.crypto.load_certificate_request, typ) - # Use a set to avoid duplication with CN and Subject Alt Names - domains = set(d for d in (loaded_csr.get_subject().CN,) if d is not None) - # pylint: disable=protected-access - domains.update(acme_crypto_util._pyopenssl_cert_or_req_san(loaded_csr)) - return list(domains) def dump_pyopenssl_chain(chain, filetype=OpenSSL.crypto.FILETYPE_PEM): From 753aea2f3f495eccb3f50cf977c3864dc56a55b6 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 8 Jun 2016 16:53:04 -0700 Subject: [PATCH 40/72] Add get_names_from_cert function --- certbot/crypto_util.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/certbot/crypto_util.py b/certbot/crypto_util.py index e8047f086..f45645de1 100644 --- a/certbot/crypto_util.py +++ b/certbot/crypto_util.py @@ -308,6 +308,20 @@ def _get_names_from_cert_or_req(cert_or_req, load_func, typ): return [subject] + [d for d in sans if d != subject] +def get_names_from_cert(csr, typ=OpenSSL.crypto.FILETYPE_PEM): + """Get a list of domains from a cert, including the CN if it is set. + + :param str cert: Certificate (encoded). + :param typ: `OpenSSL.crypto.FILETYPE_PEM` or `OpenSSL.crypto.FILETYPE_ASN1` + + :returns: A list of domain names. + :rtype: list + + """ + return _get_names_from_cert_or_req( + csr, OpenSSL.crypto.load_certificate, typ) + + def get_names_from_csr(csr, typ=OpenSSL.crypto.FILETYPE_PEM): """Get a list of domains from a CSR, including the CN if it is set. From 8db1b5627c02d4a02890075e1a3ca6f9a3a29d96 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 8 Jun 2016 16:57:56 -0700 Subject: [PATCH 41/72] Add GetNamesFromCertTest --- certbot/tests/crypto_util_test.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/certbot/tests/crypto_util_test.py b/certbot/tests/crypto_util_test.py index fa88e89e7..742d4ec8c 100644 --- a/certbot/tests/crypto_util_test.py +++ b/certbot/tests/crypto_util_test.py @@ -273,6 +273,25 @@ class GetSANsFromCSRTest(unittest.TestCase): [], self._call(test_util.load_vector('csr-nosans.pem'))) +class GetNamesFromCertTest(unittest.TestCase): + """Tests for certbot.crypto_util.get_names_from_cert.""" + + @classmethod + def _call(cls, *args, **kwargs): + from certbot.crypto_util import get_names_from_cert + return get_names_from_cert(*args, **kwargs) + + def test_single(self): + self.assertEqual( + ['example.com'], + self._call(test_util.load_vector('cert.pem'))) + + def test_san(self): + self.assertEqual( + ['example.com', 'www.example.com'], + self._call(test_util.load_vector('cert-san.pem'))) + + class GetNamesFromCSRTest(unittest.TestCase): """Tests for certbot.crypto_util.get_names_from_csr.""" @classmethod From 0a707b64ec0b9a0ee61fe56fc6bcf4b1b9525318 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 8 Jun 2016 16:59:44 -0700 Subject: [PATCH 42/72] Use common_name instead of subject --- certbot/crypto_util.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/certbot/crypto_util.py b/certbot/crypto_util.py index f45645de1..1e831dd8f 100644 --- a/certbot/crypto_util.py +++ b/certbot/crypto_util.py @@ -298,14 +298,14 @@ def get_sans_from_csr(csr, typ=OpenSSL.crypto.FILETYPE_PEM): def _get_names_from_cert_or_req(cert_or_req, load_func, typ): loaded_cert_or_req = _load_cert_or_req(cert_or_req, load_func, typ) - subject = loaded_cert_or_req.get_subject().CN + common_name = loaded_cert_or_req.get_subject().CN # pylint: disable=protected-access sans = acme_crypto_util._pyopenssl_cert_or_req_san(loaded_cert_or_req) - if subject is None: + if common_name is None: return sans else: - return [subject] + [d for d in sans if d != subject] + return [common_name] + [d for d in sans if d != common_name] def get_names_from_cert(csr, typ=OpenSSL.crypto.FILETYPE_PEM): From 2c803eff6ab161079128dca16f8efd8154049ac1 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 8 Jun 2016 17:01:54 -0700 Subject: [PATCH 43/72] Use get_names_from_cert in storage.py --- certbot/storage.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot/storage.py b/certbot/storage.py index b0c8245d3..60886e306 100644 --- a/certbot/storage.py +++ b/certbot/storage.py @@ -616,7 +616,7 @@ class RenewableCert(object): # pylint: disable=too-many-instance-attributes if target is None: raise errors.CertStorageError("could not find cert file") with open(target) as f: - return crypto_util.get_sans_from_cert(f.read()) + return crypto_util.get_names_from_cert(f.read()) def autodeployment_is_enabled(self): """Is automatic deployment enabled for this cert? From afd899886d255f4c15e89ab7940a561083a3d2c1 Mon Sep 17 00:00:00 2001 From: Willem Fibbe Date: Wed, 8 Jun 2016 16:26:56 +0200 Subject: [PATCH 44/72] Prevent bootstrap-issue on Debian systems with virtualenv package On Debian 7 (and probably relative distro's) `aptitude show virtualenv` exits with 0, since it is a virtual package. However, it doesn't have any installation candidates, so filter on this case before trying to install `virtualenv` to prevent installation-errors while bootstrapping. NB, to make this clear: (0)#: apt-cache show virtualenv N: Can't select versions from package 'virtualenv' as it is purely virtual N: No packages found (0)#: echo $? 0 Furthermore, --quiet=0 is necessary, to be able to grep through `apt-cache`'s output via a pipe. More details on http://unix.stackexchange.com/questions/201869/why-isnt-apt-cache-policy-output-piped/202041#202041. --- letsencrypt-auto-source/letsencrypt-auto | 2 +- letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 1992c9d47..3ed48216d 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -172,7 +172,7 @@ BootstrapDebCommon() { # distro version (#346) virtualenv= - if apt-cache show virtualenv > /dev/null 2>&1; then + if apt-cache show virtualenv > /dev/null 2>&1 && ! apt-cache --quiet=0 show virtualenv 2>&1 | grep -q 'No packages found'; then virtualenv="virtualenv" fi diff --git a/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh b/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh index bfbcfa31d..8eb7e16ee 100644 --- a/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh +++ b/letsencrypt-auto-source/pieces/bootstrappers/deb_common.sh @@ -23,7 +23,7 @@ BootstrapDebCommon() { # distro version (#346) virtualenv= - if apt-cache show virtualenv > /dev/null 2>&1; then + if apt-cache show virtualenv > /dev/null 2>&1 && ! apt-cache --quiet=0 show virtualenv 2>&1 | grep -q 'No packages found'; then virtualenv="virtualenv" fi From 02cdb5db0ef2e035a19b86ca0b462a0a38e50694 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 9 Jun 2016 16:03:32 -0700 Subject: [PATCH 45/72] Add cert with not alphabetically first CN --- certbot/tests/testdata/cert-5sans.pem | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 certbot/tests/testdata/cert-5sans.pem diff --git a/certbot/tests/testdata/cert-5sans.pem b/certbot/tests/testdata/cert-5sans.pem new file mode 100644 index 000000000..5de7cc6cb --- /dev/null +++ b/certbot/tests/testdata/cert-5sans.pem @@ -0,0 +1,16 @@ +-----BEGIN CERTIFICATE----- +MIICkTCCAjugAwIBAgIJAJNbfABWQ8bbMA0GCSqGSIb3DQEBCwUAMHkxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNp +c2NvMScwJQYDVQQKDB5FbGVjdHJvbmljIEZyb250aWVyIEZvdW5kYXRpb24xFDAS +BgNVBAMMC2V4YW1wbGUuY29tMB4XDTE2MDYwOTIzMDEzNloXDTE2MDcwOTIzMDEz +NloweTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcM +DVNhbiBGcmFuY2lzY28xJzAlBgNVBAoMHkVsZWN0cm9uaWMgRnJvbnRpZXIgRm91 +bmRhdGlvbjEUMBIGA1UEAwwLZXhhbXBsZS5jb20wXDANBgkqhkiG9w0BAQEFAANL +ADBIAkEArHVztFHtH92ucFJD/N/HW9AsdRsUuHUBBBDlHwNlRd3fp580rv2+6QWE +30cWgdmJS86ObRz6lUTor4R0T+3C5QIDAQABo4GlMIGiMB0GA1UdDgQWBBQmz8jt +S9eUsuQlA1gkjwTAdNWXijAfBgNVHSMEGDAWgBQmz8jtS9eUsuQlA1gkjwTAdNWX +ijAMBgNVHRMEBTADAQH/MFIGA1UdEQRLMEmCDWEuZXhhbXBsZS5jb22CDWIuZXhh +bXBsZS5jb22CDWMuZXhhbXBsZS5jb22CDWQuZXhhbXBsZS5jb22CC2V4YW1wbGUu +Y29tMA0GCSqGSIb3DQEBCwUAA0EAVXmZxB+IJdgFvY2InOYeytTD1QmouDZRtj/T +H/HIpSdsfO7qr4d/ZprI2IhLRxp2S4BiU5Qc5HUkeADcpNd06A== +-----END CERTIFICATE----- From 4f99cc7b2a2f1eb4eb1820e75d909551eea2d1c7 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 9 Jun 2016 17:43:05 -0700 Subject: [PATCH 46/72] Add _write_out_kind method --- certbot/tests/storage_test.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/certbot/tests/storage_test.py b/certbot/tests/storage_test.py index 0c88d3d55..0579c9f1c 100644 --- a/certbot/tests/storage_test.py +++ b/certbot/tests/storage_test.py @@ -84,6 +84,16 @@ class BaseRenewableCertTest(unittest.TestCase): def tearDown(self): shutil.rmtree(self.tempdir) + def _write_out_kind(self, kind, ver, value=None): + link = getattr(self.test_rc, kind) + if os.path.lexists(link): + os.unlink(link) + os.symlink(os.path.join(os.path.pardir, os.path.pardir, "archive", + "example.org", "{0}{1}.pem".format(kind, ver)), + link) + with open(link, "w") as f: + f.write(kind if value is None else value) + def _write_out_ex_kinds(self): for kind in ALL_FOUR: where = getattr(self.test_rc, kind) From 562802bfd0443f14cd928ee41a4ae73b9453ce39 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 9 Jun 2016 17:44:33 -0700 Subject: [PATCH 47/72] Refactor common symlink writing code --- certbot/tests/storage_test.py | 124 ++++++---------------------------- 1 file changed, 19 insertions(+), 105 deletions(-) diff --git a/certbot/tests/storage_test.py b/certbot/tests/storage_test.py index 0579c9f1c..44b881fd9 100644 --- a/certbot/tests/storage_test.py +++ b/certbot/tests/storage_test.py @@ -96,16 +96,8 @@ class BaseRenewableCertTest(unittest.TestCase): def _write_out_ex_kinds(self): for kind in ALL_FOUR: - where = getattr(self.test_rc, kind) - os.symlink(os.path.join("..", "..", "archive", "example.org", - "{0}12.pem".format(kind)), where) - with open(where, "w") as f: - f.write(kind) - os.unlink(where) - os.symlink(os.path.join("..", "..", "archive", "example.org", - "{0}11.pem".format(kind)), where) - with open(where, "w") as f: - f.write(kind) + self._write_out_kind(kind, 12) + self._write_out_kind(kind, 11) class RenewableCertTests(BaseRenewableCertTest): @@ -214,10 +206,7 @@ class RenewableCertTests(BaseRenewableCertTest): def test_current_target(self): # Relative path logic - os.symlink(os.path.join("..", "..", "archive", "example.org", - "cert17.pem"), self.test_rc.cert) - with open(self.test_rc.cert, "w") as f: - f.write("cert") + self._write_out_kind("cert", 17) self.assertTrue(os.path.samefile(self.test_rc.current_target("cert"), os.path.join(self.tempdir, "archive", "example.org", @@ -235,12 +224,8 @@ class RenewableCertTests(BaseRenewableCertTest): def test_current_version(self): for ver in (1, 5, 10, 20): - os.symlink(os.path.join("..", "..", "archive", "example.org", - "cert{0}.pem".format(ver)), - self.test_rc.cert) - with open(self.test_rc.cert, "w") as f: - f.write("cert") - os.unlink(self.test_rc.cert) + self._write_out_kind("cert", ver) + os.unlink(self.test_rc.cert) os.symlink(os.path.join("..", "..", "archive", "example.org", "cert10.pem"), self.test_rc.cert) self.assertEqual(self.test_rc.current_version("cert"), 10) @@ -251,61 +236,30 @@ class RenewableCertTests(BaseRenewableCertTest): def test_latest_and_next_versions(self): for ver in xrange(1, 6): for kind in ALL_FOUR: - where = getattr(self.test_rc, kind) - if os.path.islink(where): - os.unlink(where) - os.symlink(os.path.join("..", "..", "archive", "example.org", - "{0}{1}.pem".format(kind, ver)), where) - with open(where, "w") as f: - f.write(kind) + self._write_out_kind(kind, ver) self.assertEqual(self.test_rc.latest_common_version(), 5) self.assertEqual(self.test_rc.next_free_version(), 6) # Having one kind of file of a later version doesn't change the # result - os.unlink(self.test_rc.privkey) - os.symlink(os.path.join("..", "..", "archive", "example.org", - "privkey7.pem"), self.test_rc.privkey) - with open(self.test_rc.privkey, "w") as f: - f.write("privkey") + self._write_out_kind("privkey", 7) self.assertEqual(self.test_rc.latest_common_version(), 5) # ... although it does change the next free version self.assertEqual(self.test_rc.next_free_version(), 8) # Nor does having three out of four change the result - os.unlink(self.test_rc.cert) - os.symlink(os.path.join("..", "..", "archive", "example.org", - "cert7.pem"), self.test_rc.cert) - with open(self.test_rc.cert, "w") as f: - f.write("cert") - os.unlink(self.test_rc.fullchain) - os.symlink(os.path.join("..", "..", "archive", "example.org", - "fullchain7.pem"), self.test_rc.fullchain) - with open(self.test_rc.fullchain, "w") as f: - f.write("fullchain") + self._write_out_kind("cert", 7) + self._write_out_kind("fullchain", 7) self.assertEqual(self.test_rc.latest_common_version(), 5) # If we have everything from a much later version, it does change # the result - ver = 17 for kind in ALL_FOUR: - where = getattr(self.test_rc, kind) - if os.path.islink(where): - os.unlink(where) - os.symlink(os.path.join("..", "..", "archive", "example.org", - "{0}{1}.pem".format(kind, ver)), where) - with open(where, "w") as f: - f.write(kind) + self._write_out_kind(kind, 17) self.assertEqual(self.test_rc.latest_common_version(), 17) self.assertEqual(self.test_rc.next_free_version(), 18) def test_update_link_to(self): for ver in xrange(1, 6): for kind in ALL_FOUR: - where = getattr(self.test_rc, kind) - if os.path.islink(where): - os.unlink(where) - os.symlink(os.path.join("..", "..", "archive", "example.org", - "{0}{1}.pem".format(kind, ver)), where) - with open(where, "w") as f: - f.write(kind) + self._write_out_kind(kind, ver) self.assertEqual(ver, self.test_rc.current_version(kind)) # pylint: disable=protected-access self.test_rc._update_link_to("cert", 3) @@ -322,10 +276,7 @@ class RenewableCertTests(BaseRenewableCertTest): "chain3000.pem") def test_version(self): - os.symlink(os.path.join("..", "..", "archive", "example.org", - "cert12.pem"), self.test_rc.cert) - with open(self.test_rc.cert, "w") as f: - f.write("cert") + self._write_out_kind("cert", 12) # TODO: We should probably test that the directory is still the # same, but it's tricky because we can get an absolute # path out when we put a relative path in. @@ -335,13 +286,7 @@ class RenewableCertTests(BaseRenewableCertTest): def test_update_all_links_to_success(self): for ver in xrange(1, 6): for kind in ALL_FOUR: - where = getattr(self.test_rc, kind) - if os.path.islink(where): - os.unlink(where) - os.symlink(os.path.join("..", "..", "archive", "example.org", - "{0}{1}.pem".format(kind, ver)), where) - with open(where, "w") as f: - f.write(kind) + self._write_out_kind(kind, ver) self.assertEqual(ver, self.test_rc.current_version(kind)) self.assertEqual(self.test_rc.latest_common_version(), 5) for ver in xrange(1, 6): @@ -386,13 +331,7 @@ class RenewableCertTests(BaseRenewableCertTest): def test_has_pending_deployment(self): for ver in xrange(1, 6): for kind in ALL_FOUR: - where = getattr(self.test_rc, kind) - if os.path.islink(where): - os.unlink(where) - os.symlink(os.path.join("..", "..", "archive", "example.org", - "{0}{1}.pem".format(kind, ver)), where) - with open(where, "w") as f: - f.write(kind) + self._write_out_kind(kind, ver) self.assertEqual(ver, self.test_rc.current_version(kind)) for ver in xrange(1, 6): self.test_rc.update_all_links_to(ver) @@ -405,21 +344,12 @@ class RenewableCertTests(BaseRenewableCertTest): def test_names(self): # Trying the current version - test_cert = test_util.load_vector("cert-san.pem") - os.symlink(os.path.join("..", "..", "archive", "example.org", - "cert12.pem"), self.test_rc.cert) - with open(self.test_rc.cert, "w") as f: - f.write(test_cert) + self._write_out_kind("cert", 12, test_util.load_vector("cert-san.pem")) self.assertEqual(self.test_rc.names(), ["example.com", "www.example.com"]) # Trying a non-current version - test_cert = test_util.load_vector("cert.pem") - os.unlink(self.test_rc.cert) - os.symlink(os.path.join("..", "..", "archive", "example.org", - "cert15.pem"), self.test_rc.cert) - with open(self.test_rc.cert, "w") as f: - f.write(test_cert) + self._write_out_kind("cert", 15, test_util.load_vector("cert.pem")) self.assertEqual(self.test_rc.names(12), ["example.com", "www.example.com"]) @@ -490,13 +420,7 @@ class RenewableCertTests(BaseRenewableCertTest): # No pending deployment for ver in xrange(1, 6): for kind in ALL_FOUR: - where = getattr(self.test_rc, kind) - if os.path.islink(where): - os.unlink(where) - os.symlink(os.path.join("..", "..", "archive", "example.org", - "{0}{1}.pem".format(kind, ver)), where) - with open(where, "w") as f: - f.write(kind) + self._write_out_kind(kind, ver) self.assertFalse(self.test_rc.should_autodeploy()) def test_autorenewal_is_enabled(self): @@ -517,11 +441,7 @@ class RenewableCertTests(BaseRenewableCertTest): self.assertFalse(self.test_rc.should_autorenew()) self.test_rc.configuration["autorenew"] = "1" for kind in ALL_FOUR: - where = getattr(self.test_rc, kind) - os.symlink(os.path.join("..", "..", "archive", "example.org", - "{0}12.pem".format(kind)), where) - with open(where, "w") as f: - f.write(kind) + self._write_out_kind(kind, 12) # Mandatory renewal on the basis of OCSP revocation mock_ocsp.return_value = True self.assertTrue(self.test_rc.should_autorenew()) @@ -535,13 +455,7 @@ class RenewableCertTests(BaseRenewableCertTest): for ver in xrange(1, 6): for kind in ALL_FOUR: - where = getattr(self.test_rc, kind) - if os.path.islink(where): - os.unlink(where) - os.symlink(os.path.join("..", "..", "archive", "example.org", - "{0}{1}.pem".format(kind, ver)), where) - with open(where, "w") as f: - f.write(kind) + self._write_out_kind(kind, ver) self.test_rc.update_all_links_to(3) self.assertEqual( 6, self.test_rc.save_successor(3, "new cert", None, From bb1d2c0a1faf7d58249e73fdbd6ea832335755b3 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 9 Jun 2016 17:49:44 -0700 Subject: [PATCH 48/72] Test common name is listed first in storage.py --- certbot/tests/storage_test.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/certbot/tests/storage_test.py b/certbot/tests/storage_test.py index 44b881fd9..0d907eca3 100644 --- a/certbot/tests/storage_test.py +++ b/certbot/tests/storage_test.py @@ -353,6 +353,13 @@ class RenewableCertTests(BaseRenewableCertTest): self.assertEqual(self.test_rc.names(12), ["example.com", "www.example.com"]) + # Testing common name is listed first + self._write_out_kind( + "cert", 12, test_util.load_vector("cert-5sans.pem")) + self.assertEqual( + self.test_rc.names(12), + ["example.com"] + ["{0}.example.com".format(c) for c in "abcd"]) + # Trying missing cert os.unlink(self.test_rc.cert) self.assertRaises(errors.CertStorageError, self.test_rc.names) From 07cf34284eabf129ce0fae76d79939d38a8bbcdb Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 9 Jun 2016 17:55:46 -0700 Subject: [PATCH 49/72] Add test_common_name_sans_order --- certbot/tests/crypto_util_test.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/certbot/tests/crypto_util_test.py b/certbot/tests/crypto_util_test.py index 742d4ec8c..5a592bbb1 100644 --- a/certbot/tests/crypto_util_test.py +++ b/certbot/tests/crypto_util_test.py @@ -291,6 +291,13 @@ class GetNamesFromCertTest(unittest.TestCase): ['example.com', 'www.example.com'], self._call(test_util.load_vector('cert-san.pem'))) + def test_common_name_sans_order(self): + # Tests that the common name comes first + # followed by the SANS in alphabetical order + self.assertEqual( + ['example.com'] + ['{0}.example.com'.format(c) for c in 'abcd'], + self._call(test_util.load_vector('cert-5sans.pem'))) + class GetNamesFromCSRTest(unittest.TestCase): """Tests for certbot.crypto_util.get_names_from_csr.""" From 6a53522a6cbda3819bba0fd93072c50ef8095869 Mon Sep 17 00:00:00 2001 From: Sergey Nuzdhin Date: Mon, 13 Jun 2016 14:43:47 +0200 Subject: [PATCH 50/72] Add additional warning with actual exception message during renewal Log and show warning with real exception message to make it more clear what exactly happened. Currently we show `config is broken` when in fact we have broken symlinks in live folder. --- certbot/renewal.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/certbot/renewal.py b/certbot/renewal.py index d04e2d27c..95f64b94d 100644 --- a/certbot/renewal.py +++ b/certbot/renewal.py @@ -60,7 +60,8 @@ def _reconstitute(config, full_path): try: renewal_candidate = storage.RenewableCert( full_path, configuration.RenewerConfiguration(config)) - except (errors.CertStorageError, IOError): + except (errors.CertStorageError, IOError) as exc: + logger.warning(exc) logger.warning("Renewal configuration file %s is broken. Skipping.", full_path) logger.debug("Traceback was:\n%s", traceback.format_exc()) return None From f8a07a8f4673d0771c6dae034bb755b10ddb8c15 Mon Sep 17 00:00:00 2001 From: Jacob Hoffman-Andrews Date: Mon, 13 Jun 2016 11:53:32 -0700 Subject: [PATCH 51/72] Provide nonroot guidance when logging gets EACCES. --- certbot/main.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/certbot/main.py b/certbot/main.py index fa14bbf99..f68373998 100644 --- a/certbot/main.py +++ b/certbot/main.py @@ -1,6 +1,7 @@ """Certbot main entry point.""" from __future__ import print_function import atexit +import errno import functools import logging.handlers import os @@ -588,8 +589,16 @@ def renew(config, unused_plugins): def setup_log_file_handler(config, logfile, fmt): """Setup file debug logging.""" log_file_path = os.path.join(config.logs_dir, logfile) - handler = logging.handlers.RotatingFileHandler( - log_file_path, maxBytes=2 ** 20, backupCount=10) + try: + handler = logging.handlers.RotatingFileHandler( + log_file_path, maxBytes=2 ** 20, backupCount=10) + except IOError as e: + if e.errno == errno.EACCES: + msg = ("Access denied writing to {0}. To run as non-root, set " + + "--logs-dir, --config-dir, --work-dir to writable paths.") + raise errors.Error(msg.format(log_file_path)) + else: + raise # rotate on each invocation, rollover only possible when maxBytes # is nonzero and backupCount is nonzero, so we set maxBytes as big # as possible not to overrun in single CLI invocation (1MB). From c60c28514c6a8dde2f94c5d557cce7649b67a344 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 13 Jun 2016 13:49:32 -0700 Subject: [PATCH 52/72] Add global DEFAULT variable --- certbot/cli.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/certbot/cli.py b/certbot/cli.py index cff111f42..e2475ec31 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -104,6 +104,11 @@ ZERO_ARG_ACTIONS = set(("store_const", "store_true", "store_false", "append_const", "count",)) +# Maps a config option to its default value. This is set during the +# parse_args method of HelpfulArgumentParser. +DEFAULTS = None + + # Maps a config option to a set of config options that may have modified it. # This dictionary is used recursively, so if A modifies B and B modifies C, # it is determined that C was modified by the user if A was modified. From 657c4e725992abba9e2c80a9cd7598d97b79b910 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 13 Jun 2016 14:49:24 -0700 Subject: [PATCH 53/72] Set DEFAULTS during parse_args --- certbot/cli.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/certbot/cli.py b/certbot/cli.py index e2475ec31..3c65527e1 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -1,6 +1,7 @@ """Certbot command line argument & config processing.""" from __future__ import print_function import argparse +import copy import glob import logging import logging.handlers @@ -340,6 +341,10 @@ class HelpfulArgumentParser(object): if self.detect_defaults: return parsed_args + global DEFAULTS # pylint: disable=global-statement + DEFAULTS = dict((key, copy.deepcopy(self.parser.get_default(key))) + for key in vars(parsed_args)) + # Do any post-parsing homework here if self.verb == "renew" and not parsed_args.dialog_mode: From b57677b16a994d21659ea2eed7557c9a583712d1 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 13 Jun 2016 14:57:14 -0700 Subject: [PATCH 54/72] Use cli.DEFAULTS in storage.py --- certbot/storage.py | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/certbot/storage.py b/certbot/storage.py index 60886e306..7602ece2d 100644 --- a/certbot/storage.py +++ b/certbot/storage.py @@ -162,30 +162,16 @@ def relevant_values(all_values): from certbot import cli - def _is_cli_default(option, value): - # Look through the CLI parser defaults and see if this option is - # both present and equal to the specified value. If not, return - # False. - # pylint: disable=protected-access - for x in cli.helpful_parser.parser._actions: - if x.dest == option: - if x.default == value: - return True - else: - break - return False - values = dict() for option, value in all_values.iteritems(): # Try to find reasons to store this item in the # renewal config. It can be stored if it is relevant and - # (it is set_by_cli() or flag_default() is different - # from the value or flag_default() doesn't exist). + # (it is set_by_cli(), we don't know the default value, or + # the current value differs from the default value). if _relevant(option): - if (cli.set_by_cli(option) - or not _is_cli_default(option, value)): -# or option not in constants.CLI_DEFAULTS -# or constants.CLI_DEFAULTS[option] != value): + if (cli.set_by_cli(option) or + option not in cli.DEFAULTS or + cli.DEFAULTS[option] != value): values[option] = value return values From 26316fb222cb3cf180810bbf8cdea85e8ddeaf95 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 13 Jun 2016 15:06:49 -0700 Subject: [PATCH 55/72] Ensure changes to webroot_map aren't reflected in cli.DEFAULTS --- certbot/tests/cli_test.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/certbot/tests/cli_test.py b/certbot/tests/cli_test.py index f9557abfb..03edaa18f 100644 --- a/certbot/tests/cli_test.py +++ b/certbot/tests/cli_test.py @@ -490,6 +490,12 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods conflicts += ['--staging'] self._check_server_conflict_message(short_args, conflicts) + def test_defaults_global(self): + namespace = self._get_argument_parser()([]) + namespace.webroot_map['example.com'] = '/var/www/html' + + self.assertTrue(cli.DEFAULTS != namespace.webroot_map) + def _certonly_new_request_common(self, mock_client, args=None): with mock.patch('certbot.main._treat_as_renewal') as mock_renewal: mock_renewal.return_value = ("newcert", None) From 8f6866309781f656725c0ef9d6e89a7b291f4aed Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 13 Jun 2016 16:52:35 -0700 Subject: [PATCH 56/72] Add option_was_set function --- certbot/cli.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/certbot/cli.py b/certbot/cli.py index 3c65527e1..428227657 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -217,6 +217,21 @@ def set_by_cli(var): set_by_cli.detector = None +def option_was_set(option, value): + """Was option set by the user or does it differ from the default? + + :param str option: configuration variable being considered + :param value: value of the configuration variable named option + + :returns: True if the option was set, otherwise, False + :rtype: bool + + """ + return (set_by_cli(option) or + option not in DEFAULTS or + DEFAULTS[option] != value) + + def argparse_type(variable): "Return our argparse type function for a config variable (default: str)" # pylint: disable=protected-access From aaf93b65b0b1b08bec02e84ea92145d3f15e7081 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 13 Jun 2016 16:55:45 -0700 Subject: [PATCH 57/72] Refactor storage.relevant_values --- certbot/storage.py | 23 ++++++++--------------- 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/certbot/storage.py b/certbot/storage.py index 7602ece2d..82fdbfd54 100644 --- a/certbot/storage.py +++ b/certbot/storage.py @@ -7,8 +7,10 @@ import re import configobj import parsedatetime import pytz +import six import certbot +from certbot import cli from certbot import constants from certbot import crypto_util from certbot import errors @@ -158,22 +160,13 @@ def relevant_values(all_values): :param dict all_values: The original values. :returns: A new dictionary containing items that can be used in renewal. - :rtype dict:""" + :rtype dict: - from certbot import cli - - values = dict() - for option, value in all_values.iteritems(): - # Try to find reasons to store this item in the - # renewal config. It can be stored if it is relevant and - # (it is set_by_cli(), we don't know the default value, or - # the current value differs from the default value). - if _relevant(option): - if (cli.set_by_cli(option) or - option not in cli.DEFAULTS or - cli.DEFAULTS[option] != value): - values[option] = value - return values + """ + return dict( + (option, value) + for option, value in six.iteritems(all_values) + if _relevant(option) and cli.option_was_set(option, value)) class RenewableCert(object): # pylint: disable=too-many-instance-attributes From 8c174f38b5e59ecf2298abf08a84c52110cc4091 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 13 Jun 2016 17:00:59 -0700 Subject: [PATCH 58/72] Add has_default_value method --- certbot/cli.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/certbot/cli.py b/certbot/cli.py index 428227657..3c18c3c98 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -217,6 +217,21 @@ def set_by_cli(var): set_by_cli.detector = None +def has_default_value(option, value): + """Does option have the default value? + + If the default value of option is not known, False is returned. + + :param str option: configuration variable being considered + :param value: value of the configuration variable named option + + :returns: True if option has the default value, otherwise, False + :rtype: bool + + """ + return option in DEFAULTS and DEFAULTS[option] == value + + def option_was_set(option, value): """Was option set by the user or does it differ from the default? @@ -227,9 +242,7 @@ def option_was_set(option, value): :rtype: bool """ - return (set_by_cli(option) or - option not in DEFAULTS or - DEFAULTS[option] != value) + return set_by_cli(option) or not has_default_value(option, value) def argparse_type(variable): From 4c68792dd37cc93e17038eba7cd8bee94cdcc6c1 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 13 Jun 2016 17:29:56 -0700 Subject: [PATCH 59/72] Remove test_defaults_global --- certbot/tests/cli_test.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/certbot/tests/cli_test.py b/certbot/tests/cli_test.py index 03edaa18f..f9557abfb 100644 --- a/certbot/tests/cli_test.py +++ b/certbot/tests/cli_test.py @@ -490,12 +490,6 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods conflicts += ['--staging'] self._check_server_conflict_message(short_args, conflicts) - def test_defaults_global(self): - namespace = self._get_argument_parser()([]) - namespace.webroot_map['example.com'] = '/var/www/html' - - self.assertTrue(cli.DEFAULTS != namespace.webroot_map) - def _certonly_new_request_common(self, mock_client, args=None): with mock.patch('certbot.main._treat_as_renewal') as mock_renewal: mock_renewal.return_value = ("newcert", None) From 97af8dfb701edece39ae429852ac1a9784f991e2 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 13 Jun 2016 17:31:57 -0700 Subject: [PATCH 60/72] Add defaults to helpful_parser --- certbot/cli.py | 14 +++++--------- certbot/tests/storage_test.py | 5 ++--- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/certbot/cli.py b/certbot/cli.py index 3c18c3c98..ba1f23708 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -105,11 +105,6 @@ ZERO_ARG_ACTIONS = set(("store_const", "store_true", "store_false", "append_const", "count",)) -# Maps a config option to its default value. This is set during the -# parse_args method of HelpfulArgumentParser. -DEFAULTS = None - - # Maps a config option to a set of config options that may have modified it. # This dictionary is used recursively, so if A modifies B and B modifies C, # it is determined that C was modified by the user if A was modified. @@ -229,7 +224,8 @@ def has_default_value(option, value): :rtype: bool """ - return option in DEFAULTS and DEFAULTS[option] == value + return (option in helpful_parser.defaults and + helpful_parser.defaults[option] == value) def option_was_set(option, value): @@ -354,6 +350,7 @@ class HelpfulArgumentParser(object): sys.exit(0) self.visible_topics = self.determine_help_topics(self.help_arg) self.groups = {} # elements are added by .add_group() + self.defaults = {} # elements are added by .parse_args() def parse_args(self): """Parses command line arguments and returns the result. @@ -369,9 +366,8 @@ class HelpfulArgumentParser(object): if self.detect_defaults: return parsed_args - global DEFAULTS # pylint: disable=global-statement - DEFAULTS = dict((key, copy.deepcopy(self.parser.get_default(key))) - for key in vars(parsed_args)) + self.defaults = dict((key, copy.deepcopy(self.parser.get_default(key))) + for key in vars(parsed_args)) # Do any post-parsing homework here diff --git a/certbot/tests/storage_test.py b/certbot/tests/storage_test.py index 0d907eca3..138f6e2fa 100644 --- a/certbot/tests/storage_test.py +++ b/certbot/tests/storage_test.py @@ -533,10 +533,9 @@ class RenewableCertTests(BaseRenewableCertTest): """Test that relevant_values() can reject a default value.""" # pylint: disable=protected-access from certbot import storage - mock_parser.verb = "certonly" mock_parser.args = ["--standalone"] - mock_action = mock.Mock(dest="rsa_key_size", default=2048) - mock_parser.parser._actions = [mock_action] + mock_parser.defaults = {"rsa_key_size": 2048} + mock_parser.verb = "certonly" self.assertEqual(storage.relevant_values({"rsa_key_size": 2048}), {}) @mock.patch("certbot.cli.helpful_parser") From f9d5ecaf6fc6776988ddf5ea9dbb010ad45eeb7f Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Mon, 13 Jun 2016 17:45:47 -0700 Subject: [PATCH 61/72] Add option_was_set test --- certbot/tests/cli_test.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/certbot/tests/cli_test.py b/certbot/tests/cli_test.py index f9557abfb..9d6335b40 100644 --- a/certbot/tests/cli_test.py +++ b/certbot/tests/cli_test.py @@ -447,6 +447,19 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods short_args += '--server example.com'.split() self._check_server_conflict_message(short_args, '--staging') + def test_option_was_set(self): + key_size_option = 'rsa_key_size' + key_size_value = cli.flag_default(key_size_option) + self._get_argument_parser()( + '--rsa-key-size {0}'.format(key_size_value).split()) + + self.assertTrue(cli.option_was_set(key_size_option, key_size_value)) + self.assertTrue(cli.option_was_set('no_verify_ssl', True)) + + config_dir_option = 'config_dir' + self.assertFalse(cli.option_was_set( + config_dir_option, cli.flag_default(config_dir_option))) + def _assert_dry_run_flag_worked(self, namespace, existing_account): self.assertTrue(namespace.dry_run) self.assertTrue(namespace.break_my_certs) From 61b77766c26233745b922ef8777e6694c49ba053 Mon Sep 17 00:00:00 2001 From: Ben Irving Date: Tue, 14 Jun 2016 11:28:29 -0700 Subject: [PATCH 62/72] Add integration test cases for must staple and ECDSA (#3158) --- tests/boulder-integration.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/boulder-integration.sh b/tests/boulder-integration.sh index 323ea004b..ab8fde5f6 100755 --- a/tests/boulder-integration.sh +++ b/tests/boulder-integration.sh @@ -84,6 +84,24 @@ if [ "$size1" -lt 3000 ] || [ "$size2" -lt 3000 ] || [ "$size3" -gt 1800 ] ; the exit 1 fi +# ECDSA +openssl ecparam -genkey -name secp384r1 -out "${root}/privkey-p384.pem" +SAN="DNS:ecdsa.le.wtf" openssl req -new -sha256 \ + -config "${OPENSSL_CNF:-openssl.cnf}" \ + -key "${root}/privkey-p384.pem" \ + -subj "/" \ + -reqexts san \ + -outform der \ + -out "${root}/csr-p384.der" +common auth --csr "${root}/csr-p384.der" \ + --cert-path "${root}/csr/cert-p384.pem" \ + --chain-path "${root}/csr/chain-p384.pem" +openssl x509 -in "${root}/csr/cert-p384.pem" -text | grep 'ASN1 OID: secp384r1' + +# OCSP Must Staple +common auth --must-staple --domains "must-staple.le.wtf" +openssl x509 -in "${root}/conf/live/must-staple.le.wtf/cert.pem" -text | grep '1.3.6.1.5.5.7.1.24' + # revoke by account key common revoke --cert-path "$root/conf/live/le.wtf/cert.pem" # revoke renewed From 261046a2d7dd01a4ce5383d192ce82d34a92faf8 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 14 Jun 2016 13:52:39 -0700 Subject: [PATCH 63/72] Update relevant_values tests --- certbot/tests/storage_test.py | 50 ++++++++++++++++------------------- 1 file changed, 23 insertions(+), 27 deletions(-) diff --git a/certbot/tests/storage_test.py b/certbot/tests/storage_test.py index 138f6e2fa..261500b98 100644 --- a/certbot/tests/storage_test.py +++ b/certbot/tests/storage_test.py @@ -11,6 +11,7 @@ import mock import pytz import certbot +from certbot import cli from certbot import configuration from certbot import errors from certbot.storage import ALL_FOUR @@ -517,38 +518,33 @@ class RenewableCertTests(BaseRenewableCertTest): self.assertFalse(os.path.islink(self.test_rc.version("privkey", 10))) self.assertFalse(os.path.exists(temp_config_file)) - @mock.patch("certbot.cli.helpful_parser") - def test_relevant_values(self, mock_parser): + def _test_relevant_values_common(self, values): + option = "rsa_key_size" + mock_parser = mock.Mock(args=["--standalone"], verb="certonly", + defaults={option: cli.flag_default(option)}) + + from certbot.storage import relevant_values + with mock.patch("certbot.cli.helpful_parser", mock_parser): + return relevant_values(values) + + def test_relevant_values(self): """Test that relevant_values() can reject an irrelevant value.""" - # pylint: disable=protected-access - from certbot import storage - mock_parser.verb = "certonly" - mock_parser.args = ["--standalone"] - mock_action = mock.Mock(dest="rsa_key_size", default=2048) - mock_parser.parser._actions = [mock_action] - self.assertEqual(storage.relevant_values({"hello": "there"}), {}) + self.assertEqual( + self._test_relevant_values_common({"hello": "there"}), {}) - @mock.patch("certbot.cli.helpful_parser") - def test_relevant_values_default(self, mock_parser): + def test_relevant_values_default(self): """Test that relevant_values() can reject a default value.""" - # pylint: disable=protected-access - from certbot import storage - mock_parser.args = ["--standalone"] - mock_parser.defaults = {"rsa_key_size": 2048} - mock_parser.verb = "certonly" - self.assertEqual(storage.relevant_values({"rsa_key_size": 2048}), {}) + option = "rsa_key_size" + values = {option: cli.flag_default(option)} + self.assertEqual(self._test_relevant_values_common(values), {}) - @mock.patch("certbot.cli.helpful_parser") - def test_relevant_values_nondefault(self, mock_parser): + def test_relevant_values_nondefault(self): """Test that relevant_values() can retain a non-default value.""" - # pylint: disable=protected-access - from certbot import storage - mock_parser.verb = "certonly" - mock_parser.args = ["--standalone"] - mock_action = mock.Mock(dest="rsa_key_size", default=2048) - mock_parser.parser._actions = [mock_action] - self.assertEqual(storage.relevant_values({"rsa_key_size": 12}), - {"rsa_key_size": 12}) + values = {"rsa_key_size": 12} + # A copy is given to _test_relevant_values_common + # to make sure values isn't modified by the method + self.assertEqual( + self._test_relevant_values_common(values.copy()), values) @mock.patch("certbot.storage.relevant_values") def test_new_lineage(self, mock_rv): From 4158656058cb14e8afa9048b9a3612da73abf1b5 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 14 Jun 2016 16:56:16 -0700 Subject: [PATCH 64/72] Release 0.8.1 --- acme/setup.py | 2 +- certbot-apache/setup.py | 2 +- certbot-auto | 52 ++++++++++++++---- certbot-compatibility-test/setup.py | 2 +- certbot-nginx/setup.py | 2 +- certbot/__init__.py | 2 +- docs/cli-help.txt | 9 +++ letsencrypt-auto | 52 ++++++++++++++---- letsencrypt-auto-source/certbot-auto.asc | 14 ++--- letsencrypt-auto-source/letsencrypt-auto | 20 +++---- letsencrypt-auto-source/letsencrypt-auto.sig | Bin 256 -> 256 bytes .../pieces/letsencrypt-auto-requirements.txt | 18 +++--- 12 files changed, 120 insertions(+), 55 deletions(-) diff --git a/acme/setup.py b/acme/setup.py index ed133e128..2bcec9128 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.0.dev0' +version = '0.8.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 e3dbe4563..87214d2e5 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.0.dev0' +version = '0.8.1' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-auto b/certbot-auto index 2de5ff48f..80f39cf59 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.8.0" +LE_AUTO_VERSION="0.8.1" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -172,7 +172,7 @@ BootstrapDebCommon() { # distro version (#346) virtualenv= - if apt-cache show virtualenv > /dev/null 2>&1; then + if apt-cache show virtualenv > /dev/null 2>&1 && ! apt-cache --quiet=0 show virtualenv 2>&1 | grep -q 'No packages found'; then virtualenv="virtualenv" fi @@ -458,12 +458,39 @@ BootstrapSmartOS() { pkgin -y install 'gcc49' 'py27-augeas' 'py27-virtualenv' } +BootstrapMageiaCommon() { + if ! $SUDO urpmi --force \ + python \ + libpython-devel \ + python-virtualenv + then + echo "Could not install Python dependencies. Aborting bootstrap!" + exit 1 + fi + + if ! $SUDO urpmi --force \ + git \ + gcc \ + cdialog \ + python-augeas \ + libopenssl-devel \ + libffi-devel \ + rootcerts + then + echo "Could not install additional dependencies. Aborting bootstrap!" + exit 1 + fi +} + # Install required OS packages: Bootstrap() { if [ -f /etc/debian_version ]; then echo "Bootstrapping dependencies for Debian-based OSes..." BootstrapDebCommon + elif [ -f /etc/mageia-release ] ; then + # Mageia has both /etc/mageia-release and /etc/redhat-release + ExperimentalBootstrap "Mageia" BootstrapMageiaCommon elif [ -f /etc/redhat-release ]; then echo "Bootstrapping dependencies for RedHat-based OSes..." BootstrapRpmCommon @@ -476,7 +503,7 @@ Bootstrap() { BootstrapArchCommon else echo "Please use pacman to install letsencrypt packages:" - echo "# pacman -S letsencrypt letsencrypt-apache" + echo "# pacman -S certbot certbot-apache" echo echo "If you would like to use the virtualenv way, please run the script again with the" echo "--debug flag." @@ -500,6 +527,7 @@ Bootstrap() { echo "You will need to bootstrap, configure virtualenv, and run pip install manually." echo "Please see https://letsencrypt.readthedocs.org/en/latest/contributing.html#prerequisites" echo "for more info." + exit 1 fi } @@ -719,15 +747,15 @@ letsencrypt==0.7.0 \ # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. -acme==0.8.0 \ - --hash=sha256:8561d590e496afb41a8ff2dac389199661d9cd785b1636ae08325771511189af \ - --hash=sha256:dfa86b547628b231f275c7e0efc7a09bec5dfaec866f89f5c5b59b78c14564da -certbot==0.8.0 \ - --hash=sha256:395c5840ff6b75aa51ee6449c86d016c14c5f65a71281e7bcef5feecac6a3293 \ - --hash=sha256:3c3c70b484fb3243a166515adc81ae0401c5d687a2763c75b40df9d8241a4314 -certbot-apache==0.8.0 \ - --hash=sha256:f4d4fc962ecc19646f6745d49c62a265d26e5b2df3acf34ef4865351594156e3 \ - --hash=sha256:cfb211debbcb0d0645c88d7e8bb38c591fca263bfdb5337242c023956055e268 +acme==0.8.1 \ + --hash=sha256:ccd7883772efbf933f91713b8241455993834f3620c8fbd459d9ed5e50bbaaca \ + --hash=sha256:d3ea4acf280bf6253ad7d641cb0970f230a19805acfed809e7a8ddcf62157d9f +certbot==0.8.1 \ + --hash=sha256:89805d9f70249ae859ec4d7a99c00b4bb7083ca90cd12d4d202b76dfc284f7c5 \ + --hash=sha256:6ca8df3d310ced6687d38aac17c0fb8c1b2ec7a3bea156a254e4cc2a1c132771 +certbot-apache==0.8.1 \ + --hash=sha256:c9e3fdc15e65589c2e39eb0e6b1f61f0c0a1db3c17b00bb337f0ff636cc61cb3 \ + --hash=sha256:0faf2879884d3b7a58b071902fba37d4b8b58a50e2c3b8ac262c0a74134045ed UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/certbot-compatibility-test/setup.py b/certbot-compatibility-test/setup.py index fb56be65f..cd282af50 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.0.dev0' +version = '0.8.1' install_requires = [ 'certbot', diff --git a/certbot-nginx/setup.py b/certbot-nginx/setup.py index 62c705b4c..f76cbe596 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.0.dev0' +version = '0.8.1' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot/__init__.py b/certbot/__init__.py index 34358a5d9..e5d5629b1 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.0.dev0' +__version__ = '0.8.1' diff --git a/docs/cli-help.txt b/docs/cli-help.txt index b25326148..e5f1fdcb4 100644 --- a/docs/cli-help.txt +++ b/docs/cli-help.txt @@ -200,6 +200,15 @@ renew: and keys; the shell variable $RENEWED_DOMAINS will contain a space-delimited list of renewed cert domains (default: None) + --disable-hook-validation + Ordinarily the commands specified for --pre-hook + /--post-hook/--renew-hook will be checked for + validity, to see if the programs being run are in the + $PATH, so that mistakes can be caught early, even when + the hooks aren't being run just yet. The validation is + rather simplistic and fails if you use more advanced + shell constructs, so you can use this switch to + disable it. (default: True) certonly: Options for modifying how a cert is obtained diff --git a/letsencrypt-auto b/letsencrypt-auto index 2de5ff48f..80f39cf59 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.8.0" +LE_AUTO_VERSION="0.8.1" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -172,7 +172,7 @@ BootstrapDebCommon() { # distro version (#346) virtualenv= - if apt-cache show virtualenv > /dev/null 2>&1; then + if apt-cache show virtualenv > /dev/null 2>&1 && ! apt-cache --quiet=0 show virtualenv 2>&1 | grep -q 'No packages found'; then virtualenv="virtualenv" fi @@ -458,12 +458,39 @@ BootstrapSmartOS() { pkgin -y install 'gcc49' 'py27-augeas' 'py27-virtualenv' } +BootstrapMageiaCommon() { + if ! $SUDO urpmi --force \ + python \ + libpython-devel \ + python-virtualenv + then + echo "Could not install Python dependencies. Aborting bootstrap!" + exit 1 + fi + + if ! $SUDO urpmi --force \ + git \ + gcc \ + cdialog \ + python-augeas \ + libopenssl-devel \ + libffi-devel \ + rootcerts + then + echo "Could not install additional dependencies. Aborting bootstrap!" + exit 1 + fi +} + # Install required OS packages: Bootstrap() { if [ -f /etc/debian_version ]; then echo "Bootstrapping dependencies for Debian-based OSes..." BootstrapDebCommon + elif [ -f /etc/mageia-release ] ; then + # Mageia has both /etc/mageia-release and /etc/redhat-release + ExperimentalBootstrap "Mageia" BootstrapMageiaCommon elif [ -f /etc/redhat-release ]; then echo "Bootstrapping dependencies for RedHat-based OSes..." BootstrapRpmCommon @@ -476,7 +503,7 @@ Bootstrap() { BootstrapArchCommon else echo "Please use pacman to install letsencrypt packages:" - echo "# pacman -S letsencrypt letsencrypt-apache" + echo "# pacman -S certbot certbot-apache" echo echo "If you would like to use the virtualenv way, please run the script again with the" echo "--debug flag." @@ -500,6 +527,7 @@ Bootstrap() { echo "You will need to bootstrap, configure virtualenv, and run pip install manually." echo "Please see https://letsencrypt.readthedocs.org/en/latest/contributing.html#prerequisites" echo "for more info." + exit 1 fi } @@ -719,15 +747,15 @@ letsencrypt==0.7.0 \ # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. -acme==0.8.0 \ - --hash=sha256:8561d590e496afb41a8ff2dac389199661d9cd785b1636ae08325771511189af \ - --hash=sha256:dfa86b547628b231f275c7e0efc7a09bec5dfaec866f89f5c5b59b78c14564da -certbot==0.8.0 \ - --hash=sha256:395c5840ff6b75aa51ee6449c86d016c14c5f65a71281e7bcef5feecac6a3293 \ - --hash=sha256:3c3c70b484fb3243a166515adc81ae0401c5d687a2763c75b40df9d8241a4314 -certbot-apache==0.8.0 \ - --hash=sha256:f4d4fc962ecc19646f6745d49c62a265d26e5b2df3acf34ef4865351594156e3 \ - --hash=sha256:cfb211debbcb0d0645c88d7e8bb38c591fca263bfdb5337242c023956055e268 +acme==0.8.1 \ + --hash=sha256:ccd7883772efbf933f91713b8241455993834f3620c8fbd459d9ed5e50bbaaca \ + --hash=sha256:d3ea4acf280bf6253ad7d641cb0970f230a19805acfed809e7a8ddcf62157d9f +certbot==0.8.1 \ + --hash=sha256:89805d9f70249ae859ec4d7a99c00b4bb7083ca90cd12d4d202b76dfc284f7c5 \ + --hash=sha256:6ca8df3d310ced6687d38aac17c0fb8c1b2ec7a3bea156a254e4cc2a1c132771 +certbot-apache==0.8.1 \ + --hash=sha256:c9e3fdc15e65589c2e39eb0e6b1f61f0c0a1db3c17b00bb337f0ff636cc61cb3 \ + --hash=sha256:0faf2879884d3b7a58b071902fba37d4b8b58a50e2c3b8ac262c0a74134045ed UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/letsencrypt-auto-source/certbot-auto.asc b/letsencrypt-auto-source/certbot-auto.asc index 0255229b0..5bb725c96 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 -iQEcBAABAgAGBQJXUJvwAAoJEE0XyZXNl3XyvKsH/3qn7Xa/GQx3HvB6Io/Csn/E -v1nbUg5RPwvrTyyol8BJ6UrHiJw+gTbUgCAnBkZ7DYKaC8AQmQXVRcWXNALMMTzB -6LpBXjQQ2xrBYamGj70N7KnTM1QmxI96GUQouiHMJVugV4uihKJDjtR8/f2JWKok -ZSox6E4LqC45HzqLWiOqc13TrHbti32Mo8DyC63PBnSwMnypGLK6XcqM0L9Re62W -smoKu1VWKwWZYRYXIQr0dvK4JmVTrIsdASdZkhTC/vc8y4tGkdN0DcF2EHzci6OA -Tx0W+Ao+HM1ZcaaH3BJ1y3kYfT+mlt6o4OaK3UB/wtUzMmVih7l1UeiNkVL0oYk= -=t3L6 +iQEcBAABAgAGBQJXYJmBAAoJEE0XyZXNl3XyyIMH/jtYFb7rl5XXN8hjlKuK5frq +z7/jdK7fvI+mtYJ4i2Cy3yMz8T4wscXGkhxNtipbATWlpevPfjYzm4ZGC25coFZx +fDX44w0hBBgel7EISXGR1ABXb2rj24TZxIYXwaeClylsK9n5CxcWBocn8tDlfr8t +7VQUJEL3l1IlrnKnvpoL4Eq11sxlIPtitDPJ5c98ZM1293ZbWzIqyZKoXLIUkKHg +pkaa80j/QMmFumxzXFenU91JusLdeoblvjjg+kzjGonjslAYIuH4wEEjz2VJuUYe +P2+2ZyW4eLA6rRZhZ3CMtV79HzTPTWiELCYbXezb+yXJJEqzCYtIXkmbNQ3jUEY= +=86lB -----END PGP SIGNATURE----- diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 1e3118848..80f39cf59 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.0.dev0" +LE_AUTO_VERSION="0.8.1" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -747,15 +747,15 @@ letsencrypt==0.7.0 \ # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. -acme==0.8.0 \ - --hash=sha256:8561d590e496afb41a8ff2dac389199661d9cd785b1636ae08325771511189af \ - --hash=sha256:dfa86b547628b231f275c7e0efc7a09bec5dfaec866f89f5c5b59b78c14564da -certbot==0.8.0 \ - --hash=sha256:395c5840ff6b75aa51ee6449c86d016c14c5f65a71281e7bcef5feecac6a3293 \ - --hash=sha256:3c3c70b484fb3243a166515adc81ae0401c5d687a2763c75b40df9d8241a4314 -certbot-apache==0.8.0 \ - --hash=sha256:f4d4fc962ecc19646f6745d49c62a265d26e5b2df3acf34ef4865351594156e3 \ - --hash=sha256:cfb211debbcb0d0645c88d7e8bb38c591fca263bfdb5337242c023956055e268 +acme==0.8.1 \ + --hash=sha256:ccd7883772efbf933f91713b8241455993834f3620c8fbd459d9ed5e50bbaaca \ + --hash=sha256:d3ea4acf280bf6253ad7d641cb0970f230a19805acfed809e7a8ddcf62157d9f +certbot==0.8.1 \ + --hash=sha256:89805d9f70249ae859ec4d7a99c00b4bb7083ca90cd12d4d202b76dfc284f7c5 \ + --hash=sha256:6ca8df3d310ced6687d38aac17c0fb8c1b2ec7a3bea156a254e4cc2a1c132771 +certbot-apache==0.8.1 \ + --hash=sha256:c9e3fdc15e65589c2e39eb0e6b1f61f0c0a1db3c17b00bb337f0ff636cc61cb3 \ + --hash=sha256:0faf2879884d3b7a58b071902fba37d4b8b58a50e2c3b8ac262c0a74134045ed UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/letsencrypt-auto-source/letsencrypt-auto.sig b/letsencrypt-auto-source/letsencrypt-auto.sig index f024577a34a42779e39755635eca4daf6f46ac2a..e3da0e0a35a6dafe26dbbe061f546aeb929dfcdb 100644 GIT binary patch literal 256 zcmV+b0ssDf@*{!ug8Wu1n(zcS_L8lFE=3`8xR7ru#Yq0;RMek)(d|5ow9N+eJQroy zYC^uLM9I-+sE5&5@?b;V8wXnSYWY@reJu{#UVlBrThxmxIb7 G&VdBMz>LuV literal 256 zcmV+b0ssE80bqRH{`qI)8kxNPxBYvrI}8PM??lS5W%Vrx#G#77ah$EmwK78hzI8fL zpFoy+Z$Ff?%2R#7_m4mldi$VK+OCedjDk7*K$j_4-%~DH(I7GKai+aBwofiSx4Q27 z;SV#~5cO^_zi`sHUA566Xqu@Q&d>p~uV#$A5kiL^Wt5QWl@grCRt$tN>*5-L&1i=@?vr?8a-~$mStKTr+dwJTPqN4;)GA0wY_jCnH7Wesi1I|l7M@y GRi#to9)G0( diff --git a/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt b/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt index c33795ced..1291b2c96 100644 --- a/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt +++ b/letsencrypt-auto-source/pieces/letsencrypt-auto-requirements.txt @@ -181,12 +181,12 @@ letsencrypt==0.7.0 \ # THE LINES BELOW ARE EDITED BY THE RELEASE SCRIPT; ADD ALL DEPENDENCIES ABOVE. -acme==0.8.0 \ - --hash=sha256:8561d590e496afb41a8ff2dac389199661d9cd785b1636ae08325771511189af \ - --hash=sha256:dfa86b547628b231f275c7e0efc7a09bec5dfaec866f89f5c5b59b78c14564da -certbot==0.8.0 \ - --hash=sha256:395c5840ff6b75aa51ee6449c86d016c14c5f65a71281e7bcef5feecac6a3293 \ - --hash=sha256:3c3c70b484fb3243a166515adc81ae0401c5d687a2763c75b40df9d8241a4314 -certbot-apache==0.8.0 \ - --hash=sha256:f4d4fc962ecc19646f6745d49c62a265d26e5b2df3acf34ef4865351594156e3 \ - --hash=sha256:cfb211debbcb0d0645c88d7e8bb38c591fca263bfdb5337242c023956055e268 +acme==0.8.1 \ + --hash=sha256:ccd7883772efbf933f91713b8241455993834f3620c8fbd459d9ed5e50bbaaca \ + --hash=sha256:d3ea4acf280bf6253ad7d641cb0970f230a19805acfed809e7a8ddcf62157d9f +certbot==0.8.1 \ + --hash=sha256:89805d9f70249ae859ec4d7a99c00b4bb7083ca90cd12d4d202b76dfc284f7c5 \ + --hash=sha256:6ca8df3d310ced6687d38aac17c0fb8c1b2ec7a3bea156a254e4cc2a1c132771 +certbot-apache==0.8.1 \ + --hash=sha256:c9e3fdc15e65589c2e39eb0e6b1f61f0c0a1db3c17b00bb337f0ff636cc61cb3 \ + --hash=sha256:0faf2879884d3b7a58b071902fba37d4b8b58a50e2c3b8ac262c0a74134045ed From 5c74e728b584e3750ba2b67d057339e8749faecd Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 14 Jun 2016 16:56:31 -0700 Subject: [PATCH 65/72] Bump version to 0.9.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 2bcec9128..ed133e128 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -4,7 +4,7 @@ from setuptools import setup from setuptools import find_packages -version = '0.8.1' +version = '0.9.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 87214d2e5..e3dbe4563 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.8.1' +version = '0.9.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 cd282af50..fb56be65f 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.8.1' +version = '0.9.0.dev0' install_requires = [ 'certbot', diff --git a/certbot-nginx/setup.py b/certbot-nginx/setup.py index f76cbe596..62c705b4c 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.8.1' +version = '0.9.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot/__init__.py b/certbot/__init__.py index e5d5629b1..34358a5d9 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.8.1' +__version__ = '0.9.0.dev0' diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 80f39cf59..80b81c898 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.8.1" +LE_AUTO_VERSION="0.9.0.dev0" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates From 6666ff25d49deb74c7976dd12a9a384ddde39083 Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Fri, 17 Jun 2016 03:57:49 +0200 Subject: [PATCH 66/72] Moving import dialog to the top of the file --- certbot/tests/cli_test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/certbot/tests/cli_test.py b/certbot/tests/cli_test.py index 9a2009e43..9c81c070b 100644 --- a/certbot/tests/cli_test.py +++ b/certbot/tests/cli_test.py @@ -2,6 +2,7 @@ from __future__ import print_function import argparse +import dialog import functools import itertools import os @@ -923,8 +924,6 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods traceback.format_exception_only(KeyboardInterrupt, interrupt))) # Test dialog errors - - import dialog exception = dialog.error(message="test message") main._handle_exception( dialog.DialogError, exc_value=exception, trace=None, config=None) From 31d9fc7d865c4567f56b3991c90e915a620aaa2e Mon Sep 17 00:00:00 2001 From: Amjad Mashaal Date: Fri, 17 Jun 2016 04:13:44 +0200 Subject: [PATCH 67/72] Adding --skip-missing-interpreters to constributing.rst "Submitting a pull request" section --- docs/contributing.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/contributing.rst b/docs/contributing.rst index 9ceb0fbdd..633af19c6 100644 --- a/docs/contributing.rst +++ b/docs/contributing.rst @@ -317,7 +317,9 @@ Steps: 3. Run ``./pep8.travis.sh`` to do a cursory check of your code style. Fix any errors. 4. Run ``tox -e lint`` to check for pylint errors. Fix any errors. -5. Run ``tox`` to run the entire test suite including coverage. Fix any errors. +5. Run ``tox --skip-missing-interpreters`` to run the entire test suite + including coverage. The ``--skip-missing-interpreters`` argument ignores + missing versions of Python needed for running the tests. Fix any errors. 6. If your code touches communication with an ACME server/Boulder, you should run the integration tests, see `integration`_. See `Known Issues`_ for some common failures that have nothing to do with your code. From f5282ed2de63342d09e593cb1a9338383ab2b9b1 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Fri, 17 Jun 2016 10:48:54 -0700 Subject: [PATCH 68/72] Show lines missing test coverage in test output --- .coveragerc | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .coveragerc diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 000000000..087900105 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,3 @@ +[report] +# show lines missing coverage in output +show_missing = True From 6156b452bcf7c924f12c334e7094ff5a9049ee37 Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Tue, 24 May 2016 14:04:55 -0500 Subject: [PATCH 69/72] Fix FQDN checks. --- certbot/util.py | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/certbot/util.py b/certbot/util.py index 35c599737..9739e8d2f 100644 --- a/certbot/util.py +++ b/certbot/util.py @@ -423,14 +423,17 @@ def enforce_domain_sanity(domain): # It wasn't an IP address, so that's good pass - # FQDN checks from - # http://www.mkyong.com/regular-expressions/domain-name-regular-expression-example/ - # Characters used, domain parts < 63 chars, tld > 1 < 64 chars - # first and last char is not "-" - fqdn = re.compile("^((?!-)[A-Za-z0-9-]{1,63}(? 256: + raise errors.ConfigurationError(msg + "it is too long.") + return domain From a7a2049d69debf457cec637ddf4e5c9ca9848c9f Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Tue, 24 May 2016 14:14:44 -0500 Subject: [PATCH 70/72] Fix FQDN tests. --- certbot/tests/cli_test.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/certbot/tests/cli_test.py b/certbot/tests/cli_test.py index 9c81c070b..896550837 100644 --- a/certbot/tests/cli_test.py +++ b/certbot/tests/cli_test.py @@ -342,11 +342,11 @@ class CLITest(unittest.TestCase): # pylint: disable=too-many-public-methods # FQDN self.assertRaises(errors.ConfigurationError, self._call, - ['-d', 'comma,gotwrong.tld']) + ['-d', 'a' * 64]) # FQDN 2 self.assertRaises(errors.ConfigurationError, self._call, - ['-d', 'illegal.character=.tld']) + ['-d', (('a' * 50) + '.') * 10]) # Wildcard self.assertRaises(errors.ConfigurationError, self._call, From 2625daad75a9233ee0f2d57576adff23e6db1779 Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Tue, 24 May 2016 14:25:29 -0500 Subject: [PATCH 71/72] Fix more FQDN tests in ops_test.py --- certbot/tests/display/ops_test.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/certbot/tests/display/ops_test.py b/certbot/tests/display/ops_test.py index 3aff37d86..26f67b69f 100644 --- a/certbot/tests/display/ops_test.py +++ b/certbot/tests/display/ops_test.py @@ -248,9 +248,9 @@ class ChooseNamesTest(unittest.TestCase): def test_get_valid_domains(self): from certbot.display.ops import get_valid_domains all_valid = ["example.com", "second.example.com", - "also.example.com"] - all_invalid = ["xn--ls8h.tld", "*.wildcard.com", "notFQDN", - "uniçodé.com"] + "also.example.com", "under_score.example.com", + "justtld"] + all_invalid = ["xn--ls8h.tld", "*.wildcard.com", "uniçodé.com"] two_valid = ["example.com", "xn--ls8h.tld", "also.example.com"] self.assertEqual(get_valid_domains(all_valid), all_valid) self.assertEqual(get_valid_domains(all_invalid), []) @@ -276,19 +276,18 @@ class ChooseNamesTest(unittest.TestCase): mock_util().input.return_value = (display_util.OK, "xn--ls8h.tld") self.assertEqual(_choose_names_manually(), []) - # non-FQDN and no retry - mock_util().input.return_value = (display_util.OK, - "notFQDN") - self.assertEqual(_choose_names_manually(), []) - # Two valid domains + # Valid domains mock_util().input.return_value = (display_util.OK, ("example.com," + "under_score.example.com," + "justtld," "valid.example.com")) self.assertEqual(_choose_names_manually(), - ["example.com", "valid.example.com"]) + ["example.com", "under_score.example.com", + "justtld", "valid.example.com"]) # Three iterations mock_util().input.return_value = (display_util.OK, - "notFQDN") + "uniçodé.com") yn = mock.MagicMock() yn.side_effect = [True, True, False] mock_util().yesno = yn From a148d2ddfa60206f1a648dd7c9851e5921ea1805 Mon Sep 17 00:00:00 2001 From: Blake Griffith Date: Fri, 17 Jun 2016 18:58:48 -0500 Subject: [PATCH 72/72] Limit domains to 255 octets. --- certbot/util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot/util.py b/certbot/util.py index 9739e8d2f..301fc669b 100644 --- a/certbot/util.py +++ b/certbot/util.py @@ -431,7 +431,7 @@ def enforce_domain_sanity(domain): for l in labels: if not 0 < len(l) < 64: raise errors.ConfigurationError(msg + "label {0} is too long.".format(l)) - if len(domain) > 256: + if len(domain) > 255: raise errors.ConfigurationError(msg + "it is too long.") return domain