#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
This commit is contained in:
Chris Julian 2017-09-15 20:10:43 -04:00 committed by Brad Warren
parent f6be07da74
commit f0caf5b04f
5 changed files with 231 additions and 97 deletions

View file

@ -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

View file

@ -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",
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,
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",
key_path=None,
config_dir="/etc/letsencrypt",
work_dir="/var/lib/letsencrypt",
logs_dir="/var/log/letsencrypt",
no_verify_ssl=False,
http01_port=challenges.HTTP01Response.PORT,
http01_address="",
tls_sni_01_port=challenges.TLSSNI01Response.PORT,
tls_sni_01_address="",
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
auth_cert_path="./cert.pem",
auth_chain_path="./chain.pem",
strict_permissions=False,
debug_challenges=False,
)
STAGING_URI = "https://acme-staging.api.letsencrypt.org/directory"

View file

@ -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."""

View file

@ -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:

View file

@ -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.