Skip to content

Commit ee0136d

Browse files
authored
Fix CLI FileCategory choice breakage (#247)
* work around file category camelcase conversion to allow backwards compat values * add camel-case Zip option * make logic/tests work on current py42 as well as updated * style
1 parent 53cf4b3 commit ee0136d

File tree

3 files changed

+76
-2
lines changed

3 files changed

+76
-2
lines changed

src/code42cli/click_ext/types.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,3 +116,19 @@ def _get_dt_from_date_time_pair(date, time):
116116
raise BadParameter("Unable to parse date string: {}.".format(date_string))
117117
else:
118118
return dt
119+
120+
121+
class MapChoice(click.Choice):
122+
"""Choice subclass that takes an extra map of additional 'valid' keys to map to correct
123+
choices list, allowing backward compatible choice changes. The extra keys don't show up
124+
in help text, but work when passed as a choice.
125+
"""
126+
127+
def __init__(self, choices, extras_map, **kwargs):
128+
self.extras_map = extras_map
129+
super().__init__(choices, **kwargs)
130+
131+
def convert(self, value, param, ctx):
132+
if value in self.extras_map:
133+
value = self.extras_map[value]
134+
return super().convert(value, param, ctx)

src/code42cli/cmds/securitydata.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import code42cli.options as opt
1414
from code42cli.click_ext.groups import OrderedGroup
1515
from code42cli.click_ext.options import incompatible_with
16+
from code42cli.click_ext.types import MapChoice
1617
from code42cli.cmds.search import SendToCommand
1718
from code42cli.cmds.search.cursor_store import FileEventCursorStore
1819
from code42cli.cmds.search.extraction import handle_no_events
@@ -97,7 +98,25 @@
9798
file_category_option = click.option(
9899
"--file-category",
99100
multiple=True,
100-
type=click.Choice(list(FileCategory.choices())),
101+
type=MapChoice(
102+
choices=list(FileCategory.choices()),
103+
extras_map={
104+
"AUDIO": FileCategory.AUDIO,
105+
"DOCUMENT": FileCategory.DOCUMENT,
106+
"EXECUTABLE": FileCategory.EXECUTABLE,
107+
"IMAGE": FileCategory.IMAGE,
108+
"PDF": FileCategory.PDF,
109+
"PRESENTATION": FileCategory.PRESENTATION,
110+
"SCRIPT": FileCategory.SCRIPT,
111+
"SOURCE_CODE": FileCategory.SOURCE_CODE,
112+
"SPREADSHEET": FileCategory.SPREADSHEET,
113+
"VIDEO": FileCategory.VIDEO,
114+
"VIRTUAL_DISK_IMAGE": FileCategory.VIRTUAL_DISK_IMAGE,
115+
"ARCHIVE": FileCategory.ZIP,
116+
"ZIP": FileCategory.ZIP,
117+
"Zip": FileCategory.ZIP,
118+
},
119+
),
101120
callback=searchopt.is_in_filter(f.FileCategory),
102121
cls=searchopt.AdvancedQueryAndSavedSearchIncompatible,
103122
help="Limits events to file events where the file can be classified by one of these categories.",

tests/cmds/test_securitydata.py

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import pytest
66
from c42eventextractor.extractors import FileEventExtractor
77
from py42.sdk.queries.fileevents.file_event_query import FileEventQuery
8+
from py42.sdk.queries.fileevents.filters.file_filter import FileCategory
89
from tests.cmds.conftest import filter_term_is_in_call_args
910
from tests.cmds.conftest import get_filter_value_from_json
1011
from tests.cmds.conftest import get_mark_for_search_and_send_to
@@ -650,7 +651,7 @@ def test_search_and_send_to_when_given_file_path_uses_file_path_filter(
650651
def test_search_and_send_to_when_given_file_category_uses_file_category_filter(
651652
runner, cli_state, file_event_extractor, command
652653
):
653-
file_category = "IMAGE"
654+
file_category = FileCategory.IMAGE
654655
command = [*command, "--begin", "1h", "--file-category", file_category]
655656
runner.invoke(
656657
cli, command, obj=cli_state,
@@ -659,6 +660,44 @@ def test_search_and_send_to_when_given_file_category_uses_file_category_filter(
659660
assert str(f.FileCategory.is_in([file_category])) in filter_strings
660661

661662

663+
@pytest.mark.parametrize(
664+
"category_choice",
665+
[
666+
("AUDIO", FileCategory.AUDIO),
667+
("DOCUMENT", FileCategory.DOCUMENT),
668+
("EXECUTABLE", FileCategory.EXECUTABLE),
669+
("IMAGE", FileCategory.IMAGE),
670+
("PDF", FileCategory.PDF),
671+
("PRESENTATION", FileCategory.PRESENTATION),
672+
("SCRIPT", FileCategory.SCRIPT),
673+
("SOURCE_CODE", FileCategory.SOURCE_CODE),
674+
("SPREADSHEET", FileCategory.SPREADSHEET),
675+
("VIDEO", FileCategory.VIDEO),
676+
("VIRTUAL_DISK_IMAGE", FileCategory.VIRTUAL_DISK_IMAGE),
677+
("ARCHIVE", FileCategory.ZIP),
678+
("ZIP", FileCategory.ZIP),
679+
("Zip", FileCategory.ZIP),
680+
],
681+
)
682+
def test_all_caps_file_category_choices_convert_to_filecategory_constant(
683+
runner, cli_state, file_event_extractor, category_choice
684+
):
685+
ALL_CAPS_VALUE, camelCaseValue = category_choice
686+
command = [
687+
"security-data",
688+
"search",
689+
"--begin",
690+
"1h",
691+
"--file-category",
692+
ALL_CAPS_VALUE,
693+
]
694+
runner.invoke(
695+
cli, command, obj=cli_state,
696+
)
697+
filter_strings = [str(arg) for arg in file_event_extractor.extract.call_args[0]]
698+
assert str(f.FileCategory.is_in([camelCaseValue])) in filter_strings
699+
700+
662701
@search_and_send_to_test
663702
def test_search_and_send_to_when_given_process_owner_uses_process_owner_filter(
664703
runner, cli_state, file_event_extractor, command

0 commit comments

Comments
 (0)