Esempio n. 1
0
 def take_action(self, parsed_args):
     environment = self.app.options.environment
     e = SecretsEnvironment(environment)
     if parsed_args.tmpdir:
         if not e.environment_exists() and not parsed_args.create:
             return (f"[-] environment '{str(e)}' does not exist; "
                     "use '--create' to create it")
         tmpdir = e.get_tmpdir_path(create_path=parsed_args.create)
         self._print(tmpdir, parsed_args.json)
     else:
         base_path = e.get_environment_path()
         subdir = parsed_args.subdir
         full_path = base_path if subdir is None \
             else os.path.join(base_path, *subdir)
         if not os.path.exists(full_path) and parsed_args.create:
             mode = 0o700
             os.makedirs(full_path, mode)
             if self.app_args.verbose_level > 1:
                 self.logger.info("[+] created %s", full_path)
         if parsed_args.exists:
             # Just check existance and return result
             exists = os.path.exists(full_path)
             if self.app_args.verbose_level > 1:
                 status = "exists" if exists else "does not exist"
                 self.logger.info("[+] environment path '%s' %s", full_path,
                                  status)
             return 0 if exists else 1
         else:
             self._print(full_path, parsed_args.json)
Esempio n. 2
0
 def take_action(self, parsed_args):
     environment = parsed_args.environment
     if environment is None:
         environment = self.app.options.environment
     e = SecretsEnvironment(environment=environment)
     e.requires_environment()
     print_files = bool(parsed_args.no_files is False)
     atree(e.get_environment_path(),
           print_files=print_files,
           outfile=sys.stdout)
Esempio n. 3
0
 def setUp(self):
     self.cwd = os.getcwd()
     self.host = HOST
     self.keys_subdir = KEYS_SUBDIR
     self.secrets_env = None
     with patch.dict('os.environ'):
         for v in ['D2_ENVIRONMENT', 'D2_SECRETS_BASEDIR']:
             try:
                 del os.environ[v]
             except KeyError as e:  # noqa
                 pass
         self.secrets_env = SecretsEnvironment(create_root=True)
Esempio n. 4
0
 def take_action(self, parsed_args):
     se = self.app.secrets
     choice = None
     if parsed_args.environment is not None:
         choice = parsed_args.environment
     elif stdin.isatty() and 'Bullet' in globals():
         # Give user a chance to choose.
         environments = os.listdir(se.get_secrets_basedir())
         choices = ['<CANCEL>'] + sorted(environments)
         cli = Bullet(prompt="\nSelect environment to delete:",
                      choices=choices,
                      indent=0,
                      align=2,
                      margin=1,
                      shift=0,
                      bullet="→",
                      pad_right=5)
         choice = cli.launch()
         if choice == "<CANCEL>":
             self.logger.info('[-] cancelled deleting environment')
             return
     else:
         # Can't involve user in getting a choice.
         sys.exit('[-] no environment specified to delete')
     # Environment chosen. Now do we need to confirm?
     e = SecretsEnvironment(choice)
     env_path = e.get_environment_path()
     if not parsed_args.force:
         if not stdin.isatty():
             output = atree(env_path, outfile=None, print_files=True)
             raise RuntimeError(
                 "[-] must use '--force' flag to delete an environment.\n"
                 "[-] the following will be deleted: \n"
                 f"{''.join([line for line in output])}")
         else:
             prompt = f"Type the name '{choice}' to confirm: "
             cli = Input(prompt,
                         default="",
                         word_color=colors.foreground["yellow"])
             confirm = cli.launch()
             if confirm != choice:
                 self.logger.info('[-] cancelled deleting environment')
                 return
     # We have confirmation or --force. Now safe to delete.
     # TODO(dittrich): Use safe_delete_file over file list
     if env_path.is_symlink():
         env_path.unlink()
         self.logger.info("[+] deleted alias '%s'", env_path)
     else:
         shutil.rmtree(env_path)
         self.logger.info("[+] deleted directory path '%s'", env_path)
Esempio n. 5
0
class Test_SecretsEnvironment_args(unittest.TestCase):
    def setUp(self):
        self.cwd = os.getcwd()
        self.host = HOST
        self.keys_subdir = KEYS_SUBDIR
        self.envname = TESTENV
        self.basedir = Path(HOME) / (SECRETS_SUBDIR if sys.platform.startswith(
            'win') else '.' + SECRETS_SUBDIR)
        self.secrets_env = None
        with patch.dict('os.environ'):
            for v in ['D2_ENVIRONMENT', 'D2_SECRETS_BASEDIR']:
                try:
                    del os.environ[v]
                except KeyError as e:  # noqa
                    pass
            self.secrets_dir = secrets_dir(env=self.envname,
                                           basedir=self.basedir)
            self.keys_dir = keys_dir(secrets_dir=self.secrets_dir)
            self.keys_with_host_dir = keys_with_host_dir(
                keys_dir=self.keys_dir, host=self.host)
            self.secrets_env = SecretsEnvironment(
                environment=self.envname,
                secrets_basedir=self.basedir,
                create_root=True,
            )

    def tearDown(self):
        pass

    def test_no_D2_ENVIRONMENT(self):
        """Asserting D2_ENVIRONMENT not set in environment"""
        self.assertIsNone(os.environ.get('D2_ENVIRONMENT'))

    def test_environment_path(self):
        self.assertEqual(self.secrets_env.get_environment_path(),
                         self.secrets_dir)

    def test_environment_path_subdir(self):
        self.assertEqual(
            self.secrets_env.get_environment_path(subdir=self.keys_subdir),
            self.keys_dir)

    def test_environment_path_subdir_host(self):
        self.assertEqual(
            self.secrets_env.get_environment_path(subdir=KEYS_SUBDIR,
                                                  host=self.host),
            self.keys_with_host_dir)
Esempio n. 6
0
 def take_action(self, parsed_args):
     basedir = self.app.secrets.get_secrets_basedir()
     source = parsed_args.source[0]
     source_path = os.path.join(basedir, source)
     dest = parsed_args.dest[0]
     dest_path = os.path.join(basedir, dest)
     if source is None:
         raise RuntimeError('[-] no source name provided')
     if dest is None:
         raise RuntimeError('[-] no destination name provided')
     if not SecretsEnvironment(environment=source).environment_exists():
         raise RuntimeError(
             f"[-] source environment '{source}' does not exist")
     if SecretsEnvironment(environment=dest).environment_exists():
         raise RuntimeError(
             f"[-] destination environment '{dest}' already exist")
     os.rename(source_path, dest_path)
     self.logger.info("[+] environment '%s' renamed to '%s'", source, dest)
Esempio n. 7
0
 def setUp(self):
     self.host = HOST
     with patch.dict('os.environ'):
         for v in ['D2_ENVIRONMENT', 'D2_SECRETS_BASEDIR']:
             try:
                 del os.environ[v]
             except KeyError as e:  # noqa
                 pass
     self.secrets_env = SecretsEnvironment(create_root=True)
Esempio n. 8
0
 def setUp(self):
     self.cwd = os.getcwd()
     self.host = HOST
     self.keys_subdir = KEYS_SUBDIR
     self.envname = TESTENV
     self.basedir = Path(HOME) / (SECRETS_SUBDIR if sys.platform.startswith(
         'win') else '.' + SECRETS_SUBDIR)
     self.secrets_env = None
     with patch.dict('os.environ'):
         os.environ['D2_ENVIRONMENT'] = str(self.envname)
         os.environ['D2_SECRETS_BASEDIR'] = str(self.basedir)
         self.secrets_dir = secrets_dir(env=self.envname,
                                        basedir=self.basedir)
         self.keys_dir = keys_dir(secrets_dir=self.secrets_dir)
         self.keys_with_host_dir = keys_with_host_dir(
             keys_dir=self.keys_dir, host=self.host)
         self.secrets_env = SecretsEnvironment(environment=self.envname,
                                               create_root=True)  # noqa
Esempio n. 9
0
 def take_action(self, parsed_args):
     se = self.app.secrets
     # Creating a new group in an empty environment that exists is OK.
     se.requires_environment(path_only=True)
     se.read_secrets_descriptions()
     # A cloned group can inherit its name from file, otherwise a
     # name is required.
     if parsed_args.arg is None and parsed_args.clone_from is None:
         raise RuntimeError(
             '[-] no group name or group description source specified')
     group = parsed_args.arg
     groups = se.get_groups()
     clone_from = parsed_args.clone_from
     # Default is to create a new empty group
     descriptions = dict()
     if clone_from is not None:
         # Are we cloning from a file?
         if clone_from.endswith('.json'):
             if not os.path.isfile(clone_from):
                 raise RuntimeError("[-] group description file "
                                    f"'{clone_from}' does not exist")
             if group is None:
                 group = os.path.splitext(os.path.basename(clone_from))[0]
             descriptions = se.read_descriptions(infile=clone_from)
         else:
             # Must be cloning from an environment, but which group?
             if group is None:
                 raise RuntimeError(
                     "[-] please specify which group from environment "
                     f"'{parsed_args.clone_from}' you want to clone")
             clonefrom_se = SecretsEnvironment(environment=clone_from)
             if group not in clonefrom_se.get_groups():
                 raise RuntimeError(
                     f"[-] group '{group}' does not exist in "
                     f"environment '{clone_from}'")
             descriptions = clonefrom_se.read_descriptions(group=group)
     if len(descriptions) > 0:
         se.check_duplicates(descriptions)
     if group in groups:
         raise RuntimeError(f"[-] group '{group}' already exists")
     self.logger.info("[+] creating new group '%s'", group)
     se.write_descriptions(data=descriptions, group=group)
Esempio n. 10
0
class Test_SecretsEnvironment_with_env_vars(unittest.TestCase):
    def setUp(self):
        self.cwd = os.getcwd()
        self.host = HOST
        self.keys_subdir = KEYS_SUBDIR
        self.envname = TESTENV
        self.basedir = Path(HOME) / (SECRETS_SUBDIR if sys.platform.startswith(
            'win') else '.' + SECRETS_SUBDIR)
        self.secrets_env = None
        with patch.dict('os.environ'):
            os.environ['D2_ENVIRONMENT'] = str(self.envname)
            os.environ['D2_SECRETS_BASEDIR'] = str(self.basedir)
            self.secrets_dir = secrets_dir(env=self.envname,
                                           basedir=self.basedir)
            self.keys_dir = keys_dir(secrets_dir=self.secrets_dir)
            self.keys_with_host_dir = keys_with_host_dir(
                keys_dir=self.keys_dir, host=self.host)
            self.secrets_env = SecretsEnvironment(environment=self.envname,
                                                  create_root=True)  # noqa

    def tearDown(self):
        pass

    def test_environment(self):
        self.assertEqual(str(self.secrets_env), self.envname)

    def test_environment_path(self):
        self.assertEqual(self.secrets_env.get_environment_path(),
                         self.secrets_dir)

    def test_environment_path_subdir(self):
        self.assertEqual(
            self.secrets_env.get_environment_path(subdir=KEYS_SUBDIR),
            self.keys_dir)

    def test_environment_path_subdir_host(self):
        self.assertEqual(
            self.secrets_env.get_environment_path(subdir=KEYS_SUBDIR,
                                                  host=HOST),
            self.keys_with_host_dir)
Esempio n. 11
0
 def take_action(self, parsed_args):
     environment = parsed_args.environment
     if environment is None:
         environment = self.app.options.environment
     e = SecretsEnvironment(environment=environment)
     e.requires_environment()
     e.read_secrets_and_descriptions()
     secrets_tree(e, outfile=sys.stdout)
Esempio n. 12
0
class Test_SecretsEnvironment_no_env_vars(unittest.TestCase):
    def setUp(self):
        self.cwd = os.getcwd()
        self.host = HOST
        self.keys_subdir = KEYS_SUBDIR
        self.secrets_env = None
        with patch.dict('os.environ'):
            for v in ['D2_ENVIRONMENT', 'D2_SECRETS_BASEDIR']:
                try:
                    del os.environ[v]
                except KeyError as e:  # noqa
                    pass
            self.secrets_env = SecretsEnvironment(create_root=True)

    def tearDown(self):
        pass

    def test_no_D2_ENVIRONMENT(self):
        """Asserting D2_ENVIRONMENT not set in environment"""
        self.assertIsNone(os.environ.get('D2_ENVIRONMENT'))

    def test_environment_path(self):
        assert type(self.secrets_env) is not type(str)
        env_path = self.secrets_env.get_environment_path()
        self.assertEqual(env_path, secrets_dir())

    def test_environment_path_subdir(self):
        self.assertEqual(
            self.secrets_env.get_environment_path(subdir=self.keys_subdir),
            keys_dir())

    def test_environment_path_subdir_host(self):
        self.assertEqual(
            self.secrets_env.get_environment_path(subdir=KEYS_SUBDIR,
                                                  host=self.host),
            keys_with_host_dir(host=self.host))
Esempio n. 13
0
    def take_action(self, parsed_args):
        e = SecretsEnvironment(environment=self.app.options.environment)
        tmpdir = e.get_tmpdir_path()
        backend_file = os.path.join(os.getcwd(), 'tfbackend.tf')
        tfstate_file = os.path.join(tmpdir, 'terraform.tfstate')
        backend_text = textwrap.dedent("""\
            terraform {{
              backend "local" {{
              path = "{tfstate_file}"
              }}
            }}
            """.format(tfstate_file=tfstate_file))

        if parsed_args.path:
            self.logger.debug('[+] showing terraform state file path')
            print(tfstate_file)
        else:
            self.logger.debug('[+] setting up terraform backend')
            if os.path.exists(backend_file):
                self.logger.debug("[+] updating '%s'", backend_file)
            else:
                self.logger.debug("[+] creating '%s'", backend_file)
            with open(backend_file, 'w') as f:
                f.write(backend_text)
Esempio n. 14
0
 def take_action(self, parsed_args):
     e = SecretsEnvironment(environment=parsed_args.environment)
     print(e.get_descriptions_path())
Esempio n. 15
0
 def take_action(self, parsed_args):
     if (len(parsed_args.arg) == 0 and not parsed_args.undefined
             and not parsed_args.from_options):
         raise RuntimeError('[-] no secrets specified to be set')
     se = self.app.secrets
     se.requires_environment()
     se.read_secrets_and_descriptions()
     # TODO(dittrich): Use Variable map like this elsewhere
     variables = dict(se.Variable)
     types = dict(se.Type)
     from_env = None
     if parsed_args.from_environment is not None:
         from_env = SecretsEnvironment(
             environment=parsed_args.from_environment)
         from_env.read_secrets()
         variables = dict(from_env._secrets.Variable)
         types = dict(from_env._secrets.Type)
     args = (list(variables.keys())
             if len(parsed_args.arg) == 0 else parsed_args.arg)
     if parsed_args.undefined and len(variables) > 0:
         # Downselect to just those currently undefined
         args = [k for k, v in variables.items() if v in [None, '']]
     if len(args) == 0:
         raise RuntimeError('[-] no secrets identified to be set')
     for arg in args:
         k, v, k_type = None, None, None
         if parsed_args.from_options:
             k, v, k_type = (arg, se.get_default_value(arg), types.get(arg))
             # Don't set from options if the type is generable
             if is_generable(k_type):
                 continue
         elif '=' not in arg:
             # No value was specified with the argument
             k = arg
             k_type = se.secrets.get_type(k)
             if k_type is None:
                 self.logger.info("[-] no description for '%s'", k)
                 raise RuntimeError(
                     f"[-] variable '{k}' has no description")
             if from_env is not None:
                 # Getting value from same var, different environment
                 v = from_env.get_secret(k, allow_none=True)
             else:
                 # Try to prompt user for value
                 if (k_type == 'boolean' and k not in se.Options):
                     # Default options for boolean type
                     se.Options[k] = BOOLEAN_OPTIONS
                 k_options = se.get_options(k)
                 if (k_options != '*' and k in se.Options):
                     # Attempt to select from list. Options will look like
                     # 'a,b' or 'a,b,*', or 'a,*'.
                     old_v = se.get_secret(k, allow_none=True)
                     v = prompt_options_list(
                         options=k_options.split(','),
                         default=(None if old_v in ['', None] else old_v),
                         prompt=se.get_prompt(k))
                     if v is None:
                         # User cancelled selection.
                         break
                     v = v if v not in ['', '*'] else None
                 # Ask user for value
                 if v is None:
                     v = prompt_string(prompt=se.get_prompt(k), default="")
                 v = v if v != '' else None
         else:  # ('=' in arg)
             # Assignment syntax found (a=b)
             lhs, rhs = arg.split('=')
             k_type = se.get_type(lhs)
             if k_type is None:
                 self.logger.info("[-] no description for '%s'", lhs)
                 raise RuntimeError(
                     f"[-] variable '{lhs}' has no description")
             k = lhs
             if from_env is not None:
                 # Get value from different var in different environment
                 v = from_env.get_secret(rhs, allow_none=True)
                 self.logger.info(
                     "[+] getting value from '%s' in environment '%s'", rhs,
                     str(from_env))
             else:
                 # Value was specified in arg
                 v = rhs
             if v is not None:
                 # Is the value indirectly referenced?
                 if v.startswith('@'):
                     if v[1] == '~':
                         _path = os.path.expanduser(v[1:])
                     else:
                         _path = v[1:]
                     with open(_path, 'r') as f:
                         v = f.read().strip()
                 elif v.startswith('!'):
                     # >> Issue: [B603:subprocess_without_shell_equals_true] subprocess call - check for execution of untrusted input.  # noqa
                     #    Severity: Low   Confidence: High
                     #    Location: psec/secrets.py:641
                     p = run(v[1:].split(),
                             stdout=PIPE,
                             stderr=PIPE,
                             shell=False)
                     v = p.stdout.decode('UTF-8').strip()
         # After all that, did we get a value?
         if v is None:
             self.logger.info("[-] could not obtain value for '%s'", k)
         else:
             self.logger.debug("[+] setting variable '%s'", k)
             se.set_secret(k, v)
Esempio n. 16
0
 def take_action(self, parsed_args):
     e = SecretsEnvironment(environment=parsed_args.environment)
     print(e.get_secrets_file_path())
Esempio n. 17
0
 def take_action(self, parsed_args):
     secrets_basedir = self.app.secrets_basedir
     if parsed_args.alias is not None:
         if len(parsed_args.env) != 1:
             raise RuntimeError(
                 '[-] --alias requires one source environment')
         se = SecretsEnvironment(
             environment=parsed_args.alias,
             secrets_basedir=secrets_basedir,
             create_root=parsed_args.force,
         )
         se.environment_create(
             source=parsed_args.env[0],
             alias=True
         )
         if se.environment_exists():
             self.logger.info(
                 "[+] environment '%s' aliased to '%s'",
                 parsed_args.alias,
                 parsed_args.env[0]
             )
         else:
             raise RuntimeError('[-] creating environment failed')
     else:
         # Default to app environment identifier
         if len(parsed_args.env) == 0:
             parsed_args.env = list(self.app.environment)
         for environment in parsed_args.env:
             se = SecretsEnvironment(
                 environment=environment,
                 secrets_basedir=secrets_basedir,
                 create_root=True,
             )
             se.environment_create(source=parsed_args.clone_from)
             self.logger.info(
                 "[+] environment '%s' (%s) created",
                 environment,
                 se.get_environment_path()
             )
             if parsed_args.clone_from:
                 se.read_secrets(from_descriptions=True)
                 se.write_secrets()
Esempio n. 18
0
class PythonSecretsApp(App):
    """Python secrets application class."""
    def __init__(self):
        super().__init__(
            description=__doc__.strip(),
            version=__version__,
            command_manager=CommandManager(namespace='psec'),
            deferred_help=True,
        )
        self.secrets = None
        self.environment = None
        self.secrets_basedir = None
        self.secrets_file = None
        self.timer = Timer()
        # Alias the following variable for consistency using code
        # using "logger" instead of "LOG".
        self.logger = self.LOG

    def build_option_parser(self, description, version):
        parser = super().build_option_parser(description, version)
        # OCD hack: Make ``help`` output report main program name,
        # even if run as ``python -m psec.main`` or such.
        if parser.prog.endswith('.py'):
            parser.prog = self.command_manager.namespace
        # Replace the cliff SmartHelpFormatter class before first use
        # by subcommand `--help`.
        # pylint: disable=wrong-import-order
        from psec.utils import CustomFormatter
        from cliff import _argparse
        _argparse.SmartHelpFormatter = CustomFormatter
        # pylint: enable=wrong-import-order
        # We also need to change app parser, which is separate.
        parser.formatter_class = CustomFormatter
        # Global options
        parser.add_argument('--elapsed',
                            action='store_true',
                            dest='elapsed',
                            default=False,
                            help='Print elapsed time on exit')
        parser.add_argument(
            '-d',
            '--secrets-basedir',
            metavar='<secrets-basedir>',
            dest='secrets_basedir',
            default=DEFAULT_BASEDIR,
            help='Root directory for holding secrets (Env: D2_SECRETS_BASEDIR)'
        )
        parser.add_argument(
            '-e',
            '--environment',
            metavar='<environment>',
            dest='environment',
            default=DEFAULT_ENVIRONMENT,
            help='Deployment environment selector (Env: D2_ENVIRONMENT)')
        parser.add_argument('-s',
                            '--secrets-file',
                            metavar='<secrets-file>',
                            dest='secrets_file',
                            default=None,
                            help='Secrets file')
        parser.add_argument('-P',
                            '--env-var-prefix',
                            metavar='<prefix>',
                            dest='env_var_prefix',
                            default=None,
                            help='Prefix string for environment variables')
        parser.add_argument('-E',
                            '--export-env-vars',
                            action='store_true',
                            dest='export_env_vars',
                            default=False,
                            help='Export secrets as environment variables')
        parser.add_argument(
            '--preserve-existing',
            action='store_true',
            dest='preserve_existing',
            default=False,
            help='Prevent over-writing existing environment variables')
        parser.add_argument(
            '--init',
            action='store_true',
            dest='init',
            default=False,
            help='Ensure the directory for holding secrets is initialized')
        parser.add_argument(
            '--umask',
            metavar='<umask>',
            type=umask,
            dest='umask',
            default=DEFAULT_UMASK,
            help='Permissions mask to apply during app execution')
        parser.add_argument(
            '--rtd',
            action='store_true',
            dest='rtd',
            default=False,
            help='Open ReadTheDocs documentation on "help" command')
        parser.epilog = textwrap.dedent(f"""
            For programs that inherit values through environment variables, you can export
            secrets using the ``-E`` option to the ``run`` subcommand, e.g.  ``psec -E run
            -- terraform plan -out=$(psec environments path --tmpdir)/tfplan`` The
            environment variable ``PYTHON_SECRETS_ENVIRONMENT`` will also be exported with
            the identifier of the associated source environment.

            To improve overall security, a default process umask of {DEFAULT_UMASK:#05o}
            is set when the app initializes. When running programs like the example above
            where files containing sensitive data are created in the environment
            directory, this reduces the chance that files created during execution will
            end up with overly broad permissions.  If you need to relax these permissions,
            use the ``--umask`` option to apply the desired mask.

            To control the browser that is used with the ``help --rtd`` command, set the
            BROWSER environment variable (e.g., ``BROWSER=lynx``).  See:
            https://github.com/python/cpython/blob/3.8/Lib/webbrowser.py

            Current working dir: {os.getcwd()}
            Python interpreter:  {sys.executable} (v{sys.version.split()[0]})

            Environment variables consumed:
              BROWSER             Default browser for use by webbrowser.open().{show_current_value('BROWSER')}
              D2_ENVIRONMENT      Default environment identifier.{show_current_value('D2_ENVIRONMENT')}
              D2_SECRETS_BASEDIR  Default base directory for storing secrets.{show_current_value('D2_SECRETS_BASEDIR')}
              D2_SECRETS_BASENAME Default base name for secrets storage files.{show_current_value('D2_SECRETS_BASENAME')}
              D2_NO_REDACT        Default redaction setting for ``secrets show`` command.{show_current_value('D2_NO_REDACT')}
            """)  # noqa
        return parser

    def initialize_app(self, argv):
        self.logger.debug('[*] initialize_app(%s)', self.__class__.NAME)
        if sys.version_info <= (3, 6):
            raise RuntimeError('This program requires Python 3.6 or higher')
        os.umask(self.options.umask)
        self.timer.start()

    def prepare_to_run_command(self, cmd):
        self.logger.debug("[*] prepare_to_run_command('%s')", cmd.cmd_name)
        #
        # Process ReadTheDocs web browser request here and then
        # fall through, which also produces help output on the
        # command line. The webbrowser module doesn't seem to work
        # consistently on Ubuntu Linux and some versions of Mac OS X (Darwin),
        # so this helps a little though may be confusing when you don't
        # get a browser opening up like you expect.
        rtd_url = 'https://python-secrets.readthedocs.io/en/latest/usage.html'
        if cmd.cmd_name == 'help' and self.options.rtd:
            for line in [
                    '[+] Opening online documentation for python_secrets on ReadTheDocs.',  # noqa
                    '[+] If a browser does not open, make sure that you are online and/or',  # noqa
                    '[+] enter the following URL in your chosen browser:',
                    rtd_url,
            ]:
                self.logger.info(line)
            print('\n\n')
            bell()
            time.sleep(3)
            # TODO(dittrich): Add more specificity
            # FYI, new= is ignored on Windows per:
            # https://stackoverflow.com/questions/1997327/python-webbrowser-open-setting-new-0-to-open-in-the-same-browser-window-does  # noqa
            webbrowser.open(rtd_url, new=0, autoraise=True)
        self.logger.debug("[+] using environment '%s'",
                          self.options.environment)
        # Set up an environment for the app, making sure to export runtime
        # options matching those from the command line and environment
        # variables for subprocesses to inherit. It's OK to warn here about
        # missing base directory (which will happen on first use), but don't
        # force the program to exit when not necessary.
        #
        env_environment = os.environ.get('D2_ENVIRONMENT')
        self.environment = self.options.environment
        if (env_environment is None or env_environment != self.environment):
            os.environ['D2_ENVIRONMENT'] = str(self.environment)
        env_secrets_basedir = os.environ.get('D2_SECRETS_BASEDIR')
        self.secrets_basedir = ensure_secrets_basedir(
            secrets_basedir=self.options.secrets_basedir,
            allow_create=(self.options.init
                          or cmd.cmd_name.startswith('init')),
            verbose_level=self.options.verbose_level,
        )
        if (env_secrets_basedir is None
                or env_secrets_basedir != str(self.secrets_basedir)):
            os.environ['D2_SECRETS_BASEDIR'] = str(self.secrets_basedir)
        self.secrets_file = self.options.secrets_file
        cmd_base = cmd.cmd_name.split(' ')[0]
        if cmd_base not in DOES_NOT_NEED_SECRETS:
            self.secrets = SecretsEnvironment(
                environment=self.environment,
                create_root=False,
                secrets_basedir=self.secrets_basedir,
                secrets_file=self.secrets_file,
                export_env_vars=self.options.export_env_vars,
                preserve_existing=self.options.preserve_existing,
                verbose_level=self.options.verbose_level,
                env_var_prefix=self.options.env_var_prefix,
            )
            permissions_check(
                self.secrets_basedir,
                verbose_level=self.options.verbose_level,
            )
        self.logger.debug("[*] running command '%s'", cmd.cmd_name)

    def clean_up(self, cmd, result, err):
        self.logger.debug("[-] clean_up command '%s'", cmd.cmd_name)
        if err:
            self.logger.debug("[-] got an error: %s", str(err))
            if self.secrets is not None and self.secrets.changed():
                self.logger.info(
                    '[-] not writing changed secrets out due to error')
            sys.exit(result)
        if self.secrets is not None and self.secrets.changed():
            self.secrets.write_secrets()
        if (self.options.elapsed or
            (self.options.verbose_level > 1 and cmd.cmd_name != "complete")):
            self.timer.stop()
            elapsed = self.timer.elapsed()
            self.stderr.write('[+] elapsed time {}\n'.format(elapsed))
            bell()
Esempio n. 19
0
 def prepare_to_run_command(self, cmd):
     self.logger.debug("[*] prepare_to_run_command('%s')", cmd.cmd_name)
     #
     # Process ReadTheDocs web browser request here and then
     # fall through, which also produces help output on the
     # command line. The webbrowser module doesn't seem to work
     # consistently on Ubuntu Linux and some versions of Mac OS X (Darwin),
     # so this helps a little though may be confusing when you don't
     # get a browser opening up like you expect.
     rtd_url = 'https://python-secrets.readthedocs.io/en/latest/usage.html'
     if cmd.cmd_name == 'help' and self.options.rtd:
         for line in [
                 '[+] Opening online documentation for python_secrets on ReadTheDocs.',  # noqa
                 '[+] If a browser does not open, make sure that you are online and/or',  # noqa
                 '[+] enter the following URL in your chosen browser:',
                 rtd_url,
         ]:
             self.logger.info(line)
         print('\n\n')
         bell()
         time.sleep(3)
         # TODO(dittrich): Add more specificity
         # FYI, new= is ignored on Windows per:
         # https://stackoverflow.com/questions/1997327/python-webbrowser-open-setting-new-0-to-open-in-the-same-browser-window-does  # noqa
         webbrowser.open(rtd_url, new=0, autoraise=True)
     self.logger.debug("[+] using environment '%s'",
                       self.options.environment)
     # Set up an environment for the app, making sure to export runtime
     # options matching those from the command line and environment
     # variables for subprocesses to inherit. It's OK to warn here about
     # missing base directory (which will happen on first use), but don't
     # force the program to exit when not necessary.
     #
     env_environment = os.environ.get('D2_ENVIRONMENT')
     self.environment = self.options.environment
     if (env_environment is None or env_environment != self.environment):
         os.environ['D2_ENVIRONMENT'] = str(self.environment)
     env_secrets_basedir = os.environ.get('D2_SECRETS_BASEDIR')
     self.secrets_basedir = ensure_secrets_basedir(
         secrets_basedir=self.options.secrets_basedir,
         allow_create=(self.options.init
                       or cmd.cmd_name.startswith('init')),
         verbose_level=self.options.verbose_level,
     )
     if (env_secrets_basedir is None
             or env_secrets_basedir != str(self.secrets_basedir)):
         os.environ['D2_SECRETS_BASEDIR'] = str(self.secrets_basedir)
     self.secrets_file = self.options.secrets_file
     cmd_base = cmd.cmd_name.split(' ')[0]
     if cmd_base not in DOES_NOT_NEED_SECRETS:
         self.secrets = SecretsEnvironment(
             environment=self.environment,
             create_root=False,
             secrets_basedir=self.secrets_basedir,
             secrets_file=self.secrets_file,
             export_env_vars=self.options.export_env_vars,
             preserve_existing=self.options.preserve_existing,
             verbose_level=self.options.verbose_level,
             env_var_prefix=self.options.env_var_prefix,
         )
         permissions_check(
             self.secrets_basedir,
             verbose_level=self.options.verbose_level,
         )
     self.logger.debug("[*] running command '%s'", cmd.cmd_name)