diff options
author | Chris Julian <chris@zero1many.net> | 2017-09-16 03:10:43 +0300 |
---|---|---|
committer | Brad Warren <bmw@users.noreply.github.com> | 2017-09-16 03:10:43 +0300 |
commit | f0caf5b04fc33d7b08d480d5ee2bd67603081834 (patch) | |
tree | e2bcc92b2135cdea4a3631a119c9617a598e6642 | |
parent | f6be07da74c664b57ac8c053585f919c79f9af44 (diff) |
#4435. CLI Argument Default Organization (#5037)
* Enhancement #4435. Organizing defaults in prepare_and_parse_args()
* Playing fast and loose with tox.
Discovered screwy case involving flag_default returning empty list (domains)
* Setting defaults for more low-hanging fruit. Some caveats remain.
* key_path default to None
* Applying PR feedback: explicit defaults even where redundant
* Obsessive quote consistency
* Set testing config path arguments to a 'certonly' default
* Copy the default domains list rather than get reference
* Build a testing Config from CLI_DEFAULTS
* Update some email tests for use with defaults in config.
config.email and config.noninteractive_mode in these tests
used to be magic-mock'd, so were True-ish. The default
email is now None and default noninteractive_mode is
False, so update in tests accordingly.
* Lint...
* Copy anything retrieved using flag_defaults. Apply this to test_cli_ini_domains too.
* Put those quotes back. Backslashes are just the worst.
* Remove vestigial line
* A test to ensure no regressions around modifying CLI_DEFAULTS
-rw-r--r-- | certbot/cli.py | 204 | ||||
-rw-r--r-- | certbot/constants.py | 88 | ||||
-rw-r--r-- | certbot/tests/cli_test.py | 19 | ||||
-rw-r--r-- | certbot/tests/client_test.py | 2 | ||||
-rw-r--r-- | certbot/tests/util.py | 15 |
5 files changed, 231 insertions, 97 deletions
diff --git a/certbot/cli.py b/certbot/cli.py index afebbb7cb..9d17c7a25 100644 --- a/certbot/cli.py +++ b/certbot/cli.py @@ -282,7 +282,7 @@ def flag_default(name): # argparse has been set up; it is not accurate for all flags. Call it # with caution. Plugin defaults are missing, and some things are using # defaults defined in this file, not in constants.py :( - return constants.CLI_DEFAULTS[name] + return copy.deepcopy(constants.CLI_DEFAULTS[name]) def config_help(name, hidden=False): @@ -866,9 +866,10 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis "e.g. -vvv.") helpful.add( None, "-t", "--text", dest="text_mode", action="store_true", - help=argparse.SUPPRESS) + default=flag_default("text_mode"), help=argparse.SUPPRESS) helpful.add( - None, "--max-log-backups", type=nonnegative_int, default=1000, + None, "--max-log-backups", type=nonnegative_int, + default=flag_default("max_log_backups"), help="Specifies the maximum number of backup logs that should " "be kept by Certbot's built in log rotation. Setting this " "flag to 0 disables log rotation entirely, causing " @@ -876,19 +877,22 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis helpful.add( [None, "automation", "run", "certonly"], "-n", "--non-interactive", "--noninteractive", dest="noninteractive_mode", action="store_true", + default=flag_default("noninteractive_mode"), help="Run without ever asking for user input. This may require " "additional command line flags; the client will try to explain " "which ones are required if it finds one missing") helpful.add( [None, "register", "run", "certonly"], constants.FORCE_INTERACTIVE_FLAG, action="store_true", + default=flag_default("force_interactive"), help="Force Certbot to be interactive even if it detects it's not " "being run in a terminal. This flag cannot be used with the " "renew subcommand.") helpful.add( [None, "run", "certonly", "certificates"], "-d", "--domains", "--domain", dest="domains", - metavar="DOMAIN", action=_DomainsAction, default=[], + metavar="DOMAIN", action=_DomainsAction, + default=flag_default("domains"), help="Domain names to apply. For multiple domains you can use " "multiple -d flags or enter a comma separated list of domains " "as a parameter. The first provided domain will be used in " @@ -899,7 +903,7 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis helpful.add( [None, "run", "certonly", "manage", "delete", "certificates", "renew"], "--cert-name", dest="certname", - metavar="CERTNAME", default=None, + metavar="CERTNAME", default=flag_default("certname"), help="Certificate name to apply. This name is used by Certbot for housekeeping " "and in file paths; it doesn't affect the content of the certificate itself. " "To see certificate names, run 'certbot certificates'. " @@ -909,6 +913,7 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis helpful.add( [None, "testing", "renew", "certonly"], "--dry-run", action="store_true", dest="dry_run", + default=flag_default("dry_run"), help="Perform a test run of the client, obtaining test (invalid) certificates" " but not saving them to disk. This can currently only be used" " with the 'certonly' and 'renew' subcommands. \nNote: Although --dry-run" @@ -921,6 +926,7 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis " renewal. --deploy-hook commands are not called.") helpful.add( ["register", "automation"], "--register-unsafely-without-email", action="store_true", + default=flag_default("register_unsafely_without_email"), help="Specifying this flag enables registering an account with no " "email address. This is strongly discouraged, because in the " "event of key loss or account compromise you will irrevocably " @@ -931,27 +937,29 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis "update to the web site.") helpful.add( "register", "--update-registration", action="store_true", + default=flag_default("update_registration"), help="With the register verb, indicates that details associated " "with an existing registration, such as the e-mail address, " "should be updated, rather than registering a new account.") helpful.add( ["register", "unregister", "automation"], "-m", "--email", + default=flag_default("email"), help=config_help("email")) helpful.add(["register", "automation"], "--eff-email", action="store_true", - default=None, dest="eff_email", + default=flag_default("eff_email"), dest="eff_email", help="Share your e-mail address with EFF") helpful.add(["register", "automation"], "--no-eff-email", action="store_false", - default=None, dest="eff_email", + default=flag_default("eff_email"), dest="eff_email", help="Don't share your e-mail address with EFF") helpful.add( ["automation", "certonly", "run"], "--keep-until-expiring", "--keep", "--reinstall", - dest="reinstall", action="store_true", + dest="reinstall", action="store_true", default=flag_default("reinstall"), help="If the requested certificate matches an existing certificate, always keep the " "existing one until it is due for renewal (for the " "'run' subcommand this means reinstall the existing certificate). (default: Ask)") helpful.add( - "automation", "--expand", action="store_true", + "automation", "--expand", action="store_true", default=flag_default("expand"), help="If an existing certificate is a strict subset of the requested names, " "always expand and replace it with the additional names. (default: Ask)") helpful.add( @@ -960,21 +968,24 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis help="show program's version number and exit") helpful.add( ["automation", "renew"], - "--force-renewal", "--renew-by-default", - action="store_true", dest="renew_by_default", help="If a certificate " + "--force-renewal", "--renew-by-default", dest="renew_by_default", + action="store_true", default=flag_default("renew_by_default"), + help="If a certificate " "already exists for the requested domains, renew it now, " "regardless of whether it is near expiry. (Often " "--keep-until-expiring is more appropriate). Also implies " "--expand.") helpful.add( - "automation", "--renew-with-new-domains", - action="store_true", dest="renew_with_new_domains", help="If a " + "automation", "--renew-with-new-domains", dest="renew_with_new_domains", + action="store_true", default=flag_default("renew_with_new_domains"), + help="If a " "certificate already exists for the requested certificate name " "but does not match the requested domains, renew it now, " "regardless of whether it is near expiry.") helpful.add( ["automation", "renew", "certonly"], "--allow-subset-of-names", action="store_true", + default=flag_default("allow_subset_of_names"), help="When performing domain validation, do not consider it a failure " "if authorizations can not be obtained for a strict subset of " "the requested domains. This may be useful for allowing renewals for " @@ -982,39 +993,46 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis "at this system. This option cannot be used with --csr.") helpful.add( "automation", "--agree-tos", dest="tos", action="store_true", + default=flag_default("tos"), help="Agree to the ACME Subscriber Agreement (default: Ask)") helpful.add( ["unregister", "automation"], "--account", metavar="ACCOUNT_ID", + default=flag_default("account"), help="Account ID to use") helpful.add( "automation", "--duplicate", dest="duplicate", action="store_true", + default=flag_default("duplicate"), help="Allow making a certificate lineage that duplicates an existing one " "(both can be renewed in parallel)") helpful.add( "automation", "--os-packages-only", action="store_true", + default=flag_default("os_packages_only"), help="(certbot-auto only) install OS package dependencies and then stop") helpful.add( "automation", "--no-self-upgrade", action="store_true", + default=flag_default("no_self_upgrade"), help="(certbot-auto only) prevent the certbot-auto script from" " upgrading itself to newer released versions (default: Upgrade" " automatically)") helpful.add( "automation", "--no-bootstrap", action="store_true", + default=flag_default("no_bootstrap"), help="(certbot-auto only) prevent the certbot-auto script from" " installing OS-level dependencies (default: Prompt to install " " OS-wide dependencies, but exit if the user says 'No')") helpful.add( ["automation", "renew", "certonly", "run"], "-q", "--quiet", dest="quiet", action="store_true", + default=flag_default("quiet"), help="Silence all output except errors. Useful for automation via cron." " Implies --non-interactive.") # overwrites server, handled in HelpfulArgumentParser.parse_args() helpful.add(["testing", "revoke", "run"], "--test-cert", "--staging", - action='store_true', dest='staging', - help='Use the staging server to obtain or revoke test (invalid) certificates; equivalent' - ' to --server ' + constants.STAGING_URI) + dest="staging", action="store_true", default=flag_default("staging"), + help="Use the staging server to obtain or revoke test (invalid) certificates; equivalent" + " to --server " + constants.STAGING_URI) helpful.add( - "testing", "--debug", action="store_true", + "testing", "--debug", action="store_true", default=flag_default("debug"), help="Show tracebacks in case of errors, and allow certbot-auto " "execution on experimental platforms") helpful.add( @@ -1044,6 +1062,7 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis default=flag_default("http01_address"), help=config_help("http01_address")) helpful.add( "testing", "--break-my-certs", action="store_true", + default=flag_default("break_my_certs"), help="Be willing to replace or renew valid certificates with invalid " "(testing/staging) certificates") helpful.add( @@ -1051,47 +1070,51 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis default=flag_default("rsa_key_size"), help=config_help("rsa_key_size")) helpful.add( "security", "--must-staple", action="store_true", - help=config_help("must_staple"), dest="must_staple", default=False) + dest="must_staple", default=flag_default("must_staple"), + help=config_help("must_staple")) helpful.add( - "security", "--redirect", action="store_true", + "security", "--redirect", action="store_true", dest="redirect", + default=flag_default("redirect"), help="Automatically redirect all HTTP traffic to HTTPS for the newly " - "authenticated vhost. (default: Ask)", dest="redirect", default=None) + "authenticated vhost. (default: Ask)") helpful.add( - "security", "--no-redirect", action="store_false", + "security", "--no-redirect", action="store_false", dest="redirect", + default=flag_default("redirect"), help="Do not automatically redirect all HTTP traffic to HTTPS for the newly " - "authenticated vhost. (default: Ask)", dest="redirect", default=None) + "authenticated vhost. (default: Ask)") helpful.add( - "security", "--hsts", action="store_true", + "security", "--hsts", action="store_true", dest="hsts", default=flag_default("hsts"), help="Add the Strict-Transport-Security header to every HTTP response." " Forcing browser to always use SSL for the domain." - " Defends against SSL Stripping.", dest="hsts", default=False) + " Defends against SSL Stripping.") helpful.add( - "security", "--no-hsts", action="store_false", - help=argparse.SUPPRESS, dest="hsts", default=False) + "security", "--no-hsts", action="store_false", dest="hsts", + default=flag_default("hsts"), help=argparse.SUPPRESS) helpful.add( - "security", "--uir", action="store_true", - help="Add the \"Content-Security-Policy: upgrade-insecure-requests\"" - " header to every HTTP response. Forcing the browser to use" - " https:// for every http:// resource.", dest="uir", default=None) + "security", "--uir", action="store_true", dest="uir", default=flag_default("uir"), + help='Add the "Content-Security-Policy: upgrade-insecure-requests"' + ' header to every HTTP response. Forcing the browser to use' + ' https:// for every http:// resource.') helpful.add( - "security", "--no-uir", action="store_false", - help=argparse.SUPPRESS, dest="uir", default=None) + "security", "--no-uir", action="store_false", dest="uir", default=flag_default("uir"), + help=argparse.SUPPRESS) helpful.add( - "security", "--staple-ocsp", action="store_true", + "security", "--staple-ocsp", action="store_true", dest="staple", + default=flag_default("staple"), help="Enables OCSP Stapling. A valid OCSP response is stapled to" - " the certificate that the server offers during TLS.", - dest="staple", default=None) + " the certificate that the server offers during TLS.") helpful.add( - "security", "--no-staple-ocsp", action="store_false", - help=argparse.SUPPRESS, dest="staple", default=None) + "security", "--no-staple-ocsp", action="store_false", dest="staple", + default=flag_default("staple"), help=argparse.SUPPRESS) helpful.add( "security", "--strict-permissions", action="store_true", + default=flag_default("strict_permissions"), help="Require that all configuration files are owned by the current " "user; only needed if your config is somewhere unsafe like /tmp/") helpful.add( ["manual", "standalone", "certonly", "renew"], "--preferred-challenges", dest="pref_challs", - action=_PrefChallAction, default=[], + action=_PrefChallAction, default=flag_default("pref_challs"), help='A sorted, comma delimited list of the preferred challenge to ' 'use during authorization with the most preferred challenge ' 'listed first (Eg, "dns" or "tls-sni-01,http,dns"). ' @@ -1120,17 +1143,18 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis action=_RenewHookAction, help=argparse.SUPPRESS) helpful.add( "renew", "--deploy-hook", action=_DeployHookAction, - help="Command to be run in a shell once for each successfully" - " issued certificate. For this command, the shell variable" - " $RENEWED_LINEAGE will point to the config live subdirectory" + help='Command to be run in a shell once for each successfully' + ' issued certificate. For this command, the shell variable' + ' $RENEWED_LINEAGE will point to the config live subdirectory' ' (for example, "/etc/letsencrypt/live/example.com") containing' - " the new certificates and keys; the shell variable" - " $RENEWED_DOMAINS will contain a space-delimited list of" + ' the new certificates and keys; the shell variable' + ' $RENEWED_DOMAINS will contain a space-delimited list of' ' renewed certificate domains (for example, "example.com' ' www.example.com"') helpful.add( "renew", "--disable-hook-validation", - action='store_false', dest='validate_hooks', default=True, + action="store_false", dest="validate_hooks", + default=flag_default("validate_hooks"), help="Ordinarily the commands specified for" " --pre-hook/--post-hook/--deploy-hook will be checked for" " validity, to see if the programs being run are in the $PATH," @@ -1156,48 +1180,53 @@ def prepare_and_parse_args(plugins, args, detect_defaults=False): # pylint: dis def _create_subparsers(helpful): - helpful.add("config_changes", "--num", type=int, + helpful.add("config_changes", "--num", type=int, default=flag_default("num"), help="How many past revisions you want to be displayed") from certbot.client import sample_user_agent # avoid import loops helpful.add( - None, "--user-agent", default=None, - help="Set a custom user agent string for the client. User agent strings allow " - "the CA to collect high level statistics about success rates by OS, " - "plugin and use case, and to know when to deprecate support for past Python " + None, "--user-agent", default=flag_default("user_agent"), + help='Set a custom user agent string for the client. User agent strings allow ' + 'the CA to collect high level statistics about success rates by OS, ' + 'plugin and use 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: {0}). The flags encoded in the user agent are: ' '--duplicate, --force-renew, --allow-subset-of-names, -n, and ' 'whether any hooks are set.'.format(sample_user_agent())) helpful.add( - None, "--user-agent-comment", default=None, type=_user_agent_comment_type, + None, "--user-agent-comment", default=flag_default("user_agent_comment"), + type=_user_agent_comment_type, help="Add a comment to the default user agent string. May be used when repackaging Certbot " "or calling it from another tool to allow additional statistical data to be collected." " Ignored if --user-agent is set. (Example: Foo-Wrapper/1.0)") helpful.add("certonly", - "--csr", type=read_file, + "--csr", default=flag_default("csr"), type=read_file, help="Path to a Certificate Signing Request (CSR) in DER or PEM format." " Currently --csr only works with the 'certonly' subcommand.") helpful.add("revoke", "--reason", dest="reason", choices=CaseInsensitiveList(sorted(constants.REVOCATION_REASONS, key=constants.REVOCATION_REASONS.get)), - action=_EncodeReasonAction, default=0, + action=_EncodeReasonAction, default=flag_default("reason"), help="Specify reason for revoking certificate. (default: unspecified)") helpful.add("rollback", "--checkpoints", type=int, metavar="N", default=flag_default("rollback_checkpoints"), help="Revert configuration N number of checkpoints.") helpful.add("plugins", - "--init", action="store_true", help="Initialize plugins.") + "--init", action="store_true", default=flag_default("init"), + help="Initialize plugins.") helpful.add("plugins", - "--prepare", action="store_true", help="Initialize and prepare plugins.") + "--prepare", action="store_true", default=flag_default("prepare"), + help="Initialize and prepare plugins.") helpful.add("plugins", "--authenticators", action="append_const", dest="ifaces", + default=flag_default("ifaces"), const=interfaces.IAuthenticator, help="Limit to authenticator plugins only.") helpful.add("plugins", "--installers", action="append_const", dest="ifaces", + default=flag_default("ifaces"), const=interfaces.IInstaller, help="Limit to installer plugins only.") @@ -1263,53 +1292,68 @@ def _plugins_parsing(helpful, plugins): "a particular plugin by setting options provided below. Running " "--help <plugin_name> will list flags specific to that plugin.") - helpful.add("plugins", "--configurator", + helpful.add("plugins", "--configurator", default=flag_default("configurator"), help="Name of the plugin that is both an authenticator and an installer." " Should not be used together with --authenticator or --installer. " "(default: Ask)") - helpful.add("plugins", "-a", "--authenticator", help="Authenticator plugin name.") - helpful.add("plugins", "-i", "--installer", + helpful.add("plugins", "-a", "--authenticator", default=flag_default("authenticator"), + help="Authenticator plugin name.") + helpful.add("plugins", "-i", "--installer", default=flag_default("installer"), help="Installer plugin name (also used to find domains).") helpful.add(["plugins", "certonly", "run", "install", "config_changes"], - "--apache", action="store_true", + "--apache", action="store_true", default=flag_default("apache"), help="Obtain and install certificates using Apache") helpful.add(["plugins", "certonly", "run", "install", "config_changes"], - "--nginx", action="store_true", help="Obtain and install certificates using Nginx") + "--nginx", action="store_true", default=flag_default("nginx"), + help="Obtain and install certificates using Nginx") helpful.add(["plugins", "certonly"], "--standalone", action="store_true", + default=flag_default("standalone"), help='Obtain certificates using a "standalone" webserver.') helpful.add(["plugins", "certonly"], "--manual", action="store_true", - help='Provide laborious manual instructions for obtaining a certificate') + default=flag_default("manual"), + help="Provide laborious manual instructions for obtaining a certificate") helpful.add(["plugins", "certonly"], "--webroot", action="store_true", - help='Obtain certificates by placing files in a webroot directory.') + default=flag_default("webroot"), + help="Obtain certificates by placing files in a webroot directory.") helpful.add(["plugins", "certonly"], "--dns-cloudflare", action="store_true", - help=('Obtain certificates using a DNS TXT record (if you are ' - 'using Cloudflare for DNS).')) + default=flag_default("dns_cloudflare"), + help=("Obtain certificates using a DNS TXT record (if you are " + "using Cloudflare for DNS).")) helpful.add(["plugins", "certonly"], "--dns-cloudxns", action="store_true", - help=('Obtain certificates using a DNS TXT record (if you are ' - 'using CloudXNS for DNS).')) + default=flag_default("dns_cloudxns"), + help=("Obtain certificates using a DNS TXT record (if you are " + "using CloudXNS for DNS).")) helpful.add(["plugins", "certonly"], "--dns-digitalocean", action="store_true", - help=('Obtain certificates using a DNS TXT record (if you are ' - 'using DigitalOcean for DNS).')) + default=flag_default("dns_digitalocean"), + help=("Obtain certificates using a DNS TXT record (if you are " + "using DigitalOcean for DNS).")) helpful.add(["plugins", "certonly"], "--dns-dnsimple", action="store_true", - help=('Obtain certificates using a DNS TXT record (if you are ' - 'using DNSimple for DNS).')) + default=flag_default("dns_dnsimple"), + help=("Obtain certificates using a DNS TXT record (if you are " + "using DNSimple for DNS).")) helpful.add(["plugins", "certonly"], "--dns-dnsmadeeasy", action="store_true", - help=('Obtain certificates using a DNS TXT record (if you are' - 'using DNS Made Easy for DNS).')) + default=flag_default("dns_dnsmadeeasy"), + help=("Obtain certificates using a DNS TXT record (if you are" + "using DNS Made Easy for DNS).")) helpful.add(["plugins", "certonly"], "--dns-google", action="store_true", - help=('Obtain certificates using a DNS TXT record (if you are ' - 'using Google Cloud DNS).')) + default=flag_default("dns_google"), + help=("Obtain certificates using a DNS TXT record (if you are " + "using Google Cloud DNS).")) helpful.add(["plugins", "certonly"], "--dns-luadns", action="store_true", - help=('Obtain certificates using a DNS TXT record (if you are ' - 'using LuaDNS for DNS).')) + default=flag_default("dns_luadns"), + help=("Obtain certificates using a DNS TXT record (if you are " + "using LuaDNS for DNS).")) helpful.add(["plugins", "certonly"], "--dns-nsone", action="store_true", - help=('Obtain certificates using a DNS TXT record (if you are ' - 'using NS1 for DNS).')) + default=flag_default("dns_nsone"), + help=("Obtain certificates using a DNS TXT record (if you are " + "using NS1 for DNS).")) helpful.add(["plugins", "certonly"], "--dns-rfc2136", action="store_true", - help='Obtain certificates using a DNS TXT record (if you are using BIND for DNS).') + default=flag_default("dns_rfc2136"), + help="Obtain certificates using a DNS TXT record (if you are using BIND for DNS).") helpful.add(["plugins", "certonly"], "--dns-route53", action="store_true", - help=('Obtain certificates using a DNS TXT record (if you are using Route53 for ' - 'DNS).')) + default=flag_default("dns_route53"), + help=("Obtain certificates using a DNS TXT record (if you are using Route53 for " + "DNS).")) # things should not be reorder past/pre this comment: # plugins_group should be displayed in --help before plugin diff --git a/certbot/constants.py b/certbot/constants.py index 557ccd4c6..cae9864a9 100644 --- a/certbot/constants.py +++ b/certbot/constants.py @@ -19,23 +19,91 @@ CLI_DEFAULTS = dict( os.path.join(os.environ.get("XDG_CONFIG_HOME", "~/.config"), "letsencrypt", "cli.ini"), ], + + # Main parser verbose_count=-int(logging.INFO / 10), - server="https://acme-v01.api.letsencrypt.org/directory", - rsa_key_size=2048, - rollback_checkpoints=1, - config_dir="/etc/letsencrypt", - work_dir="/var/lib/letsencrypt", - logs_dir="/var/log/letsencrypt", + text_mode=False, + max_log_backups=1000, + noninteractive_mode=False, + force_interactive=False, + domains=[], + certname=None, + dry_run=False, + register_unsafely_without_email=False, + update_registration=False, + email=None, + eff_email=None, + reinstall=False, + expand=False, + renew_by_default=False, + renew_with_new_domains=False, + allow_subset_of_names=False, + tos=False, + account=None, + duplicate=False, + os_packages_only=False, + no_self_upgrade=False, + no_bootstrap=False, + quiet=False, + staging=False, + debug=False, + debug_challenges=False, no_verify_ssl=False, - http01_port=challenges.HTTP01Response.PORT, - http01_address="", tls_sni_01_port=challenges.TLSSNI01Response.PORT, tls_sni_01_address="", + http01_port=challenges.HTTP01Response.PORT, + http01_address="", + break_my_certs=False, + rsa_key_size=2048, + must_staple=False, + redirect=None, + hsts=None, + uir=None, + staple=None, + strict_permissions=False, + pref_challs=[], + validate_hooks=True, + + # Subparsers + num=None, + user_agent=None, + user_agent_comment=None, + csr=None, + reason=0, + rollback_checkpoints=1, + init=False, + prepare=False, + ifaces=None, + # Path parsers auth_cert_path="./cert.pem", auth_chain_path="./chain.pem", - strict_permissions=False, - debug_challenges=False, + key_path=None, + config_dir="/etc/letsencrypt", + work_dir="/var/lib/letsencrypt", + logs_dir="/var/log/letsencrypt", + server="https://acme-v01.api.letsencrypt.org/directory", + + # Plugins parsers + configurator=None, + authenticator=None, + installer=None, + apache=False, + nginx=False, + standalone=False, + manual=False, + webroot=False, + dns_cloudflare=False, + dns_cloudxns=False, + dns_digitalocean=False, + dns_dnsimple=False, + dns_dnsmadeeasy=False, + dns_google=False, + dns_luadns=False, + dns_nsone=False, + dns_rfc2136=False, + dns_route53=False + ) STAGING_URI = "https://acme-staging.api.letsencrypt.org/directory" diff --git a/certbot/tests/cli_test.py b/certbot/tests/cli_test.py index 1a3742348..e887e3043 100644 --- a/certbot/tests/cli_test.py +++ b/certbot/tests/cli_test.py @@ -3,6 +3,7 @@ import argparse import unittest import os import tempfile +import copy import mock import six @@ -81,7 +82,11 @@ class ParseTest(unittest.TestCase): # pylint: disable=too-many-public-methods def test_cli_ini_domains(self, mock_flag_default): tmp_config = tempfile.NamedTemporaryFile() # use a shim to get ConfigArgParse to pick up tmp_config - shim = lambda v: constants.CLI_DEFAULTS[v] if v != "config_files" else [tmp_config.name] + shim = ( + lambda v: copy.deepcopy(constants.CLI_DEFAULTS[v]) + if v != "config_files" + else [tmp_config.name] + ) mock_flag_default.side_effect = shim namespace = self.parse(["certonly"]) @@ -391,6 +396,18 @@ class ParseTest(unittest.TestCase): # pylint: disable=too-many-public-methods namespace = self.parse(["--max-log-backups", value]) self.assertEqual(namespace.max_log_backups, int(value)) + def test_unchanging_defaults(self): + namespace = self.parse([]) + self.assertEqual(namespace.domains, []) + self.assertEqual(namespace.pref_challs, []) + + namespace.pref_challs = [challenges.HTTP01.typ] + namespace.domains = ['example.com'] + + namespace = self.parse([]) + self.assertEqual(namespace.domains, []) + self.assertEqual(namespace.pref_challs, []) + class DefaultTest(unittest.TestCase): """Tests for certbot.cli._Default.""" diff --git a/certbot/tests/client_test.py b/certbot/tests/client_test.py index 2416acf95..09c4a50ca 100644 --- a/certbot/tests/client_test.py +++ b/certbot/tests/client_test.py @@ -28,6 +28,7 @@ class RegisterTest(test_util.ConfigTestCase): super(RegisterTest, self).setUp() self.config.rsa_key_size = 1024 self.config.register_unsafely_without_email = False + self.config.email = "alias@example.com" self.account_storage = account.AccountMemoryStorage() self.tos_cb = mock.MagicMock() @@ -75,6 +76,7 @@ class RegisterTest(test_util.ConfigTestCase): @mock.patch("certbot.account.report_new_account") def test_email_invalid_noninteractive(self, _rep): from acme import messages + self.config.noninteractive_mode = True msg = "DNS problem: NXDOMAIN looking up MX for example.com" mx_err = messages.Error.with_code('invalidContact', detail=msg) with mock.patch("certbot.client.acme_client.Client") as mock_client: diff --git a/certbot/tests/util.py b/certbot/tests/util.py index 698962516..73d002989 100644 --- a/certbot/tests/util.py +++ b/certbot/tests/util.py @@ -277,13 +277,16 @@ class ConfigTestCase(TempDirTestCase): def setUp(self): super(ConfigTestCase, self).setUp() self.config = configuration.NamespaceConfig( - mock.MagicMock( - config_dir=os.path.join(self.tempdir, 'config'), - work_dir=os.path.join(self.tempdir, 'work'), - logs_dir=os.path.join(self.tempdir, 'logs'), - server="example.com", - ) + mock.MagicMock(**constants.CLI_DEFAULTS) ) + self.config.verb = "certonly" + self.config.config_dir = os.path.join(self.tempdir, 'config') + self.config.work_dir = os.path.join(self.tempdir, 'work') + self.config.logs_dir = os.path.join(self.tempdir, 'logs') + self.config.cert_path = constants.CLI_DEFAULTS['auth_cert_path'] + self.config.fullchain_path = constants.CLI_DEFAULTS['auth_chain_path'] + self.config.chain_path = constants.CLI_DEFAULTS['auth_chain_path'] + self.config.server = "example.com" def lock_and_call(func, lock_path): """Grab a lock for lock_path and call func. |