From 7edef744938512a349d1058a4d72581ac256ebcd Mon Sep 17 00:00:00 2001 From: Cecilia Stevens <63068179+ceciliastevens@users.noreply.github.com> Date: Thu, 19 Dec 2024 16:18:04 -0500 Subject: [PATCH 1/4] when querying sessions, properly use timestamp in milliseconds --- src/_incydr_sdk/sessions/client.py | 8 +-- tests/test_sessions.py | 96 +++++++++++++++++++++++++++++- 2 files changed, 99 insertions(+), 5 deletions(-) diff --git a/src/_incydr_sdk/sessions/client.py b/src/_incydr_sdk/sessions/client.py index 3ea2a96..2cb0a86 100644 --- a/src/_incydr_sdk/sessions/client.py +++ b/src/_incydr_sdk/sessions/client.py @@ -76,9 +76,9 @@ def get_page( # Parse timestamps if start_time and not isinstance(start_time, (int, float)): - start_time = parse_ts_to_posix_ts(start_time) + start_time = parse_ts_to_posix_ts(start_time) * 1000 if end_time and not isinstance(end_time, (int, float)): - end_time = parse_ts_to_posix_ts(end_time) + end_time = parse_ts_to_posix_ts(end_time) * 1000 if states and not isinstance(states, List): states = [states] @@ -253,9 +253,9 @@ def update_state_by_criteria( # Parse timestamps if start_time and not isinstance(start_time, (int, float)): - start_time = parse_ts_to_posix_ts(start_time) + start_time = parse_ts_to_posix_ts(start_time) * 1000 if end_time and not isinstance(end_time, (int, float)): - end_time = parse_ts_to_posix_ts(end_time) + end_time = parse_ts_to_posix_ts(end_time) * 1000 if states and not isinstance(states, List): states = [states] diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 4fc8643..4ea733e 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -22,7 +22,11 @@ TEST_SESSION_ID = "123-session-1" DATETIME_INSTANT = datetime(2024, 1, 1, tzinfo=timezone.utc) -POSIX_TS = int(DATETIME_INSTANT.timestamp()) +POSIX_TS = int(DATETIME_INSTANT.timestamp()) * 1000 +START_DATE = "2024-12-19" +START_TIMESTAMP = 1734566400000 # in ms +END_DATE = "2024-12-20" +END_TIMESTAMP = 1734652800000 # in ms TEST_SESSION = { "actorId": TEST_SESSION_ID, @@ -157,6 +161,49 @@ def test_get_page_when_custom_params_returns_expected_data(httpserver_auth: HTTP assert page.items[0].json() == json.dumps(TEST_SESSION) assert len(page.items) == 1 == page.total_count +def test_get_page_when_given_date_uses_correct_timestamp(httpserver_auth: HTTPServer): + query = { + "actor_id": "actor-id", + "on_or_after": START_TIMESTAMP, + "before": END_TIMESTAMP, + "has_alerts": "false", + "risk_indicators": ["risk-indicator"], + "state": ["OPEN"], + "severity": [3], + "rule_id": ["rule-id"], + "watchlist_id": ["watchlist-id"], + "content_inspection_status": "PENDING", + "order_by": "score", + "sort_direction": "desc", + "page_number": 2, + "page_size": 10, + } + sessions_page = {"items": [TEST_SESSION], "totalCount": 1} + httpserver_auth.expect_request( + "/v1/sessions", method="GET", query_string=urlencode(query, doseq=True) + ).respond_with_json(sessions_page) + + client = Client() + page = client.sessions.v1.get_page( + actor_id="actor-id", + start_time=START_DATE, + end_time=END_DATE, + has_alerts=False, + sort_key=SortKeys.SCORE, + risk_indicators=["risk-indicator"], + sort_dir=SortDirection.DESC, + states=SessionStates.OPEN, + severities=3, + rule_ids="rule-id", + watchlist_ids="watchlist-id", + page_num=2, + page_size=10, + content_inspection_status=ContentInspectionStatuses.PENDING, + ) + assert isinstance(page, SessionsPage) + assert page.items[0].json() == json.dumps(TEST_SESSION) + assert len(page.items) == 1 == page.total_count + def test_iter_all_when_default_params_returns_expected_data( httpserver_auth: HTTPServer, @@ -356,6 +403,53 @@ def test_update_state_by_criteria_makes_expected_calls(httpserver_auth: HTTPServ for response in responses: assert response.status_code == 200 +def test_update_state_by_criteria_when_given_date_uses_correct_timestamp(httpserver_auth: HTTPServer): + query = { + "actor_id": "actor-id", + "on_or_after": START_TIMESTAMP, + "before": END_TIMESTAMP, + "has_alerts": "false", + "risk_indicators": ["risk-indicator"], + "state": ["OPEN"], + "severity": [3], + "rule_id": ["rule-id"], + "watchlist_id": ["watchlist-id"], + "content_inspection_status": "PENDING", + } + + token = "123-token" + httpserver_auth.expect_request( + "/v1/sessions/change-states", + query_string=urlencode(query, doseq=True), + method="POST", + json={"continuationToken": None, "newState": "CLOSED"}, + ).respond_with_json({"continuationToken": token}) + httpserver_auth.expect_request( + "/v1/sessions/change-states", + query_string=urlencode(query, doseq=True), + method="POST", + json={"continuationToken": token, "newState": "CLOSED"}, + ).respond_with_json({"continuationToken": None}) + + client = Client() + responses = client.sessions.v1.update_state_by_criteria( + new_state=SessionStates.CLOSED, + actor_id="actor-id", + start_time=START_DATE, + end_time=END_DATE, + has_alerts=False, + risk_indicators=["risk-indicator"], + states=SessionStates.OPEN, + severities=3, + rule_ids="rule-id", + watchlist_ids="watchlist-id", + content_inspection_status=ContentInspectionStatuses.PENDING, + ) + assert responses[0].json()["continuationToken"] == token + assert responses[1].json()["continuationToken"] is None + for response in responses: + assert response.status_code == 200 + # ************************************************ CLI ************************************************ From eed74e895926c517d66443f349b738c3f9e83d0b Mon Sep 17 00:00:00 2001 From: Cecilia Stevens <63068179+ceciliastevens@users.noreply.github.com> Date: Thu, 19 Dec 2024 16:19:13 -0500 Subject: [PATCH 2/4] style --- tests/test_sessions.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/test_sessions.py b/tests/test_sessions.py index 4ea733e..7562f7f 100644 --- a/tests/test_sessions.py +++ b/tests/test_sessions.py @@ -24,9 +24,9 @@ DATETIME_INSTANT = datetime(2024, 1, 1, tzinfo=timezone.utc) POSIX_TS = int(DATETIME_INSTANT.timestamp()) * 1000 START_DATE = "2024-12-19" -START_TIMESTAMP = 1734566400000 # in ms +START_TIMESTAMP = 1734566400000 # in ms END_DATE = "2024-12-20" -END_TIMESTAMP = 1734652800000 # in ms +END_TIMESTAMP = 1734652800000 # in ms TEST_SESSION = { "actorId": TEST_SESSION_ID, @@ -161,6 +161,7 @@ def test_get_page_when_custom_params_returns_expected_data(httpserver_auth: HTTP assert page.items[0].json() == json.dumps(TEST_SESSION) assert len(page.items) == 1 == page.total_count + def test_get_page_when_given_date_uses_correct_timestamp(httpserver_auth: HTTPServer): query = { "actor_id": "actor-id", @@ -403,7 +404,10 @@ def test_update_state_by_criteria_makes_expected_calls(httpserver_auth: HTTPServ for response in responses: assert response.status_code == 200 -def test_update_state_by_criteria_when_given_date_uses_correct_timestamp(httpserver_auth: HTTPServer): + +def test_update_state_by_criteria_when_given_date_uses_correct_timestamp( + httpserver_auth: HTTPServer, +): query = { "actor_id": "actor-id", "on_or_after": START_TIMESTAMP, From 78b0667e64d55009b20a1977c8dc4a938cd6bf38 Mon Sep 17 00:00:00 2001 From: Cecilia Stevens <63068179+ceciliastevens@users.noreply.github.com> Date: Wed, 8 Jan 2025 12:58:06 -0500 Subject: [PATCH 3/4] add helper method for ms timestamp --- src/_incydr_sdk/queries/utils.py | 5 +++++ src/_incydr_sdk/sessions/client.py | 9 +++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/_incydr_sdk/queries/utils.py b/src/_incydr_sdk/queries/utils.py index 00d7552..2a183ec 100644 --- a/src/_incydr_sdk/queries/utils.py +++ b/src/_incydr_sdk/queries/utils.py @@ -40,6 +40,11 @@ def parse_ts_to_posix_ts(timestamp: Union[str, datetime]): dt = timestamp if isinstance(timestamp, datetime) else parse_str_to_dt(timestamp) return dt.timestamp() +def parse_ts_to_ms_ts(timestamp: Union[str, datetime]): + """ + Parse epoch ms timestamp from DATE/DATETIME str or datetime obj. + """ + return parse_ts_to_posix_ts(timestamp) * 1000 def parse_str_to_dt(timestamp: str): try: diff --git a/src/_incydr_sdk/sessions/client.py b/src/_incydr_sdk/sessions/client.py index 2cb0a86..3490dd7 100644 --- a/src/_incydr_sdk/sessions/client.py +++ b/src/_incydr_sdk/sessions/client.py @@ -9,6 +9,7 @@ from _incydr_sdk.enums.sessions import SessionStates from _incydr_sdk.enums.sessions import SortKeys from _incydr_sdk.queries.utils import parse_ts_to_posix_ts +from _incydr_sdk.queries.utils import parse_ts_to_ms_ts from _incydr_sdk.sessions.models.models import SessionsChangeStateRequest from _incydr_sdk.sessions.models.models import SessionsCriteriaRequest from _incydr_sdk.sessions.models.models import SessionsQueryRequest @@ -76,9 +77,9 @@ def get_page( # Parse timestamps if start_time and not isinstance(start_time, (int, float)): - start_time = parse_ts_to_posix_ts(start_time) * 1000 + start_time = parse_ts_to_ms_ts(start_time) if end_time and not isinstance(end_time, (int, float)): - end_time = parse_ts_to_posix_ts(end_time) * 1000 + end_time = parse_ts_to_ms_ts(end_time) if states and not isinstance(states, List): states = [states] @@ -253,9 +254,9 @@ def update_state_by_criteria( # Parse timestamps if start_time and not isinstance(start_time, (int, float)): - start_time = parse_ts_to_posix_ts(start_time) * 1000 + start_time = parse_ts_to_ms_ts(start_time) if end_time and not isinstance(end_time, (int, float)): - end_time = parse_ts_to_posix_ts(end_time) * 1000 + end_time = parse_ts_to_ms_ts(end_time) if states and not isinstance(states, List): states = [states] From 0ab859e6bc8124ec846c8aa2359ef81fbec12d03 Mon Sep 17 00:00:00 2001 From: Cecilia Stevens <63068179+ceciliastevens@users.noreply.github.com> Date: Wed, 8 Jan 2025 13:00:56 -0500 Subject: [PATCH 4/4] style --- src/_incydr_sdk/queries/utils.py | 2 ++ src/_incydr_sdk/sessions/client.py | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/_incydr_sdk/queries/utils.py b/src/_incydr_sdk/queries/utils.py index 2a183ec..a22a6b6 100644 --- a/src/_incydr_sdk/queries/utils.py +++ b/src/_incydr_sdk/queries/utils.py @@ -40,12 +40,14 @@ def parse_ts_to_posix_ts(timestamp: Union[str, datetime]): dt = timestamp if isinstance(timestamp, datetime) else parse_str_to_dt(timestamp) return dt.timestamp() + def parse_ts_to_ms_ts(timestamp: Union[str, datetime]): """ Parse epoch ms timestamp from DATE/DATETIME str or datetime obj. """ return parse_ts_to_posix_ts(timestamp) * 1000 + def parse_str_to_dt(timestamp: str): try: dt = parser.parse(timestamp) diff --git a/src/_incydr_sdk/sessions/client.py b/src/_incydr_sdk/sessions/client.py index 3490dd7..80e4dd6 100644 --- a/src/_incydr_sdk/sessions/client.py +++ b/src/_incydr_sdk/sessions/client.py @@ -8,7 +8,6 @@ from _incydr_sdk.enums.sessions import ContentInspectionStatuses from _incydr_sdk.enums.sessions import SessionStates from _incydr_sdk.enums.sessions import SortKeys -from _incydr_sdk.queries.utils import parse_ts_to_posix_ts from _incydr_sdk.queries.utils import parse_ts_to_ms_ts from _incydr_sdk.sessions.models.models import SessionsChangeStateRequest from _incydr_sdk.sessions.models.models import SessionsCriteriaRequest