Skip to content

Commit 137a3a1

Browse files
author
Juliya Smith
authored
Merge pull request #9 from code42/add-results-param-to-get-all
Add results param to get all
2 parents 7b67339 + eef0a6d commit 137a3a1

File tree

3 files changed

+123
-65
lines changed

3 files changed

+123
-65
lines changed

Packs/Code42/Integrations/Code42/Code42.py

Lines changed: 53 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -187,12 +187,15 @@ def remove_user_from_departing_employee(self, username):
187187
self._get_sdk().detectionlists.departing_employee.remove(user_id)
188188
return user_id
189189

190-
def get_all_departing_employees(self):
190+
def get_all_departing_employees(self, results):
191191
res = []
192192
pages = self._get_sdk().detectionlists.departing_employee.get_all()
193193
for page in pages:
194194
employees = page["items"]
195-
res.extend(employees)
195+
for employee in employees:
196+
res.append(employee)
197+
if len(res) == results:
198+
return res
196199
return res
197200

198201
def add_user_to_high_risk_employee(self, username, note=None):
@@ -219,12 +222,16 @@ def remove_user_risk_tags(self, username, risk_tags):
219222
self._get_sdk().detectionlists.remove_user_risk_tags(user_id, risk_tags)
220223
return user_id
221224

222-
def get_all_high_risk_employees(self, risk_tags=None):
225+
def get_all_high_risk_employees(self, risk_tags, results):
223226
risk_tags = _try_convert_str_list_to_list(risk_tags)
224227
res = []
225228
pages = self._get_sdk().detectionlists.high_risk_employee.get_all()
226229
for page in pages:
227-
res.extend(_get_all_high_risk_employees_from_page(page, risk_tags))
230+
employees = _get_all_high_risk_employees_from_page(page, risk_tags)
231+
for employee in employees:
232+
res.append(employee)
233+
if len(res) == results:
234+
return res
228235
return res
229236

230237
def fetch_alerts(self, start_time, event_severity_filter):
@@ -578,8 +585,9 @@ def departingemployee_remove_command(client, args):
578585

579586
@logger
580587
def departingemployee_get_all_command(client, args):
588+
results = args.get("results") or 50
581589
try:
582-
employees = client.get_all_departing_employees()
590+
employees = client.get_all_departing_employees(results)
583591
employees_context = [
584592
{
585593
"UserID": e["userId"],
@@ -629,10 +637,11 @@ def highriskemployee_remove_command(client, args):
629637
@logger
630638
def highriskemployee_get_all_command(client, args):
631639
tags = args.get("risktags")
640+
results = args.get("results")
632641
try:
633-
employees = client.get_all_high_risk_employees(tags)
642+
employees = client.get_all_high_risk_employees(tags, results)
634643
employees_context = [
635-
{"UserID": e["userId"], "Username": e["userName"], "Note": e["notes"]}
644+
{"UserID": e.get("userId"), "Username": e.get("userName"), "Note": e.get("notes")}
636645
for e in employees
637646
]
638647
readable_outputs = tableToMarkdown("Retrieved All High Risk Employees", employees_context)
@@ -671,6 +680,36 @@ def highriskemployee_remove_risk_tags_command(client, args):
671680
return_error(create_command_error_message(demisto.command(), e))
672681

673682

683+
@logger
684+
def securitydata_search_command(client, args):
685+
code42_security_data_context = []
686+
_json = args.get("json")
687+
file_context = []
688+
# If JSON payload is passed as an argument, ignore all other args and search by JSON payload
689+
if _json is not None:
690+
file_events = client.search_file_events(_json)
691+
else:
692+
# Build payload
693+
payload = build_query_payload(args)
694+
file_events = client.search_file_events(payload)
695+
if file_events:
696+
for file_event in file_events:
697+
code42_context_event = map_to_code42_event_context(file_event)
698+
code42_security_data_context.append(code42_context_event)
699+
file_context_event = map_to_file_context(file_event)
700+
file_context.append(file_context_event)
701+
readable_outputs = tableToMarkdown(
702+
"Code42 Security Data Results",
703+
code42_security_data_context,
704+
headers=SECURITY_EVENT_HEADERS,
705+
)
706+
security_data_context_key = "Code42.SecurityData(val.EventID && val.EventID == obj.EventID)"
707+
context = {security_data_context_key: code42_security_data_context, "File": file_context}
708+
return readable_outputs, context, file_events
709+
else:
710+
return "No results found", {}, {}
711+
712+
674713
def _create_incident_from_alert_details(details):
675714
return {"name": "Code42 - {}".format(details["name"]), "occurred": details["createdAt"]}
676715

@@ -680,7 +719,7 @@ def _stringify_lists_if_needed(event):
680719
shared_with = event.get("sharedWith")
681720
private_ip_addresses = event.get("privateIpAddresses")
682721
if shared_with:
683-
shared_list = [u["cloudUsername"] for u in shared_with]
722+
shared_list = [u.get("cloudUsername") for u in shared_with if u.get("cloudUsername")]
684723
event["sharedWith"] = str(shared_list)
685724
if private_ip_addresses:
686725
event["privateIpAddresses"] = str(private_ip_addresses)
@@ -729,7 +768,7 @@ def _fetch_remaining_incidents_from_last_run(self):
729768
if remaining_incidents:
730769
return (
731770
self._last_run,
732-
remaining_incidents[: self._fetch_limit],
771+
remaining_incidents[:self._fetch_limit],
733772
remaining_incidents[self._fetch_limit:],
734773
)
735774

@@ -759,7 +798,11 @@ def _create_incident_from_alert(self, alert):
759798
return incident
760799

761800
def _relate_files_to_alert(self, alert_details):
762-
for obs in alert_details["observations"]:
801+
observations = alert_details.get("observations")
802+
if not observations:
803+
alert_details["fileevents"] = []
804+
return
805+
for obs in observations:
763806
file_events = self._get_file_events_from_alert_details(obs, alert_details)
764807
alert_details["fileevents"] = [_process_event_from_observation(e) for e in file_events]
765808

@@ -789,36 +832,6 @@ def fetch_incidents(
789832
return fetcher.fetch()
790833

791834

792-
@logger
793-
def securitydata_search_command(client, args):
794-
code42_security_data_context = []
795-
_json = args.get("json")
796-
file_context = []
797-
# If JSON payload is passed as an argument, ignore all other args and search by JSON payload
798-
if _json is not None:
799-
file_events = client.search_file_events(_json)
800-
else:
801-
# Build payload
802-
payload = build_query_payload(args)
803-
file_events = client.search_file_events(payload)
804-
if file_events:
805-
for file_event in file_events:
806-
code42_context_event = map_to_code42_event_context(file_event)
807-
code42_security_data_context.append(code42_context_event)
808-
file_context_event = map_to_file_context(file_event)
809-
file_context.append(file_context_event)
810-
readable_outputs = tableToMarkdown(
811-
"Code42 Security Data Results",
812-
code42_security_data_context,
813-
headers=SECURITY_EVENT_HEADERS,
814-
)
815-
security_data_context_key = "Code42.SecurityData(val.EventID && val.EventID == obj.EventID)"
816-
context = {security_data_context_key: code42_security_data_context, "File": file_context}
817-
return readable_outputs, context, file_events
818-
else:
819-
return "No results found", {}, {}
820-
821-
822835
def test_module(client):
823836
try:
824837
# Will fail if unauthorized

Packs/Code42/Integrations/Code42/Code42.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,11 @@ script:
288288
type: string
289289
description: Removes a user from the Departing Employee List.
290290
- name: code42-departingemployee-get-all
291+
arguments:
292+
- name: results
293+
description: The number of items to return.
294+
defaultvalue: "50"
295+
type: number
291296
outputs:
292297
- contextPath: Code42.DepartingEmployee.UserID
293298
description: Internal Code42 User ID for the Departing Employee.
@@ -334,6 +339,10 @@ script:
334339
arguments:
335340
- name: risktags
336341
description: To filter results by employees who have these risk tags. Space delimited.
342+
- name: results
343+
description: The number of items to return.
344+
defaultvalue: 50
345+
type: number
337346
outputs:
338347
- contextPath: Code42.HighRiskEmployee.UserID
339348
description: Internal Code42 User ID for the High Risk Employee.

Packs/Code42/Integrations/Code42/Code42_test.py

Lines changed: 61 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,7 +1183,7 @@ def test_departingemployee_remove_command(code42_sdk_mock):
11831183

11841184
def test_departingemployee_get_all_command(code42_departing_employee_mock):
11851185
client = create_client(code42_departing_employee_mock)
1186-
_, _, res = departingemployee_get_all_command(client, {"username": "[email protected]"})
1186+
_, _, res = departingemployee_get_all_command(client, {})
11871187
expected = json.loads(MOCK_GET_ALL_DEPARTING_EMPLOYEES_RESPONSE)["items"]
11881188
assert res == expected
11891189
assert code42_departing_employee_mock.detectionlists.departing_employee.get_all.call_count == 1
@@ -1203,14 +1203,33 @@ def test_departingemployee_get_all_command_gets_employees_from_multiple_pages(
12031203
)
12041204
client = create_client(code42_departing_employee_mock)
12051205

1206-
_, _, res = departingemployee_get_all_command(client, {"username": "[email protected]"})
1206+
_, _, res = departingemployee_get_all_command(client, {})
12071207

12081208
# Expect to have employees from 3 pages in the result
12091209
expected_page = json.loads(MOCK_GET_ALL_DEPARTING_EMPLOYEES_RESPONSE)["items"]
12101210
expected = expected_page + expected_page + expected_page
12111211
assert res == expected
12121212

12131213

1214+
def test_departingemployee_get_all_command_gets_number_of_employees_equal_to_results_param(
1215+
code42_departing_employee_mock, mocker
1216+
):
1217+
1218+
# Setup get all departing employees
1219+
page = MOCK_GET_ALL_DEPARTING_EMPLOYEES_RESPONSE
1220+
# Setup 3 pages of employees
1221+
employee_page_generator = (
1222+
create_mock_code42_sdk_response(mocker, page) for page in [page, page, page]
1223+
)
1224+
code42_departing_employee_mock.detectionlists.departing_employee.get_all.return_value = (
1225+
employee_page_generator
1226+
)
1227+
client = create_client(code42_departing_employee_mock)
1228+
1229+
_, _, res = departingemployee_get_all_command(client, {"results": 1})
1230+
assert len(res) == 1
1231+
1232+
12141233
def test_departingemployee_get_all_command_when_no_employees(
12151234
code42_departing_employee_mock, mocker
12161235
):
@@ -1260,29 +1279,6 @@ def test_highriskemployee_remove_command(code42_sdk_mock):
12601279
code42_sdk_mock.detectionlists.high_risk_employee.remove.assert_called_once_with(expected)
12611280

12621281

1263-
def test_fetch_when_no_significant_file_categories_ignores_filter(
1264-
code42_fetch_incidents_mock, mocker
1265-
):
1266-
response_text = MOCK_ALERT_DETAILS_RESPONSE.replace(
1267-
'"isSignificant": true', '"isSignificant": false'
1268-
)
1269-
alert_details_response = create_mock_code42_sdk_response(mocker, response_text)
1270-
code42_fetch_incidents_mock.alerts.get_details.return_value = alert_details_response
1271-
client = create_client(code42_fetch_incidents_mock)
1272-
_, _, _ = fetch_incidents(
1273-
client=client,
1274-
last_run={"last_fetch": None},
1275-
first_fetch_time=MOCK_FETCH_TIME,
1276-
event_severity_filter=None,
1277-
fetch_limit=10,
1278-
include_files=True,
1279-
integration_context=None,
1280-
)
1281-
actual_query = str(code42_fetch_incidents_mock.securitydata.search_file_events.call_args[0][0])
1282-
assert "fileCategory" not in actual_query
1283-
assert "IMAGE" not in actual_query
1284-
1285-
12861282
def test_highriskemployee_get_all_command(code42_high_risk_employee_mock):
12871283
client = create_client(code42_high_risk_employee_mock)
12881284
_, _, res = highriskemployee_get_all_command(client, {})
@@ -1327,6 +1323,23 @@ def test_highriskemployee_get_all_command_when_given_risk_tags_only_gets_employe
13271323
assert code42_high_risk_employee_mock.detectionlists.high_risk_employee.get_all.call_count == 1
13281324

13291325

1326+
def test_highriskemployee_get_all_command_gets_number_of_employees_equal_to_results_param(
1327+
code42_high_risk_employee_mock, mocker
1328+
):
1329+
# Setup get all high risk employees
1330+
page = MOCK_GET_ALL_HIGH_RISK_EMPLOYEES_RESPONSE
1331+
# Setup 3 pages of employees
1332+
employee_page_generator = (
1333+
create_mock_code42_sdk_response(mocker, page) for page in [page, page, page]
1334+
)
1335+
code42_high_risk_employee_mock.detectionlists.high_risk_employee.get_all.return_value = (
1336+
employee_page_generator
1337+
)
1338+
client = create_client(code42_high_risk_employee_mock)
1339+
_, _, res = highriskemployee_get_all_command(client, {"results": 1})
1340+
assert len(res) == 1
1341+
1342+
13301343
def test_highriskemployee_get_all_command_when_no_employees(code42_high_risk_employee_mock, mocker):
13311344
no_employees_response = get_empty_detectionlist_response(
13321345
mocker, MOCK_GET_ALL_HIGH_RISK_EMPLOYEES_RESPONSE
@@ -1387,6 +1400,29 @@ def test_security_data_search_command(code42_file_events_mock):
13871400
assert filter_groups[3]["filters"][0]["value"] == "ApplicationRead"
13881401

13891402

1403+
def test_fetch_when_no_significant_file_categories_ignores_filter(
1404+
code42_fetch_incidents_mock, mocker
1405+
):
1406+
response_text = MOCK_ALERT_DETAILS_RESPONSE.replace(
1407+
'"isSignificant": true', '"isSignificant": false'
1408+
)
1409+
alert_details_response = create_mock_code42_sdk_response(mocker, response_text)
1410+
code42_fetch_incidents_mock.alerts.get_details.return_value = alert_details_response
1411+
client = create_client(code42_fetch_incidents_mock)
1412+
_, _, _ = fetch_incidents(
1413+
client=client,
1414+
last_run={"last_fetch": None},
1415+
first_fetch_time=MOCK_FETCH_TIME,
1416+
event_severity_filter=None,
1417+
fetch_limit=10,
1418+
include_files=True,
1419+
integration_context=None,
1420+
)
1421+
actual_query = str(code42_fetch_incidents_mock.securitydata.search_file_events.call_args[0][0])
1422+
assert "fileCategory" not in actual_query
1423+
assert "IMAGE" not in actual_query
1424+
1425+
13901426
def test_fetch_incidents_handles_single_severity(code42_sdk_mock):
13911427
client = create_client(code42_sdk_mock)
13921428
fetch_incidents(

0 commit comments

Comments
 (0)