def get_parser(self, prog_name): parser = super().get_parser(prog_name) how = parser.add_mutually_exclusive_group(required=False) default_environment = get_default_environment() how.add_argument( '-A', '--alias', action='store', dest='alias', default=None, help='Environment to alias' ) how.add_argument( '-C', '--clone-from', action='store', dest='clone_from', default=None, help='Environment directory to clone from' ) parser.add_argument( '--force', action='store_true', dest='force', default=False, help='Create secrets base directory' ) parser.add_argument( 'env', nargs='*', default=[default_environment] ) return parser
def take_action(self, parsed_args): default_env = get_default_environment() columns = (['Environment', 'Default']) if parsed_args.aliasing: columns.append('AliasFor') data = list() for env_path in get_environment_paths( basedir=self.app.secrets_basedir): # noqa if is_valid_environment( env_path, self.app_args.verbose_level, ): is_default = ("Yes" if env_path.name == default_env else "No") if not parsed_args.aliasing: item = (env_path.name, is_default) else: try: alias_for = os.path.basename(os.readlink(env_path)) except OSError: alias_for = '' item = (env_path.name, is_default, alias_for) data.append(item) if len(data) == 0: sys.exit(1) return columns, data
def get_parser(self, prog_name): parser = super().get_parser(prog_name) default_environment = get_default_environment() parser.add_argument('environment', nargs='?', default=default_environment) return parser
def take_action(self, parsed_args): if parsed_args.unset: if parsed_args.environment is not None: raise RuntimeError("[-] '--unset' does not take an argument") if clear_saved_default_environment(): self.logger.info('[+] explicit default environment unset') else: self.logger.info('[+] no default environment was set') elif parsed_args.set: # If it is not possible to interactively ask for environment, # just raise an exception. if (parsed_args.environment is None and not (stdin.isatty() and 'Bullet' in globals())): raise RuntimeError('[-] no environment specified') # Otherwise, let's prompt for an environment for better UX! if parsed_args.environment is not None: choice = parsed_args.environment else: basedir = self.app.secrets.get_secrets_basedir() environments = [ env_path.name for env_path in get_environment_paths(basedir=basedir) ] choices = ['<CANCEL>'] + sorted(environments) cli = Bullet(prompt="\nChose a new default environment:", choices=choices, indent=0, align=2, margin=1, shift=0, bullet="→", pad_right=5) choice = cli.launch() # Having second thoughts, eh? if choice == "<CANCEL>": self.logger.info('[-] cancelled setting default') if save_default_environment(choice): self.logger.info( "[+] default environment explicitly set to '%s'", choice) elif parsed_args.environment is not None: print(parsed_args.environment) else: # No environment specified; show current setting. env_string = get_saved_default_environment() if env_string is not None: if self.app_args.verbose_level > 1: self.logger.info( "[+] default environment explicitly set to '%s'", env_string) else: # No explicit saved default. env_string = get_default_environment() if self.app_args.verbose_level > 1: self.logger.info( "[+] default environment is implicitly '%s'", env_string) print(env_string)
def test_get_default_environment_default_file(self): tmp_dir = '/tmp' new_env_file = get_local_default_file(cwd=tmp_dir) self.assertEqual(new_env_file, Path(tmp_dir) / '.python_secrets_environment') with open(new_env_file, 'w') as f_out: f_out.write(TESTENV) default_env = get_default_environment(cwd=tmp_dir) # noqa os.unlink(new_env_file) self.assertEqual(default_env, TESTENV)
def __init__( self, environment=None, secrets_basedir=None, secrets_file=None, create_root=False, defer_loading=False, export_env_vars=False, preserve_existing=False, env_var_prefix=None, source=None, verbose_level=1, ): """ Initialize secrets environment object. """ if secrets_file and secrets_basedir: raise RuntimeError( "[-] 'secrets_file' and 'secrets_basedir' are mutually " "exclusive when initializing a SecretsEnvironment()") self._environment = (get_default_environment() if environment is None else environment) if secrets_basedir is None: secrets_basedir = get_default_secrets_basedir() try: is_secrets_basedir(basedir=secrets_basedir, raise_exception=True) self._secrets_basedir = Path(secrets_basedir) except BasedirNotFoundError: if create_root: self._secrets_basedir = secrets_basedir_create( basedir=secrets_basedir) else: raise if secrets_file is not None: self._secrets_file = Path(secrets_file) if len(self._secrets_file.parts) < 3: # This might not exactly be true in all cases, but I don't # have time to run down all possible use cases (or put in # all necessary checks) at the moment. raise RuntimeError( '[-] the path to a secrets file should have ' f"at least 3 components ('{self._secrets_file}')") if not self._secrets_file.exists(): raise RuntimeError( f"[-] the specified secrets file '{secrets_file}' " 'does not exist') if self._environment != self._secrets_file.parts[-2]: raise RuntimeError( f"[-] environment name '{environment}' does not " f"match secrets file path '{secrets_file}'") if Path(secrets_basedir) not in self._secrets_file.parents: raise RuntimeError( f"[-] base directory '{secrets_basedir}' does not " f"match secrets file path '{secrets_file}'") self.secrets_basedir = self._secrets_file.parents[1] else: self._secrets_file = self._secrets_basedir / self._environment / SECRETS_FILE # noqa self._secrets_descriptions = self._secrets_file.parent / SECRETS_DESCRIPTIONS_DIR # noqa self._verbose_level = verbose_level self.export_env_vars = export_env_vars self.preserve_existing = preserve_existing # When exporting environment variables, include one that specifies the # environment from which these variables were derived. This also works # around a limitation in Ansible where the current working directory # from which "ansible" was run. (The D2 lookup_plugin/python_secrets.py # script needs to communicate this back to python_secrets in order for # it's .python_secrets_environment file to be used to identify the # proper environment.) if self.export_env_vars is True: os.environ['D2_ENVIRONMENT'] = self._environment # Deprecating this variable name: os.environ['PYTHON_SECRETS_ENVIRONMENT'] = self._environment self.env_var_prefix = env_var_prefix # Secrets attribute maps; anything else throws exception for a in SECRET_ATTRIBUTES: setattr(self, a, OrderedDict()) if source is not None: self.clone_from(source) self.read_secrets_descriptions() self._secrets = OrderedDict() self._descriptions = OrderedDict() self._changed = False
# Local imports from psec import __version__ from psec.secrets_environment import SecretsEnvironment from psec.utils import ( # noqa bell, ensure_secrets_basedir, get_default_environment, get_default_secrets_basedir, permissions_check, show_current_value, umask, DEFAULT_UMASK, Timer, ) # Commands that do not need secrets environments. DOES_NOT_NEED_SECRETS = ['complete', 'help', 'init', 'utils'] # Use syslog for logging? # TODO(dittrich) Make this configurable, since it can fail on Mac OS X SYSLOG = False DEFAULT_ENVIRONMENT = get_default_environment() DEFAULT_BASEDIR = get_default_secrets_basedir() 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
def test_get_default_environment_no_default_file(self): cwd = os.getcwd() self.assertEqual(get_default_environment(cwd=cwd), os.path.basename(cwd))