From 47c1045f6d467a18a30c2a8482a6bfb373706fb8 Mon Sep 17 00:00:00 2001 From: Mads Jensen Date: Mon, 31 Aug 2020 17:50:45 +0200 Subject: [PATCH 01/42] Implements support for ECDSA keys. Fixes #2163. Thanks to @pahrohfit and @Tomoyuki-GH for previous efforts to implement suport for this. Co-Authored-By: Robert Dailey Co-Authored-By: Tomoyuki-GH <55397638+Tomoyuki-GH@users.noreply.github.com> --- AUTHORS.md | 2 + .../archive/c.encryption-example.com/README | 14 ++++ .../archive/c.encryption-example.com/cert.pem | 18 +++++ .../c.encryption-example.com/chain.pem | 20 +++++ .../c.encryption-example.com/fullchain.pem | 38 +++++++++ .../c.encryption-example.com/privkey.pem | 5 ++ .../live/c.encryption-example.com/README | 14 ++++ .../live/c.encryption-example.com/cert.pem | 1 + .../live/c.encryption-example.com/chain.pem | 1 + .../c.encryption-example.com/fullchain.pem | 1 + .../live/c.encryption-example.com/privkey.pem | 1 + .../renewal/c.encryption-example.com.conf | 17 ++++ .../certbot_tests/assertions.py | 14 ++++ .../certbot_tests/test_main.py | 75 ++++++++++++++++-- .../certbot_integration_tests/utils/misc.py | 6 +- certbot/CHANGELOG.md | 11 ++- certbot/README.rst | 2 + certbot/certbot/_internal/cert_manager.py | 27 +++++-- certbot/certbot/_internal/cli/__init__.py | 10 +++ certbot/certbot/_internal/cli/helpful.py | 4 + certbot/certbot/_internal/client.py | 34 ++++++-- certbot/certbot/_internal/constants.py | 2 + certbot/certbot/_internal/main.py | 3 + certbot/certbot/_internal/renewal.py | 8 +- certbot/certbot/_internal/storage.py | 21 +++++ certbot/certbot/crypto_util.py | 68 ++++++++++++---- certbot/certbot/interfaces.py | 8 ++ certbot/certbot/tests/testdata/README | 8 +- .../tests/testdata/ec_prime256v1_key.pem | 8 ++ .../tests/testdata/ec_secp384r1_key.pem | 9 +++ .../tests/testdata/ec_secp521r1_key.pem | 10 +++ .../testdata/sample-archive-ec/cert1.pem | 18 +++++ .../testdata/sample-archive-ec/chain1.pem | 20 +++++ .../testdata/sample-archive-ec/fullchain1.pem | 38 +++++++++ .../testdata/sample-archive-ec/privkey1.pem | 5 ++ .../tests/testdata/sample-renewal-ec.conf | 79 +++++++++++++++++++ .../tests/testdata/sample-renewal.conf | 1 + certbot/certbot/tests/util.py | 4 +- certbot/docs/ciphers.rst | 6 +- certbot/docs/cli-help.txt | 8 +- certbot/docs/using.rst | 16 +++- certbot/examples/cli.ini | 4 + certbot/tests/cli_test.py | 15 ++++ certbot/tests/client_test.py | 12 ++- certbot/tests/crypto_util_test.py | 50 +++++++++++- certbot/tests/renewal_test.py | 24 ++++++ 46 files changed, 709 insertions(+), 51 deletions(-) create mode 100644 certbot-ci/certbot_integration_tests/assets/sample-config/archive/c.encryption-example.com/README create mode 100644 certbot-ci/certbot_integration_tests/assets/sample-config/archive/c.encryption-example.com/cert.pem create mode 100644 certbot-ci/certbot_integration_tests/assets/sample-config/archive/c.encryption-example.com/chain.pem create mode 100644 certbot-ci/certbot_integration_tests/assets/sample-config/archive/c.encryption-example.com/fullchain.pem create mode 100644 certbot-ci/certbot_integration_tests/assets/sample-config/archive/c.encryption-example.com/privkey.pem create mode 100644 certbot-ci/certbot_integration_tests/assets/sample-config/live/c.encryption-example.com/README create mode 120000 certbot-ci/certbot_integration_tests/assets/sample-config/live/c.encryption-example.com/cert.pem create mode 120000 certbot-ci/certbot_integration_tests/assets/sample-config/live/c.encryption-example.com/chain.pem create mode 120000 certbot-ci/certbot_integration_tests/assets/sample-config/live/c.encryption-example.com/fullchain.pem create mode 120000 certbot-ci/certbot_integration_tests/assets/sample-config/live/c.encryption-example.com/privkey.pem create mode 100644 certbot-ci/certbot_integration_tests/assets/sample-config/renewal/c.encryption-example.com.conf create mode 100644 certbot/certbot/tests/testdata/ec_prime256v1_key.pem create mode 100644 certbot/certbot/tests/testdata/ec_secp384r1_key.pem create mode 100644 certbot/certbot/tests/testdata/ec_secp521r1_key.pem create mode 100644 certbot/certbot/tests/testdata/sample-archive-ec/cert1.pem create mode 100644 certbot/certbot/tests/testdata/sample-archive-ec/chain1.pem create mode 100644 certbot/certbot/tests/testdata/sample-archive-ec/fullchain1.pem create mode 100644 certbot/certbot/tests/testdata/sample-archive-ec/privkey1.pem create mode 100644 certbot/certbot/tests/testdata/sample-renewal-ec.conf diff --git a/AUTHORS.md b/AUTHORS.md index 56fe2a3d8..f76c323a5 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -154,6 +154,7 @@ Authors * [Luca Olivetti](https://github.com/olivluca) * [Luke Rogers](https://github.com/lukeroge) * [Maarten](https://github.com/mrtndwrd) +* [Mads Jensen](https://github.com/atombrella) * [Maikel Martens](https://github.com/krukas) * [Malte Janduda](https://github.com/MalteJ) * [Mantas Mikulėnas](https://github.com/grawity) @@ -213,6 +214,7 @@ Authors * [Richard Barnes](https://github.com/r-barnes) * [Richard Panek](https://github.com/kernelpanek) * [Robert Buchholz](https://github.com/rbu) +* [Robert Dailey](https://github.com/pahrohfit) * [Robert Habermann](https://github.com/frennkie) * [Robert Xiao](https://github.com/nneonneo) * [Roland Shoemaker](https://github.com/rolandshoemaker) diff --git a/certbot-ci/certbot_integration_tests/assets/sample-config/archive/c.encryption-example.com/README b/certbot-ci/certbot_integration_tests/assets/sample-config/archive/c.encryption-example.com/README new file mode 100644 index 000000000..5050078ff --- /dev/null +++ b/certbot-ci/certbot_integration_tests/assets/sample-config/archive/c.encryption-example.com/README @@ -0,0 +1,14 @@ +This directory contains your keys and certificates. + +`privkey.pem` : the private key for your certificate. +`fullchain.pem`: the certificate file used in most server software. +`chain.pem` : used for OCSP stapling in Nginx >=1.3.7. +`cert.pem` : will break many server configurations, and should not be used + without reading further documentation (see link below). + +WARNING: DO NOT MOVE OR RENAME THESE FILES! + Certbot expects these files to remain in this location in order + to function properly! + +We recommend not moving these files. For more information, see the Certbot +User Guide at https://certbot.eff.org/docs/using.html#where-are-my-certificates. diff --git a/certbot-ci/certbot_integration_tests/assets/sample-config/archive/c.encryption-example.com/cert.pem b/certbot-ci/certbot_integration_tests/assets/sample-config/archive/c.encryption-example.com/cert.pem new file mode 100644 index 000000000..b07af2bf7 --- /dev/null +++ b/certbot-ci/certbot_integration_tests/assets/sample-config/archive/c.encryption-example.com/cert.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC2zCCAcOgAwIBAgIIBvrEnbPRYu8wDQYJKoZIhvcNAQELBQAwKDEmMCQGA1UE +AxMdUGViYmxlIEludGVybWVkaWF0ZSBDQSAxMjZjNGIwHhcNMjAxMDEyMjEwNzQw +WhcNMjUxMDEyMjEwNzQwWjAjMSEwHwYDVQQDExhjLmVuY3J5cHRpb24tZXhhbXBs +ZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARjMhuW0ENPPC33PjB5XsYU +CRw640kPQENIDatcTJaENZIZdqKd6rI6jc+lpbmXot7Zi52clJlSJS+V6oDAt2Lh +o4HYMIHVMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB +BQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUj7Kd3ENqxlPf8B2bIGhsjydX +mPswHwYDVR0jBBgwFoAUEiGxlkRsi+VvcogH5dVD3h1laAcwMQYIKwYBBQUHAQEE +JTAjMCEGCCsGAQUFBzABhhVodHRwOi8vMTI3LjAuMC4xOjQwMDIwIwYDVR0RBBww +GoIYYy5lbmNyeXB0aW9uLWV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQCl +k0JXsa8y7fg41WWMDhw60bPW77O0FtOmTcnhdI5daYNemQVk+Q5EMaBLQ/oGjgXd +9QXFzXH1PL904YEnSLt+iTpXn++7rQSNzQsdYqw0neWk4f5pEBiN+WORpb6mwobV +ifMtBOkNEHvrJ2Pkci9U1lLwtKD/DSew6QtJU5DSkmH1XdGuMJiubygEIvELtvgq +cP9S368ZvPmPGmKaJQXBiuaR8MTjY/Bkr79aXQMjKbf+mpn7h0POCcePk1DY/rm6 +Da+X16lf0hHyQhSUa7Vgyim6rK1/hlw+Z00i+sQCKD9Ih7kXuuGqfSDC33cfO8Tj +o/MXO8lcxkrem5zU5QWP +-----END CERTIFICATE----- diff --git a/certbot-ci/certbot_integration_tests/assets/sample-config/archive/c.encryption-example.com/chain.pem b/certbot-ci/certbot_integration_tests/assets/sample-config/archive/c.encryption-example.com/chain.pem new file mode 100644 index 000000000..64a805c0f --- /dev/null +++ b/certbot-ci/certbot_integration_tests/assets/sample-config/archive/c.encryption-example.com/chain.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDUDCCAjigAwIBAgIIbi787yVrcMAwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE +AxMVUGViYmxlIFJvb3QgQ0EgMGM1MjI1MCAXDTIwMTAxMjIwMjI0NloYDzIwNTAx +MDEyMjEyMjQ2WjAoMSYwJAYDVQQDEx1QZWJibGUgSW50ZXJtZWRpYXRlIENBIDEy +NmM0YjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALGeVk1BMJraeqRq +mJ2+hgso8VOAv2s2CVxUJjIVcn7f2adE8NyTsSQ1brlsnKCUYUw7yLTQH0izLQRB +qKVIDFkUqo5/FuTJ2QlfA2EwBL8J7s/7L7vj3L0DiVpwgxPSyFEwdl/Y5y7ofsX5 +CIhCFcaMAmTIuKLiSfCJjGwkbEMuolm+lO8Mikxxc/JtDVUC479ugU7PU9O09bMH +nm+sD6Bgd+KMoPkCCCoeShJS9X3Ziq9HGc7Z6nhM/zirFARt2XkonEdAZ8br01zY +MRiY9txhlWQ7mUkOtzOSoEuYJNoUbvMUf0+tNzto26WRyF7dJmh7lTBsYrvAwUTx +PzNyst0CAwEAAaOBgzCBgDAOBgNVHQ8BAf8EBAMCAoQwHQYDVR0lBBYwFAYIKwYB +BQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFBIhsZZE +bIvlb3KIB+XVQ94dZWgHMB8GA1UdIwQYMBaAFOaKTaXg37vKgRt7d79YOjAoAtJT +MA0GCSqGSIb3DQEBCwUAA4IBAQAU2mZii7PH2pkw2lNM0QqPbcW/UYyvFoUeM8Aq +uCtsI2s+oxCJTqzfLsA0N8NY4nHLQ5wAlNJfJekngni8hbmJTKU4JFTMe7kLQO8P +fJbk0pTzhhHVQw7CVwB6Pwq3u2m/JV+d6xDIDc+AVkuEl19ZJU0rTWyooClfFLZV +EdZmEiUtA3PGlxoYwYhoGHYlhFxsoFONhCsBEdN7k7FKtFGVxN7oc5SKmKp0YZTW +fcrEtrdNThATO4ymhCC2zh33NI/MT1O74fpaAc2k6LcTl57MKiLfTYX4LTL6v9JG +9tlNqjFVRRmzEbtXTPcCb+w9g1VqoOGok7mGXYLTYtShCuvE +-----END CERTIFICATE----- diff --git a/certbot-ci/certbot_integration_tests/assets/sample-config/archive/c.encryption-example.com/fullchain.pem b/certbot-ci/certbot_integration_tests/assets/sample-config/archive/c.encryption-example.com/fullchain.pem new file mode 100644 index 000000000..1ba80ba4e --- /dev/null +++ b/certbot-ci/certbot_integration_tests/assets/sample-config/archive/c.encryption-example.com/fullchain.pem @@ -0,0 +1,38 @@ +-----BEGIN CERTIFICATE----- +MIIC2zCCAcOgAwIBAgIILlmGtZhUFEwwDQYJKoZIhvcNAQELBQAwKDEmMCQGA1UE +AxMdUGViYmxlIEludGVybWVkaWF0ZSBDQSAxMjZjNGIwHhcNMjAxMDEyMjA1MDM0 +WhcNMjUxMDEyMjA1MDM0WjAjMSEwHwYDVQQDExhjLmVuY3J5cHRpb24tZXhhbXBs +ZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARHEzR8JPWrEmpmgM+F2bk5 +9mT0u6CjzmJG0QpbaqprLiG5NGpW84VQ5TFCrmC4KxYfigCfMhfHRNfFYvNUK3V/ +o4HYMIHVMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB +BQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU1CsVL+bPnzaxxQ5jUENmQJIO +lKwwHwYDVR0jBBgwFoAUEiGxlkRsi+VvcogH5dVD3h1laAcwMQYIKwYBBQUHAQEE +JTAjMCEGCCsGAQUFBzABhhVodHRwOi8vMTI3LjAuMC4xOjQwMDIwIwYDVR0RBBww +GoIYYy5lbmNyeXB0aW9uLWV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBn +2D8loC7pfk28JYpFLr5lmFKJWWmtLGlpsWDj61fVjtTfGKLziJz+MM6il4Y3hIz5 +58qiFK0ue0M63dIBJ33N+XxSEXon4Q0gy/zRWfH9jtPJ3FwfjkU/RT9PAUClYi0G +ptNWnTmgQkNzousbcAtRNXuuShH3856vhUnwkX+xM+cbIDi1JVmFjcGrEEQJ0rUF +mv2ZTyfbWbUs3v4rReETi2NVzr1Ql6J+ByNcMvHODzFy3t0L6yelAw2ca1I+c9HU ++Z0tnp/ykR7eXNuVLivok8UBf5OC413lh8ZO5g+Bgzh/LdtkUuavg1MYtEX0H6mX +9U7y3nVI8WEbPGf+HDeu +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDUDCCAjigAwIBAgIIbi787yVrcMAwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE +AxMVUGViYmxlIFJvb3QgQ0EgMGM1MjI1MCAXDTIwMTAxMjIwMjI0NloYDzIwNTAx +MDEyMjEyMjQ2WjAoMSYwJAYDVQQDEx1QZWJibGUgSW50ZXJtZWRpYXRlIENBIDEy +NmM0YjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALGeVk1BMJraeqRq +mJ2+hgso8VOAv2s2CVxUJjIVcn7f2adE8NyTsSQ1brlsnKCUYUw7yLTQH0izLQRB +qKVIDFkUqo5/FuTJ2QlfA2EwBL8J7s/7L7vj3L0DiVpwgxPSyFEwdl/Y5y7ofsX5 +CIhCFcaMAmTIuKLiSfCJjGwkbEMuolm+lO8Mikxxc/JtDVUC479ugU7PU9O09bMH +nm+sD6Bgd+KMoPkCCCoeShJS9X3Ziq9HGc7Z6nhM/zirFARt2XkonEdAZ8br01zY +MRiY9txhlWQ7mUkOtzOSoEuYJNoUbvMUf0+tNzto26WRyF7dJmh7lTBsYrvAwUTx +PzNyst0CAwEAAaOBgzCBgDAOBgNVHQ8BAf8EBAMCAoQwHQYDVR0lBBYwFAYIKwYB +BQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFBIhsZZE +bIvlb3KIB+XVQ94dZWgHMB8GA1UdIwQYMBaAFOaKTaXg37vKgRt7d79YOjAoAtJT +MA0GCSqGSIb3DQEBCwUAA4IBAQAU2mZii7PH2pkw2lNM0QqPbcW/UYyvFoUeM8Aq +uCtsI2s+oxCJTqzfLsA0N8NY4nHLQ5wAlNJfJekngni8hbmJTKU4JFTMe7kLQO8P +fJbk0pTzhhHVQw7CVwB6Pwq3u2m/JV+d6xDIDc+AVkuEl19ZJU0rTWyooClfFLZV +EdZmEiUtA3PGlxoYwYhoGHYlhFxsoFONhCsBEdN7k7FKtFGVxN7oc5SKmKp0YZTW +fcrEtrdNThATO4ymhCC2zh33NI/MT1O74fpaAc2k6LcTl57MKiLfTYX4LTL6v9JG +9tlNqjFVRRmzEbtXTPcCb+w9g1VqoOGok7mGXYLTYtShCuvE +-----END CERTIFICATE----- diff --git a/certbot-ci/certbot_integration_tests/assets/sample-config/archive/c.encryption-example.com/privkey.pem b/certbot-ci/certbot_integration_tests/assets/sample-config/archive/c.encryption-example.com/privkey.pem new file mode 100644 index 000000000..6843b83d6 --- /dev/null +++ b/certbot-ci/certbot_integration_tests/assets/sample-config/archive/c.encryption-example.com/privkey.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgNgefv2dad4U1VYEi +0WkdHuqywi5QXAe30OwNTTGjhbihRANCAARHEzR8JPWrEmpmgM+F2bk59mT0u6Cj +zmJG0QpbaqprLiG5NGpW84VQ5TFCrmC4KxYfigCfMhfHRNfFYvNUK3V/ +-----END PRIVATE KEY----- diff --git a/certbot-ci/certbot_integration_tests/assets/sample-config/live/c.encryption-example.com/README b/certbot-ci/certbot_integration_tests/assets/sample-config/live/c.encryption-example.com/README new file mode 100644 index 000000000..5050078ff --- /dev/null +++ b/certbot-ci/certbot_integration_tests/assets/sample-config/live/c.encryption-example.com/README @@ -0,0 +1,14 @@ +This directory contains your keys and certificates. + +`privkey.pem` : the private key for your certificate. +`fullchain.pem`: the certificate file used in most server software. +`chain.pem` : used for OCSP stapling in Nginx >=1.3.7. +`cert.pem` : will break many server configurations, and should not be used + without reading further documentation (see link below). + +WARNING: DO NOT MOVE OR RENAME THESE FILES! + Certbot expects these files to remain in this location in order + to function properly! + +We recommend not moving these files. For more information, see the Certbot +User Guide at https://certbot.eff.org/docs/using.html#where-are-my-certificates. diff --git a/certbot-ci/certbot_integration_tests/assets/sample-config/live/c.encryption-example.com/cert.pem b/certbot-ci/certbot_integration_tests/assets/sample-config/live/c.encryption-example.com/cert.pem new file mode 120000 index 000000000..23e9f36ef --- /dev/null +++ b/certbot-ci/certbot_integration_tests/assets/sample-config/live/c.encryption-example.com/cert.pem @@ -0,0 +1 @@ +../../archive/c.encryption-example.com/cert.pem \ No newline at end of file diff --git a/certbot-ci/certbot_integration_tests/assets/sample-config/live/c.encryption-example.com/chain.pem b/certbot-ci/certbot_integration_tests/assets/sample-config/live/c.encryption-example.com/chain.pem new file mode 120000 index 000000000..3ce63c220 --- /dev/null +++ b/certbot-ci/certbot_integration_tests/assets/sample-config/live/c.encryption-example.com/chain.pem @@ -0,0 +1 @@ +../../archive/c.encryption-example.com/chain.pem \ No newline at end of file diff --git a/certbot-ci/certbot_integration_tests/assets/sample-config/live/c.encryption-example.com/fullchain.pem b/certbot-ci/certbot_integration_tests/assets/sample-config/live/c.encryption-example.com/fullchain.pem new file mode 120000 index 000000000..5f86022af --- /dev/null +++ b/certbot-ci/certbot_integration_tests/assets/sample-config/live/c.encryption-example.com/fullchain.pem @@ -0,0 +1 @@ +../../archive/c.encryption-example.com/fullchain.pem \ No newline at end of file diff --git a/certbot-ci/certbot_integration_tests/assets/sample-config/live/c.encryption-example.com/privkey.pem b/certbot-ci/certbot_integration_tests/assets/sample-config/live/c.encryption-example.com/privkey.pem new file mode 120000 index 000000000..4a8866fdc --- /dev/null +++ b/certbot-ci/certbot_integration_tests/assets/sample-config/live/c.encryption-example.com/privkey.pem @@ -0,0 +1 @@ +../../archive/c.encryption-example.com/privkey.pem \ No newline at end of file diff --git a/certbot-ci/certbot_integration_tests/assets/sample-config/renewal/c.encryption-example.com.conf b/certbot-ci/certbot_integration_tests/assets/sample-config/renewal/c.encryption-example.com.conf new file mode 100644 index 000000000..0c65891e4 --- /dev/null +++ b/certbot-ci/certbot_integration_tests/assets/sample-config/renewal/c.encryption-example.com.conf @@ -0,0 +1,17 @@ +# renew_before_expiry = 30 days +version = 1.10.0.dev0 +archive_dir = sample-config/archive/c.encryption-example.com +cert = sample-config/live/c.encryption-example.com/cert.pem +privkey = sample-config/live/c.encryption-example.com/privkey.pem +chain = sample-config/live/c.encryption-example.com/chain.pem +fullchain = sample-config/live/c.encryption-example.com/fullchain.pem + +# Options used in the renewal process +[renewalparams] +authenticator = apache +installer = apache +account = 48d6b9e8d767eccf7e4d877d6ffa81e3 +key_type = ecdsa +config_dir = sample-config-ec +elliptic_curve = secp256r1 +manual_public_ip_logging_ok = True diff --git a/certbot-ci/certbot_integration_tests/certbot_tests/assertions.py b/certbot-ci/certbot_integration_tests/certbot_tests/assertions.py index 53df6b890..c19c0762e 100644 --- a/certbot-ci/certbot_integration_tests/certbot_tests/assertions.py +++ b/certbot-ci/certbot_integration_tests/certbot_tests/assertions.py @@ -2,6 +2,10 @@ import io import os +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateKey +from cryptography.hazmat.primitives.serialization import load_pem_private_key + try: import grp POSIX_MODE = True @@ -16,6 +20,16 @@ SYSTEM_SID = 'S-1-5-18' ADMINS_SID = 'S-1-5-32-544' +def assert_elliptic_key(key, curve): + with open(key, 'rb') as file: + privkey1 = file.read() + + key = load_pem_private_key(data=privkey1, password=None, backend=default_backend()) + + assert isinstance(key, EllipticCurvePrivateKey) + assert isinstance(key.curve, curve) + + def assert_hook_execution(probe_path, probe_content): """ Assert that a certbot hook has been executed diff --git a/certbot-ci/certbot_integration_tests/certbot_tests/test_main.py b/certbot-ci/certbot_integration_tests/certbot_tests/test_main.py index caef80af3..02c537733 100644 --- a/certbot-ci/certbot_integration_tests/certbot_tests/test_main.py +++ b/certbot-ci/certbot_integration_tests/certbot_tests/test_main.py @@ -9,12 +9,17 @@ import shutil import subprocess import time +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.asymmetric.ec import SECP256R1, SECP384R1 +from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey +from cryptography.hazmat.primitives.serialization import load_pem_private_key from cryptography.x509 import NameOID import pytest from certbot_integration_tests.certbot_tests import context as certbot_context from certbot_integration_tests.certbot_tests.assertions import assert_cert_count_for_lineage +from certbot_integration_tests.certbot_tests.assertions import assert_elliptic_key from certbot_integration_tests.certbot_tests.assertions import assert_equals_group_owner from certbot_integration_tests.certbot_tests.assertions import assert_equals_group_permissions from certbot_integration_tests.certbot_tests.assertions import assert_equals_world_read_permissions @@ -289,7 +294,7 @@ def test_renew_with_changed_private_key_complexity(context): assert_cert_count_for_lineage(context.config_dir, certname, 1) context.certbot(['renew']) - + assert_cert_count_for_lineage(context.config_dir, certname, 2) key2 = join(context.config_dir, 'archive', certname, 'privkey2.pem') assert os.stat(key2).st_size > 3000 @@ -421,20 +426,80 @@ def test_reuse_key(context): assert len({cert1, cert2, cert3}) == 3 +def test_incorrect_key_type(context): + with pytest.raises(subprocess.CalledProcessError): + context.certbot(['--key-type="failwhale"']) + + def test_ecdsa(context): - """Test certificate issuance with ECDSA key.""" + """Test issuance for ECDSA CSR based request (legacy supported mode).""" key_path = join(context.workspace, 'privkey-p384.pem') csr_path = join(context.workspace, 'csr-p384.der') cert_path = join(context.workspace, 'cert-p384.pem') chain_path = join(context.workspace, 'chain-p384.pem') - misc.generate_csr([context.get_domain('ecdsa')], key_path, csr_path, key_type=misc.ECDSA_KEY_TYPE) - context.certbot(['auth', '--csr', csr_path, '--cert-path', cert_path, '--chain-path', chain_path]) + misc.generate_csr( + [context.get_domain('ecdsa')], + key_path, csr_path, + key_type=misc.ECDSA_KEY_TYPE + ) + context.certbot([ + 'auth', '--csr', csr_path, '--cert-path', cert_path, + '--chain-path', chain_path, + ]) certificate = misc.read_certificate(cert_path) assert 'ASN1 OID: secp384r1' in certificate +def test_default_key_type(context): + """Test default key type is RSA""" + certname = context.get_domain('renew') + context.certbot([ + 'certonly', + '--cert-name', certname, '-d', certname + ]) + filename = join(context.config_dir, 'archive/{0}/privkey1.pem').format(certname) + with open(filename, 'rb') as file: + privkey1 = file.read() + + key = load_pem_private_key(data=privkey1, password=None, backend=default_backend()) + assert isinstance(key, RSAPrivateKey) + + +def test_default_curve_type(context): + """test that the curve used when not specifying any is secp256r1""" + certname = context.get_domain('renew') + context.certbot([ + '--key-type', 'ecdsa', '--cert-name', certname, '-d', certname + ]) + key1 = join(context.config_dir, 'archive/{0}/privkey1.pem'.format(certname)) + assert_elliptic_key(key1, SECP256R1) + + +def test_renew_with_ec_keys(context): + """Test proper renew with updated private key complexity.""" + certname = context.get_domain('renew') + context.certbot([ + 'certonly', + '--cert-name', certname, + '--key-type', 'ecdsa', '--elliptic-curve', 'secp256r1', + '--force-renewal', '-d', certname, + ]) + + key1 = join(context.config_dir, "archive", certname, 'privkey1.pem') + assert 200 < os.stat(key1).st_size < 250 # ec keys of 256 bits are ~225 bytes + assert_elliptic_key(key1, SECP256R1) + assert_cert_count_for_lineage(context.config_dir, certname, 1) + + context.certbot(['renew', '--elliptic-curve', 'secp384r1']) + + assert_cert_count_for_lineage(context.config_dir, certname, 2) + key2 = join(context.config_dir, 'archive', certname, 'privkey2.pem') + assert_elliptic_key(key2, SECP384R1) + assert 280 < os.stat(key2).st_size < 320 # ec keys of 384 bits are ~310 bytes + + def test_ocsp_must_staple(context): """Test that OCSP Must-Staple is correctly set in the generated certificate.""" if context.acme_server == 'pebble': @@ -657,4 +722,4 @@ def test_preferred_chain(context): with open(conf_path, 'r') as f: assert 'preferred_chain = {}'.format(requested) in f.read(), \ - 'Expected preferred_chain to be set in renewal config' \ No newline at end of file + 'Expected preferred_chain to be set in renewal config' diff --git a/certbot-ci/certbot_integration_tests/utils/misc.py b/certbot-ci/certbot_integration_tests/utils/misc.py index 38c2e60a8..d83f276ef 100644 --- a/certbot-ci/certbot_integration_tests/utils/misc.py +++ b/certbot-ci/certbot_integration_tests/utils/misc.py @@ -280,7 +280,11 @@ def load_sample_data_path(workspace): if os.name == 'nt': # Fix the symlinks on Windows if GIT is not configured to create them upon checkout - for lineage in ['a.encryption-example.com', 'b.encryption-example.com']: + for lineage in [ + 'a.encryption-example.com', + 'b.encryption-example.com', + 'c.encryption-example.com', + ]: current_live = os.path.join(copied, 'live', lineage) for name in os.listdir(current_live): if name != 'README': diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index fc83d3b46..e32bd1072 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -8,7 +8,12 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). * Added timeout to DNS query function calls for dns-rfc2136 plugin. * Confirmation when deleting certificates -* +* CLI flag `--key-type` has been added to specify 'rsa' or 'ecdsa' (default 'rsa'). + Only accepts a single value at this time. +* CLI flag `--elliptic-curve` has been added which takes an NIST/SECG elliptic curve. Either of + `secp256r1`, `secp284r1` and `secp521r1` are accepted values. +* The command `certbot certficates` lists the which type of the private key that was used + for the private key. ### Changed @@ -55,7 +60,7 @@ More details about these changes can be found on our GitHub repo. ### Added -* Added the ability to remove email and phone contact information from an account +* Added the ability to remove email and phone contact information from an account using `update_account --register-unsafely-without-email` ### Changed @@ -67,7 +72,7 @@ More details about these changes can be found on our GitHub repo. * The problem causing the Apache plugin in the Certbot snap on ARM systems to fail to load the Augeas library it depends on has been fixed. * The `acme` library can now tell the ACME server to clear contact information by passing an empty - `tuple` to the `contact` field of a `Registration` message. + `tuple` to the `contact` field of a `Registration` message. * Fixed the `*** stack smashing detected ***` error in the Certbot snap on some systems. More details about these changes can be found on our GitHub repo. diff --git a/certbot/README.rst b/certbot/README.rst index 6d04e6fa3..3bd5e4cd7 100644 --- a/certbot/README.rst +++ b/certbot/README.rst @@ -106,6 +106,8 @@ Current Features * Can get domain-validated (DV) certificates. * Can revoke certificates. * Adjustable RSA key bit-length (2048 (default), 4096, ...). +* Adjustable [EC](https://en.wikipedia.org/wiki/Elliptic-curve_cryptography) + key (`secp256r1` (default), `secp384r1`, `secp521r1`). * Can optionally install a http -> https redirect, so your site effectively runs https only (Apache only) * Fully automated. diff --git a/certbot/certbot/_internal/cert_manager.py b/certbot/certbot/_internal/cert_manager.py index 5dc909330..5e1b05e9e 100644 --- a/certbot/certbot/_internal/cert_manager.py +++ b/certbot/certbot/_internal/cert_manager.py @@ -65,6 +65,7 @@ def rename_lineage(config): disp.notification("Successfully renamed {0} to {1}." .format(certname, new_certname), pause=False) + def certificates(config): """Display information about certs configured with Certbot @@ -87,6 +88,7 @@ def certificates(config): # Describe all the certs _describe_certs(config, parsed_certs, parse_failures) + def delete(config): """Delete Certbot files associated with a certificate lineage.""" certnames = get_certnames(config, "delete", allow_multiple=True) @@ -123,11 +125,13 @@ def lineage_for_certname(cli_config, certname): logger.debug("Traceback was:\n%s", traceback.format_exc()) return None + def domains_for_certname(config, certname): """Find the domains in the cert with name certname.""" lineage = lineage_for_certname(config, certname) return lineage.names() if lineage else None + def find_duplicative_certs(config, domains): """Find existing certs that match the given domain names. @@ -172,6 +176,7 @@ def find_duplicative_certs(config, domains): return _search_lineages(config, update_certs_for_domain_matches, (None, None)) + def _archive_files(candidate_lineage, filetype): """ In order to match things like: /etc/letsencrypt/archive/example.com/chain1.pem. @@ -193,6 +198,7 @@ def _archive_files(candidate_lineage, filetype): return pattern return None + def _acceptable_matches(): """ Generates the list that's passed to match_and_check_overlaps. Is its own function to make unit testing easier. @@ -203,6 +209,7 @@ def _acceptable_matches(): return [lambda x: x.fullchain_path, lambda x: x.cert_path, lambda x: _archive_files(x, "cert"), lambda x: _archive_files(x, "fullchain")] + def cert_path_to_lineage(cli_config): """ If config.cert_path is defined, try to find an appropriate value for config.certname. @@ -219,6 +226,7 @@ def cert_path_to_lineage(cli_config): lambda x: cli_config.cert_path[0], lambda x: x.lineagename) return match[0] + def match_and_check_overlaps(cli_config, acceptable_matches, match_func, rv_func): """ Searches through all lineages for a match, and checks for duplicates. If a duplicate is found, an error is raised, as performing operations on lineages @@ -284,20 +292,23 @@ def human_readable_cert_info(config, cert, skip_filter_checks=False): valid_string = "{0} ({1})".format(cert.target_expiry, status) serial = format(crypto_util.get_serial_from_cert(cert.cert_path), 'x') - certinfo.append(" Certificate Name: {0}\n" - " Serial Number: {1}\n" - " Domains: {2}\n" - " Expiry Date: {3}\n" - " Certificate Path: {4}\n" - " Private Key Path: {5}".format( + certinfo.append(" Certificate Name: {}\n" + " Serial Number: {}\n" + " Key Type: {}\n" + " Domains: {}\n" + " Expiry Date: {}\n" + " Certificate Path: {}\n" + " Private Key Path: {}".format( cert.lineagename, serial, + cert.private_key_type, " ".join(cert.names()), valid_string, cert.fullchain, cert.privkey)) return "".join(certinfo) + def get_certnames(config, verb, allow_multiple=False, custom_prompt=None): """Get certname from flag, interactively, or error out. """ @@ -337,10 +348,12 @@ def get_certnames(config, verb, allow_multiple=False, custom_prompt=None): # Private Helpers ################### + def _report_lines(msgs): """Format a results report for a category of single-line renewal outcomes""" return " " + "\n ".join(str(msg) for msg in msgs) + def _report_human_readable(config, parsed_certs): """Format a results report for a parsed cert""" certinfo = [] @@ -348,6 +361,7 @@ def _report_human_readable(config, parsed_certs): certinfo.append(human_readable_cert_info(config, cert)) return "\n".join(certinfo) + def _describe_certs(config, parsed_certs, parse_failures): """Print information about the certs we know about""" out = [] # type: List[str] @@ -369,6 +383,7 @@ def _describe_certs(config, parsed_certs, parse_failures): disp = zope.component.getUtility(interfaces.IDisplay) disp.notification("\n".join(out), pause=False, wrap=False) + def _search_lineages(cli_config, func, initial_rv, *args): """Iterate func over unbroken lineages, allowing custom return conditions. diff --git a/certbot/certbot/_internal/cli/__init__.py b/certbot/certbot/_internal/cli/__init__.py index f6f648aa9..e50cb338a 100644 --- a/certbot/certbot/_internal/cli/__init__.py +++ b/certbot/certbot/_internal/cli/__init__.py @@ -313,6 +313,16 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): helpful.add( "security", "--rsa-key-size", type=int, metavar="N", default=flag_default("rsa_key_size"), help=config_help("rsa_key_size")) + helpful.add( + "security", "--key-type", choices=['rsa', 'ecdsa'], type=str, + default=flag_default("key_type"), help=config_help("key_type")) + helpful.add( + "security", "--elliptic-curve", type=str, choices=[ + 'secp256r1', + 'secp384r1', + 'secp521r1', + ], metavar="N", + default=flag_default("elliptic_curve"), help=config_help("elliptic_curve")) helpful.add( "security", "--must-staple", action="store_true", dest="must_staple", default=flag_default("must_staple"), diff --git a/certbot/certbot/_internal/cli/helpful.py b/certbot/certbot/_internal/cli/helpful.py index a86ff3743..141dd41a4 100644 --- a/certbot/certbot/_internal/cli/helpful.py +++ b/certbot/certbot/_internal/cli/helpful.py @@ -230,6 +230,10 @@ class HelpfulArgumentParser(object): raise errors.Error( "Parameters --hsts and --auto-hsts cannot be used simultaneously.") + if isinstance(parsed_args.key_type, list) and len(parsed_args.key_type) > 1: + raise errors.Error( + "Only *one* --key-type type may be provided at this time.") + return parsed_args def set_test_server(self, parsed_args): diff --git a/certbot/certbot/_internal/client.py b/certbot/certbot/_internal/client.py index b198a8c27..5dc62580e 100644 --- a/certbot/certbot/_internal/client.py +++ b/certbot/certbot/_internal/client.py @@ -312,7 +312,6 @@ class Client(object): :rtype: tuple """ - # We need to determine the key path, key PEM data, CSR path, # and CSR PEM data. For a dry run, the paths are None because # they aren't permanently saved to disk. For a lineage with @@ -335,16 +334,41 @@ class Client(object): # The key is set to None here but will be created below. key = None + key_size = self.config.rsa_key_size + elliptic_curve = None + + # key-type defaults to a list, but we are only handling 1 currently + if isinstance(self.config.key_type, list): + self.config.key_type = self.config.key_type[0] + if self.config.elliptic_curve and self.config.key_type == 'ecdsa': + elliptic_curve = self.config.elliptic_curve + self.config.auth_chain_path = "./chain-ecdsa.pem" + self.config.auth_cert_path = "./cert-ecdsa.pem" + self.config.key_path = "./key-ecdsa.pem" + elif self.config.rsa_key_size and self.config.key_type.lower() == 'rsa': + key_size = self.config.rsa_key_size + # Create CSR from names if self.config.dry_run: - key = key or util.Key(file=None, - pem=crypto_util.make_key(self.config.rsa_key_size)) + key = key or util.Key( + file=None, + pem=crypto_util.make_key( + bits=key_size, + elliptic_curve=elliptic_curve, + key_type=self.config.key_type, + + ), + ) csr = util.CSR(file=None, form="pem", data=acme_crypto_util.make_csr( key.pem, domains, self.config.must_staple)) else: - key = key or crypto_util.init_save_key(self.config.rsa_key_size, - self.config.key_dir) + key = key or crypto_util.init_save_key( + key_size=key_size, + key_dir=self.config.key_dir, + key_type=self.config.key_type, + elliptic_curve=elliptic_curve, + ) csr = crypto_util.init_save_csr(key, domains, self.config.csr_dir) orderr = self._get_order_and_authorizations(csr.data, self.config.allow_subset_of_names) diff --git a/certbot/certbot/_internal/constants.py b/certbot/certbot/_internal/constants.py index 9e9373f13..f79d6b9db 100644 --- a/certbot/certbot/_internal/constants.py +++ b/certbot/certbot/_internal/constants.py @@ -57,6 +57,8 @@ CLI_DEFAULTS = dict( https_port=443, break_my_certs=False, rsa_key_size=2048, + elliptic_curve="secp256r1", + key_type="rsa", must_staple=False, redirect=None, auto_hsts=False, diff --git a/certbot/certbot/_internal/main.py b/certbot/certbot/_internal/main.py index 6c1482b65..fd7df8d83 100644 --- a/certbot/certbot/_internal/main.py +++ b/certbot/certbot/_internal/main.py @@ -1009,6 +1009,7 @@ def delete(config, unused_plugins): """ cert_manager.delete(config) + def certificates(config, unused_plugins): """Display information about certs configured with Certbot @@ -1024,6 +1025,7 @@ def certificates(config, unused_plugins): """ cert_manager.certificates(config) + # TODO: coop with renewal config def revoke(config, unused_plugins): """Revoke a previously obtained certificate. @@ -1156,6 +1158,7 @@ def _csr_get_and_save_cert(config, le_client): os.path.normpath(config.chain_path), os.path.normpath(config.fullchain_path)) return cert_path, fullchain_path + def renew_cert(config, plugins, lineage): """Renew & save an existing cert. Do not install it. diff --git a/certbot/certbot/_internal/renewal.py b/certbot/certbot/_internal/renewal.py index 50e4d3a4c..1d008193d 100644 --- a/certbot/certbot/_internal/renewal.py +++ b/certbot/certbot/_internal/renewal.py @@ -10,7 +10,7 @@ import time import traceback from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives.asymmetric import rsa +from cryptography.hazmat.primitives.asymmetric import ec, rsa from cryptography.hazmat.primitives.serialization import load_pem_private_key import OpenSSL import six @@ -40,7 +40,7 @@ logger = logging.getLogger(__name__) STR_CONFIG_ITEMS = ["config_dir", "logs_dir", "work_dir", "user_agent", "server", "account", "authenticator", "installer", "renew_hook", "pre_hook", "post_hook", "http01_address", - "preferred_chain"] + "preferred_chain", "key_type", "elliptic_curve"] INT_CONFIG_ITEMS = ["rsa_key_size", "http01_port"] BOOL_CONFIG_ITEMS = ["must_staple", "allow_subset_of_names", "reuse_key", "autorenew"] @@ -506,6 +506,10 @@ def _update_renewal_params_from_key(key_path, config): with open(key_path, 'rb') as file_h: key = load_pem_private_key(file_h.read(), password=None, backend=default_backend()) if isinstance(key, rsa.RSAPrivateKey): + config.key_type = 'rsa' config.rsa_key_size = key.key_size + elif isinstance(key, ec.EllipticCurvePrivateKey): + config.key_type = 'ecdsa' + config.elliptic_curve = key.curve.name else: raise errors.Error('Key at {0} is of an unsupported type: {1}.'.format(key_path, type(key))) diff --git a/certbot/certbot/_internal/storage.py b/certbot/certbot/_internal/storage.py index 84bd33143..b6c37a5ba 100644 --- a/certbot/certbot/_internal/storage.py +++ b/certbot/certbot/_internal/storage.py @@ -10,6 +10,9 @@ import configobj import parsedatetime import pytz import six +from cryptography.hazmat.backends import default_backend +from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey +from cryptography.hazmat.primitives.serialization import load_pem_private_key import certbot from certbot import crypto_util @@ -46,6 +49,7 @@ def renewal_conf_files(config): result.sort() return result + def renewal_file_for_certname(config, certname): """Return /path/to/certname.conf in the renewal conf directory""" path = os.path.join(config.renewal_configs_dir, "{0}.conf".format(certname)) @@ -1055,6 +1059,23 @@ class RenewableCert(interfaces.RenewableCert): target, values) return cls(new_config.filename, cli_config) + @property + def private_key_type(self): + """ + :returns: The type of algorithm for the private, RSA or ECDSA + :rtype: str + """ + with open(self.configuration["privkey"], "rb") as priv_key_file: + key = load_pem_private_key( + data=priv_key_file.read(), + password=None, + backend=default_backend() + ) + if isinstance(key, RSAPrivateKey): + return "RSA" + else: + return "ECDSA" + def save_successor(self, prior_version, new_cert, new_privkey, new_chain, cli_config): """Save new cert and chain as a successor of a prior version. diff --git a/certbot/certbot/crypto_util.py b/certbot/certbot/crypto_util.py index d1a667548..b02e06ed7 100644 --- a/certbot/certbot/crypto_util.py +++ b/certbot/certbot/crypto_util.py @@ -11,14 +11,16 @@ import warnings import re # See https://github.com/pyca/cryptography/issues/4275 from cryptography import x509 # type: ignore -from cryptography.exceptions import InvalidSignature +from cryptography.exceptions import InvalidSignature, UnsupportedAlgorithm from cryptography.hazmat.backends import default_backend -from cryptography.hazmat.primitives.asymmetric.ec import ECDSA -from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePublicKey +from cryptography.hazmat.primitives.asymmetric import ec +from cryptography.hazmat.primitives.asymmetric.ec import ECDSA, EllipticCurvePublicKey from cryptography.hazmat.primitives.asymmetric.padding import PKCS1v15 from cryptography.hazmat.primitives.asymmetric.rsa import RSAPublicKey +from cryptography.hazmat.primitives.serialization import Encoding, NoEncryption, PrivateFormat from OpenSSL import crypto from OpenSSL import SSL # type: ignore + import pyrfc3339 import six import zope.component @@ -34,7 +36,9 @@ logger = logging.getLogger(__name__) # High level functions -def init_save_key(key_size, key_dir, keyname="key-certbot.pem"): +def init_save_key( + key_size, key_dir, key_type="rsa", elliptic_curve="secp256r1", keyname="key-certbot.pem" +): """Initializes and saves a privkey. Inits key and saves it in PEM format on the filesystem. @@ -42,8 +46,10 @@ def init_save_key(key_size, key_dir, keyname="key-certbot.pem"): .. note:: keyname is the attempted filename, it may be different if a file already exists at the path. - :param int key_size: RSA key size in bits + :param int key_size: key size in bits if key size is rsa. :param str key_dir: Key save directory. + :param str key_type: Key Type [rsa, ecdsa] + :param str elliptic_curve: Name of the elliptic curve if key type is ecdsa. :param str keyname: Filename of key :returns: Key @@ -53,7 +59,9 @@ def init_save_key(key_size, key_dir, keyname="key-certbot.pem"): """ try: - key_pem = make_key(key_size) + key_pem = make_key( + bits=key_size, elliptic_curve=elliptic_curve or "secp256r1", key_type=key_type, + ) except ValueError as err: logger.error("", exc_info=True) raise err @@ -65,7 +73,10 @@ def init_save_key(key_size, key_dir, keyname="key-certbot.pem"): os.path.join(key_dir, keyname), 0o600, "wb") with key_f: key_f.write(key_pem) - logger.debug("Generating key (%d bits): %s", key_size, key_path) + if key_type == 'rsa': + logger.debug("Generating RSA key (%d bits): %s", key_size, key_path) + else: + logger.debug("Generating ECDSA key (%d bits): %s", key_size, key_path) return util.Key(key_path, key_pem) @@ -174,18 +185,45 @@ def import_csr_file(csrfile, data): return PEM, util.CSR(file=csrfile, data=data_pem, form="pem"), domains -def make_key(bits): - """Generate PEM encoded RSA key. +def make_key(bits=1024, key_type="rsa", elliptic_curve=None): + """Generate PEM encoded RSA|EC key. - :param int bits: Number of bits, at least 1024. + :param int bits: Number of bits if key_type=rsa. At least 1024 for RSA. - :returns: new RSA key in PEM form with specified number of bits + :param str ec_curve: The elliptic curve to use. + + :returns: new RSA or ECDSA key in PEM form with specified number of bits + or of type ec_curve when key_type ecdsa is used. :rtype: str - """ - assert bits >= 1024 # XXX - key = crypto.PKey() - key.generate_key(crypto.TYPE_RSA, bits) + if key_type == 'rsa': + if bits < 1024: + raise errors.Error("Unsupported RSA key length: {}".format(bits)) + + key = crypto.PKey() + key.generate_key(crypto.TYPE_RSA, bits) + elif key_type == 'ecdsa': + try: + name = elliptic_curve.upper() + if name in ('SECP256R1', 'SECP384R1', 'SECP512R1'): + _key = ec.generate_private_key( + curve=getattr(ec, elliptic_curve.upper(), None)(), + backend=default_backend() + ) + else: + raise errors.Error("Unsupported elliptic curve: {}".format(elliptic_curve)) + except TypeError: + raise errors.Error("Unsupported elliptic curve: {}".format(elliptic_curve)) + except UnsupportedAlgorithm as e: + raise six.raise_from(e, errors.Error(str(e))) + _key_pem = _key.private_bytes( + encoding=Encoding.PEM, + format=PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=NoEncryption() + ) + key = crypto.load_privatekey(crypto.FILETYPE_PEM, _key_pem) + else: + raise errors.Error("Invalid key_type specified: {}. Use [rsa|ecdsa]".format(key_type)) return crypto.dump_privatekey(crypto.FILETYPE_PEM, key) diff --git a/certbot/certbot/interfaces.py b/certbot/certbot/interfaces.py index 43f081b95..6ba28bd56 100644 --- a/certbot/certbot/interfaces.py +++ b/certbot/certbot/interfaces.py @@ -198,6 +198,13 @@ class IConfig(zope.interface.Interface): "register multiple emails, ex: u1@example.com,u2@example.com. " "(default: Ask).") rsa_key_size = zope.interface.Attribute("Size of the RSA key.") + elliptic_curve = zope.interface.Attribute( + "The SECG elliptic curve name to use. Please see RFC 8446 " + "for supported values." + ) + key_type = zope.interface.Attribute( + "Type of generated private key" + "(Only *ONE* per invocation can be provided at this time)") must_staple = zope.interface.Attribute( "Adds the OCSP Must Staple extension to the certificate. " "Autoconfigures OCSP Stapling for supported setups " @@ -260,6 +267,7 @@ class IConfig(zope.interface.Interface): "offered chain will be used." ) + class IInstaller(IPlugin): """Generic Certbot Installer Interface. diff --git a/certbot/certbot/tests/testdata/README b/certbot/certbot/tests/testdata/README index 867215916..ade2fae2b 100644 --- a/certbot/certbot/tests/testdata/README +++ b/certbot/certbot/tests/testdata/README @@ -2,10 +2,16 @@ The following command has been used to generate test keys: for x in 256 512 2048; do openssl genrsa -out rsa${k}_key.pem $k; done +For the elliptic curve private keys, this command was used: + + for k in "prime256v1" "secp384r1" "secp521r1" do + openssl genpkey -algorithm ${k} -out ec_${k}_key.pem + done + and for the CSR PEM (Certificate Signing Request): openssl req -new -out csr-Xsans_X.pem -key rsa512_key.pem [-config csr-Xsans_X.conf | -subj '/CN=example.com'] [-outform DER > csr_X.der] and for the certificate: - openssl req -new -out cert_X.pem -key rsaX_key.pem -subj '/CN=example.com' -x509 [-outform DER > cert_X.der] \ No newline at end of file + openssl req -new -out cert_X.pem -key rsaX_key.pem -subj '/CN=example.com' -x509 [-outform DER > cert_X.der] diff --git a/certbot/certbot/tests/testdata/ec_prime256v1_key.pem b/certbot/certbot/tests/testdata/ec_prime256v1_key.pem new file mode 100644 index 000000000..77552a656 --- /dev/null +++ b/certbot/certbot/tests/testdata/ec_prime256v1_key.pem @@ -0,0 +1,8 @@ +-----BEGIN EC PARAMETERS----- +BggqhkjOPQMBBw== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIDqQPQl69kuh+DrecC8SFPt21f0F/HHDP3T4/Lf0zIVFoAoGCCqGSM49 +AwEHoUQDQgAEHou50Ee9u+8Vial6VbUHExlzsiCHtORlW0X0pKo5RspIKB0QyKwo +dUXvBbv95I9yCO5+MlGkKjwLHtIEze0Hww== +-----END EC PRIVATE KEY----- diff --git a/certbot/certbot/tests/testdata/ec_secp384r1_key.pem b/certbot/certbot/tests/testdata/ec_secp384r1_key.pem new file mode 100644 index 000000000..19a846a46 --- /dev/null +++ b/certbot/certbot/tests/testdata/ec_secp384r1_key.pem @@ -0,0 +1,9 @@ +-----BEGIN EC PARAMETERS----- +BgUrgQQAIg== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MIGkAgEBBDAgvZGw5C7Mp26N0cXA+vIg5K/J5MJw+MVGYfGF4ZutuCLeYMrWT68R +A0h6hJvDtMSgBwYFK4EEACKhZANiAAR1uQYZeU5Kml5o53Q8/PCdwUbqdgCSkV0C +J5a6bhDRMp20fdp2T/mbkdxuVEl81lqfKPZhsd4CZsLaVIU3RUoGgIT1R3QKawpJ +SuXq37yWFX2hqlgt+lsBufZ8RD5QnZc= +-----END EC PRIVATE KEY----- diff --git a/certbot/certbot/tests/testdata/ec_secp521r1_key.pem b/certbot/certbot/tests/testdata/ec_secp521r1_key.pem new file mode 100644 index 000000000..78bb9a0ea --- /dev/null +++ b/certbot/certbot/tests/testdata/ec_secp521r1_key.pem @@ -0,0 +1,10 @@ +-----BEGIN EC PARAMETERS----- +BgUrgQQAIw== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MIHcAgEBBEIACWWVKm1qAIejZ6qmqk9D69wQW5FAe3Er0IxWAMkonTEhu8EH5Q2i +2vT2bESm730zhGTe2Pn11b85H6UI9hxhCHygBwYFK4EEACOhgYkDgYYABAEQi1WF +m3suHjPyWACyOJYGUn1Kx6rfBo0PjC7X2TU9jr8umLkIpaaF5UsBuMBmdz1IHL0U +k0gQtoOQ0Qu8N74GuAGzGR0S3RYIv6gfYVz3dS1K4n4b307Lx62bnvtlNxcIvt3w +hmS5OdvQ1Kdxh6oqbSVhhbQmJcgab78Txx3R2QeCxw== +-----END EC PRIVATE KEY----- diff --git a/certbot/certbot/tests/testdata/sample-archive-ec/cert1.pem b/certbot/certbot/tests/testdata/sample-archive-ec/cert1.pem new file mode 100644 index 000000000..b07af2bf7 --- /dev/null +++ b/certbot/certbot/tests/testdata/sample-archive-ec/cert1.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC2zCCAcOgAwIBAgIIBvrEnbPRYu8wDQYJKoZIhvcNAQELBQAwKDEmMCQGA1UE +AxMdUGViYmxlIEludGVybWVkaWF0ZSBDQSAxMjZjNGIwHhcNMjAxMDEyMjEwNzQw +WhcNMjUxMDEyMjEwNzQwWjAjMSEwHwYDVQQDExhjLmVuY3J5cHRpb24tZXhhbXBs +ZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARjMhuW0ENPPC33PjB5XsYU +CRw640kPQENIDatcTJaENZIZdqKd6rI6jc+lpbmXot7Zi52clJlSJS+V6oDAt2Lh +o4HYMIHVMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB +BQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUj7Kd3ENqxlPf8B2bIGhsjydX +mPswHwYDVR0jBBgwFoAUEiGxlkRsi+VvcogH5dVD3h1laAcwMQYIKwYBBQUHAQEE +JTAjMCEGCCsGAQUFBzABhhVodHRwOi8vMTI3LjAuMC4xOjQwMDIwIwYDVR0RBBww +GoIYYy5lbmNyeXB0aW9uLWV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQCl +k0JXsa8y7fg41WWMDhw60bPW77O0FtOmTcnhdI5daYNemQVk+Q5EMaBLQ/oGjgXd +9QXFzXH1PL904YEnSLt+iTpXn++7rQSNzQsdYqw0neWk4f5pEBiN+WORpb6mwobV +ifMtBOkNEHvrJ2Pkci9U1lLwtKD/DSew6QtJU5DSkmH1XdGuMJiubygEIvELtvgq +cP9S368ZvPmPGmKaJQXBiuaR8MTjY/Bkr79aXQMjKbf+mpn7h0POCcePk1DY/rm6 +Da+X16lf0hHyQhSUa7Vgyim6rK1/hlw+Z00i+sQCKD9Ih7kXuuGqfSDC33cfO8Tj +o/MXO8lcxkrem5zU5QWP +-----END CERTIFICATE----- diff --git a/certbot/certbot/tests/testdata/sample-archive-ec/chain1.pem b/certbot/certbot/tests/testdata/sample-archive-ec/chain1.pem new file mode 100644 index 000000000..64a805c0f --- /dev/null +++ b/certbot/certbot/tests/testdata/sample-archive-ec/chain1.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDUDCCAjigAwIBAgIIbi787yVrcMAwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE +AxMVUGViYmxlIFJvb3QgQ0EgMGM1MjI1MCAXDTIwMTAxMjIwMjI0NloYDzIwNTAx +MDEyMjEyMjQ2WjAoMSYwJAYDVQQDEx1QZWJibGUgSW50ZXJtZWRpYXRlIENBIDEy +NmM0YjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALGeVk1BMJraeqRq +mJ2+hgso8VOAv2s2CVxUJjIVcn7f2adE8NyTsSQ1brlsnKCUYUw7yLTQH0izLQRB +qKVIDFkUqo5/FuTJ2QlfA2EwBL8J7s/7L7vj3L0DiVpwgxPSyFEwdl/Y5y7ofsX5 +CIhCFcaMAmTIuKLiSfCJjGwkbEMuolm+lO8Mikxxc/JtDVUC479ugU7PU9O09bMH +nm+sD6Bgd+KMoPkCCCoeShJS9X3Ziq9HGc7Z6nhM/zirFARt2XkonEdAZ8br01zY +MRiY9txhlWQ7mUkOtzOSoEuYJNoUbvMUf0+tNzto26WRyF7dJmh7lTBsYrvAwUTx +PzNyst0CAwEAAaOBgzCBgDAOBgNVHQ8BAf8EBAMCAoQwHQYDVR0lBBYwFAYIKwYB +BQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFBIhsZZE +bIvlb3KIB+XVQ94dZWgHMB8GA1UdIwQYMBaAFOaKTaXg37vKgRt7d79YOjAoAtJT +MA0GCSqGSIb3DQEBCwUAA4IBAQAU2mZii7PH2pkw2lNM0QqPbcW/UYyvFoUeM8Aq +uCtsI2s+oxCJTqzfLsA0N8NY4nHLQ5wAlNJfJekngni8hbmJTKU4JFTMe7kLQO8P +fJbk0pTzhhHVQw7CVwB6Pwq3u2m/JV+d6xDIDc+AVkuEl19ZJU0rTWyooClfFLZV +EdZmEiUtA3PGlxoYwYhoGHYlhFxsoFONhCsBEdN7k7FKtFGVxN7oc5SKmKp0YZTW +fcrEtrdNThATO4ymhCC2zh33NI/MT1O74fpaAc2k6LcTl57MKiLfTYX4LTL6v9JG +9tlNqjFVRRmzEbtXTPcCb+w9g1VqoOGok7mGXYLTYtShCuvE +-----END CERTIFICATE----- diff --git a/certbot/certbot/tests/testdata/sample-archive-ec/fullchain1.pem b/certbot/certbot/tests/testdata/sample-archive-ec/fullchain1.pem new file mode 100644 index 000000000..1ba80ba4e --- /dev/null +++ b/certbot/certbot/tests/testdata/sample-archive-ec/fullchain1.pem @@ -0,0 +1,38 @@ +-----BEGIN CERTIFICATE----- +MIIC2zCCAcOgAwIBAgIILlmGtZhUFEwwDQYJKoZIhvcNAQELBQAwKDEmMCQGA1UE +AxMdUGViYmxlIEludGVybWVkaWF0ZSBDQSAxMjZjNGIwHhcNMjAxMDEyMjA1MDM0 +WhcNMjUxMDEyMjA1MDM0WjAjMSEwHwYDVQQDExhjLmVuY3J5cHRpb24tZXhhbXBs +ZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAARHEzR8JPWrEmpmgM+F2bk5 +9mT0u6CjzmJG0QpbaqprLiG5NGpW84VQ5TFCrmC4KxYfigCfMhfHRNfFYvNUK3V/ +o4HYMIHVMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYB +BQUHAwIwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU1CsVL+bPnzaxxQ5jUENmQJIO +lKwwHwYDVR0jBBgwFoAUEiGxlkRsi+VvcogH5dVD3h1laAcwMQYIKwYBBQUHAQEE +JTAjMCEGCCsGAQUFBzABhhVodHRwOi8vMTI3LjAuMC4xOjQwMDIwIwYDVR0RBBww +GoIYYy5lbmNyeXB0aW9uLWV4YW1wbGUuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQBn +2D8loC7pfk28JYpFLr5lmFKJWWmtLGlpsWDj61fVjtTfGKLziJz+MM6il4Y3hIz5 +58qiFK0ue0M63dIBJ33N+XxSEXon4Q0gy/zRWfH9jtPJ3FwfjkU/RT9PAUClYi0G +ptNWnTmgQkNzousbcAtRNXuuShH3856vhUnwkX+xM+cbIDi1JVmFjcGrEEQJ0rUF +mv2ZTyfbWbUs3v4rReETi2NVzr1Ql6J+ByNcMvHODzFy3t0L6yelAw2ca1I+c9HU ++Z0tnp/ykR7eXNuVLivok8UBf5OC413lh8ZO5g+Bgzh/LdtkUuavg1MYtEX0H6mX +9U7y3nVI8WEbPGf+HDeu +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIDUDCCAjigAwIBAgIIbi787yVrcMAwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UE +AxMVUGViYmxlIFJvb3QgQ0EgMGM1MjI1MCAXDTIwMTAxMjIwMjI0NloYDzIwNTAx +MDEyMjEyMjQ2WjAoMSYwJAYDVQQDEx1QZWJibGUgSW50ZXJtZWRpYXRlIENBIDEy +NmM0YjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALGeVk1BMJraeqRq +mJ2+hgso8VOAv2s2CVxUJjIVcn7f2adE8NyTsSQ1brlsnKCUYUw7yLTQH0izLQRB +qKVIDFkUqo5/FuTJ2QlfA2EwBL8J7s/7L7vj3L0DiVpwgxPSyFEwdl/Y5y7ofsX5 +CIhCFcaMAmTIuKLiSfCJjGwkbEMuolm+lO8Mikxxc/JtDVUC479ugU7PU9O09bMH +nm+sD6Bgd+KMoPkCCCoeShJS9X3Ziq9HGc7Z6nhM/zirFARt2XkonEdAZ8br01zY +MRiY9txhlWQ7mUkOtzOSoEuYJNoUbvMUf0+tNzto26WRyF7dJmh7lTBsYrvAwUTx +PzNyst0CAwEAAaOBgzCBgDAOBgNVHQ8BAf8EBAMCAoQwHQYDVR0lBBYwFAYIKwYB +BQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFBIhsZZE +bIvlb3KIB+XVQ94dZWgHMB8GA1UdIwQYMBaAFOaKTaXg37vKgRt7d79YOjAoAtJT +MA0GCSqGSIb3DQEBCwUAA4IBAQAU2mZii7PH2pkw2lNM0QqPbcW/UYyvFoUeM8Aq +uCtsI2s+oxCJTqzfLsA0N8NY4nHLQ5wAlNJfJekngni8hbmJTKU4JFTMe7kLQO8P +fJbk0pTzhhHVQw7CVwB6Pwq3u2m/JV+d6xDIDc+AVkuEl19ZJU0rTWyooClfFLZV +EdZmEiUtA3PGlxoYwYhoGHYlhFxsoFONhCsBEdN7k7FKtFGVxN7oc5SKmKp0YZTW +fcrEtrdNThATO4ymhCC2zh33NI/MT1O74fpaAc2k6LcTl57MKiLfTYX4LTL6v9JG +9tlNqjFVRRmzEbtXTPcCb+w9g1VqoOGok7mGXYLTYtShCuvE +-----END CERTIFICATE----- diff --git a/certbot/certbot/tests/testdata/sample-archive-ec/privkey1.pem b/certbot/certbot/tests/testdata/sample-archive-ec/privkey1.pem new file mode 100644 index 000000000..6843b83d6 --- /dev/null +++ b/certbot/certbot/tests/testdata/sample-archive-ec/privkey1.pem @@ -0,0 +1,5 @@ +-----BEGIN PRIVATE KEY----- +MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgNgefv2dad4U1VYEi +0WkdHuqywi5QXAe30OwNTTGjhbihRANCAARHEzR8JPWrEmpmgM+F2bk59mT0u6Cj +zmJG0QpbaqprLiG5NGpW84VQ5TFCrmC4KxYfigCfMhfHRNfFYvNUK3V/ +-----END PRIVATE KEY----- diff --git a/certbot/certbot/tests/testdata/sample-renewal-ec.conf b/certbot/certbot/tests/testdata/sample-renewal-ec.conf new file mode 100644 index 000000000..d8a4b32bf --- /dev/null +++ b/certbot/certbot/tests/testdata/sample-renewal-ec.conf @@ -0,0 +1,79 @@ +# add some stuff here +# assets/integration_tests + +cert = MAGICDIR/live/sample-renewal-ec/cert.pem +privkey = MAGICDIR/live/sample-renewal-ec/privkey.pem +chain = MAGICDIR/live/sample-renewal-ec/chain.pem +fullchain = MAGICDIR/live/sample-renewal-ec/fullchain.pem +renew_before_expiry = 4 years + +# Options and defaults used in the renewal process +[renewalparams] +no_self_upgrade = False +apache_enmod = a2enmod +no_verify_ssl = False +ifaces = None +apache_dismod = a2dismod +register_unsafely_without_email = False +apache_handle_modules = True +uir = None +installer = None +nginx_ctl = nginx +config_dir = MAGICDIR +text_mode = False +func = +staging = True +prepare = False +work_dir = /var/lib/letsencrypt +tos = False +init = False +http01_port = 80 +duplicate = False +noninteractive_mode = True +key_path = None +nginx = False +nginx_server_root = /etc/nginx +fullchain_path = /home/ubuntu/letsencrypt/chain.pem +email = None +csr = None +agree_dev_preview = None +redirect = None +verb = certonly +verbose_count = -3 +config_file = None +renew_by_default = False +hsts = False +apache_handle_sites = True +authenticator = standalone +domains = isnot.org, +key_type = ecdsa +elliptic_curve = secp256r1 +apache_challenge_location = /etc/apache2 +checkpoints = 1 +manual_test_mode = False +apache = False +cert_path = /home/ubuntu/letsencrypt/cert.pem +webroot_path = None +reinstall = False +expand = False +strict_permissions = False +apache_server_root = /etc/apache2 +account = None +dry_run = False +manual_public_ip_logging_ok = False +chain_path = /home/ubuntu/letsencrypt/chain.pem +break_my_certs = False +standalone = True +manual = False +server = https://acme-staging-v02.api.letsencrypt.org/directory +webroot = False +os_packages_only = False +apache_init_script = None +user_agent = None +apache_le_vhost_ext = -le-ssl.conf +debug = False +logs_dir = /var/log/letsencrypt +apache_vhost_root = /etc/apache2/sites-available +configurator = None +must_staple = True +[[webroot_map]] diff --git a/certbot/certbot/tests/testdata/sample-renewal.conf b/certbot/certbot/tests/testdata/sample-renewal.conf index 936c5c0e0..0c56781b3 100644 --- a/certbot/certbot/tests/testdata/sample-renewal.conf +++ b/certbot/certbot/tests/testdata/sample-renewal.conf @@ -44,6 +44,7 @@ apache_handle_sites = True authenticator = standalone domains = isnot.org, rsa_key_size = 2048 +elliptic_curve = secp256r1 apache_challenge_location = /etc/apache2 checkpoints = 1 manual_test_mode = False diff --git a/certbot/certbot/tests/util.py b/certbot/certbot/tests/util.py index 92f52a852..b9d5caa08 100644 --- a/certbot/certbot/tests/util.py +++ b/certbot/certbot/tests/util.py @@ -93,7 +93,7 @@ def load_pyopenssl_private_key(*names): return OpenSSL.crypto.load_privatekey(loader, load_vector(*names)) -def make_lineage(config_dir, testfile): +def make_lineage(config_dir, testfile, ec=False): """Creates a lineage defined by testfile. This creates the archive, live, and renewal directories if @@ -119,7 +119,7 @@ def make_lineage(config_dir, testfile): if not os.path.exists(directory): filesystem.makedirs(directory) - sample_archive = vector_path('sample-archive') + sample_archive = vector_path('sample-archive{}'.format('-ec' if ec else '')) for kind in os.listdir(sample_archive): shutil.copyfile(os.path.join(sample_archive, kind), os.path.join(archive_dir, kind)) diff --git a/certbot/docs/ciphers.rst b/certbot/docs/ciphers.rst index 294e6a7fa..43f648898 100644 --- a/certbot/docs/ciphers.rst +++ b/certbot/docs/ciphers.rst @@ -80,8 +80,8 @@ its preferences in accordance with its own policy or its administrators' preferences, and use different cryptographic mechanisms or parameters, or a different priority order, than the defaults provided by Certbot. -If you don't use Certbot to configure your server directly, because the -client doesn't integrate with your server software or because you chose +If you don't use Certbot to configure your server directly, because the +client doesn't integrate with your server software or because you chose not to use this integration, then the cryptographic defaults haven't been modified, and the cryptography chosen by the server will still be whatever the default for your software was. For example, if you obtain a @@ -254,7 +254,7 @@ https://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/elb-secur U.S. Government 18F ~~~~~~~~~~~~~~~~~~~ -The 18F site (https://18f.gsa.gov/) is using +The 18F site (https://18f.gsa.gov/) is using :: diff --git a/certbot/docs/cli-help.txt b/certbot/docs/cli-help.txt index 3c3497282..5f8e2e00b 100644 --- a/certbot/docs/cli-help.txt +++ b/certbot/docs/cli-help.txt @@ -1,4 +1,4 @@ -usage: +usage: certbot [SUBCOMMAND] [options] [-d DOMAIN] [-d DOMAIN] ... Certbot can obtain and install HTTPS/TLS/SSL certificates. By default, @@ -188,6 +188,12 @@ security: Security parameters & server settings --rsa-key-size N Size of the RSA key. (default: 2048) + --key-type type The type of algorithm to use for the the private key. + Either ``rsa`` or ``ecdsa``. (default: ``rsa``). + --elliptic-curve The elliptic curve to use when choosing ``ecdsa`` as the key + type. Accepted values are SECG curve names as defined by + the cryptography library. ``secp256r1``, ``secp384r1``, + ``secp521r1``. (default: secp256r1). --must-staple Adds the OCSP Must Staple extension to the certificate. Autoconfigures OCSP Stapling for supported setups (Apache version >= 2.3.3 ). (default: diff --git a/certbot/docs/using.rst b/certbot/docs/using.rst index 290ac817a..353029822 100644 --- a/certbot/docs/using.rst +++ b/certbot/docs/using.rst @@ -319,6 +319,7 @@ This returns information in the following format:: Domains: example.com, www.example.com Expiry Date: 2017-02-19 19:53:00+00:00 (VALID: 30 days) Certificate Path: /etc/letsencrypt/live/example.com/fullchain.pem + Key Type: RSA Private Key Path: /etc/letsencrypt/live/example.com/privkey.pem ``Certificate Name`` shows the name of the certificate. Pass this name @@ -346,7 +347,6 @@ control Certbot's behavior when re-creating a certificate with the same name as an existing certificate. If you don't specify a requested behavior, Certbot may ask you what you intended. - ``--force-renewal`` tells Certbot to request a new certificate with the same domains as an existing certificate. Each domain must be explicitly specified via ``-d``. If successful, this certificate @@ -380,7 +380,6 @@ If you prefer, you can specify the domains individually like this: Consider using ``--cert-name`` instead of ``--expand``, as it gives more control over which certificate is modified and it lets you remove domains as well as adding them. - ``--allow-subset-of-names`` tells Certbot to continue with certificate generation if only some of the specified domain authorizations can be obtained. This may be useful if some domains specified in a certificate no longer point at this @@ -411,6 +410,19 @@ replace that set entirely:: certbot certonly --cert-name example.com -d example.org,www.example.org +Migrating to certificates based on ECDSA keys +--------------------------------------------- + +As of version 1.10, Certbot supports two types of private key algorithms: +``rsa`` and ``ecdsa``. You may freely upgrade an existing certificate with a +new private key. This requires issuing a new command, or changing the renewal +file for the certificates so it will happen on the next renewal. The two +options that you need for the renewal command are ``--key-type`` and +``--elliptic-curve `` in case you either want to be explicit or want to +use something else than the default curve ``secp256r1``:: + + certbot renew --key-type ecdsa --cert-name example.com -d example.org,www.example.org + Revoking certificates --------------------- diff --git a/certbot/examples/cli.ini b/certbot/examples/cli.ini index 4215fda5b..dfb1d6fff 100644 --- a/certbot/examples/cli.ini +++ b/certbot/examples/cli.ini @@ -7,6 +7,10 @@ # certificate on a system with several certificates should not be placed # here. +# Use ECC for the private key +key-type = ecdsa +elliptic-curve = secp384r1 + # Use a 4096 bit RSA key instead of 2048 rsa-key-size = 4096 diff --git a/certbot/tests/cli_test.py b/certbot/tests/cli_test.py index 7475e99ea..e65ec32ec 100644 --- a/certbot/tests/cli_test.py +++ b/certbot/tests/cli_test.py @@ -359,6 +359,21 @@ class ParseTest(unittest.TestCase): self.assertFalse(cli.option_was_set( 'authenticator', cli.flag_default('authenticator'))) + def test_ecdsa_key_option(self): + elliptic_curve_option = 'elliptic_curve' + elliptic_curve_option_value = cli.flag_default(elliptic_curve_option) + self.parse('--elliptic-curve {0}'.format(elliptic_curve_option_value).split()) + self.assertIs(cli.option_was_set(elliptic_curve_option, elliptic_curve_option_value), True) + + def test_invalid_key_type(self): + key_type_option = 'key_type' + key_type_value = cli.flag_default(key_type_option) + self.parse('--key-type {0}'.format(key_type_value).split()) + self.assertIs(cli.option_was_set(key_type_option, key_type_value), True) + + with self.assertRaises(SystemExit): + self.parse("--key-type foo") + def test_encode_revocation_reason(self): for reason, code in constants.REVOCATION_REASONS.items(): namespace = self.parse(['--reason', reason]) diff --git a/certbot/tests/client_test.py b/certbot/tests/client_test.py index 1b2a7413e..f40689e57 100644 --- a/certbot/tests/client_test.py +++ b/certbot/tests/client_test.py @@ -329,7 +329,11 @@ class ClientTest(ClientTestCommon): self._test_obtain_certificate_common(mock.sentinel.key, csr) mock_crypto_util.init_save_key.assert_called_once_with( - self.config.rsa_key_size, self.config.key_dir) + key_size=self.config.rsa_key_size, + key_dir=self.config.key_dir, + key_type=self.config.key_type, + elliptic_curve=None, # elliptic curve is not set + ) mock_crypto_util.init_save_csr.assert_called_once_with( mock.sentinel.key, self.eg_domains, self.config.csr_dir) mock_crypto_util.cert_and_chain_from_fullchain.assert_called_once_with( @@ -365,7 +369,11 @@ class ClientTest(ClientTestCommon): self.client.config.dry_run = True self._test_obtain_certificate_common(key, csr) - mock_crypto.make_key.assert_called_once_with(self.config.rsa_key_size) + mock_crypto.make_key.assert_called_once_with( + bits=self.config.rsa_key_size, + elliptic_curve=None, # not making an elliptic private key + key_type=self.config.key_type, + ) mock_acme_crypto.make_csr.assert_called_once_with( mock.sentinel.key_pem, self.eg_domains, self.config.must_staple) mock_crypto.init_save_key.assert_not_called() diff --git a/certbot/tests/crypto_util_test.py b/certbot/tests/crypto_util_test.py index bbd484c91..37673db99 100644 --- a/certbot/tests/crypto_util_test.py +++ b/certbot/tests/crypto_util_test.py @@ -4,7 +4,7 @@ import unittest try: import mock -except ImportError: # pragma: no cover +except ImportError: # pragma: no cover from unittest import mock import OpenSSL import zope.component @@ -32,6 +32,7 @@ CERT_LEAF = test_util.load_vector('cert_leaf.pem') CERT_ISSUER = test_util.load_vector('cert_intermediate_1.pem') CERT_ALT_ISSUER = test_util.load_vector('cert_intermediate_2.pem') + class InitSaveKeyTest(test_util.TempDirTestCase): """Tests for certbot.crypto_util.init_save_key.""" def setUp(self): @@ -174,11 +175,54 @@ class ImportCSRFileTest(unittest.TestCase): class MakeKeyTest(unittest.TestCase): """Tests for certbot.crypto_util.make_key.""" - def test_it(self): # pylint: disable=no-self-use + def test_rsa(self): # pylint: disable=no-self-use + # RSA Key Type Test from certbot.crypto_util import make_key # Do not test larger keys as it takes too long. + OpenSSL.crypto.load_privatekey(OpenSSL.crypto.FILETYPE_PEM, make_key(1024)) + + def test_ec(self): # pylint: disable=no-self-use + # ECDSA Key Type Tests + from certbot.crypto_util import make_key + # Do not test larger keys as it takes too long. + + # Try a good key size for ECDSA OpenSSL.crypto.load_privatekey( - OpenSSL.crypto.FILETYPE_PEM, make_key(1024)) + OpenSSL.crypto.FILETYPE_PEM, make_key(elliptic_curve="secp256r1", key_type='ecdsa')) + + def test_bad_key_sizes(self): + from certbot.crypto_util import make_key + # Try a bad key size for RSA and ECDSA + with self.assertRaises(errors.Error) as e: + make_key(bits=512, key_type='rsa') + self.assertEqual( + "Unsupported RSA key length: 512", + str(e.exception), + "Unsupported RSA key length: 512" + ) + + def test_bad_elliptic_curve_name(self): + from certbot.crypto_util import make_key + with self.assertRaises(errors.Error) as e: + make_key(elliptic_curve="nothere", key_type='ecdsa') + self.assertEqual( + "Unsupported elliptic curve: nothere", + str(e.exception), + "Unsupported elliptic curve: nothere" + ) + + def test_bad_key_type(self): + from certbot.crypto_util import make_key + + # Try a bad --key-type + with self.assertRaises(errors.Error) as e: + OpenSSL.crypto.load_privatekey( + OpenSSL.crypto.FILETYPE_PEM, make_key(1024, key_type='unf')) + self.assertEqual( + "Invalid key_type specified: unf. Use [rsa|ecdsa]", + str(e.exception), + "Invalid key_type specified: unf. Use [rsa|ecdsa]", + ) class VerifyCertSetup(unittest.TestCase): diff --git a/certbot/tests/renewal_test.py b/certbot/tests/renewal_test.py index 0957b5c31..e292d24fb 100644 --- a/certbot/tests/renewal_test.py +++ b/certbot/tests/renewal_test.py @@ -74,6 +74,30 @@ class RenewalTest(test_util.ConfigTestCase): assert self.config.rsa_key_size == 2048 + def test_reuse_ec_key_renewal_params(self): + self.config.elliptic_curve = 'INVALID_CURVE' + self.config.reuse_key = True + self.config.dry_run = True + self.config.key_type = 'ecdsa' + config = configuration.NamespaceConfig(self.config) + + rc_path = test_util.make_lineage( + self.config.config_dir, + 'sample-renewal-ec.conf', + ec=True, + ) + lineage = storage.RenewableCert(rc_path, config) + + le_client = mock.MagicMock() + le_client.obtain_certificate.return_value = (None, None, None, None) + + from certbot._internal import renewal + + with mock.patch('certbot._internal.renewal.hooks.renew_hook'): + renewal.renew_cert(self.config, None, le_client, lineage) + + assert self.config.elliptic_curve == 'secp256r1' + class RestoreRequiredConfigElementsTest(test_util.ConfigTestCase): """Tests for certbot._internal.renewal.restore_required_config_elements.""" From 8f5787008de288c2cec6e5d3763854703d02f298 Mon Sep 17 00:00:00 2001 From: Adrien Ferrand Date: Wed, 11 Nov 2020 21:36:16 +0100 Subject: [PATCH 02/42] Handle unexpected key type migration. (#8435) Fixes #8365 This PR adds a control when `certbot certonly` or `certbot run` are called for a certificate that already exists and would eventually be replaced. As described in #8365, this control is here to ensure that the user will not modify the key type of their certificate (eg. ECDSA to RSA) without an explicit approval (set explicitly `--cert-name` and `--key-type`), since RSA is the default if not specified. * Handle unexpected key type migration. * Update certbot-ci/certbot_integration_tests/certbot_tests/test_main.py Co-authored-by: Brad Warren --- .../certbot_tests/test_main.py | 10 ++++ certbot/certbot/_internal/main.py | 51 +++++++++++++++++-- certbot/tests/main_test.py | 51 +++++++++++++++++-- 3 files changed, 102 insertions(+), 10 deletions(-) diff --git a/certbot-ci/certbot_integration_tests/certbot_tests/test_main.py b/certbot-ci/certbot_integration_tests/certbot_tests/test_main.py index 02c537733..58d5a852d 100644 --- a/certbot-ci/certbot_integration_tests/certbot_tests/test_main.py +++ b/certbot-ci/certbot_integration_tests/certbot_tests/test_main.py @@ -499,6 +499,16 @@ def test_renew_with_ec_keys(context): assert_elliptic_key(key2, SECP384R1) assert 280 < os.stat(key2).st_size < 320 # ec keys of 384 bits are ~310 bytes + # We expect here that the command will fail because without --key-type specified, + # Certbot must error out to prevent changing an existing certificate key type, + # without explicit user consent (by specifying both --cert-name and --key-type). + with pytest.raises(subprocess.CalledProcessError): + context.certbot([ + 'certonly', + '--force-renewal', + '-d', certname + ]) + def test_ocsp_must_staple(context): """Test that OCSP Must-Staple is correctly set in the generated certificate.""" diff --git a/certbot/certbot/_internal/main.py b/certbot/certbot/_internal/main.py index fd7df8d83..8d62210e0 100644 --- a/certbot/certbot/_internal/main.py +++ b/certbot/certbot/_internal/main.py @@ -11,7 +11,7 @@ import josepy as jose import zope.component from acme import errors as acme_errors -from acme.magic_typing import Union, Iterable, Optional # pylint: disable=unused-import +from acme.magic_typing import Union, Iterable, Optional, List, Tuple # pylint: disable=unused-import import certbot from certbot import crypto_util from certbot import errors @@ -130,7 +130,33 @@ def _get_and_save_cert(le_client, config, domains=None, certname=None, lineage=N return lineage -def _handle_subset_cert_request(config, domains, cert): +def _handle_unexpected_key_type_migration(config, cert): + # type: (configuration.NamespaceConfig, storage.RenewableCert) -> None + """ + This function ensures that the user will not implicitly migrate an existing key + from one type to another in the situation where a certificate for that lineage + already exist and they have not provided explicitly --key-type and --cert-name. + :param config: Current configuration provided by the client + :param cert: Matching certificate that could be renewed + """ + if not cli.set_by_cli("key_type") or not cli.set_by_cli("certname"): + + new_key_type = config.key_type.upper() + cur_key_type = cert.private_key_type.upper() + + if new_key_type != cur_key_type: + msg = ('Are you trying to change the key type of the certificate named {0} ' + 'from {1} to {2}? Please provide both --cert-name and --key-type on ' + 'the command line confirm the change you are trying to make.') + msg = msg.format(cert.lineagename, cur_key_type, new_key_type) + raise errors.Error(msg) + + +def _handle_subset_cert_request(config, # type: configuration.NamespaceConfig + domains, # type: List[str] + cert # type: storage.RenewableCert + ): + # type: (...) -> Tuple[str, Optional[storage.RenewableCert]] """Figure out what to do if a previous cert had a subset of the names now requested :param config: Configuration object @@ -147,6 +173,8 @@ def _handle_subset_cert_request(config, domains, cert): :rtype: `tuple` of `str` """ + _handle_unexpected_key_type_migration(config, cert) + existing = ", ".join(cert.names()) question = ( "You have an existing certificate that contains a portion of " @@ -177,7 +205,10 @@ def _handle_subset_cert_request(config, domains, cert): raise errors.Error(USER_CANCELLED) -def _handle_identical_cert_request(config, lineage): +def _handle_identical_cert_request(config, # type: configuration.NamespaceConfig + lineage, # type: storage.RenewableCert + ): + # type: (...) -> Tuple[str, Optional[storage.RenewableCert]] """Figure out what to do if a lineage has the same names as a previously obtained one :param config: Configuration object @@ -191,6 +222,8 @@ def _handle_identical_cert_request(config, lineage): :rtype: `tuple` of `str` """ + _handle_unexpected_key_type_migration(config, lineage) + if not lineage.ensure_deployed(): return "reinstall", lineage if renewal.should_renew(config, lineage): @@ -266,6 +299,7 @@ def _find_lineage_for_domains(config, domains): return _handle_subset_cert_request(config, domains, subset_names_cert) return None, None + def _find_cert(config, domains, certname): """Finds an existing certificate object given domains and/or a certificate name. @@ -289,7 +323,12 @@ def _find_cert(config, domains, certname): logger.info("Keeping the existing certificate") return (action != "reinstall"), lineage -def _find_lineage_for_domains_and_certname(config, domains, certname): + +def _find_lineage_for_domains_and_certname(config, # type: configuration.NamespaceConfig + domains, # type: List[str] + certname # type: str + ): + # type: (...) -> Tuple[str, Optional[storage.RenewableCert]] """Find appropriate lineage based on given domains and/or certname. :param config: Configuration object @@ -316,8 +355,9 @@ def _find_lineage_for_domains_and_certname(config, domains, certname): if lineage: if domains: if set(cert_manager.domains_for_certname(config, certname)) != set(domains): + _handle_unexpected_key_type_migration(config, lineage) _ask_user_to_confirm_new_names(config, domains, certname, - lineage.names()) # raises if no + lineage.names()) # raises if no return "renew", lineage # unnecessarily specified domains or no domains specified return _handle_identical_cert_request(config, lineage) @@ -386,6 +426,7 @@ def _ask_user_to_confirm_new_names(config, new_domains, certname, old_domains): if not obj.yesno(msg, "Update cert", "Cancel", default=True): raise errors.ConfigurationError("Specified mismatched cert name and domains.") + def _find_domains_or_certname(config, installer, question=None): """Retrieve domains and certname from config or user input. diff --git a/certbot/tests/main_test.py b/certbot/tests/main_test.py index 691ced439..26154ae16 100644 --- a/certbot/tests/main_test.py +++ b/certbot/tests/main_test.py @@ -49,14 +49,51 @@ RSA2048_KEY_PATH = test_util.vector_path('rsa2048_key.pem') SS_CERT_PATH = test_util.vector_path('cert_2048.pem') -class TestHandleIdenticalCerts(unittest.TestCase): - """Test for certbot._internal.main._handle_identical_cert_request""" - def test_handle_identical_cert_request_pending(self): +class TestHandleCerts(unittest.TestCase): + """Test for certbot._internal.main._handle_* methods""" + @mock.patch("certbot._internal.main._handle_unexpected_key_type_migration") + def test_handle_identical_cert_request_pending(self, mock_handle_migration): mock_lineage = mock.Mock() mock_lineage.ensure_deployed.return_value = False # pylint: disable=protected-access ret = main._handle_identical_cert_request(mock.Mock(), mock_lineage) self.assertEqual(ret, ("reinstall", mock_lineage)) + self.assertTrue(mock_handle_migration.called) + + @mock.patch("certbot._internal.main._handle_unexpected_key_type_migration") + def test_handle_subset_cert_request(self, mock_handle_migration): + mock_config = mock.Mock() + mock_config.expand = True + mock_lineage = mock.Mock() + mock_lineage.names.return_value = ["dummy1", "dummy2"] + ret = main._handle_subset_cert_request(mock_config, ["dummy1"], mock_lineage) + self.assertEqual(ret, ("renew", mock_lineage)) + self.assertTrue(mock_handle_migration.called) + + @mock.patch("certbot._internal.main.cli.set_by_cli") + def test_handle_unexpected_key_type_migration(self, mock_set): + config = mock.Mock() + config.key_type = "rsa" + cert = mock.Mock() + cert.private_key_type = "ecdsa" + + mock_set.return_value = True + main._handle_unexpected_key_type_migration(config, cert) + + mock_set.return_value = False + with self.assertRaises(errors.Error) as raised: + main._handle_unexpected_key_type_migration(config, cert) + self.assertTrue("Please provide both --cert-name and --key-type" in str(raised.exception)) + + mock_set.side_effect = lambda var: var != "certname" + with self.assertRaises(errors.Error) as raised: + main._handle_unexpected_key_type_migration(config, cert) + self.assertTrue("Please provide both --cert-name and --key-type" in str(raised.exception)) + + mock_set.side_effect = lambda var: var != "key_type" + with self.assertRaises(errors.Error) as raised: + main._handle_unexpected_key_type_migration(config, cert) + self.assertTrue("Please provide both --cert-name and --key-type" in str(raised.exception)) class RunTest(test_util.ConfigTestCase): @@ -163,9 +200,10 @@ class CertonlyTest(unittest.TestCase): @mock.patch('certbot._internal.cert_manager.lineage_for_certname') @mock.patch('certbot._internal.cert_manager.domains_for_certname') @mock.patch('certbot._internal.renewal.renew_cert') + @mock.patch('certbot._internal.main._handle_unexpected_key_type_migration') @mock.patch('certbot._internal.main._report_new_cert') def test_find_lineage_for_domains_and_certname(self, mock_report_cert, - mock_renew_cert, mock_domains, mock_lineage): + mock_handle_type, mock_renew_cert, mock_domains, mock_lineage): domains = ['example.com', 'test.org'] mock_domains.return_value = domains mock_lineage.names.return_value = domains @@ -175,6 +213,7 @@ class CertonlyTest(unittest.TestCase): self.assertTrue(mock_domains.call_count == 1) self.assertTrue(mock_renew_cert.call_count == 1) self.assertTrue(mock_report_cert.call_count == 1) + self.assertTrue(mock_handle_type.call_count == 1) # user confirms updating lineage with new domains self._call(('certonly --webroot -d example.com -d test.com ' @@ -183,11 +222,12 @@ class CertonlyTest(unittest.TestCase): self.assertTrue(mock_domains.call_count == 2) self.assertTrue(mock_renew_cert.call_count == 2) self.assertTrue(mock_report_cert.call_count == 2) + self.assertTrue(mock_handle_type.call_count == 2) # error in _ask_user_to_confirm_new_names self.mock_get_utility().yesno.return_value = False self.assertRaises(errors.ConfigurationError, self._call, - ('certonly --webroot -d example.com -d test.com --cert-name example.com').split()) + 'certonly --webroot -d example.com -d test.com --cert-name example.com'.split()) @mock.patch('certbot._internal.cert_manager.domains_for_certname') @mock.patch('certbot.display.ops.choose_names') @@ -982,6 +1022,7 @@ class MainTest(test_util.ConfigTestCase): mock_lineage.should_autorenew.return_value = due_for_renewal mock_lineage.has_pending_deployment.return_value = False mock_lineage.names.return_value = ['isnot.org'] + mock_lineage.private_key_type = 'RSA' mock_certr = mock.MagicMock() mock_key = mock.MagicMock(pem='pem_key') mock_client = mock.MagicMock() From 2a118f3e8331881aaecc132d5095b4941b7c710d Mon Sep 17 00:00:00 2001 From: Adrien Ferrand Date: Wed, 11 Nov 2020 21:54:29 +0100 Subject: [PATCH 03/42] Close the session once snap connections are acquired (#8438) This PR uses the context manager available for `requests.Session` to close properly the `session` once snap connections have been acquired. --- certbot/certbot/_internal/snap_config.py | 30 ++++++++++++------------ 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/certbot/certbot/_internal/snap_config.py b/certbot/certbot/_internal/snap_config.py index e92d9431c..a90740787 100644 --- a/certbot/certbot/_internal/snap_config.py +++ b/certbot/certbot/_internal/snap_config.py @@ -49,22 +49,22 @@ def prepare_env(cli_args): os.environ['CERTBOT_AUGEAS_PATH'] = '{0}/usr/lib/{1}/libaugeas.so.0'.format( os.environ.get('SNAP'), _ARCH_TRIPLET_MAP[snap_arch]) - session = Session() - session.mount('http://snapd/', _SnapdAdapter()) + with Session() as session: + session.mount('http://snapd/', _SnapdAdapter()) - try: - response = session.get('http://snapd/v2/connections?snap=certbot&interface=content') - response.raise_for_status() - except RequestException as e: - if isinstance(e, HTTPError) and e.response.status_code == 404: - LOGGER.error('An error occurred while fetching Certbot snap plugins: ' - 'your version of snapd is outdated.') - LOGGER.error('Please run "sudo snap install core; sudo snap refresh core" ' - 'in your terminal and try again.') - else: - LOGGER.error('An error occurred while fetching Certbot snap plugins: ' - 'make sure the snapd service is running.') - raise e + try: + response = session.get('http://snapd/v2/connections?snap=certbot&interface=content') + response.raise_for_status() + except RequestException as e: + if isinstance(e, HTTPError) and e.response.status_code == 404: + LOGGER.error('An error occurred while fetching Certbot snap plugins: ' + 'your version of snapd is outdated.') + LOGGER.error('Please run "sudo snap install core; sudo snap refresh core" ' + 'in your terminal and try again.') + else: + LOGGER.error('An error occurred while fetching Certbot snap plugins: ' + 'make sure the snapd service is running.') + raise e data = response.json() connections = ['/snap/{0}/current/lib/python3.8/site-packages/'.format(item['slot']['snap']) From f15f4f9838c46e015fb4a183aeb415c794418ea9 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 11 Nov 2020 15:06:50 -0800 Subject: [PATCH 04/42] Add certbot renew --key-type test (#8447) * Test certbot renew --key-type * Fix typo --- .../certbot_tests/assertions.py | 18 ++++++++++++++++++ .../certbot_tests/test_main.py | 17 +++++++++-------- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/certbot-ci/certbot_integration_tests/certbot_tests/assertions.py b/certbot-ci/certbot_integration_tests/certbot_tests/assertions.py index c19c0762e..c223d524c 100644 --- a/certbot-ci/certbot_integration_tests/certbot_tests/assertions.py +++ b/certbot-ci/certbot_integration_tests/certbot_tests/assertions.py @@ -4,6 +4,7 @@ import os from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateKey +from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey from cryptography.hazmat.primitives.serialization import load_pem_private_key try: @@ -21,6 +22,11 @@ ADMINS_SID = 'S-1-5-32-544' def assert_elliptic_key(key, curve): + """ + Asserts that the key at the given path is an EC key using the given curve. + :param key: path to key + :param curve: name of the expected elliptic curve + """ with open(key, 'rb') as file: privkey1 = file.read() @@ -30,6 +36,18 @@ def assert_elliptic_key(key, curve): assert isinstance(key.curve, curve) +def assert_rsa_key(key): + """ + Asserts that the key at the given path is an RSA key. + :param key: path to key + """ + with open(key, 'rb') as file: + privkey1 = file.read() + + key = load_pem_private_key(data=privkey1, password=None, backend=default_backend()) + assert isinstance(key, RSAPrivateKey) + + def assert_hook_execution(probe_path, probe_content): """ Assert that a certbot hook has been executed diff --git a/certbot-ci/certbot_integration_tests/certbot_tests/test_main.py b/certbot-ci/certbot_integration_tests/certbot_tests/test_main.py index 58d5a852d..d77a71064 100644 --- a/certbot-ci/certbot_integration_tests/certbot_tests/test_main.py +++ b/certbot-ci/certbot_integration_tests/certbot_tests/test_main.py @@ -9,10 +9,7 @@ import shutil import subprocess import time -from cryptography.hazmat.backends import default_backend from cryptography.hazmat.primitives.asymmetric.ec import SECP256R1, SECP384R1 -from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey -from cryptography.hazmat.primitives.serialization import load_pem_private_key from cryptography.x509 import NameOID import pytest @@ -20,6 +17,7 @@ import pytest from certbot_integration_tests.certbot_tests import context as certbot_context from certbot_integration_tests.certbot_tests.assertions import assert_cert_count_for_lineage from certbot_integration_tests.certbot_tests.assertions import assert_elliptic_key +from certbot_integration_tests.certbot_tests.assertions import assert_rsa_key from certbot_integration_tests.certbot_tests.assertions import assert_equals_group_owner from certbot_integration_tests.certbot_tests.assertions import assert_equals_group_permissions from certbot_integration_tests.certbot_tests.assertions import assert_equals_world_read_permissions @@ -460,11 +458,7 @@ def test_default_key_type(context): '--cert-name', certname, '-d', certname ]) filename = join(context.config_dir, 'archive/{0}/privkey1.pem').format(certname) - with open(filename, 'rb') as file: - privkey1 = file.read() - - key = load_pem_private_key(data=privkey1, password=None, backend=default_backend()) - assert isinstance(key, RSAPrivateKey) + assert_rsa_key(filename) def test_default_curve_type(context): @@ -509,6 +503,13 @@ def test_renew_with_ec_keys(context): '-d', certname ]) + # We expect that the previous behavior of requiring both --cert-name and + # --key-type to be set to not apply to the renew subcommand. + context.certbot(['renew', '--force-renewal', '--key-type', 'rsa']) + assert_cert_count_for_lineage(context.config_dir, certname, 3) + key3 = join(context.config_dir, 'archive', certname, 'privkey3.pem') + assert_rsa_key(key3) + def test_ocsp_must_staple(context): """Test that OCSP Must-Staple is correctly set in the generated certificate.""" From 2132cf7f043238893c08fc6a103f8c40bba583e4 Mon Sep 17 00:00:00 2001 From: Adrien Ferrand Date: Thu, 12 Nov 2020 21:44:05 +0100 Subject: [PATCH 05/42] Use Python 3.8 for Linux integration tests (#8449) Do we have any specific reason to run the standard Linux integration tests on Python 2.7? If not, we should move to a more recent version of Python. This PR does it for Python 3.8. --- .azure-pipelines/templates/jobs/standard-tests-jobs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.azure-pipelines/templates/jobs/standard-tests-jobs.yml b/.azure-pipelines/templates/jobs/standard-tests-jobs.yml index 69e8b279b..7a1f620bb 100644 --- a/.azure-pipelines/templates/jobs/standard-tests-jobs.yml +++ b/.azure-pipelines/templates/jobs/standard-tests-jobs.yml @@ -52,7 +52,7 @@ jobs: TOXENV: mypy linux-integration: IMAGE_NAME: ubuntu-18.04 - PYTHON_VERSION: 2.7 + PYTHON_VERSION: 3.8 TOXENV: integration ACME_SERVER: pebble apache-compat: From b742b60c4d9422e00871555a6db29e9ba27dbf78 Mon Sep 17 00:00:00 2001 From: Mads Jensen Date: Thu, 12 Nov 2020 23:33:02 +0100 Subject: [PATCH 06/42] Use better asserts. Added notes to style guide. (#8451) --- acme/tests/messages_test.py | 8 ++--- certbot-apache/tests/configurator_test.py | 8 ++--- certbot-apache/tests/dualnode_test.py | 6 ++-- certbot-apache/tests/obj_test.py | 20 ++++++------- certbot-dns-rfc2136/tests/dns_rfc2136_test.py | 2 +- certbot-nginx/tests/configurator_test.py | 2 +- certbot-nginx/tests/obj_test.py | 4 +-- certbot/docs/contributing.rst | 9 +++++- certbot/tests/auth_handler_test.py | 4 +-- certbot/tests/display/ops_test.py | 4 +-- certbot/tests/main_test.py | 30 ++++++++++--------- certbot/tests/plugins/common_test.py | 4 +-- certbot/tests/util_test.py | 2 +- 13 files changed, 56 insertions(+), 47 deletions(-) diff --git a/acme/tests/messages_test.py b/acme/tests/messages_test.py index 3458105b2..70b05b419 100644 --- a/acme/tests/messages_test.py +++ b/acme/tests/messages_test.py @@ -108,11 +108,11 @@ class ConstantTest(unittest.TestCase): def test_equality(self): const_a_prime = self.MockConstant('a') - self.assertFalse(self.const_a == self.const_b) - self.assertTrue(self.const_a == const_a_prime) + self.assertNotEqual(self.const_a, self.const_b) + self.assertEqual(self.const_a, const_a_prime) - self.assertTrue(self.const_a != self.const_b) - self.assertFalse(self.const_a != const_a_prime) + self.assertNotEqual(self.const_a, self.const_b) + self.assertEqual(self.const_a, const_a_prime) class DirectoryTest(unittest.TestCase): diff --git a/certbot-apache/tests/configurator_test.py b/certbot-apache/tests/configurator_test.py index 091a6a828..433229727 100644 --- a/certbot-apache/tests/configurator_test.py +++ b/certbot-apache/tests/configurator_test.py @@ -1357,10 +1357,10 @@ class MultipleVhostsTest(util.ApacheTest): # And the actual returned values self.assertEqual(len(vhs), 1) - self.assertTrue(vhs[0].name == "certbot.demo") + self.assertEqual(vhs[0].name, "certbot.demo") self.assertTrue(vhs[0].ssl) - self.assertFalse(vhs[0] == self.vh_truth[3]) + self.assertNotEqual(vhs[0], self.vh_truth[3]) @mock.patch("certbot_apache._internal.configurator.ApacheConfigurator.make_vhost_ssl") def test_choose_vhosts_wildcard_no_ssl(self, mock_makessl): @@ -1471,10 +1471,10 @@ class MultipleVhostsTest(util.ApacheTest): self.config.parser.aug.match = mock_match vhs = self.config.get_virtual_hosts() self.assertEqual(len(vhs), 2) - self.assertTrue(vhs[0] == self.vh_truth[1]) + self.assertEqual(vhs[0], self.vh_truth[1]) # mock_vhost should have replaced the vh_truth[0], because its filepath # isn't a symlink - self.assertTrue(vhs[1] == mock_vhost) + self.assertEqual(vhs[1], mock_vhost) class AugeasVhostsTest(util.ApacheTest): diff --git a/certbot-apache/tests/dualnode_test.py b/certbot-apache/tests/dualnode_test.py index 44cc69ff4..ef7f8b2d8 100644 --- a/certbot-apache/tests/dualnode_test.py +++ b/certbot-apache/tests/dualnode_test.py @@ -412,9 +412,9 @@ class DualParserNodeTest(unittest.TestCase): # pylint: disable=too-many-public- ancestor=self.block, filepath="/path/to/whatever", metadata=self.metadata) - self.assertFalse(self.block == ne_block) - self.assertFalse(self.directive == ne_directive) - self.assertFalse(self.comment == ne_comment) + self.assertNotEqual(self.block, ne_block) + self.assertNotEqual(self.directive, ne_directive) + self.assertNotEqual(self.comment, ne_comment) def test_parsed_paths(self): mock_p = mock.MagicMock(return_value=['/path/file.conf', diff --git a/certbot-apache/tests/obj_test.py b/certbot-apache/tests/obj_test.py index eac6a64ef..8aae3ad45 100644 --- a/certbot-apache/tests/obj_test.py +++ b/certbot-apache/tests/obj_test.py @@ -27,14 +27,14 @@ class VirtualHostTest(unittest.TestCase): "certbot_apache._internal.obj.Addr(('127.0.0.1', '443'))") def test_eq(self): - self.assertTrue(self.vhost1b == self.vhost1) - self.assertFalse(self.vhost1 == self.vhost2) + self.assertEqual(self.vhost1b, self.vhost1) + self.assertNotEqual(self.vhost1, self.vhost2) self.assertEqual(str(self.vhost1b), str(self.vhost1)) - self.assertFalse(self.vhost1b == 1234) + self.assertNotEqual(self.vhost1b, 1234) def test_ne(self): - self.assertTrue(self.vhost1 != self.vhost2) - self.assertFalse(self.vhost1 != self.vhost1b) + self.assertNotEqual(self.vhost1, self.vhost2) + self.assertEqual(self.vhost1, self.vhost1b) def test_conflicts(self): from certbot_apache._internal.obj import Addr @@ -128,13 +128,13 @@ class AddrTest(unittest.TestCase): self.assertTrue(self.addr1.conflicts(self.addr2)) def test_equal(self): - self.assertTrue(self.addr1 == self.addr2) - self.assertFalse(self.addr == self.addr1) - self.assertFalse(self.addr == 123) + self.assertEqual(self.addr1, self.addr2) + self.assertNotEqual(self.addr, self.addr1) + self.assertNotEqual(self.addr, 123) def test_not_equal(self): - self.assertFalse(self.addr1 != self.addr2) - self.assertTrue(self.addr != self.addr1) + self.assertEqual(self.addr1, self.addr2) + self.assertNotEqual(self.addr, self.addr1) if __name__ == "__main__": diff --git a/certbot-dns-rfc2136/tests/dns_rfc2136_test.py b/certbot-dns-rfc2136/tests/dns_rfc2136_test.py index de5e2912b..dc4a73a04 100644 --- a/certbot-dns-rfc2136/tests/dns_rfc2136_test.py +++ b/certbot-dns-rfc2136/tests/dns_rfc2136_test.py @@ -154,7 +154,7 @@ class RFC2136ClientTest(unittest.TestCase): # _find_domain | pylint: disable=protected-access domain = self.rfc2136_client._find_domain('foo.bar.'+DOMAIN) - self.assertTrue(domain == DOMAIN) + self.assertEqual(domain, DOMAIN) def test_find_domain_wraps_errors(self): # _query_soa | pylint: disable=protected-access diff --git a/certbot-nginx/tests/configurator_test.py b/certbot-nginx/tests/configurator_test.py index e677ad471..5e788e394 100644 --- a/certbot-nginx/tests/configurator_test.py +++ b/certbot-nginx/tests/configurator_test.py @@ -842,7 +842,7 @@ class NginxConfiguratorTest(util.NginxTest): self.config.recovery_routine() self.config.revert_challenge_config() self.config.rollback_checkpoints() - self.assertTrue(mock_parser_load.call_count == 3) + self.assertEqual(mock_parser_load.call_count, 3) def test_choose_vhosts_wildcard(self): # pylint: disable=protected-access diff --git a/certbot-nginx/tests/obj_test.py b/certbot-nginx/tests/obj_test.py index 93b9493eb..f385649ed 100644 --- a/certbot-nginx/tests/obj_test.py +++ b/certbot-nginx/tests/obj_test.py @@ -75,7 +75,7 @@ class AddrTest(unittest.TestCase): new_addr1 = Addr.fromstring("192.168.1.1 spdy") self.assertEqual(self.addr1, new_addr1) self.assertNotEqual(self.addr1, self.addr2) - self.assertFalse(self.addr1 == 3333) + self.assertNotEqual(self.addr1, 3333) def test_equivalent_any_addresses(self): from certbot_nginx._internal.obj import Addr @@ -168,7 +168,7 @@ class VirtualHostTest(unittest.TestCase): self.assertEqual(vhost1b, self.vhost1) self.assertEqual(str(vhost1b), str(self.vhost1)) - self.assertFalse(vhost1b == 1234) + self.assertNotEqual(vhost1b, 1234) def test_str(self): stringified = '\n'.join(['file: filep', 'addrs: localhost', diff --git a/certbot/docs/contributing.rst b/certbot/docs/contributing.rst index 32a1ee72b..908f75459 100644 --- a/certbot/docs/contributing.rst +++ b/certbot/docs/contributing.rst @@ -431,16 +431,23 @@ Please: 4. Remember to use ``pylint``. +5. You may consider installing a plugin for `editorconfig`_ in + your editor to prevent some linting warnings. + +6. Please avoid `unittest.assertTrue` or `unittest.assertFalse` when + possible, and use `assertEqual` or more specific assert. They give + better messages when it's failing, and are generally more correct. + .. _Google Python Style Guide: https://google.github.io/styleguide/pyguide.html .. _Sphinx-style: https://www.sphinx-doc.org/ .. _PEP 8 - Style Guide for Python Code: https://www.python.org/dev/peps/pep-0008 +.. _editorconfig: https://editorconfig.org/ Use ``certbot.compat.os`` instead of ``os`` =========================================== - Python's standard library ``os`` module lacks full support for several Windows security features about file permissions (eg. DACLs). However several files handled by Certbot (eg. private keys) need strongly restricted access diff --git a/certbot/tests/auth_handler_test.py b/certbot/tests/auth_handler_test.py index 6cd207b4b..8eb5d7702 100644 --- a/certbot/tests/auth_handler_test.py +++ b/certbot/tests/auth_handler_test.py @@ -510,7 +510,7 @@ class ReportFailedAuthzrsTest(unittest.TestCase): auth_handler._report_failed_authzrs([self.authzr1], 'key') call_list = mock_zope().add_message.call_args_list - self.assertTrue(len(call_list) == 1) + self.assertEqual(len(call_list), 1) self.assertTrue("Domain: example.com\nType: tls\nDetail: detail" in call_list[0][0][0]) @test_util.patch_get_utility() @@ -518,7 +518,7 @@ class ReportFailedAuthzrsTest(unittest.TestCase): from certbot._internal import auth_handler auth_handler._report_failed_authzrs([self.authzr1, self.authzr2], 'key') - self.assertTrue(mock_zope().add_message.call_count == 2) + self.assertEqual(mock_zope().add_message.call_count, 2) def gen_auth_resp(chall_list): diff --git a/certbot/tests/display/ops_test.py b/certbot/tests/display/ops_test.py index bdc6472bf..417c14a76 100644 --- a/certbot/tests/display/ops_test.py +++ b/certbot/tests/display/ops_test.py @@ -43,7 +43,7 @@ class GetEmailTest(unittest.TestCase): mock_input.return_value = (display_util.OK, "foo@bar.baz") with mock.patch("certbot.display.ops.util.safe_email") as mock_safe_email: mock_safe_email.return_value = True - self.assertTrue(self._call() == "foo@bar.baz") + self.assertEqual(self._call(), "foo@bar.baz") @test_util.patch_get_utility("certbot.display.ops.z_util") def test_ok_not_safe(self, mock_get_utility): @@ -51,7 +51,7 @@ class GetEmailTest(unittest.TestCase): mock_input.return_value = (display_util.OK, "foo@bar.baz") with mock.patch("certbot.display.ops.util.safe_email") as mock_safe_email: mock_safe_email.side_effect = [False, True] - self.assertTrue(self._call() == "foo@bar.baz") + self.assertEqual(self._call(), "foo@bar.baz") @test_util.patch_get_utility("certbot.display.ops.z_util") def test_invalid_flag(self, mock_get_utility): diff --git a/certbot/tests/main_test.py b/certbot/tests/main_test.py index 26154ae16..3e712a039 100644 --- a/certbot/tests/main_test.py +++ b/certbot/tests/main_test.py @@ -209,20 +209,21 @@ class CertonlyTest(unittest.TestCase): mock_lineage.names.return_value = domains self._call(('certonly --webroot -d example.com -d test.org ' '--cert-name example.com').split()) - self.assertTrue(mock_lineage.call_count == 1) - self.assertTrue(mock_domains.call_count == 1) - self.assertTrue(mock_renew_cert.call_count == 1) - self.assertTrue(mock_report_cert.call_count == 1) - self.assertTrue(mock_handle_type.call_count == 1) + + self.assertEqual(mock_lineage.call_count, 1) + self.assertEqual(mock_domains.call_count, 1) + self.assertEqual(mock_renew_cert.call_count, 1) + self.assertEqual(mock_report_cert.call_count, 1) + self.assertEqual(mock_handle_type.call_count, 1) # user confirms updating lineage with new domains self._call(('certonly --webroot -d example.com -d test.com ' '--cert-name example.com').split()) - self.assertTrue(mock_lineage.call_count == 2) - self.assertTrue(mock_domains.call_count == 2) - self.assertTrue(mock_renew_cert.call_count == 2) - self.assertTrue(mock_report_cert.call_count == 2) - self.assertTrue(mock_handle_type.call_count == 2) + self.assertEqual(mock_lineage.call_count, 2) + self.assertEqual(mock_domains.call_count, 2) + self.assertEqual(mock_renew_cert.call_count, 2) + self.assertEqual(mock_report_cert.call_count, 2) + self.assertEqual(mock_handle_type.call_count, 2) # error in _ask_user_to_confirm_new_names self.mock_get_utility().yesno.return_value = False @@ -240,14 +241,15 @@ class CertonlyTest(unittest.TestCase): # no lineage with this name but we specified domains so create a new cert self._call(('certonly --webroot -d example.com -d test.com ' '--cert-name example.com').split()) - self.assertTrue(mock_lineage.call_count == 1) - self.assertTrue(mock_report_cert.call_count == 1) + self.assertEqual(mock_lineage.call_count, 1) + self.assertEqual(mock_report_cert.call_count, 1) # no lineage with this name and we didn't give domains mock_choose_names.return_value = ["somename"] mock_domains_for_certname.return_value = None self._call(('certonly --webroot --cert-name example.com').split()) - self.assertTrue(mock_choose_names.called) + self.assertIs(mock_choose_names.called, True) + class FindDomainsOrCertnameTest(unittest.TestCase): """Tests for certbot._internal.main._find_domains_or_certname.""" @@ -755,7 +757,7 @@ class MainTest(test_util.ConfigTestCase): # This needed two calls to find_all(), which we're avoiding for now # because of possible side effects: # https://github.com/letsencrypt/letsencrypt/commit/51ed2b681f87b1eb29088dd48718a54f401e4855 - #with mock.patch('certbot._internal.cli.plugins_testable') as plugins: + # with mock.patch('certbot._internal.cli.plugins_testable') as plugins: # plugins.return_value = {"apache": True, "nginx": True} # ret, _, _, _ = self._call(args) # self.assertTrue("Too many flags setting" in ret) diff --git a/certbot/tests/plugins/common_test.py b/certbot/tests/plugins/common_test.py index 344e6312f..bcd190e9b 100644 --- a/certbot/tests/plugins/common_test.py +++ b/certbot/tests/plugins/common_test.py @@ -233,11 +233,11 @@ class AddrTest(unittest.TestCase): def test_eq(self): self.assertEqual(self.addr1, self.addr2.get_addr_obj("")) self.assertNotEqual(self.addr1, self.addr2) - self.assertFalse(self.addr1 == 3333) + self.assertNotEqual(self.addr1, 3333) self.assertEqual(self.addr4, self.addr4.get_addr_obj("")) self.assertNotEqual(self.addr4, self.addr5) - self.assertFalse(self.addr4 == 3333) + self.assertNotEqual(self.addr4, 3333) from certbot.plugins.common import Addr self.assertEqual(self.addr4, Addr.fromstring("[fe00:0:0::1]")) self.assertEqual(self.addr4, Addr.fromstring("[fe00:0::0:0:1]")) diff --git a/certbot/tests/util_test.py b/certbot/tests/util_test.py index d28d7df6f..4b93d2c38 100644 --- a/certbot/tests/util_test.py +++ b/certbot/tests/util_test.py @@ -127,7 +127,7 @@ class LockDirUntilExit(test_util.TempDirTestCase): from certbot import util # Despite lock_dir_until_exit has been called twice to subdir, its lock should have been # added only once. So we expect to have two lock references: for self.tempdir and subdir - self.assertTrue(len(util._LOCKS) == 2) # pylint: disable=protected-access + self.assertEqual(len(util._LOCKS), 2) # pylint: disable=protected-access registered_func() # Exception should not be raised # Logically, logger.debug, that would be invoked in case of unlock failure, # should never been called. From 553d3279c6b4fde84c7dd82a1c8dec1a8a465fe6 Mon Sep 17 00:00:00 2001 From: Adrien Ferrand Date: Fri, 13 Nov 2020 00:31:32 +0100 Subject: [PATCH 07/42] Add --dns-server option in run_acme_server (#7722) Fixes #7717 This PR adds a `--dns-server` option to the `run_acme_server` test tool, in order to provide an arbitrary DNS server to Pebble or Boulder for the integration tests. I also take this occasion to make `run_acme_server` a real CLI tool using argparse, and set the `--server-type` (default `pebble`) option as well. * Set --dns-server flag in run_acme_server * Default to pebble * Add documentation * Configure also Boulder --- .../utils/acme_server.py | 57 +++++++++++++------ certbot/docs/contributing.rst | 5 +- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/certbot-ci/certbot_integration_tests/utils/acme_server.py b/certbot-ci/certbot_integration_tests/utils/acme_server.py index c73b6c895..5559b44a6 100755 --- a/certbot-ci/certbot_integration_tests/utils/acme_server.py +++ b/certbot-ci/certbot_integration_tests/utils/acme_server.py @@ -2,10 +2,12 @@ """Module to setup an ACME CA server environment able to run multiple tests in parallel""" from __future__ import print_function +import argparse import errno import json import os from os.path import join +import re import shutil import subprocess import sys @@ -32,13 +34,14 @@ class ACMEServer(object): ACMEServer is also a context manager, and so can be used to ensure ACME server is started/stopped upon context enter/exit. """ - def __init__(self, acme_server, nodes, http_proxy=True, stdout=False): + def __init__(self, acme_server, nodes, http_proxy=True, stdout=False, dns_server=None): """ Create an ACMEServer instance. :param str acme_server: the type of acme server used (boulder-v1, boulder-v2 or pebble) :param list nodes: list of node names that will be setup by pytest xdist :param bool http_proxy: if False do not start the HTTP proxy :param bool stdout: if True stream all subprocesses stdout to standard stdout + :param str dns_server: if set, Pebble/Boulder will use it to resolve domains """ self._construct_acme_xdist(acme_server, nodes) @@ -47,6 +50,7 @@ class ACMEServer(object): self._workspace = tempfile.mkdtemp() self._processes = [] self._stdout = sys.stdout if stdout else open(os.devnull, 'w') + self._dns_server = dns_server def start(self): """Start the test stack""" @@ -132,13 +136,18 @@ class ACMEServer(object): environ['PEBBLE_AUTHZREUSE'] = '100' environ['PEBBLE_ALTERNATE_ROOTS'] = str(PEBBLE_ALTERNATE_ROOTS) - self._launch_process( - [pebble_path, '-config', pebble_config_path, '-dnsserver', '127.0.0.1:8053', '-strict'], - env=environ) + if self._dns_server: + dns_server = self._dns_server + else: + dns_server = '127.0.0.1:8053' + self._launch_process( + [challtestsrv_path, '-management', ':{0}'.format(CHALLTESTSRV_PORT), + '-defaultIPv6', '""', '-defaultIPv4', '127.0.0.1', '-http01', '""', + '-tlsalpn01', '""', '-https01', '""']) self._launch_process( - [challtestsrv_path, '-management', ':{0}'.format(CHALLTESTSRV_PORT), '-defaultIPv6', '""', - '-defaultIPv4', '127.0.0.1', '-http01', '""', '-tlsalpn01', '""', '-https01', '""']) + [pebble_path, '-config', pebble_config_path, '-dnsserver', dns_server, '-strict'], + env=environ) # pebble_ocsp_server is imported here and not at the top of module in order to avoid a useless # ImportError, in the case where cryptography dependency is too old to support ocsp, but @@ -167,6 +176,14 @@ class ACMEServer(object): os.rename(join(instance_path, 'test/rate-limit-policies-b.yml'), join(instance_path, 'test/rate-limit-policies.yml')) + if self._dns_server: + # Change Boulder config to use the provided DNS server + with open(join(instance_path, 'test/config/va.json'), 'r') as file_h: + config = json.loads(file_h.read()) + config['va']['dnsResolvers'] = [self._dns_server] + with open(join(instance_path, 'test/config/va.json'), 'w') as file_h: + file_h.write(json.dumps(config, indent=2, separators=(',', ': '))) + try: # Launch the Boulder server self._launch_process(['docker-compose', 'up', '--force-recreate'], cwd=instance_path) @@ -175,10 +192,11 @@ class ACMEServer(object): print('=> Waiting for boulder instance to respond...') misc.check_until_timeout(self.acme_xdist['directory_url'], attempts=300) - # Configure challtestsrv to answer any A record request with ip of the docker host. - response = requests.post('http://localhost:{0}/set-default-ipv4'.format(CHALLTESTSRV_PORT), - json={'ip': '10.77.77.1'}) - response.raise_for_status() + if not self._dns_server: + # Configure challtestsrv to answer any A record request with ip of the docker host. + response = requests.post('http://localhost:{0}/set-default-ipv4'.format(CHALLTESTSRV_PORT), + json={'ip': '10.77.77.1'}) + response.raise_for_status() except BaseException: # If we failed to set up boulder, print its logs. print('=> Boulder setup failed. Boulder logs are:') @@ -208,14 +226,19 @@ class ACMEServer(object): def main(): - args = sys.argv[1:] - server_type = args[0] if args else 'pebble' - possible_values = ('pebble', 'boulder-v1', 'boulder-v2') - if server_type not in possible_values: - raise ValueError('Invalid server value {0}, should be one of {1}' - .format(server_type, possible_values)) + parser = argparse.ArgumentParser( + description='CLI tool to start a local instance of Pebble or Boulder CA server.') + parser.add_argument('--server-type', '-s', + choices=['pebble', 'boulder-v1', 'boulder-v2'], default='pebble', + help='type of CA server to start: can be Pebble or Boulder ' + '(in ACMEv1 or ACMEv2 mode), Pebble is used if not set.') + parser.add_argument('--dns-server', '-d', + help='specify the DNS server as `IP:PORT` to use by ' + 'Pebble; if not specified, a local mock DNS server will be used to ' + 'resolve domains to localhost.') + args = parser.parse_args() - acme_server = ACMEServer(server_type, [], http_proxy=False, stdout=True) + acme_server = ACMEServer(args.server_type, [], http_proxy=False, stdout=True, dns_server=args.dns_server) try: with acme_server as acme_xdist: diff --git a/certbot/docs/contributing.rst b/certbot/docs/contributing.rst index 32a1ee72b..fadb26b8a 100644 --- a/certbot/docs/contributing.rst +++ b/certbot/docs/contributing.rst @@ -169,7 +169,7 @@ To do so you need: - Docker installed, and a user with access to the Docker client, - an available `local copy`_ of Certbot. -The virtual environment set up with `python tools/venv3.py` contains two commands +The virtual environment set up with `python tools/venv3.py` contains two CLI tools that can be used once the virtual environment is activated: .. code-block:: shell @@ -180,6 +180,9 @@ that can be used once the virtual environment is activated: - Press CTRL+C to stop this instance. - This instance is configured to validate challenges against certbot executed locally. +.. note:: Some options are available to tweak the local ACME server. You can execute + ``run_acme_server --help`` to see the inline help of the ``run_acme_server`` tool. + .. code-block:: shell certbot_test [ARGS...] From 78edb2889ed4140b6e5c4662b4907f1bd3e89417 Mon Sep 17 00:00:00 2001 From: alexzorin Date: Fri, 13 Nov 2020 11:09:29 +1100 Subject: [PATCH 08/42] cli: improve Obtaining/Renewing wording (#8395) * cli: improve Obtaining/Renewing wording * dont use logger, and use new phrasing * .display_util.notify: dont wrap As this function is supposed to be an analogue for print, we do not want it to wrap by default. --- certbot/certbot/_internal/main.py | 16 ++++++++++++++-- certbot/certbot/display/util.py | 28 +++++++++++++++++++++++++++- certbot/tests/display/util_test.py | 23 ++++++++++++++++++++++- 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/certbot/certbot/_internal/main.py b/certbot/certbot/_internal/main.py index e02737c4c..933b1dd8b 100644 --- a/certbot/certbot/_internal/main.py +++ b/certbot/certbot/_internal/main.py @@ -113,12 +113,24 @@ def _get_and_save_cert(le_client, config, domains=None, certname=None, lineage=N if lineage is not None: # Renewal, where we already know the specific lineage we're # interested in - logger.info("Renewing an existing certificate") + display_util.notify( + "{action} for {domains}".format( + action="Simulating renewal of an existing certificate" + if config.dry_run else "Renewing an existing certificate", + domains=display_util.summarize_domain_list(domains or lineage.names()) + ) + ) renewal.renew_cert(config, domains, le_client, lineage) else: # TREAT AS NEW REQUEST assert domains is not None - logger.info("Obtaining a new certificate") + display_util.notify( + "{action} for {domains}".format( + action="Simulating a certificate request" if config.dry_run else + "Requesting a certificate", + domains=display_util.summarize_domain_list(domains) + ) + ) lineage = le_client.obtain_and_enroll_certificate(domains, certname) if lineage is False: raise errors.Error("Certificate could not be obtained") diff --git a/certbot/certbot/display/util.py b/certbot/certbot/display/util.py index bc56f8778..c48454637 100644 --- a/certbot/certbot/display/util.py +++ b/certbot/certbot/display/util.py @@ -16,6 +16,7 @@ import textwrap import zope.interface import zope.component +from acme.magic_typing import List from certbot import errors from certbot import interfaces from certbot._internal import constants @@ -105,7 +106,7 @@ def notify(msg): """ zope.component.getUtility(interfaces.IDisplay).notification( - msg, pause=False, decorate=False + msg, pause=False, decorate=False, wrap=False ) @@ -633,3 +634,28 @@ def _parens_around_char(label): """ return "({first}){rest}".format(first=label[0], rest=label[1:]) + + +def summarize_domain_list(domains): + # type: (List[str]) -> str + """Summarizes a list of domains in the format of: + example.com.com and N more domains + or if there is are only two domains: + example.com and www.example.com + or if there is only one domain: + example.com + + :param list domains: `str` list of domains + :returns: the domain list summary + :rtype: str + """ + if not domains: + return "" + + l = len(domains) + if l == 1: + return domains[0] + elif l == 2: + return " and ".join(domains) + else: + return "{0} and {1} more domains".format(domains[0], l-1) diff --git a/certbot/tests/display/util_test.py b/certbot/tests/display/util_test.py index 7af454abd..1b22d3422 100644 --- a/certbot/tests/display/util_test.py +++ b/certbot/tests/display/util_test.py @@ -454,6 +454,27 @@ class PlaceParensTest(unittest.TestCase): self.assertEqual("(y)es please", self._call("yes please")) +class SummarizeDomainListTest(unittest.TestCase): + @classmethod + def _call(cls, domains): + from certbot.display.util import summarize_domain_list + return summarize_domain_list(domains) + + def test_single_domain(self): + self.assertEqual("example.com", self._call(["example.com"])) + + def test_two_domains(self): + self.assertEqual("example.com and example.org", + self._call(["example.com", "example.org"])) + + def test_many_domains(self): + self.assertEqual("example.com and 2 more domains", + self._call(["example.com", "example.org", "a.example.com"])) + + def test_empty_domains(self): + self.assertEqual("", self._call([])) + + class NotifyTest(unittest.TestCase): """Test the notify function """ @@ -462,7 +483,7 @@ class NotifyTest(unittest.TestCase): from certbot.display.util import notify notify("Hello World") mock_util().notification.assert_called_with( - "Hello World", pause=False, decorate=False + "Hello World", pause=False, decorate=False, wrap=False ) From 90557921e39cd04caaa255a5923e1d644a14ca25 Mon Sep 17 00:00:00 2001 From: alexzorin Date: Tue, 17 Nov 2020 19:27:27 +1100 Subject: [PATCH 09/42] Add certbot-dns-rfc2136 integration testing (#8448) * tests: add certbot-dns-rfc2136 integration tests * dont use 'with' form of socket.socket fixes py2 crash * address some feedback: - conftest: make DNS server a global resource - conftest: add dns_xdist parameter into node config - conftest: add --dns-server=bind flag - conftest: if configured, point the ACME server to the DNS server - dnsserver: make it sort-of compatible with xdist (future-proofing) - context: parameterize dns-rfc2136 credentials file (future proofing) - context: reduce dns-rfc2136 propagation time to speed up tests - tox: add a integration-dns-rfc2136 target - rfc2136: add a test/zone for subdelegation - rfc2136: skip tests if no DNS server is configured * try add integration-dns-rfc2136 to CI * mock recursive dns via RPZ * update --dns-server args and tox.ini args * address more feedback: - dns_server: rename rfc2136 creds file to .tpl - dns_server: dont vary dns server port, instead we will vary zone names (#8455) - dns_server: log error if bind9 fails to stop cleanly - dns_server: replace assert with raise - context: remove redundant _worker_id - context: remove redundant cleanup override - context: fix seek/flush in credentials context manager - context: rename skip_if_no_server -> ...bind_server - context: add newline EOF * conftest: document _setup_primary_node sideeffects * ci: rfc2136-integration from standard->nightly * fix _stop_bind (function was renamed to stop) * ignore errors from shutil.rmtree during cleanup * dns_server: check for crash while polling * remove --dry-run from rfc2136 test --- .../templates/jobs/extended-tests-jobs.yml | 4 + .../assets/bind-config/conf/named.conf | 60 ++++++++ .../rfc2136-credentials-default.ini.tpl | 10 ++ .../assets/bind-config/zones/db.example.com | 11 ++ .../bind-config/zones/db.sub.example.com | 9 ++ .../bind-config/zones/rpz.mock-recursion | 6 + .../certbot_integration_tests/conftest.py | 40 ++++- .../rfc2136_tests/__init__.py | 0 .../rfc2136_tests/context.py | 64 ++++++++ .../rfc2136_tests/test_main.py | 25 ++++ .../utils/dns_server.py | 138 ++++++++++++++++++ tox.ini | 7 + 12 files changed, 368 insertions(+), 6 deletions(-) create mode 100644 certbot-ci/certbot_integration_tests/assets/bind-config/conf/named.conf create mode 100644 certbot-ci/certbot_integration_tests/assets/bind-config/rfc2136-credentials-default.ini.tpl create mode 100644 certbot-ci/certbot_integration_tests/assets/bind-config/zones/db.example.com create mode 100644 certbot-ci/certbot_integration_tests/assets/bind-config/zones/db.sub.example.com create mode 100644 certbot-ci/certbot_integration_tests/assets/bind-config/zones/rpz.mock-recursion create mode 100644 certbot-ci/certbot_integration_tests/rfc2136_tests/__init__.py create mode 100644 certbot-ci/certbot_integration_tests/rfc2136_tests/context.py create mode 100644 certbot-ci/certbot_integration_tests/rfc2136_tests/test_main.py create mode 100644 certbot-ci/certbot_integration_tests/utils/dns_server.py diff --git a/.azure-pipelines/templates/jobs/extended-tests-jobs.yml b/.azure-pipelines/templates/jobs/extended-tests-jobs.yml index c22f1003f..3197501e1 100644 --- a/.azure-pipelines/templates/jobs/extended-tests-jobs.yml +++ b/.azure-pipelines/templates/jobs/extended-tests-jobs.yml @@ -64,6 +64,10 @@ jobs: ACME_SERVER: boulder-v2 nginx-compat: TOXENV: nginx_compat + linux-integration-rfc2136: + IMAGE_NAME: ubuntu-18.04 + PYTHON_VERSION: 3.8 + TOXENV: integration-dns-rfc2136 le-auto-oraclelinux6: TOXENV: le_auto_oraclelinux6 docker-dev: diff --git a/certbot-ci/certbot_integration_tests/assets/bind-config/conf/named.conf b/certbot-ci/certbot_integration_tests/assets/bind-config/conf/named.conf new file mode 100644 index 000000000..672a447d3 --- /dev/null +++ b/certbot-ci/certbot_integration_tests/assets/bind-config/conf/named.conf @@ -0,0 +1,60 @@ +options { + directory "/var/cache/bind"; + + // Running inside Docker. Bind address on Docker host is 127.0.0.1. + listen-on { any; }; + listen-on-v6 { any; }; + + // We are allowing BIND to service recursive queries, but only in an extremely limimited sense + // where it is entirely disconnected from public DNS: + // - Iterative queries are disabled. Only forwarding to a non-existent forwarder. + // - The only recursive answers we can get (that will not be a SERVFAIL) will come from the + // RPZ "mock-recursion" zone. Effectively this means we are mocking out the entirety of + // public DNS. + allow-recursion { any; }; // BIND will only answer using RPZ if recursion is enabled + forwarders { 192.0.2.254; }; // Nobody is listening, this is TEST-NET-1 + forward only; // Do NOT perform iterative queries from the root zone + dnssec-validation no; // Do not bother fetching the root DNSKEY set (performance) + response-policy { // All recursive queries will be served from here. + zone "mock-recursion" + log yes; + } recursive-only no // Allow RPZs to affect authoritative zones too. + qname-wait-recurse no // No real recursion. + nsip-wait-recurse no; // No real recursion. + + allow-transfer { none; }; + allow-update { none; }; +}; + +key "default-key." { + algorithm hmac-sha512; + secret "91CgOwzihr0nAVEHKFXJPQCbuBBbBI19Ks5VAweUXgbF40NWTD83naeg3c5y2MPdEiFRXnRLJxL6M+AfHCGLNw=="; +}; + +zone "mock-recursion" { + type primary; + file "/var/lib/bind/rpz.mock-recursion"; + allow-query { + none; + }; +}; + +zone "example.com." { + type primary; + file "/var/lib/bind/db.example.com"; + journal "/var/cache/bind/db.example.com.jnl"; + + update-policy { + grant default-key zonesub TXT; + }; +}; + +zone "sub.example.com." { + type primary; + file "/var/lib/bind/db.sub.example.com"; + journal "/var/cache/bind/db.sub.example.com.jnl"; + + update-policy { + grant default-key zonesub TXT; + }; +}; diff --git a/certbot-ci/certbot_integration_tests/assets/bind-config/rfc2136-credentials-default.ini.tpl b/certbot-ci/certbot_integration_tests/assets/bind-config/rfc2136-credentials-default.ini.tpl new file mode 100644 index 000000000..8aa7cc3cb --- /dev/null +++ b/certbot-ci/certbot_integration_tests/assets/bind-config/rfc2136-credentials-default.ini.tpl @@ -0,0 +1,10 @@ +# Target DNS server +dns_rfc2136_server = {server_address} +# Target DNS port +dns_rfc2136_port = {server_port} +# TSIG key name +dns_rfc2136_name = default-key. +# TSIG key secret +dns_rfc2136_secret = 91CgOwzihr0nAVEHKFXJPQCbuBBbBI19Ks5VAweUXgbF40NWTD83naeg3c5y2MPdEiFRXnRLJxL6M+AfHCGLNw== +# TSIG key algorithm +dns_rfc2136_algorithm = HMAC-SHA512 diff --git a/certbot-ci/certbot_integration_tests/assets/bind-config/zones/db.example.com b/certbot-ci/certbot_integration_tests/assets/bind-config/zones/db.example.com new file mode 100644 index 000000000..2573470b5 --- /dev/null +++ b/certbot-ci/certbot_integration_tests/assets/bind-config/zones/db.example.com @@ -0,0 +1,11 @@ +$ORIGIN example.com. +$TTL 3600 +example.com. IN SOA ns1.example.com. admin.example.com. ( 2020091025 7200 3600 1209600 3600 ) + +example.com. IN NS ns1 +example.com. IN NS ns2 + +ns1 IN A 192.0.2.2 +ns2 IN A 192.0.2.3 + +@ IN A 192.0.2.1 diff --git a/certbot-ci/certbot_integration_tests/assets/bind-config/zones/db.sub.example.com b/certbot-ci/certbot_integration_tests/assets/bind-config/zones/db.sub.example.com new file mode 100644 index 000000000..0379003b7 --- /dev/null +++ b/certbot-ci/certbot_integration_tests/assets/bind-config/zones/db.sub.example.com @@ -0,0 +1,9 @@ +$ORIGIN sub.example.com. +$TTL 3600 +sub.example.com. IN SOA ns1.example.com. admin.example.com. ( 2020091025 7200 3600 1209600 3600 ) + +sub.example.com. IN NS ns1 +sub.example.com. IN NS ns2 + +ns1 IN A 192.0.2.2 +ns2 IN A 192.0.2.3 diff --git a/certbot-ci/certbot_integration_tests/assets/bind-config/zones/rpz.mock-recursion b/certbot-ci/certbot_integration_tests/assets/bind-config/zones/rpz.mock-recursion new file mode 100644 index 000000000..589689d37 --- /dev/null +++ b/certbot-ci/certbot_integration_tests/assets/bind-config/zones/rpz.mock-recursion @@ -0,0 +1,6 @@ +$TTL 3600 + +@ SOA ns1.example.test. dummy.example.test. 1 12h 15m 3w 2h + NS ns1.example.test. + +_acme-challenge.aliased.example IN CNAME _acme-challenge.example.com. diff --git a/certbot-ci/certbot_integration_tests/conftest.py b/certbot-ci/certbot_integration_tests/conftest.py index bb1d76e57..bb5c07dac 100644 --- a/certbot-ci/certbot_integration_tests/conftest.py +++ b/certbot-ci/certbot_integration_tests/conftest.py @@ -12,6 +12,8 @@ import subprocess import sys from certbot_integration_tests.utils import acme_server as acme_lib +from certbot_integration_tests.utils import dns_server as dns_lib +from certbot_integration_tests.utils.dns_server import DNSServer def pytest_addoption(parser): @@ -23,6 +25,10 @@ def pytest_addoption(parser): choices=['boulder-v1', 'boulder-v2', 'pebble'], help='select the ACME server to use (boulder-v1, boulder-v2, ' 'pebble), defaulting to pebble') + parser.addoption('--dns-server', default='challtestsrv', + choices=['bind', 'challtestsrv'], + help='select the DNS server to use (bind, challtestsrv), ' + 'defaulting to challtestsrv') def pytest_configure(config): @@ -32,7 +38,7 @@ def pytest_configure(config): """ if not hasattr(config, 'slaveinput'): # If true, this is the primary node with _print_on_err(): - config.acme_xdist = _setup_primary_node(config) + _setup_primary_node(config) def pytest_configure_node(node): @@ -41,6 +47,7 @@ def pytest_configure_node(node): :param node: current worker node """ node.slaveinput['acme_xdist'] = node.config.acme_xdist + node.slaveinput['dns_xdist'] = node.config.dns_xdist @contextlib.contextmanager @@ -61,12 +68,18 @@ def _print_on_err(): def _setup_primary_node(config): """ Setup the environment for integration tests. - Will: + + This function will: - check runtime compatibility (Docker, docker-compose, Nginx) - create a temporary workspace and the persistent GIT repositories space + - configure and start a DNS server using Docker, if configured - configure and start paralleled ACME CA servers using Docker - - transfer ACME CA servers configurations to pytest nodes using env variables - :param config: Configuration of the pytest primary node + - transfer ACME CA and DNS servers configurations to pytest nodes using env variables + + This function modifies `config` by injecting the ACME CA and DNS server configurations, + in addition to cleanup functions for those servers. + + :param config: Configuration of the pytest primary node. Is modified by this function. """ # Check for runtime compatibility: some tools are required to be available in PATH if 'boulder' in config.option.acme_server: @@ -86,11 +99,26 @@ def _setup_primary_node(config): workers = ['primary'] if not config.option.numprocesses\ else ['gw{0}'.format(i) for i in range(config.option.numprocesses)] + # If a non-default DNS server is configured, start it and feed it to the ACME server + dns_server = None + acme_dns_server = None + if config.option.dns_server == 'bind': + dns_server = dns_lib.DNSServer(workers) + config.add_cleanup(dns_server.stop) + print('DNS xdist config:\n{0}'.format(dns_server.dns_xdist)) + dns_server.start() + acme_dns_server = '{}:{}'.format( + dns_server.dns_xdist['address'], + dns_server.dns_xdist['port'] + ) + # By calling setup_acme_server we ensure that all necessary acme server instances will be # fully started. This runtime is reflected by the acme_xdist returned. - acme_server = acme_lib.ACMEServer(config.option.acme_server, workers) + acme_server = acme_lib.ACMEServer(config.option.acme_server, workers, + dns_server=acme_dns_server) config.add_cleanup(acme_server.stop) print('ACME xdist config:\n{0}'.format(acme_server.acme_xdist)) acme_server.start() - return acme_server.acme_xdist + config.acme_xdist = acme_server.acme_xdist + config.dns_xdist = dns_server.dns_xdist if dns_server else None diff --git a/certbot-ci/certbot_integration_tests/rfc2136_tests/__init__.py b/certbot-ci/certbot_integration_tests/rfc2136_tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/certbot-ci/certbot_integration_tests/rfc2136_tests/context.py b/certbot-ci/certbot_integration_tests/rfc2136_tests/context.py new file mode 100644 index 000000000..b9fe8b401 --- /dev/null +++ b/certbot-ci/certbot_integration_tests/rfc2136_tests/context.py @@ -0,0 +1,64 @@ +from contextlib import contextmanager +from pytest import skip +from pkg_resources import resource_filename +import tempfile + +from certbot_integration_tests.certbot_tests import context as certbot_context +from certbot_integration_tests.utils import certbot_call + + +class IntegrationTestsContext(certbot_context.IntegrationTestsContext): + """Integration test context for certbot-dns-rfc2136""" + def __init__(self, request): + super(IntegrationTestsContext, self).__init__(request) + + self.request = request + + self._dns_xdist = None + if hasattr(request.config, 'slaveinput'): # Worker node + self._dns_xdist = request.config.slaveinput['dns_xdist'] + else: # Primary node + self._dns_xdist = request.config.dns_xdist + + def certbot_test_rfc2136(self, args): + """ + Main command to execute certbot using the RFC2136 DNS authenticator. + :param list args: list of arguments to pass to Certbot + """ + command = ['--authenticator', 'dns-rfc2136', '--dns-rfc2136-propagation-seconds', '2'] + command.extend(args) + return certbot_call.certbot_test( + command, self.directory_url, self.http_01_port, self.tls_alpn_01_port, + self.config_dir, self.workspace, force_renew=True) + + @contextmanager + def rfc2136_credentials(self, label='default'): + # type: (str) -> str + """ + Produces the contents of a certbot-dns-rfc2136 credentials file. + :param str label: which RFC2136 credential to use + :yields: Path to credentials file + :rtype: str + """ + src_file = resource_filename('certbot_integration_tests', + 'assets/bind-config/rfc2136-credentials-{}.ini.tpl' + .format(label)) + contents = None + + with open(src_file, 'r') as f: + contents = f.read().format( + server_address=self._dns_xdist['address'], + server_port=self._dns_xdist['port'] + ) + + with tempfile.NamedTemporaryFile('w+', prefix='rfc2136-creds-{}'.format(label), + suffix='.ini', dir=self.workspace) as f: + f.write(contents) + f.flush() + yield f.name + + def skip_if_no_bind9_server(self): + """Skips the test if there was no RFC2136-capable DNS server configured + in the test environment""" + if not self._dns_xdist: + skip('No RFC2136-capable DNS server is configured') diff --git a/certbot-ci/certbot_integration_tests/rfc2136_tests/test_main.py b/certbot-ci/certbot_integration_tests/rfc2136_tests/test_main.py new file mode 100644 index 000000000..69996d533 --- /dev/null +++ b/certbot-ci/certbot_integration_tests/rfc2136_tests/test_main.py @@ -0,0 +1,25 @@ +"""Module executing integration tests against Certbot with the RFC2136 DNS authenticator.""" +import pytest + +from certbot_integration_tests.rfc2136_tests import context as rfc2136_context + + +@pytest.fixture() +def context(request): + # Fixture request is a built-in pytest fixture describing current test request. + integration_test_context = rfc2136_context.IntegrationTestsContext(request) + try: + yield integration_test_context + finally: + integration_test_context.cleanup() + + +@pytest.mark.parametrize('domain', [('example.com'), ('sub.example.com')]) +def test_get_certificate(domain, context): + context.skip_if_no_bind9_server() + + with context.rfc2136_credentials() as creds: + context.certbot_test_rfc2136([ + 'certonly', '--dns-rfc2136-credentials', creds, + '-d', domain, '-d', '*.{}'.format(domain) + ]) diff --git a/certbot-ci/certbot_integration_tests/utils/dns_server.py b/certbot-ci/certbot_integration_tests/utils/dns_server.py new file mode 100644 index 000000000..b6b922f6d --- /dev/null +++ b/certbot-ci/certbot_integration_tests/utils/dns_server.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python +"""Module to setup an RFC2136-capable DNS server""" +import os +import os.path +from pkg_resources import resource_filename +import shutil +import socket +import subprocess +import sys +import tempfile +import time + + +BIND_DOCKER_IMAGE = 'internetsystemsconsortium/bind9:9.16' +BIND_BIND_ADDRESS = ('127.0.0.1', 45953) + +# A TCP DNS message which is a query for '. CH A' transaction ID 0xcb37. This is used +# by _wait_until_ready to check that BIND is responding without depending on dnspython. +BIND_TEST_QUERY = bytearray.fromhex('0011cb37000000010000000000000000010003') + + +class DNSServer(object): + """ + DNSServer configures and handles the lifetime of an RFC2136-capable server. + DNServer provides access to the dns_xdist parameter, listing the address and port + to use for each pytest node. + + At this time, DNSServer should only be used with a single node, but may be expanded in + future to support parallelization (https://github.com/certbot/certbot/issues/8455). + """ + + def __init__(self, nodes, show_output=False): + """ + Create an DNSServer instance. + :param list nodes: list of node names that will be setup by pytest xdist + :param bool show_output: if True, print the output of the DNS server + """ + + self.bind_root = tempfile.mkdtemp() + + self.dns_xdist = { + 'address': BIND_BIND_ADDRESS[0], + 'port': BIND_BIND_ADDRESS[1] + } + + # Unfortunately the BIND9 image forces everything to stderr with -g and we can't + # modify the verbosity. + self._output = sys.stderr if show_output else open(os.devnull, 'w') + + def start(self): + """Start the DNS server""" + try: + self._configure_bind() + self._start_bind() + except: + self.stop() + raise + + def stop(self): + """Stop the DNS server, and clean its resources""" + try: + self.process.terminate() + self.process.wait() + except BaseException as e: + print("BIND9 did not stop cleanly: {}".format(e), file=sys.stderr) + + shutil.rmtree(self.bind_root, ignore_errors=True) + + if self._output != sys.stderr: + self._output.close() + + def _configure_bind(self): + """Configure the BIND9 server based on the prebaked configuration""" + bind_conf_src = resource_filename('certbot_integration_tests', 'assets/bind-config') + shutil.copytree(bind_conf_src, self.bind_root, dirs_exist_ok=True) + + def _start_bind(self): + """Launch the BIND9 server as a Docker container""" + addr_str = '{}:{}'.format(BIND_BIND_ADDRESS[0], BIND_BIND_ADDRESS[1]) + self.process = subprocess.Popen([ + 'docker', 'run', '--rm', + '-p', '{}:53/udp'.format(addr_str), + '-p', '{}:53/tcp'.format(addr_str), + '-v', '{}/conf:/etc/bind'.format(self.bind_root), + '-v', '{}/zones:/var/lib/bind'.format(self.bind_root), + BIND_DOCKER_IMAGE + ], stdout=self._output, stderr=self._output) + + if self.process.poll(): + raise("BIND9 server stopped unexpectedly") + + try: + self._wait_until_ready() + except: + # The container might be running even if we think it isn't + self.stop() + raise + + def _wait_until_ready(self, attempts=30): + # type: (int) -> None + """ + Polls the DNS server over TCP until it gets a response, or until + it runs out of attempts and raises a ValueError. + The DNS response message must match the txn_id of the DNS query message, + but otherwise the contents are ignored. + :param int attempts: The number of attempts to make. + """ + for _ in range(attempts): + if self.process.poll(): + raise ValueError('BIND9 server stopped unexpectedly') + + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(5.0) + try: + sock.connect(BIND_BIND_ADDRESS) + sock.sendall(BIND_TEST_QUERY) + buf = sock.recv(1024) + # We should receive a DNS message with the same tx_id + if buf and len(buf) > 4 and buf[2:4] == BIND_TEST_QUERY[2:4]: + return + # If we got a response but it wasn't the one we wanted, wait a little + time.sleep(1) + except: + # If there was a network error, wait a little + time.sleep(1) + pass + finally: + sock.close() + + raise ValueError( + 'Gave up waiting for DNS server {} to respond'.format(BIND_BIND_ADDRESS)) + + def __enter__(self): + self.start() + return self.dns_xdist + + def __exit__(self, exc_type, exc_val, exc_tb): + self.stop() diff --git a/tox.ini b/tox.ini index 5dcc55d3f..7f806bb4d 100644 --- a/tox.ini +++ b/tox.ini @@ -240,6 +240,13 @@ commands = --cov-config=certbot-ci/certbot_integration_tests/.coveragerc coverage report --include 'certbot/*' --show-missing --fail-under=62 +[testenv:integration-dns-rfc2136] +commands = + {[base]pip_install} acme certbot certbot-dns-rfc2136 certbot-ci + pytest certbot-ci/certbot_integration_tests/rfc2136_tests \ + --acme-server=pebble --dns-server=bind \ + --numprocesses=1 + [testenv:integration-external] # Run integration tests with Certbot outside of tox's virtual environment. commands = From 7ba35b44075579b9274486982b92c93b58f5094d Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 17 Nov 2020 11:51:27 -0800 Subject: [PATCH 10/42] import print_function --- certbot-ci/certbot_integration_tests/utils/dns_server.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/certbot-ci/certbot_integration_tests/utils/dns_server.py b/certbot-ci/certbot_integration_tests/utils/dns_server.py index b6b922f6d..3d2f50d3b 100644 --- a/certbot-ci/certbot_integration_tests/utils/dns_server.py +++ b/certbot-ci/certbot_integration_tests/utils/dns_server.py @@ -1,5 +1,7 @@ #!/usr/bin/env python """Module to setup an RFC2136-capable DNS server""" +from __future__ import print_function + import os import os.path from pkg_resources import resource_filename From e8139e80be54fe478fce28321a8d7f15c5182673 Mon Sep 17 00:00:00 2001 From: Alex Zorin Date: Wed, 18 Nov 2020 09:51:42 +1100 Subject: [PATCH 11/42] certbot-ci: fix py2 crash in dns_server --- .../utils/dns_server.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/certbot-ci/certbot_integration_tests/utils/dns_server.py b/certbot-ci/certbot_integration_tests/utils/dns_server.py index 3d2f50d3b..779d736e3 100644 --- a/certbot-ci/certbot_integration_tests/utils/dns_server.py +++ b/certbot-ci/certbot_integration_tests/utils/dns_server.py @@ -40,6 +40,8 @@ class DNSServer(object): self.bind_root = tempfile.mkdtemp() + self.process = None + self.dns_xdist = { 'address': BIND_BIND_ADDRESS[0], 'port': BIND_BIND_ADDRESS[1] @@ -60,11 +62,12 @@ class DNSServer(object): def stop(self): """Stop the DNS server, and clean its resources""" - try: - self.process.terminate() - self.process.wait() - except BaseException as e: - print("BIND9 did not stop cleanly: {}".format(e), file=sys.stderr) + if self.process: + try: + self.process.terminate() + self.process.wait() + except BaseException as e: + print("BIND9 did not stop cleanly: {}".format(e), file=sys.stderr) shutil.rmtree(self.bind_root, ignore_errors=True) @@ -74,7 +77,8 @@ class DNSServer(object): def _configure_bind(self): """Configure the BIND9 server based on the prebaked configuration""" bind_conf_src = resource_filename('certbot_integration_tests', 'assets/bind-config') - shutil.copytree(bind_conf_src, self.bind_root, dirs_exist_ok=True) + for dir in ('conf', 'zones'): + shutil.copytree(os.path.join(bind_conf_src, dir), os.path.join(self.bind_root, dir)) def _start_bind(self): """Launch the BIND9 server as a Docker container""" From be3d0d872fabc04c40931f62603b7e40b83fe064 Mon Sep 17 00:00:00 2001 From: Mads Jensen Date: Wed, 18 Nov 2020 01:02:35 +0100 Subject: [PATCH 12/42] Read files as binary in crypto_util for crypto.load_certificate. (#8371) --- certbot/certbot/crypto_util.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/certbot/certbot/crypto_util.py b/certbot/certbot/crypto_util.py index 5de412b5e..c4b6128aa 100644 --- a/certbot/certbot/crypto_util.py +++ b/certbot/certbot/crypto_util.py @@ -447,9 +447,8 @@ def _notAfterBefore(cert_path, method): """ # pylint: disable=redefined-outer-name - with open(cert_path) as f: - x509 = crypto.load_certificate(crypto.FILETYPE_PEM, - f.read()) + with open(cert_path, "rb") as f: # type: IO[bytes] + x509 = crypto.load_certificate(crypto.FILETYPE_PEM, f.read()) # pyopenssl always returns bytes timestamp = method(x509) reformatted_timestamp = [timestamp[0:4], b"-", timestamp[4:6], b"-", @@ -520,6 +519,7 @@ def cert_and_chain_from_fullchain(fullchain_pem): # Since each normalized cert has a newline suffix, no extra newlines are required. return (certs_normalized[0], "".join(certs_normalized[1:])) + def get_serial_from_cert(cert_path): """Retrieve the serial number of a certificate from certificate path @@ -529,9 +529,8 @@ def get_serial_from_cert(cert_path): :rtype: int """ # pylint: disable=redefined-outer-name - with open(cert_path) as f: - x509 = crypto.load_certificate(crypto.FILETYPE_PEM, - f.read()) + with open(cert_path, "rb") as f: # type: IO[bytes] + x509 = crypto.load_certificate(crypto.FILETYPE_PEM, f.read()) return x509.get_serial_number() From a8cede6ae1f85c32227ccb976b145d971a913f66 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 19 Nov 2020 00:10:56 -0800 Subject: [PATCH 13/42] Flesh out ECDSA documentation (#8464) * Changelog tweaks. * Add ECDSA documentation * Fix typo --- certbot/CHANGELOG.md | 3 +- certbot/docs/using.rst | 67 ++++++++++++++++++++++++++++++++++++------ 2 files changed, 59 insertions(+), 11 deletions(-) diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index e32bd1072..b7d57a62d 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -9,8 +9,7 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). * Added timeout to DNS query function calls for dns-rfc2136 plugin. * Confirmation when deleting certificates * CLI flag `--key-type` has been added to specify 'rsa' or 'ecdsa' (default 'rsa'). - Only accepts a single value at this time. -* CLI flag `--elliptic-curve` has been added which takes an NIST/SECG elliptic curve. Either of +* CLI flag `--elliptic-curve` has been added which takes an NIST/SECG elliptic curve. Any of `secp256r1`, `secp284r1` and `secp521r1` are accepted values. * The command `certbot certficates` lists the which type of the private key that was used for the private key. diff --git a/certbot/docs/using.rst b/certbot/docs/using.rst index 353029822..1912dafa4 100644 --- a/certbot/docs/using.rst +++ b/certbot/docs/using.rst @@ -410,18 +410,67 @@ replace that set entirely:: certbot certonly --cert-name example.com -d example.org,www.example.org -Migrating to certificates based on ECDSA keys ---------------------------------------------- +Using ECDSA keys +---------------- As of version 1.10, Certbot supports two types of private key algorithms: -``rsa`` and ``ecdsa``. You may freely upgrade an existing certificate with a -new private key. This requires issuing a new command, or changing the renewal -file for the certificates so it will happen on the next renewal. The two -options that you need for the renewal command are ``--key-type`` and -``--elliptic-curve `` in case you either want to be explicit or want to -use something else than the default curve ``secp256r1``:: +``rsa`` and ``ecdsa``. The type of key used by Certbot can be controlled +through the ``--key-type`` option. You can also use the ``--elliptic-curve`` +option to control the curve used in ECDSA certificates. - certbot renew --key-type ecdsa --cert-name example.com -d example.org,www.example.org +.. warning:: If you obtain certificates using ECDSA keys, you should be careful + not to downgrade your Certbot installation since ECDSA keys are not + supported by older versions of Certbot. Downgrades like this are possible if + you switch from something like the snaps or certbot-auto to packages + provided by your operating system which often lag behind. + +Changing existing certificates from RSA to ECDSA +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Unless you are aware that you need to support very old HTTPS clients that are +not supported by most sites, you can safely just transition your site to use +ECDSA keys instead of RSA keys. To accomplish this if you have existing +certificates managed by Certbot, you may freely change the certificate to a new +private key. + +If you want to use ECDSA keys for all certificates in the future, you can +simply add the following line to Certbot's :ref:`configuration file ` + +.. code-block:: ini + + key-type = ecdsa + +After this option is set, newly obtained certificates will use ECDSA keys. This +includes certificates managed by Certbot that previously used RSA keys. + +If you want to change a single certificate to use ECDSA keys, you'll need to +issue a new Certbot command setting ``--key-type ecdsa`` on the command line +like + +.. code-block:: shell + + certbot renew --key-type ecdsa --cert-name example.com --force-renewal + +Obtaining ECDSA certificates in addition to RSA certificates +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When Certbot configures the certificates it obtains with Apache or Nginx, all +HTTPS clients that we try to support can use certificates with ECDSA keys. If, +however, you are aware of having a specific need to support very old TLS +clients, you may want to obtain both ECDSA and RSA certificates for the same +domains. Certbot can only configure Apache or Nginx to use a single +certificate, however, you could manually configure your software to use the +different certificates depending on your needs. + +When obtaining both ECDSA and RSA certificates for the same domains with +Certbot, we recommend using the ``--cert-name`` option to give your +certificates names so that you can easily identify them. For instance, you may +want to append "ecdsa" to the name of your ECDSA certificate by using a command +like + +.. code-block:: shell + + certbot certonly --key-type ecdsa --cert-name example.com-ecdsa Revoking certificates --------------------- From 9a4e95e25a542a6a295e2a2800000970afed41e6 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 19 Nov 2020 12:48:36 -0800 Subject: [PATCH 14/42] Add Python 3.9 support and tests (#8460) Fixes https://github.com/certbot/certbot/issues/8134. * Test on Python 3.9. * Mention Python 3.9 support in changelog. * s/\( *'Pro.*3\.\)8\(',\)/\18\2\n\19\2/ * undo changes to tox.ini * Move more tests to Python 3.9 * Update PyYAML and packages which pinned it back * Upgrade typed-ast * Use <= to "pin" dnspython * Fix lint by telling pylint it cannot be trusted * Disable mypy on RFC plugin * add comment about <= support --- .../templates/jobs/extended-tests-jobs.yml | 13 ++++++++- .../templates/jobs/standard-tests-jobs.yml | 14 ++++----- acme/setup.py | 1 + certbot-apache/setup.py | 1 + certbot-ci/setup.py | 1 + certbot-compatibility-test/setup.py | 1 + certbot-dns-cloudflare/setup.py | 1 + certbot-dns-cloudxns/setup.py | 1 + certbot-dns-digitalocean/setup.py | 1 + certbot-dns-dnsimple/setup.py | 1 + certbot-dns-dnsmadeeasy/setup.py | 1 + certbot-dns-gehirn/setup.py | 1 + certbot-dns-google/setup.py | 1 + certbot-dns-linode/setup.py | 1 + certbot-dns-luadns/setup.py | 1 + certbot-dns-nsone/setup.py | 1 + certbot-dns-ovh/setup.py | 1 + .../_internal/dns_rfc2136.py | 10 +++++++ certbot-dns-rfc2136/setup.py | 1 + certbot-dns-route53/setup.py | 1 + certbot-dns-sakuracloud/setup.py | 1 + certbot-nginx/setup.py | 1 + certbot/CHANGELOG.md | 1 + certbot/setup.py | 1 + tools/dev_constraints.txt | 17 +++++++---- tools/merge_requirements.py | 29 ++++++++++++++----- 26 files changed, 83 insertions(+), 21 deletions(-) diff --git a/.azure-pipelines/templates/jobs/extended-tests-jobs.yml b/.azure-pipelines/templates/jobs/extended-tests-jobs.yml index 3197501e1..f835078c8 100644 --- a/.azure-pipelines/templates/jobs/extended-tests-jobs.yml +++ b/.azure-pipelines/templates/jobs/extended-tests-jobs.yml @@ -4,7 +4,7 @@ jobs: - name: IMAGE_NAME value: ubuntu-18.04 - name: PYTHON_VERSION - value: 3.8 + value: 3.9 - group: certbot-common strategy: matrix: @@ -14,6 +14,9 @@ jobs: linux-py37: PYTHON_VERSION: 3.7 TOXENV: py37 + linux-py38: + PYTHON_VERSION: 3.8 + TOXENV: py38 linux-py37-nopin: PYTHON_VERSION: 3.7 TOXENV: py37 @@ -62,6 +65,14 @@ jobs: PYTHON_VERSION: 3.8 TOXENV: integration ACME_SERVER: boulder-v2 + linux-boulder-v1-py39-integration: + PYTHON_VERSION: 3.9 + TOXENV: integration + ACME_SERVER: boulder-v1 + linux-boulder-v2-py39-integration: + PYTHON_VERSION: 3.9 + TOXENV: integration + ACME_SERVER: boulder-v2 nginx-compat: TOXENV: nginx_compat linux-integration-rfc2136: diff --git a/.azure-pipelines/templates/jobs/standard-tests-jobs.yml b/.azure-pipelines/templates/jobs/standard-tests-jobs.yml index 7a1f620bb..897ab40bb 100644 --- a/.azure-pipelines/templates/jobs/standard-tests-jobs.yml +++ b/.azure-pipelines/templates/jobs/standard-tests-jobs.yml @@ -1,17 +1,17 @@ jobs: - job: test variables: - PYTHON_VERSION: 3.8 + PYTHON_VERSION: 3.9 strategy: matrix: macos-py27: IMAGE_NAME: macOS-10.15 PYTHON_VERSION: 2.7 TOXENV: py27 - macos-py38: + macos-py39: IMAGE_NAME: macOS-10.15 - PYTHON_VERSION: 3.8 - TOXENV: py38 + PYTHON_VERSION: 3.9 + TOXENV: py39 windows-py36: IMAGE_NAME: vs2017-win2016 PYTHON_VERSION: 3.6 @@ -38,10 +38,10 @@ jobs: IMAGE_NAME: ubuntu-18.04 PYTHON_VERSION: 3.6 TOXENV: py36 - linux-py38-cover: + linux-py39-cover: IMAGE_NAME: ubuntu-18.04 - PYTHON_VERSION: 3.8 - TOXENV: py38-cover + PYTHON_VERSION: 3.9 + TOXENV: py39-cover linux-py37-lint: IMAGE_NAME: ubuntu-18.04 PYTHON_VERSION: 3.7 diff --git a/acme/setup.py b/acme/setup.py index 96adc2963..55d1ae17d 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -66,6 +66,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Security', ], diff --git a/certbot-apache/setup.py b/certbot-apache/setup.py index cd1a24f93..c6fadb929 100644 --- a/certbot-apache/setup.py +++ b/certbot-apache/setup.py @@ -53,6 +53,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Security', 'Topic :: System :: Installation/Setup', diff --git a/certbot-ci/setup.py b/certbot-ci/setup.py index 971db2b8e..ce29fe45d 100644 --- a/certbot-ci/setup.py +++ b/certbot-ci/setup.py @@ -52,6 +52,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Security', ], diff --git a/certbot-compatibility-test/setup.py b/certbot-compatibility-test/setup.py index 598454ae8..66e1c9f03 100644 --- a/certbot-compatibility-test/setup.py +++ b/certbot-compatibility-test/setup.py @@ -50,6 +50,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Security', ], diff --git a/certbot-dns-cloudflare/setup.py b/certbot-dns-cloudflare/setup.py index 96db7351a..34938aca1 100644 --- a/certbot-dns-cloudflare/setup.py +++ b/certbot-dns-cloudflare/setup.py @@ -63,6 +63,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Security', 'Topic :: System :: Installation/Setup', diff --git a/certbot-dns-cloudxns/setup.py b/certbot-dns-cloudxns/setup.py index 09225a42e..81f6afa12 100644 --- a/certbot-dns-cloudxns/setup.py +++ b/certbot-dns-cloudxns/setup.py @@ -63,6 +63,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Security', 'Topic :: System :: Installation/Setup', diff --git a/certbot-dns-digitalocean/setup.py b/certbot-dns-digitalocean/setup.py index 4da161146..f6c5936ae 100644 --- a/certbot-dns-digitalocean/setup.py +++ b/certbot-dns-digitalocean/setup.py @@ -64,6 +64,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Security', 'Topic :: System :: Installation/Setup', diff --git a/certbot-dns-dnsimple/setup.py b/certbot-dns-dnsimple/setup.py index cd1246e07..e0d95eea1 100644 --- a/certbot-dns-dnsimple/setup.py +++ b/certbot-dns-dnsimple/setup.py @@ -74,6 +74,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Security', 'Topic :: System :: Installation/Setup', diff --git a/certbot-dns-dnsmadeeasy/setup.py b/certbot-dns-dnsmadeeasy/setup.py index c077acbef..0ff3c71ab 100644 --- a/certbot-dns-dnsmadeeasy/setup.py +++ b/certbot-dns-dnsmadeeasy/setup.py @@ -63,6 +63,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Security', 'Topic :: System :: Installation/Setup', diff --git a/certbot-dns-gehirn/setup.py b/certbot-dns-gehirn/setup.py index ba58509f7..e57796e1a 100644 --- a/certbot-dns-gehirn/setup.py +++ b/certbot-dns-gehirn/setup.py @@ -62,6 +62,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Security', 'Topic :: System :: Installation/Setup', diff --git a/certbot-dns-google/setup.py b/certbot-dns-google/setup.py index 78a78cbc3..c52215f33 100644 --- a/certbot-dns-google/setup.py +++ b/certbot-dns-google/setup.py @@ -66,6 +66,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Security', 'Topic :: System :: Installation/Setup', diff --git a/certbot-dns-linode/setup.py b/certbot-dns-linode/setup.py index 4be13cf56..e7cdcabfb 100644 --- a/certbot-dns-linode/setup.py +++ b/certbot-dns-linode/setup.py @@ -62,6 +62,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Security', 'Topic :: System :: Installation/Setup', diff --git a/certbot-dns-luadns/setup.py b/certbot-dns-luadns/setup.py index 805158771..d38c9fcca 100644 --- a/certbot-dns-luadns/setup.py +++ b/certbot-dns-luadns/setup.py @@ -63,6 +63,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Security', 'Topic :: System :: Installation/Setup', diff --git a/certbot-dns-nsone/setup.py b/certbot-dns-nsone/setup.py index 100a48551..deaa60790 100644 --- a/certbot-dns-nsone/setup.py +++ b/certbot-dns-nsone/setup.py @@ -63,6 +63,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Security', 'Topic :: System :: Installation/Setup', diff --git a/certbot-dns-ovh/setup.py b/certbot-dns-ovh/setup.py index 585b038a3..349903900 100644 --- a/certbot-dns-ovh/setup.py +++ b/certbot-dns-ovh/setup.py @@ -63,6 +63,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Security', 'Topic :: System :: Installation/Setup', diff --git a/certbot-dns-rfc2136/certbot_dns_rfc2136/_internal/dns_rfc2136.py b/certbot-dns-rfc2136/certbot_dns_rfc2136/_internal/dns_rfc2136.py index 57e9506f2..a3a943660 100644 --- a/certbot-dns-rfc2136/certbot_dns_rfc2136/_internal/dns_rfc2136.py +++ b/certbot-dns-rfc2136/certbot_dns_rfc2136/_internal/dns_rfc2136.py @@ -1,3 +1,13 @@ +# type: ignore +# pylint: disable=no-member +# Many attributes of dnspython are now dynamically defined which causes both +# mypy and pylint to error about accessing attributes they think do not exist. +# This is the case even in up-to-date versions of mypy and pylint which as of +# writing this are 0.790 and 2.6.0 respectively. This problem may be fixed in +# dnspython 2.1.0. See https://github.com/rthalley/dnspython/issues/598. For +# now, let's disable these checks. This is done at the very top of the file +# like this because "type: ignore" must be the first line in the file to be +# respected by mypy. """DNS Authenticator using RFC 2136 Dynamic Updates.""" import logging diff --git a/certbot-dns-rfc2136/setup.py b/certbot-dns-rfc2136/setup.py index c841aefc1..c2c97a41f 100644 --- a/certbot-dns-rfc2136/setup.py +++ b/certbot-dns-rfc2136/setup.py @@ -63,6 +63,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Security', 'Topic :: System :: Installation/Setup', diff --git a/certbot-dns-route53/setup.py b/certbot-dns-route53/setup.py index 2ad0de045..7d28d2703 100644 --- a/certbot-dns-route53/setup.py +++ b/certbot-dns-route53/setup.py @@ -58,6 +58,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Security', 'Topic :: System :: Installation/Setup', diff --git a/certbot-dns-sakuracloud/setup.py b/certbot-dns-sakuracloud/setup.py index b1c6ee6a3..22f5fa031 100644 --- a/certbot-dns-sakuracloud/setup.py +++ b/certbot-dns-sakuracloud/setup.py @@ -62,6 +62,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Security', 'Topic :: System :: Installation/Setup', diff --git a/certbot-nginx/setup.py b/certbot-nginx/setup.py index a4faf470e..9dfa7bbb3 100644 --- a/certbot-nginx/setup.py +++ b/certbot-nginx/setup.py @@ -49,6 +49,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Security', 'Topic :: System :: Installation/Setup', diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index b7d57a62d..a7f48ea3b 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -13,6 +13,7 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). `secp256r1`, `secp284r1` and `secp521r1` are accepted values. * The command `certbot certficates` lists the which type of the private key that was used for the private key. +* Support for Python 3.9 was added to Certbot and all of its components. ### Changed diff --git a/certbot/setup.py b/certbot/setup.py index 742900402..ea87d2301 100644 --- a/certbot/setup.py +++ b/certbot/setup.py @@ -131,6 +131,7 @@ setup( 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Internet :: WWW/HTTP', 'Topic :: Security', 'Topic :: System :: Installation/Setup', diff --git a/tools/dev_constraints.txt b/tools/dev_constraints.txt index 1d8001727..967596ded 100644 --- a/tools/dev_constraints.txt +++ b/tools/dev_constraints.txt @@ -26,9 +26,15 @@ coverage==4.5.4 decorator==4.4.1 deprecated==1.2.10 dns-lexicon==3.3.17 -dnspython==1.15.0 -docker==3.7.2 -docker-compose==1.25.0 +# There is no version of dnspython that works on both Python 2 and Python 3.9. +# To work around this, we make use of the fact that subject to other +# constraints, pip will install the newest version of a package while ignoring +# versions that don't support the version of Python being used. The result of +# this is dnspython 2.0.0 is installed in Python 3 while dnspython 1.16.0 is +# installed in Python 2. +dnspython<=2.0.0 +docker==4.3.1 +docker-compose==1.26.2 docker-pycreds==0.4.0 dockerpty==0.4.1 docopt==0.6.2 @@ -94,8 +100,9 @@ pytest-sugar==0.9.2 pytest-rerunfailures==4.2 python-dateutil==2.8.1 python-digitalocean==1.11 +python-dotenv==0.14.0 pywin32==227 -PyYAML==3.13 +PyYAML==5.3.1 repoze.sphinx.autointerface==0.8 requests-file==1.4.2 requests-oauthlib==1.3.0 @@ -116,7 +123,7 @@ tox==3.14.0 tqdm==4.19.4 traitlets==4.3.3 twine==1.11.0 -typed-ast==1.4.0 +typed-ast==1.4.1 typing==3.6.4 uritemplate==3.0.0 virtualenv==16.6.2 diff --git a/tools/merge_requirements.py b/tools/merge_requirements.py index 0d41d12c4..bbcb38051 100755 --- a/tools/merge_requirements.py +++ b/tools/merge_requirements.py @@ -1,8 +1,9 @@ #!/usr/bin/env python """Merges multiple Python requirements files into one file. -Requirements files specified later take precedence over earlier ones. Only -simple SomeProject==1.2.3 format is currently supported. +Requirements files specified later take precedence over earlier ones. +Only the simple formats SomeProject==1.2.3 or SomeProject<=1.2.3 are +currently supported. """ from __future__ import print_function @@ -16,17 +17,28 @@ def process_entries(entries): :param list entries: List of entries - :returns: mapping from a project to its pinned version + :returns: mapping from a project to its version specifier :rtype: dict """ data = {} for e in entries: e = e.strip() if e and not e.startswith('#') and not e.startswith('-e'): - project, version = e.split('==') - if not version: + # Support for <= was added as part of + # https://github.com/certbot/certbot/pull/8460 because we weren't + # able to pin a package to an exact version. Normally, this + # functionality shouldn't be needed so we could remove it in the + # future. If you do so, make sure to update other places in this + # file related to this behavior such as this file's docstring. + for comparison in ('==', '<=',): + parts = e.split(comparison) + if len(parts) == 2: + project_name = parts[0] + version = parts[1] + data[project_name] = comparison + version + break + else: raise ValueError("Unexpected syntax '{0}'".format(e)) - data[project] = version return data def read_file(file_path): @@ -44,10 +56,11 @@ def read_file(file_path): def output_requirements(requirements): """Prepare print requirements to stdout. - :param dict requirements: mapping from a project to its pinned version + :param dict requirements: mapping from a project to its version + specifier """ - return '\n'.join('{0}=={1}'.format(key, value) + return '\n'.join('{0}{1}'.format(key, value) for key, value in sorted(requirements.items())) From aea416f6549d6cb0176bfcb6113ea6b61584e570 Mon Sep 17 00:00:00 2001 From: Mads Jensen Date: Wed, 25 Nov 2020 10:11:51 +0100 Subject: [PATCH 15/42] Fix link typo in README (#8476) --- certbot/README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot/README.rst b/certbot/README.rst index 3bd5e4cd7..2ff2d41be 100644 --- a/certbot/README.rst +++ b/certbot/README.rst @@ -106,7 +106,7 @@ Current Features * Can get domain-validated (DV) certificates. * Can revoke certificates. * Adjustable RSA key bit-length (2048 (default), 4096, ...). -* Adjustable [EC](https://en.wikipedia.org/wiki/Elliptic-curve_cryptography) +* Adjustable `EC `_ key (`secp256r1` (default), `secp384r1`, `secp521r1`). * Can optionally install a http -> https redirect, so your site effectively runs https only (Apache only) From f5a88ade54cc34ae216959a84a658986324ea69c Mon Sep 17 00:00:00 2001 From: alexzorin Date: Sat, 28 Nov 2020 04:15:27 +1100 Subject: [PATCH 16/42] nginx: fix Unicode crash on Python 2 (#8480) * nginx: fix py2 unicode sandwich The nginx parser would crash when saving configuraitons containing Unicode, because py2's `str` type does not support Unicode. This change fixes that crash by ensuring that a string type supporting Unicode is used in both Python 2 and Python 3. * nginx: add unicode to the integration test config * update CHANGELOG --- .../nginx_tests/nginx_config.py | 31 ++++++++++--------- .../certbot_nginx/_internal/http_01.py | 3 +- .../certbot_nginx/_internal/nginxparser.py | 18 ++++++----- .../certbot_nginx/_internal/parser.py | 2 +- certbot-nginx/tests/parser_test.py | 8 +++++ certbot/CHANGELOG.md | 2 +- 6 files changed, 39 insertions(+), 25 deletions(-) diff --git a/certbot-ci/certbot_integration_tests/nginx_tests/nginx_config.py b/certbot-ci/certbot_integration_tests/nginx_tests/nginx_config.py index 18991ae62..bbbe8ea06 100644 --- a/certbot-ci/certbot_integration_tests/nginx_tests/nginx_config.py +++ b/certbot-ci/certbot_integration_tests/nginx_tests/nginx_config.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- """General purpose nginx test configuration generator.""" import getpass @@ -42,6 +43,8 @@ events {{ worker_connections 1024; }} +# “This comment contains valid Unicode”. + http {{ # Set an array of temp, cache and log file options that will otherwise default to # restricted locations accessible only to root. @@ -51,61 +54,61 @@ http {{ #scgi_temp_path {nginx_root}/scgi_temp; #uwsgi_temp_path {nginx_root}/uwsgi_temp; access_log {nginx_root}/error.log; - + # This should be turned off in a Virtualbox VM, as it can cause some # interesting issues with data corruption in delivered files. sendfile off; - + tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; - + #include /etc/nginx/mime.types; index index.html index.htm index.php; - + log_format main '$remote_addr - $remote_user [$time_local] $status ' '"$request" $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; - + default_type application/octet-stream; - + server {{ # IPv4. listen {http_port} {default_server}; # IPv6. listen [::]:{http_port} {default_server}; server_name nginx.{wtf_prefix}.wtf nginx2.{wtf_prefix}.wtf; - + root {nginx_webroot}; - + location / {{ # First attempt to serve request as file, then as directory, then fall # back to index.html. try_files $uri $uri/ /index.html; }} }} - + server {{ listen {http_port}; listen [::]:{http_port}; server_name nginx3.{wtf_prefix}.wtf; - + root {nginx_webroot}; - + location /.well-known/ {{ return 404; }} - + return 301 https://$host$request_uri; }} - + server {{ listen {other_port}; listen [::]:{other_port}; server_name nginx4.{wtf_prefix}.wtf nginx5.{wtf_prefix}.wtf; }} - + server {{ listen {http_port}; listen [::]:{http_port}; diff --git a/certbot-nginx/certbot_nginx/_internal/http_01.py b/certbot-nginx/certbot_nginx/_internal/http_01.py index 2f6458f87..40f994988 100644 --- a/certbot-nginx/certbot_nginx/_internal/http_01.py +++ b/certbot-nginx/certbot_nginx/_internal/http_01.py @@ -1,5 +1,6 @@ """A class that performs HTTP-01 challenges for Nginx""" +import io import logging from acme import challenges @@ -102,7 +103,7 @@ class NginxHttp01(common.ChallengePerformer): self.configurator.reverter.register_file_creation( True, self.challenge_conf) - with open(self.challenge_conf, "w") as new_conf: + with io.open(self.challenge_conf, "w", encoding="utf-8") as new_conf: nginxparser.dump(config, new_conf) def _default_listen_addresses(self): diff --git a/certbot-nginx/certbot_nginx/_internal/nginxparser.py b/certbot-nginx/certbot_nginx/_internal/nginxparser.py index a8ac90427..5f723dcef 100644 --- a/certbot-nginx/certbot_nginx/_internal/nginxparser.py +++ b/certbot-nginx/certbot_nginx/_internal/nginxparser.py @@ -16,6 +16,7 @@ from pyparsing import stringEnd from pyparsing import White from pyparsing import ZeroOrMore import six +from acme.magic_typing import IO, Any # pylint: disable=unused-import logger = logging.getLogger(__name__) @@ -130,26 +131,27 @@ def load(_file): def dumps(blocks): - """Dump to a string. + # type: (UnspacedList) -> six.text_type + """Dump to a Unicode string. :param UnspacedList block: The parsed tree - :param int indentation: The number of spaces to indent - :rtype: str + :rtype: six.text_type """ - return str(RawNginxDumper(blocks.spaced)) + return six.text_type(RawNginxDumper(blocks.spaced)) def dump(blocks, _file): + # type: (UnspacedList, IO[Any]) -> None """Dump to a file. :param UnspacedList block: The parsed tree - :param file _file: The file to dump to - :param int indentation: The number of spaces to indent - :rtype: NoneType + :param IO[Any] _file: The file stream to dump to. It must be opened with + Unicode encoding. + :rtype: None """ - return _file.write(dumps(blocks)) + _file.write(dumps(blocks)) spacey = lambda x: (isinstance(x, six.string_types) and x.isspace()) or x == '' diff --git a/certbot-nginx/certbot_nginx/_internal/parser.py b/certbot-nginx/certbot_nginx/_internal/parser.py index 641ffb020..72091b03f 100644 --- a/certbot-nginx/certbot_nginx/_internal/parser.py +++ b/certbot-nginx/certbot_nginx/_internal/parser.py @@ -249,7 +249,7 @@ class NginxParser(object): continue out = nginxparser.dumps(tree) logger.debug('Writing nginx conf tree to %s:\n%s', filename, out) - with open(filename, 'w') as _file: + with io.open(filename, 'w', encoding='utf-8') as _file: _file.write(out) except IOError: diff --git a/certbot-nginx/tests/parser_test.py b/certbot-nginx/tests/parser_test.py index 620d1b6de..0083c2448 100644 --- a/certbot-nginx/tests/parser_test.py +++ b/certbot-nginx/tests/parser_test.py @@ -492,6 +492,14 @@ class NginxParserTest(util.NginxTest): self.assertEqual(['server'], parsed[0][2][0]) self.assertEqual(['listen', '80'], parsed[0][2][1][3]) + def test_valid_unicode_roundtrip(self): + """This tests the parser's ability to load and save a config containing Unicode""" + nparser = parser.NginxParser(self.config_path) + nparser._parse_files( + nparser.abs_path('valid_unicode_comments.conf') + ) # pylint: disable=protected-access + nparser.filedump(lazy=False) + def test_invalid_unicode_characters(self): with self.assertLogs() as log: nparser = parser.NginxParser(self.config_path) diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index a7f48ea3b..b3e2373a0 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -24,7 +24,7 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). ### Fixed -* +* Fixed a Unicode-related crash in the nginx plugin when running under Python 2. More details about these changes can be found on our GitHub repo. From 43ee2993f135218cf1c3318acfa4c01b20a3922b Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 1 Dec 2020 10:22:39 -0800 Subject: [PATCH 17/42] Update changelog for 1.10.0 release --- certbot/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index b3e2373a0..4e4a27316 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -2,7 +2,7 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). -## 1.10.0 - master +## 1.10.0 - 2020-12-01 ### Added From adacc4ab6dc63b024b17f0ec5adeb1adc9f93300 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 1 Dec 2020 10:35:55 -0800 Subject: [PATCH 18/42] Release 1.10.0 --- acme/setup.py | 2 +- certbot-apache/setup.py | 2 +- certbot-auto | 32 ++++++++---------- certbot-compatibility-test/setup.py | 2 +- certbot-dns-cloudflare/setup.py | 2 +- certbot-dns-cloudxns/setup.py | 2 +- certbot-dns-digitalocean/setup.py | 2 +- certbot-dns-dnsimple/setup.py | 2 +- certbot-dns-dnsmadeeasy/setup.py | 2 +- certbot-dns-gehirn/setup.py | 2 +- certbot-dns-google/setup.py | 2 +- certbot-dns-linode/setup.py | 2 +- certbot-dns-luadns/setup.py | 2 +- certbot-dns-nsone/setup.py | 2 +- certbot-dns-ovh/setup.py | 2 +- certbot-dns-rfc2136/setup.py | 2 +- certbot-dns-route53/setup.py | 2 +- certbot-dns-sakuracloud/setup.py | 2 +- certbot-nginx/setup.py | 2 +- certbot/certbot/__init__.py | 2 +- certbot/docs/cli-help.txt | 28 +++++++-------- letsencrypt-auto | 32 ++++++++---------- letsencrypt-auto-source/certbot-auto.asc | 16 ++++----- letsencrypt-auto-source/letsencrypt-auto | 26 +++++++------- letsencrypt-auto-source/letsencrypt-auto.sig | Bin 256 -> 256 bytes .../pieces/certbot-requirements.txt | 24 ++++++------- 26 files changed, 93 insertions(+), 103 deletions(-) diff --git a/acme/setup.py b/acme/setup.py index 55d1ae17d..76db38fe6 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -5,7 +5,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0.dev0' +version = '1.10.0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-apache/setup.py b/certbot-apache/setup.py index c6fadb929..8e632e1db 100644 --- a/certbot-apache/setup.py +++ b/certbot-apache/setup.py @@ -5,7 +5,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0.dev0' +version = '1.10.0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-auto b/certbot-auto index 2a0cda9b3..96b40c0c8 100755 --- a/certbot-auto +++ b/certbot-auto @@ -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.9.0" +LE_AUTO_VERSION="1.10.0" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -799,11 +799,7 @@ BootstrapMageiaCommon() { # that function. If Bootstrap is set to a function that doesn't install any # packages BOOTSTRAP_VERSION is not set. if [ -f /etc/debian_version ]; then - Bootstrap() { - BootstrapMessage "Debian-based OSes" - BootstrapDebCommon - } - BOOTSTRAP_VERSION="BootstrapDebCommon $BOOTSTRAP_DEB_COMMON_VERSION" + DEPRECATED_OS=1 elif [ -f /etc/mageia-release ]; then # Mageia has both /etc/mageia-release and /etc/redhat-release DEPRECATED_OS=1 @@ -1497,18 +1493,18 @@ letsencrypt==0.7.0 \ --hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \ --hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9 -certbot==1.9.0 \ - --hash=sha256:d5a804d32e471050921f7b39ed9859e2e9de02824176ed78f57266222036b53a \ - --hash=sha256:2ff9bf7d9af381c7efee22dec2dd6938d9d8fddcc9e11682b86e734164a30b57 -acme==1.9.0 \ - --hash=sha256:d8061b396a22b21782c9b23ff9a945b23e50fca2573909a42f845e11d5658ac5 \ - --hash=sha256:38a1630c98e144136c62eec4d2c545a1bdb1a3cd4eca82214be6b83a1f5a161f -certbot-apache==1.9.0 \ - --hash=sha256:09528a820d57e54984d490100644cd8a6603db97bf5776f86e95795ecfacf23d \ - --hash=sha256:f47fb3f4a9bd927f4812121a0beefe56b163475a28f4db34c64dc838688d9e9e -certbot-nginx==1.9.0 \ - --hash=sha256:bb2e3f7fe17f071f350a3efa48571b8ef40a8e4b6db9c6da72539206a20b70be \ - --hash=sha256:ab26a4f49d53b0e8bf0f903e58e2a840cda233fe1cbbc54c36ff17f973e57d65 +certbot==1.10.0 \ + --hash=sha256:b4f3d73c440d09a95346991bf7cf80870baf37dcf4865f3766dc43bc35d2c9a6 \ + --hash=sha256:5d79bd451756112a7db2cdb25d193de9baf3df85211ed9587685be32b779bbfc +acme==1.10.0 \ + --hash=sha256:bcaff04357d4fa1b87b12fd9721a7da9e1496b88c5e9edda85ec9d69376e9a29 \ + --hash=sha256:e3939526d08530d4b17623f843b9a983f2d772eefb7836bd31091c229da04a90 +certbot-apache==1.10.0 \ + --hash=sha256:2ccc61b03d307631da24a63b2a0449094e2accda9bb1fe3d66a178e806d89101 \ + --hash=sha256:5396526937c46f1ed5bc1615506ed67e7dbb26b247666842cc9788c9e2b6d012 +certbot-nginx==1.10.0 \ + --hash=sha256:dfa5254b5ea5bd94578fad4094585bd14ed940767ac1bdffe2a68fd395432a6b \ + --hash=sha256:aaf5ee4b00fa9b9a347843d4a01c70a770485c44284d52c4da5e155741125b09 UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/certbot-compatibility-test/setup.py b/certbot-compatibility-test/setup.py index 66e1c9f03..f9390f5d4 100644 --- a/certbot-compatibility-test/setup.py +++ b/certbot-compatibility-test/setup.py @@ -5,7 +5,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0.dev0' +version = '1.10.0' install_requires = [ 'certbot', diff --git a/certbot-dns-cloudflare/setup.py b/certbot-dns-cloudflare/setup.py index 34938aca1..fd6fc1f8e 100644 --- a/certbot-dns-cloudflare/setup.py +++ b/certbot-dns-cloudflare/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0.dev0' +version = '1.10.0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-cloudxns/setup.py b/certbot-dns-cloudxns/setup.py index 81f6afa12..93e2aae50 100644 --- a/certbot-dns-cloudxns/setup.py +++ b/certbot-dns-cloudxns/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0.dev0' +version = '1.10.0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-digitalocean/setup.py b/certbot-dns-digitalocean/setup.py index f6c5936ae..b231f3060 100644 --- a/certbot-dns-digitalocean/setup.py +++ b/certbot-dns-digitalocean/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0.dev0' +version = '1.10.0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-dnsimple/setup.py b/certbot-dns-dnsimple/setup.py index e0d95eea1..6c4aff4a6 100644 --- a/certbot-dns-dnsimple/setup.py +++ b/certbot-dns-dnsimple/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0.dev0' +version = '1.10.0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-dnsmadeeasy/setup.py b/certbot-dns-dnsmadeeasy/setup.py index 0ff3c71ab..68a432a35 100644 --- a/certbot-dns-dnsmadeeasy/setup.py +++ b/certbot-dns-dnsmadeeasy/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0.dev0' +version = '1.10.0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-gehirn/setup.py b/certbot-dns-gehirn/setup.py index e57796e1a..0d1d04bf2 100644 --- a/certbot-dns-gehirn/setup.py +++ b/certbot-dns-gehirn/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0.dev0' +version = '1.10.0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-dns-google/setup.py b/certbot-dns-google/setup.py index c52215f33..081a74170 100644 --- a/certbot-dns-google/setup.py +++ b/certbot-dns-google/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0.dev0' +version = '1.10.0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-linode/setup.py b/certbot-dns-linode/setup.py index e7cdcabfb..3d56cd737 100644 --- a/certbot-dns-linode/setup.py +++ b/certbot-dns-linode/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0.dev0' +version = '1.10.0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-dns-luadns/setup.py b/certbot-dns-luadns/setup.py index d38c9fcca..229bb03d8 100644 --- a/certbot-dns-luadns/setup.py +++ b/certbot-dns-luadns/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0.dev0' +version = '1.10.0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-nsone/setup.py b/certbot-dns-nsone/setup.py index deaa60790..a3fc92b9c 100644 --- a/certbot-dns-nsone/setup.py +++ b/certbot-dns-nsone/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0.dev0' +version = '1.10.0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-ovh/setup.py b/certbot-dns-ovh/setup.py index 349903900..ac8b52fdf 100644 --- a/certbot-dns-ovh/setup.py +++ b/certbot-dns-ovh/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0.dev0' +version = '1.10.0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-rfc2136/setup.py b/certbot-dns-rfc2136/setup.py index c2c97a41f..af919c32a 100644 --- a/certbot-dns-rfc2136/setup.py +++ b/certbot-dns-rfc2136/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0.dev0' +version = '1.10.0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-route53/setup.py b/certbot-dns-route53/setup.py index 7d28d2703..6fc8494d3 100644 --- a/certbot-dns-route53/setup.py +++ b/certbot-dns-route53/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0.dev0' +version = '1.10.0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-sakuracloud/setup.py b/certbot-dns-sakuracloud/setup.py index 22f5fa031..d567a3a4e 100644 --- a/certbot-dns-sakuracloud/setup.py +++ b/certbot-dns-sakuracloud/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0.dev0' +version = '1.10.0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-nginx/setup.py b/certbot-nginx/setup.py index 9dfa7bbb3..4a89e2662 100644 --- a/certbot-nginx/setup.py +++ b/certbot-nginx/setup.py @@ -5,7 +5,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0.dev0' +version = '1.10.0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot/certbot/__init__.py b/certbot/certbot/__init__.py index 8ee415682..7028d15b2 100644 --- a/certbot/certbot/__init__.py +++ b/certbot/certbot/__init__.py @@ -1,4 +1,4 @@ """Certbot client.""" # version number like 1.2.3a0, must have at least 2 parts, like 1.2 -__version__ = '1.10.0.dev0' +__version__ = '1.10.0' diff --git a/certbot/docs/cli-help.txt b/certbot/docs/cli-help.txt index 5f8e2e00b..01cdb3130 100644 --- a/certbot/docs/cli-help.txt +++ b/certbot/docs/cli-help.txt @@ -1,4 +1,4 @@ -usage: +usage: certbot [SUBCOMMAND] [options] [-d DOMAIN] [-d DOMAIN] ... Certbot can obtain and install HTTPS/TLS/SSL certificates. By default, @@ -118,12 +118,12 @@ 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.9.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, - --force-renew, --allow-subset-of-names, -n, and - whether any hooks are set. + "". (default: CertbotACMEClient/1.10.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, --force-renew, --allow- + subset-of-names, -n, and whether any hooks are set. --user-agent-comment USER_AGENT_COMMENT Add a comment to the default user agent string. May be used when repackaging Certbot or calling it from @@ -188,12 +188,12 @@ security: Security parameters & server settings --rsa-key-size N Size of the RSA key. (default: 2048) - --key-type type The type of algorithm to use for the the private key. - Either ``rsa`` or ``ecdsa``. (default: ``rsa``). - --elliptic-curve The elliptic curve to use when choosing ``ecdsa`` as the key - type. Accepted values are SECG curve names as defined by - the cryptography library. ``secp256r1``, ``secp384r1``, - ``secp521r1``. (default: secp256r1). + --key-type {rsa,ecdsa} + Type of generated private key(Only *ONE* per + invocation can be provided at this time) (default: + rsa) + --elliptic-curve N The SECG elliptic curve name to use. Please see RFC + 8446 for supported values. (default: secp256r1) --must-staple Adds the OCSP Must Staple extension to the certificate. Autoconfigures OCSP Stapling for supported setups (Apache version >= 2.3.3 ). (default: @@ -694,8 +694,6 @@ manual: --manual-cleanup-hook MANUAL_CLEANUP_HOOK Path or command to execute for the cleanup script (default: None) - --manual-public-ip-logging-ok - Automatically allows public IP logging (default: Ask) nginx: Nginx Web Server plugin diff --git a/letsencrypt-auto b/letsencrypt-auto index 2a0cda9b3..96b40c0c8 100755 --- a/letsencrypt-auto +++ b/letsencrypt-auto @@ -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.9.0" +LE_AUTO_VERSION="1.10.0" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -799,11 +799,7 @@ BootstrapMageiaCommon() { # that function. If Bootstrap is set to a function that doesn't install any # packages BOOTSTRAP_VERSION is not set. if [ -f /etc/debian_version ]; then - Bootstrap() { - BootstrapMessage "Debian-based OSes" - BootstrapDebCommon - } - BOOTSTRAP_VERSION="BootstrapDebCommon $BOOTSTRAP_DEB_COMMON_VERSION" + DEPRECATED_OS=1 elif [ -f /etc/mageia-release ]; then # Mageia has both /etc/mageia-release and /etc/redhat-release DEPRECATED_OS=1 @@ -1497,18 +1493,18 @@ letsencrypt==0.7.0 \ --hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \ --hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9 -certbot==1.9.0 \ - --hash=sha256:d5a804d32e471050921f7b39ed9859e2e9de02824176ed78f57266222036b53a \ - --hash=sha256:2ff9bf7d9af381c7efee22dec2dd6938d9d8fddcc9e11682b86e734164a30b57 -acme==1.9.0 \ - --hash=sha256:d8061b396a22b21782c9b23ff9a945b23e50fca2573909a42f845e11d5658ac5 \ - --hash=sha256:38a1630c98e144136c62eec4d2c545a1bdb1a3cd4eca82214be6b83a1f5a161f -certbot-apache==1.9.0 \ - --hash=sha256:09528a820d57e54984d490100644cd8a6603db97bf5776f86e95795ecfacf23d \ - --hash=sha256:f47fb3f4a9bd927f4812121a0beefe56b163475a28f4db34c64dc838688d9e9e -certbot-nginx==1.9.0 \ - --hash=sha256:bb2e3f7fe17f071f350a3efa48571b8ef40a8e4b6db9c6da72539206a20b70be \ - --hash=sha256:ab26a4f49d53b0e8bf0f903e58e2a840cda233fe1cbbc54c36ff17f973e57d65 +certbot==1.10.0 \ + --hash=sha256:b4f3d73c440d09a95346991bf7cf80870baf37dcf4865f3766dc43bc35d2c9a6 \ + --hash=sha256:5d79bd451756112a7db2cdb25d193de9baf3df85211ed9587685be32b779bbfc +acme==1.10.0 \ + --hash=sha256:bcaff04357d4fa1b87b12fd9721a7da9e1496b88c5e9edda85ec9d69376e9a29 \ + --hash=sha256:e3939526d08530d4b17623f843b9a983f2d772eefb7836bd31091c229da04a90 +certbot-apache==1.10.0 \ + --hash=sha256:2ccc61b03d307631da24a63b2a0449094e2accda9bb1fe3d66a178e806d89101 \ + --hash=sha256:5396526937c46f1ed5bc1615506ed67e7dbb26b247666842cc9788c9e2b6d012 +certbot-nginx==1.10.0 \ + --hash=sha256:dfa5254b5ea5bd94578fad4094585bd14ed940767ac1bdffe2a68fd395432a6b \ + --hash=sha256:aaf5ee4b00fa9b9a347843d4a01c70a770485c44284d52c4da5e155741125b09 UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/letsencrypt-auto-source/certbot-auto.asc b/letsencrypt-auto-source/certbot-auto.asc index f73e8b35e..4b8d6d60a 100644 --- a/letsencrypt-auto-source/certbot-auto.asc +++ b/letsencrypt-auto-source/certbot-auto.asc @@ -1,11 +1,11 @@ -----BEGIN PGP SIGNATURE----- -iQEzBAABCAAdFiEEos+1H6J1pyhiNOeyTRfJlc2XdfIFAl98wk8ACgkQTRfJlc2X -dfIctgf/TO83xXJJ8haqxke0ehHCwcmipX7ijPhwvaUTSqciMa56KnGJLNp1lAVz -vv8sfHUf7NSvGlRg+5M0szWY25+JzveJDNzse3rOzFmxA1GNKUycE3/zE/IdBRwN -fmxJHaUBrBL2erBZPHe8gFGTvlzopBoGSmQpWGY3hIufPWKBJohCbTscKbaa9hyz -njmMvwRdeqzvLWVZ4jNDDsil9kKl2Emue3guzA/cvVxHe17DZyLDfqni7ysZIcTn -wPAQzpLBKHyiqVRoVk+BJ6Z6wamW4NAxKbjXy9GrHy4txlfW8tGd3jXha8yWqJeH -xEFK02Zp+T17+C5uqEW4o0cIofMjCw== -=9UGf +iQEzBAABCAAdFiEEos+1H6J1pyhiNOeyTRfJlc2XdfIFAl/GjQkACgkQTRfJlc2X +dfJSUwf/fdEu4EJhIPzotzUz8hiyWWvQdH/rdhjd9rWjF/B8FZjjb5vMQAPMn3Z3 +E0MhE4AKvVly4ckh7WGRDP9pNA770JXsT6dOdpnlAtwZozfEcWYQnKHXurc4hCqE +17dlE1jhyHpveUulGmf0A+biWExT3nrG2wE6bACQztYp6+sCmnGfGsR0NXW2YWSx +c+C6ixlmXYDU8QFxpgQVpqthI9k/LiFzCWJFYeERN12gLaK16Yc8lCU7lgVuCul2 +PrNN9ngX6i5zomfgv1ZGpfgZT1Nr0qKf4SSW7Ql73pXPtAR8mA6Jo7HxlwaS/qQ9 +m+EhHDGeylyA1cyqw/94qaDVBIyz7A== +=+xVC -----END PGP SIGNATURE----- diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 83a1041ba..96b40c0c8 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -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.10.0.dev0" +LE_AUTO_VERSION="1.10.0" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -1493,18 +1493,18 @@ letsencrypt==0.7.0 \ --hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \ --hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9 -certbot==1.9.0 \ - --hash=sha256:d5a804d32e471050921f7b39ed9859e2e9de02824176ed78f57266222036b53a \ - --hash=sha256:2ff9bf7d9af381c7efee22dec2dd6938d9d8fddcc9e11682b86e734164a30b57 -acme==1.9.0 \ - --hash=sha256:d8061b396a22b21782c9b23ff9a945b23e50fca2573909a42f845e11d5658ac5 \ - --hash=sha256:38a1630c98e144136c62eec4d2c545a1bdb1a3cd4eca82214be6b83a1f5a161f -certbot-apache==1.9.0 \ - --hash=sha256:09528a820d57e54984d490100644cd8a6603db97bf5776f86e95795ecfacf23d \ - --hash=sha256:f47fb3f4a9bd927f4812121a0beefe56b163475a28f4db34c64dc838688d9e9e -certbot-nginx==1.9.0 \ - --hash=sha256:bb2e3f7fe17f071f350a3efa48571b8ef40a8e4b6db9c6da72539206a20b70be \ - --hash=sha256:ab26a4f49d53b0e8bf0f903e58e2a840cda233fe1cbbc54c36ff17f973e57d65 +certbot==1.10.0 \ + --hash=sha256:b4f3d73c440d09a95346991bf7cf80870baf37dcf4865f3766dc43bc35d2c9a6 \ + --hash=sha256:5d79bd451756112a7db2cdb25d193de9baf3df85211ed9587685be32b779bbfc +acme==1.10.0 \ + --hash=sha256:bcaff04357d4fa1b87b12fd9721a7da9e1496b88c5e9edda85ec9d69376e9a29 \ + --hash=sha256:e3939526d08530d4b17623f843b9a983f2d772eefb7836bd31091c229da04a90 +certbot-apache==1.10.0 \ + --hash=sha256:2ccc61b03d307631da24a63b2a0449094e2accda9bb1fe3d66a178e806d89101 \ + --hash=sha256:5396526937c46f1ed5bc1615506ed67e7dbb26b247666842cc9788c9e2b6d012 +certbot-nginx==1.10.0 \ + --hash=sha256:dfa5254b5ea5bd94578fad4094585bd14ed940767ac1bdffe2a68fd395432a6b \ + --hash=sha256:aaf5ee4b00fa9b9a347843d4a01c70a770485c44284d52c4da5e155741125b09 UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/letsencrypt-auto-source/letsencrypt-auto.sig b/letsencrypt-auto-source/letsencrypt-auto.sig index 66b2b2084ee9a8a4df1bf13160f83d1b3074e336..fba43c16f50a922d1ba3f484b57777229dedbb43 100644 GIT binary patch literal 256 zcmV+b0ssD%vXCa-pMfAZU8x`QAcDw*r*t})Y_~h-0Z8|4UDl!iYNX#8g|EGCFOBPGRZ2U8REBjfM!%Fmlq}6 z#*=2JkJEEYm2M3K=sKJZh8N(+=I<`T;)-BralaL#T;H31s04%CG!`4dZ46y@x Date: Tue, 1 Dec 2020 10:35:57 -0800 Subject: [PATCH 19/42] Add contents to certbot/CHANGELOG.md for next version --- certbot/CHANGELOG.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index 4e4a27316..7214582e0 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -2,6 +2,22 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). +## 1.11.0 - master + +### Added + +* + +### Changed + +* + +### Fixed + +* + +More details about these changes can be found on our GitHub repo. + ## 1.10.0 - 2020-12-01 ### Added From baab69e6533a7862f24a6c9cae2002c683c2ed22 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 1 Dec 2020 10:35:58 -0800 Subject: [PATCH 20/42] Bump version to 1.11.0 --- acme/setup.py | 2 +- certbot-apache/setup.py | 2 +- certbot-compatibility-test/setup.py | 2 +- certbot-dns-cloudflare/setup.py | 2 +- certbot-dns-cloudxns/setup.py | 2 +- certbot-dns-digitalocean/setup.py | 2 +- certbot-dns-dnsimple/setup.py | 2 +- certbot-dns-dnsmadeeasy/setup.py | 2 +- certbot-dns-gehirn/setup.py | 2 +- certbot-dns-google/setup.py | 2 +- certbot-dns-linode/setup.py | 2 +- certbot-dns-luadns/setup.py | 2 +- certbot-dns-nsone/setup.py | 2 +- certbot-dns-ovh/setup.py | 2 +- certbot-dns-rfc2136/setup.py | 2 +- certbot-dns-route53/setup.py | 2 +- certbot-dns-sakuracloud/setup.py | 2 +- certbot-nginx/setup.py | 2 +- certbot/certbot/__init__.py | 2 +- letsencrypt-auto-source/letsencrypt-auto | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/acme/setup.py b/acme/setup.py index 76db38fe6..f8f9efaad 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -5,7 +5,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.11.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-apache/setup.py b/certbot-apache/setup.py index 8e632e1db..8b908ade7 100644 --- a/certbot-apache/setup.py +++ b/certbot-apache/setup.py @@ -5,7 +5,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-compatibility-test/setup.py b/certbot-compatibility-test/setup.py index f9390f5d4..c894e5dee 100644 --- a/certbot-compatibility-test/setup.py +++ b/certbot-compatibility-test/setup.py @@ -5,7 +5,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.11.0.dev0' install_requires = [ 'certbot', diff --git a/certbot-dns-cloudflare/setup.py b/certbot-dns-cloudflare/setup.py index fd6fc1f8e..a00f06a8a 100644 --- a/certbot-dns-cloudflare/setup.py +++ b/certbot-dns-cloudflare/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-cloudxns/setup.py b/certbot-dns-cloudxns/setup.py index 93e2aae50..3771c1d34 100644 --- a/certbot-dns-cloudxns/setup.py +++ b/certbot-dns-cloudxns/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-digitalocean/setup.py b/certbot-dns-digitalocean/setup.py index b231f3060..f168ee06a 100644 --- a/certbot-dns-digitalocean/setup.py +++ b/certbot-dns-digitalocean/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-dnsimple/setup.py b/certbot-dns-dnsimple/setup.py index 6c4aff4a6..f23bd6668 100644 --- a/certbot-dns-dnsimple/setup.py +++ b/certbot-dns-dnsimple/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-dnsmadeeasy/setup.py b/certbot-dns-dnsmadeeasy/setup.py index 68a432a35..e654ed421 100644 --- a/certbot-dns-dnsmadeeasy/setup.py +++ b/certbot-dns-dnsmadeeasy/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-gehirn/setup.py b/certbot-dns-gehirn/setup.py index 0d1d04bf2..a856f1cde 100644 --- a/certbot-dns-gehirn/setup.py +++ b/certbot-dns-gehirn/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.11.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-dns-google/setup.py b/certbot-dns-google/setup.py index 081a74170..82c2a9102 100644 --- a/certbot-dns-google/setup.py +++ b/certbot-dns-google/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-linode/setup.py b/certbot-dns-linode/setup.py index 3d56cd737..a6f159757 100644 --- a/certbot-dns-linode/setup.py +++ b/certbot-dns-linode/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.11.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-dns-luadns/setup.py b/certbot-dns-luadns/setup.py index 229bb03d8..ff4a1b41d 100644 --- a/certbot-dns-luadns/setup.py +++ b/certbot-dns-luadns/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-nsone/setup.py b/certbot-dns-nsone/setup.py index a3fc92b9c..887d5120a 100644 --- a/certbot-dns-nsone/setup.py +++ b/certbot-dns-nsone/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-ovh/setup.py b/certbot-dns-ovh/setup.py index ac8b52fdf..d519a9e18 100644 --- a/certbot-dns-ovh/setup.py +++ b/certbot-dns-ovh/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-rfc2136/setup.py b/certbot-dns-rfc2136/setup.py index af919c32a..540fc1a67 100644 --- a/certbot-dns-rfc2136/setup.py +++ b/certbot-dns-rfc2136/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-route53/setup.py b/certbot-dns-route53/setup.py index 6fc8494d3..cffa16367 100644 --- a/certbot-dns-route53/setup.py +++ b/certbot-dns-route53/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-sakuracloud/setup.py b/certbot-dns-sakuracloud/setup.py index d567a3a4e..2c88f1226 100644 --- a/certbot-dns-sakuracloud/setup.py +++ b/certbot-dns-sakuracloud/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.11.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-nginx/setup.py b/certbot-nginx/setup.py index 4a89e2662..0ed164da2 100644 --- a/certbot-nginx/setup.py +++ b/certbot-nginx/setup.py @@ -5,7 +5,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot/certbot/__init__.py b/certbot/certbot/__init__.py index 7028d15b2..11c97dfac 100644 --- a/certbot/certbot/__init__.py +++ b/certbot/certbot/__init__.py @@ -1,4 +1,4 @@ """Certbot client.""" # version number like 1.2.3a0, must have at least 2 parts, like 1.2 -__version__ = '1.10.0' +__version__ = '1.11.0.dev0' diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 96b40c0c8..31f648721 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -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.10.0" +LE_AUTO_VERSION="1.11.0.dev0" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates From 31b5f1310e1fd0331faaa7efbcb8cccdfee93e78 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Tue, 1 Dec 2020 13:57:04 -0800 Subject: [PATCH 21/42] Fix changelog typo (#8488) * fix changelog typo * remove empty entry --- certbot/CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index 7214582e0..94dde1e11 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -26,7 +26,7 @@ More details about these changes can be found on our GitHub repo. * Confirmation when deleting certificates * CLI flag `--key-type` has been added to specify 'rsa' or 'ecdsa' (default 'rsa'). * CLI flag `--elliptic-curve` has been added which takes an NIST/SECG elliptic curve. Any of - `secp256r1`, `secp284r1` and `secp521r1` are accepted values. + `secp256r1`, `secp384r1` and `secp521r1` are accepted values. * The command `certbot certficates` lists the which type of the private key that was used for the private key. * Support for Python 3.9 was added to Certbot and all of its components. @@ -36,7 +36,6 @@ More details about these changes can be found on our GitHub repo. * certbot-auto was deprecated on Debian based systems. * CLI flag `--manual-public-ip-logging-ok` is now a no-op, generates a deprecation warning, and will be removed in a future release. -* ### Fixed From ff3a07dca34350064bf9f8e9fbe93eda7482acc0 Mon Sep 17 00:00:00 2001 From: Adrien Ferrand Date: Tue, 1 Dec 2020 23:46:01 +0100 Subject: [PATCH 22/42] Deprecate certbot-auto and remove tests * Completely deprecate certbot-auto * DeaDeactivate centos6/oraclelinux6 tests * Remove tests assets * Remove another test * Revert "Remove tests assets" This reverts commit e603afe6c4683a25982351557a348d35eba2f65b. --- .../templates/jobs/extended-tests-jobs.yml | 2 - .../templates/jobs/standard-tests-jobs.yml | 4 +- letsencrypt-auto-source/Dockerfile.redhat6 | 54 -- letsencrypt-auto-source/letsencrypt-auto | 106 +--- .../letsencrypt-auto.template | 106 +--- letsencrypt-auto-source/tests/__init__.py | 7 - letsencrypt-auto-source/tests/auto_test.py | 503 ------------------ .../tests/centos6_tests.sh | 173 ------ .../tests/certs/ca/my-root-ca.crt.pem | 23 - .../tests/certs/ca/my-root-ca.key.pem | 27 - .../tests/certs/ca/my-root-ca.srl | 1 - .../tests/certs/localhost/cert.pem | 19 - .../tests/certs/localhost/localhost.csr.pem | 17 - .../tests/certs/localhost/privkey.pem | 27 - .../tests/certs/localhost/server.pem | 46 -- .../dist/letsencrypt-99.9.9.tar.gz | Bin 876 -> 0 bytes .../tests/fake-letsencrypt/letsencrypt.py | 8 - .../tests/fake-letsencrypt/setup.py | 12 - .../tests/oraclelinux6_tests.sh | 85 --- .../tests/uname_wrapper.sh | 10 - .../letstest/scripts/test_leauto_upgrades.sh | 32 +- ...st_letsencrypt_auto_certonly_standalone.sh | 58 +- tox.ini | 23 - 23 files changed, 17 insertions(+), 1326 deletions(-) delete mode 100644 letsencrypt-auto-source/Dockerfile.redhat6 delete mode 100644 letsencrypt-auto-source/tests/__init__.py delete mode 100644 letsencrypt-auto-source/tests/auto_test.py delete mode 100644 letsencrypt-auto-source/tests/centos6_tests.sh delete mode 100644 letsencrypt-auto-source/tests/certs/ca/my-root-ca.crt.pem delete mode 100644 letsencrypt-auto-source/tests/certs/ca/my-root-ca.key.pem delete mode 100644 letsencrypt-auto-source/tests/certs/ca/my-root-ca.srl delete mode 100644 letsencrypt-auto-source/tests/certs/localhost/cert.pem delete mode 100644 letsencrypt-auto-source/tests/certs/localhost/localhost.csr.pem delete mode 100644 letsencrypt-auto-source/tests/certs/localhost/privkey.pem delete mode 100644 letsencrypt-auto-source/tests/certs/localhost/server.pem delete mode 100644 letsencrypt-auto-source/tests/fake-letsencrypt/dist/letsencrypt-99.9.9.tar.gz delete mode 100755 letsencrypt-auto-source/tests/fake-letsencrypt/letsencrypt.py delete mode 100644 letsencrypt-auto-source/tests/fake-letsencrypt/setup.py delete mode 100644 letsencrypt-auto-source/tests/oraclelinux6_tests.sh delete mode 100644 letsencrypt-auto-source/tests/uname_wrapper.sh diff --git a/.azure-pipelines/templates/jobs/extended-tests-jobs.yml b/.azure-pipelines/templates/jobs/extended-tests-jobs.yml index f835078c8..0c92136e8 100644 --- a/.azure-pipelines/templates/jobs/extended-tests-jobs.yml +++ b/.azure-pipelines/templates/jobs/extended-tests-jobs.yml @@ -79,8 +79,6 @@ jobs: IMAGE_NAME: ubuntu-18.04 PYTHON_VERSION: 3.8 TOXENV: integration-dns-rfc2136 - le-auto-oraclelinux6: - TOXENV: le_auto_oraclelinux6 docker-dev: TOXENV: docker_dev macos-farmtest-apache2: diff --git a/.azure-pipelines/templates/jobs/standard-tests-jobs.yml b/.azure-pipelines/templates/jobs/standard-tests-jobs.yml index 897ab40bb..39cd628bc 100644 --- a/.azure-pipelines/templates/jobs/standard-tests-jobs.yml +++ b/.azure-pipelines/templates/jobs/standard-tests-jobs.yml @@ -58,9 +58,9 @@ jobs: apache-compat: IMAGE_NAME: ubuntu-18.04 TOXENV: apache_compat - le-auto-centos6: + le-modification: IMAGE_NAME: ubuntu-18.04 - TOXENV: le_auto_centos6 + TOXENV: modification apacheconftest: IMAGE_NAME: ubuntu-18.04 PYTHON_VERSION: 2.7 diff --git a/letsencrypt-auto-source/Dockerfile.redhat6 b/letsencrypt-auto-source/Dockerfile.redhat6 deleted file mode 100644 index 66f21bc14..000000000 --- a/letsencrypt-auto-source/Dockerfile.redhat6 +++ /dev/null @@ -1,54 +0,0 @@ -# For running tests, build a docker image with a passwordless sudo and a trust -# store we can manipulate. - -ARG REDHAT_DIST_FLAVOR -FROM ${REDHAT_DIST_FLAVOR}:6 - -ARG REDHAT_DIST_FLAVOR - -RUN curl -O https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm \ - && rpm -ivh epel-release-latest-6.noarch.rpm - -# Install pip and sudo: -RUN yum install -y python-pip sudo -# Update to a stable and tested version of pip. -# We do not use pipstrap here because it no longer supports Python 2.6. -RUN pip install pip==9.0.1 setuptools==29.0.1 wheel==0.29.0 -# Pin pytest version for increased stability -RUN pip install pytest==3.2.5 six==1.10.0 - -# Add an unprivileged user: -RUN useradd --create-home --home-dir /home/lea --shell /bin/bash --groups wheel --uid 1000 lea - -# Let that user sudo: -RUN sed -i.bkp -e \ - 's/# %wheel\(NOPASSWD: ALL\)\?/%wheel/g' \ - /etc/sudoers - -RUN mkdir -p /home/lea/certbot - -# Install fake testing CA: -COPY ./tests/certs/ca/my-root-ca.crt.pem /usr/local/share/ca-certificates/ -RUN update-ca-trust - -# Copy current letsencrypt-auto: -COPY . /home/lea/certbot/letsencrypt-auto-source - -# Tweak uname binary for tests on fake 32bits -COPY tests/uname_wrapper.sh /bin -RUN mv /bin/uname /bin/uname_orig \ - && mv /bin/uname_wrapper.sh /bin/uname \ - && chmod +x /bin/uname - -# Fetch previous letsencrypt-auto that was installing python 3.4 -RUN curl https://raw.githubusercontent.com/certbot/certbot/v0.38.0/letsencrypt-auto-source/letsencrypt-auto \ - -o /home/lea/certbot/letsencrypt-auto-source/letsencrypt-auto_py_34 \ - && chmod +x /home/lea/certbot/letsencrypt-auto-source/letsencrypt-auto_py_34 - -RUN cp /home/lea/certbot/letsencrypt-auto-source/tests/${REDHAT_DIST_FLAVOR}6_tests.sh /home/lea/certbot/letsencrypt-auto-source/tests/redhat6_tests.sh \ - && chmod +x /home/lea/certbot/letsencrypt-auto-source/tests/redhat6_tests.sh - -USER lea -WORKDIR /home/lea - -CMD ["sudo", "certbot/letsencrypt-auto-source/tests/redhat6_tests.sh"] diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 31f648721..8120e92df 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -794,110 +794,8 @@ BootstrapMageiaCommon() { } -# Set Bootstrap to the function that installs OS dependencies on this system -# and BOOTSTRAP_VERSION to the unique identifier for the current version of -# that function. If Bootstrap is set to a function that doesn't install any -# packages BOOTSTRAP_VERSION is not set. -if [ -f /etc/debian_version ]; then - DEPRECATED_OS=1 -elif [ -f /etc/mageia-release ]; then - # Mageia has both /etc/mageia-release and /etc/redhat-release - DEPRECATED_OS=1 -elif [ -f /etc/redhat-release ]; then - # Run DeterminePythonVersion to decide on the basis of available Python versions - # whether to use 2.x or 3.x on RedHat-like systems. - # Then, revert LE_PYTHON to its previous state. - prev_le_python="$LE_PYTHON" - unset LE_PYTHON - DeterminePythonVersion "NOCRASH" - - RPM_DIST_NAME=`(. /etc/os-release 2> /dev/null && echo $ID) || echo "unknown"` - - if [ "$PYVER" -eq 26 -a $(uname -m) != 'x86_64' ]; then - # 32 bits CentOS 6 and affiliates are not supported anymore by certbot-auto. - DEPRECATED_OS=1 - fi - - # Set RPM_DIST_VERSION to VERSION_ID from /etc/os-release after splitting on - # '.' characters (e.g. "8.0" becomes "8"). If the command exits with an - # error, RPM_DIST_VERSION is set to "unknown". - RPM_DIST_VERSION=$( (. /etc/os-release 2> /dev/null && echo "$VERSION_ID") | cut -d '.' -f1 || echo "unknown") - - # If RPM_DIST_VERSION is an empty string or it contains any nonnumeric - # characters, the value is unexpected so we set RPM_DIST_VERSION to 0. - if [ -z "$RPM_DIST_VERSION" ] || [ -n "$(echo "$RPM_DIST_VERSION" | tr -d '[0-9]')" ]; then - RPM_DIST_VERSION=0 - fi - - # Handle legacy RPM distributions - if [ "$PYVER" -eq 26 ]; then - # Check if an automated bootstrap can be achieved on this system. - if ! Python36SclIsAvailable; then - INTERACTIVE_BOOTSTRAP=1 - fi - - Bootstrap() { - BootstrapMessage "Legacy RedHat-based OSes that will use Python3" - BootstrapRpmPython3Legacy - } - USE_PYTHON_3=1 - BOOTSTRAP_VERSION="BootstrapRpmPython3Legacy $BOOTSTRAP_RPM_PYTHON3_LEGACY_VERSION" - - # Try now to enable SCL rh-python36 for systems already bootstrapped - # NB: EnablePython36SCL has been defined along with BootstrapRpmPython3Legacy in certbot-auto - EnablePython36SCL - else - # Starting to Fedora 29, python2 is on a deprecation path. Let's move to python3 then. - # RHEL 8 also uses python3 by default. - if [ "$RPM_DIST_NAME" = "fedora" -a "$RPM_DIST_VERSION" -ge 29 ]; then - RPM_USE_PYTHON_3=1 - elif [ "$RPM_DIST_NAME" = "rhel" -a "$RPM_DIST_VERSION" -ge 8 ]; then - RPM_USE_PYTHON_3=1 - elif [ "$RPM_DIST_NAME" = "centos" -a "$RPM_DIST_VERSION" -ge 8 ]; then - RPM_USE_PYTHON_3=1 - else - RPM_USE_PYTHON_3=0 - fi - - if [ "$RPM_USE_PYTHON_3" = 1 ]; then - Bootstrap() { - BootstrapMessage "RedHat-based OSes that will use Python3" - BootstrapRpmPython3 - } - USE_PYTHON_3=1 - BOOTSTRAP_VERSION="BootstrapRpmPython3 $BOOTSTRAP_RPM_PYTHON3_VERSION" - else - Bootstrap() { - BootstrapMessage "RedHat-based OSes" - BootstrapRpmCommon - } - BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION" - fi - fi - - LE_PYTHON="$prev_le_python" -elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then - DEPRECATED_OS=1 -elif [ -f /etc/arch-release ]; then - DEPRECATED_OS=1 -elif [ -f /etc/manjaro-release ]; then - DEPRECATED_OS=1 -elif [ -f /etc/gentoo-release ]; then - DEPRECATED_OS=1 -elif uname | grep -iq FreeBSD ; then - DEPRECATED_OS=1 -elif uname | grep -iq Darwin ; then - DEPRECATED_OS=1 -elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then - Bootstrap() { - ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon - } - BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION" -elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then - DEPRECATED_OS=1 -else - DEPRECATED_OS=1 -fi +# Certbot-auto is now fully deprecated +DEPRECATED_OS=1 # We handle this case after determining the normal bootstrap version to allow # variables like USE_PYTHON_3 to be properly set. As described above, if the diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index 5eb82b705..e4611abdf 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -316,110 +316,8 @@ DeterminePythonVersion() { {{ bootstrappers/smartos.sh }} {{ bootstrappers/mageia_common.sh }} -# Set Bootstrap to the function that installs OS dependencies on this system -# and BOOTSTRAP_VERSION to the unique identifier for the current version of -# that function. If Bootstrap is set to a function that doesn't install any -# packages BOOTSTRAP_VERSION is not set. -if [ -f /etc/debian_version ]; then - DEPRECATED_OS=1 -elif [ -f /etc/mageia-release ]; then - # Mageia has both /etc/mageia-release and /etc/redhat-release - DEPRECATED_OS=1 -elif [ -f /etc/redhat-release ]; then - # Run DeterminePythonVersion to decide on the basis of available Python versions - # whether to use 2.x or 3.x on RedHat-like systems. - # Then, revert LE_PYTHON to its previous state. - prev_le_python="$LE_PYTHON" - unset LE_PYTHON - DeterminePythonVersion "NOCRASH" - - RPM_DIST_NAME=`(. /etc/os-release 2> /dev/null && echo $ID) || echo "unknown"` - - if [ "$PYVER" -eq 26 -a $(uname -m) != 'x86_64' ]; then - # 32 bits CentOS 6 and affiliates are not supported anymore by certbot-auto. - DEPRECATED_OS=1 - fi - - # Set RPM_DIST_VERSION to VERSION_ID from /etc/os-release after splitting on - # '.' characters (e.g. "8.0" becomes "8"). If the command exits with an - # error, RPM_DIST_VERSION is set to "unknown". - RPM_DIST_VERSION=$( (. /etc/os-release 2> /dev/null && echo "$VERSION_ID") | cut -d '.' -f1 || echo "unknown") - - # If RPM_DIST_VERSION is an empty string or it contains any nonnumeric - # characters, the value is unexpected so we set RPM_DIST_VERSION to 0. - if [ -z "$RPM_DIST_VERSION" ] || [ -n "$(echo "$RPM_DIST_VERSION" | tr -d '[0-9]')" ]; then - RPM_DIST_VERSION=0 - fi - - # Handle legacy RPM distributions - if [ "$PYVER" -eq 26 ]; then - # Check if an automated bootstrap can be achieved on this system. - if ! Python36SclIsAvailable; then - INTERACTIVE_BOOTSTRAP=1 - fi - - Bootstrap() { - BootstrapMessage "Legacy RedHat-based OSes that will use Python3" - BootstrapRpmPython3Legacy - } - USE_PYTHON_3=1 - BOOTSTRAP_VERSION="BootstrapRpmPython3Legacy $BOOTSTRAP_RPM_PYTHON3_LEGACY_VERSION" - - # Try now to enable SCL rh-python36 for systems already bootstrapped - # NB: EnablePython36SCL has been defined along with BootstrapRpmPython3Legacy in certbot-auto - EnablePython36SCL - else - # Starting to Fedora 29, python2 is on a deprecation path. Let's move to python3 then. - # RHEL 8 also uses python3 by default. - if [ "$RPM_DIST_NAME" = "fedora" -a "$RPM_DIST_VERSION" -ge 29 ]; then - RPM_USE_PYTHON_3=1 - elif [ "$RPM_DIST_NAME" = "rhel" -a "$RPM_DIST_VERSION" -ge 8 ]; then - RPM_USE_PYTHON_3=1 - elif [ "$RPM_DIST_NAME" = "centos" -a "$RPM_DIST_VERSION" -ge 8 ]; then - RPM_USE_PYTHON_3=1 - else - RPM_USE_PYTHON_3=0 - fi - - if [ "$RPM_USE_PYTHON_3" = 1 ]; then - Bootstrap() { - BootstrapMessage "RedHat-based OSes that will use Python3" - BootstrapRpmPython3 - } - USE_PYTHON_3=1 - BOOTSTRAP_VERSION="BootstrapRpmPython3 $BOOTSTRAP_RPM_PYTHON3_VERSION" - else - Bootstrap() { - BootstrapMessage "RedHat-based OSes" - BootstrapRpmCommon - } - BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION" - fi - fi - - LE_PYTHON="$prev_le_python" -elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then - DEPRECATED_OS=1 -elif [ -f /etc/arch-release ]; then - DEPRECATED_OS=1 -elif [ -f /etc/manjaro-release ]; then - DEPRECATED_OS=1 -elif [ -f /etc/gentoo-release ]; then - DEPRECATED_OS=1 -elif uname | grep -iq FreeBSD ; then - DEPRECATED_OS=1 -elif uname | grep -iq Darwin ; then - DEPRECATED_OS=1 -elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then - Bootstrap() { - ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon - } - BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION" -elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then - DEPRECATED_OS=1 -else - DEPRECATED_OS=1 -fi +# Certbot-auto is now fully deprecated +DEPRECATED_OS=1 # We handle this case after determining the normal bootstrap version to allow # variables like USE_PYTHON_3 to be properly set. As described above, if the diff --git a/letsencrypt-auto-source/tests/__init__.py b/letsencrypt-auto-source/tests/__init__.py deleted file mode 100644 index 8a1613aa5..000000000 --- a/letsencrypt-auto-source/tests/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -"""Tests for letsencrypt-auto - -Run these locally by saying... :: - - ./build.py && docker build -t lea . -f Dockerfile. && docker run --rm -t -i lea - -""" diff --git a/letsencrypt-auto-source/tests/auto_test.py b/letsencrypt-auto-source/tests/auto_test.py deleted file mode 100644 index 805bb21af..000000000 --- a/letsencrypt-auto-source/tests/auto_test.py +++ /dev/null @@ -1,503 +0,0 @@ -"""Tests for letsencrypt-auto""" - -from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler -from contextlib import contextmanager -from functools import partial -from json import dumps -from os import chmod, environ, makedirs, stat -from os.path import abspath, dirname, exists, join -import re -from shutil import copy, rmtree -import socket -import ssl -from stat import S_IMODE, S_IRUSR, S_IWUSR, S_IXUSR, S_IWGRP, S_IWOTH -from subprocess import CalledProcessError, Popen, PIPE -import sys -from tempfile import mkdtemp -from threading import Thread -from unittest import TestCase - -from pytest import mark -from six.moves import xrange # pylint: disable=redefined-builtin - - -@mark.skip -def tests_dir(): - """Return a path to the "tests" directory.""" - return dirname(abspath(__file__)) - - -def copy_stable(src, dst): - """ - Copy letsencrypt-auto, and replace its current version to its equivalent stable one. - This is needed to test correctly the self-upgrade functionality. - """ - copy(src, dst) - with open(dst, 'r') as file: - filedata = file.read() - filedata = re.sub(r'LE_AUTO_VERSION="(.*)\.dev0"', r'LE_AUTO_VERSION="\1"', filedata) - with open(dst, 'w') as file: - file.write(filedata) - - -sys.path.insert(0, dirname(tests_dir())) -from build import build as build_le_auto - - -BOOTSTRAP_FILENAME = 'certbot-auto-bootstrap-version.txt' -"""Name of the file where certbot-auto saves its bootstrap version.""" - - -class RequestHandler(BaseHTTPRequestHandler): - """An HTTPS request handler which is quiet and serves a specific folder.""" - - def __init__(self, resources, *args, **kwargs): - """ - :arg resources: A dict of resource paths pointing to content bytes - - """ - self.resources = resources - BaseHTTPRequestHandler.__init__(self, *args, **kwargs) - - def log_message(self, format, *args): - """Don't log each request to the terminal.""" - - def do_GET(self): - """Serve a GET request.""" - content = self.send_head() - if content is not None: - self.wfile.write(content) - - def send_head(self): - """Common code for GET and HEAD commands - - This sends the response code and MIME headers and returns either a - bytestring of content or, if none is found, None. - - """ - path = self.path[1:] # Strip leading slash. - content = self.resources.get(path) - if content is None: - self.send_error(404, 'Path "%s" not found in self.resources' % path) - else: - self.send_response(200) - self.send_header('Content-type', 'text/plain') - self.send_header('Content-Length', str(len(content))) - self.end_headers() - return content - - -def server_and_port(resources): - """Return an unstarted HTTPS server and the port it will use.""" - # Find a port, and bind to it. I can't get the OS to close the socket - # promptly after we shut down the server, so we typically need to try - # a couple ports after the first test case. Setting - # TCPServer.allow_reuse_address = True seems to have nothing to do - # with this behavior. - worked = False - for port in xrange(4443, 4543): - try: - server = HTTPServer(('localhost', port), - partial(RequestHandler, resources)) - except socket.error: - pass - else: - worked = True - server.socket = ssl.wrap_socket( - server.socket, - certfile=join(tests_dir(), 'certs', 'localhost', 'server.pem'), - server_side=True) - break - if not worked: - raise RuntimeError("Couldn't find an unused socket for the testing HTTPS server.") - return server, port - - -@contextmanager -def serving(resources): - """Spin up a local HTTPS server, and yield its base URL. - - Use a self-signed cert generated as outlined by - https://coolaj86.com/articles/create-your-own-certificate-authority-for- - testing/. - - """ - server, port = server_and_port(resources) - thread = Thread(target=server.serve_forever) - try: - thread.start() - yield 'https://localhost:{port}/'.format(port=port) - finally: - server.shutdown() - thread.join() - - -LE_AUTO_PATH = join(dirname(tests_dir()), 'letsencrypt-auto') - - -@contextmanager -def temp_paths(): - """Creates and deletes paths for letsencrypt-auto and its venv.""" - dir = mkdtemp(prefix='le-test-') - try: - yield join(dir, 'letsencrypt-auto'), join(dir, 'venv') - finally: - rmtree(dir, ignore_errors=True) - - -def out_and_err(command, input=None, shell=False, env=None): - """Run a shell command, and return stderr and stdout as string. - - If the command returns nonzero, raise CalledProcessError. - - :arg command: A list of commandline args - :arg input: Data to pipe to stdin. Omit for none. - - Remaining args have the same meaning as for Popen. - - """ - process = Popen(command, - stdout=PIPE, - stdin=PIPE, - stderr=PIPE, - shell=shell, - env=env) - out, err = process.communicate(input=input) - status = process.poll() # same as in check_output(), though wait() sounds better - if status: - error = CalledProcessError(status, command) - error.output = out - print('stdout output was:') - print(out) - print('stderr output was:') - print(err) - raise error - return out, err - - -def signed(content, private_key_name='signing.key'): - """Return the signed SHA-256 hash of ``content``, using the given key file.""" - command = ['openssl', 'dgst', '-sha256', '-sign', - join(tests_dir(), private_key_name)] - out, err = out_and_err(command, input=content) - return out - - -def install_le_auto(contents, install_path): - """Install some given source code as the letsencrypt-auto script at the - root level of a virtualenv. - - :arg contents: The contents of the built letsencrypt-auto script - :arg install_path: The path where to install the script - - """ - with open(install_path, 'w') as le_auto: - le_auto.write(contents) - chmod(install_path, S_IRUSR | S_IXUSR) - - -def run_le_auto(le_auto_path, venv_dir, base_url=None, le_auto_args_str='--version', **kwargs): - """Run the prebuilt version of letsencrypt-auto, returning stdout and - stderr strings. - - If the command returns other than 0, raise CalledProcessError. - - """ - env = environ.copy() - d = dict(VENV_PATH=venv_dir, - NO_CERT_VERIFY='1', - **kwargs) - - if base_url is not None: - # URL to PyPI-style JSON that tell us the latest released version - # of LE: - d['LE_AUTO_JSON_URL'] = base_url + 'certbot/json' - # URL to dir containing letsencrypt-auto and letsencrypt-auto.sig: - d['LE_AUTO_DIR_TEMPLATE'] = base_url + '%s/' - # The public key corresponding to signing.key: - d['LE_AUTO_PUBLIC_KEY'] = """-----BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsMoSzLYQ7E1sdSOkwelg -tzKIh2qi3bpXuYtcfFC0XrvWig071NwIj+dZiT0OLZ2hPispEH0B7ISuuWg1ll7G -hFW0VdbxL6JdGzS2ShNWkX9hE9z+j8VqwDPOBn3ZHm03qwpYkBDwQib3KqOdYbTT -uUtJmmGcuk3a9Aq/sCT6DdfmTSdP5asdQYwIcaQreDrOosaS84DTWI3IU+UYJVgl -LsIVPBuy9IcgHidUQ96hJnoPsDCWsHwX62495QKEarauyKQrJzFes0EY95orDM47 -Z5o/NDiQB11m91yNB0MmPYY9QSbnOA9j7IaaC97AwRLuwXY+/R2ablTcxurWou68 -iQIDAQAB ------END PUBLIC KEY-----""" - - env.update(d) - - return out_and_err( - le_auto_path + ' ' + le_auto_args_str, - shell=True, - env=env) - - -def set_le_script_version(venv_dir, version): - """Tell the letsencrypt script to report a certain version. - - We actually replace the script with a dummy version that knows only how to - print its version. - - """ - letsencrypt_path = join(venv_dir, 'bin', 'letsencrypt') - with open(letsencrypt_path, 'w') as script: - script.write("#!/usr/bin/env python\n" - "from sys import stderr\n" - "stderr.write('letsencrypt %s\\n')" % version) - chmod(letsencrypt_path, S_IRUSR | S_IXUSR) - - -def sudo_chmod(path, mode): - """Runs `sudo chmod mode path`.""" - mode = oct(mode).replace('o', '') - out_and_err(['sudo', 'chmod', mode, path]) - - -class AutoTests(TestCase): - """Test the major branch points of letsencrypt-auto: - - * An le-auto upgrade is needed. - * An le-auto upgrade is not needed. - * There was an out-of-date LE script installed. - * There was a current LE script installed. - * There was no LE script installed (less important). - * Pip hash-verification passes. - * Pip has a hash mismatch. - * The OpenSSL sig matches. - * The OpenSSL sig mismatches. - - For tests which get to the end, we run merely ``letsencrypt --version``. - The functioning of the rest of the certbot script is covered by other - test suites. - - """ - NEW_LE_AUTO = build_le_auto( - version='99.9.9', - requirements='letsencrypt==99.9.9 --hash=sha256:1cc14d61ab424cdee446f51e50f1123f8482ec740587fe78626c933bba2873a0') - NEW_LE_AUTO_SIG = signed(NEW_LE_AUTO) - - def test_successes(self): - """Exercise most branches of letsencrypt-auto. - - They just happen to be the branches in which everything goes well. - - I violate my usual rule of having small, decoupled tests, because... - - 1. We shouldn't need to run a Cartesian product of the branches: the - phases run in separate shell processes, containing state leakage - pretty effectively. The only shared state is FS state, and it's - limited to a temp dir, assuming (if we dare) all functions properly. - 2. One combination of branches happens to set us up nicely for testing - the next, saving code. - - """ - with temp_paths() as (le_auto_path, venv_dir): - # This serves a PyPI page with a higher version, a GitHub-alike - # with a corresponding le-auto script, and a matching signature. - resources = {'certbot/json': dumps({'releases': {'99.9.9': None}}), - 'v99.9.9/letsencrypt-auto': self.NEW_LE_AUTO, - 'v99.9.9/letsencrypt-auto.sig': self.NEW_LE_AUTO_SIG} - with serving(resources) as base_url: - run_letsencrypt_auto = partial( - run_le_auto, - le_auto_path, - venv_dir, - base_url, - PIP_FIND_LINKS=join(tests_dir(), - 'fake-letsencrypt', - 'dist')) - - # Test when a phase-1 upgrade is needed, there's no LE binary - # installed, and pip hashes verify: - install_le_auto(build_le_auto(version='50.0.0'), le_auto_path) - out, err = run_letsencrypt_auto() - self.assertTrue(re.match(r'letsencrypt \d+\.\d+\.\d+', - err.strip().splitlines()[-1])) - # Make a few assertions to test the validity of the next tests: - self.assertTrue('Upgrading certbot-auto ' in out) - self.assertTrue('Creating virtual environment...' in out) - - # Now we have le-auto 99.9.9 and LE 99.9.9 installed. This - # conveniently sets us up to test the next 2 cases. - - # Test when neither phase-1 upgrade nor phase-2 upgrade is - # needed (probably a common case): - out, err = run_letsencrypt_auto() - self.assertFalse('Upgrading certbot-auto ' in out) - self.assertFalse('Creating virtual environment...' in out) - - def test_phase2_upgrade(self): - """Test a phase-2 upgrade without a phase-1 upgrade.""" - resources = {'certbot/json': dumps({'releases': {'99.9.9': None}}), - 'v99.9.9/letsencrypt-auto': self.NEW_LE_AUTO, - 'v99.9.9/letsencrypt-auto.sig': self.NEW_LE_AUTO_SIG} - with serving(resources) as base_url: - pip_find_links=join(tests_dir(), 'fake-letsencrypt', 'dist') - with temp_paths() as (le_auto_path, venv_dir): - install_le_auto(self.NEW_LE_AUTO, le_auto_path) - - # Create venv saving the correct bootstrap script version - out, err = run_le_auto(le_auto_path, venv_dir, base_url, - PIP_FIND_LINKS=pip_find_links) - self.assertFalse('Upgrading certbot-auto ' in out) - self.assertTrue('Creating virtual environment...' in out) - with open(join(venv_dir, BOOTSTRAP_FILENAME)) as f: - bootstrap_version = f.read() - - # Create a new venv with an old letsencrypt version - with temp_paths() as (le_auto_path, venv_dir): - venv_bin = join(venv_dir, 'bin') - makedirs(venv_bin) - set_le_script_version(venv_dir, '0.0.1') - with open(join(venv_dir, BOOTSTRAP_FILENAME), 'w') as f: - f.write(bootstrap_version) - - install_le_auto(self.NEW_LE_AUTO, le_auto_path) - out, err = run_le_auto(le_auto_path, venv_dir, base_url, - PIP_FIND_LINKS=pip_find_links) - - self.assertFalse('Upgrading certbot-auto ' in out) - self.assertTrue('Creating virtual environment...' in out) - - def test_openssl_failure(self): - """Make sure we stop if the openssl signature check fails.""" - with temp_paths() as (le_auto_path, venv_dir): - # Serve an unrelated hash signed with the good key (easier than - # making a bad key, and a mismatch is a mismatch): - resources = {'': 'certbot/', - 'certbot/json': dumps({'releases': {'99.9.9': None}}), - 'v99.9.9/letsencrypt-auto': build_le_auto(version='99.9.9'), - 'v99.9.9/letsencrypt-auto.sig': signed('something else')} - with serving(resources) as base_url: - copy_stable(LE_AUTO_PATH, le_auto_path) - try: - out, err = run_le_auto(le_auto_path, venv_dir, base_url) - except CalledProcessError as exc: - self.assertEqual(exc.returncode, 1) - self.assertTrue("Couldn't verify signature of downloaded " - "certbot-auto." in exc.output) - else: - print(out) - self.fail('Signature check on certbot-auto erroneously passed.') - - def test_pip_failure(self): - """Make sure pip stops us if there is a hash mismatch.""" - with temp_paths() as (le_auto_path, venv_dir): - resources = {'': 'certbot/', - 'certbot/json': dumps({'releases': {'99.9.9': None}})} - with serving(resources) as base_url: - # Build a le-auto script embedding a bad requirements file: - install_le_auto( - build_le_auto( - version='99.9.9', - requirements='configobj==5.0.6 --hash=sha256:badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadb'), - le_auto_path) - try: - out, err = run_le_auto(le_auto_path, venv_dir, base_url) - except CalledProcessError as exc: - self.assertEqual(exc.returncode, 1) - self.assertTrue("THESE PACKAGES DO NOT MATCH THE HASHES " - "FROM THE REQUIREMENTS FILE" in exc.output) - self.assertFalse( - exists(venv_dir), - msg="The virtualenv was left around, even though " - "installation didn't succeed. We shouldn't do " - "this, as it foils our detection of whether we " - "need to recreate the virtualenv, which hinges " - "on the presence of $VENV_BIN/letsencrypt.") - else: - self.fail("Pip didn't detect a bad hash and stop the " - "installation.") - - def test_permissions_warnings(self): - """Make sure letsencrypt-auto properly warns about permissions problems.""" - # This test assumes that only the parent of the directory containing - # letsencrypt-auto (usually /tmp) may have permissions letsencrypt-auto - # considers insecure. - with temp_paths() as (le_auto_path, venv_dir): - le_auto_path = abspath(le_auto_path) - le_auto_dir = dirname(le_auto_path) - le_auto_dir_parent = dirname(le_auto_dir) - install_le_auto(self.NEW_LE_AUTO, le_auto_path) - - run_letsencrypt_auto = partial( - run_le_auto, le_auto_path, venv_dir, - le_auto_args_str='--install-only --no-self-upgrade', - PIP_FIND_LINKS=join(tests_dir(), 'fake-letsencrypt', 'dist')) - # Run letsencrypt-auto once with current permissions to avoid - # potential problems when the script tries to write to temporary - # directories. - run_letsencrypt_auto() - - le_auto_dir_mode = stat(le_auto_dir).st_mode - le_auto_dir_parent_mode = S_IMODE(stat(le_auto_dir_parent).st_mode) - try: - # Make letsencrypt-auto happy with the current permissions - chmod(le_auto_dir, S_IRUSR | S_IXUSR) - sudo_chmod(le_auto_dir_parent, 0o755) - - self._test_permissions_warnings_about_path(le_auto_path, run_letsencrypt_auto) - self._test_permissions_warnings_about_path(le_auto_dir, run_letsencrypt_auto) - finally: - chmod(le_auto_dir, le_auto_dir_mode) - sudo_chmod(le_auto_dir_parent, le_auto_dir_parent_mode) - - def _test_permissions_warnings_about_path(self, path, run_le_auto_func): - # Test that there are no problems with the current permissions - out, _ = run_le_auto_func() - self.assertFalse('insecure permissions' in out) - - stat_result = stat(path) - original_mode = stat_result.st_mode - - # Test world permissions - chmod(path, original_mode | S_IWOTH) - out, _ = run_le_auto_func() - self.assertTrue('insecure permissions' in out) - - # Test group permissions - if stat_result.st_gid >= 1000: - chmod(path, original_mode | S_IWGRP) - out, _ = run_le_auto_func() - self.assertTrue('insecure permissions' in out) - - # Test owner permissions - if stat_result.st_uid >= 1000: - chmod(path, original_mode | S_IWUSR) - out, _ = run_le_auto_func() - self.assertTrue('insecure permissions' in out) - - # Test that permissions were properly restored - chmod(path, original_mode) - out, _ = run_le_auto_func() - self.assertFalse('insecure permissions' in out) - - def test_disabled_permissions_warnings(self): - """Make sure that letsencrypt-auto permissions warnings can be disabled.""" - with temp_paths() as (le_auto_path, venv_dir): - le_auto_path = abspath(le_auto_path) - install_le_auto(self.NEW_LE_AUTO, le_auto_path) - - le_auto_args_str='--install-only --no-self-upgrade' - pip_links=join(tests_dir(), 'fake-letsencrypt', 'dist') - out, _ = run_le_auto(le_auto_path, venv_dir, - le_auto_args_str=le_auto_args_str, - PIP_FIND_LINKS=pip_links) - self.assertTrue('insecure permissions' in out) - - # Test that warnings are disabled when the script isn't run as - # root. - out, _ = run_le_auto(le_auto_path, venv_dir, - le_auto_args_str=le_auto_args_str, - LE_AUTO_SUDO='', - PIP_FIND_LINKS=pip_links) - self.assertFalse('insecure permissions' in out) - - # Test that --no-permissions-check disables warnings. - le_auto_args_str += ' --no-permissions-check' - out, _ = run_le_auto( - le_auto_path, venv_dir, - le_auto_args_str=le_auto_args_str, - PIP_FIND_LINKS=pip_links) - self.assertFalse('insecure permissions' in out) diff --git a/letsencrypt-auto-source/tests/centos6_tests.sh b/letsencrypt-auto-source/tests/centos6_tests.sh deleted file mode 100644 index 8bdffec87..000000000 --- a/letsencrypt-auto-source/tests/centos6_tests.sh +++ /dev/null @@ -1,173 +0,0 @@ -#!/bin/bash -set -e -# Start by making sure your system is up-to-date: -yum update -y >/dev/null -yum install -y centos-release-scl >/dev/null -yum install -y python27 >/dev/null 2>/dev/null - -LE_AUTO_PY_34="certbot/letsencrypt-auto-source/letsencrypt-auto_py_34" -LE_AUTO="certbot/letsencrypt-auto-source/letsencrypt-auto" - -# Last version of certbot-auto that was bootstraping Python 3.4 for CentOS 6 users -INITIAL_CERTBOT_VERSION_PY34="certbot 0.38.0" - -# we're going to modify env variables, so do this in a subshell -( -# ensure CentOS6 32bits is not supported anymore, and so certbot is not installed -export UNAME_FAKE_32BITS=true -if ! "$LE_AUTO" 2>&1 | grep -q "Certbot cannot be installed."; then - echo "ERROR: certbot-auto installed certbot on 32-bit CentOS." - exit 1 -fi -) - -echo "PASSED: On CentOS 6 32 bits, certbot-auto refused to install certbot." - -# we're going to modify env variables, so do this in a subshell -( - . /opt/rh/python27/enable - - # ensure python 3 isn't installed - if python3 --version 2> /dev/null; then - echo "ERROR: Python3 is already installed." - exit 1 - fi - - # ensure python2.7 is available - if ! python2.7 --version 2> /dev/null; then - echo "ERROR: Python2.7 is not available." - exit 1 - fi - - # bootstrap, but don't install python 3. - "$LE_AUTO" --no-self-upgrade -n --version > /dev/null 2> /dev/null - - # ensure python 3 isn't installed - if python3 --version 2> /dev/null; then - echo "ERROR: letsencrypt-auto installed Python3 even though Python2.7 is present." - exit 1 - fi - - echo "PASSED: Did not upgrade to Python3 when Python2.7 is present." -) - -# ensure python2.7 isn't available -if python2.7 --version 2> /dev/null; then - echo "ERROR: Python2.7 is still available." - exit 1 -fi - -# Skip self upgrade due to Python 3 not being available. -if ! "$LE_AUTO" 2>&1 | grep -q "WARNING: couldn't find Python"; then - echo "ERROR: Python upgrade failure warning not printed!" - exit 1 -fi - -# bootstrap from the old letsencrypt-auto, this time installing python3.4 -"$LE_AUTO_PY_34" --no-self-upgrade -n --version >/dev/null 2>/dev/null - -# ensure python 3.4 is installed -if ! python3.4 --version >/dev/null 2>/dev/null; then - echo "ERROR: letsencrypt-auto failed to install Python3.4 using letsencrypt-auto < 0.37.0 when only Python2.6 is present." - exit 1 -fi - -echo "PASSED: Successfully upgraded to Python3.4 using letsencrypt-auto < 0.37.0 when only Python2.6 is present." - -# As "certbot-auto" (so without implicit --non-interactive flag set), check that the script -# refuses to install SCL Python 3.6 when run in a non interactive shell (simulated here -# using | tee /dev/null) if --non-interactive flag is not provided. -cp "$LE_AUTO" /tmp/certbot-auto -# NB: Readline has an issue on all Python versions for CentOS 6, making `certbot --version` -# output an unprintable ASCII character on a new line at the end. -# So we take the second last line of the output. -version=$(/tmp/certbot-auto --version 2>/dev/null | tee /dev/null | tail -2 | head -1) - -if [ "$version" != "$INITIAL_CERTBOT_VERSION_PY34" ]; then - echo "ERROR: certbot-auto upgraded certbot in a non-interactive shell with --non-interactive flag not set." - exit 1 -fi - -echo "PASSED: certbot-auto did not upgrade certbot in a non-interactive shell with --non-interactive flag not set." - -if [ -f /opt/rh/rh-python36/enable ]; then - echo "ERROR: certbot-auto installed Python3.6 in a non-interactive shell with --non-interactive flag not set." - exit 1 -fi - -echo "PASSED: certbot-auto did not install Python3.6 in a non-interactive shell with --non-interactive flag not set." - -# now bootstrap from current letsencrypt-auto, that will install python3.6 from SCL -"$LE_AUTO" --no-self-upgrade -n --version >/dev/null 2>/dev/null - -# Following test is executed in a subshell, to not leak any environment variable -( - # enable SCL rh-python36 - . /opt/rh/rh-python36/enable - - # ensure python 3.6 is installed - if ! python3.6 --version >/dev/null 2>/dev/null; then - echo "ERROR: letsencrypt-auto failed to install Python3.6 using current letsencrypt-auto when only Python2.6/Python3.4 are present." - exit 1 - fi - - echo "PASSED: Successfully upgraded to Python3.6 using current letsencrypt-auto when only Python2.6/Python3.4 are present." -) - -# Following test is executed in a subshell, to not leak any environment variable -( - export VENV_PATH=$(mktemp -d) - "$LE_AUTO" -n --no-bootstrap --no-self-upgrade --version >/dev/null 2>&1 - if [ "$($VENV_PATH/bin/python -V 2>&1 | cut -d" " -f2 | cut -d. -f1-2)" != "3.6" ]; then - echo "ERROR: Python 3.6 wasn't used with --no-bootstrap!" - exit 1 - fi -) - -# Following test is executed in a subshell, to not leak any environment variable -( - # enable SCL rh-python36 - . /opt/rh/rh-python36/enable - - # ensure everything works fine with certbot-auto bootstrap when python 3.6 is already enabled - export VENV_PATH=$(mktemp -d) - if ! "$LE_AUTO" --no-self-upgrade -n --version >/dev/null 2>/dev/null; then - echo "ERROR: Certbot-auto broke when Python 3.6 SCL is already enabled." - exit 1 - fi -) - -# we're going to modify env variables, so do this in a subshell -( - # ensure CentOS6 32bits is not supported anymore, and so certbot - # is not upgraded nor reinstalled. - export UNAME_FAKE_32BITS=true - OUTPUT=$("$LE_AUTO" --version 2>&1) - if ! echo "$OUTPUT" | grep -q "Certbot will no longer receive updates."; then - echo "ERROR: certbot-auto failed to run or upgraded pre-existing Certbot instance on 32-bit CentOS 6." - exit 1 - fi - if ! "$LE_AUTO" --install-only 2>&1 | grep -q "Certbot cannot be installed."; then - echo "ERROR: certbot-auto reinstalled Certbot on 32-bit CentOS 6." - exit 1 - fi -) - -# we're going to modify env variables, so do this in a subshell -( - # Prepare a certbot installation in the old venv path - rm -rf /opt/eff.org - VENV_PATH=~/.local/share/letsencrypt "$LE_AUTO" --install-only > /dev/null 2> /dev/null - # fake 32 bits mode - export UNAME_FAKE_32BITS=true - OUTPUT=$("$LE_AUTO" --version 2>&1) - if ! echo "$OUTPUT" | grep -q "Certbot will no longer receive updates."; then - echo "ERROR: certbot-auto failed to run or upgraded pre-existing Certbot instance in the old venv path on 32-bit CentOS 6." - exit 1 - fi -) - -echo "PASSED: certbot-auto refused to install/upgrade certbot on 32-bit CentOS 6." - -# test using python3 -pytest -v -s certbot/letsencrypt-auto-source/tests diff --git a/letsencrypt-auto-source/tests/certs/ca/my-root-ca.crt.pem b/letsencrypt-auto-source/tests/certs/ca/my-root-ca.crt.pem deleted file mode 100644 index 4e4d29bd2..000000000 --- a/letsencrypt-auto-source/tests/certs/ca/my-root-ca.crt.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID5jCCAs6gAwIBAgIJAI1Qkfyw88REMA0GCSqGSIb3DQEBBQUAMFUxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMRswGQYDVQQKExJNeSBCb2d1cyBS -b290IENlcnQxFDASBgNVBAMTC2V4YW1wbGUuY29tMB4XDTE1MTIwNDIwNTIxNVoX -DTQwMTIwMzIwNTIxNVowVTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3Rh -dGUxGzAZBgNVBAoTEk15IEJvZ3VzIFJvb3QgQ2VydDEUMBIGA1UEAxMLZXhhbXBs -ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQVQpQ2EH4gTJB -NJP6+ocT3xJwT8mSXYUnvzjj6iv+JxZiXRGzAPziNzrrSRKY0yDHF+UiJwuOerLa -n8laZkLb1Ogqzs2u64rKeb0xWv90Qp+eXG0J/1xb4dw+GExqe5QFo1JUJzO/eK7m -1S04SeFkN1qV9mD5yJUy7DGiTUzDHgCxM2tXMLusXYqkxsQQ9+2EJ7BEOK4YJGEx -Sign5FuSxb64PiNow6OA97CaLl7tV4INP4w195ueDRIaS4poeOep4s8U7IAdMjIZ -EryJgKNCij50xK92vPBBJSj0NOitltBlwoEqkOZpQCOZamFd6nvt78LQ6W8Am+l6 -y6oCON5JAgMBAAGjgbgwgbUwHQYDVR0OBBYEFAlrdStDhaayLLj89Whe3Gc+HE8y -MIGFBgNVHSMEfjB8gBQJa3UrQ4Wmsiy4/PVoXtxnPhxPMqFZpFcwVTELMAkGA1UE -BhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxGzAZBgNVBAoTEk15IEJvZ3VzIFJv -b3QgQ2VydDEUMBIGA1UEAxMLZXhhbXBsZS5jb22CCQCNUJH8sPPERDAMBgNVHRME -BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQC7KAQfDTiNM3QO8Ic3x21CAPJUavkH -zshifN+Ei0+nmseHDTCTgsGfGDOToLUpUEZ4PuiHnz08UwRfd9wotc3SgY9ZaXMe -vRs8KUAF9EoyTvESzPyv2b6cS9NNMpj5y7KyXSyP17VoGbNavtiGQ4dwgEH6VgNl -0RtBvcSBv/tqxIIx1tWzL74tVEm0Kbd9BAZsYpQNKL8e6WXP35/j0PvCCvtofGrA -E8LTqMz4kCwnX+QaJIMJhBophRCsjXdAkvFbFxX0DGPztQtzIwBPcdMjsft7AFeE -0XchhDDXxw8YsbpvPfCvrD8XiiVuBycbnB1zt0LLVwB/QsCzUW9ImpLC ------END CERTIFICATE----- diff --git a/letsencrypt-auto-source/tests/certs/ca/my-root-ca.key.pem b/letsencrypt-auto-source/tests/certs/ca/my-root-ca.key.pem deleted file mode 100644 index 9caa7ddaa..000000000 --- a/letsencrypt-auto-source/tests/certs/ca/my-root-ca.key.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEA0FUKUNhB+IEyQTST+vqHE98ScE/Jkl2FJ7844+or/icWYl0R -swD84jc660kSmNMgxxflIicLjnqy2p/JWmZC29ToKs7NruuKynm9MVr/dEKfnlxt -Cf9cW+HcPhhManuUBaNSVCczv3iu5tUtOEnhZDdalfZg+ciVMuwxok1Mwx4AsTNr -VzC7rF2KpMbEEPfthCewRDiuGCRhMUooJ+RbksW+uD4jaMOjgPewmi5e7VeCDT+M -Nfebng0SGkuKaHjnqeLPFOyAHTIyGRK8iYCjQoo+dMSvdrzwQSUo9DTorZbQZcKB -KpDmaUAjmWphXep77e/C0OlvAJvpesuqAjjeSQIDAQABAoIBAH+qbVzneV3wxjwh -HUHi/p3VyHXc3xh7iNq3mwRH/1eK2nPCttLsGwwBbnC64dOXJfH7maWZKcLRPAMv -gfOM0RHn4bJB8tdrbizv91lke0DihvBDkWpb+1wvB4lh2Io0Wpwt3ojFUTfXm87G -+iQRWjbQmQlm5zyKh6uiBDSCjDTQdb9omZEBMAwlGPTZwt8TRUEtWd8QgW8FCHoB -iLER2WBwXdvn3PBtocI3VE6IYDSeZ81Xv+d7925RtVintT8Suk4toYwX+jfSz+wZ -sgHd5V6PSv9a7GUlWoUihD99D9wqDZE8IvMDZ5ofSAUd1KfICDtmsEyugY7u2yYZ -tYt49AECgYEA73f7ITMHg8JsUipqb6eG10gCRtRhkqrrO1g/TNeTBh3CTrQGb56e -y6kmUivn5gK46t3T2N4Ht4IR8fpLcJcbPYPQNulSjmWm5y6WduafXW/VCW1NA9Lc -FyGPkMxFCIVJTLFxfLFepBVvtUzLLDKGGtQxru/GNbBzjdtmVfDPIoECgYEA3rbM -cTfvj+jWrV1YsRbphyjy+k3OJEIVx6KA4s5d7Tp12UfYQp/B3HPhXXm5wqeo1Nos -UAEWZIMi1VoE8iu6jjeJ6uERtbKKQVed25Us/ff0jUPbxlXgiBOtRcllq9d9Srjm -ybHUgfjLsZ2/xpIcOl+oI5pDM9JvD8Sq4ZCFR8kCgYBK/H0tFjeiML2OtS2DLShy -PWBJIbQ0I0Vp3eZkf5TQc30m/ASP61G6YItZa9pAElYpZbEy1cQA2MAZz9DTvt2O -07ndmA57/KTY+6OuM+Vvctd5DjrxmZPFwoKcSvrLAkHDvETXUQtbwkKquRNeEawg -tpWgPAELSufEYhGXk8KpAQKBgBDCqPgMQZcO6rj5QWdyVfi5+C8mE9Fet8ziSdjH -twHXWG8VnQzGgQxaHCewtW4Ut/vsv1D2A/1kcQalU6H18IArZdGrRm3qFcV9FoAj -5dLnChxncu6mH9Odx3htA52/BcrNx3B+VYPCeXHQcVI8RKuP71NelJgdygXhwwpe -mekhAoGBAOUovnqylciYa9HRqo+xZk59eyX+ehhnlV8SeJ2K0PwaQkzQ0KYtCmE7 -kdSdhcv8h/IQKGaFfc/LyFMM/a26PfAeY5bj41UjkT0K5hQrYuL/52xaT401YLcb -Xo+bZz9K0hrdP7TdZFuTY/WxojXgjsVAuAN1NwnJumqxhzPh+hfl ------END RSA PRIVATE KEY----- diff --git a/letsencrypt-auto-source/tests/certs/ca/my-root-ca.srl b/letsencrypt-auto-source/tests/certs/ca/my-root-ca.srl deleted file mode 100644 index ad6d262b4..000000000 --- a/letsencrypt-auto-source/tests/certs/ca/my-root-ca.srl +++ /dev/null @@ -1 +0,0 @@ -D613482D0EF95DD0 diff --git a/letsencrypt-auto-source/tests/certs/localhost/cert.pem b/letsencrypt-auto-source/tests/certs/localhost/cert.pem deleted file mode 100644 index ac83535ce..000000000 --- a/letsencrypt-auto-source/tests/certs/localhost/cert.pem +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDKjCCAhICCQDWE0gtDvld0DANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJB -VTETMBEGA1UECBMKU29tZS1TdGF0ZTEbMBkGA1UEChMSTXkgQm9ndXMgUm9vdCBD -ZXJ0MRQwEgYDVQQDEwtleGFtcGxlLmNvbTAeFw0xNTEyMDQyMDU0MzFaFw00MDEy -MDMyMDU0MzFaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEw -HwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMTCWxvY2Fs -aG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK2WIIi86Mis4UQH -a5PrFbX2PBtQHbI3t3ekN1CewRsgQ/2X3lCeWhKmr3CJYXVgA7q/23PORQAiuV6y -DG2dQIrjeahWCXaCptTi49ljfVRTW2IxrHke/iA8TkDuZbWGzVLb8TB83ipBOD41 -SjuomoN4A/ktnIfbNqRqgjjHs2wwJHDfxPiCQlwyOayjHmdlh8cqfVE8rWEm5/3T -Iu0X1J53SammR1SbUmsLJNofxFYMK1ogHb0CaFEG9QuuUDPJl5K74Rr6InMQZKPn -ne4W3cGoALxPHAca7yicpSMSmdsmd6pqylc2Fdua7o/wf0SwShxS4A1DqA/HWLEM -V6MSEF8CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAz5sMAFG6W/ZEULZITkBTCU6P -NttpGiKufnqyBW5HyNylaczfnHnClvQjr8f/84xvKVcfC3xP0lz+92aIQqo+5L/n -v7gLhBFR4Vr2XwMt2qz2FpkaxmVwnhVAHaaC05WIKQ6W2gDwWT0u1K8YdTh+7mvN -AT9FW4vDgtNZWq4W/PePh9QCiOOQhGOuBYj/7zqLtz4XPifhi66ILIRDHiu0kond -3YMFcECIAf4MPT9vT0iNcWX+c8CfAixPt8nMD6bzOo3oTcfuZh/2enfgLbMqOlOi -uk72FM5VVPXTWAckJvL/vVjqsvDuJQKqbr0oUc3bdWbS36xtWZUycp4IQLguAQ== ------END CERTIFICATE----- diff --git a/letsencrypt-auto-source/tests/certs/localhost/localhost.csr.pem b/letsencrypt-auto-source/tests/certs/localhost/localhost.csr.pem deleted file mode 100644 index 8a6189f88..000000000 --- a/letsencrypt-auto-source/tests/certs/localhost/localhost.csr.pem +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIICnjCCAYYCAQAwWTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUx -ITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAxMJbG9j -YWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArZYgiLzoyKzh -RAdrk+sVtfY8G1Adsje3d6Q3UJ7BGyBD/ZfeUJ5aEqavcIlhdWADur/bc85FACK5 -XrIMbZ1AiuN5qFYJdoKm1OLj2WN9VFNbYjGseR7+IDxOQO5ltYbNUtvxMHzeKkE4 -PjVKO6iag3gD+S2ch9s2pGqCOMezbDAkcN/E+IJCXDI5rKMeZ2WHxyp9UTytYSbn -/dMi7RfUnndJqaZHVJtSawsk2h/EVgwrWiAdvQJoUQb1C65QM8mXkrvhGvoicxBk -o+ed7hbdwagAvE8cBxrvKJylIxKZ2yZ3qmrKVzYV25ruj/B/RLBKHFLgDUOoD8dY -sQxXoxIQXwIDAQABoAAwDQYJKoZIhvcNAQEFBQADggEBAFbg3WrAokoPx7iAYG6z -PqeDd4/XanXjeL4Ryxv6LoGhu69mmBAd3N5ILPyQJjnkWpIjEmJDzEcPMzhQjRh5 -GlWTyvKWO4zClYU840KZk7crVkpzNZ+HP0YeM/Agz6sab00ffRcq5m1wEF9MCvDE -8FUXk1HBHRAb/6t9QV/7axsPOkGT8SjQ1v2SCaiB0HQL3sYChYLi5zu4dfmQNPGq -ar9Xm5a0YqOQIFfmy8RSwxk0Q/ipNFTGN1uvlIRkgbT9zPnodxjWZsSI9BF+q5Af -uiE/oAk7MxfJ0LyLfhOWB+T98bKIOVtFT3wMLS1IIgMogwqCEXFf30Q9p2iTEzqT -6UE= ------END CERTIFICATE REQUEST----- diff --git a/letsencrypt-auto-source/tests/certs/localhost/privkey.pem b/letsencrypt-auto-source/tests/certs/localhost/privkey.pem deleted file mode 100644 index 18feba403..000000000 --- a/letsencrypt-auto-source/tests/certs/localhost/privkey.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEArZYgiLzoyKzhRAdrk+sVtfY8G1Adsje3d6Q3UJ7BGyBD/Zfe -UJ5aEqavcIlhdWADur/bc85FACK5XrIMbZ1AiuN5qFYJdoKm1OLj2WN9VFNbYjGs -eR7+IDxOQO5ltYbNUtvxMHzeKkE4PjVKO6iag3gD+S2ch9s2pGqCOMezbDAkcN/E -+IJCXDI5rKMeZ2WHxyp9UTytYSbn/dMi7RfUnndJqaZHVJtSawsk2h/EVgwrWiAd -vQJoUQb1C65QM8mXkrvhGvoicxBko+ed7hbdwagAvE8cBxrvKJylIxKZ2yZ3qmrK -VzYV25ruj/B/RLBKHFLgDUOoD8dYsQxXoxIQXwIDAQABAoIBAG8bVJ+xKt6nqVg9 -16HKKw9ZGIfy888K0qgFuFImCzwtntdGycmYUdb2Uf0aMgNK/ZgfDXxGXuwDTdtK -46GVsaY0i74vs8bjQZ2pzGVsxN+gqzFi0h6Es+w2LXBqJzfVnL6YgPykMB+jtzg6 -K9Wbyaq0uvZXN4XNzl/WvJtTV4i7Cff1MOd5EhKFdqxrZvB/SRBCr/SMMafRtB9P -EvMneNKzhmlrutHAxuyxEKZR32Kkx7ydAdTjGgn+rE+NL5BweXfeWhLU4Bv14bn9 -Mkneu3w5o1ryJfE2YnVajUP//jeopUT0nTQ3MpEusBQCLBlvFXjjM9uCaFX+5+MP -0H4xVcECgYEA1Q+wR3GHbk37vIGSlbENyUsri5WlMt8IVAHsDsTOpxAjYB0yyo+x -h9RS+RJZQECJlA6H72peUl3GM7RgdWIcKOT3nZ12XqYKG57rr/N5zlUuxbdS8KBk -JhyZeJdYjq/Jrno1ZP+OSmc7VvBLcM7irY7LHlvK0o8W1W0TNJ8jrZkCgYEA0JHX -lJd+fiezcUS7g4moHtzJp0JKquQiXLX+c2urmpyhb3ZrTuQ8OUjSy6DlwHlgDx8K -Hg2sdx/ZCuDaGjR4IY/Qs5RFt9WUqlK9gi9V3nYVrzBOQkdFOf/Ad3j4pQ8/aeCX -nP6snHXz1WqPpbCXG6l6GzFGbQU473GfuKsDuLcCgYAWQaNKc0OQdDj9whNL68ji -5CVSWXl+TOoTzHeaO1jS/s6TNbmei1AiPj3EovQL0DIO802j5tqfhAg2UntZB7yl -UPXE0zQQQwv/QqSgJrDsqt1N7g6N8FNF3+rwO+8WSKqqvT1ipYd5ojsCo+tdh18K -fkYdj70qLaRW+yPsdUtG0QKBgEYc8NqbvsML94+ZKmwCh4iwcf2PFGi0PjTqXTpR -tKNKCh7dMR+ZLAGZ0HrxgKqeYsNSjOUjdZmqFB1LDyaGAuhNXzwvGOy+mLZVEC3G -Wdhp28pDs9sl+EiSCBJhkTxzjr656F23YzFJmYlhxB5P6cw7wbeIbgNSIRylFqtO -mfarAoGBAICsAEWypOctxtmtOcjxgJ7jMbOA7rrsGlXpiy1/WlwIwRGF5LMvIIFX -qFAfiPcZn05ZgdAGzaFYowdjmQB10FW0jZbDf+nIHfOF5YmfmfWjsaweEGALJmqB -okGu/lGNGf3XoYzy0/hC3WAqk3znSZtQLUq8jEWF7dLNUizUeUow ------END RSA PRIVATE KEY----- diff --git a/letsencrypt-auto-source/tests/certs/localhost/server.pem b/letsencrypt-auto-source/tests/certs/localhost/server.pem deleted file mode 100644 index c5765dd89..000000000 --- a/letsencrypt-auto-source/tests/certs/localhost/server.pem +++ /dev/null @@ -1,46 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEArZYgiLzoyKzhRAdrk+sVtfY8G1Adsje3d6Q3UJ7BGyBD/Zfe -UJ5aEqavcIlhdWADur/bc85FACK5XrIMbZ1AiuN5qFYJdoKm1OLj2WN9VFNbYjGs -eR7+IDxOQO5ltYbNUtvxMHzeKkE4PjVKO6iag3gD+S2ch9s2pGqCOMezbDAkcN/E -+IJCXDI5rKMeZ2WHxyp9UTytYSbn/dMi7RfUnndJqaZHVJtSawsk2h/EVgwrWiAd -vQJoUQb1C65QM8mXkrvhGvoicxBko+ed7hbdwagAvE8cBxrvKJylIxKZ2yZ3qmrK -VzYV25ruj/B/RLBKHFLgDUOoD8dYsQxXoxIQXwIDAQABAoIBAG8bVJ+xKt6nqVg9 -16HKKw9ZGIfy888K0qgFuFImCzwtntdGycmYUdb2Uf0aMgNK/ZgfDXxGXuwDTdtK -46GVsaY0i74vs8bjQZ2pzGVsxN+gqzFi0h6Es+w2LXBqJzfVnL6YgPykMB+jtzg6 -K9Wbyaq0uvZXN4XNzl/WvJtTV4i7Cff1MOd5EhKFdqxrZvB/SRBCr/SMMafRtB9P -EvMneNKzhmlrutHAxuyxEKZR32Kkx7ydAdTjGgn+rE+NL5BweXfeWhLU4Bv14bn9 -Mkneu3w5o1ryJfE2YnVajUP//jeopUT0nTQ3MpEusBQCLBlvFXjjM9uCaFX+5+MP -0H4xVcECgYEA1Q+wR3GHbk37vIGSlbENyUsri5WlMt8IVAHsDsTOpxAjYB0yyo+x -h9RS+RJZQECJlA6H72peUl3GM7RgdWIcKOT3nZ12XqYKG57rr/N5zlUuxbdS8KBk -JhyZeJdYjq/Jrno1ZP+OSmc7VvBLcM7irY7LHlvK0o8W1W0TNJ8jrZkCgYEA0JHX -lJd+fiezcUS7g4moHtzJp0JKquQiXLX+c2urmpyhb3ZrTuQ8OUjSy6DlwHlgDx8K -Hg2sdx/ZCuDaGjR4IY/Qs5RFt9WUqlK9gi9V3nYVrzBOQkdFOf/Ad3j4pQ8/aeCX -nP6snHXz1WqPpbCXG6l6GzFGbQU473GfuKsDuLcCgYAWQaNKc0OQdDj9whNL68ji -5CVSWXl+TOoTzHeaO1jS/s6TNbmei1AiPj3EovQL0DIO802j5tqfhAg2UntZB7yl -UPXE0zQQQwv/QqSgJrDsqt1N7g6N8FNF3+rwO+8WSKqqvT1ipYd5ojsCo+tdh18K -fkYdj70qLaRW+yPsdUtG0QKBgEYc8NqbvsML94+ZKmwCh4iwcf2PFGi0PjTqXTpR -tKNKCh7dMR+ZLAGZ0HrxgKqeYsNSjOUjdZmqFB1LDyaGAuhNXzwvGOy+mLZVEC3G -Wdhp28pDs9sl+EiSCBJhkTxzjr656F23YzFJmYlhxB5P6cw7wbeIbgNSIRylFqtO -mfarAoGBAICsAEWypOctxtmtOcjxgJ7jMbOA7rrsGlXpiy1/WlwIwRGF5LMvIIFX -qFAfiPcZn05ZgdAGzaFYowdjmQB10FW0jZbDf+nIHfOF5YmfmfWjsaweEGALJmqB -okGu/lGNGf3XoYzy0/hC3WAqk3znSZtQLUq8jEWF7dLNUizUeUow ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIIDKjCCAhICCQDWE0gtDvld0DANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJB -VTETMBEGA1UECBMKU29tZS1TdGF0ZTEbMBkGA1UEChMSTXkgQm9ndXMgUm9vdCBD -ZXJ0MRQwEgYDVQQDEwtleGFtcGxlLmNvbTAeFw0xNTEyMDQyMDU0MzFaFw00MDEy -MDMyMDU0MzFaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEw -HwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMTCWxvY2Fs -aG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK2WIIi86Mis4UQH -a5PrFbX2PBtQHbI3t3ekN1CewRsgQ/2X3lCeWhKmr3CJYXVgA7q/23PORQAiuV6y -DG2dQIrjeahWCXaCptTi49ljfVRTW2IxrHke/iA8TkDuZbWGzVLb8TB83ipBOD41 -SjuomoN4A/ktnIfbNqRqgjjHs2wwJHDfxPiCQlwyOayjHmdlh8cqfVE8rWEm5/3T -Iu0X1J53SammR1SbUmsLJNofxFYMK1ogHb0CaFEG9QuuUDPJl5K74Rr6InMQZKPn -ne4W3cGoALxPHAca7yicpSMSmdsmd6pqylc2Fdua7o/wf0SwShxS4A1DqA/HWLEM -V6MSEF8CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAz5sMAFG6W/ZEULZITkBTCU6P -NttpGiKufnqyBW5HyNylaczfnHnClvQjr8f/84xvKVcfC3xP0lz+92aIQqo+5L/n -v7gLhBFR4Vr2XwMt2qz2FpkaxmVwnhVAHaaC05WIKQ6W2gDwWT0u1K8YdTh+7mvN -AT9FW4vDgtNZWq4W/PePh9QCiOOQhGOuBYj/7zqLtz4XPifhi66ILIRDHiu0kond -3YMFcECIAf4MPT9vT0iNcWX+c8CfAixPt8nMD6bzOo3oTcfuZh/2enfgLbMqOlOi -uk72FM5VVPXTWAckJvL/vVjqsvDuJQKqbr0oUc3bdWbS36xtWZUycp4IQLguAQ== ------END CERTIFICATE----- diff --git a/letsencrypt-auto-source/tests/fake-letsencrypt/dist/letsencrypt-99.9.9.tar.gz b/letsencrypt-auto-source/tests/fake-letsencrypt/dist/letsencrypt-99.9.9.tar.gz deleted file mode 100644 index 5f9a48a34a22ca70c28ac318336ba986ea32b60e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 876 zcmV-y1C#t8iwFqixs_G||72-%bT4dWbaQ2HV{&NJ*NTsMH6vyVzPZ#P-0dC^Sy-NbJaQ%c^PreNIB#Gy@8>WScl&h0@r$ z7>>V_6B84e5jGODRO*L^ZS^^5Z5u=3IZnPcJ;$hS=d{d@Yde-@d$u~xwA_x-!cMCJ zCYcNb#;uFw`rhN#_0NBi`Sw2{{xklSrgl1OApTazTE^eVBxu26o1K6KPFQWx8)DH<@|4$_G1AL9S%;Oz6OH>Xc{ z`mgujGVA`Ej@p3#&BkB7@}v2?Ke}}ioE*Q?KlI-Y(7Gvt9{dcs{mAP3+}%fQQj-FY z^S>UEt=9i;r~dpmU0DBVg!9@G$q?PYK7ycNc#;0kQ~y)ff9`$$J5J4i!^_uy!2jpx z6Olm}$Uy&6F1U8F*)~u=NJzKpK3a5_lLVbkk|YqbE`IvjE_%-sqNl-F-Ri7=+#h`H zqoawu6P0@6W$Q;eA}p(%_IkP6ylgy)0~v9VEL%YLhxosV>f7<(w7vZQ|KLCP z5B@jqfB6nLipEX(Z+KSCf5)~>@V}AzUsZU1Uf~Uq495P&gvOyN`->fw7l`_96g%0J z`GQPoVR_yNHUR(t0000000000000000000000000000000002|4SoYxfON0`PyhhZ CB*3r$ diff --git a/letsencrypt-auto-source/tests/fake-letsencrypt/letsencrypt.py b/letsencrypt-auto-source/tests/fake-letsencrypt/letsencrypt.py deleted file mode 100755 index 9d811fab5..000000000 --- a/letsencrypt-auto-source/tests/fake-letsencrypt/letsencrypt.py +++ /dev/null @@ -1,8 +0,0 @@ -from sys import argv, stderr - - -def main(): - """Act like letsencrypt --version insofar as printing the version number to - stderr.""" - if '--version' in argv: - stderr.write('letsencrypt 99.9.9\n') diff --git a/letsencrypt-auto-source/tests/fake-letsencrypt/setup.py b/letsencrypt-auto-source/tests/fake-letsencrypt/setup.py deleted file mode 100644 index e5f7fde35..000000000 --- a/letsencrypt-auto-source/tests/fake-letsencrypt/setup.py +++ /dev/null @@ -1,12 +0,0 @@ -from setuptools import setup - - -setup( - name='letsencrypt', - version='99.9.9', - description='A mock version of letsencrypt that just prints its version', - py_modules=['letsencrypt'], - entry_points={ - 'console_scripts': ['letsencrypt = letsencrypt:main'] - } -) diff --git a/letsencrypt-auto-source/tests/oraclelinux6_tests.sh b/letsencrypt-auto-source/tests/oraclelinux6_tests.sh deleted file mode 100644 index f3fd952f3..000000000 --- a/letsencrypt-auto-source/tests/oraclelinux6_tests.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/bash -set -eo pipefail -# Start by making sure your system is up-to-date: -yum update -y >/dev/null - -LE_AUTO_PY_34="certbot/letsencrypt-auto-source/letsencrypt-auto_py_34" -LE_AUTO="certbot/letsencrypt-auto-source/letsencrypt-auto" - -# Apply installation instructions from official documentation: -# https://certbot.eff.org/lets-encrypt/centosrhel6-other -cp "$LE_AUTO" /usr/local/bin/certbot-auto -chown root /usr/local/bin/certbot-auto -chmod 0755 /usr/local/bin/certbot-auto -LE_AUTO=/usr/local/bin/certbot-auto - -# Last version of certbot-auto that was bootstraping Python 3.4 for CentOS 6 users -INITIAL_CERTBOT_VERSION_PY34="certbot 0.38.0" - -# Check bootstrap from current certbot-auto will fail, because SCL is not enabled. -set +o pipefail -if ! "$LE_AUTO" -n 2>&1 | grep -q "Enable the SCL repository and try running Certbot again."; then - echo "ERROR: Bootstrap was not aborted although SCL was not installed!" - exit 1 -fi -set -o pipefail - -echo "PASSED: Bootstrap was aborted since SCL was not installed." - -# Bootstrap from the old letsencrypt-auto, Python 3.4 will be installed from EPEL. -"$LE_AUTO_PY_34" --no-self-upgrade -n --install-only >/dev/null 2>/dev/null - -# Ensure Python 3.4 is installed -if ! command -v python3.4 &>/dev/null; then - echo "ERROR: old letsencrypt-auto failed to install Python3.4 using letsencrypt-auto < 0.37.0 when only Python2.6 is present." - exit 1 -fi - -echo "PASSED: Bootstrap from old letsencrypt-auto succeeded and installed Python 3.4" - -# Expect certbot-auto to skip rebootstrapping with a warning since SCL is not installed. -if ! "$LE_AUTO" --non-interactive --version 2>&1 | grep -q "This requires manual user intervention"; then - echo "FAILED: Script certbot-auto did not print a warning about needing manual intervention!" - exit 1 -fi - -echo "PASSED: Script certbot-auto did not rebootstrap." - -# NB: Readline has an issue on all Python versions for OL 6, making `certbot --version` -# output an unprintable ASCII character on a new line at the end. -# So we take the second last line of the output. -version=$($LE_AUTO --version 2>/dev/null | tail -2 | head -1) - -if [ "$version" != "$INITIAL_CERTBOT_VERSION_PY34" ]; then - echo "ERROR: Script certbot-auto upgraded certbot in a non-interactive shell while SCL was not enabled." - exit 1 -fi - -echo "PASSED: Script certbot-auto did not upgrade certbot but started it successfully while SCL was not enabled." - -# Enable SCL -yum install -y oracle-softwarecollection-release-el6 >/dev/null - -# Expect certbot-auto to bootstrap successfully since SCL is available. -"$LE_AUTO" -n --version &>/dev/null - -if [ "$(/opt/eff.org/certbot/venv/bin/python -V 2>&1 | cut -d" " -f2 | cut -d. -f1-2)" != "3.6" ]; then - echo "ERROR: Script certbot-auto failed to bootstrap and install Python 3.6 while SCL is available." - exit 1 -fi - -if ! /opt/eff.org/certbot/venv/bin/certbot --version > /dev/null 2> /dev/null; then - echo "ERROR: Script certbot-auto did not install certbot correctly while SCL is enabled." - exit 1 -fi - -echo "PASSED: Script certbot-auto correctly bootstraped Certbot using rh-python36 when SCL is available." - -# Expect certbot-auto will be totally silent now that everything has been correctly boostraped. -OUTPUT_LEN=$("$LE_AUTO" --install-only --no-self-upgrade --quiet 2>&1 | wc -c) -if [ "$OUTPUT_LEN" != 0 ]; then - echo certbot-auto produced unexpected output! - exit 1 -fi - -echo "PASSED: Script certbot-auto did not print anything in quiet mode." diff --git a/letsencrypt-auto-source/tests/uname_wrapper.sh b/letsencrypt-auto-source/tests/uname_wrapper.sh deleted file mode 100644 index df1f568c6..000000000 --- a/letsencrypt-auto-source/tests/uname_wrapper.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -set -e - -uname_output=$(/bin/uname_orig "$@") - -if [ "$UNAME_FAKE_32BITS" = true ]; then - uname_output="${uname_output//x86_64/i686}" -fi - -echo "$uname_output" diff --git a/tests/letstest/scripts/test_leauto_upgrades.sh b/tests/letstest/scripts/test_leauto_upgrades.sh index 51ff640c5..1eeafad21 100755 --- a/tests/letstest/scripts/test_leauto_upgrades.sh +++ b/tests/letstest/scripts/test_leauto_upgrades.sh @@ -105,15 +105,10 @@ if ./letsencrypt-auto -v --debug --version | grep "WARNING: couldn't find Python exit 1 fi -# On systems like Debian where certbot-auto is deprecated, we expect it to -# leave existing Certbot installations unmodified so we check for the same -# version that was initially installed below. Once certbot-auto is deprecated -# on RHEL systems, we can unconditionally check for INITIAL_VERSION. -if [ -f /etc/debian_version ]; then - EXPECTED_VERSION="$INITIAL_VERSION" -else - EXPECTED_VERSION=$(grep -m1 LE_AUTO_VERSION certbot-auto | cut -d\" -f2) -fi +# Since certbot-auto is deprecated, we expect it to leave existing Certbot +# installations unmodified so we check for the same version that was initially +# installed below. +EXPECTED_VERSION="$INITIAL_VERSION" if ! /opt/eff.org/certbot/venv/bin/letsencrypt --version 2>&1 | tail -n1 | grep "^certbot $EXPECTED_VERSION$" ; then echo unexpected certbot version found @@ -124,22 +119,3 @@ if ! diff letsencrypt-auto letsencrypt-auto-source/letsencrypt-auto ; then echo letsencrypt-auto and letsencrypt-auto-source/letsencrypt-auto differ exit 1 fi - -if [ "$RUN_RHEL6_TESTS" = 1 ]; then - # Add the SCL python release to PATH in order to resolve python3 command - PATH="/opt/rh/rh-python36/root/usr/bin:$PATH" - if ! command -v python3; then - echo "Python3 wasn't properly installed" - exit 1 - fi - if [ "$(/opt/eff.org/certbot/venv/bin/python -V 2>&1 | cut -d" " -f 2 | cut -d. -f1)" != 3 ]; then - echo "Python3 wasn't used in venv!" - exit 1 - fi - - if [ "$("$PYTHON_NAME" tools/readlink.py $OLD_VENV_PATH)" != "/opt/eff.org/certbot/venv" ]; then - echo symlink from old venv path not properly created! - exit 1 - fi -fi -echo upgrade appeared to be successful diff --git a/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh b/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh index 15cf9ee1b..fc5435916 100755 --- a/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh +++ b/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh @@ -16,58 +16,14 @@ sudo chown root "$LE_AUTO_PATH" sudo chmod 0755 "$LE_AUTO_PATH" export PATH="$LE_AUTO_DIR:$PATH" -# On systems like Debian where certbot-auto is deprecated, we expect -# certbot-auto to error and refuse to install Certbot. Once certbot-auto is -# deprecated on RHEL systems, we can unconditionally run this code. -if [ -f /etc/debian_version ]; then - set +o pipefail - if ! letsencrypt-auto --debug --version | grep "Certbot cannot be installed."; then - echo "letsencrypt-auto didn't report being uninstallable." - exit 1 - fi - if [ ${PIPESTATUS[0]} != 1 ]; then - echo "letsencrypt-auto didn't exit with status 1 as expected" - exit 1 - fi - # letsencrypt-auto is deprecated and cannot be installed on this system so - # we cannot run the rest of this test. - exit 0 -fi - -letsencrypt-auto --os-packages-only --debug --version - -# This script sets the environment variables PYTHON_NAME, VENV_PATH, and -# VENV_SCRIPT based on the version of Python available on the system. For -# instance, Fedora uses Python 3 and Python 2 is not installed. -. tests/letstest/scripts/set_python_envvars.sh - -# Create a venv-like layout at the old virtual environment path to test that a -# symlink is properly created when letsencrypt-auto runs. -HOME=${HOME:-~root} -XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} -OLD_VENV_BIN="$XDG_DATA_HOME/letsencrypt/bin" -mkdir -p "$OLD_VENV_BIN" -touch "$OLD_VENV_BIN/letsencrypt" - -letsencrypt-auto certonly --no-self-upgrade -v --standalone --debug \ - --text --agree-tos \ - --renew-by-default --redirect \ - --register-unsafely-without-email \ - --domain $PUBLIC_HOSTNAME --server $BOULDER_URL - -LINK_PATH=$("$PYTHON_NAME" tools/readlink.py ${XDG_DATA_HOME:-~/.local/share}/letsencrypt) -if [ "$LINK_PATH" != "/opt/eff.org/certbot/venv" ]; then - echo symlink from old venv path not properly created! +# Since certbot-auto is deprecated, we expect certbot-auto to error and +# refuse to install Certbot. +set +o pipefail +if ! letsencrypt-auto --debug --version | grep "Certbot cannot be installed."; then + echo "letsencrypt-auto didn't report being uninstallable." exit 1 fi - -if ! letsencrypt-auto --help --no-self-upgrade | grep -F "letsencrypt-auto [SUBCOMMAND]"; then - echo "letsencrypt-auto not included in help output!" - exit 1 -fi - -OUTPUT_LEN=$(letsencrypt-auto --install-only --no-self-upgrade --quiet 2>&1 | wc -c) -if [ "$OUTPUT_LEN" != 0 ]; then - echo letsencrypt-auto produced unexpected output! +if [ ${PIPESTATUS[0]} != 1 ]; then + echo "letsencrypt-auto didn't exit with status 1 as expected" exit 1 fi diff --git a/tox.ini b/tox.ini index 7f806bb4d..f87c1dbca 100644 --- a/tox.ini +++ b/tox.ini @@ -188,29 +188,6 @@ whitelist_externals = passenv = DOCKER_* -[testenv:le_auto_centos6] -# At the moment, this tests under Python 2.6 only, as only that version is -# readily available on the CentOS 6 Docker image. -commands = - python {toxinidir}/tests/modification-check.py - docker build -f letsencrypt-auto-source/Dockerfile.redhat6 --build-arg REDHAT_DIST_FLAVOR=centos -t lea letsencrypt-auto-source - docker run --rm -t lea -whitelist_externals = - docker -passenv = - DOCKER_* - TARGET_BRANCH - -[testenv:le_auto_oraclelinux6] -# At the moment, this tests under Python 2.6 only, as only that version is -# readily available on the Oracle Linux 6 Docker image. -commands = - docker build -f letsencrypt-auto-source/Dockerfile.redhat6 --build-arg REDHAT_DIST_FLAVOR=oraclelinux -t lea letsencrypt-auto-source - docker run --rm -t lea -whitelist_externals = - docker -passenv = DOCKER_* - [testenv:docker_dev] # tests the Dockerfile-dev file to ensure development with it works # as expected From e5113d5815a1118d0720e29424cb98ea06957b4d Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 2 Dec 2020 09:44:27 -0800 Subject: [PATCH 23/42] Undo certbot-auto changes and remove centos6 tests * Don't deprecate certbot-auto quite yet * Remove centos6 test farm tests * undo changes to test farm test scripts --- letsencrypt-auto-source/letsencrypt-auto | 106 +++++++++++++++++- .../letsencrypt-auto.template | 106 +++++++++++++++++- tests/letstest/auto_targets.yaml | 11 -- .../letstest/scripts/test_leauto_upgrades.sh | 32 +++++- ...st_letsencrypt_auto_certonly_standalone.sh | 58 ++++++++-- tests/letstest/targets.yaml | 11 -- 6 files changed, 287 insertions(+), 37 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 8120e92df..31f648721 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -794,8 +794,110 @@ BootstrapMageiaCommon() { } -# Certbot-auto is now fully deprecated -DEPRECATED_OS=1 +# Set Bootstrap to the function that installs OS dependencies on this system +# and BOOTSTRAP_VERSION to the unique identifier for the current version of +# that function. If Bootstrap is set to a function that doesn't install any +# packages BOOTSTRAP_VERSION is not set. +if [ -f /etc/debian_version ]; then + DEPRECATED_OS=1 +elif [ -f /etc/mageia-release ]; then + # Mageia has both /etc/mageia-release and /etc/redhat-release + DEPRECATED_OS=1 +elif [ -f /etc/redhat-release ]; then + # Run DeterminePythonVersion to decide on the basis of available Python versions + # whether to use 2.x or 3.x on RedHat-like systems. + # Then, revert LE_PYTHON to its previous state. + prev_le_python="$LE_PYTHON" + unset LE_PYTHON + DeterminePythonVersion "NOCRASH" + + RPM_DIST_NAME=`(. /etc/os-release 2> /dev/null && echo $ID) || echo "unknown"` + + if [ "$PYVER" -eq 26 -a $(uname -m) != 'x86_64' ]; then + # 32 bits CentOS 6 and affiliates are not supported anymore by certbot-auto. + DEPRECATED_OS=1 + fi + + # Set RPM_DIST_VERSION to VERSION_ID from /etc/os-release after splitting on + # '.' characters (e.g. "8.0" becomes "8"). If the command exits with an + # error, RPM_DIST_VERSION is set to "unknown". + RPM_DIST_VERSION=$( (. /etc/os-release 2> /dev/null && echo "$VERSION_ID") | cut -d '.' -f1 || echo "unknown") + + # If RPM_DIST_VERSION is an empty string or it contains any nonnumeric + # characters, the value is unexpected so we set RPM_DIST_VERSION to 0. + if [ -z "$RPM_DIST_VERSION" ] || [ -n "$(echo "$RPM_DIST_VERSION" | tr -d '[0-9]')" ]; then + RPM_DIST_VERSION=0 + fi + + # Handle legacy RPM distributions + if [ "$PYVER" -eq 26 ]; then + # Check if an automated bootstrap can be achieved on this system. + if ! Python36SclIsAvailable; then + INTERACTIVE_BOOTSTRAP=1 + fi + + Bootstrap() { + BootstrapMessage "Legacy RedHat-based OSes that will use Python3" + BootstrapRpmPython3Legacy + } + USE_PYTHON_3=1 + BOOTSTRAP_VERSION="BootstrapRpmPython3Legacy $BOOTSTRAP_RPM_PYTHON3_LEGACY_VERSION" + + # Try now to enable SCL rh-python36 for systems already bootstrapped + # NB: EnablePython36SCL has been defined along with BootstrapRpmPython3Legacy in certbot-auto + EnablePython36SCL + else + # Starting to Fedora 29, python2 is on a deprecation path. Let's move to python3 then. + # RHEL 8 also uses python3 by default. + if [ "$RPM_DIST_NAME" = "fedora" -a "$RPM_DIST_VERSION" -ge 29 ]; then + RPM_USE_PYTHON_3=1 + elif [ "$RPM_DIST_NAME" = "rhel" -a "$RPM_DIST_VERSION" -ge 8 ]; then + RPM_USE_PYTHON_3=1 + elif [ "$RPM_DIST_NAME" = "centos" -a "$RPM_DIST_VERSION" -ge 8 ]; then + RPM_USE_PYTHON_3=1 + else + RPM_USE_PYTHON_3=0 + fi + + if [ "$RPM_USE_PYTHON_3" = 1 ]; then + Bootstrap() { + BootstrapMessage "RedHat-based OSes that will use Python3" + BootstrapRpmPython3 + } + USE_PYTHON_3=1 + BOOTSTRAP_VERSION="BootstrapRpmPython3 $BOOTSTRAP_RPM_PYTHON3_VERSION" + else + Bootstrap() { + BootstrapMessage "RedHat-based OSes" + BootstrapRpmCommon + } + BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION" + fi + fi + + LE_PYTHON="$prev_le_python" +elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then + DEPRECATED_OS=1 +elif [ -f /etc/arch-release ]; then + DEPRECATED_OS=1 +elif [ -f /etc/manjaro-release ]; then + DEPRECATED_OS=1 +elif [ -f /etc/gentoo-release ]; then + DEPRECATED_OS=1 +elif uname | grep -iq FreeBSD ; then + DEPRECATED_OS=1 +elif uname | grep -iq Darwin ; then + DEPRECATED_OS=1 +elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then + Bootstrap() { + ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon + } + BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION" +elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then + DEPRECATED_OS=1 +else + DEPRECATED_OS=1 +fi # We handle this case after determining the normal bootstrap version to allow # variables like USE_PYTHON_3 to be properly set. As described above, if the diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index e4611abdf..5eb82b705 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -316,8 +316,110 @@ DeterminePythonVersion() { {{ bootstrappers/smartos.sh }} {{ bootstrappers/mageia_common.sh }} -# Certbot-auto is now fully deprecated -DEPRECATED_OS=1 +# Set Bootstrap to the function that installs OS dependencies on this system +# and BOOTSTRAP_VERSION to the unique identifier for the current version of +# that function. If Bootstrap is set to a function that doesn't install any +# packages BOOTSTRAP_VERSION is not set. +if [ -f /etc/debian_version ]; then + DEPRECATED_OS=1 +elif [ -f /etc/mageia-release ]; then + # Mageia has both /etc/mageia-release and /etc/redhat-release + DEPRECATED_OS=1 +elif [ -f /etc/redhat-release ]; then + # Run DeterminePythonVersion to decide on the basis of available Python versions + # whether to use 2.x or 3.x on RedHat-like systems. + # Then, revert LE_PYTHON to its previous state. + prev_le_python="$LE_PYTHON" + unset LE_PYTHON + DeterminePythonVersion "NOCRASH" + + RPM_DIST_NAME=`(. /etc/os-release 2> /dev/null && echo $ID) || echo "unknown"` + + if [ "$PYVER" -eq 26 -a $(uname -m) != 'x86_64' ]; then + # 32 bits CentOS 6 and affiliates are not supported anymore by certbot-auto. + DEPRECATED_OS=1 + fi + + # Set RPM_DIST_VERSION to VERSION_ID from /etc/os-release after splitting on + # '.' characters (e.g. "8.0" becomes "8"). If the command exits with an + # error, RPM_DIST_VERSION is set to "unknown". + RPM_DIST_VERSION=$( (. /etc/os-release 2> /dev/null && echo "$VERSION_ID") | cut -d '.' -f1 || echo "unknown") + + # If RPM_DIST_VERSION is an empty string or it contains any nonnumeric + # characters, the value is unexpected so we set RPM_DIST_VERSION to 0. + if [ -z "$RPM_DIST_VERSION" ] || [ -n "$(echo "$RPM_DIST_VERSION" | tr -d '[0-9]')" ]; then + RPM_DIST_VERSION=0 + fi + + # Handle legacy RPM distributions + if [ "$PYVER" -eq 26 ]; then + # Check if an automated bootstrap can be achieved on this system. + if ! Python36SclIsAvailable; then + INTERACTIVE_BOOTSTRAP=1 + fi + + Bootstrap() { + BootstrapMessage "Legacy RedHat-based OSes that will use Python3" + BootstrapRpmPython3Legacy + } + USE_PYTHON_3=1 + BOOTSTRAP_VERSION="BootstrapRpmPython3Legacy $BOOTSTRAP_RPM_PYTHON3_LEGACY_VERSION" + + # Try now to enable SCL rh-python36 for systems already bootstrapped + # NB: EnablePython36SCL has been defined along with BootstrapRpmPython3Legacy in certbot-auto + EnablePython36SCL + else + # Starting to Fedora 29, python2 is on a deprecation path. Let's move to python3 then. + # RHEL 8 also uses python3 by default. + if [ "$RPM_DIST_NAME" = "fedora" -a "$RPM_DIST_VERSION" -ge 29 ]; then + RPM_USE_PYTHON_3=1 + elif [ "$RPM_DIST_NAME" = "rhel" -a "$RPM_DIST_VERSION" -ge 8 ]; then + RPM_USE_PYTHON_3=1 + elif [ "$RPM_DIST_NAME" = "centos" -a "$RPM_DIST_VERSION" -ge 8 ]; then + RPM_USE_PYTHON_3=1 + else + RPM_USE_PYTHON_3=0 + fi + + if [ "$RPM_USE_PYTHON_3" = 1 ]; then + Bootstrap() { + BootstrapMessage "RedHat-based OSes that will use Python3" + BootstrapRpmPython3 + } + USE_PYTHON_3=1 + BOOTSTRAP_VERSION="BootstrapRpmPython3 $BOOTSTRAP_RPM_PYTHON3_VERSION" + else + Bootstrap() { + BootstrapMessage "RedHat-based OSes" + BootstrapRpmCommon + } + BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION" + fi + fi + + LE_PYTHON="$prev_le_python" +elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then + DEPRECATED_OS=1 +elif [ -f /etc/arch-release ]; then + DEPRECATED_OS=1 +elif [ -f /etc/manjaro-release ]; then + DEPRECATED_OS=1 +elif [ -f /etc/gentoo-release ]; then + DEPRECATED_OS=1 +elif uname | grep -iq FreeBSD ; then + DEPRECATED_OS=1 +elif uname | grep -iq Darwin ; then + DEPRECATED_OS=1 +elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then + Bootstrap() { + ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon + } + BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION" +elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then + DEPRECATED_OS=1 +else + DEPRECATED_OS=1 +fi # We handle this case after determining the normal bootstrap version to allow # variables like USE_PYTHON_3 to be properly set. As described above, if the diff --git a/tests/letstest/auto_targets.yaml b/tests/letstest/auto_targets.yaml index 76b3a3dc5..9d97c6a83 100644 --- a/tests/letstest/auto_targets.yaml +++ b/tests/letstest/auto_targets.yaml @@ -56,17 +56,6 @@ targets: type: centos virt: hvm user: centos - # centos6 requires EPEL repo added - - ami: ami-1585c46a - name: centos6 - type: centos - virt: hvm - user: centos - userdata: | - #cloud-config - runcmd: - - yum install -y epel-release - - iptables -F - ami: ami-01ca03df4a6012157 name: centos8 type: centos diff --git a/tests/letstest/scripts/test_leauto_upgrades.sh b/tests/letstest/scripts/test_leauto_upgrades.sh index 1eeafad21..51ff640c5 100755 --- a/tests/letstest/scripts/test_leauto_upgrades.sh +++ b/tests/letstest/scripts/test_leauto_upgrades.sh @@ -105,10 +105,15 @@ if ./letsencrypt-auto -v --debug --version | grep "WARNING: couldn't find Python exit 1 fi -# Since certbot-auto is deprecated, we expect it to leave existing Certbot -# installations unmodified so we check for the same version that was initially -# installed below. -EXPECTED_VERSION="$INITIAL_VERSION" +# On systems like Debian where certbot-auto is deprecated, we expect it to +# leave existing Certbot installations unmodified so we check for the same +# version that was initially installed below. Once certbot-auto is deprecated +# on RHEL systems, we can unconditionally check for INITIAL_VERSION. +if [ -f /etc/debian_version ]; then + EXPECTED_VERSION="$INITIAL_VERSION" +else + EXPECTED_VERSION=$(grep -m1 LE_AUTO_VERSION certbot-auto | cut -d\" -f2) +fi if ! /opt/eff.org/certbot/venv/bin/letsencrypt --version 2>&1 | tail -n1 | grep "^certbot $EXPECTED_VERSION$" ; then echo unexpected certbot version found @@ -119,3 +124,22 @@ if ! diff letsencrypt-auto letsencrypt-auto-source/letsencrypt-auto ; then echo letsencrypt-auto and letsencrypt-auto-source/letsencrypt-auto differ exit 1 fi + +if [ "$RUN_RHEL6_TESTS" = 1 ]; then + # Add the SCL python release to PATH in order to resolve python3 command + PATH="/opt/rh/rh-python36/root/usr/bin:$PATH" + if ! command -v python3; then + echo "Python3 wasn't properly installed" + exit 1 + fi + if [ "$(/opt/eff.org/certbot/venv/bin/python -V 2>&1 | cut -d" " -f 2 | cut -d. -f1)" != 3 ]; then + echo "Python3 wasn't used in venv!" + exit 1 + fi + + if [ "$("$PYTHON_NAME" tools/readlink.py $OLD_VENV_PATH)" != "/opt/eff.org/certbot/venv" ]; then + echo symlink from old venv path not properly created! + exit 1 + fi +fi +echo upgrade appeared to be successful diff --git a/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh b/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh index fc5435916..15cf9ee1b 100755 --- a/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh +++ b/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh @@ -16,14 +16,58 @@ sudo chown root "$LE_AUTO_PATH" sudo chmod 0755 "$LE_AUTO_PATH" export PATH="$LE_AUTO_DIR:$PATH" -# Since certbot-auto is deprecated, we expect certbot-auto to error and -# refuse to install Certbot. -set +o pipefail -if ! letsencrypt-auto --debug --version | grep "Certbot cannot be installed."; then - echo "letsencrypt-auto didn't report being uninstallable." +# On systems like Debian where certbot-auto is deprecated, we expect +# certbot-auto to error and refuse to install Certbot. Once certbot-auto is +# deprecated on RHEL systems, we can unconditionally run this code. +if [ -f /etc/debian_version ]; then + set +o pipefail + if ! letsencrypt-auto --debug --version | grep "Certbot cannot be installed."; then + echo "letsencrypt-auto didn't report being uninstallable." + exit 1 + fi + if [ ${PIPESTATUS[0]} != 1 ]; then + echo "letsencrypt-auto didn't exit with status 1 as expected" + exit 1 + fi + # letsencrypt-auto is deprecated and cannot be installed on this system so + # we cannot run the rest of this test. + exit 0 +fi + +letsencrypt-auto --os-packages-only --debug --version + +# This script sets the environment variables PYTHON_NAME, VENV_PATH, and +# VENV_SCRIPT based on the version of Python available on the system. For +# instance, Fedora uses Python 3 and Python 2 is not installed. +. tests/letstest/scripts/set_python_envvars.sh + +# Create a venv-like layout at the old virtual environment path to test that a +# symlink is properly created when letsencrypt-auto runs. +HOME=${HOME:-~root} +XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} +OLD_VENV_BIN="$XDG_DATA_HOME/letsencrypt/bin" +mkdir -p "$OLD_VENV_BIN" +touch "$OLD_VENV_BIN/letsencrypt" + +letsencrypt-auto certonly --no-self-upgrade -v --standalone --debug \ + --text --agree-tos \ + --renew-by-default --redirect \ + --register-unsafely-without-email \ + --domain $PUBLIC_HOSTNAME --server $BOULDER_URL + +LINK_PATH=$("$PYTHON_NAME" tools/readlink.py ${XDG_DATA_HOME:-~/.local/share}/letsencrypt) +if [ "$LINK_PATH" != "/opt/eff.org/certbot/venv" ]; then + echo symlink from old venv path not properly created! exit 1 fi -if [ ${PIPESTATUS[0]} != 1 ]; then - echo "letsencrypt-auto didn't exit with status 1 as expected" + +if ! letsencrypt-auto --help --no-self-upgrade | grep -F "letsencrypt-auto [SUBCOMMAND]"; then + echo "letsencrypt-auto not included in help output!" + exit 1 +fi + +OUTPUT_LEN=$(letsencrypt-auto --install-only --no-self-upgrade --quiet 2>&1 | wc -c) +if [ "$OUTPUT_LEN" != 0 ]; then + echo letsencrypt-auto produced unexpected output! exit 1 fi diff --git a/tests/letstest/targets.yaml b/tests/letstest/targets.yaml index 29edd1552..97c775f6c 100644 --- a/tests/letstest/targets.yaml +++ b/tests/letstest/targets.yaml @@ -52,17 +52,6 @@ targets: type: centos virt: hvm user: centos - # centos6 requires EPEL repo added - - ami: ami-1585c46a - name: centos6 - type: centos - virt: hvm - user: centos - userdata: | - #cloud-config - runcmd: - - yum install -y epel-release - - iptables -F - ami: ami-01ca03df4a6012157 name: centos8 type: centos From 1a3c96a9554061a924624b7b30e8e0b9db40a542 Mon Sep 17 00:00:00 2001 From: Adrien Ferrand Date: Tue, 1 Dec 2020 23:46:01 +0100 Subject: [PATCH 24/42] Deprecate certbot-auto and remove tests * Completely deprecate certbot-auto * DeaDeactivate centos6/oraclelinux6 tests * Remove tests assets * Remove another test * Revert "Remove tests assets" This reverts commit e603afe6c4683a25982351557a348d35eba2f65b. (cherry picked from commit ff3a07dca34350064bf9f8e9fbe93eda7482acc0) --- .../templates/jobs/extended-tests-jobs.yml | 2 - .../templates/jobs/standard-tests-jobs.yml | 4 +- letsencrypt-auto-source/Dockerfile.redhat6 | 54 -- letsencrypt-auto-source/letsencrypt-auto | 106 +--- .../letsencrypt-auto.template | 106 +--- letsencrypt-auto-source/tests/__init__.py | 7 - letsencrypt-auto-source/tests/auto_test.py | 503 ------------------ .../tests/centos6_tests.sh | 173 ------ .../tests/certs/ca/my-root-ca.crt.pem | 23 - .../tests/certs/ca/my-root-ca.key.pem | 27 - .../tests/certs/ca/my-root-ca.srl | 1 - .../tests/certs/localhost/cert.pem | 19 - .../tests/certs/localhost/localhost.csr.pem | 17 - .../tests/certs/localhost/privkey.pem | 27 - .../tests/certs/localhost/server.pem | 46 -- .../dist/letsencrypt-99.9.9.tar.gz | Bin 876 -> 0 bytes .../tests/fake-letsencrypt/letsencrypt.py | 8 - .../tests/fake-letsencrypt/setup.py | 12 - .../tests/oraclelinux6_tests.sh | 85 --- .../tests/uname_wrapper.sh | 10 - .../letstest/scripts/test_leauto_upgrades.sh | 32 +- ...st_letsencrypt_auto_certonly_standalone.sh | 58 +- tox.ini | 23 - 23 files changed, 17 insertions(+), 1326 deletions(-) delete mode 100644 letsencrypt-auto-source/Dockerfile.redhat6 delete mode 100644 letsencrypt-auto-source/tests/__init__.py delete mode 100644 letsencrypt-auto-source/tests/auto_test.py delete mode 100644 letsencrypt-auto-source/tests/centos6_tests.sh delete mode 100644 letsencrypt-auto-source/tests/certs/ca/my-root-ca.crt.pem delete mode 100644 letsencrypt-auto-source/tests/certs/ca/my-root-ca.key.pem delete mode 100644 letsencrypt-auto-source/tests/certs/ca/my-root-ca.srl delete mode 100644 letsencrypt-auto-source/tests/certs/localhost/cert.pem delete mode 100644 letsencrypt-auto-source/tests/certs/localhost/localhost.csr.pem delete mode 100644 letsencrypt-auto-source/tests/certs/localhost/privkey.pem delete mode 100644 letsencrypt-auto-source/tests/certs/localhost/server.pem delete mode 100644 letsencrypt-auto-source/tests/fake-letsencrypt/dist/letsencrypt-99.9.9.tar.gz delete mode 100755 letsencrypt-auto-source/tests/fake-letsencrypt/letsencrypt.py delete mode 100644 letsencrypt-auto-source/tests/fake-letsencrypt/setup.py delete mode 100644 letsencrypt-auto-source/tests/oraclelinux6_tests.sh delete mode 100644 letsencrypt-auto-source/tests/uname_wrapper.sh diff --git a/.azure-pipelines/templates/jobs/extended-tests-jobs.yml b/.azure-pipelines/templates/jobs/extended-tests-jobs.yml index f835078c8..0c92136e8 100644 --- a/.azure-pipelines/templates/jobs/extended-tests-jobs.yml +++ b/.azure-pipelines/templates/jobs/extended-tests-jobs.yml @@ -79,8 +79,6 @@ jobs: IMAGE_NAME: ubuntu-18.04 PYTHON_VERSION: 3.8 TOXENV: integration-dns-rfc2136 - le-auto-oraclelinux6: - TOXENV: le_auto_oraclelinux6 docker-dev: TOXENV: docker_dev macos-farmtest-apache2: diff --git a/.azure-pipelines/templates/jobs/standard-tests-jobs.yml b/.azure-pipelines/templates/jobs/standard-tests-jobs.yml index 897ab40bb..39cd628bc 100644 --- a/.azure-pipelines/templates/jobs/standard-tests-jobs.yml +++ b/.azure-pipelines/templates/jobs/standard-tests-jobs.yml @@ -58,9 +58,9 @@ jobs: apache-compat: IMAGE_NAME: ubuntu-18.04 TOXENV: apache_compat - le-auto-centos6: + le-modification: IMAGE_NAME: ubuntu-18.04 - TOXENV: le_auto_centos6 + TOXENV: modification apacheconftest: IMAGE_NAME: ubuntu-18.04 PYTHON_VERSION: 2.7 diff --git a/letsencrypt-auto-source/Dockerfile.redhat6 b/letsencrypt-auto-source/Dockerfile.redhat6 deleted file mode 100644 index 66f21bc14..000000000 --- a/letsencrypt-auto-source/Dockerfile.redhat6 +++ /dev/null @@ -1,54 +0,0 @@ -# For running tests, build a docker image with a passwordless sudo and a trust -# store we can manipulate. - -ARG REDHAT_DIST_FLAVOR -FROM ${REDHAT_DIST_FLAVOR}:6 - -ARG REDHAT_DIST_FLAVOR - -RUN curl -O https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm \ - && rpm -ivh epel-release-latest-6.noarch.rpm - -# Install pip and sudo: -RUN yum install -y python-pip sudo -# Update to a stable and tested version of pip. -# We do not use pipstrap here because it no longer supports Python 2.6. -RUN pip install pip==9.0.1 setuptools==29.0.1 wheel==0.29.0 -# Pin pytest version for increased stability -RUN pip install pytest==3.2.5 six==1.10.0 - -# Add an unprivileged user: -RUN useradd --create-home --home-dir /home/lea --shell /bin/bash --groups wheel --uid 1000 lea - -# Let that user sudo: -RUN sed -i.bkp -e \ - 's/# %wheel\(NOPASSWD: ALL\)\?/%wheel/g' \ - /etc/sudoers - -RUN mkdir -p /home/lea/certbot - -# Install fake testing CA: -COPY ./tests/certs/ca/my-root-ca.crt.pem /usr/local/share/ca-certificates/ -RUN update-ca-trust - -# Copy current letsencrypt-auto: -COPY . /home/lea/certbot/letsencrypt-auto-source - -# Tweak uname binary for tests on fake 32bits -COPY tests/uname_wrapper.sh /bin -RUN mv /bin/uname /bin/uname_orig \ - && mv /bin/uname_wrapper.sh /bin/uname \ - && chmod +x /bin/uname - -# Fetch previous letsencrypt-auto that was installing python 3.4 -RUN curl https://raw.githubusercontent.com/certbot/certbot/v0.38.0/letsencrypt-auto-source/letsencrypt-auto \ - -o /home/lea/certbot/letsencrypt-auto-source/letsencrypt-auto_py_34 \ - && chmod +x /home/lea/certbot/letsencrypt-auto-source/letsencrypt-auto_py_34 - -RUN cp /home/lea/certbot/letsencrypt-auto-source/tests/${REDHAT_DIST_FLAVOR}6_tests.sh /home/lea/certbot/letsencrypt-auto-source/tests/redhat6_tests.sh \ - && chmod +x /home/lea/certbot/letsencrypt-auto-source/tests/redhat6_tests.sh - -USER lea -WORKDIR /home/lea - -CMD ["sudo", "certbot/letsencrypt-auto-source/tests/redhat6_tests.sh"] diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 96b40c0c8..6082a7339 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -794,110 +794,8 @@ BootstrapMageiaCommon() { } -# Set Bootstrap to the function that installs OS dependencies on this system -# and BOOTSTRAP_VERSION to the unique identifier for the current version of -# that function. If Bootstrap is set to a function that doesn't install any -# packages BOOTSTRAP_VERSION is not set. -if [ -f /etc/debian_version ]; then - DEPRECATED_OS=1 -elif [ -f /etc/mageia-release ]; then - # Mageia has both /etc/mageia-release and /etc/redhat-release - DEPRECATED_OS=1 -elif [ -f /etc/redhat-release ]; then - # Run DeterminePythonVersion to decide on the basis of available Python versions - # whether to use 2.x or 3.x on RedHat-like systems. - # Then, revert LE_PYTHON to its previous state. - prev_le_python="$LE_PYTHON" - unset LE_PYTHON - DeterminePythonVersion "NOCRASH" - - RPM_DIST_NAME=`(. /etc/os-release 2> /dev/null && echo $ID) || echo "unknown"` - - if [ "$PYVER" -eq 26 -a $(uname -m) != 'x86_64' ]; then - # 32 bits CentOS 6 and affiliates are not supported anymore by certbot-auto. - DEPRECATED_OS=1 - fi - - # Set RPM_DIST_VERSION to VERSION_ID from /etc/os-release after splitting on - # '.' characters (e.g. "8.0" becomes "8"). If the command exits with an - # error, RPM_DIST_VERSION is set to "unknown". - RPM_DIST_VERSION=$( (. /etc/os-release 2> /dev/null && echo "$VERSION_ID") | cut -d '.' -f1 || echo "unknown") - - # If RPM_DIST_VERSION is an empty string or it contains any nonnumeric - # characters, the value is unexpected so we set RPM_DIST_VERSION to 0. - if [ -z "$RPM_DIST_VERSION" ] || [ -n "$(echo "$RPM_DIST_VERSION" | tr -d '[0-9]')" ]; then - RPM_DIST_VERSION=0 - fi - - # Handle legacy RPM distributions - if [ "$PYVER" -eq 26 ]; then - # Check if an automated bootstrap can be achieved on this system. - if ! Python36SclIsAvailable; then - INTERACTIVE_BOOTSTRAP=1 - fi - - Bootstrap() { - BootstrapMessage "Legacy RedHat-based OSes that will use Python3" - BootstrapRpmPython3Legacy - } - USE_PYTHON_3=1 - BOOTSTRAP_VERSION="BootstrapRpmPython3Legacy $BOOTSTRAP_RPM_PYTHON3_LEGACY_VERSION" - - # Try now to enable SCL rh-python36 for systems already bootstrapped - # NB: EnablePython36SCL has been defined along with BootstrapRpmPython3Legacy in certbot-auto - EnablePython36SCL - else - # Starting to Fedora 29, python2 is on a deprecation path. Let's move to python3 then. - # RHEL 8 also uses python3 by default. - if [ "$RPM_DIST_NAME" = "fedora" -a "$RPM_DIST_VERSION" -ge 29 ]; then - RPM_USE_PYTHON_3=1 - elif [ "$RPM_DIST_NAME" = "rhel" -a "$RPM_DIST_VERSION" -ge 8 ]; then - RPM_USE_PYTHON_3=1 - elif [ "$RPM_DIST_NAME" = "centos" -a "$RPM_DIST_VERSION" -ge 8 ]; then - RPM_USE_PYTHON_3=1 - else - RPM_USE_PYTHON_3=0 - fi - - if [ "$RPM_USE_PYTHON_3" = 1 ]; then - Bootstrap() { - BootstrapMessage "RedHat-based OSes that will use Python3" - BootstrapRpmPython3 - } - USE_PYTHON_3=1 - BOOTSTRAP_VERSION="BootstrapRpmPython3 $BOOTSTRAP_RPM_PYTHON3_VERSION" - else - Bootstrap() { - BootstrapMessage "RedHat-based OSes" - BootstrapRpmCommon - } - BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION" - fi - fi - - LE_PYTHON="$prev_le_python" -elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then - DEPRECATED_OS=1 -elif [ -f /etc/arch-release ]; then - DEPRECATED_OS=1 -elif [ -f /etc/manjaro-release ]; then - DEPRECATED_OS=1 -elif [ -f /etc/gentoo-release ]; then - DEPRECATED_OS=1 -elif uname | grep -iq FreeBSD ; then - DEPRECATED_OS=1 -elif uname | grep -iq Darwin ; then - DEPRECATED_OS=1 -elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then - Bootstrap() { - ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon - } - BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION" -elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then - DEPRECATED_OS=1 -else - DEPRECATED_OS=1 -fi +# Certbot-auto is now fully deprecated +DEPRECATED_OS=1 # We handle this case after determining the normal bootstrap version to allow # variables like USE_PYTHON_3 to be properly set. As described above, if the diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index 5eb82b705..e4611abdf 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -316,110 +316,8 @@ DeterminePythonVersion() { {{ bootstrappers/smartos.sh }} {{ bootstrappers/mageia_common.sh }} -# Set Bootstrap to the function that installs OS dependencies on this system -# and BOOTSTRAP_VERSION to the unique identifier for the current version of -# that function. If Bootstrap is set to a function that doesn't install any -# packages BOOTSTRAP_VERSION is not set. -if [ -f /etc/debian_version ]; then - DEPRECATED_OS=1 -elif [ -f /etc/mageia-release ]; then - # Mageia has both /etc/mageia-release and /etc/redhat-release - DEPRECATED_OS=1 -elif [ -f /etc/redhat-release ]; then - # Run DeterminePythonVersion to decide on the basis of available Python versions - # whether to use 2.x or 3.x on RedHat-like systems. - # Then, revert LE_PYTHON to its previous state. - prev_le_python="$LE_PYTHON" - unset LE_PYTHON - DeterminePythonVersion "NOCRASH" - - RPM_DIST_NAME=`(. /etc/os-release 2> /dev/null && echo $ID) || echo "unknown"` - - if [ "$PYVER" -eq 26 -a $(uname -m) != 'x86_64' ]; then - # 32 bits CentOS 6 and affiliates are not supported anymore by certbot-auto. - DEPRECATED_OS=1 - fi - - # Set RPM_DIST_VERSION to VERSION_ID from /etc/os-release after splitting on - # '.' characters (e.g. "8.0" becomes "8"). If the command exits with an - # error, RPM_DIST_VERSION is set to "unknown". - RPM_DIST_VERSION=$( (. /etc/os-release 2> /dev/null && echo "$VERSION_ID") | cut -d '.' -f1 || echo "unknown") - - # If RPM_DIST_VERSION is an empty string or it contains any nonnumeric - # characters, the value is unexpected so we set RPM_DIST_VERSION to 0. - if [ -z "$RPM_DIST_VERSION" ] || [ -n "$(echo "$RPM_DIST_VERSION" | tr -d '[0-9]')" ]; then - RPM_DIST_VERSION=0 - fi - - # Handle legacy RPM distributions - if [ "$PYVER" -eq 26 ]; then - # Check if an automated bootstrap can be achieved on this system. - if ! Python36SclIsAvailable; then - INTERACTIVE_BOOTSTRAP=1 - fi - - Bootstrap() { - BootstrapMessage "Legacy RedHat-based OSes that will use Python3" - BootstrapRpmPython3Legacy - } - USE_PYTHON_3=1 - BOOTSTRAP_VERSION="BootstrapRpmPython3Legacy $BOOTSTRAP_RPM_PYTHON3_LEGACY_VERSION" - - # Try now to enable SCL rh-python36 for systems already bootstrapped - # NB: EnablePython36SCL has been defined along with BootstrapRpmPython3Legacy in certbot-auto - EnablePython36SCL - else - # Starting to Fedora 29, python2 is on a deprecation path. Let's move to python3 then. - # RHEL 8 also uses python3 by default. - if [ "$RPM_DIST_NAME" = "fedora" -a "$RPM_DIST_VERSION" -ge 29 ]; then - RPM_USE_PYTHON_3=1 - elif [ "$RPM_DIST_NAME" = "rhel" -a "$RPM_DIST_VERSION" -ge 8 ]; then - RPM_USE_PYTHON_3=1 - elif [ "$RPM_DIST_NAME" = "centos" -a "$RPM_DIST_VERSION" -ge 8 ]; then - RPM_USE_PYTHON_3=1 - else - RPM_USE_PYTHON_3=0 - fi - - if [ "$RPM_USE_PYTHON_3" = 1 ]; then - Bootstrap() { - BootstrapMessage "RedHat-based OSes that will use Python3" - BootstrapRpmPython3 - } - USE_PYTHON_3=1 - BOOTSTRAP_VERSION="BootstrapRpmPython3 $BOOTSTRAP_RPM_PYTHON3_VERSION" - else - Bootstrap() { - BootstrapMessage "RedHat-based OSes" - BootstrapRpmCommon - } - BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION" - fi - fi - - LE_PYTHON="$prev_le_python" -elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then - DEPRECATED_OS=1 -elif [ -f /etc/arch-release ]; then - DEPRECATED_OS=1 -elif [ -f /etc/manjaro-release ]; then - DEPRECATED_OS=1 -elif [ -f /etc/gentoo-release ]; then - DEPRECATED_OS=1 -elif uname | grep -iq FreeBSD ; then - DEPRECATED_OS=1 -elif uname | grep -iq Darwin ; then - DEPRECATED_OS=1 -elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then - Bootstrap() { - ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon - } - BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION" -elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then - DEPRECATED_OS=1 -else - DEPRECATED_OS=1 -fi +# Certbot-auto is now fully deprecated +DEPRECATED_OS=1 # We handle this case after determining the normal bootstrap version to allow # variables like USE_PYTHON_3 to be properly set. As described above, if the diff --git a/letsencrypt-auto-source/tests/__init__.py b/letsencrypt-auto-source/tests/__init__.py deleted file mode 100644 index 8a1613aa5..000000000 --- a/letsencrypt-auto-source/tests/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -"""Tests for letsencrypt-auto - -Run these locally by saying... :: - - ./build.py && docker build -t lea . -f Dockerfile. && docker run --rm -t -i lea - -""" diff --git a/letsencrypt-auto-source/tests/auto_test.py b/letsencrypt-auto-source/tests/auto_test.py deleted file mode 100644 index 805bb21af..000000000 --- a/letsencrypt-auto-source/tests/auto_test.py +++ /dev/null @@ -1,503 +0,0 @@ -"""Tests for letsencrypt-auto""" - -from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler -from contextlib import contextmanager -from functools import partial -from json import dumps -from os import chmod, environ, makedirs, stat -from os.path import abspath, dirname, exists, join -import re -from shutil import copy, rmtree -import socket -import ssl -from stat import S_IMODE, S_IRUSR, S_IWUSR, S_IXUSR, S_IWGRP, S_IWOTH -from subprocess import CalledProcessError, Popen, PIPE -import sys -from tempfile import mkdtemp -from threading import Thread -from unittest import TestCase - -from pytest import mark -from six.moves import xrange # pylint: disable=redefined-builtin - - -@mark.skip -def tests_dir(): - """Return a path to the "tests" directory.""" - return dirname(abspath(__file__)) - - -def copy_stable(src, dst): - """ - Copy letsencrypt-auto, and replace its current version to its equivalent stable one. - This is needed to test correctly the self-upgrade functionality. - """ - copy(src, dst) - with open(dst, 'r') as file: - filedata = file.read() - filedata = re.sub(r'LE_AUTO_VERSION="(.*)\.dev0"', r'LE_AUTO_VERSION="\1"', filedata) - with open(dst, 'w') as file: - file.write(filedata) - - -sys.path.insert(0, dirname(tests_dir())) -from build import build as build_le_auto - - -BOOTSTRAP_FILENAME = 'certbot-auto-bootstrap-version.txt' -"""Name of the file where certbot-auto saves its bootstrap version.""" - - -class RequestHandler(BaseHTTPRequestHandler): - """An HTTPS request handler which is quiet and serves a specific folder.""" - - def __init__(self, resources, *args, **kwargs): - """ - :arg resources: A dict of resource paths pointing to content bytes - - """ - self.resources = resources - BaseHTTPRequestHandler.__init__(self, *args, **kwargs) - - def log_message(self, format, *args): - """Don't log each request to the terminal.""" - - def do_GET(self): - """Serve a GET request.""" - content = self.send_head() - if content is not None: - self.wfile.write(content) - - def send_head(self): - """Common code for GET and HEAD commands - - This sends the response code and MIME headers and returns either a - bytestring of content or, if none is found, None. - - """ - path = self.path[1:] # Strip leading slash. - content = self.resources.get(path) - if content is None: - self.send_error(404, 'Path "%s" not found in self.resources' % path) - else: - self.send_response(200) - self.send_header('Content-type', 'text/plain') - self.send_header('Content-Length', str(len(content))) - self.end_headers() - return content - - -def server_and_port(resources): - """Return an unstarted HTTPS server and the port it will use.""" - # Find a port, and bind to it. I can't get the OS to close the socket - # promptly after we shut down the server, so we typically need to try - # a couple ports after the first test case. Setting - # TCPServer.allow_reuse_address = True seems to have nothing to do - # with this behavior. - worked = False - for port in xrange(4443, 4543): - try: - server = HTTPServer(('localhost', port), - partial(RequestHandler, resources)) - except socket.error: - pass - else: - worked = True - server.socket = ssl.wrap_socket( - server.socket, - certfile=join(tests_dir(), 'certs', 'localhost', 'server.pem'), - server_side=True) - break - if not worked: - raise RuntimeError("Couldn't find an unused socket for the testing HTTPS server.") - return server, port - - -@contextmanager -def serving(resources): - """Spin up a local HTTPS server, and yield its base URL. - - Use a self-signed cert generated as outlined by - https://coolaj86.com/articles/create-your-own-certificate-authority-for- - testing/. - - """ - server, port = server_and_port(resources) - thread = Thread(target=server.serve_forever) - try: - thread.start() - yield 'https://localhost:{port}/'.format(port=port) - finally: - server.shutdown() - thread.join() - - -LE_AUTO_PATH = join(dirname(tests_dir()), 'letsencrypt-auto') - - -@contextmanager -def temp_paths(): - """Creates and deletes paths for letsencrypt-auto and its venv.""" - dir = mkdtemp(prefix='le-test-') - try: - yield join(dir, 'letsencrypt-auto'), join(dir, 'venv') - finally: - rmtree(dir, ignore_errors=True) - - -def out_and_err(command, input=None, shell=False, env=None): - """Run a shell command, and return stderr and stdout as string. - - If the command returns nonzero, raise CalledProcessError. - - :arg command: A list of commandline args - :arg input: Data to pipe to stdin. Omit for none. - - Remaining args have the same meaning as for Popen. - - """ - process = Popen(command, - stdout=PIPE, - stdin=PIPE, - stderr=PIPE, - shell=shell, - env=env) - out, err = process.communicate(input=input) - status = process.poll() # same as in check_output(), though wait() sounds better - if status: - error = CalledProcessError(status, command) - error.output = out - print('stdout output was:') - print(out) - print('stderr output was:') - print(err) - raise error - return out, err - - -def signed(content, private_key_name='signing.key'): - """Return the signed SHA-256 hash of ``content``, using the given key file.""" - command = ['openssl', 'dgst', '-sha256', '-sign', - join(tests_dir(), private_key_name)] - out, err = out_and_err(command, input=content) - return out - - -def install_le_auto(contents, install_path): - """Install some given source code as the letsencrypt-auto script at the - root level of a virtualenv. - - :arg contents: The contents of the built letsencrypt-auto script - :arg install_path: The path where to install the script - - """ - with open(install_path, 'w') as le_auto: - le_auto.write(contents) - chmod(install_path, S_IRUSR | S_IXUSR) - - -def run_le_auto(le_auto_path, venv_dir, base_url=None, le_auto_args_str='--version', **kwargs): - """Run the prebuilt version of letsencrypt-auto, returning stdout and - stderr strings. - - If the command returns other than 0, raise CalledProcessError. - - """ - env = environ.copy() - d = dict(VENV_PATH=venv_dir, - NO_CERT_VERIFY='1', - **kwargs) - - if base_url is not None: - # URL to PyPI-style JSON that tell us the latest released version - # of LE: - d['LE_AUTO_JSON_URL'] = base_url + 'certbot/json' - # URL to dir containing letsencrypt-auto and letsencrypt-auto.sig: - d['LE_AUTO_DIR_TEMPLATE'] = base_url + '%s/' - # The public key corresponding to signing.key: - d['LE_AUTO_PUBLIC_KEY'] = """-----BEGIN PUBLIC KEY----- -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsMoSzLYQ7E1sdSOkwelg -tzKIh2qi3bpXuYtcfFC0XrvWig071NwIj+dZiT0OLZ2hPispEH0B7ISuuWg1ll7G -hFW0VdbxL6JdGzS2ShNWkX9hE9z+j8VqwDPOBn3ZHm03qwpYkBDwQib3KqOdYbTT -uUtJmmGcuk3a9Aq/sCT6DdfmTSdP5asdQYwIcaQreDrOosaS84DTWI3IU+UYJVgl -LsIVPBuy9IcgHidUQ96hJnoPsDCWsHwX62495QKEarauyKQrJzFes0EY95orDM47 -Z5o/NDiQB11m91yNB0MmPYY9QSbnOA9j7IaaC97AwRLuwXY+/R2ablTcxurWou68 -iQIDAQAB ------END PUBLIC KEY-----""" - - env.update(d) - - return out_and_err( - le_auto_path + ' ' + le_auto_args_str, - shell=True, - env=env) - - -def set_le_script_version(venv_dir, version): - """Tell the letsencrypt script to report a certain version. - - We actually replace the script with a dummy version that knows only how to - print its version. - - """ - letsencrypt_path = join(venv_dir, 'bin', 'letsencrypt') - with open(letsencrypt_path, 'w') as script: - script.write("#!/usr/bin/env python\n" - "from sys import stderr\n" - "stderr.write('letsencrypt %s\\n')" % version) - chmod(letsencrypt_path, S_IRUSR | S_IXUSR) - - -def sudo_chmod(path, mode): - """Runs `sudo chmod mode path`.""" - mode = oct(mode).replace('o', '') - out_and_err(['sudo', 'chmod', mode, path]) - - -class AutoTests(TestCase): - """Test the major branch points of letsencrypt-auto: - - * An le-auto upgrade is needed. - * An le-auto upgrade is not needed. - * There was an out-of-date LE script installed. - * There was a current LE script installed. - * There was no LE script installed (less important). - * Pip hash-verification passes. - * Pip has a hash mismatch. - * The OpenSSL sig matches. - * The OpenSSL sig mismatches. - - For tests which get to the end, we run merely ``letsencrypt --version``. - The functioning of the rest of the certbot script is covered by other - test suites. - - """ - NEW_LE_AUTO = build_le_auto( - version='99.9.9', - requirements='letsencrypt==99.9.9 --hash=sha256:1cc14d61ab424cdee446f51e50f1123f8482ec740587fe78626c933bba2873a0') - NEW_LE_AUTO_SIG = signed(NEW_LE_AUTO) - - def test_successes(self): - """Exercise most branches of letsencrypt-auto. - - They just happen to be the branches in which everything goes well. - - I violate my usual rule of having small, decoupled tests, because... - - 1. We shouldn't need to run a Cartesian product of the branches: the - phases run in separate shell processes, containing state leakage - pretty effectively. The only shared state is FS state, and it's - limited to a temp dir, assuming (if we dare) all functions properly. - 2. One combination of branches happens to set us up nicely for testing - the next, saving code. - - """ - with temp_paths() as (le_auto_path, venv_dir): - # This serves a PyPI page with a higher version, a GitHub-alike - # with a corresponding le-auto script, and a matching signature. - resources = {'certbot/json': dumps({'releases': {'99.9.9': None}}), - 'v99.9.9/letsencrypt-auto': self.NEW_LE_AUTO, - 'v99.9.9/letsencrypt-auto.sig': self.NEW_LE_AUTO_SIG} - with serving(resources) as base_url: - run_letsencrypt_auto = partial( - run_le_auto, - le_auto_path, - venv_dir, - base_url, - PIP_FIND_LINKS=join(tests_dir(), - 'fake-letsencrypt', - 'dist')) - - # Test when a phase-1 upgrade is needed, there's no LE binary - # installed, and pip hashes verify: - install_le_auto(build_le_auto(version='50.0.0'), le_auto_path) - out, err = run_letsencrypt_auto() - self.assertTrue(re.match(r'letsencrypt \d+\.\d+\.\d+', - err.strip().splitlines()[-1])) - # Make a few assertions to test the validity of the next tests: - self.assertTrue('Upgrading certbot-auto ' in out) - self.assertTrue('Creating virtual environment...' in out) - - # Now we have le-auto 99.9.9 and LE 99.9.9 installed. This - # conveniently sets us up to test the next 2 cases. - - # Test when neither phase-1 upgrade nor phase-2 upgrade is - # needed (probably a common case): - out, err = run_letsencrypt_auto() - self.assertFalse('Upgrading certbot-auto ' in out) - self.assertFalse('Creating virtual environment...' in out) - - def test_phase2_upgrade(self): - """Test a phase-2 upgrade without a phase-1 upgrade.""" - resources = {'certbot/json': dumps({'releases': {'99.9.9': None}}), - 'v99.9.9/letsencrypt-auto': self.NEW_LE_AUTO, - 'v99.9.9/letsencrypt-auto.sig': self.NEW_LE_AUTO_SIG} - with serving(resources) as base_url: - pip_find_links=join(tests_dir(), 'fake-letsencrypt', 'dist') - with temp_paths() as (le_auto_path, venv_dir): - install_le_auto(self.NEW_LE_AUTO, le_auto_path) - - # Create venv saving the correct bootstrap script version - out, err = run_le_auto(le_auto_path, venv_dir, base_url, - PIP_FIND_LINKS=pip_find_links) - self.assertFalse('Upgrading certbot-auto ' in out) - self.assertTrue('Creating virtual environment...' in out) - with open(join(venv_dir, BOOTSTRAP_FILENAME)) as f: - bootstrap_version = f.read() - - # Create a new venv with an old letsencrypt version - with temp_paths() as (le_auto_path, venv_dir): - venv_bin = join(venv_dir, 'bin') - makedirs(venv_bin) - set_le_script_version(venv_dir, '0.0.1') - with open(join(venv_dir, BOOTSTRAP_FILENAME), 'w') as f: - f.write(bootstrap_version) - - install_le_auto(self.NEW_LE_AUTO, le_auto_path) - out, err = run_le_auto(le_auto_path, venv_dir, base_url, - PIP_FIND_LINKS=pip_find_links) - - self.assertFalse('Upgrading certbot-auto ' in out) - self.assertTrue('Creating virtual environment...' in out) - - def test_openssl_failure(self): - """Make sure we stop if the openssl signature check fails.""" - with temp_paths() as (le_auto_path, venv_dir): - # Serve an unrelated hash signed with the good key (easier than - # making a bad key, and a mismatch is a mismatch): - resources = {'': 'certbot/', - 'certbot/json': dumps({'releases': {'99.9.9': None}}), - 'v99.9.9/letsencrypt-auto': build_le_auto(version='99.9.9'), - 'v99.9.9/letsencrypt-auto.sig': signed('something else')} - with serving(resources) as base_url: - copy_stable(LE_AUTO_PATH, le_auto_path) - try: - out, err = run_le_auto(le_auto_path, venv_dir, base_url) - except CalledProcessError as exc: - self.assertEqual(exc.returncode, 1) - self.assertTrue("Couldn't verify signature of downloaded " - "certbot-auto." in exc.output) - else: - print(out) - self.fail('Signature check on certbot-auto erroneously passed.') - - def test_pip_failure(self): - """Make sure pip stops us if there is a hash mismatch.""" - with temp_paths() as (le_auto_path, venv_dir): - resources = {'': 'certbot/', - 'certbot/json': dumps({'releases': {'99.9.9': None}})} - with serving(resources) as base_url: - # Build a le-auto script embedding a bad requirements file: - install_le_auto( - build_le_auto( - version='99.9.9', - requirements='configobj==5.0.6 --hash=sha256:badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadb'), - le_auto_path) - try: - out, err = run_le_auto(le_auto_path, venv_dir, base_url) - except CalledProcessError as exc: - self.assertEqual(exc.returncode, 1) - self.assertTrue("THESE PACKAGES DO NOT MATCH THE HASHES " - "FROM THE REQUIREMENTS FILE" in exc.output) - self.assertFalse( - exists(venv_dir), - msg="The virtualenv was left around, even though " - "installation didn't succeed. We shouldn't do " - "this, as it foils our detection of whether we " - "need to recreate the virtualenv, which hinges " - "on the presence of $VENV_BIN/letsencrypt.") - else: - self.fail("Pip didn't detect a bad hash and stop the " - "installation.") - - def test_permissions_warnings(self): - """Make sure letsencrypt-auto properly warns about permissions problems.""" - # This test assumes that only the parent of the directory containing - # letsencrypt-auto (usually /tmp) may have permissions letsencrypt-auto - # considers insecure. - with temp_paths() as (le_auto_path, venv_dir): - le_auto_path = abspath(le_auto_path) - le_auto_dir = dirname(le_auto_path) - le_auto_dir_parent = dirname(le_auto_dir) - install_le_auto(self.NEW_LE_AUTO, le_auto_path) - - run_letsencrypt_auto = partial( - run_le_auto, le_auto_path, venv_dir, - le_auto_args_str='--install-only --no-self-upgrade', - PIP_FIND_LINKS=join(tests_dir(), 'fake-letsencrypt', 'dist')) - # Run letsencrypt-auto once with current permissions to avoid - # potential problems when the script tries to write to temporary - # directories. - run_letsencrypt_auto() - - le_auto_dir_mode = stat(le_auto_dir).st_mode - le_auto_dir_parent_mode = S_IMODE(stat(le_auto_dir_parent).st_mode) - try: - # Make letsencrypt-auto happy with the current permissions - chmod(le_auto_dir, S_IRUSR | S_IXUSR) - sudo_chmod(le_auto_dir_parent, 0o755) - - self._test_permissions_warnings_about_path(le_auto_path, run_letsencrypt_auto) - self._test_permissions_warnings_about_path(le_auto_dir, run_letsencrypt_auto) - finally: - chmod(le_auto_dir, le_auto_dir_mode) - sudo_chmod(le_auto_dir_parent, le_auto_dir_parent_mode) - - def _test_permissions_warnings_about_path(self, path, run_le_auto_func): - # Test that there are no problems with the current permissions - out, _ = run_le_auto_func() - self.assertFalse('insecure permissions' in out) - - stat_result = stat(path) - original_mode = stat_result.st_mode - - # Test world permissions - chmod(path, original_mode | S_IWOTH) - out, _ = run_le_auto_func() - self.assertTrue('insecure permissions' in out) - - # Test group permissions - if stat_result.st_gid >= 1000: - chmod(path, original_mode | S_IWGRP) - out, _ = run_le_auto_func() - self.assertTrue('insecure permissions' in out) - - # Test owner permissions - if stat_result.st_uid >= 1000: - chmod(path, original_mode | S_IWUSR) - out, _ = run_le_auto_func() - self.assertTrue('insecure permissions' in out) - - # Test that permissions were properly restored - chmod(path, original_mode) - out, _ = run_le_auto_func() - self.assertFalse('insecure permissions' in out) - - def test_disabled_permissions_warnings(self): - """Make sure that letsencrypt-auto permissions warnings can be disabled.""" - with temp_paths() as (le_auto_path, venv_dir): - le_auto_path = abspath(le_auto_path) - install_le_auto(self.NEW_LE_AUTO, le_auto_path) - - le_auto_args_str='--install-only --no-self-upgrade' - pip_links=join(tests_dir(), 'fake-letsencrypt', 'dist') - out, _ = run_le_auto(le_auto_path, venv_dir, - le_auto_args_str=le_auto_args_str, - PIP_FIND_LINKS=pip_links) - self.assertTrue('insecure permissions' in out) - - # Test that warnings are disabled when the script isn't run as - # root. - out, _ = run_le_auto(le_auto_path, venv_dir, - le_auto_args_str=le_auto_args_str, - LE_AUTO_SUDO='', - PIP_FIND_LINKS=pip_links) - self.assertFalse('insecure permissions' in out) - - # Test that --no-permissions-check disables warnings. - le_auto_args_str += ' --no-permissions-check' - out, _ = run_le_auto( - le_auto_path, venv_dir, - le_auto_args_str=le_auto_args_str, - PIP_FIND_LINKS=pip_links) - self.assertFalse('insecure permissions' in out) diff --git a/letsencrypt-auto-source/tests/centos6_tests.sh b/letsencrypt-auto-source/tests/centos6_tests.sh deleted file mode 100644 index 8bdffec87..000000000 --- a/letsencrypt-auto-source/tests/centos6_tests.sh +++ /dev/null @@ -1,173 +0,0 @@ -#!/bin/bash -set -e -# Start by making sure your system is up-to-date: -yum update -y >/dev/null -yum install -y centos-release-scl >/dev/null -yum install -y python27 >/dev/null 2>/dev/null - -LE_AUTO_PY_34="certbot/letsencrypt-auto-source/letsencrypt-auto_py_34" -LE_AUTO="certbot/letsencrypt-auto-source/letsencrypt-auto" - -# Last version of certbot-auto that was bootstraping Python 3.4 for CentOS 6 users -INITIAL_CERTBOT_VERSION_PY34="certbot 0.38.0" - -# we're going to modify env variables, so do this in a subshell -( -# ensure CentOS6 32bits is not supported anymore, and so certbot is not installed -export UNAME_FAKE_32BITS=true -if ! "$LE_AUTO" 2>&1 | grep -q "Certbot cannot be installed."; then - echo "ERROR: certbot-auto installed certbot on 32-bit CentOS." - exit 1 -fi -) - -echo "PASSED: On CentOS 6 32 bits, certbot-auto refused to install certbot." - -# we're going to modify env variables, so do this in a subshell -( - . /opt/rh/python27/enable - - # ensure python 3 isn't installed - if python3 --version 2> /dev/null; then - echo "ERROR: Python3 is already installed." - exit 1 - fi - - # ensure python2.7 is available - if ! python2.7 --version 2> /dev/null; then - echo "ERROR: Python2.7 is not available." - exit 1 - fi - - # bootstrap, but don't install python 3. - "$LE_AUTO" --no-self-upgrade -n --version > /dev/null 2> /dev/null - - # ensure python 3 isn't installed - if python3 --version 2> /dev/null; then - echo "ERROR: letsencrypt-auto installed Python3 even though Python2.7 is present." - exit 1 - fi - - echo "PASSED: Did not upgrade to Python3 when Python2.7 is present." -) - -# ensure python2.7 isn't available -if python2.7 --version 2> /dev/null; then - echo "ERROR: Python2.7 is still available." - exit 1 -fi - -# Skip self upgrade due to Python 3 not being available. -if ! "$LE_AUTO" 2>&1 | grep -q "WARNING: couldn't find Python"; then - echo "ERROR: Python upgrade failure warning not printed!" - exit 1 -fi - -# bootstrap from the old letsencrypt-auto, this time installing python3.4 -"$LE_AUTO_PY_34" --no-self-upgrade -n --version >/dev/null 2>/dev/null - -# ensure python 3.4 is installed -if ! python3.4 --version >/dev/null 2>/dev/null; then - echo "ERROR: letsencrypt-auto failed to install Python3.4 using letsencrypt-auto < 0.37.0 when only Python2.6 is present." - exit 1 -fi - -echo "PASSED: Successfully upgraded to Python3.4 using letsencrypt-auto < 0.37.0 when only Python2.6 is present." - -# As "certbot-auto" (so without implicit --non-interactive flag set), check that the script -# refuses to install SCL Python 3.6 when run in a non interactive shell (simulated here -# using | tee /dev/null) if --non-interactive flag is not provided. -cp "$LE_AUTO" /tmp/certbot-auto -# NB: Readline has an issue on all Python versions for CentOS 6, making `certbot --version` -# output an unprintable ASCII character on a new line at the end. -# So we take the second last line of the output. -version=$(/tmp/certbot-auto --version 2>/dev/null | tee /dev/null | tail -2 | head -1) - -if [ "$version" != "$INITIAL_CERTBOT_VERSION_PY34" ]; then - echo "ERROR: certbot-auto upgraded certbot in a non-interactive shell with --non-interactive flag not set." - exit 1 -fi - -echo "PASSED: certbot-auto did not upgrade certbot in a non-interactive shell with --non-interactive flag not set." - -if [ -f /opt/rh/rh-python36/enable ]; then - echo "ERROR: certbot-auto installed Python3.6 in a non-interactive shell with --non-interactive flag not set." - exit 1 -fi - -echo "PASSED: certbot-auto did not install Python3.6 in a non-interactive shell with --non-interactive flag not set." - -# now bootstrap from current letsencrypt-auto, that will install python3.6 from SCL -"$LE_AUTO" --no-self-upgrade -n --version >/dev/null 2>/dev/null - -# Following test is executed in a subshell, to not leak any environment variable -( - # enable SCL rh-python36 - . /opt/rh/rh-python36/enable - - # ensure python 3.6 is installed - if ! python3.6 --version >/dev/null 2>/dev/null; then - echo "ERROR: letsencrypt-auto failed to install Python3.6 using current letsencrypt-auto when only Python2.6/Python3.4 are present." - exit 1 - fi - - echo "PASSED: Successfully upgraded to Python3.6 using current letsencrypt-auto when only Python2.6/Python3.4 are present." -) - -# Following test is executed in a subshell, to not leak any environment variable -( - export VENV_PATH=$(mktemp -d) - "$LE_AUTO" -n --no-bootstrap --no-self-upgrade --version >/dev/null 2>&1 - if [ "$($VENV_PATH/bin/python -V 2>&1 | cut -d" " -f2 | cut -d. -f1-2)" != "3.6" ]; then - echo "ERROR: Python 3.6 wasn't used with --no-bootstrap!" - exit 1 - fi -) - -# Following test is executed in a subshell, to not leak any environment variable -( - # enable SCL rh-python36 - . /opt/rh/rh-python36/enable - - # ensure everything works fine with certbot-auto bootstrap when python 3.6 is already enabled - export VENV_PATH=$(mktemp -d) - if ! "$LE_AUTO" --no-self-upgrade -n --version >/dev/null 2>/dev/null; then - echo "ERROR: Certbot-auto broke when Python 3.6 SCL is already enabled." - exit 1 - fi -) - -# we're going to modify env variables, so do this in a subshell -( - # ensure CentOS6 32bits is not supported anymore, and so certbot - # is not upgraded nor reinstalled. - export UNAME_FAKE_32BITS=true - OUTPUT=$("$LE_AUTO" --version 2>&1) - if ! echo "$OUTPUT" | grep -q "Certbot will no longer receive updates."; then - echo "ERROR: certbot-auto failed to run or upgraded pre-existing Certbot instance on 32-bit CentOS 6." - exit 1 - fi - if ! "$LE_AUTO" --install-only 2>&1 | grep -q "Certbot cannot be installed."; then - echo "ERROR: certbot-auto reinstalled Certbot on 32-bit CentOS 6." - exit 1 - fi -) - -# we're going to modify env variables, so do this in a subshell -( - # Prepare a certbot installation in the old venv path - rm -rf /opt/eff.org - VENV_PATH=~/.local/share/letsencrypt "$LE_AUTO" --install-only > /dev/null 2> /dev/null - # fake 32 bits mode - export UNAME_FAKE_32BITS=true - OUTPUT=$("$LE_AUTO" --version 2>&1) - if ! echo "$OUTPUT" | grep -q "Certbot will no longer receive updates."; then - echo "ERROR: certbot-auto failed to run or upgraded pre-existing Certbot instance in the old venv path on 32-bit CentOS 6." - exit 1 - fi -) - -echo "PASSED: certbot-auto refused to install/upgrade certbot on 32-bit CentOS 6." - -# test using python3 -pytest -v -s certbot/letsencrypt-auto-source/tests diff --git a/letsencrypt-auto-source/tests/certs/ca/my-root-ca.crt.pem b/letsencrypt-auto-source/tests/certs/ca/my-root-ca.crt.pem deleted file mode 100644 index 4e4d29bd2..000000000 --- a/letsencrypt-auto-source/tests/certs/ca/my-root-ca.crt.pem +++ /dev/null @@ -1,23 +0,0 @@ ------BEGIN CERTIFICATE----- -MIID5jCCAs6gAwIBAgIJAI1Qkfyw88REMA0GCSqGSIb3DQEBBQUAMFUxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMRswGQYDVQQKExJNeSBCb2d1cyBS -b290IENlcnQxFDASBgNVBAMTC2V4YW1wbGUuY29tMB4XDTE1MTIwNDIwNTIxNVoX -DTQwMTIwMzIwNTIxNVowVTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3Rh -dGUxGzAZBgNVBAoTEk15IEJvZ3VzIFJvb3QgQ2VydDEUMBIGA1UEAxMLZXhhbXBs -ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQVQpQ2EH4gTJB -NJP6+ocT3xJwT8mSXYUnvzjj6iv+JxZiXRGzAPziNzrrSRKY0yDHF+UiJwuOerLa -n8laZkLb1Ogqzs2u64rKeb0xWv90Qp+eXG0J/1xb4dw+GExqe5QFo1JUJzO/eK7m -1S04SeFkN1qV9mD5yJUy7DGiTUzDHgCxM2tXMLusXYqkxsQQ9+2EJ7BEOK4YJGEx -Sign5FuSxb64PiNow6OA97CaLl7tV4INP4w195ueDRIaS4poeOep4s8U7IAdMjIZ -EryJgKNCij50xK92vPBBJSj0NOitltBlwoEqkOZpQCOZamFd6nvt78LQ6W8Am+l6 -y6oCON5JAgMBAAGjgbgwgbUwHQYDVR0OBBYEFAlrdStDhaayLLj89Whe3Gc+HE8y -MIGFBgNVHSMEfjB8gBQJa3UrQ4Wmsiy4/PVoXtxnPhxPMqFZpFcwVTELMAkGA1UE -BhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxGzAZBgNVBAoTEk15IEJvZ3VzIFJv -b3QgQ2VydDEUMBIGA1UEAxMLZXhhbXBsZS5jb22CCQCNUJH8sPPERDAMBgNVHRME -BTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQC7KAQfDTiNM3QO8Ic3x21CAPJUavkH -zshifN+Ei0+nmseHDTCTgsGfGDOToLUpUEZ4PuiHnz08UwRfd9wotc3SgY9ZaXMe -vRs8KUAF9EoyTvESzPyv2b6cS9NNMpj5y7KyXSyP17VoGbNavtiGQ4dwgEH6VgNl -0RtBvcSBv/tqxIIx1tWzL74tVEm0Kbd9BAZsYpQNKL8e6WXP35/j0PvCCvtofGrA -E8LTqMz4kCwnX+QaJIMJhBophRCsjXdAkvFbFxX0DGPztQtzIwBPcdMjsft7AFeE -0XchhDDXxw8YsbpvPfCvrD8XiiVuBycbnB1zt0LLVwB/QsCzUW9ImpLC ------END CERTIFICATE----- diff --git a/letsencrypt-auto-source/tests/certs/ca/my-root-ca.key.pem b/letsencrypt-auto-source/tests/certs/ca/my-root-ca.key.pem deleted file mode 100644 index 9caa7ddaa..000000000 --- a/letsencrypt-auto-source/tests/certs/ca/my-root-ca.key.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEA0FUKUNhB+IEyQTST+vqHE98ScE/Jkl2FJ7844+or/icWYl0R -swD84jc660kSmNMgxxflIicLjnqy2p/JWmZC29ToKs7NruuKynm9MVr/dEKfnlxt -Cf9cW+HcPhhManuUBaNSVCczv3iu5tUtOEnhZDdalfZg+ciVMuwxok1Mwx4AsTNr -VzC7rF2KpMbEEPfthCewRDiuGCRhMUooJ+RbksW+uD4jaMOjgPewmi5e7VeCDT+M -Nfebng0SGkuKaHjnqeLPFOyAHTIyGRK8iYCjQoo+dMSvdrzwQSUo9DTorZbQZcKB -KpDmaUAjmWphXep77e/C0OlvAJvpesuqAjjeSQIDAQABAoIBAH+qbVzneV3wxjwh -HUHi/p3VyHXc3xh7iNq3mwRH/1eK2nPCttLsGwwBbnC64dOXJfH7maWZKcLRPAMv -gfOM0RHn4bJB8tdrbizv91lke0DihvBDkWpb+1wvB4lh2Io0Wpwt3ojFUTfXm87G -+iQRWjbQmQlm5zyKh6uiBDSCjDTQdb9omZEBMAwlGPTZwt8TRUEtWd8QgW8FCHoB -iLER2WBwXdvn3PBtocI3VE6IYDSeZ81Xv+d7925RtVintT8Suk4toYwX+jfSz+wZ -sgHd5V6PSv9a7GUlWoUihD99D9wqDZE8IvMDZ5ofSAUd1KfICDtmsEyugY7u2yYZ -tYt49AECgYEA73f7ITMHg8JsUipqb6eG10gCRtRhkqrrO1g/TNeTBh3CTrQGb56e -y6kmUivn5gK46t3T2N4Ht4IR8fpLcJcbPYPQNulSjmWm5y6WduafXW/VCW1NA9Lc -FyGPkMxFCIVJTLFxfLFepBVvtUzLLDKGGtQxru/GNbBzjdtmVfDPIoECgYEA3rbM -cTfvj+jWrV1YsRbphyjy+k3OJEIVx6KA4s5d7Tp12UfYQp/B3HPhXXm5wqeo1Nos -UAEWZIMi1VoE8iu6jjeJ6uERtbKKQVed25Us/ff0jUPbxlXgiBOtRcllq9d9Srjm -ybHUgfjLsZ2/xpIcOl+oI5pDM9JvD8Sq4ZCFR8kCgYBK/H0tFjeiML2OtS2DLShy -PWBJIbQ0I0Vp3eZkf5TQc30m/ASP61G6YItZa9pAElYpZbEy1cQA2MAZz9DTvt2O -07ndmA57/KTY+6OuM+Vvctd5DjrxmZPFwoKcSvrLAkHDvETXUQtbwkKquRNeEawg -tpWgPAELSufEYhGXk8KpAQKBgBDCqPgMQZcO6rj5QWdyVfi5+C8mE9Fet8ziSdjH -twHXWG8VnQzGgQxaHCewtW4Ut/vsv1D2A/1kcQalU6H18IArZdGrRm3qFcV9FoAj -5dLnChxncu6mH9Odx3htA52/BcrNx3B+VYPCeXHQcVI8RKuP71NelJgdygXhwwpe -mekhAoGBAOUovnqylciYa9HRqo+xZk59eyX+ehhnlV8SeJ2K0PwaQkzQ0KYtCmE7 -kdSdhcv8h/IQKGaFfc/LyFMM/a26PfAeY5bj41UjkT0K5hQrYuL/52xaT401YLcb -Xo+bZz9K0hrdP7TdZFuTY/WxojXgjsVAuAN1NwnJumqxhzPh+hfl ------END RSA PRIVATE KEY----- diff --git a/letsencrypt-auto-source/tests/certs/ca/my-root-ca.srl b/letsencrypt-auto-source/tests/certs/ca/my-root-ca.srl deleted file mode 100644 index ad6d262b4..000000000 --- a/letsencrypt-auto-source/tests/certs/ca/my-root-ca.srl +++ /dev/null @@ -1 +0,0 @@ -D613482D0EF95DD0 diff --git a/letsencrypt-auto-source/tests/certs/localhost/cert.pem b/letsencrypt-auto-source/tests/certs/localhost/cert.pem deleted file mode 100644 index ac83535ce..000000000 --- a/letsencrypt-auto-source/tests/certs/localhost/cert.pem +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDKjCCAhICCQDWE0gtDvld0DANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJB -VTETMBEGA1UECBMKU29tZS1TdGF0ZTEbMBkGA1UEChMSTXkgQm9ndXMgUm9vdCBD -ZXJ0MRQwEgYDVQQDEwtleGFtcGxlLmNvbTAeFw0xNTEyMDQyMDU0MzFaFw00MDEy -MDMyMDU0MzFaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEw -HwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMTCWxvY2Fs -aG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK2WIIi86Mis4UQH -a5PrFbX2PBtQHbI3t3ekN1CewRsgQ/2X3lCeWhKmr3CJYXVgA7q/23PORQAiuV6y -DG2dQIrjeahWCXaCptTi49ljfVRTW2IxrHke/iA8TkDuZbWGzVLb8TB83ipBOD41 -SjuomoN4A/ktnIfbNqRqgjjHs2wwJHDfxPiCQlwyOayjHmdlh8cqfVE8rWEm5/3T -Iu0X1J53SammR1SbUmsLJNofxFYMK1ogHb0CaFEG9QuuUDPJl5K74Rr6InMQZKPn -ne4W3cGoALxPHAca7yicpSMSmdsmd6pqylc2Fdua7o/wf0SwShxS4A1DqA/HWLEM -V6MSEF8CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAz5sMAFG6W/ZEULZITkBTCU6P -NttpGiKufnqyBW5HyNylaczfnHnClvQjr8f/84xvKVcfC3xP0lz+92aIQqo+5L/n -v7gLhBFR4Vr2XwMt2qz2FpkaxmVwnhVAHaaC05WIKQ6W2gDwWT0u1K8YdTh+7mvN -AT9FW4vDgtNZWq4W/PePh9QCiOOQhGOuBYj/7zqLtz4XPifhi66ILIRDHiu0kond -3YMFcECIAf4MPT9vT0iNcWX+c8CfAixPt8nMD6bzOo3oTcfuZh/2enfgLbMqOlOi -uk72FM5VVPXTWAckJvL/vVjqsvDuJQKqbr0oUc3bdWbS36xtWZUycp4IQLguAQ== ------END CERTIFICATE----- diff --git a/letsencrypt-auto-source/tests/certs/localhost/localhost.csr.pem b/letsencrypt-auto-source/tests/certs/localhost/localhost.csr.pem deleted file mode 100644 index 8a6189f88..000000000 --- a/letsencrypt-auto-source/tests/certs/localhost/localhost.csr.pem +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIICnjCCAYYCAQAwWTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUx -ITAfBgNVBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAxMJbG9j -YWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArZYgiLzoyKzh -RAdrk+sVtfY8G1Adsje3d6Q3UJ7BGyBD/ZfeUJ5aEqavcIlhdWADur/bc85FACK5 -XrIMbZ1AiuN5qFYJdoKm1OLj2WN9VFNbYjGseR7+IDxOQO5ltYbNUtvxMHzeKkE4 -PjVKO6iag3gD+S2ch9s2pGqCOMezbDAkcN/E+IJCXDI5rKMeZ2WHxyp9UTytYSbn -/dMi7RfUnndJqaZHVJtSawsk2h/EVgwrWiAdvQJoUQb1C65QM8mXkrvhGvoicxBk -o+ed7hbdwagAvE8cBxrvKJylIxKZ2yZ3qmrKVzYV25ruj/B/RLBKHFLgDUOoD8dY -sQxXoxIQXwIDAQABoAAwDQYJKoZIhvcNAQEFBQADggEBAFbg3WrAokoPx7iAYG6z -PqeDd4/XanXjeL4Ryxv6LoGhu69mmBAd3N5ILPyQJjnkWpIjEmJDzEcPMzhQjRh5 -GlWTyvKWO4zClYU840KZk7crVkpzNZ+HP0YeM/Agz6sab00ffRcq5m1wEF9MCvDE -8FUXk1HBHRAb/6t9QV/7axsPOkGT8SjQ1v2SCaiB0HQL3sYChYLi5zu4dfmQNPGq -ar9Xm5a0YqOQIFfmy8RSwxk0Q/ipNFTGN1uvlIRkgbT9zPnodxjWZsSI9BF+q5Af -uiE/oAk7MxfJ0LyLfhOWB+T98bKIOVtFT3wMLS1IIgMogwqCEXFf30Q9p2iTEzqT -6UE= ------END CERTIFICATE REQUEST----- diff --git a/letsencrypt-auto-source/tests/certs/localhost/privkey.pem b/letsencrypt-auto-source/tests/certs/localhost/privkey.pem deleted file mode 100644 index 18feba403..000000000 --- a/letsencrypt-auto-source/tests/certs/localhost/privkey.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEArZYgiLzoyKzhRAdrk+sVtfY8G1Adsje3d6Q3UJ7BGyBD/Zfe -UJ5aEqavcIlhdWADur/bc85FACK5XrIMbZ1AiuN5qFYJdoKm1OLj2WN9VFNbYjGs -eR7+IDxOQO5ltYbNUtvxMHzeKkE4PjVKO6iag3gD+S2ch9s2pGqCOMezbDAkcN/E -+IJCXDI5rKMeZ2WHxyp9UTytYSbn/dMi7RfUnndJqaZHVJtSawsk2h/EVgwrWiAd -vQJoUQb1C65QM8mXkrvhGvoicxBko+ed7hbdwagAvE8cBxrvKJylIxKZ2yZ3qmrK -VzYV25ruj/B/RLBKHFLgDUOoD8dYsQxXoxIQXwIDAQABAoIBAG8bVJ+xKt6nqVg9 -16HKKw9ZGIfy888K0qgFuFImCzwtntdGycmYUdb2Uf0aMgNK/ZgfDXxGXuwDTdtK -46GVsaY0i74vs8bjQZ2pzGVsxN+gqzFi0h6Es+w2LXBqJzfVnL6YgPykMB+jtzg6 -K9Wbyaq0uvZXN4XNzl/WvJtTV4i7Cff1MOd5EhKFdqxrZvB/SRBCr/SMMafRtB9P -EvMneNKzhmlrutHAxuyxEKZR32Kkx7ydAdTjGgn+rE+NL5BweXfeWhLU4Bv14bn9 -Mkneu3w5o1ryJfE2YnVajUP//jeopUT0nTQ3MpEusBQCLBlvFXjjM9uCaFX+5+MP -0H4xVcECgYEA1Q+wR3GHbk37vIGSlbENyUsri5WlMt8IVAHsDsTOpxAjYB0yyo+x -h9RS+RJZQECJlA6H72peUl3GM7RgdWIcKOT3nZ12XqYKG57rr/N5zlUuxbdS8KBk -JhyZeJdYjq/Jrno1ZP+OSmc7VvBLcM7irY7LHlvK0o8W1W0TNJ8jrZkCgYEA0JHX -lJd+fiezcUS7g4moHtzJp0JKquQiXLX+c2urmpyhb3ZrTuQ8OUjSy6DlwHlgDx8K -Hg2sdx/ZCuDaGjR4IY/Qs5RFt9WUqlK9gi9V3nYVrzBOQkdFOf/Ad3j4pQ8/aeCX -nP6snHXz1WqPpbCXG6l6GzFGbQU473GfuKsDuLcCgYAWQaNKc0OQdDj9whNL68ji -5CVSWXl+TOoTzHeaO1jS/s6TNbmei1AiPj3EovQL0DIO802j5tqfhAg2UntZB7yl -UPXE0zQQQwv/QqSgJrDsqt1N7g6N8FNF3+rwO+8WSKqqvT1ipYd5ojsCo+tdh18K -fkYdj70qLaRW+yPsdUtG0QKBgEYc8NqbvsML94+ZKmwCh4iwcf2PFGi0PjTqXTpR -tKNKCh7dMR+ZLAGZ0HrxgKqeYsNSjOUjdZmqFB1LDyaGAuhNXzwvGOy+mLZVEC3G -Wdhp28pDs9sl+EiSCBJhkTxzjr656F23YzFJmYlhxB5P6cw7wbeIbgNSIRylFqtO -mfarAoGBAICsAEWypOctxtmtOcjxgJ7jMbOA7rrsGlXpiy1/WlwIwRGF5LMvIIFX -qFAfiPcZn05ZgdAGzaFYowdjmQB10FW0jZbDf+nIHfOF5YmfmfWjsaweEGALJmqB -okGu/lGNGf3XoYzy0/hC3WAqk3znSZtQLUq8jEWF7dLNUizUeUow ------END RSA PRIVATE KEY----- diff --git a/letsencrypt-auto-source/tests/certs/localhost/server.pem b/letsencrypt-auto-source/tests/certs/localhost/server.pem deleted file mode 100644 index c5765dd89..000000000 --- a/letsencrypt-auto-source/tests/certs/localhost/server.pem +++ /dev/null @@ -1,46 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEowIBAAKCAQEArZYgiLzoyKzhRAdrk+sVtfY8G1Adsje3d6Q3UJ7BGyBD/Zfe -UJ5aEqavcIlhdWADur/bc85FACK5XrIMbZ1AiuN5qFYJdoKm1OLj2WN9VFNbYjGs -eR7+IDxOQO5ltYbNUtvxMHzeKkE4PjVKO6iag3gD+S2ch9s2pGqCOMezbDAkcN/E -+IJCXDI5rKMeZ2WHxyp9UTytYSbn/dMi7RfUnndJqaZHVJtSawsk2h/EVgwrWiAd -vQJoUQb1C65QM8mXkrvhGvoicxBko+ed7hbdwagAvE8cBxrvKJylIxKZ2yZ3qmrK -VzYV25ruj/B/RLBKHFLgDUOoD8dYsQxXoxIQXwIDAQABAoIBAG8bVJ+xKt6nqVg9 -16HKKw9ZGIfy888K0qgFuFImCzwtntdGycmYUdb2Uf0aMgNK/ZgfDXxGXuwDTdtK -46GVsaY0i74vs8bjQZ2pzGVsxN+gqzFi0h6Es+w2LXBqJzfVnL6YgPykMB+jtzg6 -K9Wbyaq0uvZXN4XNzl/WvJtTV4i7Cff1MOd5EhKFdqxrZvB/SRBCr/SMMafRtB9P -EvMneNKzhmlrutHAxuyxEKZR32Kkx7ydAdTjGgn+rE+NL5BweXfeWhLU4Bv14bn9 -Mkneu3w5o1ryJfE2YnVajUP//jeopUT0nTQ3MpEusBQCLBlvFXjjM9uCaFX+5+MP -0H4xVcECgYEA1Q+wR3GHbk37vIGSlbENyUsri5WlMt8IVAHsDsTOpxAjYB0yyo+x -h9RS+RJZQECJlA6H72peUl3GM7RgdWIcKOT3nZ12XqYKG57rr/N5zlUuxbdS8KBk -JhyZeJdYjq/Jrno1ZP+OSmc7VvBLcM7irY7LHlvK0o8W1W0TNJ8jrZkCgYEA0JHX -lJd+fiezcUS7g4moHtzJp0JKquQiXLX+c2urmpyhb3ZrTuQ8OUjSy6DlwHlgDx8K -Hg2sdx/ZCuDaGjR4IY/Qs5RFt9WUqlK9gi9V3nYVrzBOQkdFOf/Ad3j4pQ8/aeCX -nP6snHXz1WqPpbCXG6l6GzFGbQU473GfuKsDuLcCgYAWQaNKc0OQdDj9whNL68ji -5CVSWXl+TOoTzHeaO1jS/s6TNbmei1AiPj3EovQL0DIO802j5tqfhAg2UntZB7yl -UPXE0zQQQwv/QqSgJrDsqt1N7g6N8FNF3+rwO+8WSKqqvT1ipYd5ojsCo+tdh18K -fkYdj70qLaRW+yPsdUtG0QKBgEYc8NqbvsML94+ZKmwCh4iwcf2PFGi0PjTqXTpR -tKNKCh7dMR+ZLAGZ0HrxgKqeYsNSjOUjdZmqFB1LDyaGAuhNXzwvGOy+mLZVEC3G -Wdhp28pDs9sl+EiSCBJhkTxzjr656F23YzFJmYlhxB5P6cw7wbeIbgNSIRylFqtO -mfarAoGBAICsAEWypOctxtmtOcjxgJ7jMbOA7rrsGlXpiy1/WlwIwRGF5LMvIIFX -qFAfiPcZn05ZgdAGzaFYowdjmQB10FW0jZbDf+nIHfOF5YmfmfWjsaweEGALJmqB -okGu/lGNGf3XoYzy0/hC3WAqk3znSZtQLUq8jEWF7dLNUizUeUow ------END RSA PRIVATE KEY----- ------BEGIN CERTIFICATE----- -MIIDKjCCAhICCQDWE0gtDvld0DANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJB -VTETMBEGA1UECBMKU29tZS1TdGF0ZTEbMBkGA1UEChMSTXkgQm9ndXMgUm9vdCBD -ZXJ0MRQwEgYDVQQDEwtleGFtcGxlLmNvbTAeFw0xNTEyMDQyMDU0MzFaFw00MDEy -MDMyMDU0MzFaMFkxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEw -HwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMTCWxvY2Fs -aG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK2WIIi86Mis4UQH -a5PrFbX2PBtQHbI3t3ekN1CewRsgQ/2X3lCeWhKmr3CJYXVgA7q/23PORQAiuV6y -DG2dQIrjeahWCXaCptTi49ljfVRTW2IxrHke/iA8TkDuZbWGzVLb8TB83ipBOD41 -SjuomoN4A/ktnIfbNqRqgjjHs2wwJHDfxPiCQlwyOayjHmdlh8cqfVE8rWEm5/3T -Iu0X1J53SammR1SbUmsLJNofxFYMK1ogHb0CaFEG9QuuUDPJl5K74Rr6InMQZKPn -ne4W3cGoALxPHAca7yicpSMSmdsmd6pqylc2Fdua7o/wf0SwShxS4A1DqA/HWLEM -V6MSEF8CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAz5sMAFG6W/ZEULZITkBTCU6P -NttpGiKufnqyBW5HyNylaczfnHnClvQjr8f/84xvKVcfC3xP0lz+92aIQqo+5L/n -v7gLhBFR4Vr2XwMt2qz2FpkaxmVwnhVAHaaC05WIKQ6W2gDwWT0u1K8YdTh+7mvN -AT9FW4vDgtNZWq4W/PePh9QCiOOQhGOuBYj/7zqLtz4XPifhi66ILIRDHiu0kond -3YMFcECIAf4MPT9vT0iNcWX+c8CfAixPt8nMD6bzOo3oTcfuZh/2enfgLbMqOlOi -uk72FM5VVPXTWAckJvL/vVjqsvDuJQKqbr0oUc3bdWbS36xtWZUycp4IQLguAQ== ------END CERTIFICATE----- diff --git a/letsencrypt-auto-source/tests/fake-letsencrypt/dist/letsencrypt-99.9.9.tar.gz b/letsencrypt-auto-source/tests/fake-letsencrypt/dist/letsencrypt-99.9.9.tar.gz deleted file mode 100644 index 5f9a48a34a22ca70c28ac318336ba986ea32b60e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 876 zcmV-y1C#t8iwFqixs_G||72-%bT4dWbaQ2HV{&NJ*NTsMH6vyVzPZ#P-0dC^Sy-NbJaQ%c^PreNIB#Gy@8>WScl&h0@r$ z7>>V_6B84e5jGODRO*L^ZS^^5Z5u=3IZnPcJ;$hS=d{d@Yde-@d$u~xwA_x-!cMCJ zCYcNb#;uFw`rhN#_0NBi`Sw2{{xklSrgl1OApTazTE^eVBxu26o1K6KPFQWx8)DH<@|4$_G1AL9S%;Oz6OH>Xc{ z`mgujGVA`Ej@p3#&BkB7@}v2?Ke}}ioE*Q?KlI-Y(7Gvt9{dcs{mAP3+}%fQQj-FY z^S>UEt=9i;r~dpmU0DBVg!9@G$q?PYK7ycNc#;0kQ~y)ff9`$$J5J4i!^_uy!2jpx z6Olm}$Uy&6F1U8F*)~u=NJzKpK3a5_lLVbkk|YqbE`IvjE_%-sqNl-F-Ri7=+#h`H zqoawu6P0@6W$Q;eA}p(%_IkP6ylgy)0~v9VEL%YLhxosV>f7<(w7vZQ|KLCP z5B@jqfB6nLipEX(Z+KSCf5)~>@V}AzUsZU1Uf~Uq495P&gvOyN`->fw7l`_96g%0J z`GQPoVR_yNHUR(t0000000000000000000000000000000002|4SoYxfON0`PyhhZ CB*3r$ diff --git a/letsencrypt-auto-source/tests/fake-letsencrypt/letsencrypt.py b/letsencrypt-auto-source/tests/fake-letsencrypt/letsencrypt.py deleted file mode 100755 index 9d811fab5..000000000 --- a/letsencrypt-auto-source/tests/fake-letsencrypt/letsencrypt.py +++ /dev/null @@ -1,8 +0,0 @@ -from sys import argv, stderr - - -def main(): - """Act like letsencrypt --version insofar as printing the version number to - stderr.""" - if '--version' in argv: - stderr.write('letsencrypt 99.9.9\n') diff --git a/letsencrypt-auto-source/tests/fake-letsencrypt/setup.py b/letsencrypt-auto-source/tests/fake-letsencrypt/setup.py deleted file mode 100644 index e5f7fde35..000000000 --- a/letsencrypt-auto-source/tests/fake-letsencrypt/setup.py +++ /dev/null @@ -1,12 +0,0 @@ -from setuptools import setup - - -setup( - name='letsencrypt', - version='99.9.9', - description='A mock version of letsencrypt that just prints its version', - py_modules=['letsencrypt'], - entry_points={ - 'console_scripts': ['letsencrypt = letsencrypt:main'] - } -) diff --git a/letsencrypt-auto-source/tests/oraclelinux6_tests.sh b/letsencrypt-auto-source/tests/oraclelinux6_tests.sh deleted file mode 100644 index f3fd952f3..000000000 --- a/letsencrypt-auto-source/tests/oraclelinux6_tests.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/bash -set -eo pipefail -# Start by making sure your system is up-to-date: -yum update -y >/dev/null - -LE_AUTO_PY_34="certbot/letsencrypt-auto-source/letsencrypt-auto_py_34" -LE_AUTO="certbot/letsencrypt-auto-source/letsencrypt-auto" - -# Apply installation instructions from official documentation: -# https://certbot.eff.org/lets-encrypt/centosrhel6-other -cp "$LE_AUTO" /usr/local/bin/certbot-auto -chown root /usr/local/bin/certbot-auto -chmod 0755 /usr/local/bin/certbot-auto -LE_AUTO=/usr/local/bin/certbot-auto - -# Last version of certbot-auto that was bootstraping Python 3.4 for CentOS 6 users -INITIAL_CERTBOT_VERSION_PY34="certbot 0.38.0" - -# Check bootstrap from current certbot-auto will fail, because SCL is not enabled. -set +o pipefail -if ! "$LE_AUTO" -n 2>&1 | grep -q "Enable the SCL repository and try running Certbot again."; then - echo "ERROR: Bootstrap was not aborted although SCL was not installed!" - exit 1 -fi -set -o pipefail - -echo "PASSED: Bootstrap was aborted since SCL was not installed." - -# Bootstrap from the old letsencrypt-auto, Python 3.4 will be installed from EPEL. -"$LE_AUTO_PY_34" --no-self-upgrade -n --install-only >/dev/null 2>/dev/null - -# Ensure Python 3.4 is installed -if ! command -v python3.4 &>/dev/null; then - echo "ERROR: old letsencrypt-auto failed to install Python3.4 using letsencrypt-auto < 0.37.0 when only Python2.6 is present." - exit 1 -fi - -echo "PASSED: Bootstrap from old letsencrypt-auto succeeded and installed Python 3.4" - -# Expect certbot-auto to skip rebootstrapping with a warning since SCL is not installed. -if ! "$LE_AUTO" --non-interactive --version 2>&1 | grep -q "This requires manual user intervention"; then - echo "FAILED: Script certbot-auto did not print a warning about needing manual intervention!" - exit 1 -fi - -echo "PASSED: Script certbot-auto did not rebootstrap." - -# NB: Readline has an issue on all Python versions for OL 6, making `certbot --version` -# output an unprintable ASCII character on a new line at the end. -# So we take the second last line of the output. -version=$($LE_AUTO --version 2>/dev/null | tail -2 | head -1) - -if [ "$version" != "$INITIAL_CERTBOT_VERSION_PY34" ]; then - echo "ERROR: Script certbot-auto upgraded certbot in a non-interactive shell while SCL was not enabled." - exit 1 -fi - -echo "PASSED: Script certbot-auto did not upgrade certbot but started it successfully while SCL was not enabled." - -# Enable SCL -yum install -y oracle-softwarecollection-release-el6 >/dev/null - -# Expect certbot-auto to bootstrap successfully since SCL is available. -"$LE_AUTO" -n --version &>/dev/null - -if [ "$(/opt/eff.org/certbot/venv/bin/python -V 2>&1 | cut -d" " -f2 | cut -d. -f1-2)" != "3.6" ]; then - echo "ERROR: Script certbot-auto failed to bootstrap and install Python 3.6 while SCL is available." - exit 1 -fi - -if ! /opt/eff.org/certbot/venv/bin/certbot --version > /dev/null 2> /dev/null; then - echo "ERROR: Script certbot-auto did not install certbot correctly while SCL is enabled." - exit 1 -fi - -echo "PASSED: Script certbot-auto correctly bootstraped Certbot using rh-python36 when SCL is available." - -# Expect certbot-auto will be totally silent now that everything has been correctly boostraped. -OUTPUT_LEN=$("$LE_AUTO" --install-only --no-self-upgrade --quiet 2>&1 | wc -c) -if [ "$OUTPUT_LEN" != 0 ]; then - echo certbot-auto produced unexpected output! - exit 1 -fi - -echo "PASSED: Script certbot-auto did not print anything in quiet mode." diff --git a/letsencrypt-auto-source/tests/uname_wrapper.sh b/letsencrypt-auto-source/tests/uname_wrapper.sh deleted file mode 100644 index df1f568c6..000000000 --- a/letsencrypt-auto-source/tests/uname_wrapper.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -set -e - -uname_output=$(/bin/uname_orig "$@") - -if [ "$UNAME_FAKE_32BITS" = true ]; then - uname_output="${uname_output//x86_64/i686}" -fi - -echo "$uname_output" diff --git a/tests/letstest/scripts/test_leauto_upgrades.sh b/tests/letstest/scripts/test_leauto_upgrades.sh index 51ff640c5..1eeafad21 100755 --- a/tests/letstest/scripts/test_leauto_upgrades.sh +++ b/tests/letstest/scripts/test_leauto_upgrades.sh @@ -105,15 +105,10 @@ if ./letsencrypt-auto -v --debug --version | grep "WARNING: couldn't find Python exit 1 fi -# On systems like Debian where certbot-auto is deprecated, we expect it to -# leave existing Certbot installations unmodified so we check for the same -# version that was initially installed below. Once certbot-auto is deprecated -# on RHEL systems, we can unconditionally check for INITIAL_VERSION. -if [ -f /etc/debian_version ]; then - EXPECTED_VERSION="$INITIAL_VERSION" -else - EXPECTED_VERSION=$(grep -m1 LE_AUTO_VERSION certbot-auto | cut -d\" -f2) -fi +# Since certbot-auto is deprecated, we expect it to leave existing Certbot +# installations unmodified so we check for the same version that was initially +# installed below. +EXPECTED_VERSION="$INITIAL_VERSION" if ! /opt/eff.org/certbot/venv/bin/letsencrypt --version 2>&1 | tail -n1 | grep "^certbot $EXPECTED_VERSION$" ; then echo unexpected certbot version found @@ -124,22 +119,3 @@ if ! diff letsencrypt-auto letsencrypt-auto-source/letsencrypt-auto ; then echo letsencrypt-auto and letsencrypt-auto-source/letsencrypt-auto differ exit 1 fi - -if [ "$RUN_RHEL6_TESTS" = 1 ]; then - # Add the SCL python release to PATH in order to resolve python3 command - PATH="/opt/rh/rh-python36/root/usr/bin:$PATH" - if ! command -v python3; then - echo "Python3 wasn't properly installed" - exit 1 - fi - if [ "$(/opt/eff.org/certbot/venv/bin/python -V 2>&1 | cut -d" " -f 2 | cut -d. -f1)" != 3 ]; then - echo "Python3 wasn't used in venv!" - exit 1 - fi - - if [ "$("$PYTHON_NAME" tools/readlink.py $OLD_VENV_PATH)" != "/opt/eff.org/certbot/venv" ]; then - echo symlink from old venv path not properly created! - exit 1 - fi -fi -echo upgrade appeared to be successful diff --git a/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh b/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh index 15cf9ee1b..fc5435916 100755 --- a/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh +++ b/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh @@ -16,58 +16,14 @@ sudo chown root "$LE_AUTO_PATH" sudo chmod 0755 "$LE_AUTO_PATH" export PATH="$LE_AUTO_DIR:$PATH" -# On systems like Debian where certbot-auto is deprecated, we expect -# certbot-auto to error and refuse to install Certbot. Once certbot-auto is -# deprecated on RHEL systems, we can unconditionally run this code. -if [ -f /etc/debian_version ]; then - set +o pipefail - if ! letsencrypt-auto --debug --version | grep "Certbot cannot be installed."; then - echo "letsencrypt-auto didn't report being uninstallable." - exit 1 - fi - if [ ${PIPESTATUS[0]} != 1 ]; then - echo "letsencrypt-auto didn't exit with status 1 as expected" - exit 1 - fi - # letsencrypt-auto is deprecated and cannot be installed on this system so - # we cannot run the rest of this test. - exit 0 -fi - -letsencrypt-auto --os-packages-only --debug --version - -# This script sets the environment variables PYTHON_NAME, VENV_PATH, and -# VENV_SCRIPT based on the version of Python available on the system. For -# instance, Fedora uses Python 3 and Python 2 is not installed. -. tests/letstest/scripts/set_python_envvars.sh - -# Create a venv-like layout at the old virtual environment path to test that a -# symlink is properly created when letsencrypt-auto runs. -HOME=${HOME:-~root} -XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} -OLD_VENV_BIN="$XDG_DATA_HOME/letsencrypt/bin" -mkdir -p "$OLD_VENV_BIN" -touch "$OLD_VENV_BIN/letsencrypt" - -letsencrypt-auto certonly --no-self-upgrade -v --standalone --debug \ - --text --agree-tos \ - --renew-by-default --redirect \ - --register-unsafely-without-email \ - --domain $PUBLIC_HOSTNAME --server $BOULDER_URL - -LINK_PATH=$("$PYTHON_NAME" tools/readlink.py ${XDG_DATA_HOME:-~/.local/share}/letsencrypt) -if [ "$LINK_PATH" != "/opt/eff.org/certbot/venv" ]; then - echo symlink from old venv path not properly created! +# Since certbot-auto is deprecated, we expect certbot-auto to error and +# refuse to install Certbot. +set +o pipefail +if ! letsencrypt-auto --debug --version | grep "Certbot cannot be installed."; then + echo "letsencrypt-auto didn't report being uninstallable." exit 1 fi - -if ! letsencrypt-auto --help --no-self-upgrade | grep -F "letsencrypt-auto [SUBCOMMAND]"; then - echo "letsencrypt-auto not included in help output!" - exit 1 -fi - -OUTPUT_LEN=$(letsencrypt-auto --install-only --no-self-upgrade --quiet 2>&1 | wc -c) -if [ "$OUTPUT_LEN" != 0 ]; then - echo letsencrypt-auto produced unexpected output! +if [ ${PIPESTATUS[0]} != 1 ]; then + echo "letsencrypt-auto didn't exit with status 1 as expected" exit 1 fi diff --git a/tox.ini b/tox.ini index 7f806bb4d..f87c1dbca 100644 --- a/tox.ini +++ b/tox.ini @@ -188,29 +188,6 @@ whitelist_externals = passenv = DOCKER_* -[testenv:le_auto_centos6] -# At the moment, this tests under Python 2.6 only, as only that version is -# readily available on the CentOS 6 Docker image. -commands = - python {toxinidir}/tests/modification-check.py - docker build -f letsencrypt-auto-source/Dockerfile.redhat6 --build-arg REDHAT_DIST_FLAVOR=centos -t lea letsencrypt-auto-source - docker run --rm -t lea -whitelist_externals = - docker -passenv = - DOCKER_* - TARGET_BRANCH - -[testenv:le_auto_oraclelinux6] -# At the moment, this tests under Python 2.6 only, as only that version is -# readily available on the Oracle Linux 6 Docker image. -commands = - docker build -f letsencrypt-auto-source/Dockerfile.redhat6 --build-arg REDHAT_DIST_FLAVOR=oraclelinux -t lea letsencrypt-auto-source - docker run --rm -t lea -whitelist_externals = - docker -passenv = DOCKER_* - [testenv:docker_dev] # tests the Dockerfile-dev file to ensure development with it works # as expected From 7497c51f3456517e61465ced9b446794d8075d90 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 2 Dec 2020 09:44:27 -0800 Subject: [PATCH 25/42] Undo certbot-auto changes and remove centos6 tests * Don't deprecate certbot-auto quite yet * Remove centos6 test farm tests * undo changes to test farm test scripts (cherry picked from commit e5113d5815a1118d0720e29424cb98ea06957b4d) --- letsencrypt-auto-source/letsencrypt-auto | 106 +++++++++++++++++- .../letsencrypt-auto.template | 106 +++++++++++++++++- tests/letstest/auto_targets.yaml | 11 -- .../letstest/scripts/test_leauto_upgrades.sh | 32 +++++- ...st_letsencrypt_auto_certonly_standalone.sh | 58 ++++++++-- tests/letstest/targets.yaml | 11 -- 6 files changed, 287 insertions(+), 37 deletions(-) diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 6082a7339..96b40c0c8 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -794,8 +794,110 @@ BootstrapMageiaCommon() { } -# Certbot-auto is now fully deprecated -DEPRECATED_OS=1 +# Set Bootstrap to the function that installs OS dependencies on this system +# and BOOTSTRAP_VERSION to the unique identifier for the current version of +# that function. If Bootstrap is set to a function that doesn't install any +# packages BOOTSTRAP_VERSION is not set. +if [ -f /etc/debian_version ]; then + DEPRECATED_OS=1 +elif [ -f /etc/mageia-release ]; then + # Mageia has both /etc/mageia-release and /etc/redhat-release + DEPRECATED_OS=1 +elif [ -f /etc/redhat-release ]; then + # Run DeterminePythonVersion to decide on the basis of available Python versions + # whether to use 2.x or 3.x on RedHat-like systems. + # Then, revert LE_PYTHON to its previous state. + prev_le_python="$LE_PYTHON" + unset LE_PYTHON + DeterminePythonVersion "NOCRASH" + + RPM_DIST_NAME=`(. /etc/os-release 2> /dev/null && echo $ID) || echo "unknown"` + + if [ "$PYVER" -eq 26 -a $(uname -m) != 'x86_64' ]; then + # 32 bits CentOS 6 and affiliates are not supported anymore by certbot-auto. + DEPRECATED_OS=1 + fi + + # Set RPM_DIST_VERSION to VERSION_ID from /etc/os-release after splitting on + # '.' characters (e.g. "8.0" becomes "8"). If the command exits with an + # error, RPM_DIST_VERSION is set to "unknown". + RPM_DIST_VERSION=$( (. /etc/os-release 2> /dev/null && echo "$VERSION_ID") | cut -d '.' -f1 || echo "unknown") + + # If RPM_DIST_VERSION is an empty string or it contains any nonnumeric + # characters, the value is unexpected so we set RPM_DIST_VERSION to 0. + if [ -z "$RPM_DIST_VERSION" ] || [ -n "$(echo "$RPM_DIST_VERSION" | tr -d '[0-9]')" ]; then + RPM_DIST_VERSION=0 + fi + + # Handle legacy RPM distributions + if [ "$PYVER" -eq 26 ]; then + # Check if an automated bootstrap can be achieved on this system. + if ! Python36SclIsAvailable; then + INTERACTIVE_BOOTSTRAP=1 + fi + + Bootstrap() { + BootstrapMessage "Legacy RedHat-based OSes that will use Python3" + BootstrapRpmPython3Legacy + } + USE_PYTHON_3=1 + BOOTSTRAP_VERSION="BootstrapRpmPython3Legacy $BOOTSTRAP_RPM_PYTHON3_LEGACY_VERSION" + + # Try now to enable SCL rh-python36 for systems already bootstrapped + # NB: EnablePython36SCL has been defined along with BootstrapRpmPython3Legacy in certbot-auto + EnablePython36SCL + else + # Starting to Fedora 29, python2 is on a deprecation path. Let's move to python3 then. + # RHEL 8 also uses python3 by default. + if [ "$RPM_DIST_NAME" = "fedora" -a "$RPM_DIST_VERSION" -ge 29 ]; then + RPM_USE_PYTHON_3=1 + elif [ "$RPM_DIST_NAME" = "rhel" -a "$RPM_DIST_VERSION" -ge 8 ]; then + RPM_USE_PYTHON_3=1 + elif [ "$RPM_DIST_NAME" = "centos" -a "$RPM_DIST_VERSION" -ge 8 ]; then + RPM_USE_PYTHON_3=1 + else + RPM_USE_PYTHON_3=0 + fi + + if [ "$RPM_USE_PYTHON_3" = 1 ]; then + Bootstrap() { + BootstrapMessage "RedHat-based OSes that will use Python3" + BootstrapRpmPython3 + } + USE_PYTHON_3=1 + BOOTSTRAP_VERSION="BootstrapRpmPython3 $BOOTSTRAP_RPM_PYTHON3_VERSION" + else + Bootstrap() { + BootstrapMessage "RedHat-based OSes" + BootstrapRpmCommon + } + BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION" + fi + fi + + LE_PYTHON="$prev_le_python" +elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then + DEPRECATED_OS=1 +elif [ -f /etc/arch-release ]; then + DEPRECATED_OS=1 +elif [ -f /etc/manjaro-release ]; then + DEPRECATED_OS=1 +elif [ -f /etc/gentoo-release ]; then + DEPRECATED_OS=1 +elif uname | grep -iq FreeBSD ; then + DEPRECATED_OS=1 +elif uname | grep -iq Darwin ; then + DEPRECATED_OS=1 +elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then + Bootstrap() { + ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon + } + BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION" +elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then + DEPRECATED_OS=1 +else + DEPRECATED_OS=1 +fi # We handle this case after determining the normal bootstrap version to allow # variables like USE_PYTHON_3 to be properly set. As described above, if the diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index e4611abdf..5eb82b705 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -316,8 +316,110 @@ DeterminePythonVersion() { {{ bootstrappers/smartos.sh }} {{ bootstrappers/mageia_common.sh }} -# Certbot-auto is now fully deprecated -DEPRECATED_OS=1 +# Set Bootstrap to the function that installs OS dependencies on this system +# and BOOTSTRAP_VERSION to the unique identifier for the current version of +# that function. If Bootstrap is set to a function that doesn't install any +# packages BOOTSTRAP_VERSION is not set. +if [ -f /etc/debian_version ]; then + DEPRECATED_OS=1 +elif [ -f /etc/mageia-release ]; then + # Mageia has both /etc/mageia-release and /etc/redhat-release + DEPRECATED_OS=1 +elif [ -f /etc/redhat-release ]; then + # Run DeterminePythonVersion to decide on the basis of available Python versions + # whether to use 2.x or 3.x on RedHat-like systems. + # Then, revert LE_PYTHON to its previous state. + prev_le_python="$LE_PYTHON" + unset LE_PYTHON + DeterminePythonVersion "NOCRASH" + + RPM_DIST_NAME=`(. /etc/os-release 2> /dev/null && echo $ID) || echo "unknown"` + + if [ "$PYVER" -eq 26 -a $(uname -m) != 'x86_64' ]; then + # 32 bits CentOS 6 and affiliates are not supported anymore by certbot-auto. + DEPRECATED_OS=1 + fi + + # Set RPM_DIST_VERSION to VERSION_ID from /etc/os-release after splitting on + # '.' characters (e.g. "8.0" becomes "8"). If the command exits with an + # error, RPM_DIST_VERSION is set to "unknown". + RPM_DIST_VERSION=$( (. /etc/os-release 2> /dev/null && echo "$VERSION_ID") | cut -d '.' -f1 || echo "unknown") + + # If RPM_DIST_VERSION is an empty string or it contains any nonnumeric + # characters, the value is unexpected so we set RPM_DIST_VERSION to 0. + if [ -z "$RPM_DIST_VERSION" ] || [ -n "$(echo "$RPM_DIST_VERSION" | tr -d '[0-9]')" ]; then + RPM_DIST_VERSION=0 + fi + + # Handle legacy RPM distributions + if [ "$PYVER" -eq 26 ]; then + # Check if an automated bootstrap can be achieved on this system. + if ! Python36SclIsAvailable; then + INTERACTIVE_BOOTSTRAP=1 + fi + + Bootstrap() { + BootstrapMessage "Legacy RedHat-based OSes that will use Python3" + BootstrapRpmPython3Legacy + } + USE_PYTHON_3=1 + BOOTSTRAP_VERSION="BootstrapRpmPython3Legacy $BOOTSTRAP_RPM_PYTHON3_LEGACY_VERSION" + + # Try now to enable SCL rh-python36 for systems already bootstrapped + # NB: EnablePython36SCL has been defined along with BootstrapRpmPython3Legacy in certbot-auto + EnablePython36SCL + else + # Starting to Fedora 29, python2 is on a deprecation path. Let's move to python3 then. + # RHEL 8 also uses python3 by default. + if [ "$RPM_DIST_NAME" = "fedora" -a "$RPM_DIST_VERSION" -ge 29 ]; then + RPM_USE_PYTHON_3=1 + elif [ "$RPM_DIST_NAME" = "rhel" -a "$RPM_DIST_VERSION" -ge 8 ]; then + RPM_USE_PYTHON_3=1 + elif [ "$RPM_DIST_NAME" = "centos" -a "$RPM_DIST_VERSION" -ge 8 ]; then + RPM_USE_PYTHON_3=1 + else + RPM_USE_PYTHON_3=0 + fi + + if [ "$RPM_USE_PYTHON_3" = 1 ]; then + Bootstrap() { + BootstrapMessage "RedHat-based OSes that will use Python3" + BootstrapRpmPython3 + } + USE_PYTHON_3=1 + BOOTSTRAP_VERSION="BootstrapRpmPython3 $BOOTSTRAP_RPM_PYTHON3_VERSION" + else + Bootstrap() { + BootstrapMessage "RedHat-based OSes" + BootstrapRpmCommon + } + BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION" + fi + fi + + LE_PYTHON="$prev_le_python" +elif [ -f /etc/os-release ] && `grep -q openSUSE /etc/os-release` ; then + DEPRECATED_OS=1 +elif [ -f /etc/arch-release ]; then + DEPRECATED_OS=1 +elif [ -f /etc/manjaro-release ]; then + DEPRECATED_OS=1 +elif [ -f /etc/gentoo-release ]; then + DEPRECATED_OS=1 +elif uname | grep -iq FreeBSD ; then + DEPRECATED_OS=1 +elif uname | grep -iq Darwin ; then + DEPRECATED_OS=1 +elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then + Bootstrap() { + ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon + } + BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION" +elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then + DEPRECATED_OS=1 +else + DEPRECATED_OS=1 +fi # We handle this case after determining the normal bootstrap version to allow # variables like USE_PYTHON_3 to be properly set. As described above, if the diff --git a/tests/letstest/auto_targets.yaml b/tests/letstest/auto_targets.yaml index 76b3a3dc5..9d97c6a83 100644 --- a/tests/letstest/auto_targets.yaml +++ b/tests/letstest/auto_targets.yaml @@ -56,17 +56,6 @@ targets: type: centos virt: hvm user: centos - # centos6 requires EPEL repo added - - ami: ami-1585c46a - name: centos6 - type: centos - virt: hvm - user: centos - userdata: | - #cloud-config - runcmd: - - yum install -y epel-release - - iptables -F - ami: ami-01ca03df4a6012157 name: centos8 type: centos diff --git a/tests/letstest/scripts/test_leauto_upgrades.sh b/tests/letstest/scripts/test_leauto_upgrades.sh index 1eeafad21..51ff640c5 100755 --- a/tests/letstest/scripts/test_leauto_upgrades.sh +++ b/tests/letstest/scripts/test_leauto_upgrades.sh @@ -105,10 +105,15 @@ if ./letsencrypt-auto -v --debug --version | grep "WARNING: couldn't find Python exit 1 fi -# Since certbot-auto is deprecated, we expect it to leave existing Certbot -# installations unmodified so we check for the same version that was initially -# installed below. -EXPECTED_VERSION="$INITIAL_VERSION" +# On systems like Debian where certbot-auto is deprecated, we expect it to +# leave existing Certbot installations unmodified so we check for the same +# version that was initially installed below. Once certbot-auto is deprecated +# on RHEL systems, we can unconditionally check for INITIAL_VERSION. +if [ -f /etc/debian_version ]; then + EXPECTED_VERSION="$INITIAL_VERSION" +else + EXPECTED_VERSION=$(grep -m1 LE_AUTO_VERSION certbot-auto | cut -d\" -f2) +fi if ! /opt/eff.org/certbot/venv/bin/letsencrypt --version 2>&1 | tail -n1 | grep "^certbot $EXPECTED_VERSION$" ; then echo unexpected certbot version found @@ -119,3 +124,22 @@ if ! diff letsencrypt-auto letsencrypt-auto-source/letsencrypt-auto ; then echo letsencrypt-auto and letsencrypt-auto-source/letsencrypt-auto differ exit 1 fi + +if [ "$RUN_RHEL6_TESTS" = 1 ]; then + # Add the SCL python release to PATH in order to resolve python3 command + PATH="/opt/rh/rh-python36/root/usr/bin:$PATH" + if ! command -v python3; then + echo "Python3 wasn't properly installed" + exit 1 + fi + if [ "$(/opt/eff.org/certbot/venv/bin/python -V 2>&1 | cut -d" " -f 2 | cut -d. -f1)" != 3 ]; then + echo "Python3 wasn't used in venv!" + exit 1 + fi + + if [ "$("$PYTHON_NAME" tools/readlink.py $OLD_VENV_PATH)" != "/opt/eff.org/certbot/venv" ]; then + echo symlink from old venv path not properly created! + exit 1 + fi +fi +echo upgrade appeared to be successful diff --git a/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh b/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh index fc5435916..15cf9ee1b 100755 --- a/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh +++ b/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh @@ -16,14 +16,58 @@ sudo chown root "$LE_AUTO_PATH" sudo chmod 0755 "$LE_AUTO_PATH" export PATH="$LE_AUTO_DIR:$PATH" -# Since certbot-auto is deprecated, we expect certbot-auto to error and -# refuse to install Certbot. -set +o pipefail -if ! letsencrypt-auto --debug --version | grep "Certbot cannot be installed."; then - echo "letsencrypt-auto didn't report being uninstallable." +# On systems like Debian where certbot-auto is deprecated, we expect +# certbot-auto to error and refuse to install Certbot. Once certbot-auto is +# deprecated on RHEL systems, we can unconditionally run this code. +if [ -f /etc/debian_version ]; then + set +o pipefail + if ! letsencrypt-auto --debug --version | grep "Certbot cannot be installed."; then + echo "letsencrypt-auto didn't report being uninstallable." + exit 1 + fi + if [ ${PIPESTATUS[0]} != 1 ]; then + echo "letsencrypt-auto didn't exit with status 1 as expected" + exit 1 + fi + # letsencrypt-auto is deprecated and cannot be installed on this system so + # we cannot run the rest of this test. + exit 0 +fi + +letsencrypt-auto --os-packages-only --debug --version + +# This script sets the environment variables PYTHON_NAME, VENV_PATH, and +# VENV_SCRIPT based on the version of Python available on the system. For +# instance, Fedora uses Python 3 and Python 2 is not installed. +. tests/letstest/scripts/set_python_envvars.sh + +# Create a venv-like layout at the old virtual environment path to test that a +# symlink is properly created when letsencrypt-auto runs. +HOME=${HOME:-~root} +XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} +OLD_VENV_BIN="$XDG_DATA_HOME/letsencrypt/bin" +mkdir -p "$OLD_VENV_BIN" +touch "$OLD_VENV_BIN/letsencrypt" + +letsencrypt-auto certonly --no-self-upgrade -v --standalone --debug \ + --text --agree-tos \ + --renew-by-default --redirect \ + --register-unsafely-without-email \ + --domain $PUBLIC_HOSTNAME --server $BOULDER_URL + +LINK_PATH=$("$PYTHON_NAME" tools/readlink.py ${XDG_DATA_HOME:-~/.local/share}/letsencrypt) +if [ "$LINK_PATH" != "/opt/eff.org/certbot/venv" ]; then + echo symlink from old venv path not properly created! exit 1 fi -if [ ${PIPESTATUS[0]} != 1 ]; then - echo "letsencrypt-auto didn't exit with status 1 as expected" + +if ! letsencrypt-auto --help --no-self-upgrade | grep -F "letsencrypt-auto [SUBCOMMAND]"; then + echo "letsencrypt-auto not included in help output!" + exit 1 +fi + +OUTPUT_LEN=$(letsencrypt-auto --install-only --no-self-upgrade --quiet 2>&1 | wc -c) +if [ "$OUTPUT_LEN" != 0 ]; then + echo letsencrypt-auto produced unexpected output! exit 1 fi diff --git a/tests/letstest/targets.yaml b/tests/letstest/targets.yaml index 29edd1552..97c775f6c 100644 --- a/tests/letstest/targets.yaml +++ b/tests/letstest/targets.yaml @@ -52,17 +52,6 @@ targets: type: centos virt: hvm user: centos - # centos6 requires EPEL repo added - - ami: ami-1585c46a - name: centos6 - type: centos - virt: hvm - user: centos - userdata: | - #cloud-config - runcmd: - - yum install -y epel-release - - iptables -F - ami: ami-01ca03df4a6012157 name: centos8 type: centos From 5f73274390dfc6241e489917f4beb640a72b66a5 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 2 Dec 2020 15:08:07 -0800 Subject: [PATCH 26/42] Fix add deprecated argument (#8500) Fixes https://github.com/certbot/certbot/issues/8495. To further explain the problem here, `modify_kwargs_for_default_detection` as called in `add` is simplistic and doesn't always work. See https://github.com/certbot/certbot/issues/6164 for one other example. In this case, were bitten by the code https://github.com/certbot/certbot/blob/d1e7404358c05734aaf436ef3c9d709029d62b09/certbot/certbot/_internal/cli/helpful.py#L393-L395 The action used for deprecated arguments isn't in `ZERO_ARG_ACTIONS` so it assumes that all deprecated flags take one parameter. Rather than trying to fix this function (which I think can only realistically be fixed by https://github.com/certbot/certbot/issues/4493), I took the approach that was previously used in `HelpfulArgumentParser.add_deprecated_argument` of bypassing this extra logic entirely. I adapted that function to now call `HelpfulArgumentParser.add` as well for consistency and to make testing easier. * Rename deprecated arg action class * Skip extra parsing for deprecated arguments * Add back test of --manual-public-ip-logging-ok * Add changelog entry --- .../utils/certbot_call.py | 1 + certbot/CHANGELOG.md | 4 ++- certbot/certbot/_internal/cli/helpful.py | 32 +++++++++++++++++-- certbot/certbot/util.py | 10 +++--- certbot/tests/helpful_test.py | 16 ++++++++++ 5 files changed, 55 insertions(+), 8 deletions(-) diff --git a/certbot-ci/certbot_integration_tests/utils/certbot_call.py b/certbot-ci/certbot_integration_tests/utils/certbot_call.py index a71c610e5..2ddaa41c8 100755 --- a/certbot-ci/certbot_integration_tests/utils/certbot_call.py +++ b/certbot-ci/certbot_integration_tests/utils/certbot_call.py @@ -92,6 +92,7 @@ def _prepare_args_env(certbot_args, directory_url, http_01_port, tls_alpn_01_por '--no-verify-ssl', '--http-01-port', str(http_01_port), '--https-port', str(tls_alpn_01_port), + '--manual-public-ip-logging-ok', '--config-dir', config_dir, '--work-dir', os.path.join(workspace, 'work'), '--logs-dir', os.path.join(workspace, 'logs'), diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index 94dde1e11..f9813bba4 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -14,7 +14,9 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). ### Fixed -* +* Fixed a bug in `certbot.util.add_deprecated_argument` that caused the + deprecated `--manual-public-ip-logging-ok` flag to crash Certbot in some + scenarios. More details about these changes can be found on our GitHub repo. diff --git a/certbot/certbot/_internal/cli/helpful.py b/certbot/certbot/_internal/cli/helpful.py index 141dd41a4..2cb506157 100644 --- a/certbot/certbot/_internal/cli/helpful.py +++ b/certbot/certbot/_internal/cli/helpful.py @@ -2,8 +2,10 @@ from __future__ import print_function import argparse import copy +import functools import glob import sys + import configargparse import six import zope.component @@ -356,6 +358,18 @@ class HelpfulArgumentParser(object): :param dict **kwargs: various argparse settings for this argument """ + action = kwargs.get("action") + if action is util.DeprecatedArgumentAction: + # If the argument is deprecated through + # certbot.util.add_deprecated_argument, it is not shown in the help + # output and any value given to the argument is thrown away during + # argument parsing. Because of this, we handle this case early + # skipping putting the argument in different help topics and + # handling default detection since these actions aren't needed and + # can cause bugs like + # https://github.com/certbot/certbot/issues/8495. + self.parser.add_argument(*args, **kwargs) + return if isinstance(topics, list): # if this flag can be listed in multiple sections, try to pick the one @@ -410,8 +424,22 @@ class HelpfulArgumentParser(object): :param int nargs: Number of arguments the option takes. """ - util.add_deprecated_argument( - self.parser.add_argument, argument_name, num_args) + # certbot.util.add_deprecated_argument expects the normal add_argument + # interface provided by argparse. This is what is given including when + # certbot.util.add_deprecated_argument is used by plugins, however, in + # that case the first argument to certbot.util.add_deprecated_argument + # is certbot._internal.cli.HelpfulArgumentGroup.add_argument which + # internally calls the add method of this class. + # + # The difference between the add method of this class and the standard + # argparse add_argument method caused a bug in the past (see + # https://github.com/certbot/certbot/issues/8495) so we use the same + # code path here for consistency and to ensure it works. To do that, we + # wrap the add method in a similar way to + # HelpfulArgumentGroup.add_argument by providing a help topic (which in + # this case is set to None). + add_func = functools.partial(self.add, None) + util.add_deprecated_argument(add_func, argument_name, num_args) def add_group(self, topic, verbs=(), **kwargs): """Create a new argument group. diff --git a/certbot/certbot/util.py b/certbot/certbot/util.py index fd7b46f85..8db5ab34a 100644 --- a/certbot/certbot/util.py +++ b/certbot/certbot/util.py @@ -439,7 +439,7 @@ def safe_email(email): return False -class _ShowWarning(argparse.Action): +class DeprecatedArgumentAction(argparse.Action): """Action to log a warning when an argument is used.""" def __call__(self, unused1, unused2, unused3, option_string=None): logger.warning("Use of %s is deprecated.", option_string) @@ -458,16 +458,16 @@ def add_deprecated_argument(add_argument, argument_name, nargs): :param nargs: Value for nargs when adding the argument to argparse. """ - if _ShowWarning not in configargparse.ACTION_TYPES_THAT_DONT_NEED_A_VALUE: + if DeprecatedArgumentAction not in configargparse.ACTION_TYPES_THAT_DONT_NEED_A_VALUE: # In version 0.12.0 ACTION_TYPES_THAT_DONT_NEED_A_VALUE was # changed from a set to a tuple. if isinstance(configargparse.ACTION_TYPES_THAT_DONT_NEED_A_VALUE, set): configargparse.ACTION_TYPES_THAT_DONT_NEED_A_VALUE.add( - _ShowWarning) + DeprecatedArgumentAction) else: configargparse.ACTION_TYPES_THAT_DONT_NEED_A_VALUE += ( - _ShowWarning,) - add_argument(argument_name, action=_ShowWarning, + DeprecatedArgumentAction,) + add_argument(argument_name, action=DeprecatedArgumentAction, help=argparse.SUPPRESS, nargs=nargs) diff --git a/certbot/tests/helpful_test.py b/certbot/tests/helpful_test.py index 292e55304..1a5c2bea6 100644 --- a/certbot/tests/helpful_test.py +++ b/certbot/tests/helpful_test.py @@ -1,6 +1,11 @@ """Tests for certbot.helpful_parser""" import unittest +try: + import mock +except ImportError: # pragma: no cover + from unittest import mock + from certbot import errors from certbot._internal.cli import HelpfulArgumentParser from certbot._internal.cli import _DomainsAction @@ -189,5 +194,16 @@ class TestParseArgsErrors(unittest.TestCase): arg_parser.parse_args() +class TestAddDeprecatedArgument(unittest.TestCase): + """Tests for add_deprecated_argument method of HelpfulArgumentParser""" + + @mock.patch.object(HelpfulArgumentParser, "modify_kwargs_for_default_detection") + def test_no_default_detection_modifications(self, mock_modify): + arg_parser = HelpfulArgumentParser(["run"], {}, detect_defaults=True) + arg_parser.add_deprecated_argument("--foo", 0) + arg_parser.parse_args() + mock_modify.assert_not_called() + + if __name__ == '__main__': unittest.main() # pragma: no cover From 45e48b565d3e20520cabc66f7e58f0db7fd54767 Mon Sep 17 00:00:00 2001 From: Mads Jensen Date: Thu, 3 Dec 2020 00:12:27 +0100 Subject: [PATCH 27/42] Fix changelog typo (#8497) Co-authored-by: Adrien Ferrand --- certbot/CHANGELOG.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index 4e4a27316..db191dfa2 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -10,7 +10,7 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). * Confirmation when deleting certificates * CLI flag `--key-type` has been added to specify 'rsa' or 'ecdsa' (default 'rsa'). * CLI flag `--elliptic-curve` has been added which takes an NIST/SECG elliptic curve. Any of - `secp256r1`, `secp284r1` and `secp521r1` are accepted values. + `secp256r1`, `secp384r1` and `secp521r1` are accepted values. * The command `certbot certficates` lists the which type of the private key that was used for the private key. * Support for Python 3.9 was added to Certbot and all of its components. @@ -20,7 +20,6 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). * certbot-auto was deprecated on Debian based systems. * CLI flag `--manual-public-ip-logging-ok` is now a no-op, generates a deprecation warning, and will be removed in a future release. -* ### Fixed From a71e22678f72c2b784530c778a84c70c84c3a5ae Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 3 Dec 2020 00:06:05 -0800 Subject: [PATCH 28/42] Fix add deprecated argument (#8500) (#8501) Fixes https://github.com/certbot/certbot/issues/8495. To further explain the problem here, `modify_kwargs_for_default_detection` as called in `add` is simplistic and doesn't always work. See https://github.com/certbot/certbot/issues/6164 for one other example. In this case, were bitten by the code https://github.com/certbot/certbot/blob/d1e7404358c05734aaf436ef3c9d709029d62b09/certbot/certbot/_internal/cli/helpful.py#L393-L395 The action used for deprecated arguments isn't in `ZERO_ARG_ACTIONS` so it assumes that all deprecated flags take one parameter. Rather than trying to fix this function (which I think can only realistically be fixed by https://github.com/certbot/certbot/issues/4493), I took the approach that was previously used in `HelpfulArgumentParser.add_deprecated_argument` of bypassing this extra logic entirely. I adapted that function to now call `HelpfulArgumentParser.add` as well for consistency and to make testing easier. * Rename deprecated arg action class * Skip extra parsing for deprecated arguments * Add back test of --manual-public-ip-logging-ok * Add changelog entry (cherry picked from commit 5f73274390dfc6241e489917f4beb640a72b66a5) --- .../utils/certbot_call.py | 1 + certbot/CHANGELOG.md | 10 ++++++ certbot/certbot/_internal/cli/helpful.py | 32 +++++++++++++++++-- certbot/certbot/util.py | 10 +++--- certbot/tests/helpful_test.py | 16 ++++++++++ 5 files changed, 62 insertions(+), 7 deletions(-) diff --git a/certbot-ci/certbot_integration_tests/utils/certbot_call.py b/certbot-ci/certbot_integration_tests/utils/certbot_call.py index a71c610e5..2ddaa41c8 100755 --- a/certbot-ci/certbot_integration_tests/utils/certbot_call.py +++ b/certbot-ci/certbot_integration_tests/utils/certbot_call.py @@ -92,6 +92,7 @@ def _prepare_args_env(certbot_args, directory_url, http_01_port, tls_alpn_01_por '--no-verify-ssl', '--http-01-port', str(http_01_port), '--https-port', str(tls_alpn_01_port), + '--manual-public-ip-logging-ok', '--config-dir', config_dir, '--work-dir', os.path.join(workspace, 'work'), '--logs-dir', os.path.join(workspace, 'logs'), diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index db191dfa2..ee978412f 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -2,6 +2,16 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). +## 1.10.1 - master + +### Fixed + +* Fixed a bug in `certbot.util.add_deprecated_argument` that caused the + deprecated `--manual-public-ip-logging-ok` flag to crash Certbot in some + scenarios. + +More details about these changes can be found on our GitHub repo. + ## 1.10.0 - 2020-12-01 ### Added diff --git a/certbot/certbot/_internal/cli/helpful.py b/certbot/certbot/_internal/cli/helpful.py index 141dd41a4..2cb506157 100644 --- a/certbot/certbot/_internal/cli/helpful.py +++ b/certbot/certbot/_internal/cli/helpful.py @@ -2,8 +2,10 @@ from __future__ import print_function import argparse import copy +import functools import glob import sys + import configargparse import six import zope.component @@ -356,6 +358,18 @@ class HelpfulArgumentParser(object): :param dict **kwargs: various argparse settings for this argument """ + action = kwargs.get("action") + if action is util.DeprecatedArgumentAction: + # If the argument is deprecated through + # certbot.util.add_deprecated_argument, it is not shown in the help + # output and any value given to the argument is thrown away during + # argument parsing. Because of this, we handle this case early + # skipping putting the argument in different help topics and + # handling default detection since these actions aren't needed and + # can cause bugs like + # https://github.com/certbot/certbot/issues/8495. + self.parser.add_argument(*args, **kwargs) + return if isinstance(topics, list): # if this flag can be listed in multiple sections, try to pick the one @@ -410,8 +424,22 @@ class HelpfulArgumentParser(object): :param int nargs: Number of arguments the option takes. """ - util.add_deprecated_argument( - self.parser.add_argument, argument_name, num_args) + # certbot.util.add_deprecated_argument expects the normal add_argument + # interface provided by argparse. This is what is given including when + # certbot.util.add_deprecated_argument is used by plugins, however, in + # that case the first argument to certbot.util.add_deprecated_argument + # is certbot._internal.cli.HelpfulArgumentGroup.add_argument which + # internally calls the add method of this class. + # + # The difference between the add method of this class and the standard + # argparse add_argument method caused a bug in the past (see + # https://github.com/certbot/certbot/issues/8495) so we use the same + # code path here for consistency and to ensure it works. To do that, we + # wrap the add method in a similar way to + # HelpfulArgumentGroup.add_argument by providing a help topic (which in + # this case is set to None). + add_func = functools.partial(self.add, None) + util.add_deprecated_argument(add_func, argument_name, num_args) def add_group(self, topic, verbs=(), **kwargs): """Create a new argument group. diff --git a/certbot/certbot/util.py b/certbot/certbot/util.py index fd7b46f85..8db5ab34a 100644 --- a/certbot/certbot/util.py +++ b/certbot/certbot/util.py @@ -439,7 +439,7 @@ def safe_email(email): return False -class _ShowWarning(argparse.Action): +class DeprecatedArgumentAction(argparse.Action): """Action to log a warning when an argument is used.""" def __call__(self, unused1, unused2, unused3, option_string=None): logger.warning("Use of %s is deprecated.", option_string) @@ -458,16 +458,16 @@ def add_deprecated_argument(add_argument, argument_name, nargs): :param nargs: Value for nargs when adding the argument to argparse. """ - if _ShowWarning not in configargparse.ACTION_TYPES_THAT_DONT_NEED_A_VALUE: + if DeprecatedArgumentAction not in configargparse.ACTION_TYPES_THAT_DONT_NEED_A_VALUE: # In version 0.12.0 ACTION_TYPES_THAT_DONT_NEED_A_VALUE was # changed from a set to a tuple. if isinstance(configargparse.ACTION_TYPES_THAT_DONT_NEED_A_VALUE, set): configargparse.ACTION_TYPES_THAT_DONT_NEED_A_VALUE.add( - _ShowWarning) + DeprecatedArgumentAction) else: configargparse.ACTION_TYPES_THAT_DONT_NEED_A_VALUE += ( - _ShowWarning,) - add_argument(argument_name, action=_ShowWarning, + DeprecatedArgumentAction,) + add_argument(argument_name, action=DeprecatedArgumentAction, help=argparse.SUPPRESS, nargs=nargs) diff --git a/certbot/tests/helpful_test.py b/certbot/tests/helpful_test.py index 292e55304..1a5c2bea6 100644 --- a/certbot/tests/helpful_test.py +++ b/certbot/tests/helpful_test.py @@ -1,6 +1,11 @@ """Tests for certbot.helpful_parser""" import unittest +try: + import mock +except ImportError: # pragma: no cover + from unittest import mock + from certbot import errors from certbot._internal.cli import HelpfulArgumentParser from certbot._internal.cli import _DomainsAction @@ -189,5 +194,16 @@ class TestParseArgsErrors(unittest.TestCase): arg_parser.parse_args() +class TestAddDeprecatedArgument(unittest.TestCase): + """Tests for add_deprecated_argument method of HelpfulArgumentParser""" + + @mock.patch.object(HelpfulArgumentParser, "modify_kwargs_for_default_detection") + def test_no_default_detection_modifications(self, mock_modify): + arg_parser = HelpfulArgumentParser(["run"], {}, detect_defaults=True) + arg_parser.add_deprecated_argument("--foo", 0) + arg_parser.parse_args() + mock_modify.assert_not_called() + + if __name__ == '__main__': unittest.main() # pragma: no cover From 4c896fd87caaa20114bea6180ccaa4d5c9a85c2a Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 3 Dec 2020 10:20:11 -0800 Subject: [PATCH 29/42] Update changelog for 1.10.1 release --- certbot/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index ee978412f..c6ef75824 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -2,7 +2,7 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). -## 1.10.1 - master +## 1.10.1 - 2020-12-03 ### Fixed From 64543d49704be2180668371cdcff3b42521b51b2 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 3 Dec 2020 10:33:30 -0800 Subject: [PATCH 30/42] Release 1.10.1 --- acme/setup.py | 2 +- certbot-apache/setup.py | 2 +- certbot-auto | 26 +++++++++--------- certbot-compatibility-test/setup.py | 2 +- certbot-dns-cloudflare/setup.py | 2 +- certbot-dns-cloudxns/setup.py | 2 +- certbot-dns-digitalocean/setup.py | 2 +- certbot-dns-dnsimple/setup.py | 2 +- certbot-dns-dnsmadeeasy/setup.py | 2 +- certbot-dns-gehirn/setup.py | 2 +- certbot-dns-google/setup.py | 2 +- certbot-dns-linode/setup.py | 2 +- certbot-dns-luadns/setup.py | 2 +- certbot-dns-nsone/setup.py | 2 +- certbot-dns-ovh/setup.py | 2 +- certbot-dns-rfc2136/setup.py | 2 +- certbot-dns-route53/setup.py | 2 +- certbot-dns-sakuracloud/setup.py | 2 +- certbot-nginx/setup.py | 2 +- certbot/certbot/__init__.py | 2 +- certbot/docs/cli-help.txt | 2 +- letsencrypt-auto | 26 +++++++++--------- letsencrypt-auto-source/certbot-auto.asc | 16 +++++------ letsencrypt-auto-source/letsencrypt-auto | 26 +++++++++--------- letsencrypt-auto-source/letsencrypt-auto.sig | Bin 256 -> 256 bytes .../pieces/certbot-requirements.txt | 24 ++++++++-------- 26 files changed, 79 insertions(+), 79 deletions(-) diff --git a/acme/setup.py b/acme/setup.py index 76db38fe6..a6b2850f9 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -5,7 +5,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.10.1' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-apache/setup.py b/certbot-apache/setup.py index 8e632e1db..2c7d8d377 100644 --- a/certbot-apache/setup.py +++ b/certbot-apache/setup.py @@ -5,7 +5,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.10.1' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-auto b/certbot-auto index 96b40c0c8..ee12d4706 100755 --- a/certbot-auto +++ b/certbot-auto @@ -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.10.0" +LE_AUTO_VERSION="1.10.1" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -1493,18 +1493,18 @@ letsencrypt==0.7.0 \ --hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \ --hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9 -certbot==1.10.0 \ - --hash=sha256:b4f3d73c440d09a95346991bf7cf80870baf37dcf4865f3766dc43bc35d2c9a6 \ - --hash=sha256:5d79bd451756112a7db2cdb25d193de9baf3df85211ed9587685be32b779bbfc -acme==1.10.0 \ - --hash=sha256:bcaff04357d4fa1b87b12fd9721a7da9e1496b88c5e9edda85ec9d69376e9a29 \ - --hash=sha256:e3939526d08530d4b17623f843b9a983f2d772eefb7836bd31091c229da04a90 -certbot-apache==1.10.0 \ - --hash=sha256:2ccc61b03d307631da24a63b2a0449094e2accda9bb1fe3d66a178e806d89101 \ - --hash=sha256:5396526937c46f1ed5bc1615506ed67e7dbb26b247666842cc9788c9e2b6d012 -certbot-nginx==1.10.0 \ - --hash=sha256:dfa5254b5ea5bd94578fad4094585bd14ed940767ac1bdffe2a68fd395432a6b \ - --hash=sha256:aaf5ee4b00fa9b9a347843d4a01c70a770485c44284d52c4da5e155741125b09 +certbot==1.10.1 \ + --hash=sha256:011ac980fa21b9f29e02c9b8d8b86e8a4bf4670b51b6ad91656e401e9d2d2231 \ + --hash=sha256:0d9ee3fc09e0d03b2d1b1f1c4916e61ecfc6904b4216ddef4e6a5ca1424d9cb7 +acme==1.10.1 \ + --hash=sha256:752d598e54e98ad1e874de53fd50c61044f1b566d6deb790db5676ce9c573546 \ + --hash=sha256:fcbb559aedc96b404edf593e78517dcd7291984d5a37036c3fc77f3c5c122fd8 +certbot-apache==1.10.1 \ + --hash=sha256:f077b4b7f166627ef5e0921fe7cde57700670fc86e9ad9dbdfaf2c573cc0f2fa \ + --hash=sha256:97ed637b4c7b03820db6c69aa90145dc989933351d46a3d62baf6b71674f0a10 +certbot-nginx==1.10.1 \ + --hash=sha256:7c36459021f8a1ec3b6c062e4c4fc866bfaa1dbf26ccd29e043dd6848003be08 \ + --hash=sha256:c0bbeccf85f46b728fd95e6bb8c2649d32d3383d7f47ea4b9c312d12bf04d2f0 UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/certbot-compatibility-test/setup.py b/certbot-compatibility-test/setup.py index f9390f5d4..4387c2b4a 100644 --- a/certbot-compatibility-test/setup.py +++ b/certbot-compatibility-test/setup.py @@ -5,7 +5,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.10.1' install_requires = [ 'certbot', diff --git a/certbot-dns-cloudflare/setup.py b/certbot-dns-cloudflare/setup.py index fd6fc1f8e..a0932235e 100644 --- a/certbot-dns-cloudflare/setup.py +++ b/certbot-dns-cloudflare/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.10.1' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-cloudxns/setup.py b/certbot-dns-cloudxns/setup.py index 93e2aae50..6e0077d91 100644 --- a/certbot-dns-cloudxns/setup.py +++ b/certbot-dns-cloudxns/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.10.1' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-digitalocean/setup.py b/certbot-dns-digitalocean/setup.py index b231f3060..e16c63279 100644 --- a/certbot-dns-digitalocean/setup.py +++ b/certbot-dns-digitalocean/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.10.1' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-dnsimple/setup.py b/certbot-dns-dnsimple/setup.py index 6c4aff4a6..aedbac92a 100644 --- a/certbot-dns-dnsimple/setup.py +++ b/certbot-dns-dnsimple/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.10.1' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-dnsmadeeasy/setup.py b/certbot-dns-dnsmadeeasy/setup.py index 68a432a35..2a198e386 100644 --- a/certbot-dns-dnsmadeeasy/setup.py +++ b/certbot-dns-dnsmadeeasy/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.10.1' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-gehirn/setup.py b/certbot-dns-gehirn/setup.py index 0d1d04bf2..eefc1d42f 100644 --- a/certbot-dns-gehirn/setup.py +++ b/certbot-dns-gehirn/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.10.1' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-dns-google/setup.py b/certbot-dns-google/setup.py index 081a74170..c6ac9ce72 100644 --- a/certbot-dns-google/setup.py +++ b/certbot-dns-google/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.10.1' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-linode/setup.py b/certbot-dns-linode/setup.py index 3d56cd737..b3eedd83a 100644 --- a/certbot-dns-linode/setup.py +++ b/certbot-dns-linode/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.10.1' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-dns-luadns/setup.py b/certbot-dns-luadns/setup.py index 229bb03d8..fd87d3fa7 100644 --- a/certbot-dns-luadns/setup.py +++ b/certbot-dns-luadns/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.10.1' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-nsone/setup.py b/certbot-dns-nsone/setup.py index a3fc92b9c..425a8e84a 100644 --- a/certbot-dns-nsone/setup.py +++ b/certbot-dns-nsone/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.10.1' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-ovh/setup.py b/certbot-dns-ovh/setup.py index ac8b52fdf..096580f0f 100644 --- a/certbot-dns-ovh/setup.py +++ b/certbot-dns-ovh/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.10.1' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-rfc2136/setup.py b/certbot-dns-rfc2136/setup.py index af919c32a..d3b374109 100644 --- a/certbot-dns-rfc2136/setup.py +++ b/certbot-dns-rfc2136/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.10.1' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-route53/setup.py b/certbot-dns-route53/setup.py index 6fc8494d3..aa0496877 100644 --- a/certbot-dns-route53/setup.py +++ b/certbot-dns-route53/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.10.1' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-sakuracloud/setup.py b/certbot-dns-sakuracloud/setup.py index d567a3a4e..0e0f6468f 100644 --- a/certbot-dns-sakuracloud/setup.py +++ b/certbot-dns-sakuracloud/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.10.1' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-nginx/setup.py b/certbot-nginx/setup.py index 4a89e2662..75d62fd91 100644 --- a/certbot-nginx/setup.py +++ b/certbot-nginx/setup.py @@ -5,7 +5,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.0' +version = '1.10.1' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot/certbot/__init__.py b/certbot/certbot/__init__.py index 7028d15b2..5e47c610a 100644 --- a/certbot/certbot/__init__.py +++ b/certbot/certbot/__init__.py @@ -1,4 +1,4 @@ """Certbot client.""" # version number like 1.2.3a0, must have at least 2 parts, like 1.2 -__version__ = '1.10.0' +__version__ = '1.10.1' diff --git a/certbot/docs/cli-help.txt b/certbot/docs/cli-help.txt index 01cdb3130..a320b30e8 100644 --- a/certbot/docs/cli-help.txt +++ b/certbot/docs/cli-help.txt @@ -118,7 +118,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.10.0 + "". (default: CertbotACMEClient/1.10.1 (certbot(-auto); OS_NAME OS_VERSION) Authenticator/XXX Installer/YYY (SUBCOMMAND; flags: FLAGS) Py/major.minor.patchlevel). The flags encoded in the diff --git a/letsencrypt-auto b/letsencrypt-auto index 96b40c0c8..ee12d4706 100755 --- a/letsencrypt-auto +++ b/letsencrypt-auto @@ -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.10.0" +LE_AUTO_VERSION="1.10.1" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -1493,18 +1493,18 @@ letsencrypt==0.7.0 \ --hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \ --hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9 -certbot==1.10.0 \ - --hash=sha256:b4f3d73c440d09a95346991bf7cf80870baf37dcf4865f3766dc43bc35d2c9a6 \ - --hash=sha256:5d79bd451756112a7db2cdb25d193de9baf3df85211ed9587685be32b779bbfc -acme==1.10.0 \ - --hash=sha256:bcaff04357d4fa1b87b12fd9721a7da9e1496b88c5e9edda85ec9d69376e9a29 \ - --hash=sha256:e3939526d08530d4b17623f843b9a983f2d772eefb7836bd31091c229da04a90 -certbot-apache==1.10.0 \ - --hash=sha256:2ccc61b03d307631da24a63b2a0449094e2accda9bb1fe3d66a178e806d89101 \ - --hash=sha256:5396526937c46f1ed5bc1615506ed67e7dbb26b247666842cc9788c9e2b6d012 -certbot-nginx==1.10.0 \ - --hash=sha256:dfa5254b5ea5bd94578fad4094585bd14ed940767ac1bdffe2a68fd395432a6b \ - --hash=sha256:aaf5ee4b00fa9b9a347843d4a01c70a770485c44284d52c4da5e155741125b09 +certbot==1.10.1 \ + --hash=sha256:011ac980fa21b9f29e02c9b8d8b86e8a4bf4670b51b6ad91656e401e9d2d2231 \ + --hash=sha256:0d9ee3fc09e0d03b2d1b1f1c4916e61ecfc6904b4216ddef4e6a5ca1424d9cb7 +acme==1.10.1 \ + --hash=sha256:752d598e54e98ad1e874de53fd50c61044f1b566d6deb790db5676ce9c573546 \ + --hash=sha256:fcbb559aedc96b404edf593e78517dcd7291984d5a37036c3fc77f3c5c122fd8 +certbot-apache==1.10.1 \ + --hash=sha256:f077b4b7f166627ef5e0921fe7cde57700670fc86e9ad9dbdfaf2c573cc0f2fa \ + --hash=sha256:97ed637b4c7b03820db6c69aa90145dc989933351d46a3d62baf6b71674f0a10 +certbot-nginx==1.10.1 \ + --hash=sha256:7c36459021f8a1ec3b6c062e4c4fc866bfaa1dbf26ccd29e043dd6848003be08 \ + --hash=sha256:c0bbeccf85f46b728fd95e6bb8c2649d32d3383d7f47ea4b9c312d12bf04d2f0 UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/letsencrypt-auto-source/certbot-auto.asc b/letsencrypt-auto-source/certbot-auto.asc index 4b8d6d60a..c1897074c 100644 --- a/letsencrypt-auto-source/certbot-auto.asc +++ b/letsencrypt-auto-source/certbot-auto.asc @@ -1,11 +1,11 @@ -----BEGIN PGP SIGNATURE----- -iQEzBAABCAAdFiEEos+1H6J1pyhiNOeyTRfJlc2XdfIFAl/GjQkACgkQTRfJlc2X -dfJSUwf/fdEu4EJhIPzotzUz8hiyWWvQdH/rdhjd9rWjF/B8FZjjb5vMQAPMn3Z3 -E0MhE4AKvVly4ckh7WGRDP9pNA770JXsT6dOdpnlAtwZozfEcWYQnKHXurc4hCqE -17dlE1jhyHpveUulGmf0A+biWExT3nrG2wE6bACQztYp6+sCmnGfGsR0NXW2YWSx -c+C6ixlmXYDU8QFxpgQVpqthI9k/LiFzCWJFYeERN12gLaK16Yc8lCU7lgVuCul2 -PrNN9ngX6i5zomfgv1ZGpfgZT1Nr0qKf4SSW7Ql73pXPtAR8mA6Jo7HxlwaS/qQ9 -m+EhHDGeylyA1cyqw/94qaDVBIyz7A== -=+xVC +iQEzBAABCAAdFiEEos+1H6J1pyhiNOeyTRfJlc2XdfIFAl/JL3kACgkQTRfJlc2X +dfKJMwf/RXjfg5KScEjWiR+YMAcTVxGl4ITDMNBvmPoqCfrPwIJQewy1k6yQUITr +tMe0tkPneGgGccJreLAuO4+RdmNqm2MKBO3wMW9YZobJxcbMmrtVxyBD2OP4K/lL +oCZvjcN5pLvje6OlMwJ/fQ+zGY8mFUpfKIluxKrqkkO3p6Q+i/wPXF5Gjjb2J/bI +N+TczQJYUkDWAw7Tp4ho3J9xpqIn3zyOc2hI3wQDMC1o9sU5a80Vyc/mEqpE8SQ3 +qOWg9Gdx3DXTWOztcx2IxZtFEkIukPM8iD/Fkr//3XHeIc3+mqRAQdY+w7EopzbP +hLwjHVEJs1EMYq8ntWmMFjZ4+ImFgw== +=Peuv -----END PGP SIGNATURE----- diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 96b40c0c8..ee12d4706 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -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.10.0" +LE_AUTO_VERSION="1.10.1" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates @@ -1493,18 +1493,18 @@ letsencrypt==0.7.0 \ --hash=sha256:105a5fb107e45bcd0722eb89696986dcf5f08a86a321d6aef25a0c7c63375ade \ --hash=sha256:c36e532c486a7e92155ee09da54b436a3c420813ec1c590b98f635d924720de9 -certbot==1.10.0 \ - --hash=sha256:b4f3d73c440d09a95346991bf7cf80870baf37dcf4865f3766dc43bc35d2c9a6 \ - --hash=sha256:5d79bd451756112a7db2cdb25d193de9baf3df85211ed9587685be32b779bbfc -acme==1.10.0 \ - --hash=sha256:bcaff04357d4fa1b87b12fd9721a7da9e1496b88c5e9edda85ec9d69376e9a29 \ - --hash=sha256:e3939526d08530d4b17623f843b9a983f2d772eefb7836bd31091c229da04a90 -certbot-apache==1.10.0 \ - --hash=sha256:2ccc61b03d307631da24a63b2a0449094e2accda9bb1fe3d66a178e806d89101 \ - --hash=sha256:5396526937c46f1ed5bc1615506ed67e7dbb26b247666842cc9788c9e2b6d012 -certbot-nginx==1.10.0 \ - --hash=sha256:dfa5254b5ea5bd94578fad4094585bd14ed940767ac1bdffe2a68fd395432a6b \ - --hash=sha256:aaf5ee4b00fa9b9a347843d4a01c70a770485c44284d52c4da5e155741125b09 +certbot==1.10.1 \ + --hash=sha256:011ac980fa21b9f29e02c9b8d8b86e8a4bf4670b51b6ad91656e401e9d2d2231 \ + --hash=sha256:0d9ee3fc09e0d03b2d1b1f1c4916e61ecfc6904b4216ddef4e6a5ca1424d9cb7 +acme==1.10.1 \ + --hash=sha256:752d598e54e98ad1e874de53fd50c61044f1b566d6deb790db5676ce9c573546 \ + --hash=sha256:fcbb559aedc96b404edf593e78517dcd7291984d5a37036c3fc77f3c5c122fd8 +certbot-apache==1.10.1 \ + --hash=sha256:f077b4b7f166627ef5e0921fe7cde57700670fc86e9ad9dbdfaf2c573cc0f2fa \ + --hash=sha256:97ed637b4c7b03820db6c69aa90145dc989933351d46a3d62baf6b71674f0a10 +certbot-nginx==1.10.1 \ + --hash=sha256:7c36459021f8a1ec3b6c062e4c4fc866bfaa1dbf26ccd29e043dd6848003be08 \ + --hash=sha256:c0bbeccf85f46b728fd95e6bb8c2649d32d3383d7f47ea4b9c312d12bf04d2f0 UNLIKELY_EOF # ------------------------------------------------------------------------- diff --git a/letsencrypt-auto-source/letsencrypt-auto.sig b/letsencrypt-auto-source/letsencrypt-auto.sig index fba43c16f50a922d1ba3f484b57777229dedbb43..c701f4a4d72a66e1a9d5c92f6f70131f026f5bf7 100644 GIT binary patch literal 256 zcmV+b0ssDKEcN#9*)y-HYq)0nSnt|roL~JE1~9~R#Gwyd2Wg+1cG%gELpx}1wm;n_ ztGYG?;RV%ccUW2^8RyHD<>ka!7v0o(aX{lDGN1e4Bd$< zkQZZ3o5($@b~o5;ibiiMkEw^b*{9bfE#|m6tvB18{z~C#dG)IF GnT@>-N`of= literal 256 zcmV+b0ssD%vXCa-pMfAZU8x`QAcDw*r*t})Y_~h-0Z8|4UDl!iYNX#8g| Date: Thu, 3 Dec 2020 10:33:32 -0800 Subject: [PATCH 31/42] Add contents to certbot/CHANGELOG.md for next version --- certbot/CHANGELOG.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index c6ef75824..e987f2a1c 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -2,6 +2,22 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). +## 1.11.0 - master + +### Added + +* + +### Changed + +* + +### Fixed + +* + +More details about these changes can be found on our GitHub repo. + ## 1.10.1 - 2020-12-03 ### Fixed From 1dfac955c74c4ab3581808c593faefc8a5834610 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Thu, 3 Dec 2020 10:33:32 -0800 Subject: [PATCH 32/42] Bump version to 1.11.0 --- acme/setup.py | 2 +- certbot-apache/setup.py | 2 +- certbot-compatibility-test/setup.py | 2 +- certbot-dns-cloudflare/setup.py | 2 +- certbot-dns-cloudxns/setup.py | 2 +- certbot-dns-digitalocean/setup.py | 2 +- certbot-dns-dnsimple/setup.py | 2 +- certbot-dns-dnsmadeeasy/setup.py | 2 +- certbot-dns-gehirn/setup.py | 2 +- certbot-dns-google/setup.py | 2 +- certbot-dns-linode/setup.py | 2 +- certbot-dns-luadns/setup.py | 2 +- certbot-dns-nsone/setup.py | 2 +- certbot-dns-ovh/setup.py | 2 +- certbot-dns-rfc2136/setup.py | 2 +- certbot-dns-route53/setup.py | 2 +- certbot-dns-sakuracloud/setup.py | 2 +- certbot-nginx/setup.py | 2 +- certbot/certbot/__init__.py | 2 +- letsencrypt-auto-source/letsencrypt-auto | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/acme/setup.py b/acme/setup.py index a6b2850f9..f8f9efaad 100644 --- a/acme/setup.py +++ b/acme/setup.py @@ -5,7 +5,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.1' +version = '1.11.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-apache/setup.py b/certbot-apache/setup.py index 2c7d8d377..8b908ade7 100644 --- a/certbot-apache/setup.py +++ b/certbot-apache/setup.py @@ -5,7 +5,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.1' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-compatibility-test/setup.py b/certbot-compatibility-test/setup.py index 4387c2b4a..c894e5dee 100644 --- a/certbot-compatibility-test/setup.py +++ b/certbot-compatibility-test/setup.py @@ -5,7 +5,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.1' +version = '1.11.0.dev0' install_requires = [ 'certbot', diff --git a/certbot-dns-cloudflare/setup.py b/certbot-dns-cloudflare/setup.py index a0932235e..a00f06a8a 100644 --- a/certbot-dns-cloudflare/setup.py +++ b/certbot-dns-cloudflare/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.1' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-cloudxns/setup.py b/certbot-dns-cloudxns/setup.py index 6e0077d91..3771c1d34 100644 --- a/certbot-dns-cloudxns/setup.py +++ b/certbot-dns-cloudxns/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.1' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-digitalocean/setup.py b/certbot-dns-digitalocean/setup.py index e16c63279..f168ee06a 100644 --- a/certbot-dns-digitalocean/setup.py +++ b/certbot-dns-digitalocean/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.1' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-dnsimple/setup.py b/certbot-dns-dnsimple/setup.py index aedbac92a..f23bd6668 100644 --- a/certbot-dns-dnsimple/setup.py +++ b/certbot-dns-dnsimple/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.1' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-dnsmadeeasy/setup.py b/certbot-dns-dnsmadeeasy/setup.py index 2a198e386..e654ed421 100644 --- a/certbot-dns-dnsmadeeasy/setup.py +++ b/certbot-dns-dnsmadeeasy/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.1' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-gehirn/setup.py b/certbot-dns-gehirn/setup.py index eefc1d42f..a856f1cde 100644 --- a/certbot-dns-gehirn/setup.py +++ b/certbot-dns-gehirn/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.1' +version = '1.11.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-dns-google/setup.py b/certbot-dns-google/setup.py index c6ac9ce72..82c2a9102 100644 --- a/certbot-dns-google/setup.py +++ b/certbot-dns-google/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.1' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-linode/setup.py b/certbot-dns-linode/setup.py index b3eedd83a..a6f159757 100644 --- a/certbot-dns-linode/setup.py +++ b/certbot-dns-linode/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.1' +version = '1.11.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-dns-luadns/setup.py b/certbot-dns-luadns/setup.py index fd87d3fa7..ff4a1b41d 100644 --- a/certbot-dns-luadns/setup.py +++ b/certbot-dns-luadns/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.1' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-nsone/setup.py b/certbot-dns-nsone/setup.py index 425a8e84a..887d5120a 100644 --- a/certbot-dns-nsone/setup.py +++ b/certbot-dns-nsone/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.1' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-ovh/setup.py b/certbot-dns-ovh/setup.py index 096580f0f..d519a9e18 100644 --- a/certbot-dns-ovh/setup.py +++ b/certbot-dns-ovh/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.1' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-rfc2136/setup.py b/certbot-dns-rfc2136/setup.py index d3b374109..540fc1a67 100644 --- a/certbot-dns-rfc2136/setup.py +++ b/certbot-dns-rfc2136/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.1' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-route53/setup.py b/certbot-dns-route53/setup.py index aa0496877..cffa16367 100644 --- a/certbot-dns-route53/setup.py +++ b/certbot-dns-route53/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.1' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot-dns-sakuracloud/setup.py b/certbot-dns-sakuracloud/setup.py index 0e0f6468f..2c88f1226 100644 --- a/certbot-dns-sakuracloud/setup.py +++ b/certbot-dns-sakuracloud/setup.py @@ -6,7 +6,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.1' +version = '1.11.0.dev0' # Please update tox.ini when modifying dependency version requirements install_requires = [ diff --git a/certbot-nginx/setup.py b/certbot-nginx/setup.py index 75d62fd91..0ed164da2 100644 --- a/certbot-nginx/setup.py +++ b/certbot-nginx/setup.py @@ -5,7 +5,7 @@ from setuptools import __version__ as setuptools_version from setuptools import find_packages from setuptools import setup -version = '1.10.1' +version = '1.11.0.dev0' # Remember to update local-oldest-requirements.txt when changing the minimum # acme/certbot version. diff --git a/certbot/certbot/__init__.py b/certbot/certbot/__init__.py index 5e47c610a..11c97dfac 100644 --- a/certbot/certbot/__init__.py +++ b/certbot/certbot/__init__.py @@ -1,4 +1,4 @@ """Certbot client.""" # version number like 1.2.3a0, must have at least 2 parts, like 1.2 -__version__ = '1.10.1' +__version__ = '1.11.0.dev0' diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index ee12d4706..789904992 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -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.10.1" +LE_AUTO_VERSION="1.11.0.dev0" BASENAME=$(basename $0) USAGE="Usage: $BASENAME [OPTIONS] A self-updating wrapper script for the Certbot ACME client. When run, updates From 22cf94f9308ce683c14e6c4e52ec10c5d22fa8d2 Mon Sep 17 00:00:00 2001 From: alexzorin Date: Fri, 4 Dec 2020 11:38:59 +1100 Subject: [PATCH 33/42] cli: clean up `certbot renew` summary (#8503) * cli: clean up `certbot renew` summary - Unduplicate output which was being sent to both stdout and stderr - Don't use IDisplay.notification to buffer output - Remove big "DRY RUN" guards above and below, instead change language to "renewal" or "simulated renewal" - Reword "Attempting to renew cert ... produced an unexpected error" to be more concise. * add newline to docstring Co-authored-by: ohemorange Co-authored-by: ohemorange --- certbot/certbot/_internal/renewal.py | 52 +++++++++++----------- certbot/tests/renewal_test.py | 65 ++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 26 deletions(-) diff --git a/certbot/certbot/_internal/renewal.py b/certbot/certbot/_internal/renewal.py index 1d008193d..9b528cb6a 100644 --- a/certbot/certbot/_internal/renewal.py +++ b/certbot/certbot/_internal/renewal.py @@ -19,6 +19,7 @@ import zope.component from acme.magic_typing import List from acme.magic_typing import Optional # pylint: disable=unused-import from certbot import crypto_util +from certbot.display import util as display_util from certbot import errors from certbot import interfaces from certbot import util @@ -347,40 +348,42 @@ def report(msgs, category): def _renew_describe_results(config, renew_successes, renew_failures, renew_skipped, parse_failures): + # type: (interfaces.IConfig, List[str], List[str], List[str], List[str]) -> None + """ + Print a report to the terminal about the results of the renewal process. - out = [] # type: List[str] - notify = out.append - disp = zope.component.getUtility(interfaces.IDisplay) + :param interfaces.IConfig config: Configuration + :param list renew_successes: list of fullchain paths which were renewed + :param list renew_failures: list of fullchain paths which failed to be renewed + :param list renew_skipped: list of messages to print about skipped certificates + :param list parse_failures: list of renewal parameter paths which had erorrs + """ + notify = display_util.notify + notify_error = logger.error - def notify_error(err): - """Notify and log errors.""" - notify(str(err)) - logger.error(err) + notify('\n{}'.format(display_util.SIDE_FRAME)) + + renewal_noun = "simulated renewal" if config.dry_run else "renewal" - if config.dry_run: - notify("** DRY RUN: simulating 'certbot renew' close to cert expiry") - notify("** (The test certificates below have not been saved.)") - notify("") if renew_skipped: notify("The following certs are not due for renewal yet:") notify(report(renew_skipped, "skipped")) if not renew_successes and not renew_failures: - notify("No renewals were attempted.") + notify("No {renewal}s were attempted.".format(renewal=renewal_noun)) if (config.pre_hook is not None or config.renew_hook is not None or config.post_hook is not None): notify("No hooks were run.") elif renew_successes and not renew_failures: - notify("Congratulations, all renewals succeeded. The following certs " - "have been renewed:") + notify("Congratulations, all {renewal}s succeeded: ".format(renewal=renewal_noun)) notify(report(renew_successes, "success")) elif renew_failures and not renew_successes: - notify_error("All renewal attempts failed. The following certs could " - "not be renewed:") + notify_error("All %ss failed. The following certs could " + "not be renewed:", renewal_noun) notify_error(report(renew_failures, "failure")) elif renew_failures and renew_successes: - notify("The following certs were successfully renewed:") + notify("The following {renewal}s succeeded:".format(renewal=renewal_noun)) notify(report(renew_successes, "success") + "\n") - notify_error("The following certs could not be renewed:") + notify_error("The following %ss failed:", renewal_noun) notify_error(report(renew_failures, "failure")) if parse_failures: @@ -388,11 +391,7 @@ def _renew_describe_results(config, renew_successes, renew_failures, "were invalid: ") notify(report(parse_failures, "parsefail")) - if config.dry_run: - notify("** DRY RUN: simulating 'certbot renew' close to cert expiry") - notify("** (The test certificates above have not been saved.)") - - disp.notification("\n".join(out), wrap=False) + notify(display_util.SIDE_FRAME) def handle_renewal_request(config): @@ -482,9 +481,10 @@ def handle_renewal_request(config): except Exception as e: # pylint: disable=broad-except # obtain_cert (presumably) encountered an unanticipated problem. - logger.warning("Attempting to renew cert (%s) from %s produced an " - "unexpected error: %s. Skipping.", lineagename, - renewal_file, e) + logger.error( + "Failed to renew cert %s with error: %s", + lineagename, e + ) logger.debug("Traceback was:\n%s", traceback.format_exc()) renew_failures.append(renewal_candidate.fullchain) diff --git a/certbot/tests/renewal_test.py b/certbot/tests/renewal_test.py index e292d24fb..44c78c701 100644 --- a/certbot/tests/renewal_test.py +++ b/certbot/tests/renewal_test.py @@ -163,5 +163,70 @@ class RestoreRequiredConfigElementsTest(test_util.ConfigTestCase): self.assertEqual(self.config.server, constants.CLI_DEFAULTS['server']) +class DescribeResultsTest(unittest.TestCase): + """Tests for certbot._internal.renewal._renew_describe_results.""" + def setUp(self): + self.patchers = { + 'log_error': mock.patch('certbot._internal.renewal.logger.error'), + 'notify': mock.patch('certbot._internal.renewal.display_util.notify')} + self.mock_notify = self.patchers['notify'].start() + self.mock_error = self.patchers['log_error'].start() + + def tearDown(self): + for patch in self.patchers.values(): + patch.stop() + + @classmethod + def _call(cls, *args, **kwargs): + from certbot._internal.renewal import _renew_describe_results + _renew_describe_results(*args, **kwargs) + + def _assert_success_output(self, lines): + self.mock_notify.assert_has_calls([mock.call(l) for l in lines]) + + def test_no_renewal_attempts(self): + self._call(mock.MagicMock(dry_run=True), [], [], [], []) + self._assert_success_output(['No simulated renewals were attempted.']) + + def test_successful_renewal(self): + self._call(mock.MagicMock(dry_run=False), ['good.pem'], None, None, None) + self._assert_success_output([ + '\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -', + 'Congratulations, all renewals succeeded: ', + ' good.pem (success)', + '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -', + ]) + + def test_failed_renewal(self): + self._call(mock.MagicMock(dry_run=False), [], ['bad.pem'], [], []) + self._assert_success_output([ + '\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -', + '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -', + ]) + self.mock_error.assert_has_calls([ + mock.call('All %ss failed. The following certs could not be renewed:', 'renewal'), + mock.call(' bad.pem (failure)'), + ]) + + def test_all_renewal(self): + self._call(mock.MagicMock(dry_run=True), + ['good.pem', 'good2.pem'], ['bad.pem', 'bad2.pem'], + ['foo.pem expires on 123'], ['errored.conf']) + self._assert_success_output([ + '\n- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -', + 'The following certs are not due for renewal yet:', + ' foo.pem expires on 123 (skipped)', + 'The following simulated renewals succeeded:', + ' good.pem (success)\n good2.pem (success)\n', + '\nAdditionally, the following renewal configurations were invalid: ', + ' errored.conf (parsefail)', + '- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -', + ]) + self.mock_error.assert_has_calls([ + mock.call('The following %ss failed:', 'simulated renewal'), + mock.call(' bad.pem (failure)\n bad2.pem (failure)'), + ]) + + if __name__ == "__main__": unittest.main() # pragma: no cover From d476aa43899c06320f5cf7c6e40f859a5bf9d1f8 Mon Sep 17 00:00:00 2001 From: Adrien Ferrand Date: Fri, 4 Dec 2020 02:00:32 +0100 Subject: [PATCH 34/42] Update both main VA and remote VA to use the provided DNS server (#8467) --- .../utils/acme_server.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/certbot-ci/certbot_integration_tests/utils/acme_server.py b/certbot-ci/certbot_integration_tests/utils/acme_server.py index 5559b44a6..aa501a279 100755 --- a/certbot-ci/certbot_integration_tests/utils/acme_server.py +++ b/certbot-ci/certbot_integration_tests/utils/acme_server.py @@ -149,10 +149,10 @@ class ACMEServer(object): [pebble_path, '-config', pebble_config_path, '-dnsserver', dns_server, '-strict'], env=environ) - # pebble_ocsp_server is imported here and not at the top of module in order to avoid a useless - # ImportError, in the case where cryptography dependency is too old to support ocsp, but - # Boulder is used instead of Pebble, so pebble_ocsp_server is not used. This is the typical - # situation of integration-certbot-oldest tox testenv. + # pebble_ocsp_server is imported here and not at the top of module in order to avoid a + # useless ImportError, in the case where cryptography dependency is too old to support ocsp, + # but Boulder is used instead of Pebble, so pebble_ocsp_server is not used. This is the + # typical situation of integration-certbot-oldest tox testenv. from certbot_integration_tests.utils import pebble_ocsp_server self._launch_process([sys.executable, pebble_ocsp_server.__file__]) @@ -178,11 +178,12 @@ class ACMEServer(object): if self._dns_server: # Change Boulder config to use the provided DNS server - with open(join(instance_path, 'test/config/va.json'), 'r') as file_h: - config = json.loads(file_h.read()) - config['va']['dnsResolvers'] = [self._dns_server] - with open(join(instance_path, 'test/config/va.json'), 'w') as file_h: - file_h.write(json.dumps(config, indent=2, separators=(',', ': '))) + for suffix in ["", "-remote-a", "-remote-b"]: + with open(join(instance_path, 'test/config/va{}.json'.format(suffix)), 'r') as f: + config = json.loads(f.read()) + config['va']['dnsResolvers'] = [self._dns_server] + with open(join(instance_path, 'test/config/va{}.json'.format(suffix)), 'w') as f: + f.write(json.dumps(config, indent=2, separators=(',', ': '))) try: # Launch the Boulder server From 356e8d84d6963d73ede820299d8d15304ab9be83 Mon Sep 17 00:00:00 2001 From: alexzorin Date: Sat, 5 Dec 2020 00:09:10 +1100 Subject: [PATCH 35/42] dns-google: improve credentials error message (#8482) This adds a 'Error parsing credentials file ...' wrapper to any errors raised inside certbot-dns-google's usage of oauth2client, to make it obvious to the user where the problem lies. --- .../certbot_dns_google/_internal/dns_google.py | 10 +++++++--- certbot-dns-google/tests/dns_google_test.py | 11 +++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/certbot-dns-google/certbot_dns_google/_internal/dns_google.py b/certbot-dns-google/certbot_dns_google/_internal/dns_google.py index 4eaed1783..1bd3468da 100644 --- a/certbot-dns-google/certbot_dns_google/_internal/dns_google.py +++ b/certbot-dns-google/certbot_dns_google/_internal/dns_google.py @@ -85,9 +85,13 @@ class _GoogleClient(object): scopes = ['https://www.googleapis.com/auth/ndev.clouddns.readwrite'] if account_json is not None: - credentials = ServiceAccountCredentials.from_json_keyfile_name(account_json, scopes) - with open(account_json) as account: - self.project_id = json.load(account)['project_id'] + try: + credentials = ServiceAccountCredentials.from_json_keyfile_name(account_json, scopes) + with open(account_json) as account: + self.project_id = json.load(account)['project_id'] + except Exception as e: + raise errors.PluginError( + "Error parsing credentials file '{}': {}".format(account_json, e)) else: credentials = None self.project_id = self.get_project_id() diff --git a/certbot-dns-google/tests/dns_google_test.py b/certbot-dns-google/tests/dns_google_test.py index 5af027cef..40002f143 100644 --- a/certbot-dns-google/tests/dns_google_test.py +++ b/certbot-dns-google/tests/dns_google_test.py @@ -107,6 +107,17 @@ class GoogleClientTest(unittest.TestCase): self.assertFalse(credential_mock.called) self.assertTrue(get_project_id_mock.called) + @mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name') + def test_client_bad_credentials_file(self, credential_mock): + credential_mock.side_effect = ValueError('Some exception buried in oauth2client') + with self.assertRaises(errors.PluginError) as cm: + self._setUp_client_with_mock([]) + self.assertEqual( + str(cm.exception), + "Error parsing credentials file '/not/a/real/path.json': " + "Some exception buried in oauth2client" + ) + @mock.patch('oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name') @mock.patch('certbot_dns_google._internal.dns_google.open', mock.mock_open(read_data='{"project_id": "' + PROJECT_ID + '"}'), create=True) From 5871de0c07cba22a4556e66dcdd68336ffa76b29 Mon Sep 17 00:00:00 2001 From: Mads Jensen Date: Fri, 4 Dec 2020 14:29:58 +0100 Subject: [PATCH 36/42] Removed some unused imports. (#8424) These were not annotated as something that should be ignored, and the test-suite passes with these changes. --- acme/acme/__init__.py | 1 - certbot-ci/windows_installer_integration_tests/conftest.py | 2 -- certbot/certbot/_internal/plugins/null.py | 1 - certbot/tests/client_test.py | 1 - certbot/tests/compat/filesystem_test.py | 1 - 5 files changed, 6 deletions(-) diff --git a/acme/acme/__init__.py b/acme/acme/__init__.py index d1679fcad..8b6ce88c0 100644 --- a/acme/acme/__init__.py +++ b/acme/acme/__init__.py @@ -6,7 +6,6 @@ This module is an implementation of the `ACME protocol`_. """ import sys -import warnings # This code exists to keep backwards compatibility with people using acme.jose # before it became the standalone josepy package. diff --git a/certbot-ci/windows_installer_integration_tests/conftest.py b/certbot-ci/windows_installer_integration_tests/conftest.py index e36654f90..c6a89c323 100644 --- a/certbot-ci/windows_installer_integration_tests/conftest.py +++ b/certbot-ci/windows_installer_integration_tests/conftest.py @@ -9,8 +9,6 @@ See https://docs.pytest.org/en/latest/reference.html#hook-reference from __future__ import print_function import os -import pytest - ROOT_PATH = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) diff --git a/certbot/certbot/_internal/plugins/null.py b/certbot/certbot/_internal/plugins/null.py index cf7c05a2b..5ab2f4a04 100644 --- a/certbot/certbot/_internal/plugins/null.py +++ b/certbot/certbot/_internal/plugins/null.py @@ -1,7 +1,6 @@ """Null plugin.""" import logging -import zope.component import zope.interface from certbot import interfaces diff --git a/certbot/tests/client_test.py b/certbot/tests/client_test.py index f40689e57..f058cb658 100644 --- a/certbot/tests/client_test.py +++ b/certbot/tests/client_test.py @@ -13,7 +13,6 @@ except ImportError: # pragma: no cover from certbot import errors from certbot import util from certbot._internal import account -from certbot.compat import filesystem from certbot.compat import os import certbot.tests.util as test_util diff --git a/certbot/tests/compat/filesystem_test.py b/certbot/tests/compat/filesystem_test.py index 262fd02b5..263029cb0 100644 --- a/certbot/tests/compat/filesystem_test.py +++ b/certbot/tests/compat/filesystem_test.py @@ -1,7 +1,6 @@ """Tests for certbot.compat.filesystem""" import contextlib import errno -import stat import unittest try: From dc3ac13750de7df2f48b7808fb7ffca2b1335cf8 Mon Sep 17 00:00:00 2001 From: alexzorin Date: Sun, 6 Dec 2020 19:10:03 +1100 Subject: [PATCH 37/42] snap: disable the "user site-packages directory" (#8509) Although Certbot is a classic snap, it shouldn't load Python code from the host system. This change prevents packages being loaded from the "user site-packages directory" (PEP-370). i.e. Certbot will no longer load DNS plugins installed via `pip install --user certbot-dns-*`. --- certbot/CHANGELOG.md | 3 ++- snap/snapcraft.yaml | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index e987f2a1c..82ba6121a 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -14,7 +14,8 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). ### Fixed -* +* The Certbot snap no longer loads packages installed via `pip install --user`. This + was unintended and DNS plugins should be installed via `snap` instead. More details about these changes can be found on our GitHub repo. diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 5fbf8503d..09d409d26 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -20,13 +20,13 @@ adopt-info: certbot apps: certbot: - command: bin/python3 $SNAP/bin/certbot + command: bin/python3 -s $SNAP/bin/certbot environment: 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" CERTBOT_SNAPPED: "True" renew: - command: bin/python3 $SNAP/bin/certbot -q renew + command: bin/python3 -s $SNAP/bin/certbot -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" From 38017473c5f945cbf85744d55ef876fdfcc72b2b Mon Sep 17 00:00:00 2001 From: alexzorin Date: Sun, 6 Dec 2020 19:23:33 +1100 Subject: [PATCH 38/42] add coverage testing to dns-rfc2136 integration (#8469) * add coverage testing to dns-rfc2136 integration * add coverage rule for certbot/* as well --- tox.ini | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tox.ini b/tox.ini index f87c1dbca..142e62a92 100644 --- a/tox.ini +++ b/tox.ini @@ -222,7 +222,11 @@ commands = {[base]pip_install} acme certbot certbot-dns-rfc2136 certbot-ci pytest certbot-ci/certbot_integration_tests/rfc2136_tests \ --acme-server=pebble --dns-server=bind \ - --numprocesses=1 + --numprocesses=1 \ + --cov=acme --cov=certbot --cov=certbot_dns_rfc2136 --cov-report= \ + --cov-config=certbot-ci/certbot_integration_tests/.coveragerc + coverage report --include 'certbot/*' --show-missing --fail-under=45 + coverage report --include 'certbot-dns-rfc2136/*' --show-missing --fail-under=87 [testenv:integration-external] # Run integration tests with Certbot outside of tox's virtual environment. From 447b6ffaefe0af1cd8b2aefb6e2d1a4a66b08d98 Mon Sep 17 00:00:00 2001 From: Adrien Ferrand Date: Tue, 8 Dec 2020 00:18:00 +0100 Subject: [PATCH 39/42] Completely deprecate certbot-auto (#8489) Fixes #8296 * Completely deprecate certbot-auto * Add changelog --- certbot/CHANGELOG.md | 2 +- letsencrypt-auto-source/letsencrypt-auto | 22 +------ .../letsencrypt-auto.template | 22 +------ .../letstest/scripts/test_leauto_upgrades.sh | 32 ++-------- ...st_letsencrypt_auto_certonly_standalone.sh | 58 +++---------------- 5 files changed, 16 insertions(+), 120 deletions(-) diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index 82ba6121a..eef84f7f5 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -10,7 +10,7 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). ### Changed -* +* certbot-auto was deprecated on all systems. ### Fixed diff --git a/letsencrypt-auto-source/letsencrypt-auto b/letsencrypt-auto-source/letsencrypt-auto index 789904992..7f358f805 100755 --- a/letsencrypt-auto-source/letsencrypt-auto +++ b/letsencrypt-auto-source/letsencrypt-auto @@ -804,6 +804,7 @@ elif [ -f /etc/mageia-release ]; then # Mageia has both /etc/mageia-release and /etc/redhat-release DEPRECATED_OS=1 elif [ -f /etc/redhat-release ]; then + DEPRECATED_OS=1 # Run DeterminePythonVersion to decide on the basis of available Python versions # whether to use 2.x or 3.x on RedHat-like systems. # Then, revert LE_PYTHON to its previous state. @@ -836,12 +837,7 @@ elif [ -f /etc/redhat-release ]; then INTERACTIVE_BOOTSTRAP=1 fi - Bootstrap() { - BootstrapMessage "Legacy RedHat-based OSes that will use Python3" - BootstrapRpmPython3Legacy - } USE_PYTHON_3=1 - BOOTSTRAP_VERSION="BootstrapRpmPython3Legacy $BOOTSTRAP_RPM_PYTHON3_LEGACY_VERSION" # Try now to enable SCL rh-python36 for systems already bootstrapped # NB: EnablePython36SCL has been defined along with BootstrapRpmPython3Legacy in certbot-auto @@ -860,18 +856,7 @@ elif [ -f /etc/redhat-release ]; then fi if [ "$RPM_USE_PYTHON_3" = 1 ]; then - Bootstrap() { - BootstrapMessage "RedHat-based OSes that will use Python3" - BootstrapRpmPython3 - } USE_PYTHON_3=1 - BOOTSTRAP_VERSION="BootstrapRpmPython3 $BOOTSTRAP_RPM_PYTHON3_VERSION" - else - Bootstrap() { - BootstrapMessage "RedHat-based OSes" - BootstrapRpmCommon - } - BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION" fi fi @@ -889,10 +874,7 @@ elif uname | grep -iq FreeBSD ; then elif uname | grep -iq Darwin ; then DEPRECATED_OS=1 elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then - Bootstrap() { - ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon - } - BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION" + DEPRECATED_OS=1 elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then DEPRECATED_OS=1 else diff --git a/letsencrypt-auto-source/letsencrypt-auto.template b/letsencrypt-auto-source/letsencrypt-auto.template index 5eb82b705..bc27469fb 100755 --- a/letsencrypt-auto-source/letsencrypt-auto.template +++ b/letsencrypt-auto-source/letsencrypt-auto.template @@ -326,6 +326,7 @@ elif [ -f /etc/mageia-release ]; then # Mageia has both /etc/mageia-release and /etc/redhat-release DEPRECATED_OS=1 elif [ -f /etc/redhat-release ]; then + DEPRECATED_OS=1 # Run DeterminePythonVersion to decide on the basis of available Python versions # whether to use 2.x or 3.x on RedHat-like systems. # Then, revert LE_PYTHON to its previous state. @@ -358,12 +359,7 @@ elif [ -f /etc/redhat-release ]; then INTERACTIVE_BOOTSTRAP=1 fi - Bootstrap() { - BootstrapMessage "Legacy RedHat-based OSes that will use Python3" - BootstrapRpmPython3Legacy - } USE_PYTHON_3=1 - BOOTSTRAP_VERSION="BootstrapRpmPython3Legacy $BOOTSTRAP_RPM_PYTHON3_LEGACY_VERSION" # Try now to enable SCL rh-python36 for systems already bootstrapped # NB: EnablePython36SCL has been defined along with BootstrapRpmPython3Legacy in certbot-auto @@ -382,18 +378,7 @@ elif [ -f /etc/redhat-release ]; then fi if [ "$RPM_USE_PYTHON_3" = 1 ]; then - Bootstrap() { - BootstrapMessage "RedHat-based OSes that will use Python3" - BootstrapRpmPython3 - } USE_PYTHON_3=1 - BOOTSTRAP_VERSION="BootstrapRpmPython3 $BOOTSTRAP_RPM_PYTHON3_VERSION" - else - Bootstrap() { - BootstrapMessage "RedHat-based OSes" - BootstrapRpmCommon - } - BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION" fi fi @@ -411,10 +396,7 @@ elif uname | grep -iq FreeBSD ; then elif uname | grep -iq Darwin ; then DEPRECATED_OS=1 elif [ -f /etc/issue ] && grep -iq "Amazon Linux" /etc/issue ; then - Bootstrap() { - ExperimentalBootstrap "Amazon Linux" BootstrapRpmCommon - } - BOOTSTRAP_VERSION="BootstrapRpmCommon $BOOTSTRAP_RPM_COMMON_VERSION" + DEPRECATED_OS=1 elif [ -f /etc/product ] && grep -q "Joyent Instance" /etc/product ; then DEPRECATED_OS=1 else diff --git a/tests/letstest/scripts/test_leauto_upgrades.sh b/tests/letstest/scripts/test_leauto_upgrades.sh index 51ff640c5..1eeafad21 100755 --- a/tests/letstest/scripts/test_leauto_upgrades.sh +++ b/tests/letstest/scripts/test_leauto_upgrades.sh @@ -105,15 +105,10 @@ if ./letsencrypt-auto -v --debug --version | grep "WARNING: couldn't find Python exit 1 fi -# On systems like Debian where certbot-auto is deprecated, we expect it to -# leave existing Certbot installations unmodified so we check for the same -# version that was initially installed below. Once certbot-auto is deprecated -# on RHEL systems, we can unconditionally check for INITIAL_VERSION. -if [ -f /etc/debian_version ]; then - EXPECTED_VERSION="$INITIAL_VERSION" -else - EXPECTED_VERSION=$(grep -m1 LE_AUTO_VERSION certbot-auto | cut -d\" -f2) -fi +# Since certbot-auto is deprecated, we expect it to leave existing Certbot +# installations unmodified so we check for the same version that was initially +# installed below. +EXPECTED_VERSION="$INITIAL_VERSION" if ! /opt/eff.org/certbot/venv/bin/letsencrypt --version 2>&1 | tail -n1 | grep "^certbot $EXPECTED_VERSION$" ; then echo unexpected certbot version found @@ -124,22 +119,3 @@ if ! diff letsencrypt-auto letsencrypt-auto-source/letsencrypt-auto ; then echo letsencrypt-auto and letsencrypt-auto-source/letsencrypt-auto differ exit 1 fi - -if [ "$RUN_RHEL6_TESTS" = 1 ]; then - # Add the SCL python release to PATH in order to resolve python3 command - PATH="/opt/rh/rh-python36/root/usr/bin:$PATH" - if ! command -v python3; then - echo "Python3 wasn't properly installed" - exit 1 - fi - if [ "$(/opt/eff.org/certbot/venv/bin/python -V 2>&1 | cut -d" " -f 2 | cut -d. -f1)" != 3 ]; then - echo "Python3 wasn't used in venv!" - exit 1 - fi - - if [ "$("$PYTHON_NAME" tools/readlink.py $OLD_VENV_PATH)" != "/opt/eff.org/certbot/venv" ]; then - echo symlink from old venv path not properly created! - exit 1 - fi -fi -echo upgrade appeared to be successful diff --git a/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh b/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh index 15cf9ee1b..fc5435916 100755 --- a/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh +++ b/tests/letstest/scripts/test_letsencrypt_auto_certonly_standalone.sh @@ -16,58 +16,14 @@ sudo chown root "$LE_AUTO_PATH" sudo chmod 0755 "$LE_AUTO_PATH" export PATH="$LE_AUTO_DIR:$PATH" -# On systems like Debian where certbot-auto is deprecated, we expect -# certbot-auto to error and refuse to install Certbot. Once certbot-auto is -# deprecated on RHEL systems, we can unconditionally run this code. -if [ -f /etc/debian_version ]; then - set +o pipefail - if ! letsencrypt-auto --debug --version | grep "Certbot cannot be installed."; then - echo "letsencrypt-auto didn't report being uninstallable." - exit 1 - fi - if [ ${PIPESTATUS[0]} != 1 ]; then - echo "letsencrypt-auto didn't exit with status 1 as expected" - exit 1 - fi - # letsencrypt-auto is deprecated and cannot be installed on this system so - # we cannot run the rest of this test. - exit 0 -fi - -letsencrypt-auto --os-packages-only --debug --version - -# This script sets the environment variables PYTHON_NAME, VENV_PATH, and -# VENV_SCRIPT based on the version of Python available on the system. For -# instance, Fedora uses Python 3 and Python 2 is not installed. -. tests/letstest/scripts/set_python_envvars.sh - -# Create a venv-like layout at the old virtual environment path to test that a -# symlink is properly created when letsencrypt-auto runs. -HOME=${HOME:-~root} -XDG_DATA_HOME=${XDG_DATA_HOME:-~/.local/share} -OLD_VENV_BIN="$XDG_DATA_HOME/letsencrypt/bin" -mkdir -p "$OLD_VENV_BIN" -touch "$OLD_VENV_BIN/letsencrypt" - -letsencrypt-auto certonly --no-self-upgrade -v --standalone --debug \ - --text --agree-tos \ - --renew-by-default --redirect \ - --register-unsafely-without-email \ - --domain $PUBLIC_HOSTNAME --server $BOULDER_URL - -LINK_PATH=$("$PYTHON_NAME" tools/readlink.py ${XDG_DATA_HOME:-~/.local/share}/letsencrypt) -if [ "$LINK_PATH" != "/opt/eff.org/certbot/venv" ]; then - echo symlink from old venv path not properly created! +# Since certbot-auto is deprecated, we expect certbot-auto to error and +# refuse to install Certbot. +set +o pipefail +if ! letsencrypt-auto --debug --version | grep "Certbot cannot be installed."; then + echo "letsencrypt-auto didn't report being uninstallable." exit 1 fi - -if ! letsencrypt-auto --help --no-self-upgrade | grep -F "letsencrypt-auto [SUBCOMMAND]"; then - echo "letsencrypt-auto not included in help output!" - exit 1 -fi - -OUTPUT_LEN=$(letsencrypt-auto --install-only --no-self-upgrade --quiet 2>&1 | wc -c) -if [ "$OUTPUT_LEN" != 0 ]; then - echo letsencrypt-auto produced unexpected output! +if [ ${PIPESTATUS[0]} != 1 ]; then + echo "letsencrypt-auto didn't exit with status 1 as expected" exit 1 fi From 9045c03949bd2d690c17fe89518eb743626cfd6b Mon Sep 17 00:00:00 2001 From: Adrien Ferrand Date: Tue, 8 Dec 2020 21:19:42 +0100 Subject: [PATCH 40/42] Deprecate support for Python 2 (#8491) Fixes #8388 * Deprecate support for Python 2 * Ignore deprecation warning * Update certbot/CHANGELOG.md Co-authored-by: Brad Warren --- acme/acme/__init__.py | 8 ++++++++ certbot/CHANGELOG.md | 2 ++ certbot/certbot/__init__.py | 9 +++++++++ certbot/certbot/_internal/main.py | 8 ++++++++ pytest.ini | 3 +++ 5 files changed, 30 insertions(+) diff --git a/acme/acme/__init__.py b/acme/acme/__init__.py index 8b6ce88c0..3ec5203bf 100644 --- a/acme/acme/__init__.py +++ b/acme/acme/__init__.py @@ -6,6 +6,7 @@ This module is an implementation of the `ACME protocol`_. """ import sys +import warnings # This code exists to keep backwards compatibility with people using acme.jose # before it became the standalone josepy package. @@ -19,3 +20,10 @@ for mod in list(sys.modules): # preserved (acme.jose.* is josepy.*) if mod == 'josepy' or mod.startswith('josepy.'): sys.modules['acme.' + mod.replace('josepy', 'jose', 1)] = sys.modules[mod] + +if sys.version_info[0] == 2: + warnings.warn( + "Python 2 support will be dropped in the next release of acme. " + "Please upgrade your Python version.", + PendingDeprecationWarning, + ) # pragma: no cover diff --git a/certbot/CHANGELOG.md b/certbot/CHANGELOG.md index eef84f7f5..6e2d70d9d 100644 --- a/certbot/CHANGELOG.md +++ b/certbot/CHANGELOG.md @@ -10,6 +10,8 @@ Certbot adheres to [Semantic Versioning](https://semver.org/). ### Changed +* We deprecated support for Python 2 in Certbot and its ACME library. + Support for Python 2 will be removed in the next planned release of Certbot. * certbot-auto was deprecated on all systems. ### Fixed diff --git a/certbot/certbot/__init__.py b/certbot/certbot/__init__.py index 11c97dfac..98009a71b 100644 --- a/certbot/certbot/__init__.py +++ b/certbot/certbot/__init__.py @@ -1,4 +1,13 @@ """Certbot client.""" +import warnings +import sys # version number like 1.2.3a0, must have at least 2 parts, like 1.2 __version__ = '1.11.0.dev0' + +if sys.version_info[0] == 2: + warnings.warn( + "Python 2 support will be dropped in the next release of Certbot. " + "Please upgrade your Python version.", + PendingDeprecationWarning, + ) # pragma: no cover diff --git a/certbot/certbot/_internal/main.py b/certbot/certbot/_internal/main.py index 1d68bde59..a1cd19560 100644 --- a/certbot/certbot/_internal/main.py +++ b/certbot/certbot/_internal/main.py @@ -5,6 +5,7 @@ from __future__ import print_function import functools import logging.handlers import sys +import warnings import configobj import josepy as jose @@ -1402,6 +1403,13 @@ def main(cli_args=None): if config.func != plugins_cmd: # pylint: disable=comparison-with-callable raise + if sys.version_info[0] == 2: + warnings.warn( + "Python 2 support will be dropped in the next release of Certbot. " + "Please upgrade your Python version.", + PendingDeprecationWarning, + ) # pragma: no cover + set_displayer(config) # Reporter diff --git a/pytest.ini b/pytest.ini index 16aa9a193..b7a6928ea 100644 --- a/pytest.ini +++ b/pytest.ini @@ -4,6 +4,8 @@ [pytest] # In general, all warnings are treated as errors. Here are the exceptions: # 1- decodestring: https://github.com/rthalley/dnspython/issues/338 +# 2- Python 2 deprecation: https://github.com/certbot/certbot/issues/8388 +# (to be removed with Certbot 1.12.0 and its drop of Python 2 support) # Warnings being triggered by our plugins using deprecated features in # acme/certbot should be fixed by having our plugins no longer using the # deprecated code rather than adding them to the list of ignored warnings here. @@ -14,3 +16,4 @@ filterwarnings = error ignore:decodestring:DeprecationWarning + ignore:Python 2 support will be dropped:PendingDeprecationWarning From 148246b85b5b9fd37c91a9beed8318da66987d90 Mon Sep 17 00:00:00 2001 From: Brad Warren Date: Wed, 9 Dec 2020 00:02:53 -0800 Subject: [PATCH 41/42] Add reminders to update documentation (#8518) * Add documentation PR checklist item. * Update contributing doc --- certbot/docs/contributing.rst | 6 ++++-- pull_request_template.md | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/certbot/docs/contributing.rst b/certbot/docs/contributing.rst index eb90b05f4..4e2643d7c 100644 --- a/certbot/docs/contributing.rst +++ b/certbot/docs/contributing.rst @@ -516,11 +516,13 @@ Steps: 4. Run ``tox --skip-missing-interpreters`` to run the entire test suite including coverage. The ``--skip-missing-interpreters`` argument ignores missing versions of Python needed for running the tests. Fix any errors. -5. Submit the PR. Once your PR is open, please do not force push to the branch +5. If any documentation should be added or updated as part of the changes you + have made, please include the documentation changes in your PR. +6. Submit the PR. Once your PR is open, please do not force push to the branch containing your pull request to squash or amend commits. We use `squash merges `_ on PRs and rewriting commits makes changes harder to track between reviews. -6. Did your tests pass on Azure Pipelines? If they didn't, fix any errors. +7. Did your tests pass on Azure Pipelines? If they didn't, fix any errors. .. _ask for help: diff --git a/pull_request_template.md b/pull_request_template.md index c806d33e8..53298291b 100644 --- a/pull_request_template.md +++ b/pull_request_template.md @@ -1,4 +1,5 @@ ## Pull Request Checklist - [ ] If the change being made is to a [distributed component](https://certbot.eff.org/docs/contributing.html#code-components-and-layout), edit the `master` section of `certbot/CHANGELOG.md` to include a description of the change being made. +- [ ] Add or update any documentation as needed to support the changes in this PR. - [ ] Include your name in `AUTHORS.md` if you like. From 878c3e396fc42110c8e96351cb4fc71ac0aadf68 Mon Sep 17 00:00:00 2001 From: Adrien Ferrand Date: Thu, 10 Dec 2020 21:05:32 +0100 Subject: [PATCH 42/42] Avoid --system-site-packages during the snap build by preparing a venv with pipstrap that already includes wheel (#8445) This PR proposes an alternative configuration for the snap build that avoid the need to use `--system-site-package` when constructing the virtual environment in the snap. The rationale of `--system-site-package` was that by default, snapcraft creates a virtual environment without `wheel` installed in it. However we need it to build the wheels like `cryptography` on ARM architectures. Sadly there is not way to instruct snapcraft to install some build dependencies in the virtual environment before it kicks in the build phase itself, without overriding that entire phase (which is possible with `parts.override-build`). The alternative proposed here is to not override the entire build part, but just add some preparatory steps that will be done before the main actions handled by the `python` snap plugin. To do so, I take advantage of the `--upgrade` flag available for the `venv` module in Python 3. This allows to reuse a preexisting virtual environment, and upgrade its component. Adding a flag to the `venv` call is possible in snapcraft, thanks to the `SNAPCRAFT_PYTHON_VENV_ARGS` environment variable (and it is already used to set the `--system-site-package`). Given `SNAPCRAFT_PYTHON_VENV_ARGS` set to `--upgrade` , we configure the build phase as follows: * create the virtual environment ourselves in the expected place (`SNAPCRAFT_PART_INSTALL`) * leverage `tools/pipstrap.py` to install `setuptools`, `pip`, and of course, `wheel` * let the standard build operations kick in with a call to `snapcraftctl build`: at that point the `--upgrade` flag will be appended to the standard virtual environment creation, reusing our crafted venv instead of creating a new one. This approach has also the advantage to invoke `pipstrap.py` as it is done for the other deployable artifacts, and for the PR validations, reducing risks of shifts between the various deployment methods. --- snap/snapcraft.yaml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/snap/snapcraft.yaml b/snap/snapcraft.yaml index 09d409d26..45072ddd6 100644 --- a/snap/snapcraft.yaml +++ b/snap/snapcraft.yaml @@ -64,7 +64,6 @@ parts: - libpython3.8-stdlib - libpython3.8-minimal - python3-pip - - python3-setuptools - python3-wheel - python3-venv - python3-minimal @@ -74,13 +73,16 @@ parts: # To build cryptography and cffi if needed build-packages: [gcc, libffi-dev, libssl-dev, git, libaugeas-dev, python3-dev] build-environment: - - SNAPCRAFT_PYTHON_VENV_ARGS: --system-site-packages + - SNAPCRAFT_PYTHON_VENV_ARGS: --upgrade - PIP_NO_BUILD_ISOLATION: "no" + override-build: | + python3 -m venv "${SNAPCRAFT_PART_INSTALL}" + "${SNAPCRAFT_PART_INSTALL}"/bin/python3 "${SNAPCRAFT_PART_SRC}/tools/pipstrap.py" + snapcraftctl build override-pull: | - snapcraftctl pull - 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 `grep -oP "__version__ = '\K.*(?=')" $SNAPCRAFT_PART_SRC/certbot/certbot/__init__.py` + snapcraftctl pull + python3 "${SNAPCRAFT_PART_SRC}/tools/strip_hashes.py" "${SNAPCRAFT_PART_SRC}/letsencrypt-auto-source/pieces/dependency-requirements.txt" | grep -v python-augeas > "${SNAPCRAFT_PART_SRC}/snap-constraints.txt" + snapcraftctl set-version `grep -oP "__version__ = '\K.*(?=')" "${SNAPCRAFT_PART_SRC}/certbot/certbot/__init__.py"` shared-metadata: plugin: dump source: .