diff --git a/.azure-pipelines/templates/jobs/packaging-jobs.yml b/.azure-pipelines/templates/jobs/packaging-jobs.yml index 0a25e7cf5..18fae075a 100644 --- a/.azure-pipelines/templates/jobs/packaging-jobs.yml +++ b/.azure-pipelines/templates/jobs/packaging-jobs.yml @@ -63,8 +63,6 @@ jobs: matrix: amd64: ARCH: amd64 - i386: - ARCH: i386 arm64: ARCH: arm64 armhf: diff --git a/AUTHORS.md b/AUTHORS.md index a00d20375..6b6b5d118 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -85,6 +85,7 @@ Authors * [Felix Schwarz](https://github.com/FelixSchwarz) * [Felix Yan](https://github.com/felixonmars) * [Filip Ochnik](https://github.com/filipochnik) +* [Florian Klink](https://github.com/flokli) * [Francois Marier](https://github.com/fmarier) * [Frank](https://github.com/Frankkkkk) * [Frederic BLANC](https://github.com/fblanc) diff --git a/acme/setup.py b/acme/setup.py index c993b0f2e..3d0cbf126 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -1,4 +1,4 @@ -from distutils.version import StrictVersion +from distutils.version import LooseVersion import sys from setuptools import __version__ as setuptools_version @@ -27,7 +27,7 @@ install_requires = [ 'six>=1.9.0', # needed for python_2_unicode_compatible ] -setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2')) +setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) if setuptools_known_environment_markers: install_requires.append('mock ; python_version < "3.3"') elif 'bdist_wheel' in sys.argv[1:]: diff --git a/certbot-apache/setup.py b/certbot-apache/setup.py index 719bea004..54ff59ff1 100644 --- a/certbot-apache/setup.py +++ b/certbot-apache/setup.py @@ -1,4 +1,4 @@ -from distutils.version import StrictVersion +from distutils.version import LooseVersion import sys from setuptools import __version__ as setuptools_version @@ -19,7 +19,7 @@ install_requires = [ 'zope.interface', ] -setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2')) +setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) if setuptools_known_environment_markers: install_requires.append('mock ; python_version < "3.3"') elif 'bdist_wheel' in sys.argv[1:]: diff --git a/certbot-ci/setup.py b/certbot-ci/setup.py index 75d2cc96a..128eab18a 100644 --- a/certbot-ci/setup.py +++ b/certbot-ci/setup.py @@ -1,4 +1,4 @@ -from distutils.version import StrictVersion +from distutils.version import LooseVersion import sys from setuptools import __version__ as setuptools_version @@ -26,7 +26,7 @@ install_requires = [ # However environment markers are supported only with setuptools >= 36.2. # So this dependency is not added for old Linux distributions with old setuptools, # in order to allow these systems to build certbot from sources. -if StrictVersion(setuptools_version) >= StrictVersion('36.2'): +if LooseVersion(setuptools_version) >= LooseVersion('36.2'): install_requires.append("pywin32>=224 ; sys_platform == 'win32'") elif 'bdist_wheel' in sys.argv[1:]: raise RuntimeError('Error, you are trying to build certbot wheels using an old version ' diff --git a/certbot-compatibility-test/setup.py b/certbot-compatibility-test/setup.py index 9a646d7ce..53875123f 100644 --- a/certbot-compatibility-test/setup.py +++ b/certbot-compatibility-test/setup.py @@ -1,4 +1,4 @@ -from distutils.version import StrictVersion +from distutils.version import LooseVersion import sys from setuptools import __version__ as setuptools_version @@ -15,7 +15,7 @@ install_requires = [ 'zope.interface', ] -setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2')) +setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) if setuptools_known_environment_markers: install_requires.append('mock ; python_version < "3.3"') elif 'bdist_wheel' in sys.argv[1:]: diff --git a/certbot-dns-cloudflare/certbot_dns_cloudflare/__init__.py b/certbot-dns-cloudflare/certbot_dns_cloudflare/__init__.py index 11886ea54..d59862a3c 100644 --- a/certbot-dns-cloudflare/certbot_dns_cloudflare/__init__.py +++ b/certbot-dns-cloudflare/certbot_dns_cloudflare/__init__.py @@ -21,8 +21,8 @@ Credentials ----------- Use of this plugin requires a configuration file containing Cloudflare API -credentials, obtained from your Cloudflare -`account page `_. +credentials, obtained from your +`Cloudflare dashboard `_. Previously, Cloudflare's "Global API Key" was used for authentication, however this key can access the entire Cloudflare API for all domains in your account, @@ -31,11 +31,8 @@ meaning it could cause a lot of damage if leaked. Cloudflare's newer API Tokens can be restricted to specific domains and operations, and are therefore now the recommended authentication option. -However, due to some shortcomings in Cloudflare's implementation of Tokens, -Tokens created for Certbot currently require ``Zone:Zone:Read`` and ``Zone:DNS:Edit`` -permissions for **all** zones in your account. While this is not ideal, your Token -will still have fewer permission than the Global key, so it's still worth doing. -Hopefully Cloudflare will improve this in the future. +The Token needed by Certbot requires ``Zone:DNS:Edit`` permissions for only the +zones you need certificates for. Using Cloudflare Tokens also requires at least version 2.3.1 of the ``cloudflare`` python module. If the version that automatically installed with this plugin is diff --git a/certbot-dns-cloudflare/certbot_dns_cloudflare/_internal/dns_cloudflare.py b/certbot-dns-cloudflare/certbot_dns_cloudflare/_internal/dns_cloudflare.py index 22dbcfa1f..5978af85c 100644 --- a/certbot-dns-cloudflare/certbot_dns_cloudflare/_internal/dns_cloudflare.py +++ b/certbot-dns-cloudflare/certbot_dns_cloudflare/_internal/dns_cloudflare.py @@ -14,7 +14,7 @@ from certbot.plugins import dns_common logger = logging.getLogger(__name__) -ACCOUNT_URL = 'https://dash.cloudflare.com/profile/api-tokens' +ACCOUNT_URL = 'https://dash.cloudflare.com/?to=/:account/profile/api-tokens' @zope.interface.implementer(interfaces.IAuthenticator) @@ -118,7 +118,7 @@ class _CloudflareClient(object): code = int(e) hint = None - if code == 9109: + if code == 1009: hint = 'Does your API token have "Zone:DNS:Edit" permissions?' logger.error('Encountered CloudFlareAPIError adding TXT record: %d %s', e, e) @@ -210,11 +210,22 @@ class _CloudflareClient(object): logger.debug('Found zone_id of %s for %s using name %s', zone_id, domain, zone_name) return zone_id - raise errors.PluginError('Unable to determine zone_id for {0} using zone names: {1}. ' - 'Please confirm that the domain name has been entered correctly ' - 'and is already associated with the supplied Cloudflare account.{2}' - .format(domain, zone_name_guesses, ' The error from Cloudflare was:' - ' {0} {1}'.format(code, msg) if code is not None else '')) + if msg is not None: + if 'com.cloudflare.api.account.zone.list' in msg: + raise errors.PluginError('Unable to determine zone_id for {0} using zone names: ' + '{1}. Please confirm that the domain name has been ' + 'entered correctly and your Cloudflare Token has access ' + 'to the domain.'.format(domain, zone_name_guesses)) + else: + raise errors.PluginError('Unable to determine zone_id for {0} using zone names: ' + '{1}. The error from Cloudflare was: {2} {3}.' + .format(domain, zone_name_guesses, code, msg)) + else: + raise errors.PluginError('Unable to determine zone_id for {0} using zone names: ' + '{1}. Please confirm that the domain name has been ' + 'entered correctly and is already associated with the ' + 'supplied Cloudflare account.' + .format(domain, zone_name_guesses)) def _find_txt_record_id(self, zone_id, record_name, record_content): """ diff --git a/certbot-dns-cloudflare/setup.py b/certbot-dns-cloudflare/setup.py index 91c3683b6..54b31b44e 100644 --- a/certbot-dns-cloudflare/setup.py +++ b/certbot-dns-cloudflare/setup.py @@ -1,4 +1,4 @@ -from distutils.version import StrictVersion +from distutils.version import LooseVersion import sys from setuptools import __version__ as setuptools_version @@ -18,7 +18,7 @@ install_requires = [ 'zope.interface', ] -setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2')) +setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) if setuptools_known_environment_markers: install_requires.append('mock ; python_version < "3.3"') elif 'bdist_wheel' in sys.argv[1:]: diff --git a/certbot-dns-cloudflare/tests/dns_cloudflare_test.py b/certbot-dns-cloudflare/tests/dns_cloudflare_test.py index 4d2dcf4ca..e9adf4ed9 100644 --- a/certbot-dns-cloudflare/tests/dns_cloudflare_test.py +++ b/certbot-dns-cloudflare/tests/dns_cloudflare_test.py @@ -133,7 +133,7 @@ class CloudflareClientTest(unittest.TestCase): def test_add_txt_record_error(self): self.cf.zones.get.return_value = [{'id': self.zone_id}] - self.cf.zones.dns_records.post.side_effect = CloudFlare.exceptions.CloudFlareAPIError(9109, '', '') + self.cf.zones.dns_records.post.side_effect = CloudFlare.exceptions.CloudFlareAPIError(1009, '', '') self.assertRaises( errors.PluginError, @@ -175,6 +175,12 @@ class CloudflareClientTest(unittest.TestCase): self.cloudflare_client.add_txt_record, DOMAIN, self.record_name, self.record_content, self.record_ttl) + self.cf.zones.get.side_effect = CloudFlare.exceptions.CloudFlareAPIError(0, 'com.cloudflare.api.account.zone.list', '') + self.assertRaises( + errors.PluginError, + self.cloudflare_client.add_txt_record, + DOMAIN, self.record_name, self.record_content, self.record_ttl) + def test_del_txt_record(self): self.cf.zones.get.return_value = [{'id': self.zone_id}] self.cf.zones.dns_records.get.return_value = [{'id': self.record_id}] diff --git a/certbot-dns-cloudxns/setup.py b/certbot-dns-cloudxns/setup.py index 579637dab..7d3097976 100644 --- a/certbot-dns-cloudxns/setup.py +++ b/certbot-dns-cloudxns/setup.py @@ -1,4 +1,4 @@ -from distutils.version import StrictVersion +from distutils.version import LooseVersion import sys from setuptools import __version__ as setuptools_version @@ -18,7 +18,7 @@ install_requires = [ 'zope.interface', ] -setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2')) +setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) if setuptools_known_environment_markers: install_requires.append('mock ; python_version < "3.3"') elif 'bdist_wheel' in sys.argv[1:]: diff --git a/certbot-dns-digitalocean/setup.py b/certbot-dns-digitalocean/setup.py index d30167a14..32376aff8 100644 --- a/certbot-dns-digitalocean/setup.py +++ b/certbot-dns-digitalocean/setup.py @@ -1,4 +1,4 @@ -from distutils.version import StrictVersion +from distutils.version import LooseVersion import sys from setuptools import __version__ as setuptools_version @@ -19,7 +19,7 @@ install_requires = [ 'zope.interface', ] -setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2')) +setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) if setuptools_known_environment_markers: install_requires.append('mock ; python_version < "3.3"') elif 'bdist_wheel' in sys.argv[1:]: diff --git a/certbot-dns-dnsimple/setup.py b/certbot-dns-dnsimple/setup.py index 9ba71a7ea..769a1c032 100644 --- a/certbot-dns-dnsimple/setup.py +++ b/certbot-dns-dnsimple/setup.py @@ -1,4 +1,4 @@ -from distutils.version import StrictVersion +from distutils.version import LooseVersion import os import sys @@ -12,13 +12,20 @@ version = '1.6.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. install_requires = [ - 'acme>=0.31.0', - 'certbot>=1.1.0', 'setuptools', 'zope.interface', ] -setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2')) +if not os.environ.get('EXCLUDE_CERTBOT_DEPS'): + install_requires.extend([ + 'acme>=0.31.0', + 'certbot>=1.1.0', + ]) +elif 'bdist_wheel' in sys.argv[1:]: + raise RuntimeError('Unset EXCLUDE_CERTBOT_DEPS when building wheels ' + 'to include certbot dependencies.') + +setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) if setuptools_known_environment_markers: install_requires.append('mock ; python_version < "3.3"') elif 'bdist_wheel' in sys.argv[1:]: diff --git a/certbot-dns-dnsimple/snap/snapcraft.yaml b/certbot-dns-dnsimple/snap/snapcraft.yaml new file mode 100644 index 000000000..64be45436 --- /dev/null +++ b/certbot-dns-dnsimple/snap/snapcraft.yaml @@ -0,0 +1,26 @@ +name: certbot-dns-dnsimple +summary: DNSimple DNS Authenticator plugin for Certbot +description: TBC +confinement: strict +grade: devel +base: core18 +adopt-info: certbot-dns-dnsimple + +parts: + certbot-dns-dnsimple: + 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:]"` + build-environment: + - EXCLUDE_CERTBOT_DEPS: "True" + +slots: + certbot: + interface: content + content: certbot-1 + read: + - $SNAP/lib/python3.6/site-packages diff --git a/certbot-dns-dnsmadeeasy/setup.py b/certbot-dns-dnsmadeeasy/setup.py index a5e025e66..01525afca 100644 --- a/certbot-dns-dnsmadeeasy/setup.py +++ b/certbot-dns-dnsmadeeasy/setup.py @@ -1,4 +1,4 @@ -from distutils.version import StrictVersion +from distutils.version import LooseVersion import sys from setuptools import __version__ as setuptools_version @@ -18,7 +18,7 @@ install_requires = [ 'zope.interface', ] -setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2')) +setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) if setuptools_known_environment_markers: install_requires.append('mock ; python_version < "3.3"') elif 'bdist_wheel' in sys.argv[1:]: diff --git a/certbot-dns-gehirn/setup.py b/certbot-dns-gehirn/setup.py index 8965e6b8c..224ea53b2 100644 --- a/certbot-dns-gehirn/setup.py +++ b/certbot-dns-gehirn/setup.py @@ -1,4 +1,4 @@ -from distutils.version import StrictVersion +from distutils.version import LooseVersion import sys from setuptools import __version__ as setuptools_version @@ -17,7 +17,7 @@ install_requires = [ 'zope.interface', ] -setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2')) +setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) if setuptools_known_environment_markers: install_requires.append('mock ; python_version < "3.3"') elif 'bdist_wheel' in sys.argv[1:]: diff --git a/certbot-dns-google/setup.py b/certbot-dns-google/setup.py index 27c5e6b05..de9d172bb 100644 --- a/certbot-dns-google/setup.py +++ b/certbot-dns-google/setup.py @@ -1,4 +1,4 @@ -from distutils.version import StrictVersion +from distutils.version import LooseVersion import sys from setuptools import __version__ as setuptools_version @@ -21,7 +21,7 @@ install_requires = [ 'httplib2' ] -setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2')) +setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) if setuptools_known_environment_markers: install_requires.append('mock ; python_version < "3.3"') elif 'bdist_wheel' in sys.argv[1:]: diff --git a/certbot-dns-linode/setup.py b/certbot-dns-linode/setup.py index ebe9660fa..068c04b06 100644 --- a/certbot-dns-linode/setup.py +++ b/certbot-dns-linode/setup.py @@ -1,4 +1,4 @@ -from distutils.version import StrictVersion +from distutils.version import LooseVersion import sys from setuptools import __version__ as setuptools_version @@ -17,7 +17,7 @@ install_requires = [ 'zope.interface', ] -setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2')) +setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) if setuptools_known_environment_markers: install_requires.append('mock ; python_version < "3.3"') elif 'bdist_wheel' in sys.argv[1:]: diff --git a/certbot-dns-luadns/setup.py b/certbot-dns-luadns/setup.py index 21daf4c57..d9723491c 100644 --- a/certbot-dns-luadns/setup.py +++ b/certbot-dns-luadns/setup.py @@ -1,4 +1,4 @@ -from distutils.version import StrictVersion +from distutils.version import LooseVersion import sys from setuptools import __version__ as setuptools_version @@ -18,7 +18,7 @@ install_requires = [ 'zope.interface', ] -setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2')) +setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) if setuptools_known_environment_markers: install_requires.append('mock ; python_version < "3.3"') elif 'bdist_wheel' in sys.argv[1:]: diff --git a/certbot-dns-nsone/setup.py b/certbot-dns-nsone/setup.py index ad42991f9..073b6458c 100644 --- a/certbot-dns-nsone/setup.py +++ b/certbot-dns-nsone/setup.py @@ -1,4 +1,4 @@ -from distutils.version import StrictVersion +from distutils.version import LooseVersion import sys from setuptools import __version__ as setuptools_version @@ -18,7 +18,7 @@ install_requires = [ 'zope.interface', ] -setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2')) +setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) if setuptools_known_environment_markers: install_requires.append('mock ; python_version < "3.3"') elif 'bdist_wheel' in sys.argv[1:]: diff --git a/certbot-dns-ovh/setup.py b/certbot-dns-ovh/setup.py index eee6ddc82..10d22e7a7 100644 --- a/certbot-dns-ovh/setup.py +++ b/certbot-dns-ovh/setup.py @@ -1,4 +1,4 @@ -from distutils.version import StrictVersion +from distutils.version import LooseVersion import sys from setuptools import __version__ as setuptools_version @@ -18,7 +18,7 @@ install_requires = [ 'zope.interface', ] -setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2')) +setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) if setuptools_known_environment_markers: install_requires.append('mock ; python_version < "3.3"') elif 'bdist_wheel' in sys.argv[1:]: diff --git a/certbot-dns-rfc2136/setup.py b/certbot-dns-rfc2136/setup.py index d9863aedd..1f035d88f 100644 --- a/certbot-dns-rfc2136/setup.py +++ b/certbot-dns-rfc2136/setup.py @@ -1,4 +1,4 @@ -from distutils.version import StrictVersion +from distutils.version import LooseVersion import sys from setuptools import __version__ as setuptools_version @@ -18,7 +18,7 @@ install_requires = [ 'zope.interface', ] -setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2')) +setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) if setuptools_known_environment_markers: install_requires.append('mock ; python_version < "3.3"') elif 'bdist_wheel' in sys.argv[1:]: diff --git a/certbot-dns-route53/setup.py b/certbot-dns-route53/setup.py index c207e5db5..b0d0d1beb 100644 --- a/certbot-dns-route53/setup.py +++ b/certbot-dns-route53/setup.py @@ -1,4 +1,4 @@ -from distutils.version import StrictVersion +from distutils.version import LooseVersion import sys from setuptools import __version__ as setuptools_version @@ -18,7 +18,7 @@ install_requires = [ 'zope.interface', ] -setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2')) +setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) if setuptools_known_environment_markers: install_requires.append('mock ; python_version < "3.3"') elif 'bdist_wheel' in sys.argv[1:]: diff --git a/certbot-dns-sakuracloud/setup.py b/certbot-dns-sakuracloud/setup.py index 06ce9613e..1b4ea512e 100644 --- a/certbot-dns-sakuracloud/setup.py +++ b/certbot-dns-sakuracloud/setup.py @@ -1,4 +1,4 @@ -from distutils.version import StrictVersion +from distutils.version import LooseVersion import sys from setuptools import __version__ as setuptools_version @@ -17,7 +17,7 @@ install_requires = [ 'zope.interface', ] -setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2')) +setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) if setuptools_known_environment_markers: install_requires.append('mock ; python_version < "3.3"') elif 'bdist_wheel' in sys.argv[1:]: diff --git a/certbot-nginx/setup.py b/certbot-nginx/setup.py index 6138a06c2..073a1a4d2 100644 --- a/certbot-nginx/setup.py +++ b/certbot-nginx/setup.py @@ -1,4 +1,4 @@ -from distutils.version import StrictVersion +from distutils.version import LooseVersion import sys from setuptools import __version__ as setuptools_version @@ -19,7 +19,7 @@ install_requires = [ 'zope.interface', ] -setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2')) +setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) if setuptools_known_environment_markers: install_requires.append('mock ; python_version < "3.3"') elif 'bdist_wheel' in sys.argv[1:]: diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index 60a5d2aaa..815ad66ca 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -6,7 +6,7 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). ### Added -* Certbot snaps are now available for the i386, arm64, and armhf architectures. +* Certbot snaps are now available for the arm64 and armhf architectures. * Add minimal code to run Nginx plugin on NetBSD. * Make Certbot snap find externally snapped plugins * Function `certbot.compat.filesystem.umask` is a drop-in replacement for `os.umask` @@ -23,7 +23,10 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). ### Fixed -* +* Cloudflare API Tokens may now be restricted to individual zones. +* 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. More details about these changes can be found on our GitHub repo. diff --git a/certbot/certbot/_internal/account.py b/certbot/certbot/_internal/account.py index 61f63bda6..c36559032 100644 --- a/certbot/certbot/_internal/account.py +++ b/certbot/certbot/_internal/account.py @@ -15,6 +15,7 @@ import zope.component from acme import fields as acme_fields from acme import messages +from acme.client import ClientBase # pylint: disable=unused-import from certbot import errors from certbot import interfaces from certbot import util @@ -39,6 +40,8 @@ class Account(object): :ivar datetime.datetime creation_dt: Creation date and time (UTC). :ivar str creation_host: FQDN of host, where account has been created. + :ivar str register_to_eff: If not None, Certbot will register the provided + email during the account registration. .. note:: ``creation_dt`` and ``creation_host`` are useful in cross-machine migration scenarios. @@ -46,15 +49,16 @@ class Account(object): """ creation_dt = acme_fields.RFC3339Field("creation_dt") creation_host = jose.Field("creation_host") + register_to_eff = jose.Field("register_to_eff", omitempty=True) def __init__(self, regr, key, meta=None): self.key = key self.regr = regr self.meta = self.Meta( # pyrfc3339 drops microseconds, make sure __eq__ is sane - creation_dt=datetime.datetime.now( - tz=pytz.UTC).replace(microsecond=0), - creation_host=socket.getfqdn()) if meta is None else meta + creation_dt=datetime.datetime.now(tz=pytz.UTC).replace(microsecond=0), + creation_host=socket.getfqdn(), + register_to_eff=None) if meta is None else meta # try MD5, else use MD5 in non-security mode (e.g. for FIPS systems / RHEL) try: @@ -242,15 +246,47 @@ class AccountFileStorage(interfaces.AccountStorage): return self._load_for_server_path(account_id, self.config.server_path) def save(self, account, client): - self._save(account, client, regr_only=False) + # type: (Account, ClientBase) -> None + """Create a new account. - def save_regr(self, account, acme): - """Save the registration resource. - - :param Account account: account whose regr should be saved + :param Account account: account to create + :param ClientBase client: ACME client associated to the account """ - self._save(account, acme, regr_only=True) + try: + dir_path = self._prepare(account) + self._create(account, dir_path) + self._update_meta(account, dir_path) + self._update_regr(account, client, dir_path) + except IOError as error: + raise errors.AccountStorageError(error) + + def update_regr(self, account, client): + # type: (Account, ClientBase) -> None + """Update the registration resource. + + :param Account account: account to update + :param ClientBase client: ACME client associated to the account + + """ + try: + dir_path = self._prepare(account) + self._update_regr(account, client, dir_path) + except IOError as error: + raise errors.AccountStorageError(error) + + def update_meta(self, account): + # type: (Account) -> None + """Update the meta resource. + + :param Account account: account to update + + """ + try: + dir_path = self._prepare(account) + self._update_meta(account, dir_path) + except IOError as error: + raise errors.AccountStorageError(error) def delete(self, account_id): """Delete registration info from disk @@ -318,32 +354,36 @@ class AccountFileStorage(interfaces.AccountStorage): return dir_path - def _save(self, account, acme, regr_only): + def _prepare(self, account): + # type: (Account) -> str account_dir_path = self._account_dir_path(account.id) util.make_or_verify_dir(account_dir_path, 0o700, self.config.strict_permissions) - try: - with open(self._regr_path(account_dir_path), "w") as regr_file: - regr = account.regr - # If we have a value for new-authz, save it for forwards - # compatibility with older versions of Certbot. If we don't - # have a value for new-authz, this is an ACMEv2 directory where - # an older version of Certbot won't work anyway. - if hasattr(acme.directory, "new-authz"): - regr = RegistrationResourceWithNewAuthzrURI( - new_authzr_uri=acme.directory.new_authz, - body={}, - uri=regr.uri) - else: - regr = messages.RegistrationResource( - body={}, - uri=regr.uri) - regr_file.write(regr.json_dumps()) - if not regr_only: - with util.safe_open(self._key_path(account_dir_path), - "w", chmod=0o400) as key_file: - key_file.write(account.key.json_dumps()) - with open(self._metadata_path( - account_dir_path), "w") as metadata_file: - metadata_file.write(account.meta.json_dumps()) - except IOError as error: - raise errors.AccountStorageError(error) + return account_dir_path + + def _create(self, account, dir_path): + # type: (Account, str) -> None + with util.safe_open(self._key_path(dir_path), "w", chmod=0o400) as key_file: + key_file.write(account.key.json_dumps()) + + def _update_regr(self, account, acme, dir_path): + # type: (Account, ClientBase, str) -> None + with open(self._regr_path(dir_path), "w") as regr_file: + regr = account.regr + # If we have a value for new-authz, save it for forwards + # compatibility with older versions of Certbot. If we don't + # have a value for new-authz, this is an ACMEv2 directory where + # an older version of Certbot won't work anyway. + if hasattr(acme.directory, "new-authz"): + regr = RegistrationResourceWithNewAuthzrURI( + new_authzr_uri=acme.directory.new_authz, + body={}, + uri=regr.uri) + else: + regr = messages.RegistrationResource( + body={}, + uri=regr.uri) + regr_file.write(regr.json_dumps()) + + def _update_meta(self, account, dir_path): + with open(self._metadata_path(dir_path), "w") as metadata_file: + metadata_file.write(account.meta.json_dumps()) diff --git a/certbot/certbot/_internal/client.py b/certbot/certbot/_internal/client.py index a9bf946cc..039e246de 100644 --- a/certbot/certbot/_internal/client.py +++ b/certbot/certbot/_internal/client.py @@ -178,7 +178,7 @@ def register(config, account_storage, tos_cb=None): account.report_new_account(config) account_storage.save(acc, acme) - eff.handle_subscription(config) + eff.prepare_subscription(config, acc) return acc, acme @@ -389,6 +389,7 @@ class Client(object): authzr = self.auth_handler.handle_authorizations(orderr, best_effort) return orderr.update(authorizations=authzr) + def obtain_and_enroll_certificate(self, domains, certname): """Obtain and enroll certificate. diff --git a/certbot/certbot/_internal/eff.py b/certbot/certbot/_internal/eff.py index 586697dbb..ae8690821 100644 --- a/certbot/certbot/_internal/eff.py +++ b/certbot/certbot/_internal/eff.py @@ -4,32 +4,68 @@ import logging import requests import zope.component +from acme.magic_typing import Optional # pylint: disable=unused-import + from certbot import interfaces from certbot._internal import constants +from certbot._internal.account import Account # pylint: disable=unused-import +from certbot._internal.account import AccountFileStorage +from certbot.interfaces import IConfig # pylint: disable=unused-import logger = logging.getLogger(__name__) -def handle_subscription(config): - """High level function to take care of EFF newsletter subscriptions. +def prepare_subscription(config, acc): + # type: (IConfig, Account) -> None + """High level function to store potential EFF newsletter subscriptions. The user may be asked if they want to sign up for the newsletter if - they have not already specified. + they have not given their explicit approval or refusal using --eff-mail + or --no-eff-mail flag. - :param .IConfig config: Client configuration. + Decision about EFF subscription will be stored in the account metadata. + + :param IConfig config: Client configuration. + :param Account acc: Current client account. """ - if config.email is None: - if config.eff_email: - _report_failure("you didn't provide an e-mail address") + if config.eff_email is False: return - if config.eff_email is None: - config.eff_email = _want_subscription() - if config.eff_email: - subscribe(config.email) + if config.eff_email is True: + if config.email is None: + _report_failure("you didn't provide an e-mail address") + else: + acc.meta = acc.meta.update(register_to_eff=config.email) + elif config.email and _want_subscription(): + acc.meta = acc.meta.update(register_to_eff=config.email) + + if acc.meta.register_to_eff: + storage = AccountFileStorage(config) + storage.update_meta(acc) + + +def handle_subscription(config, acc): + # type: (IConfig, Account) -> None + """High level function to take care of EFF newsletter subscriptions. + + Once subscription is handled, it will not be handled again. + + :param IConfig config: Client configuration. + :param Account acc: Current client account. + + """ + if config.dry_run: + return + if acc.meta.register_to_eff: + subscribe(acc.meta.register_to_eff) + + acc.meta = acc.meta.update(register_to_eff=None) + storage = AccountFileStorage(config) + storage.update_meta(acc) def _want_subscription(): + # type: () -> bool """Does the user want to be subscribed to the EFF newsletter? :returns: True if we should subscribe the user, otherwise, False @@ -37,16 +73,17 @@ def _want_subscription(): """ prompt = ( - 'Would you be willing to share your email address with the ' - "Electronic Frontier Foundation, a founding partner of the Let's " - 'Encrypt project and the non-profit organization that develops ' - "Certbot? We'd like to send you email about our work encrypting " + 'Would you be willing, once your first certificate is successfully issued, ' + 'to share your email address with the Electronic Frontier Foundation, a ' + "founding partner of the Let's Encrypt project and the non-profit organization " + "that develops Certbot? We'd like to send you email about our work encrypting " "the web, EFF news, campaigns, and ways to support digital freedom. ") display = zope.component.getUtility(interfaces.IDisplay) return display.yesno(prompt, default=False) def subscribe(email): + # type: (str) -> None """Subscribe the user to the EFF mailing list. :param str email: the e-mail address to subscribe @@ -56,11 +93,13 @@ def subscribe(email): data = {'data_type': 'json', 'email': email, 'form_id': 'eff_supporters_library_subscribe_form'} + logger.info('Subscribe to the EFF mailing list (email: %s).', email) logger.debug('Sending POST request to %s:\n%s', url, data) _check_response(requests.post(url, data=data)) def _check_response(response): + # type: (requests.Response) -> None """Check for errors in the server's response. If an error occurred, it will be reported to the user. @@ -81,6 +120,7 @@ def _check_response(response): def _report_failure(reason=None): + # type: (Optional[str]) -> None """Notify the user of failing to sign them up for the newsletter. :param reason: a phrase describing what the problem was diff --git a/certbot/certbot/_internal/main.py b/certbot/certbot/_internal/main.py index 264f9667e..cd00297a9 100644 --- a/certbot/certbot/_internal/main.py +++ b/certbot/certbot/_internal/main.py @@ -721,11 +721,12 @@ def update_account(config, unused_plugins): # the v2 uri. Since it's the same object on disk, put it back to the v1 uri # so that we can also continue to use the account object with acmev1. acc.regr = acc.regr.update(uri=prev_regr_uri) - account_storage.save_regr(acc, cb_client.acme) - eff.handle_subscription(config) + account_storage.update_regr(acc, cb_client.acme) + eff.prepare_subscription(config, acc) add_msg("Your e-mail address was updated to {0}.".format(config.email)) return None + def _install_cert(config, le_client, domains, lineage=None): """Install a cert @@ -1116,6 +1117,7 @@ def run(config, plugins): display_ops.success_renewal(domains) _suggest_donation_if_appropriate(config) + eff.handle_subscription(config, le_client.account) return None @@ -1189,6 +1191,7 @@ def renew_cert(config, plugins, lineage): notify("new certificate deployed with reload of {0} server; fullchain is {1}".format( config.installer, lineage.fullchain), pause=False) + def certonly(config, plugins): """Authenticate & obtain cert, but do not install it. @@ -1220,6 +1223,7 @@ def certonly(config, plugins): cert_path, fullchain_path = _csr_get_and_save_cert(config, le_client) _report_new_cert(config, cert_path, fullchain_path) _suggest_donation_if_appropriate(config) + eff.handle_subscription(config, le_client.account) return domains, certname = _find_domains_or_certname(config, installer) @@ -1237,6 +1241,8 @@ def certonly(config, plugins): key_path = lineage.key_path if lineage else None _report_new_cert(config, cert_path, fullchain_path, key_path) _suggest_donation_if_appropriate(config) + eff.handle_subscription(config, le_client.account) + def renew(config, unused_plugins): """Renew previously-obtained certificates. diff --git a/certbot/setup.py b/certbot/setup.py index 54dcea071..31a5d19d2 100644 --- a/certbot/setup.py +++ b/certbot/setup.py @@ -1,5 +1,5 @@ import codecs -from distutils.version import StrictVersion +from distutils.version import LooseVersion import os import re import sys @@ -61,7 +61,7 @@ install_requires = [ # So this dependency is not added for old Linux distributions with old setuptools, # in order to allow these systems to build certbot from sources. pywin32_req = 'pywin32>=227' # do not forget to edit pywin32 dependency accordingly in windows-installer/construct.py -setuptools_known_environment_markers = (StrictVersion(setuptools_version) >= StrictVersion('36.2')) +setuptools_known_environment_markers = (LooseVersion(setuptools_version) >= LooseVersion('36.2')) if setuptools_known_environment_markers: install_requires.append(pywin32_req + " ; sys_platform == 'win32'") elif 'bdist_wheel' in sys.argv[1:]: diff --git a/certbot/tests/account_test.py b/certbot/tests/account_test.py index 6c6e6c860..6d215eed1 100644 --- a/certbot/tests/account_test.py +++ b/certbot/tests/account_test.py @@ -17,6 +17,7 @@ from certbot.compat import misc from certbot.compat import os import certbot.tests.util as test_util + KEY = jose.JWKRSA.load(test_util.load_vector("rsa512_key.pem")) @@ -56,6 +57,32 @@ class AccountTest(unittest.TestCase): self.assertTrue(repr(self.acc).startswith( " 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. + +### Reset the Environment + +The instructions below clean up the build environment so it can reliably be used again. + +1. `cd ~/certbot` (or to an alternate path where you put our source files) +2. `snapcraft clean --use-lxd` +3. `rm certbot_*_amd64.snap` +4. `cd certbot-dns-dnsimple` +5. `rm certbot-dns-dnsimple_*_amd64.snap` +6. `snapcraft clean --use-lxd` +7. `cd ..` + +## Publishing Permissions + +There are security implications to permitting anyone to publish, without +review, a plugin into the Snap Store which will then run in Certbot's classic +snap context, with full access to the host system. + +At a minimum, it is clear that this should happen only with the user's explicit +opt-in action. + +As implemented, Certbot will only load plugins connected via the snap interface +mechanism, so permission is effectively delegated to what interface connections +the snap infrastucture will permit. + +We have approval from the snap team to use this design as long as we make it +explicit what a user is agreeing to when they connect a plugin to the +Certbot snap. That work was completed in +https://github.com/certbot/certbot/issues/8013. + +## Outstanding issues + +[Outstanding items relating to plugin support in Certbot snaps are tracked on GitHub](https://github.com/certbot/certbot/issues?q=is%3Aopen+is%3Aissue+label%3A%22area%3A+snaps%22). diff --git a/snap/local/build.sh b/snap/local/build.sh index ba28a30ec..2a0f64b92 100755 --- a/snap/local/build.sh +++ b/snap/local/build.sh @@ -21,7 +21,8 @@ source "${DIR}/common.sh" RegisterQemuHandlers ResolveArch "${SNAP_ARCH}" -tools/strip_hashes.py letsencrypt-auto-source/pieces/dependency-requirements.txt > snap-constraints.txt +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 & diff --git a/snap/local/common.sh b/snap/local/common.sh index 00a7614e8..7fc44e8ba 100644 --- a/snap/local/common.sh +++ b/snap/local/common.sh @@ -3,7 +3,7 @@ # Resolve the Snap architecture to Docker architecture (DOCKER_ARCH variable) # and QEMU architecture (QEMU_ARCH variable). -# Usage: ResolveArch [amd64|i386|arm64|armhf] +# Usage: ResolveArch [amd64|arm64|armhf] ResolveArch() { local SNAP_ARCH=$1 @@ -12,10 +12,6 @@ ResolveArch() { DOCKER_ARCH="amd64" QEMU_ARCH="x86_64" ;; - "i386") - DOCKER_ARCH="i386" - QEMU_ARCH="i386" - ;; "arm64") DOCKER_ARCH="arm64v8" QEMU_ARCH="aarch64" diff --git a/snap/local/compile_native_wheels.sh b/snap/local/compile_native_wheels.sh index 5dbb0f5d6..cabbf99e7 100755 --- a/snap/local/compile_native_wheels.sh +++ b/snap/local/compile_native_wheels.sh @@ -5,7 +5,7 @@ set -ex DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -TARGET_ARCHS="i386 arm64 armhf" +TARGET_ARCHS="arm64 armhf" rm -rf "${DIR}/packages/"* @@ -14,7 +14,8 @@ source "${DIR}/common.sh" RegisterQemuHandlers -tools/strip_hashes.py letsencrypt-auto-source/pieces/dependency-requirements.txt > "${DIR}/snap-constraints.txt" +tools/strip_hashes.py letsencrypt-auto-source/pieces/dependency-requirements.txt \ + | grep -v python-augeas > "${DIR}/snap-constraints.txt" for SNAP_ARCH in ${TARGET_ARCHS}; do ResolveArch "${SNAP_ARCH}" DownloadQemuStatic "${QEMU_ARCH}" "${DIR}" @@ -24,7 +25,7 @@ for SNAP_ARCH in ${TARGET_ARCHS}; do -v "${DIR}/qemu-${QEMU_ARCH}-static:/usr/bin/qemu-${QEMU_ARCH}-static" \ -v "${DIR}:/workspace" \ -w "/workspace" \ - "${DOCKER_ARCH}/ubuntu:18.04" \ + "${DOCKER_ARCH}/ubuntu:20.04" \ sh -c "\ apt-get update \ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends python3 python3-venv python3-dev libffi-dev libssl-dev gcc \ diff --git a/snap/local/packages/cffi/cffi-1.14.0-cp36-cp36m-linux_aarch64.whl b/snap/local/packages/cffi/cffi-1.14.0-cp36-cp36m-linux_aarch64.whl deleted file mode 100644 index 36dfa9ade..000000000 Binary files a/snap/local/packages/cffi/cffi-1.14.0-cp36-cp36m-linux_aarch64.whl and /dev/null differ diff --git a/snap/local/packages/cffi/cffi-1.14.0-cp36-cp36m-linux_armv7l.whl b/snap/local/packages/cffi/cffi-1.14.0-cp36-cp36m-linux_armv7l.whl deleted file mode 100644 index 26f107cc9..000000000 Binary files a/snap/local/packages/cffi/cffi-1.14.0-cp36-cp36m-linux_armv7l.whl and /dev/null differ diff --git a/snap/local/packages/cffi/cffi-1.14.0-cp36-cp36m-manylinux1_i686.whl b/snap/local/packages/cffi/cffi-1.14.0-cp36-cp36m-manylinux1_i686.whl deleted file mode 100644 index 1e5491b6e..000000000 Binary files a/snap/local/packages/cffi/cffi-1.14.0-cp36-cp36m-manylinux1_i686.whl and /dev/null differ diff --git a/snap/local/packages/cffi/cffi-1.14.0-cp38-cp38-linux_aarch64.whl b/snap/local/packages/cffi/cffi-1.14.0-cp38-cp38-linux_aarch64.whl new file mode 100644 index 000000000..aded6d595 Binary files /dev/null and b/snap/local/packages/cffi/cffi-1.14.0-cp38-cp38-linux_aarch64.whl differ diff --git a/snap/local/packages/cffi/cffi-1.14.0-cp38-cp38-linux_armv7l.whl b/snap/local/packages/cffi/cffi-1.14.0-cp38-cp38-linux_armv7l.whl new file mode 100644 index 000000000..4f6d0ab7d Binary files /dev/null and b/snap/local/packages/cffi/cffi-1.14.0-cp38-cp38-linux_armv7l.whl differ diff --git a/snap/local/packages/cryptography/cryptography-2.8-cp36-cp36m-linux_aarch64.whl b/snap/local/packages/cryptography/cryptography-2.8-cp36-cp36m-linux_aarch64.whl deleted file mode 100644 index 3a969945a..000000000 Binary files a/snap/local/packages/cryptography/cryptography-2.8-cp36-cp36m-linux_aarch64.whl and /dev/null differ diff --git a/snap/local/packages/cryptography/cryptography-2.8-cp36-cp36m-linux_armv7l.whl b/snap/local/packages/cryptography/cryptography-2.8-cp36-cp36m-linux_armv7l.whl deleted file mode 100644 index ea49f5dab..000000000 Binary files a/snap/local/packages/cryptography/cryptography-2.8-cp36-cp36m-linux_armv7l.whl and /dev/null differ diff --git a/snap/local/packages/cryptography/cryptography-2.8-cp36-cp36m-linux_i686.whl b/snap/local/packages/cryptography/cryptography-2.8-cp36-cp36m-linux_i686.whl deleted file mode 100644 index 18d7e6fd7..000000000 Binary files a/snap/local/packages/cryptography/cryptography-2.8-cp36-cp36m-linux_i686.whl and /dev/null differ diff --git a/snap/local/packages/cryptography/cryptography-2.8-cp38-cp38-linux_aarch64.whl b/snap/local/packages/cryptography/cryptography-2.8-cp38-cp38-linux_aarch64.whl new file mode 100644 index 000000000..e0392fcd4 Binary files /dev/null and b/snap/local/packages/cryptography/cryptography-2.8-cp38-cp38-linux_aarch64.whl differ diff --git a/snap/local/packages/cryptography/cryptography-2.8-cp38-cp38-linux_armv7l.whl b/snap/local/packages/cryptography/cryptography-2.8-cp38-cp38-linux_armv7l.whl new file mode 100644 index 000000000..38ee1eada Binary files /dev/null and b/snap/local/packages/cryptography/cryptography-2.8-cp38-cp38-linux_armv7l.whl differ diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 30959dacd..ea81e2b61 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -15,7 +15,7 @@ description: | - Help you revoke the certificate if that ever becomes necessary. confinement: classic grade: devel -base: core18 +base: core20 adopt-info: certbot apps: @@ -26,7 +26,7 @@ apps: AUGEAS_LENS_LIB: "$SNAP/usr/share/augeas/lenses/dist" LD_LIBRARY_PATH: "$SNAP/usr/lib/x86_64-linux-gnu/:$LD_LIBRARY_PATH" renew: - command: certbot -q renew + command: certbot.wrapper -q renew daemon: oneshot environment: PATH: "$SNAP/bin:$SNAP/usr/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games" @@ -35,58 +35,42 @@ apps: # Run approximately twice a day with randomization timer: 00:00~24:00/2 + parts: - python-augeas: - plugin: python - source: git://github.com/basak/python-augeas - source-branch: snap - python-version: python3 - build-packages: [libaugeas-dev] - acme: - plugin: python - source: . - source-subdir: acme - constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt] - python-version: python3 - # To build cryptography and cffi if needed - build-packages: [libffi-dev, libssl-dev] certbot: plugin: python source: . - source-subdir: certbot constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt] - python-version: python3 - after: [acme] + python-packages: + - git+https://github.com/basak/python-augeas.git@snap + - ./acme + - ./certbot + - ./certbot-apache + - ./certbot-nginx + stage: + - -usr/lib/python3.8/sitecustomize.py # maybe unnecessary + # Prefer cffi + - -lib/python3.8/site-packages/augeas.py + stage-packages: + - libaugeas0 + # added to stage python: + - libpython3-stdlib + - libpython3.8-stdlib + - libpython3.8-minimal + - python3-pip + - python3-setuptools + - python3-wheel + - python3-venv + - python3-minimal + - python3-distutils + - python3-pkg-resources + - python3.8-minimal + # To build cryptography and cffi if needed + build-packages: [libffi-dev, libssl-dev, git, libaugeas-dev, python3-dev] override-pull: | snapcraftctl pull - snapcraftctl set-version `cd $SNAPCRAFT_PART_SRC && git describe|sed s/^v//` - # Workaround for lack of site-packages leading to empty sitecustomize.py - stage: - - -usr/lib/python3.6/sitecustomize.py - certbot-apache: - plugin: python - source: . - source-subdir: certbot-apache - constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt] - python-version: python3 - after: [python-augeas, certbot] - stage-packages: [libaugeas0] - stage: - # Prefer cffi - - -lib/python3.6/site-packages/augeas.py - certbot-nginx: - plugin: python - source: . - source-subdir: certbot-nginx - constraints: [$SNAPCRAFT_PART_SRC/snap-constraints.txt] - python-version: python3 - # This is the last step, compile pycache now as there should be no conflicts. - override-prime: | - snapcraftctl prime - ./usr/bin/python3 -m compileall -q . - # After certbot-apache to not rebuild duplicates (essentially sharing what was already staged, - # like zope) - after: [certbot-apache] + snapcraftctl set-version `cd $SNAPCRAFT_PART_SRC/certbot && git describe|sed s/^v//` + wrappers: plugin: dump source: .