Merge branch 'master' into windows-auto-update

This commit is contained in:
Adrien Ferrand 2020-03-30 22:23:37 +02:00
commit 54064d6ee1
52 changed files with 275 additions and 321 deletions

View file

@ -0,0 +1,13 @@
# Advanced pipeline for running our full test suite on demand.
trigger:
# When changing these triggers, please ensure the documentation under
# "Running tests in CI" is still correct.
- azure-test-*
- test-*
pr: none
jobs:
# Any addition here should be reflected in the advanced and release pipelines.
# It is advised to declare all jobs here as templates to improve maintainability.
- template: templates/tests-suite.yml
- template: templates/installer-tests.yml

View file

@ -1,12 +1,7 @@
# Advanced pipeline for isolated checks and release purpose
# Advanced pipeline for running our full test suite on protected branches.
trigger:
# When changing these triggers, please ensure the documentation under
# "Running tests in CI" is still correct.
- azure-test-*
- test-*
- '*.x'
pr:
- test-*
pr: none
# This pipeline is also nightly run on master
schedules:
- cron: "0 4 * * *"
@ -17,7 +12,7 @@ schedules:
always: true
jobs:
# Any addition here should be reflected in the release pipeline.
# Any addition here should be reflected in the advanced-test and release pipelines.
# It is advised to declare all jobs here as templates to improve maintainability.
- template: templates/tests-suite.yml
- template: templates/installer-tests.yml

View file

@ -6,7 +6,7 @@ trigger:
pr: none
jobs:
# Any addition here should be reflected in the advanced pipeline.
# Any addition here should be reflected in the advanced and advanced-test pipelines.
# It is advised to declare all jobs here as templates to improve maintainability.
- template: templates/tests-suite.yml
- template: templates/installer-tests.yml

View file

@ -28,15 +28,13 @@ jobs:
imageName: windows-2019
win2016:
imageName: vs2017-win2016
win2012r2:
imageName: vs2015-win2012r2
pool:
vmImage: $(imageName)
steps:
- powershell: Invoke-WebRequest https://www.python.org/ftp/python/3.8.1/python-3.8.1-amd64-webinstall.exe -OutFile C:\py3-setup.exe
displayName: Get Python
- script: C:\py3-setup.exe /quiet PrependPath=1 InstallAllUsers=1 Include_launcher=1 InstallLauncherAllUsers=1 Include_test=0 Include_doc=0 Include_dev=1 Include_debug=0 Include_tcltk=0 TargetDir=C:\py3
displayName: Install Python
- task: UsePythonVersion@0
inputs:
versionSpec: 3.8
addToPath: true
- task: DownloadPipelineArtifact@2
inputs:
artifact: windows-installer

View file

@ -25,8 +25,6 @@ jobs:
PYTEST_ADDOPTS: --numprocesses 4
pool:
vmImage: $(IMAGE_NAME)
variables:
- group: certbot-common
steps:
- bash: brew install augeas
condition: startswith(variables['IMAGE_NAME'], 'macOS')
@ -39,14 +37,3 @@ jobs:
displayName: Install dependencies
- script: python -m tox
displayName: Run tox
# We do not require codecov report upload to succeed. So to avoid to break the pipeline if
# something goes wrong, each command is suffixed with a command that hides any non zero exit
# codes and echoes an informative message instead.
- bash: |
curl -s https://codecov.io/bash -o codecov-bash || echo "Failed to download codecov-bash"
chmod +x codecov-bash || echo "Failed to apply execute permissions on codecov-bash"
./codecov-bash -F windows || echo "Codecov did not collect coverage reports"
condition: in(variables['TOXENV'], 'py37-cover', 'integration-certbot')
env:
CODECOV_TOKEN: $(codecov_token)
displayName: Publish coverage

View file

@ -1,18 +0,0 @@
coverage:
status:
project:
default: off
linux:
flags: linux
# Fixed target instead of auto set by #7173, can
# be removed when flags in Codecov are added back.
target: 97.4
threshold: 0.1
base: auto
windows:
flags: windows
# Fixed target instead of auto set by #7173, can
# be removed when flags in Codecov are added back.
target: 97.4
threshold: 0.1
base: auto

View file

@ -247,15 +247,13 @@ addons:
# version of virtualenv. The option "-I" is set so when CERTBOT_NO_PIN is also
# set, pip updates dependencies it thinks are already satisfied to avoid some
# problems with its lack of real dependency resolution.
install: 'tools/pip_install.py -I codecov tox virtualenv'
install: 'tools/pip_install.py -I tox virtualenv'
# Most of the time TRAVIS_RETRY is an empty string, and has no effect on the
# script command. It is set only to `travis_retry` during farm tests, in
# order to trigger the Travis retry feature, and compensate the inherent
# flakiness of these specific tests.
script: '$TRAVIS_RETRY tox'
after_success: '[ "$TOXENV" == "py27-cover" ] && codecov -F linux'
notifications:
email: false
irc:

View file

@ -4,7 +4,7 @@ from setuptools import find_packages
from setuptools import setup
from setuptools.command.test import test as TestCommand
version = '1.3.0.dev0'
version = '1.4.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [

View file

@ -1,5 +1,6 @@
"""A class that performs HTTP-01 challenges for Apache"""
import logging
import errno
from acme.magic_typing import List
from acme.magic_typing import Set
@ -168,7 +169,15 @@ class ApacheHttp01(common.ChallengePerformer):
def _set_up_challenges(self):
if not os.path.isdir(self.challenge_dir):
filesystem.makedirs(self.challenge_dir, 0o755)
old_umask = os.umask(0o022)
try:
filesystem.makedirs(self.challenge_dir, 0o755)
except OSError as exception:
if exception.errno not in (errno.EEXIST, errno.EISDIR):
raise errors.PluginError(
"Couldn't create root for http-01 challenge")
finally:
os.umask(old_umask)
responses = []
for achall in self.achalls:

View file

@ -4,7 +4,7 @@ from setuptools import find_packages
from setuptools import setup
from setuptools.command.test import test as TestCommand
version = '1.3.0.dev0'
version = '1.4.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View file

@ -1,5 +1,6 @@
"""Test for certbot_apache._internal.http_01."""
import unittest
import errno
import mock
@ -197,6 +198,12 @@ class ApacheHttp01Test(util.ApacheTest):
self.assertTrue(os.path.exists(challenge_dir))
@mock.patch("certbot_apache._internal.http_01.filesystem.makedirs")
def test_failed_makedirs(self, mock_makedirs):
mock_makedirs.side_effect = OSError(errno.EACCES, "msg")
self.http.add_chall(self.achalls[0])
self.assertRaises(errors.PluginError, self.http.perform)
def _test_challenge_conf(self):
with open(self.http.challenge_conf_pre) as f:
pre_conf_contents = f.read()

View file

@ -31,7 +31,7 @@ if [ -z "$VENV_PATH" ]; then
fi
VENV_BIN="$VENV_PATH/bin"
BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
LE_AUTO_VERSION="1.2.0"
LE_AUTO_VERSION="1.3.0"
BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates
@ -1540,18 +1540,18 @@ letsencrypt==0.7.0 \
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
certbot==1.2.0 \
--hash=sha256:e25c17125c00b3398c8e9b9d54ef473c0e8f5aff53389f313a51b06cf472d335 \
--hash=sha256:95dcbae085f8e4eb18442fe7b12994b08964a9a6e8e352e556cdb4a8a625373c
acme==1.2.0 \
--hash=sha256:284d22fde75687a8ea72d737cac6bcbdc91f3c796221aa25378b8732ba6f6875 \
--hash=sha256:0630c740d49bda945e97bd35fc8d6f02d082c8cb9e18f8fec0dbb3d395ac26ab
certbot-apache==1.2.0 \
--hash=sha256:3f7493918353d3bd6067d446a2cf263e03831c4c10ec685b83d644b47767090d \
--hash=sha256:b46e9def272103a68108e48bf7e410ea46801529b1ea6954f6506b14dd9df9b3
certbot-nginx==1.2.0 \
--hash=sha256:efd32a2b32f2439279da446b6bf67684f591f289323c5f494ebfd86a566a28fd \
--hash=sha256:6fd7cf4f2545ad66e57000343227df9ccccaf04420e835e05cb3250fac1fa6db
certbot==1.3.0 \
--hash=sha256:979793b36151be26c159f1946d065a0cbbcaed3e9ac452c19a142b0d2d2b42e3 \
--hash=sha256:bc2091cbbc2f432872ed69309046e79771d9c81cd441bde3e6a6553ecd04b1d8
acme==1.3.0 \
--hash=sha256:b888757c750e393407a3cdf0eb5c2d06036951e10c41db4c83537617568561b6 \
--hash=sha256:c0de9e1fbcb4a28509825a4d19ab5455910862b23fa338acebc7bbe7c0abd20d
certbot-apache==1.3.0 \
--hash=sha256:1050cd262bcc598957c45a6fa1febdf5e41e87176c0aebad3a1ab7268b0d82d9 \
--hash=sha256:4a6bb818a7a70803127590a54bb25c1e79810761c9d4c92cf9f16a56b518bd52
certbot-nginx==1.3.0 \
--hash=sha256:46106b96429d1aaf3765635056352d2372941027a3bc26bbf964e4329202adc7 \
--hash=sha256:9aa0869c1250b7ea0a1eb1df6bdb5d0d6190d6ca0400da1033a8decc0df6f65b
UNLIKELY_EOF
# -------------------------------------------------------------------------

View file

@ -595,6 +595,23 @@ def test_ocsp_status_live(context):
assert output.count('REVOKED') == 1, 'Expected {0} to be REVOKED'.format(cert)
def test_ocsp_renew(context):
"""Test that revoked certificates are renewed."""
# Obtain a certificate
certname = context.get_domain('ocsp-renew')
context.certbot(['--domains', certname])
# Test that "certbot renew" does not renew the certificate
assert_cert_count_for_lineage(context.config_dir, certname, 1)
context.certbot(['renew'], force_renew=False)
assert_cert_count_for_lineage(context.config_dir, certname, 1)
# Revoke the certificate and test that it does renew the certificate
context.certbot(['revoke', '--cert-name', certname, '--no-delete-after-revoke'])
context.certbot(['renew'], force_renew=False)
assert_cert_count_for_lineage(context.config_dir, certname, 2)
def test_dry_run_deactivate_authzs(context):
"""Test that Certbot deactivates authorizations when performing a dry run"""

View file

@ -3,7 +3,7 @@ import sys
from setuptools import find_packages
from setuptools import setup
version = '1.3.0.dev0'
version = '1.4.0.dev0'
install_requires = [
'certbot',

View file

@ -4,7 +4,7 @@ from setuptools import find_packages
from setuptools import setup
from setuptools.command.test import test as TestCommand
version = '1.3.0.dev0'
version = '1.4.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View file

@ -4,7 +4,7 @@ from setuptools import find_packages
from setuptools import setup
from setuptools.command.test import test as TestCommand
version = '1.3.0.dev0'
version = '1.4.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View file

@ -4,7 +4,7 @@ from setuptools import find_packages
from setuptools import setup
from setuptools.command.test import test as TestCommand
version = '1.3.0.dev0'
version = '1.4.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View file

@ -5,7 +5,7 @@ from setuptools import find_packages
from setuptools import setup
from setuptools.command.test import test as TestCommand
version = '1.3.0.dev0'
version = '1.4.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View file

@ -4,7 +4,7 @@ from setuptools import find_packages
from setuptools import setup
from setuptools.command.test import test as TestCommand
version = '1.3.0.dev0'
version = '1.4.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View file

@ -4,7 +4,7 @@ from setuptools import find_packages
from setuptools import setup
from setuptools.command.test import test as TestCommand
version = '1.3.0.dev0'
version = '1.4.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [

View file

@ -4,7 +4,7 @@ from setuptools import find_packages
from setuptools import setup
from setuptools.command.test import test as TestCommand
version = '1.3.0.dev0'
version = '1.4.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View file

@ -4,7 +4,7 @@ from setuptools import find_packages
from setuptools import setup
from setuptools.command.test import test as TestCommand
version = '1.3.0.dev0'
version = '1.4.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [

View file

@ -4,7 +4,7 @@ from setuptools import find_packages
from setuptools import setup
from setuptools.command.test import test as TestCommand
version = '1.3.0.dev0'
version = '1.4.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View file

@ -4,7 +4,7 @@ from setuptools import find_packages
from setuptools import setup
from setuptools.command.test import test as TestCommand
version = '1.3.0.dev0'
version = '1.4.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View file

@ -4,7 +4,7 @@ from setuptools import find_packages
from setuptools import setup
from setuptools.command.test import test as TestCommand
version = '1.3.0.dev0'
version = '1.4.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View file

@ -4,7 +4,7 @@ from setuptools import find_packages
from setuptools import setup
from setuptools.command.test import test as TestCommand
version = '1.3.0.dev0'
version = '1.4.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View file

@ -4,7 +4,7 @@ from setuptools import find_packages
from setuptools import setup
from setuptools.command.test import test as TestCommand
version = '1.3.0.dev0'
version = '1.4.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View file

@ -4,7 +4,7 @@ from setuptools import find_packages
from setuptools import setup
from setuptools.command.test import test as TestCommand
version = '1.3.0.dev0'
version = '1.4.0.dev0'
# Please update tox.ini when modifying dependency version requirements
install_requires = [

View file

@ -4,7 +4,7 @@ from setuptools import find_packages
from setuptools import setup
from setuptools.command.test import test as TestCommand
version = '1.3.0.dev0'
version = '1.4.0.dev0'
# Remember to update local-oldest-requirements.txt when changing the minimum
# acme/certbot version.

View file

@ -2,7 +2,23 @@
Certbot adheres to [Semantic Versioning](https://semver.org/).
## 1.3.0 - master
## 1.4.0 - master
### Added
*
### Changed
*
### Fixed
*
More details about these changes can be found on our GitHub repo.
## 1.3.0 - 2020-03-03
### Added
@ -10,17 +26,19 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).
determine the OCSP status of certificates.
* Don't verify the existing certificate in HTTP01Response.simple_verify, for
compatibility with the real-world ACME challenge checks.
* Added support for `$hostname` in nginx `server_name` directive
### Changed
* certbot._internal.cli is now a package split in submodules instead of a whole module.
* Certbot will now renew certificates early if they have been revoked according
to OCSP.
* Fix acme module warnings when response Content-Type includes params (e.g. charset).
* Fixed issue where webroot plugin would incorrectly raise `Read-only file system`
error when creating challenge directories (issue #7165).
### Fixed
*
* Fix Apache plugin to use less restrictive umask for making the challenge directory when a restrictive umask was set when certbot was started.
More details about these changes can be found on our GitHub repo.
@ -29,7 +47,6 @@ More details about these changes can be found on our GitHub repo.
### Added
* Added support for Cloudflare's limited-scope API Tokens
* Added support for `$hostname` in nginx `server_name` directive
### Changed

View file

@ -71,16 +71,12 @@ ACME spec: http://ietf-wg-acme.github.io/acme/
ACME working area in github: https://github.com/ietf-wg-acme/acme
|build-status| |coverage| |container|
|build-status| |container|
.. |build-status| image:: https://travis-ci.com/certbot/certbot.svg?branch=master
:target: https://travis-ci.com/certbot/certbot
:alt: Travis CI status
.. |coverage| image:: https://codecov.io/gh/certbot/certbot/branch/master/graph/badge.svg
:target: https://codecov.io/gh/certbot/certbot
:alt: Coverage status
.. |container| image:: https://quay.io/repository/letsencrypt/letsencrypt/status
:target: https://quay.io/repository/letsencrypt/letsencrypt
:alt: Docker Repository on Quay.io

View file

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

View file

@ -394,7 +394,7 @@ def _find_domains_or_certname(config, installer, question=None):
:param installer: Installer object
:type installer: interfaces.IInstaller
:param `str` question: Overriding dialog question to ask the user if asked
:param `str` question: Overriding default question to ask the user if asked
to choose from domain names.
:returns: Two-part tuple of domains and certname

View file

@ -1,34 +0,0 @@
"""Send e-mail notification to system administrators."""
import email
import smtplib
import socket
import subprocess
def notify(subject, whom, what):
"""Send email notification.
Try to notify the addressee (``whom``) by e-mail, with Subject:
defined by ``subject`` and message body by ``what``.
"""
msg = email.message_from_string(what)
msg.add_header("From", "Certbot renewal agent <root>")
msg.add_header("To", whom)
msg.add_header("Subject", subject)
msg = msg.as_string()
try:
lmtp = smtplib.LMTP()
lmtp.connect()
lmtp.sendmail("root", [whom], msg)
except (smtplib.SMTPHeloError, smtplib.SMTPRecipientsRefused,
smtplib.SMTPSenderRefused, smtplib.SMTPDataError, socket.error):
# We should try using /usr/sbin/sendmail in this case
try:
proc = subprocess.Popen(["/usr/sbin/sendmail", "-t"],
stdin=subprocess.PIPE)
proc.communicate(msg)
except OSError:
return False
return True

View file

@ -15,6 +15,7 @@ import certbot
from certbot import crypto_util
from certbot import errors
from certbot import interfaces
from certbot import ocsp
from certbot import util
from certbot._internal import cli
from certbot._internal import constants
@ -882,27 +883,33 @@ class RenewableCert(interfaces.RenewableCert):
with open(target) as f:
return crypto_util.get_names_from_cert(f.read())
def ocsp_revoked(self, version=None):
# pylint: disable=unused-argument
def ocsp_revoked(self, version):
"""Is the specified cert version revoked according to OCSP?
Also returns True if the cert version is declared as intended
to be revoked according to Let's Encrypt OCSP extensions.
(If no version is specified, uses the current version.)
This method is not yet implemented and currently always returns
False.
Also returns True if the cert version is declared as revoked
according to OCSP. If OCSP status could not be determined, False
is returned.
:param int version: the desired version number
:returns: whether the certificate is or will be revoked
:returns: True if the certificate is revoked, otherwise, False
:rtype: bool
"""
# XXX: This query and its associated network service aren't
# implemented yet, so we currently return False (indicating that the
# certificate is not revoked).
return False
cert_path = self.version("cert", version)
chain_path = self.version("chain", version)
# While the RevocationChecker should return False if it failed to
# determine the OCSP status, let's ensure we don't crash Certbot by
# catching all exceptions here.
try:
return ocsp.RevocationChecker().ocsp_revoked_by_paths(cert_path,
chain_path)
except Exception as e: # pylint: disable=broad-except
logger.warning(
"An error occurred determining the OCSP status of %s.",
cert_path)
logger.debug(str(e))
return False
def autorenewal_is_enabled(self):
"""Is automatic renewal enabled for this cert?

View file

@ -107,7 +107,7 @@ def choose_names(installer, question=None):
:param installer: An installer object
:type installer: :class:`certbot.interfaces.IInstaller`
:param `str` question: Overriding dialog question to ask the user if asked
:param `str` question: Overriding default question to ask the user if asked
to choose from domain names.
:returns: List of selected names

View file

@ -68,8 +68,19 @@ class RevocationChecker(object):
:rtype: bool
"""
cert_path, chain_path = cert.cert_path, cert.chain_path
return self.ocsp_revoked_by_paths(cert.cert_path, cert.chain_path)
def ocsp_revoked_by_paths(self, cert_path, chain_path):
# type: (str, str) -> bool
"""Performs the OCSP revocation check
:param str cert_path: Certificate filepath
:param str chain_path: Certificate chain filepath
:returns: True if revoked; False if valid or the check failed or cert is expired.
:rtype: bool
"""
if self.broken:
return False

View file

@ -25,11 +25,9 @@ from certbot._internal import lock
from certbot.compat import filesystem
from certbot.compat import os
if sys.platform.startswith('linux'):
_USE_DISTRO = sys.platform.startswith('linux')
if _USE_DISTRO:
import distro
_USE_DISTRO = True
else:
_USE_DISTRO = False
logger = logging.getLogger(__name__)

View file

@ -113,7 +113,7 @@ optional arguments:
case, and to know when to deprecate support for past
Python versions and flags. If you wish to hide this
information from the Let's Encrypt server, set this to
"". (default: CertbotACMEClient/1.2.0 (certbot(-auto);
"". (default: CertbotACMEClient/1.3.0 (certbot(-auto);
OS_NAME OS_VERSION) Authenticator/XXX Installer/YYY
(SUBCOMMAND; flags: FLAGS) Py/major.minor.patchlevel).
The flags encoded in the user agent are: --duplicate,

View file

@ -485,43 +485,6 @@ If you want your hook to run only after a successful renewal, use
``certbot renew --deploy-hook /path/to/deploy-hook-script``
For example, if you have a daemon that does not read its certificates as the
root user, a deploy hook like this can copy them to the correct location and
apply appropriate file permissions.
/path/to/deploy-hook-script
.. code-block:: none
#!/bin/sh
set -e
for domain in $RENEWED_DOMAINS; do
case $domain in
example.com)
daemon_cert_root=/etc/some-daemon/certs
# Make sure the certificate and private key files are
# never world readable, even just for an instant while
# we're copying them into daemon_cert_root.
umask 077
cp "$RENEWED_LINEAGE/fullchain.pem" "$daemon_cert_root/$domain.cert"
cp "$RENEWED_LINEAGE/privkey.pem" "$daemon_cert_root/$domain.key"
# Apply the proper file ownership and permissions for
# the daemon to read its certificate and key.
chown some-daemon "$daemon_cert_root/$domain.cert" \
"$daemon_cert_root/$domain.key"
chmod 400 "$daemon_cert_root/$domain.cert" \
"$daemon_cert_root/$domain.key"
service some-daemon restart >/dev/null
;;
esac
done
You can also specify hooks by placing files in subdirectories of Certbot's
configuration directory. Assuming your configuration directory is
``/etc/letsencrypt``, any executable files found in
@ -686,6 +649,17 @@ your (web) server configuration directly to those files (or create
symlinks). During the renewal_, ``/etc/letsencrypt/live`` is updated
with the latest necessary files.
For historical reasons, the containing directories are created with
permissions of ``0700`` meaning that certificates are accessible only
to servers that run as the root user. **If you will never downgrade
to an older version of Certbot**, then you can safely fix this using
``chmod 0755 /etc/letsencrypt/{live,archive}``.
For servers that drop root privileges before attempting to read the
private key file, you will also need to use ``chgrp`` and ``chmod
0640`` to allow the server to read
``/etc/letsencrypt/live/$domain/privkey.pem``.
.. note:: ``/etc/letsencrypt/archive`` and ``/etc/letsencrypt/keys``
contain all previous keys and certificates, while
``/etc/letsencrypt/live`` symlinks to the latest versions.

View file

@ -30,15 +30,23 @@ class TestReadFile(TempDirTestCase):
# However a relative path between two different drives is invalid. So we move to
# self.tempdir to ensure that we stay on the same drive.
os.chdir(self.tempdir)
rel_test_path = os.path.relpath(os.path.join(self.tempdir, 'foo'))
# The read-only filesystem introduced with macOS Catalina can break
# code using relative paths below. See
# https://bugs.python.org/issue38295 for another example of this.
# Eliminating any possible symlinks in self.tempdir before passing
# it to os.path.relpath solves the problem. This is done by calling
# filesystem.realpath which removes any symlinks in the path on
# POSIX systems.
real_path = filesystem.realpath(os.path.join(self.tempdir, 'foo'))
relative_path = os.path.relpath(real_path)
self.assertRaises(
argparse.ArgumentTypeError, cli.read_file, rel_test_path)
argparse.ArgumentTypeError, cli.read_file, relative_path)
test_contents = b'bar\n'
with open(rel_test_path, 'wb') as f:
with open(relative_path, 'wb') as f:
f.write(test_contents)
path, contents = cli.read_file(rel_test_path)
path, contents = cli.read_file(relative_path)
self.assertEqual(path, os.path.abspath(path))
self.assertEqual(contents, test_contents)
finally:
@ -142,7 +150,6 @@ class ParseTest(unittest.TestCase):
self.assertTrue("how a certificate is deployed" in out)
self.assertTrue("--webroot-path" in out)
self.assertTrue("--text" not in out)
self.assertTrue("--dialog" not in out)
self.assertTrue("%s" not in out)
self.assertTrue("{0}" not in out)
self.assertTrue("--renew-hook" not in out)
@ -203,7 +210,6 @@ class ParseTest(unittest.TestCase):
self.assertTrue("how a certificate is deployed" in out)
self.assertTrue("--webroot-path" in out)
self.assertTrue("--text" not in out)
self.assertTrue("--dialog" not in out)
self.assertTrue("%s" not in out)
self.assertTrue("{0}" not in out)

View file

@ -1,52 +0,0 @@
"""Tests for certbot._internal.notify."""
import socket
import unittest
import mock
class NotifyTests(unittest.TestCase):
"""Tests for the notifier."""
@mock.patch("certbot._internal.notify.smtplib.LMTP")
def test_smtp_success(self, mock_lmtp):
from certbot._internal.notify import notify
lmtp_obj = mock.MagicMock()
mock_lmtp.return_value = lmtp_obj
self.assertTrue(notify("Goose", "auntrhody@example.com",
"The old grey goose is dead."))
self.assertEqual(lmtp_obj.connect.call_count, 1)
self.assertEqual(lmtp_obj.sendmail.call_count, 1)
@mock.patch("certbot._internal.notify.smtplib.LMTP")
@mock.patch("certbot._internal.notify.subprocess.Popen")
def test_smtp_failure(self, mock_popen, mock_lmtp):
from certbot._internal.notify import notify
lmtp_obj = mock.MagicMock()
mock_lmtp.return_value = lmtp_obj
lmtp_obj.sendmail.side_effect = socket.error(17)
proc = mock.MagicMock()
mock_popen.return_value = proc
self.assertTrue(notify("Goose", "auntrhody@example.com",
"The old grey goose is dead."))
self.assertEqual(lmtp_obj.sendmail.call_count, 1)
self.assertEqual(proc.communicate.call_count, 1)
@mock.patch("certbot._internal.notify.smtplib.LMTP")
@mock.patch("certbot._internal.notify.subprocess.Popen")
def test_everything_fails(self, mock_popen, mock_lmtp):
from certbot._internal.notify import notify
lmtp_obj = mock.MagicMock()
mock_lmtp.return_value = lmtp_obj
lmtp_obj.sendmail.side_effect = socket.error(17)
proc = mock.MagicMock()
mock_popen.return_value = proc
proc.communicate.side_effect = OSError("What we have here is a "
"failure to communicate.")
self.assertFalse(notify("Goose", "auntrhody@example.com",
"The old grey goose is dead."))
self.assertEqual(lmtp_obj.sendmail.call_count, 1)
self.assertEqual(proc.communicate.call_count, 1)
if __name__ == "__main__":
unittest.main() # pragma: no cover

View file

@ -177,7 +177,7 @@ class InstallerTest(test_util.ConfigTestCase):
class AddrTest(unittest.TestCase):
"""Tests for certbot._internal.client.plugins.common.Addr."""
"""Tests for certbot.plugins.common.Addr."""
def setUp(self):
from certbot.plugins.common import Addr

View file

@ -672,10 +672,35 @@ class RenewableCertTests(BaseRenewableCertTest):
errors.CertStorageError,
self.test_rc._update_link_to, "elephant", 17)
def test_ocsp_revoked(self):
# XXX: This is currently hardcoded to False due to a lack of an
# OCSP server to test against.
self.assertFalse(self.test_rc.ocsp_revoked())
@mock.patch("certbot.ocsp.RevocationChecker.ocsp_revoked_by_paths")
def test_ocsp_revoked(self, mock_checker):
# Write out test files
for kind in ALL_FOUR:
self._write_out_kind(kind, 1)
version = self.test_rc.latest_common_version()
expected_cert_path = self.test_rc.version("cert", version)
expected_chain_path = self.test_rc.version("chain", version)
# Test with cert revoked
mock_checker.return_value = True
self.assertTrue(self.test_rc.ocsp_revoked(version))
self.assertEqual(mock_checker.call_args[0][0], expected_cert_path)
self.assertEqual(mock_checker.call_args[0][1], expected_chain_path)
# Test with cert not revoked
mock_checker.return_value = False
self.assertFalse(self.test_rc.ocsp_revoked(version))
self.assertEqual(mock_checker.call_args[0][0], expected_cert_path)
self.assertEqual(mock_checker.call_args[0][1], expected_chain_path)
# Test with error
mock_checker.side_effect = ValueError
with mock.patch("certbot._internal.storage.logger.warning") as logger:
self.assertFalse(self.test_rc.ocsp_revoked(version))
self.assertEqual(mock_checker.call_args[0][0], expected_cert_path)
self.assertEqual(mock_checker.call_args[0][1], expected_chain_path)
log_msg = logger.call_args[0][0]
self.assertIn("An error occurred determining the OCSP status", log_msg)
def test_add_time_interval(self):
from certbot._internal import storage

View file

@ -31,7 +31,7 @@ if [ -z "$VENV_PATH" ]; then
fi
VENV_BIN="$VENV_PATH/bin"
BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
LE_AUTO_VERSION="1.2.0"
LE_AUTO_VERSION="1.3.0"
BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates
@ -1540,18 +1540,18 @@ letsencrypt==0.7.0 \
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
certbot==1.2.0 \
--hash=sha256:e25c17125c00b3398c8e9b9d54ef473c0e8f5aff53389f313a51b06cf472d335 \
--hash=sha256:95dcbae085f8e4eb18442fe7b12994b08964a9a6e8e352e556cdb4a8a625373c
acme==1.2.0 \
--hash=sha256:284d22fde75687a8ea72d737cac6bcbdc91f3c796221aa25378b8732ba6f6875 \
--hash=sha256:0630c740d49bda945e97bd35fc8d6f02d082c8cb9e18f8fec0dbb3d395ac26ab
certbot-apache==1.2.0 \
--hash=sha256:3f7493918353d3bd6067d446a2cf263e03831c4c10ec685b83d644b47767090d \
--hash=sha256:b46e9def272103a68108e48bf7e410ea46801529b1ea6954f6506b14dd9df9b3
certbot-nginx==1.2.0 \
--hash=sha256:efd32a2b32f2439279da446b6bf67684f591f289323c5f494ebfd86a566a28fd \
--hash=sha256:6fd7cf4f2545ad66e57000343227df9ccccaf04420e835e05cb3250fac1fa6db
certbot==1.3.0 \
--hash=sha256:979793b36151be26c159f1946d065a0cbbcaed3e9ac452c19a142b0d2d2b42e3 \
--hash=sha256:bc2091cbbc2f432872ed69309046e79771d9c81cd441bde3e6a6553ecd04b1d8
acme==1.3.0 \
--hash=sha256:b888757c750e393407a3cdf0eb5c2d06036951e10c41db4c83537617568561b6 \
--hash=sha256:c0de9e1fbcb4a28509825a4d19ab5455910862b23fa338acebc7bbe7c0abd20d
certbot-apache==1.3.0 \
--hash=sha256:1050cd262bcc598957c45a6fa1febdf5e41e87176c0aebad3a1ab7268b0d82d9 \
--hash=sha256:4a6bb818a7a70803127590a54bb25c1e79810761c9d4c92cf9f16a56b518bd52
certbot-nginx==1.3.0 \
--hash=sha256:46106b96429d1aaf3765635056352d2372941027a3bc26bbf964e4329202adc7 \
--hash=sha256:9aa0869c1250b7ea0a1eb1df6bdb5d0d6190d6ca0400da1033a8decc0df6f65b
UNLIKELY_EOF
# -------------------------------------------------------------------------

View file

@ -1,11 +1,11 @@
-----BEGIN PGP SIGNATURE-----
iQEzBAABCAAdFiEEos+1H6J1pyhiNOeyTRfJlc2XdfIFAl456ZoACgkQTRfJlc2X
dfJx8wf/addMw4kUlwu6poHqLvsifZzHAESgvq+qybgFvl5yTh2U+99PGBgxRYx+
bENIWBi6+XB+CiVuLzIXWw/VkXh+za99orRkkVK9PI33Xr7jBMZo5Oa3JviYjl3X
PcfjioRQCD+a9Tf9RO25LXQmxn87Ql9x3nxJuk//YeSpuImFmYjIBPE4n/LPEf7z
8WHU4oxxa/bgqGCPgv6O7ZBw7ipd3g+VHcDZcNQMP4tWYb6m7x/nN61yirid7q3M
uqQ1lbitN48ISyru6xPyE6WGTvfl1SIQd21FNRETpcoesx+MTv3ApWT4dqXjZvaX
FeM55IS65e7ci6yLV9qdAbqGKzhX0Q==
=uLcV
iQEzBAABCAAdFiEEos+1H6J1pyhiNOeyTRfJlc2XdfIFAl5ewVUACgkQTRfJlc2X
dfJnZAf+KmxYl1YoP/FlTG5Npb64qaDdxm59SeEVJez6fZh15xq71tRPYR+4xszE
XTeyGt7uAxjYqeiBJU5xBvGC1Veprhj5AbflVOTP+5yiBr9iNWC35zmgaE63UlZ/
V94sfL0pkax7wLngil7a0OuzUjikzK3gXOqrY8LoUdr4mAA9AhSjajWHmyY3tpDR
84GKrVhybIt0sjy/172VuPPbXZKno/clztkKMZHXNrDeL5jgJ15Va4Ts5FK0j9VT
HQvuazbGkYVCuvlp8Np5ESDje69LCJfPZxl34htoa8WNJoVIOsQWZpoXp5B5huSP
vGrh4LabZ5UDsl+k11ikHBRUpO7E5w==
=IgRH
-----END PGP SIGNATURE-----

View file

@ -31,7 +31,7 @@ if [ -z "$VENV_PATH" ]; then
fi
VENV_BIN="$VENV_PATH/bin"
BOOTSTRAP_VERSION_PATH="$VENV_PATH/certbot-auto-bootstrap-version.txt"
LE_AUTO_VERSION="1.3.0.dev0"
LE_AUTO_VERSION="1.4.0.dev0"
BASENAME=$(basename $0)
USAGE="Usage: $BASENAME [OPTIONS]
A self-updating wrapper script for the Certbot ACME client. When run, updates
@ -1540,18 +1540,18 @@ letsencrypt==0.7.0 \
--hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \
--hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9
certbot==1.2.0 \
--hash=sha256:e25c17125c00b3398c8e9b9d54ef473c0e8f5aff53389f313a51b06cf472d335 \
--hash=sha256:95dcbae085f8e4eb18442fe7b12994b08964a9a6e8e352e556cdb4a8a625373c
acme==1.2.0 \
--hash=sha256:284d22fde75687a8ea72d737cac6bcbdc91f3c796221aa25378b8732ba6f6875 \
--hash=sha256:0630c740d49bda945e97bd35fc8d6f02d082c8cb9e18f8fec0dbb3d395ac26ab
certbot-apache==1.2.0 \
--hash=sha256:3f7493918353d3bd6067d446a2cf263e03831c4c10ec685b83d644b47767090d \
--hash=sha256:b46e9def272103a68108e48bf7e410ea46801529b1ea6954f6506b14dd9df9b3
certbot-nginx==1.2.0 \
--hash=sha256:efd32a2b32f2439279da446b6bf67684f591f289323c5f494ebfd86a566a28fd \
--hash=sha256:6fd7cf4f2545ad66e57000343227df9ccccaf04420e835e05cb3250fac1fa6db
certbot==1.3.0 \
--hash=sha256:979793b36151be26c159f1946d065a0cbbcaed3e9ac452c19a142b0d2d2b42e3 \
--hash=sha256:bc2091cbbc2f432872ed69309046e79771d9c81cd441bde3e6a6553ecd04b1d8
acme==1.3.0 \
--hash=sha256:b888757c750e393407a3cdf0eb5c2d06036951e10c41db4c83537617568561b6 \
--hash=sha256:c0de9e1fbcb4a28509825a4d19ab5455910862b23fa338acebc7bbe7c0abd20d
certbot-apache==1.3.0 \
--hash=sha256:1050cd262bcc598957c45a6fa1febdf5e41e87176c0aebad3a1ab7268b0d82d9 \
--hash=sha256:4a6bb818a7a70803127590a54bb25c1e79810761c9d4c92cf9f16a56b518bd52
certbot-nginx==1.3.0 \
--hash=sha256:46106b96429d1aaf3765635056352d2372941027a3bc26bbf964e4329202adc7 \
--hash=sha256:9aa0869c1250b7ea0a1eb1df6bdb5d0d6190d6ca0400da1033a8decc0df6f65b
UNLIKELY_EOF
# -------------------------------------------------------------------------

View file

@ -1,12 +1,12 @@
certbot==1.2.0 \
--hash=sha256:e25c17125c00b3398c8e9b9d54ef473c0e8f5aff53389f313a51b06cf472d335 \
--hash=sha256:95dcbae085f8e4eb18442fe7b12994b08964a9a6e8e352e556cdb4a8a625373c
acme==1.2.0 \
--hash=sha256:284d22fde75687a8ea72d737cac6bcbdc91f3c796221aa25378b8732ba6f6875 \
--hash=sha256:0630c740d49bda945e97bd35fc8d6f02d082c8cb9e18f8fec0dbb3d395ac26ab
certbot-apache==1.2.0 \
--hash=sha256:3f7493918353d3bd6067d446a2cf263e03831c4c10ec685b83d644b47767090d \
--hash=sha256:b46e9def272103a68108e48bf7e410ea46801529b1ea6954f6506b14dd9df9b3
certbot-nginx==1.2.0 \
--hash=sha256:efd32a2b32f2439279da446b6bf67684f591f289323c5f494ebfd86a566a28fd \
--hash=sha256:6fd7cf4f2545ad66e57000343227df9ccccaf04420e835e05cb3250fac1fa6db
certbot==1.3.0 \
--hash=sha256:979793b36151be26c159f1946d065a0cbbcaed3e9ac452c19a142b0d2d2b42e3 \
--hash=sha256:bc2091cbbc2f432872ed69309046e79771d9c81cd441bde3e6a6553ecd04b1d8
acme==1.3.0 \
--hash=sha256:b888757c750e393407a3cdf0eb5c2d06036951e10c41db4c83537617568561b6 \
--hash=sha256:c0de9e1fbcb4a28509825a4d19ab5455910862b23fa338acebc7bbe7c0abd20d
certbot-apache==1.3.0 \
--hash=sha256:1050cd262bcc598957c45a6fa1febdf5e41e87176c0aebad3a1ab7268b0d82d9 \
--hash=sha256:4a6bb818a7a70803127590a54bb25c1e79810761c9d4c92cf9f16a56b518bd52
certbot-nginx==1.3.0 \
--hash=sha256:46106b96429d1aaf3765635056352d2372941027a3bc26bbf964e4329202adc7 \
--hash=sha256:9aa0869c1250b7ea0a1eb1df6bdb5d0d6190d6ca0400da1033a8decc0df6f65b

View file

@ -1,25 +1,19 @@
asn1crypto==0.24.0
awscli==1.16.157
bcrypt==3.1.6
boto3==1.9.146
botocore==1.12.147
cffi==1.12.3
colorama==0.3.9
cryptography==2.4.2
docutils==0.14
enum34==1.1.6
bcrypt==3.1.7
boto3==1.12.7
botocore==1.15.7
cffi==1.14.0
cryptography==2.8
docutils==0.15.2
enum34==1.1.9
Fabric==1.14.1
futures==3.2.0
idna==2.8
ipaddress==1.0.22
jmespath==0.9.4
paramiko==2.4.2
pyasn1==0.4.5
futures==3.3.0
ipaddress==1.0.23
jmespath==0.9.5
paramiko==2.7.1
pycparser==2.19
PyNaCl==1.3.0
python-dateutil==2.8.0
PyYAML==3.10
rsa==3.4.2
s3transfer==0.2.0
six==1.12.0
urllib3==1.24.3
python-dateutil==2.8.1
PyYAML==5.3
s3transfer==0.3.3
six==1.14.0
urllib3==1.25.8

View file

@ -18,7 +18,6 @@ boto3==1.11.7
botocore==1.14.7
cached-property==1.5.1
cloudflare==2.3.1
codecov==2.0.15
configparser==3.7.4
contextlib2==0.6.0.post1
coverage==4.5.4

View file

@ -1,4 +1,6 @@
#!/usr/bin/env python
from __future__ import print_function
import argparse
import os
import subprocess
@ -48,18 +50,23 @@ def cover(package):
subprocess.check_call([sys.executable, '-m', 'pytest',
'--cov', pkg_dir, '--cov-append', '--cov-report=', pkg_dir])
subprocess.check_call([
sys.executable, '-m', 'coverage', 'report', '--fail-under', str(threshold), '--include',
'{0}/*'.format(pkg_dir), '--show-missing'])
try:
subprocess.check_call([
sys.executable, '-m', 'coverage', 'report', '--fail-under',
str(threshold), '--include', '{0}/*'.format(pkg_dir),
'--show-missing'])
except subprocess.CalledProcessError as err:
print(err)
print('Test coverage on', pkg_dir,
'did not meet threshold of {0}%.'.format(threshold))
sys.exit(1)
def main():
description = """
This script is used by tox.ini (and thus by Travis CI and Azure Pipelines) in
order to generate separate stats for each package. It should be removed once
those packages are moved to a separate repo.
Option -e makes sure we fail fast and don't submit to codecov."""
those packages are moved to a separate repo."""
parser = argparse.ArgumentParser(description=description)
parser.add_argument('--packages', nargs='+')