Repository: certbot/certbot

Issue:
Implement --staging
This should point the client at the staging server, but also take steps to ensure that lineages with valid certs aren't accidentally updated with happy hacker fake CA ones.



Discussion:
This should help mitigate users' problems with rate limits, so bumping it into the 0.1.1 bugfix milestone.


Resolving patch:
diff --git a/letsencrypt/cli.py b/letsencrypt/cli.py
--- a/letsencrypt/cli.py
+++ b/letsencrypt/cli.py
@@ -696,6 +696,14 @@ def parse_args(self):
         parsed_args = self.parser.parse_args(self.args)
         parsed_args.func = self.VERBS[self.verb]
 
+        # Do any post-parsing homework here
+
+        # argparse seemingly isn't flexible enough to give us this behaviour easily...
+        if parsed_args.staging:
+            if parsed_args.server not in (flag_default("server"), constants.STAGING_URI):
+                raise errors.Error("--server value conflicts with --staging")
+            parsed_args.server = constants.STAGING_URI
+
         return parsed_args
 
 
@@ -1037,6 +1045,10 @@ def _paths_parser(helpful):
         help="Logs directory.")
     add("paths", "--server", default=flag_default("server"),
         help=config_help("server"))
+    # overwrites server, handled in HelpfulArgumentParser.parse_args()
+    add("testing", "--test-cert", "--staging", action='store_true', dest='staging',
+        help='Use the staging server to obtain test (invalid) certs; equivalent'
+             ' to --server ' + constants.STAGING_URI)
 
 
 def _plugins_parsing(helpful, plugins):
diff --git a/letsencrypt/constants.py b/letsencrypt/constants.py
--- a/letsencrypt/constants.py
+++ b/letsencrypt/constants.py
@@ -30,8 +30,9 @@
     auth_chain_path="./chain.pem",
     strict_permissions=False,
 )
-"""Defaults for CLI flags and `.IConfig` attributes."""
+STAGING_URI = "https://acme-staging.api.letsencrypt.org/directory"
 
+"""Defaults for CLI flags and `.IConfig` attributes."""
 
 RENEWER_DEFAULTS = dict(
     renewer_enabled="yes",


Test patch:
diff --git a/letsencrypt/tests/cli_test.py b/letsencrypt/tests/cli_test.py
--- a/letsencrypt/tests/cli_test.py
+++ b/letsencrypt/tests/cli_test.py
@@ -15,6 +15,7 @@
 from letsencrypt import account
 from letsencrypt import cli
 from letsencrypt import configuration
+from letsencrypt import constants
 from letsencrypt import crypto_util
 from letsencrypt import errors
 from letsencrypt import le_util
@@ -343,6 +344,19 @@ def test_parse_domains(self):
         namespace = cli.prepare_and_parse_args(plugins, long_args)
         self.assertEqual(namespace.domains, ['example.com', 'another.net'])
 
+    def test_parse_server(self):
+        plugins = disco.PluginsRegistry.find_all()
+        short_args = ['--server', 'example.com']
+        namespace = cli.prepare_and_parse_args(plugins, short_args)
+        self.assertEqual(namespace.server, 'example.com')
+
+        short_args = ['--staging']
+        namespace = cli.prepare_and_parse_args(plugins, short_args)
+        self.assertEqual(namespace.server, constants.STAGING_URI)
+
+        short_args = ['--staging', '--server', 'example.com']
+        self.assertRaises(errors.Error, cli.prepare_and_parse_args, plugins, short_args)
+
     def test_parse_webroot(self):
         plugins = disco.PluginsRegistry.find_all()
         webroot_args = ['--webroot', '-w', '/var/www/example',