Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-certbot for openSUSE:Factory 
checked in at 2022-07-11 19:10:19
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-certbot (Old)
 and      /work/SRC/openSUSE:Factory/.python-certbot.new.1523 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-certbot"

Mon Jul 11 19:10:19 2022 rev:43 rq:988433 version:1.29.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-certbot/python-certbot.changes    
2022-06-25 10:25:03.274741630 +0200
+++ /work/SRC/openSUSE:Factory/.python-certbot.new.1523/python-certbot.changes  
2022-07-11 19:11:29.887791619 +0200
@@ -1,0 +2,15 @@
+Mon Jul 11 13:07:42 UTC 2022 - Dirk M??ller <[email protected]>
+
+- update to 1.29.0:
+  * --allow-subset-of-names will now additionally retry in cases where domains
+    are rejected while creating or finalizing orders. This requires subproblem
+    support from the ACME server
+  * The show_account subcommand now uses the "newAccount" ACME endpoint to
+    fetch the account data, so it doesn't rely on the locally stored account 
URL.
+    This fixes situations where Certbot
+    would use old ACMEv1 registration info with non-functional account URLs.
+  * The generated Certificate Signing Requests are now generated as version 1
+    instead of version 3. This resolves situations in where strict enforcement
+    of PKCS#10 meant that CSRs that were generated as version 3 were rejected
+
+-------------------------------------------------------------------

Old:
----
  certbot-1.28.0.tar.gz
  certbot-1.28.0.tar.gz.asc

New:
----
  certbot-1.29.0.tar.gz
  certbot-1.29.0.tar.gz.asc

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-certbot.spec ++++++
--- /var/tmp/diff_new_pack.OVU7tl/_old  2022-07-11 19:11:30.219792101 +0200
+++ /var/tmp/diff_new_pack.OVU7tl/_new  2022-07-11 19:11:30.223792106 +0200
@@ -19,7 +19,7 @@
 %{?!python_module:%define python_module() python-%{**} python3-%{**}}
 %define skip_python2 1
 Name:           python-certbot
-Version:        1.28.0
+Version:        1.29.0
 Release:        0
 Summary:        ACME client
 License:        Apache-2.0

++++++ certbot-1.28.0.tar.gz -> certbot-1.29.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-1.28.0/CHANGELOG.md 
new/certbot-1.29.0/CHANGELOG.md
--- old/certbot-1.28.0/CHANGELOG.md     2022-06-07 21:41:07.000000000 +0200
+++ new/certbot-1.29.0/CHANGELOG.md     2022-07-05 20:15:47.000000000 +0200
@@ -2,12 +2,33 @@
 
 Certbot adheres to [Semantic Versioning](https://semver.org/).
 
+## 1.29.0 - 2022-07-05
+
+### Added
+
+* Updated Windows installer to be signed and trusted in Windows 
+
+### Changed
+
+* `--allow-subset-of-names` will now additionally retry in cases where domains 
are rejected while creating or finalizing orders. This requires subproblem 
support from the ACME server.
+
+### Fixed
+
+* The `show_account` subcommand now uses the "newAccount" ACME endpoint to 
fetch the account
+  data, so it doesn't rely on the locally stored account URL. This fixes 
situations where Certbot
+  would use old ACMEv1 registration info with non-functional account URLs.
+
+* The generated Certificate Signing Requests are now generated as version 1 
instead of version 3. This resolves situations in where strict enforcement of 
PKCS#10 meant that CSRs that were generated as version 3 were rejected.
+
+More details about these changes can be found on our GitHub repo.
+
 ## 1.28.0 - 2022-06-07
 
 ### Added
 
 * Updated Apache/NGINX TLS configs to document contents are based on 
ssl-config.mozilla.org
 
+
 ### Changed
 
 * A change to order finalization has been made to the `acme` module and 
Certbot:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-1.28.0/PKG-INFO new/certbot-1.29.0/PKG-INFO
--- old/certbot-1.28.0/PKG-INFO 2022-06-07 21:41:09.812716700 +0200
+++ new/certbot-1.29.0/PKG-INFO 2022-07-05 20:15:48.407816600 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: certbot
-Version: 1.28.0
+Version: 1.29.0
 Summary: ACME client
 Home-page: https://github.com/letsencrypt/letsencrypt
 Author: Certbot Project
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-1.28.0/certbot/__init__.py 
new/certbot-1.29.0/certbot/__init__.py
--- old/certbot-1.28.0/certbot/__init__.py      2022-06-07 21:41:08.000000000 
+0200
+++ new/certbot-1.29.0/certbot/__init__.py      2022-07-05 20:15:48.000000000 
+0200
@@ -1,3 +1,3 @@
 """Certbot client."""
 # version number like 1.2.3a0, must have at least 2 parts, like 1.2
-__version__ = '1.28.0'
+__version__ = '1.29.0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-1.28.0/certbot/_internal/client.py 
new/certbot-1.29.0/certbot/_internal/client.py
--- old/certbot-1.28.0/certbot/_internal/client.py      2022-06-07 
21:41:07.000000000 +0200
+++ new/certbot-1.29.0/certbot/_internal/client.py      2022-07-05 
20:15:47.000000000 +0200
@@ -438,7 +438,17 @@
             csr = crypto_util.generate_csr(key, domains, self.config.csr_dir,
                                            self.config.must_staple, 
self.config.strict_permissions)
 
-        orderr = self._get_order_and_authorizations(csr.data, 
self.config.allow_subset_of_names)
+        try:
+            orderr = self._get_order_and_authorizations(csr.data, 
self.config.allow_subset_of_names)
+        except messages.Error as error:
+            # Some domains may be rejected during order creation.
+            # Certbot can retry the operation without the rejected
+            # domains contained within subproblems.
+            if self.config.allow_subset_of_names:
+                successful_domains = 
self._successful_domains_from_error(error, domains)
+                if successful_domains != domains and len(successful_domains) 
!= 0:
+                    return self._retry_obtain_certificate(key, csr, domains, 
successful_domains)
+            raise
         authzr = orderr.authorizations
         auth_domains = {a.body.identifier.value for a in authzr}
         successful_domains = [d for d in domains if d in auth_domains]
@@ -449,13 +459,20 @@
         # domains contains a wildcard because the ACME spec forbids identifiers
         # in authzs from containing a wildcard character.
         if self.config.allow_subset_of_names and successful_domains != domains:
-            if not self.config.dry_run:
-                os.remove(key.file)
-                os.remove(csr.file)
-            return self.obtain_certificate(successful_domains)
+            return self._retry_obtain_certificate(key, csr, domains, 
successful_domains)
         else:
-            cert, chain = self.obtain_certificate_from_csr(csr, orderr)
-            return cert, chain, key, csr
+            try:
+                cert, chain = self.obtain_certificate_from_csr(csr, orderr)
+                return cert, chain, key, csr
+            except messages.Error as error:
+                # Some domains may be rejected during the very late stage of
+                # order finalization. Certbot can retry the operation without
+                # the rejected domains contained within subproblems.
+                if self.config.allow_subset_of_names:
+                    successful_domains = 
self._successful_domains_from_error(error, domains)
+                    if successful_domains != domains and 
len(successful_domains) != 0:
+                        return self._retry_obtain_certificate(key, csr, 
domains, successful_domains)
+                raise
 
     def _get_order_and_authorizations(self, csr_pem: bytes,
                                       best_effort: bool) -> 
messages.OrderResource:
@@ -528,6 +545,27 @@
             key.pem, chain,
             self.config)
 
+    def _successful_domains_from_error(self, error: messages.Error, domains: 
List[str],
+                                ) -> List[str]:
+        if error.subproblems is not None:
+            failed_domains = [problem.identifier.value for problem in 
error.subproblems
+                                if problem.identifier is not None]
+            successful_domains = [x for x in domains if x not in 
failed_domains]
+            return successful_domains
+        return []
+
+    def _retry_obtain_certificate(self, key: util.Key,
+                                csr: util.CSR, domains: List[str], 
successful_domains: List[str]
+                                ) -> Tuple[bytes, bytes, util.Key, util.CSR]:
+        failed_domains = [d for d in domains if d not in successful_domains]
+        domains_list = ", ".join(failed_domains)
+        display_util.notify("Unable to obtain a certificate with every 
requested "
+            f"domain. Retrying without: {domains_list}")
+        if not self.config.dry_run:
+            os.remove(key.file)
+            os.remove(csr.file)
+        return self.obtain_certificate(successful_domains)
+
     def _choose_lineagename(self, domains: List[str], certname: Optional[str]) 
-> str:
         """Chooses a name for the new lineage.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-1.28.0/certbot.egg-info/PKG-INFO 
new/certbot-1.29.0/certbot.egg-info/PKG-INFO
--- old/certbot-1.28.0/certbot.egg-info/PKG-INFO        2022-06-07 
21:41:09.000000000 +0200
+++ new/certbot-1.29.0/certbot.egg-info/PKG-INFO        2022-07-05 
20:15:48.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: certbot
-Version: 1.28.0
+Version: 1.29.0
 Summary: ACME client
 Home-page: https://github.com/letsencrypt/letsencrypt
 Author: Certbot Project
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-1.28.0/certbot.egg-info/SOURCES.txt 
new/certbot-1.29.0/certbot.egg-info/SOURCES.txt
--- old/certbot-1.28.0/certbot.egg-info/SOURCES.txt     2022-06-07 
21:41:09.000000000 +0200
+++ new/certbot-1.29.0/certbot.egg-info/SOURCES.txt     2022-07-05 
20:15:48.000000000 +0200
@@ -139,7 +139,6 @@
 docs/make.bat
 docs/packaging.rst
 docs/resources.rst
-docs/uninstall.rst
 docs/using.rst
 docs/what.rst
 docs/_static/.gitignore
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-1.28.0/certbot.egg-info/requires.txt 
new/certbot-1.29.0/certbot.egg-info/requires.txt
--- old/certbot-1.28.0/certbot.egg-info/requires.txt    2022-06-07 
21:41:09.000000000 +0200
+++ new/certbot-1.29.0/certbot.egg-info/requires.txt    2022-07-05 
20:15:48.000000000 +0200
@@ -1,4 +1,4 @@
-acme>=1.28.0
+acme>=1.29.0
 ConfigArgParse>=0.9.3
 configobj>=5.0.6
 cryptography>=2.5.0
@@ -17,7 +17,6 @@
 [all]
 azure-devops
 ipdb
-PyGithub
 poetry>=1.2.0a1
 twine
 Sphinx>=1.2
@@ -44,7 +43,6 @@
 [dev]
 azure-devops
 ipdb
-PyGithub
 poetry>=1.2.0a1
 twine
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-1.28.0/docs/cli-help.txt 
new/certbot-1.29.0/docs/cli-help.txt
--- old/certbot-1.28.0/docs/cli-help.txt        2022-06-07 21:41:07.000000000 
+0200
+++ new/certbot-1.29.0/docs/cli-help.txt        2022-07-05 20:15:47.000000000 
+0200
@@ -126,7 +126,7 @@
                         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.27.0 (certbot;
+                        "". (default: CertbotACMEClient/1.28.0 (certbot;
                         OS_NAME OS_VERSION) Authenticator/XXX Installer/YYY
                         (SUBCOMMAND; flags: FLAGS) Py/major.minor.patchlevel).
                         The flags encoded in the user agent are: --duplicate,
@@ -351,7 +351,7 @@
                         renew", regardless of if the certificate is renewed.
                         This setting does not apply to important TLS
                         configuration updates. (default: False)
-  --no-autorenew        Disable auto renewal of certificates. (default: True)
+  --no-autorenew        Disable auto renewal of certificates. (default: False)
 
 certificates:
   List certificates managed by Certbot
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-1.28.0/docs/contributing.rst 
new/certbot-1.29.0/docs/contributing.rst
--- old/certbot-1.28.0/docs/contributing.rst    2022-06-07 21:41:07.000000000 
+0200
+++ new/certbot-1.29.0/docs/contributing.rst    2022-07-05 20:15:47.000000000 
+0200
@@ -313,7 +313,7 @@
 Writing your own plugin
 -----------------------
 
-.. note:: The Certbot team is not currently accepting any new DNS plugins
+.. note:: The Certbot team is not currently accepting any new plugins
     because we want to rethink our approach to the challenge and resolve some
     issues like `#6464 <https://github.com/certbot/certbot/issues/6464>`_,
     `#6503 <https://github.com/certbot/certbot/issues/6503>`_, and `#6504
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-1.28.0/docs/install.rst 
new/certbot-1.29.0/docs/install.rst
--- old/certbot-1.28.0/docs/install.rst 2022-06-07 21:41:07.000000000 +0200
+++ new/certbot-1.29.0/docs/install.rst 2022-07-05 20:15:47.000000000 +0200
@@ -125,21 +125,6 @@
 .. _Docker: https://docker.com
 .. _`install Docker`: https://docs.docker.com/engine/installation/
 
-.. _certbot-auto:
-
-Certbot-Auto
-------------
-.. toctree::
-   :hidden:
-
-   uninstall
-
-
-We used to have a shell script named ``certbot-auto`` to help people install
-Certbot on UNIX operating systems, however, this script is no longer supported.
-If you want to uninstall ``certbot-auto``, you can follow our instructions
-:doc:`here <uninstall>`.
-
 Pip
 ---
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-1.28.0/docs/uninstall.rst 
new/certbot-1.29.0/docs/uninstall.rst
--- old/certbot-1.28.0/docs/uninstall.rst       2022-06-07 21:41:07.000000000 
+0200
+++ new/certbot-1.29.0/docs/uninstall.rst       1970-01-01 01:00:00.000000000 
+0100
@@ -1,16 +0,0 @@
-=========================
-Uninstalling certbot-auto
-=========================
-
-To uninstall ``certbot-auto``, you need to do three things:
-
-1. If you added a cron job or systemd timer to automatically run
-   ``certbot-auto`` to renew your certificates, you should delete it. If you
-   did this by following our instructions, you can delete the entry added to
-   ``/etc/crontab`` by running a command like ``sudo sed -i '/certbot-auto/d'
-   /etc/crontab``.
-2. Delete the ``certbot-auto`` script. If you placed it in ``/usr/local/bin``
-   like we recommended, you can delete it by running ``sudo rm
-   /usr/local/bin/certbot-auto``.
-3. Delete the Certbot installation created by ``certbot-auto`` by running
-   ``sudo rm -rf /opt/eff.org``.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-1.28.0/docs/using.rst 
new/certbot-1.29.0/docs/using.rst
--- old/certbot-1.28.0/docs/using.rst   2022-06-07 21:41:07.000000000 +0200
+++ new/certbot-1.29.0/docs/using.rst   2022-07-05 20:15:47.000000000 +0200
@@ -14,7 +14,7 @@
 and commonly-used commands will be discussed throughout this
 document; an exhaustive list also appears near the end of the document.
 
-The ``certbot`` script on your web server might be named ``letsencrypt`` if 
your system uses an older package, or ``certbot-auto`` if you used a 
now-deprecated installation method. Throughout the docs, whenever you see 
``certbot``, swap in the correct name as needed.
+The ``certbot`` script on your web server might be named ``letsencrypt`` if 
your system uses an older package. Throughout the docs, whenever you see 
``certbot``, swap in the correct name as needed.
 
 .. _plugins:
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-1.28.0/setup.py new/certbot-1.29.0/setup.py
--- old/certbot-1.28.0/setup.py 2022-06-07 21:41:07.000000000 +0200
+++ new/certbot-1.29.0/setup.py 2022-07-05 20:15:47.000000000 +0200
@@ -67,7 +67,6 @@
 dev_extras = [
     'azure-devops',
     'ipdb',
-    'PyGithub',
     # poetry 1.2.0+ is required for it to pin pip, setuptools, and wheel. See
     # https://github.com/python-poetry/poetry/issues/1584.
     'poetry>=1.2.0a1',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/certbot-1.28.0/tests/client_test.py 
new/certbot-1.29.0/tests/client_test.py
--- old/certbot-1.28.0/tests/client_test.py     2022-06-07 21:41:07.000000000 
+0200
+++ new/certbot-1.29.0/tests/client_test.py     2022-07-05 20:15:47.000000000 
+0200
@@ -396,6 +396,193 @@
         
self.assertEqual(mock_crypto_util.cert_and_chain_from_fullchain.call_count, 1)
 
     @mock.patch("certbot._internal.client.crypto_util")
+    @mock.patch("certbot.compat.os.remove")
+    def test_obtain_certificate_finalize_order_partial_success(self, 
mock_remove, mock_crypto_util):
+        from acme import messages
+        csr = util.CSR(form="pem", file=mock.sentinel.csr_file, data=CSR_SAN)
+        key = util.CSR(form="pem", file=mock.sentinel.key_file, data=CSR_SAN)
+        mock_crypto_util.generate_csr.return_value = csr
+        mock_crypto_util.generate_key.return_value = key
+        
self._set_mock_from_fullchain(mock_crypto_util.cert_and_chain_from_fullchain)
+
+        self._mock_obtain_certificate()
+        authzr = self._authzr_from_domains(self.eg_domains)
+        self.eg_order.authorizations = authzr
+        self.client.auth_handler.handle_authorizations.return_value = authzr
+
+        identifier = messages.Identifier(typ=messages.IDENTIFIER_FQDN, 
value='example.com')
+        subproblem = messages.Error.with_code('caa', detail='bar', 
title='title', identifier=identifier)
+        error_with_subproblems = messages.Error.with_code('malformed', 
detail='foo', title='title', subproblems=[subproblem])
+        self.client.acme.finalize_order.side_effect = [error_with_subproblems, 
mock.DEFAULT]
+
+        self.config.allow_subset_of_names = True
+
+        with test_util.patch_display_util():
+            result = self.client.obtain_certificate(self.eg_domains)
+
+        self.assertEqual(
+            result,
+            (mock.sentinel.cert, mock.sentinel.chain, key, csr))
+        
self.assertEqual(self.client.auth_handler.handle_authorizations.call_count, 2)
+        self.assertEqual(self.acme.finalize_order.call_count, 2)
+
+        successful_domains = [d for d in self.eg_domains if d != 'example.com']
+        self.assertEqual(mock_crypto_util.generate_key.call_count, 2)
+        mock_crypto_util.generate_csr.assert_has_calls([
+            mock.call(key, self.eg_domains, self.config.csr_dir, 
self.config.must_staple, self.config.strict_permissions),
+            mock.call(key, successful_domains, self.config.csr_dir, 
self.config.must_staple, self.config.strict_permissions)])
+        self.assertEqual(mock_remove.call_count, 2)
+        
self.assertEqual(mock_crypto_util.cert_and_chain_from_fullchain.call_count, 1)
+
+    @mock.patch("certbot._internal.client.crypto_util")
+    def test_obtain_certificate_finalize_order_no_retryable_domains(self, 
mock_crypto_util):
+        from acme import messages
+        csr = util.CSR(form="pem", file=mock.sentinel.csr_file, data=CSR_SAN)
+        key = util.CSR(form="pem", file=mock.sentinel.key_file, data=CSR_SAN)
+        mock_crypto_util.generate_csr.return_value = csr
+        mock_crypto_util.generate_key.return_value = key
+        
self._set_mock_from_fullchain(mock_crypto_util.cert_and_chain_from_fullchain)
+
+        self._mock_obtain_certificate()
+        authzr = self._authzr_from_domains(self.eg_domains)
+        self.eg_order.authorizations = authzr
+        self.client.auth_handler.handle_authorizations.return_value = authzr
+
+        identifier1 = messages.Identifier(typ=messages.IDENTIFIER_FQDN, 
value='example.com')
+        identifier2 = messages.Identifier(typ=messages.IDENTIFIER_FQDN, 
value='www.example.com')
+        subproblem1 = messages.Error.with_code('caa', detail='bar', 
title='title', identifier=identifier1)
+        subproblem2 = messages.Error.with_code('caa', detail='bar', 
title='title', identifier=identifier2)
+        error_with_subproblems = messages.Error.with_code('malformed', 
detail='foo', title='title', subproblems=[subproblem1, subproblem2])
+        self.client.acme.finalize_order.side_effect = error_with_subproblems
+
+        self.config.allow_subset_of_names = True
+
+        self.assertRaises(messages.Error, self.client.obtain_certificate, 
self.eg_domains)
+        
self.assertEqual(self.client.auth_handler.handle_authorizations.call_count, 1)
+        self.assertEqual(self.acme.finalize_order.call_count, 1)
+        self.assertEqual(mock_crypto_util.generate_key.call_count, 1)
+        
self.assertEqual(mock_crypto_util.cert_and_chain_from_fullchain.call_count, 0)
+
+    @mock.patch("certbot._internal.client.crypto_util")
+    def 
test_obtain_certificate_finalize_order_rejected_identifier_no_subproblems(self, 
mock_crypto_util):
+        from acme import messages
+        csr = util.CSR(form="pem", file=mock.sentinel.csr_file, data=CSR_SAN)
+        key = util.CSR(form="pem", file=mock.sentinel.key_file, data=CSR_SAN)
+        mock_crypto_util.generate_csr.return_value = csr
+        mock_crypto_util.generate_key.return_value = key
+        
self._set_mock_from_fullchain(mock_crypto_util.cert_and_chain_from_fullchain)
+
+        self._mock_obtain_certificate()
+        authzr = self._authzr_from_domains(self.eg_domains)
+        self.eg_order.authorizations = authzr
+        self.client.auth_handler.handle_authorizations.return_value = authzr
+
+        error = messages.Error.with_code('caa', detail='foo', title='title')
+        self.client.acme.finalize_order.side_effect = error
+
+        self.config.allow_subset_of_names = True
+
+        self.assertRaises(messages.Error, self.client.obtain_certificate,
+                          self.eg_domains)
+        
self.assertEqual(self.client.auth_handler.handle_authorizations.call_count, 1)
+        self.assertEqual(self.acme.finalize_order.call_count, 1)
+        self.assertEqual(mock_crypto_util.generate_key.call_count, 1)
+        
self.assertEqual(mock_crypto_util.cert_and_chain_from_fullchain.call_count, 0)
+
+    @mock.patch("certbot._internal.client.crypto_util")
+    @mock.patch("certbot.compat.os.remove")
+    def test_obtain_certificate_get_order_partial_success(self, mock_remove, 
mock_crypto_util):
+        from acme import messages
+        csr = util.CSR(form="pem", file=mock.sentinel.csr_file, data=CSR_SAN)
+        key = util.CSR(form="pem", file=mock.sentinel.key_file, data=CSR_SAN)
+        mock_crypto_util.generate_csr.return_value = csr
+        mock_crypto_util.generate_key.return_value = key
+        
self._set_mock_from_fullchain(mock_crypto_util.cert_and_chain_from_fullchain)
+
+        self._mock_obtain_certificate()
+        authzr = self._authzr_from_domains(self.eg_domains)
+        self.eg_order.authorizations = authzr
+        self.client.auth_handler.handle_authorizations.return_value = authzr
+
+        identifier = messages.Identifier(typ=messages.IDENTIFIER_FQDN, 
value='example.com')
+        subproblem = messages.Error.with_code('caa', detail='bar', 
title='title', identifier=identifier)
+        error_with_subproblems = messages.Error.with_code('malformed', 
detail='foo', title='title', subproblems=[subproblem])
+        self.client.acme.new_order.side_effect = [error_with_subproblems, 
mock.DEFAULT]
+
+        self.config.allow_subset_of_names = True
+
+        with test_util.patch_display_util():
+            result = self.client.obtain_certificate(self.eg_domains)
+
+        self.assertEqual(
+            result,
+            (mock.sentinel.cert, mock.sentinel.chain, key, csr))
+        
self.assertEqual(self.client.auth_handler.handle_authorizations.call_count, 1)
+        self.assertEqual(self.acme.new_order.call_count, 2)
+
+        successful_domains = [d for d in self.eg_domains if d != 'example.com']
+        self.assertEqual(mock_crypto_util.generate_key.call_count, 2)
+        mock_crypto_util.generate_csr.assert_has_calls([
+            mock.call(key, self.eg_domains, self.config.csr_dir, 
self.config.must_staple, self.config.strict_permissions),
+            mock.call(key, successful_domains, self.config.csr_dir, 
self.config.must_staple, self.config.strict_permissions)])
+        self.assertEqual(mock_remove.call_count, 2)
+        
self.assertEqual(mock_crypto_util.cert_and_chain_from_fullchain.call_count, 1)
+
+    @mock.patch("certbot._internal.client.crypto_util")
+    def test_obtain_certificate_get_order_no_retryable_domains(self, 
mock_crypto_util):
+        from acme import messages
+        csr = util.CSR(form="pem", file=mock.sentinel.csr_file, data=CSR_SAN)
+        key = util.CSR(form="pem", file=mock.sentinel.key_file, data=CSR_SAN)
+        mock_crypto_util.generate_csr.return_value = csr
+        mock_crypto_util.generate_key.return_value = key
+        
self._set_mock_from_fullchain(mock_crypto_util.cert_and_chain_from_fullchain)
+
+        self._mock_obtain_certificate()
+        authzr = self._authzr_from_domains(self.eg_domains)
+        self.eg_order.authorizations = authzr
+        self.client.auth_handler.handle_authorizations.return_value = authzr
+
+        identifier1 = messages.Identifier(typ=messages.IDENTIFIER_FQDN, 
value='example.com')
+        identifier2 = messages.Identifier(typ=messages.IDENTIFIER_FQDN, 
value='www.example.com')
+        subproblem1 = messages.Error.with_code('caa', detail='bar', 
title='title', identifier=identifier1)
+        subproblem2 = messages.Error.with_code('caa', detail='bar', 
title='title', identifier=identifier2)
+        error_with_subproblems = messages.Error.with_code('malformed', 
detail='foo', title='title', subproblems=[subproblem1, subproblem2])
+        self.client.acme.new_order.side_effect = error_with_subproblems
+
+        self.config.allow_subset_of_names = True
+
+        self.assertRaises(messages.Error, self.client.obtain_certificate, 
self.eg_domains)
+        
self.assertEqual(self.client.auth_handler.handle_authorizations.call_count, 0)
+        self.assertEqual(self.acme.new_order.call_count, 1)
+        self.assertEqual(mock_crypto_util.generate_key.call_count, 1)
+        
self.assertEqual(mock_crypto_util.cert_and_chain_from_fullchain.call_count, 0)
+
+    @mock.patch("certbot._internal.client.crypto_util")
+    def 
test_obtain_certificate_get_order_rejected_identifier_no_subproblems(self, 
mock_crypto_util):
+        from acme import messages
+        csr = util.CSR(form="pem", file=mock.sentinel.csr_file, data=CSR_SAN)
+        key = util.CSR(form="pem", file=mock.sentinel.key_file, data=CSR_SAN)
+        mock_crypto_util.generate_csr.return_value = csr
+        mock_crypto_util.generate_key.return_value = key
+        
self._set_mock_from_fullchain(mock_crypto_util.cert_and_chain_from_fullchain)
+
+        self._mock_obtain_certificate()
+        authzr = self._authzr_from_domains(self.eg_domains)
+        self.eg_order.authorizations = authzr
+        self.client.auth_handler.handle_authorizations.return_value = authzr
+
+        error = messages.Error.with_code('caa', detail='foo', title='title')
+        self.client.acme.new_order.side_effect = error
+
+        self.config.allow_subset_of_names = True
+
+        self.assertRaises(messages.Error, self.client.obtain_certificate, 
self.eg_domains)
+        
self.assertEqual(self.client.auth_handler.handle_authorizations.call_count, 0)
+        self.assertEqual(self.acme.new_order.call_count, 1)
+        self.assertEqual(mock_crypto_util.generate_key.call_count, 1)
+        
self.assertEqual(mock_crypto_util.cert_and_chain_from_fullchain.call_count, 0)
+
+    @mock.patch("certbot._internal.client.crypto_util")
     @mock.patch("certbot._internal.client.acme_crypto_util")
     def test_obtain_certificate_dry_run(self, mock_acme_crypto, mock_crypto):
         csr = util.CSR(form="pem", file=None, data=CSR_SAN)

Reply via email to