diff --git a/tenable/io/filters.py b/tenable/io/filters.py index 456165f75..df0e89622 100644 --- a/tenable/io/filters.py +++ b/tenable/io/filters.py @@ -44,10 +44,20 @@ def _normalize(self, filterset: list[dict[str, Any]]) -> dict[str, Any]: # is a list of dictionary items, and in other cases the "list" # is a list of string values. if isinstance(item['control']['list'][0], dict): - key = 'value' if 'value' in item['control']['list'][0] else 'id' - datablock['choices'] = [ - str(i[key]) for i in item['control']['list'] - ] + # The list items don't always carry the same key. Most use + # 'value' or 'id', but some (e.g. the target_group filter) + # only provide a 'name'. Pick the first key that exists + # rather than assuming 'id', which raised KeyError before. + first = item['control']['list'][0] + key = next( + (k for k in ('value', 'id', 'name') if k in first), None + ) + if key is not None: + datablock['choices'] = [ + str(i[key]) + for i in item['control']['list'] + if key in i + ] elif isinstance(item['control']['list'], list): datablock['choices'] = [str(i) for i in item['control']['list']] if 'regex' in item['control']: diff --git a/tests/io/test_filters.py b/tests/io/test_filters.py index 1f5215064..089631b1e 100644 --- a/tests/io/test_filters.py +++ b/tests/io/test_filters.py @@ -167,3 +167,24 @@ def test_filters_credentials_false_filters(api): check(data[1], 'readable_name', str, allow_none=True) check(data[1], 'operators', list, allow_none=True) check(data[1], 'control', dict, allow_none=True) + + +def test_normalize_name_only_choices(api): + """ + test that _normalize handles list items that only carry a 'name' key + (e.g. the target_group filter) instead of raising KeyError: 'id' + """ + filterset = [ + { + 'name': 'target_group', + 'operators': ['eq', 'neq'], + 'control': { + 'type': 'dropdown_multi', + 'list': [{'name': 'mygroup'}], + }, + } + ] + result = getattr(api.filters, '_normalize')(filterset) + assert result['target_group']['choices'] == ['mygroup'] + assert result['target_group']['operators'] == ['eq', 'neq'] + assert result['target_group']['pattern'] is None