Merge branch 'master' into full-azure-pipelines

This commit is contained in:
Adrien Ferrand 2020-06-26 21:05:24 +02:00
commit d220f5c3e7
36 changed files with 515 additions and 69 deletions

View file

@ -225,7 +225,8 @@ def _get_runtime_cfg(command):
command,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True)
universal_newlines=True,
env=util.env_no_snap_for_external_calls())
stdout, stderr = proc.communicate()
except (OSError, ValueError):

View file

@ -0,0 +1,25 @@
name: certbot-dns-cloudflare
summary: Cloudflare DNS Authenticator plugin for Certbot
description: Cloudflare DNS Authenticator plugin for Certbot
confinement: strict
grade: devel
base: core20
adopt-info: certbot-dns-cloudflare
parts:
certbot-dns-cloudflare:
plugin: python
source: .
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
override-pull: |
snapcraftctl pull
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
build-environment:
- EXCLUDE_CERTBOT_DEPS: "True"
slots:
certbot:
interface: content
content: certbot-1
read:
- $SNAP/lib/python3.8/site-packages

View file

@ -0,0 +1,25 @@
name: certbot-dns-cloudxns
summary: CloudXNS DNS Authenticator plugin for Certbot
description: CloudXNS DNS Authenticator plugin for Certbot
confinement: strict
grade: devel
base: core20
adopt-info: certbot-dns-cloudxns
parts:
certbot-dns-cloudxns:
plugin: python
source: .
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
override-pull: |
snapcraftctl pull
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
build-environment:
- EXCLUDE_CERTBOT_DEPS: "True"
slots:
certbot:
interface: content
content: certbot-1
read:
- $SNAP/lib/python3.8/site-packages

View file

@ -0,0 +1,25 @@
name: certbot-dns-digitalocean
summary: DigitalOcean DNS Authenticator plugin for Certbot
description: DigitalOcean DNS Authenticator plugin for Certbot
confinement: strict
grade: devel
base: core20
adopt-info: certbot-dns-digitalocean
parts:
certbot-dns-digitalocean:
plugin: python
source: .
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
override-pull: |
snapcraftctl pull
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
build-environment:
- EXCLUDE_CERTBOT_DEPS: "True"
slots:
certbot:
interface: content
content: certbot-1
read:
- $SNAP/lib/python3.8/site-packages

View file

@ -1,9 +1,9 @@
name: certbot-dns-dnsimple
summary: DNSimple DNS Authenticator plugin for Certbot
description: TBC
description: DNSimple DNS Authenticator plugin for Certbot
confinement: strict
grade: devel
base: core18
base: core20
adopt-info: certbot-dns-dnsimple
parts:
@ -11,7 +11,6 @@ parts:
plugin: python
source: .
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
python-version: python3
override-pull: |
snapcraftctl pull
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
@ -23,4 +22,4 @@ slots:
interface: content
content: certbot-1
read:
- $SNAP/lib/python3.6/site-packages
- $SNAP/lib/python3.8/site-packages

View file

@ -0,0 +1,25 @@
name: certbot-dns-dnsmadeeasy
summary: DNS Made Easy DNS Authenticator plugin for Certbot
description: DNS Made Easy DNS Authenticator plugin for Certbot
confinement: strict
grade: devel
base: core20
adopt-info: certbot-dns-dnsmadeeasy
parts:
certbot-dns-dnsmadeeasy:
plugin: python
source: .
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
override-pull: |
snapcraftctl pull
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
build-environment:
- EXCLUDE_CERTBOT_DEPS: "True"
slots:
certbot:
interface: content
content: certbot-1
read:
- $SNAP/lib/python3.8/site-packages

View file

@ -0,0 +1,25 @@
name: certbot-dns-gehirn
summary: Gehirn Infrastructure Service DNS Authenticator plugin for Certbot
description: Gehirn Infrastructure Service DNS Authenticator plugin for Certbot
confinement: strict
grade: devel
base: core20
adopt-info: certbot-dns-gehirn
parts:
certbot-dns-gehirn:
plugin: python
source: .
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
override-pull: |
snapcraftctl pull
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
build-environment:
- EXCLUDE_CERTBOT_DEPS: "True"
slots:
certbot:
interface: content
content: certbot-1
read:
- $SNAP/lib/python3.8/site-packages

View file

@ -0,0 +1,25 @@
name: certbot-dns-google
summary: Google Cloud DNS Authenticator plugin for Certbot
description: Google Cloud DNS Authenticator plugin for Certbot
confinement: strict
grade: devel
base: core20
adopt-info: certbot-dns-google
parts:
certbot-dns-google:
plugin: python
source: .
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
override-pull: |
snapcraftctl pull
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
build-environment:
- EXCLUDE_CERTBOT_DEPS: "True"
slots:
certbot:
interface: content
content: certbot-1
read:
- $SNAP/lib/python3.8/site-packages

View file

@ -0,0 +1,25 @@
name: certbot-dns-linode
summary: Linode DNS Authenticator plugin for Certbot
description: Linode DNS Authenticator plugin for Certbot
confinement: strict
grade: devel
base: core20
adopt-info: certbot-dns-linode
parts:
certbot-dns-linode:
plugin: python
source: .
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
override-pull: |
snapcraftctl pull
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
build-environment:
- EXCLUDE_CERTBOT_DEPS: "True"
slots:
certbot:
interface: content
content: certbot-1
read:
- $SNAP/lib/python3.8/site-packages

View file

@ -0,0 +1,25 @@
name: certbot-dns-luadns
summary: LuaDNS Authenticator plugin for Certbot
description: LuaDNS Authenticator plugin for Certbot
confinement: strict
grade: devel
base: core20
adopt-info: certbot-dns-luadns
parts:
certbot-dns-luadns:
plugin: python
source: .
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
override-pull: |
snapcraftctl pull
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
build-environment:
- EXCLUDE_CERTBOT_DEPS: "True"
slots:
certbot:
interface: content
content: certbot-1
read:
- $SNAP/lib/python3.8/site-packages

View file

@ -0,0 +1,25 @@
name: certbot-dns-nsone
summary: NS1 DNS Authenticator plugin for Certbot
description: NS1 DNS Authenticator plugin for Certbot
confinement: strict
grade: devel
base: core20
adopt-info: certbot-dns-nsone
parts:
certbot-dns-nsone:
plugin: python
source: .
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
override-pull: |
snapcraftctl pull
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
build-environment:
- EXCLUDE_CERTBOT_DEPS: "True"
slots:
certbot:
interface: content
content: certbot-1
read:
- $SNAP/lib/python3.8/site-packages

View file

@ -0,0 +1,25 @@
name: certbot-dns-ovh
summary: OVH DNS Authenticator plugin for Certbot
description: OVH DNS Authenticator plugin for Certbot
confinement: strict
grade: devel
base: core20
adopt-info: certbot-dns-ovh
parts:
certbot-dns-ovh:
plugin: python
source: .
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
override-pull: |
snapcraftctl pull
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
build-environment:
- EXCLUDE_CERTBOT_DEPS: "True"
slots:
certbot:
interface: content
content: certbot-1
read:
- $SNAP/lib/python3.8/site-packages

View file

@ -0,0 +1,25 @@
name: certbot-dns-rfc2136
summary: RFC 2136 DNS Authenticator plugin for Certbot
description: RFC 2136 DNS Authenticator plugin for Certbot
confinement: strict
grade: devel
base: core20
adopt-info: certbot-dns-rfc2136
parts:
certbot-dns-rfc2136:
plugin: python
source: .
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
override-pull: |
snapcraftctl pull
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
build-environment:
- EXCLUDE_CERTBOT_DEPS: "True"
slots:
certbot:
interface: content
content: certbot-1
read:
- $SNAP/lib/python3.8/site-packages

View file

@ -0,0 +1,25 @@
name: certbot-dns-route53
summary: Route53 DNS Authenticator plugin for Certbot
description: Route53 DNS Authenticator plugin for Certbot
confinement: strict
grade: devel
base: core20
adopt-info: certbot-dns-route53
parts:
certbot-dns-route53:
plugin: python
source: .
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
override-pull: |
snapcraftctl pull
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
build-environment:
- EXCLUDE_CERTBOT_DEPS: "True"
slots:
certbot:
interface: content
content: certbot-1
read:
- $SNAP/lib/python3.8/site-packages

View file

@ -0,0 +1,25 @@
name: certbot-dns-sakuracloud
summary: Sakura Cloud DNS Authenticator plugin for Certbot
description: Sakura Cloud DNS Authenticator plugin for Certbot
confinement: strict
grade: devel
base: core20
adopt-info: certbot-dns-sakuracloud
parts:
certbot-dns-sakuracloud:
plugin: python
source: .
constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt]
override-pull: |
snapcraftctl pull
snapcraftctl set-version `grep ^version $SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"`
build-environment:
- EXCLUDE_CERTBOT_DEPS: "True"
slots:
certbot:
interface: content
content: certbot-1
read:
- $SNAP/lib/python3.8/site-packages

View file

@ -939,7 +939,8 @@ class NginxConfigurator(common.Installer):
[self.conf('ctl'), "-c", self.nginx_conf, "-V"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True)
universal_newlines=True,
env=util.env_no_snap_for_external_calls())
text = proc.communicate()[1] # nginx prints output to stderr
except (OSError, ValueError) as error:
logger.debug(str(error), exc_info=True)
@ -1169,7 +1170,8 @@ def nginx_restart(nginx_ctl, nginx_conf):
"""
try:
proc = subprocess.Popen([nginx_ctl, "-c", nginx_conf, "-s", "reload"])
proc = subprocess.Popen([nginx_ctl, "-c", nginx_conf, "-s", "reload"],
env=util.env_no_snap_for_external_calls())
proc.communicate()
if proc.returncode != 0:
@ -1179,7 +1181,7 @@ def nginx_restart(nginx_ctl, nginx_conf):
with tempfile.TemporaryFile() as out:
with tempfile.TemporaryFile() as err:
nginx_proc = subprocess.Popen([nginx_ctl, "-c", nginx_conf],
stdout=out, stderr=err)
stdout=out, stderr=err, env=util.env_no_snap_for_external_calls())
nginx_proc.communicate()
if nginx_proc.returncode != 0:
# Enter recovery routine...

View file

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

View file

@ -12,7 +12,7 @@ version = '1.6.0.dev0'
# acme/certbot version.
install_requires = [
'acme>=1.4.0',
'certbot>=1.4.0',
'certbot>=1.6.0.dev0',
'PyOpenSSL',
'pyparsing>=1.5.5', # Python3 support
'setuptools',

View file

@ -11,9 +11,6 @@ join() {
fi
}
paths=$(for plugin_snap in $(snap connections certbot|sed -n '2,$p'|awk '$1=="content[certbot-1]"{print $3}'|cut -d: -f1); do echo /snap/$plugin_snap/current/lib/python3.6/site-packages; done)
export PYTHONPATH=$(join : $PYTHONPATH $paths)
if [ -z "$PYTHONPATH" ]; then
unset PYTHONPATH
fi
paths=$(for plugin_snap in $(snap connections certbot|sed -n '2,$p'|awk '$1=="content[certbot-1]"{print $3}'|cut -d: -f1); do echo /snap/$plugin_snap/current/lib/python3.8/site-packages; done)
export CERTBOT_PLUGIN_PATH=$(join : $paths)
exec certbot "$@"

View file

@ -15,6 +15,7 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).
### Changed
* Allow session tickets to be disabled in Apache when mod_ssl is statically linked.
* Generalize UI warning message on renewal rate limits
* Certbot behaves similarly on Windows to on UNIX systems regarding umask, and
the umask `022` is applied by default: all files/directories are not writable by anyone
other than the user running Certbot and the system/admin users.
@ -27,6 +28,9 @@ Certbot adheres to [Semantic Versioning](https://semver.org/).
* Don't use `StrictVersion`, but `LooseVersion` to check version requirements with setuptools,
to fix some packaging issues with libraries respecting PEP404 for version string,
with doesn't match `StrictVersion` requirements.
* Certbot output doesn't refer to SSL Labs due to confusing scoring behavior.
* Fix paths when calling to programs outside of the Certbot Snap, fixing the apache and nginx
plugins on, e.g., CentOS 7.
More details about these changes can be found on our GitHub repo.

View file

@ -228,7 +228,7 @@ def _run_hook(cmd_name, shell_cmd):
:type shell_cmd: `list` of `str` or `str`
:returns: stderr if there was any"""
err, _ = misc.execute_command(cmd_name, shell_cmd)
err, _ = misc.execute_command(cmd_name, shell_cmd, env=util.env_no_snap_for_external_calls())
return err

View file

@ -209,7 +209,7 @@ def _handle_identical_cert_request(config, lineage):
elif config.verb == "certonly":
keep_opt = "Keep the existing certificate for now"
choices = [keep_opt,
"Renew & replace the cert (limit ~5 per 7 days)"]
"Renew & replace the cert (may be subject to CA rate limits)"]
display = zope.component.getUtility(interfaces.IDisplay)
response = display.menu(question, choices,

View file

@ -2,6 +2,7 @@
import collections
import itertools
import logging
import sys
import pkg_resources
import six
@ -12,6 +13,7 @@ from acme.magic_typing import Dict
from certbot import errors
from certbot import interfaces
from certbot._internal import constants
from certbot.compat import os
try:
# Python 3.3+
@ -198,6 +200,12 @@ class PluginsRegistry(Mapping):
def find_all(cls):
"""Find plugins using setuptools entry points."""
plugins = {} # type: Dict[str, PluginEntryPoint]
plugin_paths_string = os.getenv('CERTBOT_PLUGIN_PATH')
plugin_paths = plugin_paths_string.split(':') if plugin_paths_string else []
# XXX should ensure this only happens once
sys.path.extend(plugin_paths)
for plugin_path in plugin_paths:
pkg_resources.working_set.add_entry(plugin_path)
entry_points = itertools.chain(
pkg_resources.iter_entry_points(
constants.SETUPTOOLS_PLUGINS_ENTRY_POINT),

View file

@ -8,6 +8,7 @@ from certbot import achallenges # pylint: disable=unused-import
from certbot import errors
from certbot import interfaces
from certbot import reverter
from certbot import util
from certbot._internal import hooks
from certbot.compat import misc
from certbot.compat import os
@ -187,4 +188,5 @@ permitted by DNS standards.)
self.reverter.recovery_routine()
def _execute_hook(self, hook_name):
return misc.execute_command(self.option_name(hook_name), self.conf(hook_name))
return misc.execute_command(self.option_name(hook_name), self.conf(hook_name),
env=util.env_no_snap_for_external_calls())

View file

@ -12,7 +12,7 @@ import sys
from certbot import errors
from certbot.compat import os
from acme.magic_typing import Tuple
from acme.magic_typing import Tuple, Optional
try:
from win32com.shell import shell as shellwin32
@ -116,8 +116,8 @@ def underscores_for_unsupported_characters_in_path(path):
return drive + tail.replace(':', '_')
def execute_command(cmd_name, shell_cmd):
# type: (str, str) -> Tuple[str, str]
def execute_command(cmd_name, shell_cmd, env=None):
# type: (str, str, Optional[dict]) -> Tuple[str, str]
"""
Run a command:
- on Linux command will be run by the standard shell selected with Popen(shell=True)
@ -125,6 +125,7 @@ def execute_command(cmd_name, shell_cmd):
:param str cmd_name: the user facing name of the hook being run
:param str shell_cmd: shell command to execute
:param dict env: environ to pass into Popen
:returns: `tuple` (`str` stderr, `str` stdout)
"""
@ -132,11 +133,12 @@ def execute_command(cmd_name, shell_cmd):
if POSIX_MODE:
cmd = subprocess.Popen(shell_cmd, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, universal_newlines=True)
stderr=subprocess.PIPE, universal_newlines=True,
env=env)
else:
line = ['powershell.exe', '-Command', shell_cmd]
cmd = subprocess.Popen(line, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True)
universal_newlines=True, env=env)
# universal_newlines causes Popen.communicate()
# to return str objects instead of bytes in Python 3

View file

@ -241,11 +241,8 @@ def success_installation(domains):
"""
z_util(interfaces.IDisplay).notification(
"Congratulations! You have successfully enabled {0}{1}{1}"
"You should test your configuration at:{1}{2}".format(
_gen_https_names(domains),
os.linesep,
os.linesep.join(_gen_ssl_lab_urls(domains))),
"Congratulations! You have successfully enabled {0}".format(
_gen_https_names(domains)),
pause=False)
@ -258,13 +255,12 @@ def success_renewal(domains):
z_util(interfaces.IDisplay).notification(
"Your existing certificate has been successfully renewed, and the "
"new certificate has been installed.{1}{1}"
"The new certificate covers the following domains: {0}{1}{1}"
"You should test your configuration at:{1}{2}".format(
"The new certificate covers the following domains: {0}".format(
_gen_https_names(domains),
os.linesep,
os.linesep.join(_gen_ssl_lab_urls(domains))),
os.linesep),
pause=False)
def success_revocation(cert_path):
"""Display a box confirming a certificate has been revoked.

View file

@ -51,7 +51,8 @@ class RevocationChecker(object):
# New versions of openssl want -header var=val, old ones want -header var val
test_host_format = Popen(["openssl", "ocsp", "-header", "var", "val"],
stdout=PIPE, stderr=PIPE, universal_newlines=True)
stdout=PIPE, stderr=PIPE, universal_newlines=True,
env=util.env_no_snap_for_external_calls())
_out, err = test_host_format.communicate()
if "Missing =" in err:
self.host_args = lambda host: ["Host=" + host]

View file

@ -61,6 +61,31 @@ _INITIAL_PID = os.getpid()
_LOCKS = OrderedDict() # type: OrderedDict[str, lock.LockFile]
def env_no_snap_for_external_calls():
"""
When Certbot is run inside a Snap, certain environment variables
are modified. But Certbot sometimes calls out to external programs,
since it uses classic confinement. When we do that, we must modify
the env to remove our modifications so it will use the system's
libraries, since they may be incompatible with the versions of
libraries included in the Snap. For example, apachectl, Nginx, and
anything run from inside a hook should call this function and pass
the results into the ``env`` argument of ``subprocess.Popen``.
:returns: A modified copy of os.environ ready to pass to Popen
:rtype: dict
"""
env = os.environ.copy()
# Avoid accidentally modifying env
if 'SNAP' not in env or 'CERTBOT_SNAPPED' not in env:
return env
for path_name in ('PATH', 'LD_LIBRARY_PATH'):
if path_name in env:
env[path_name] = ':'.join(x for x in env[path_name].split(':') if env['SNAP'] not in x)
return env
def run_script(params, log=logger.error):
"""Run the script with the given params.
@ -72,7 +97,8 @@ def run_script(params, log=logger.error):
proc = subprocess.Popen(params,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
universal_newlines=True)
universal_newlines=True,
env=env_no_snap_for_external_calls())
except (OSError, ValueError):
msg = "Unable to run the command: %s" % " ".join(params)
@ -377,12 +403,14 @@ def get_python_os_info(pretty=False):
["/usr/bin/sw_vers", "-productVersion"],
stdout=subprocess.PIPE,
universal_newlines=True,
env=env_no_snap_for_external_calls(),
)
except OSError:
proc = subprocess.Popen(
["sw_vers", "-productVersion"],
stdout=subprocess.PIPE,
universal_newlines=True,
env=env_no_snap_for_external_calls(),
)
os_ver = proc.communicate()[0].rstrip('\n')
elif os_type.startswith('freebsd'):

View file

@ -110,8 +110,7 @@ to most-backwards compatible). The client will follow the Mozilla defaults
for the *Intermediate* configuration by default, at least with regards to
ciphersuites and TLS versions. Mozilla's web site describes which client
software will be compatible with each configuration. You can also use
the Qualys SSL Labs site, which Certbot will suggest
when installing a certificate, to test your server and see whether it
the Qualys SSL Labs site to test your server and see whether it
will be compatible with particular software versions.
The Let's Encrypt project expects to follow the Mozilla recommendations

View file

@ -122,7 +122,7 @@ class PreHookTest(HookTest):
def _test_nonrenew_common(self):
mock_execute = self._call_with_mock_execute(self.config)
mock_execute.assert_called_once_with("pre-hook", self.config.pre_hook)
mock_execute.assert_called_once_with("pre-hook", self.config.pre_hook, env=mock.ANY)
self._test_no_executions_common()
def test_no_hooks(self):
@ -138,21 +138,21 @@ class PreHookTest(HookTest):
def test_renew_disabled_dir_hooks(self):
self.config.directory_hooks = False
mock_execute = self._call_with_mock_execute(self.config)
mock_execute.assert_called_once_with("pre-hook", self.config.pre_hook)
mock_execute.assert_called_once_with("pre-hook", self.config.pre_hook, env=mock.ANY)
self._test_no_executions_common()
def test_renew_no_overlap(self):
self.config.verb = "renew"
mock_execute = self._call_with_mock_execute(self.config)
mock_execute.assert_any_call("pre-hook", self.dir_hook)
mock_execute.assert_called_with("pre-hook", self.config.pre_hook)
mock_execute.assert_any_call("pre-hook", self.dir_hook, env=mock.ANY)
mock_execute.assert_called_with("pre-hook", self.config.pre_hook, env=mock.ANY)
self._test_no_executions_common()
def test_renew_with_overlap(self):
self.config.pre_hook = self.dir_hook
self.config.verb = "renew"
mock_execute = self._call_with_mock_execute(self.config)
mock_execute.assert_called_once_with("pre-hook", self.dir_hook)
mock_execute.assert_called_once_with("pre-hook", self.dir_hook, env=mock.ANY)
self._test_no_executions_common()
def _test_no_executions_common(self):
@ -194,7 +194,7 @@ class PostHookTest(HookTest):
for verb in ("certonly", "run",):
self.config.verb = verb
mock_execute = self._call_with_mock_execute(self.config)
mock_execute.assert_called_once_with("post-hook", self.config.post_hook)
mock_execute.assert_called_once_with("post-hook", self.config.post_hook, env=mock.ANY)
self.assertFalse(self._get_eventually())
def test_cert_only_and_run_without_hook(self):
@ -283,7 +283,7 @@ class RunSavedPostHooksTest(HookTest):
def test_single(self):
self.eventually = ["foo"]
mock_execute = self._call_with_mock_execute_and_eventually()
mock_execute.assert_called_once_with("post-hook", self.eventually[0])
mock_execute.assert_called_once_with("post-hook", self.eventually[0], env=mock.ANY)
class RenewalHookTest(HookTest):
@ -361,7 +361,7 @@ class DeployHookTest(RenewalHookTest):
self.config.deploy_hook = "foo"
mock_execute = self._call_with_mock_execute(
self.config, domains, lineage)
mock_execute.assert_called_once_with("deploy-hook", self.config.deploy_hook)
mock_execute.assert_called_once_with("deploy-hook", self.config.deploy_hook, env=mock.ANY)
class RenewHookTest(RenewalHookTest):
@ -385,7 +385,7 @@ class RenewHookTest(RenewalHookTest):
self.config.directory_hooks = False
mock_execute = self._call_with_mock_execute(
self.config, ["example.org"], "/foo/bar")
mock_execute.assert_called_once_with("deploy-hook", self.config.renew_hook)
mock_execute.assert_called_once_with("deploy-hook", self.config.renew_hook, env=mock.ANY)
@mock.patch("certbot._internal.hooks.logger")
def test_dry_run(self, mock_logger):
@ -409,13 +409,13 @@ class RenewHookTest(RenewalHookTest):
self.config.renew_hook = self.dir_hook
mock_execute = self._call_with_mock_execute(
self.config, ["example.net", "example.org"], "/foo/bar")
mock_execute.assert_called_once_with("deploy-hook", self.dir_hook)
mock_execute.assert_called_once_with("deploy-hook", self.dir_hook, env=mock.ANY)
def test_no_overlap(self):
mock_execute = self._call_with_mock_execute(
self.config, ["example.org"], "/foo/bar")
mock_execute.assert_any_call("deploy-hook", self.dir_hook)
mock_execute.assert_called_with("deploy-hook", self.config.renew_hook)
mock_execute.assert_any_call("deploy-hook", self.dir_hook, env=mock.ANY)
mock_execute.assert_called_with("deploy-hook", self.config.renew_hook, env=mock.ANY)
class ListHooksTest(test_util.TempDirTestCase):

View file

@ -17,6 +17,40 @@ from certbot.compat import os
import certbot.tests.util as test_util
class EnvNoSnapForExternalCallsTest(unittest.TestCase):
"""Tests for certbot.util.env_no_snap_for_external_calls."""
@classmethod
def _call(cls):
from certbot.util import env_no_snap_for_external_calls
return env_no_snap_for_external_calls()
def test_removed(self):
original_path = os.environ['PATH']
env_copy_dict = os.environ.copy()
env_copy_dict['PATH'] = 'RANDOM_NONSENSE_GARBAGE/blah/blah:' + original_path
env_copy_dict['SNAP'] = 'RANDOM_NONSENSE_GARBAGE'
env_copy_dict['CERTBOT_SNAPPED'] = 'True'
with mock.patch('certbot.compat.os.environ.copy', return_value=env_copy_dict):
self.assertEqual(self._call()['PATH'], original_path)
def test_noop(self):
env_copy_dict_unmodified = os.environ.copy()
env_copy_dict_unmodified['PATH'] = 'RANDOM_NONSENSE_GARBAGE/blah/blah:' \
+ env_copy_dict_unmodified['PATH']
env_copy_dict = env_copy_dict_unmodified.copy()
with mock.patch('certbot.compat.os.environ.copy', return_value=env_copy_dict):
# contains neither necessary key
env_copy_dict.pop('SNAP', None)
env_copy_dict.pop('CERTBOT_SNAPPED', None)
self.assertEqual(self._call()['PATH'], env_copy_dict_unmodified['PATH'])
# contains only one necessary key
env_copy_dict['SNAP'] = 'RANDOM_NONSENSE_GARBAGE'
self.assertEqual(self._call()['PATH'], env_copy_dict_unmodified['PATH'])
del env_copy_dict['SNAP']
env_copy_dict['CERTBOT_SNAPPED'] = 'True'
self.assertEqual(self._call()['PATH'], env_copy_dict_unmodified['PATH'])
class RunScriptTest(unittest.TestCase):
"""Tests for certbot.util.run_script."""
@classmethod

View file

@ -66,23 +66,22 @@ These steps need to be done once to set up your VM and do not need to be run aga
5. Add your current user to the lxd group and update your shell to have the new assignment by running `sudo usermod -a -G lxd ${USER} && newgrp lxd`.
6. Install snapcraft with `sudo snap install --classic snapcraft`.
7. `cd ~` (or any other directory where you want our source files to be)
8. Run `git clone git://github.com/certbot/certbot -b snap-plugin`
8. Run `git clone git://github.com/certbot/certbot`
9. `cd certbot`
### Build the Snaps
These are the steps to build and install the snaps. If you have run these steps before, you may want to run the commands in the section below to clean things up before building the snap again.
1. Run `tools/strip_hashes.py letsencrypt-auto-source/pieces/dependency-requirements.txt | grep -v python-augeas > snap-constraints.txt` (this is a workaround for https://github.com/certbot/certbot/issues/7957).
2. Run `snapcraft --use-lxd`.
3. Install the generated snap with `sudo snap install --dangerous --classic certbot_*_amd64.snap`. You can transfer the snap to a different machine to run it there instead if you prefer.
4. Run `tools/strip_hashes.py letsencrypt-auto-source/pieces/dependency-requirements.txt > certbot-dns-dnsimple/snap-constraints.txt`.
5. `cd certbot-dns-dnsimple`
6. `snapcraft --use-lxd`
7. Run `sudo snap set certbot trust-plugin-with-root=ok`.
8. Install the generated snap with `sudo snap install --dangerous certbot-dns-dnsimple_*_amd64.snap`. Again, you can transfer the snap to a different machine to run it there instead if you prefer.
9. Connect the plugin with `sudo snap connect certbot:plugin certbot-dns-dnsimple`.
10. Now you can run Certbot as normal. For example, `certbot plugins` should display the DNSimple plugin as installed.
1. Run `snapcraft --use-lxd`.
2. Install the generated snap with `sudo snap install --dangerous --classic certbot_*_amd64.snap`. You can transfer the snap to a different machine to run it there instead if you prefer.
3. Run `tools/merge_requirements.py tools/dev_constraints.txt <(tools/strip_hashes.py letsencrypt-auto-source/pieces/dependency-requirements.txt) > certbot-dns-dnsimple/snap-constraints.txt` (this is a workaround for https://github.com/certbot/certbot/issues/8100).
4. `cd certbot-dns-dnsimple`
5. `snapcraft --use-lxd`
6. Run `sudo snap set certbot trust-plugin-with-root=ok`.
7. Install the generated snap with `sudo snap install --dangerous certbot-dns-dnsimple_*_amd64.snap`. Again, you can transfer the snap to a different machine to run it there instead if you prefer.
8. Connect the plugin with `sudo snap connect certbot:plugin certbot-dns-dnsimple`.
9. Now you can run Certbot as normal. For example, `certbot plugins` should display the DNSimple plugin as installed.
### Reset the Environment

View file

@ -21,9 +21,6 @@ source "${DIR}/common.sh"
RegisterQemuHandlers
ResolveArch "${SNAP_ARCH}"
tools/strip_hashes.py letsencrypt-auto-source/pieces/dependency-requirements.txt \
| grep -v python-augeas > snap-constraints.txt
pushd "${DIR}/packages"
"${CERTBOT_DIR}/tools/simple_http_server.py" 8080 >/dev/null 2>&1 &
HTTP_SERVER_PID="$!"

View file

@ -25,6 +25,7 @@ apps:
PATH: "$SNAP/bin:$SNAP/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"
AUGEAS_LENS_LIB: "$SNAP/usr/share/augeas/lenses/dist"
LD_LIBRARY_PATH: "$SNAP/usr/lib/x86_64-linux-gnu/:$LD_LIBRARY_PATH"
CERTBOT_SNAPPED: "True"
renew:
command: certbot.wrapper -q renew
daemon: oneshot
@ -32,6 +33,7 @@ apps:
PATH: "$SNAP/bin:$SNAP/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games"
AUGEAS_LENS_LIB: $SNAP/usr/share/augeas/lenses/dist
LD_LIBRARY_PATH: "$SNAP/usr/lib/x86_64-linux-gnu/:$LD_LIBRARY_PATH"
CERTBOT_SNAPPED: "True"
# Run approximately twice a day with randomization
timer: 00:00~24:00/2
@ -49,8 +51,13 @@ parts:
- ./certbot-nginx
stage:
- -usr/lib/python3.8/sitecustomize.py # maybe unnecessary
# Prefer cffi
- -lib/python3.8/site-packages/augeas.py
# Old versions of this file used to unstage
# lib/python3.8/site-packages/augeas.py to avoid conflicts between
# python-augeas 0.5.0 which was pinned in snap-constraints.txt and
# Robie's python-augeas fork which creates an auto-generated cffi file at
# the same path. Since we've combined things in one part and removed the
# python-augeas pinning, unstaging this file had a different, unintended
# effect so we now stage the file to keep the auto-generated cffi file.
stage-packages:
- libaugeas0
# added to stage python:
@ -69,7 +76,9 @@ parts:
build-packages: [libffi-dev, libssl-dev, git, libaugeas-dev, python3-dev]
override-pull: |
snapcraftctl pull
snapcraftctl set-version `cd $SNAPCRAFT_PART_SRC/certbot && git describe|sed s/^v//`
cd $SNAPCRAFT_PART_SRC
python3 tools/strip_hashes.py letsencrypt-auto-source/pieces/dependency-requirements.txt | grep -v python-augeas > snap-constraints.txt
snapcraftctl set-version `git describe|sed s/^v//`
wrappers:
plugin: dump

View file

@ -1,19 +1,23 @@
awscli==1.18.88
bcrypt==3.1.7
boto3==1.12.7
botocore==1.15.7
boto3==1.14.11
botocore==1.17.11
cffi==1.14.0
colorama==0.4.3
cryptography==2.8
docutils==0.15.2
enum34==1.1.9
Fabric==2.5.0
fabric==2.5.0
invoke==1.4.1
ipaddress==1.0.23
Invoke==1.4.1
jmespath==0.9.5
paramiko==2.7.1
pyasn1==0.4.8
pycparser==2.19
PyNaCl==1.3.0
python-dateutil==2.8.1
PyYAML==5.3
rsa==3.4.2
s3transfer==0.3.3
six==1.14.0
urllib3==1.25.8

View file

@ -0,0 +1,39 @@
#!/bin/bash
# Generate the snapcraft.yaml file for all DNS plugins
set -e
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
CERTBOT_DIR="$(dirname "${DIR}")"
for PLUGIN_PATH in "${CERTBOT_DIR}"/certbot-dns-*; do
PLUGIN=$(basename "${PLUGIN_PATH}")
DESCRIPTION=$(grep description "${PLUGIN_PATH}/setup.py" | sed -E 's|\s+description="(.*)",|\1|g')
mkdir -p "${PLUGIN_PATH}/snap"
cat <<EOF > "${PLUGIN_PATH}/snap/snapcraft.yaml"
name: ${PLUGIN}
summary: ${DESCRIPTION}
description: ${DESCRIPTION}
confinement: strict
grade: devel
base: core20
adopt-info: ${PLUGIN}
parts:
${PLUGIN}:
plugin: python
source: .
constraints: [\$SNAPCRAFT_PART_SRC/snap-constraints.txt]
override-pull: |
snapcraftctl pull
snapcraftctl set-version \`grep ^version \$SNAPCRAFT_PART_SRC/setup.py | cut -f2 -d= | tr -d "'[:space:]"\`
build-environment:
- EXCLUDE_CERTBOT_DEPS: "True"
slots:
certbot:
interface: content
content: certbot-1
read:
- \$SNAP/lib/python3.8/site-packages
EOF
done