From 53a19064e618c99ab05f3ec6f7294150fa099987 Mon Sep 17 00:00:00 2001 From: Ivan Dimov <78815270+idimov-keeper@users.noreply.github.com> Date: Tue, 13 Feb 2024 17:47:50 -0600 Subject: [PATCH] Added folder support to secret list command --- .../keeper_secrets_manager_cli/__main__.py | 11 +++++-- .../keeper_secrets_manager_cli/secret.py | 33 +++++++++++++------ 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/integration/keeper_secrets_manager_cli/keeper_secrets_manager_cli/__main__.py b/integration/keeper_secrets_manager_cli/keeper_secrets_manager_cli/__main__.py index 80fa6c92..064acd9f 100644 --- a/integration/keeper_secrets_manager_cli/keeper_secrets_manager_cli/__main__.py +++ b/integration/keeper_secrets_manager_cli/keeper_secrets_manager_cli/__main__.py @@ -248,7 +248,8 @@ def handle_parse_result(self, ctx, opts, args): for mutex_opt in self.not_required_if: if mutex_opt and mutex_opt[0] in opts and (len(mutex_opt) == 1 or opts.get(mutex_opt[0], str(mutex_opt[1])+'_') == mutex_opt[1]): if current_opt: - raise click.UsageError("Illegal usage: '" + str(self.name) + "' is mutually exclusive with " + str(mutex_opt) + ".") + opt = str(mutex_opt) if len(mutex_opt) > 1 else f"'{str(mutex_opt[0])}'" + raise click.UsageError("Illegal usage: '" + str(self.name) + "' is mutually exclusive with " + opt + ".") else: self.prompt = None for mutex_opt in self.required_if: @@ -529,10 +530,12 @@ def secret_command(ctx): cls=HelpColorsCommand, help_options_color='blue' ) -@click.option('--uid', "-u", type=str, multiple=True) +@click.option('--uid', '-u', type=str, multiple=True, help='List specific records by Record UID', cls=Mutex, not_required_if=[('folder',)]) +@click.option('--folder', '-f', type=str, help='List only records in specified folder UID') +@click.option('--recursive', '-r', is_flag=True, help='List recursively all records including subfolders of the folder UID') @click.option('--json', is_flag=True, help='Return secret as JSON') @click.pass_context -def secret_list_command(ctx, uid, json): +def secret_list_command(ctx, uid, folder, recursive, json): """List all secrets""" output = "text" @@ -541,6 +544,8 @@ def secret_list_command(ctx, uid, json): ctx.obj["secret"].secret_list( uids=uid, + folder=folder, + recursive=recursive, output_format=output, use_color=ctx.obj["cli"].use_color ) diff --git a/integration/keeper_secrets_manager_cli/keeper_secrets_manager_cli/secret.py b/integration/keeper_secrets_manager_cli/keeper_secrets_manager_cli/secret.py index 40dad3cb..c2ffc631 100644 --- a/integration/keeper_secrets_manager_cli/keeper_secrets_manager_cli/secret.py +++ b/integration/keeper_secrets_manager_cli/keeper_secrets_manager_cli/secret.py @@ -359,9 +359,9 @@ def _query_jsonpath(self, jsonpath_query, records, force_array, raw): except Exception as err: raise KsmCliException("JSONPath failed: {}".format(err)) - def query(self, uids=None, titles=None, field=None, output_format='json', jsonpath_query=None, - force_array=False, load_references=False, unmask=False, use_color=None, inflate=True, - raw=False): + def query(self, uids=None, folder=None, recursive=False, titles=None, field=None, + output_format='json', jsonpath_query=None, force_array=False, + load_references=False, unmask=False, use_color=None, inflate=True, raw=False): if use_color is None: use_color = self.cli.use_color @@ -390,16 +390,29 @@ def query(self, uids=None, titles=None, field=None, output_format='json', jsonpa if len(secrets) == 0 and fetch_uids is not None: raise KsmCliException("Cannot find requested record(s).") + folders = self.cli.client.get_folders() if folder and recursive else [] + for record in secrets: add_record = False - # If we are searching by title, the fetch_uids was None, we have all the records. We need to filter - # them by the title or uids. - if len(titles) > 0: - if record.title in titles or record.uid in uids: + if folder: + if record.inner_folder_uid == folder or (not record.inner_folder_uid and record.folder_uid == folder): add_record = True + elif recursive and (record.inner_folder_uid or record.folder_uid): + fldr = record.inner_folder_uid or record.folder_uid + fldr = str(fldr) if fldr else '' + while fldr and fldr != folder: + fldr = next((x.parent_uid for x in folders if x.folder_uid == fldr), '') + if fldr == folder: + add_record = True else: - add_record = True + # If we are searching by title, the fetch_uids was None, we have all the records. We need to filter + # them by the title or uids. + if len(titles) > 0: + if record.title in titles or record.uid in uids: + add_record = True + else: + add_record = True if add_record is True: records.append(self._record_to_dict(record, @@ -435,12 +448,12 @@ def _format_list(record_dict, use_color=True): table.add_row([record["uid"], record["type"], record["title"]]) return "\n" + table.get_string() + "\n" - def secret_list(self, uids=None, output_format='json', use_color=None): + def secret_list(self, uids=None, folder=None, recursive=False, output_format='json', use_color=None): if use_color is None: use_color = self.cli.user_color - record_dict = self.query(uids=uids, output_format='dict', unmask=True, use_color=use_color) + record_dict = self.query(uids=uids, folder=folder, recursive=recursive, output_format='dict', unmask=True, use_color=use_color) if output_format == 'text': self.cli.output(self._format_list(record_dict, use_color=use_color)) elif output_format == 'json':