From 0f1ca4c937713d4137a3cdab8227a93f106f7aad Mon Sep 17 00:00:00 2001 From: yedidyacohenpalo Date: Thu, 14 Nov 2024 11:32:27 +0200 Subject: [PATCH 1/6] done --- .../JamfProtectEventCollector.py | 112 ++++++++++++++++-- .../JamfProtectEventCollector.yml | 7 ++ .../JamfProtectEventCollector_test.py | 16 +-- Packs/JamfProtect/ReleaseNotes/1_1_4.md | 6 + Packs/JamfProtect/pack_metadata.json | 2 +- 5 files changed, 124 insertions(+), 19 deletions(-) create mode 100644 Packs/JamfProtect/ReleaseNotes/1_1_4.md diff --git a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.py b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.py index 258d2a542fdf..0cb14b4f0dbb 100644 --- a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.py +++ b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.py @@ -236,7 +236,7 @@ def get_alerts(self, args: dict, next_page: str) -> dict: def get_computer(self, args: dict, next_page: str) -> dict: """ - Fetches computer from the Jamf Protect API. + Fetches computer from the Jamf Protect API, with date filter Args: args (dict): The arguments to be used in the GraphQL query. @@ -321,6 +321,87 @@ def get_computer(self, args: dict, next_page: str) -> dict: variables["next"] = next_page return self.graphql(query, variables) + def get_all_computers(self, args: dict, next_page: str) -> dict: + """ + Fetches a complete list of computers from the Jamf Protect API, without a date filter. + + Args: + args (dict): This argument is not used in this function, but is kept for compatibility + with similar client functions. + next_page (str): The next page token for pagination. + + Returns: + dict: The response from the API. + """ + query = """ + query listComputers($page_size: Int, $next: String ) { + listComputers( input: { + pageSize: $page_size next: $next + } + ) { + items { + serial + uuid + provisioningUDID + updated + checkin + connectionStatus + lastConnection + lastConnectionIp + lastDisconnection + lastDisconnectionReason + insightsUpdated + insightsStatsFail + insightsStatsPass + insightsStatsUnknown + version + signaturesVersion + installType + plan { + hash + id + name + logLevel + } + scorecard { + uuid + label + section + pass + tags + enabled + } + osMajor + osMinor + osPatch + osString + arch + certid + configHash + created + hostName + kernelVersion + memorySize + modelName + label + webProtectionActive + fullDiskAccess + tags + } + pageInfo { + next + total + } + } + } + """ + variables: dict[str, Any] = { + "page_size": COMPUTER_PAGE_SIZE + } + if next_page: + variables["next"] = next_page + return self.graphql(query, variables) + def get_audits(self, args: dict, next_page: str) -> dict: """ Fetches audit logs from the Jamf Protect API. @@ -382,7 +463,7 @@ def test_module(client: Client) -> str: Returns: str: Returns "ok" if the client is able to interact with the API successfully, raises an exception otherwise. """ - fetch_events(client, max_fetch_audits=1, max_fetch_alerts=1, max_fetch_computer=1) + fetch_events(client, max_fetch_audits=1, max_fetch_alerts=1, max_fetch_computer=1, fetch_all_computers=False) return "ok" @@ -451,7 +532,9 @@ def get_events_alert_type(client: Client, start_date: str, max_fetch: int, last_ return events, new_last_run_without_next_page -def get_events_computer_type(client: Client, start_date: str, max_fetch: int, last_run: dict) -> tuple[list[dict], dict]: +def get_events_computer_type( + client: Client, start_date: str, max_fetch: int, last_run: dict, fetch_all_computers: bool +) -> tuple[list[dict], dict]: """ Fetches computer type events from the Jamf Protect API within a specified date range. @@ -473,10 +556,14 @@ def get_events_computer_type(client: Client, start_date: str, max_fetch: int, la """ created, current_date = calculate_fetch_dates(start_date, last_run=last_run, last_run_key="computer") command_args = {"created": created} - client_event_type_func = client.get_computer next_page = last_run.get("computer", {}).get("next_page", "") + if fetch_all_computers and not last_run: + client_event_type_func = client.get_all_computers + demisto.debug("Fetching all computers") + else: + client_event_type_func = client.get_computer + demisto.debug(f"Fetching computers since {created}") - demisto.debug(f"Fetching computers since {created}") events, next_page = get_events(command_args, client_event_type_func, max_fetch, next_page) for event in events: event["source_log_type"] = "computers" @@ -606,8 +693,8 @@ def calculate_fetch_dates(start_date: str, last_run_key: str, last_run: dict, en return start_date, end_date -def fetch_events(client: Client, max_fetch_alerts: int, max_fetch_audits: int, max_fetch_computer: int, start_date_arg: str = "", - end_date_arg: str = "") -> EventResult: +def fetch_events(client: Client, max_fetch_alerts: int, max_fetch_audits: int, max_fetch_computer: int, fetch_all_computers: bool, + start_date_arg: str = "", end_date_arg: str = "") -> EventResult: """ Fetches events from the Jamf Protect API within a specified date range. @@ -639,7 +726,9 @@ def fetch_events(client: Client, max_fetch_alerts: int, max_fetch_audits: int, m audit_events, audit_next_run = get_events_audit_type(client, start_date_arg, end_date_arg, max_fetch_audits, last_run) if no_next_pages or computer_next_page: # The only case we don't trigger the computer event type cycle is when have only the alert and audit next page token. - computer_events, computer_next_run = get_events_computer_type(client, start_date_arg, max_fetch_computer, last_run) + computer_events, computer_next_run = get_events_computer_type( + client, start_date_arg, max_fetch_computer, last_run, fetch_all_computers + ) next_run: dict[str, Any] = {"alert": alert_next_run, "audit": audit_next_run, 'computer': computer_next_run} if "next_page" in (alert_next_run | audit_next_run | computer_next_run): # Will instantly re-trigger the fetch command. @@ -708,7 +797,8 @@ def get_events_command( max_fetch_audits=limit, max_fetch_computer=limit, start_date_arg=start_date, - end_date_arg=end_date + end_date_arg=end_date, + fetch_all_computers=False ) events_with_time = {event_type: add_time_field(events[:limit]) for event_type, events in event_result.as_dict().items() if events} @@ -762,6 +852,7 @@ def main() -> None: # pragma: no cover max_fetch_audits = arg_to_number(params.get('max_fetch_audits')) or DEFAULT_MAX_FETCH_AUDIT max_fetch_alerts = arg_to_number(params.get('max_fetch_alerts')) or DEFAULT_MAX_FETCH_ALERT max_fetch_computer = arg_to_number(params.get('max_fetch_computer')) or DEFAULT_MAX_FETCH_COMPUTER + fetch_all_computers = argToBoolean(params.get('fetch_all_computers')) or False demisto.debug(f'Command being called is {command}') @@ -785,7 +876,8 @@ def main() -> None: # pragma: no cover alert_events, audit_events, computer_events, new_last_run = fetch_events(client=client, max_fetch_alerts=max_fetch_alerts, max_fetch_audits=max_fetch_audits, - max_fetch_computer=max_fetch_computer + max_fetch_computer=max_fetch_computer, + fetch_all_computers=fetch_all_computers ) events = alert_events + audit_events + computer_events if events: diff --git a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.yml b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.yml index fb894f9f5146..75770eab577f 100644 --- a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.yml +++ b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.yml @@ -56,6 +56,13 @@ configuration: type: 0 advanced: true section: Collect +- display: Fetch all computers + name: fetch_all_computers + defaultvalue: "false" + type: 8 + required: false + advanced: true + section: Collect description: Use this integration to fetch audit logs, alerts and computer events from Jamf Protect as events in Cortex XSIAM. display: Jamf Protect Event Collector name: Jamf Protect Event Collector diff --git a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector_test.py b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector_test.py index 10331502697d..c1f5c7158ab8 100644 --- a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector_test.py +++ b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector_test.py @@ -151,22 +151,22 @@ def test_nextTrigger( client = Client(base_url=MOCK_BASEURL, verify=False, proxy=False, client_id=MOCK_CLIENT_ID, client_password=MOCK_CLIENT_PASSWORD) - _, _, _, next_run = fetch_events(client, 1, 1, 1) + _, _, _, next_run = fetch_events(client, 1, 1, 1, True) if with_alert_next_page: assert next_run.get("nextTrigger") == "0" - assert next_run.get("alert").get("next_page") == "example_next_page" + assert next_run.get("alert", {}).get("next_page") == "example_next_page" if not with_alert_next_page: - assert not next_run.get("alert").get("next_page") + assert not next_run.get("alert", {}).get("next_page") if with_audit_next_page: assert next_run.get("nextTrigger") == "0" - assert next_run.get("audit").get("next_page") == "example_next_page" + assert next_run.get("audit", {}).get("next_page") == "example_next_page" if not with_audit_next_page: - assert not next_run.get("audit").get("next_page") + assert not next_run.get("audit", {}).get("next_page") if with_computer_next_page: assert next_run.get("nextTrigger") == "0" - assert next_run.get("computer").get("next_page") == "example_next_page" + assert next_run.get("computer", {}).get("next_page") == "example_next_page" if not with_computer_next_page: - assert not next_run.get("computer").get("next_page") + assert not next_run.get("computer", {}).get("next_page") def test_next_trigger(mocker): @@ -182,4 +182,4 @@ def test_next_trigger(mocker): client_password=MOCK_CLIENT_PASSWORD) mocker.patch('JamfProtectEventCollector.get_events_alert_type', return_value=([], {})) mocker.patch('JamfProtectEventCollector.get_events_audit_type', return_value=([], {})) - fetch_events(client, 1, 1, 1) + fetch_events(client, 1, 1, 1, False) diff --git a/Packs/JamfProtect/ReleaseNotes/1_1_4.md b/Packs/JamfProtect/ReleaseNotes/1_1_4.md new file mode 100644 index 000000000000..c8b27c7e02a6 --- /dev/null +++ b/Packs/JamfProtect/ReleaseNotes/1_1_4.md @@ -0,0 +1,6 @@ + +#### Integrations + +##### Jamf Protect Event Collector-dev + +- Added the fetch_all_computers parameter to enable fetching all computers without a date filter. \ No newline at end of file diff --git a/Packs/JamfProtect/pack_metadata.json b/Packs/JamfProtect/pack_metadata.json index 2cb6e7d03e92..3f40cd3431dc 100644 --- a/Packs/JamfProtect/pack_metadata.json +++ b/Packs/JamfProtect/pack_metadata.json @@ -2,7 +2,7 @@ "name": "JamfProtect", "description": "Apple Mobile and Mac endpoint protection", "support": "xsoar", - "currentVersion": "1.1.3", + "currentVersion": "1.1.4", "author": "Cortex XSOAR", "url": "https://www.paloaltonetworks.com/cortex", "email": "", From 1ed9c4c98afd20155c91b237d53761ea14bd3494 Mon Sep 17 00:00:00 2001 From: yedidyacohenpalo Date: Thu, 14 Nov 2024 12:13:55 +0200 Subject: [PATCH 2/6] rn name fixed --- .../JamfProtectEventCollector/JamfProtectEventCollector.py | 2 +- Packs/JamfProtect/ReleaseNotes/1_1_4.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.py b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.py index 0cb14b4f0dbb..e96a08571d40 100644 --- a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.py +++ b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.py @@ -236,7 +236,7 @@ def get_alerts(self, args: dict, next_page: str) -> dict: def get_computer(self, args: dict, next_page: str) -> dict: """ - Fetches computer from the Jamf Protect API, with date filter + Fetches computer from the Jamf Protect API, with date filter. Args: args (dict): The arguments to be used in the GraphQL query. diff --git a/Packs/JamfProtect/ReleaseNotes/1_1_4.md b/Packs/JamfProtect/ReleaseNotes/1_1_4.md index c8b27c7e02a6..e4f34462f573 100644 --- a/Packs/JamfProtect/ReleaseNotes/1_1_4.md +++ b/Packs/JamfProtect/ReleaseNotes/1_1_4.md @@ -1,6 +1,6 @@ #### Integrations -##### Jamf Protect Event Collector-dev +##### Jamf Protect Event Collector - Added the fetch_all_computers parameter to enable fetching all computers without a date filter. \ No newline at end of file From c019e0bf60ec5daba12ed175ee2ba50ae2ae66f6 Mon Sep 17 00:00:00 2001 From: yedidyacohenpalo Date: Sun, 17 Nov 2024 13:37:57 +0200 Subject: [PATCH 3/6] done --- .../JamfProtectEventCollector.py | 244 +++++++----------- .../JamfProtectEventCollector.yml | 3 +- .../JamfProtectEventCollector_test.py | 49 +++- .../JamfProtectEventCollector/README.md | 7 + Packs/JamfProtect/ReleaseNotes/1_1_4.md | 3 +- 5 files changed, 144 insertions(+), 162 deletions(-) diff --git a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.py b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.py index e96a08571d40..1fb5ebe9c362 100644 --- a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.py +++ b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.py @@ -234,172 +234,104 @@ def get_alerts(self, args: dict, next_page: str) -> dict: variables["next"] = next_page return self.graphql(query, variables) - def get_computer(self, args: dict, next_page: str) -> dict: + def get_computers(self, args: dict, next_page: str) -> dict: """ - Fetches computer from the Jamf Protect API, with date filter. + Fetches a list of computers from the Jamf Protect API, with an optional date filter. Args: - args (dict): The arguments to be used in the GraphQL query. - It should contain a key "created" with a value representing the creation date of the computer. - next_page (str): The next page token for pagination. + args (dict): A dictionary of arguments for the GraphQL query. + If using a date filter, this should include: + - "use_date_filter" (bool): If True, a creation date filter is applied. + - "created" (str): A date in 'YYYY-MM-DDTHH:MM:SSZ' format, representing the + minimum creation date for filtering the results. + next_page (str): The token for the next page of results, used for pagination. Returns: - dict: The response from the API. + dict: The API response containing a list of computers and pagination information. """ - query = """ - query listComputers($page_size: Int, $next: String $created:AWSDateTime) { - listComputers( input: { - filter: { - created: { - greaterThan: $created - } - } - pageSize: $page_size next: $next - } - ) { - items { - serial - uuid - provisioningUDID - updated - checkin - connectionStatus - lastConnection - lastConnectionIp - lastDisconnection - lastDisconnectionReason - insightsUpdated - insightsStatsFail - insightsStatsPass - insightsStatsUnknown - version - signaturesVersion - installType - plan { - hash - id - name - logLevel - } - scorecard { - uuid - label - section - pass - tags - enabled - } - osMajor - osMinor - osPatch - osString - arch - certid - configHash - created - hostName - kernelVersion - memorySize - modelName - label - webProtectionActive - fullDiskAccess - tags - } - pageInfo { - next - total + date_filter = "$created: AWSDateTime" if args.get('use_date_filter') else "" + filter_clause = """ + filter: { + created: { + greaterThan: $created } } - } - """ - variables = { - "created": args.get("created"), - "page_size": COMPUTER_PAGE_SIZE - } - if next_page: - variables["next"] = next_page - return self.graphql(query, variables) + """ if args.get('use_date_filter') else "" - def get_all_computers(self, args: dict, next_page: str) -> dict: + query = f""" + query listComputers($page_size: Int, $next: String {date_filter}) {{ + listComputers( input: {{ + {filter_clause} + pageSize: $page_size + next: $next + }}) {{ + items {{ + serial + uuid + provisioningUDID + updated + checkin + connectionStatus + lastConnection + lastConnectionIp + lastDisconnection + lastDisconnectionReason + insightsUpdated + insightsStatsFail + insightsStatsPass + insightsStatsUnknown + version + signaturesVersion + installType + plan {{ + hash + id + name + logLevel + }} + scorecard {{ + uuid + label + section + pass + tags + enabled + }} + osMajor + osMinor + osPatch + osString + arch + certid + configHash + created + hostName + kernelVersion + memorySize + modelName + label + webProtectionActive + fullDiskAccess + tags + }} + pageInfo {{ + next + total + }} + }} + }} """ - Fetches a complete list of computers from the Jamf Protect API, without a date filter. - Args: - args (dict): This argument is not used in this function, but is kept for compatibility - with similar client functions. - next_page (str): The next page token for pagination. - - Returns: - dict: The response from the API. - """ - query = """ - query listComputers($page_size: Int, $next: String ) { - listComputers( input: { - pageSize: $page_size next: $next - } - ) { - items { - serial - uuid - provisioningUDID - updated - checkin - connectionStatus - lastConnection - lastConnectionIp - lastDisconnection - lastDisconnectionReason - insightsUpdated - insightsStatsFail - insightsStatsPass - insightsStatsUnknown - version - signaturesVersion - installType - plan { - hash - id - name - logLevel - } - scorecard { - uuid - label - section - pass - tags - enabled - } - osMajor - osMinor - osPatch - osString - arch - certid - configHash - created - hostName - kernelVersion - memorySize - modelName - label - webProtectionActive - fullDiskAccess - tags - } - pageInfo { - next - total - } - } - } - """ variables: dict[str, Any] = { "page_size": COMPUTER_PAGE_SIZE } + + if args.get('use_date_filter'): + variables["created"] = args.get("created") + if next_page: variables["next"] = next_page + return self.graphql(query, variables) def get_audits(self, args: dict, next_page: str) -> dict: @@ -555,15 +487,13 @@ def get_events_computer_type( the end date of the fetched events and a continuance token if the fetched reached the max limit. """ created, current_date = calculate_fetch_dates(start_date, last_run=last_run, last_run_key="computer") - command_args = {"created": created} + command_args = {"created": created, 'use_date_filter': bool(last_run or not fetch_all_computers)} next_page = last_run.get("computer", {}).get("next_page", "") - if fetch_all_computers and not last_run: - client_event_type_func = client.get_all_computers - demisto.debug("Fetching all computers") - else: - client_event_type_func = client.get_computer - demisto.debug(f"Fetching computers since {created}") + debug_message = "Fetching all computers" if fetch_all_computers and not last_run else f"Fetching computers since {created}" + demisto.debug(debug_message) + + client_event_type_func = client.get_computers events, next_page = get_events(command_args, client_event_type_func, max_fetch, next_page) for event in events: event["source_log_type"] = "computers" diff --git a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.yml b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.yml index 75770eab577f..43f4e8828ed0 100644 --- a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.yml +++ b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.yml @@ -63,6 +63,7 @@ configuration: required: false advanced: true section: Collect + additionalinfo: When set to true, retrieves all available computers during the initial fetch, ignoring the Events Fetch Interval and not limited to recent changes. description: Use this integration to fetch audit logs, alerts and computer events from Jamf Protect as events in Cortex XSIAM. display: Jamf Protect Event Collector name: Jamf Protect Event Collector @@ -91,7 +92,7 @@ script: type: python subtype: python3 isfetchevents: true - dockerimage: demisto/python3:3.11.9.105369 + dockerimage: demisto/python3:3.11.10.116439 marketplaces: - marketplacev2 fromversion: 6.9.0 diff --git a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector_test.py b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector_test.py index c1f5c7158ab8..c2a00f51ef37 100644 --- a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector_test.py +++ b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector_test.py @@ -124,48 +124,56 @@ def test_calculate_fetch_dates_without_arguments(client): @pytest.mark.parametrize("with_alert_next_page", [True, False]) @pytest.mark.parametrize("with_audit_next_page", [True, False]) @pytest.mark.parametrize("with_computer_next_page", [True, False]) +@pytest.mark.parametrize("fetch_all_computers", [True, False]) def test_nextTrigger( with_alert_next_page: bool, with_audit_next_page: bool, with_computer_next_page: bool, + fetch_all_computers: bool, mocker: MockerFixture ): """ Given: A mock JamfProtect client. - When: Running fetch_events with different next pages for alerts, audits and computers. + When: Running fetch_events with different next pages for alerts, audits, and computers, + and different values of fetch_all_computers. Then: Ensure the nextTrigger is set to 0 when there are no next pages, and the next page is set when there are next pages. """ from JamfProtectEventCollector import fetch_events, Client mocked_alerts = util_load_json('test_data/raw_alerts.json') mocked_audits = util_load_json('test_data/raw_audits.json') mocked_computers = util_load_json('test_data/raw_computers.json') + if with_alert_next_page: mocked_alerts["data"]["listAlerts"]["pageInfo"]["next"] = "example_next_page" if with_audit_next_page: mocked_audits["data"]["listAuditLogsByDate"]["pageInfo"]["next"] = "example_next_page" if with_computer_next_page: mocked_computers["data"]["listComputers"]["pageInfo"]["next"] = "example_next_page" + mocker.patch.object(Client, '_http_request', side_effect=[mocked_alerts, mocked_audits, mocked_computers]) mocker.patch.object(Client, '_login', return_value="ExampleToken") client = Client(base_url=MOCK_BASEURL, verify=False, proxy=False, client_id=MOCK_CLIENT_ID, client_password=MOCK_CLIENT_PASSWORD) - _, _, _, next_run = fetch_events(client, 1, 1, 1, True) + _, _, _, next_run = fetch_events(client, 1, 1, 1, fetch_all_computers) + if with_alert_next_page: assert next_run.get("nextTrigger") == "0" assert next_run.get("alert", {}).get("next_page") == "example_next_page" if not with_alert_next_page: assert not next_run.get("alert", {}).get("next_page") + if with_audit_next_page: assert next_run.get("nextTrigger") == "0" assert next_run.get("audit", {}).get("next_page") == "example_next_page" if not with_audit_next_page: assert not next_run.get("audit", {}).get("next_page") + if with_computer_next_page: assert next_run.get("nextTrigger") == "0" assert next_run.get("computer", {}).get("next_page") == "example_next_page" - if not with_computer_next_page: + else: assert not next_run.get("computer", {}).get("next_page") @@ -183,3 +191,38 @@ def test_next_trigger(mocker): mocker.patch('JamfProtectEventCollector.get_events_alert_type', return_value=([], {})) mocker.patch('JamfProtectEventCollector.get_events_audit_type', return_value=([], {})) fetch_events(client, 1, 1, 1, False) + + +@freeze_time(MOCK_TIME_UTC_NOW) +@pytest.mark.parametrize("fetch_all_computers", [True, False]) +def test_get_events_computer_type(mocker: MockerFixture, client, fetch_all_computers): + """ + Test get_events_computer_type function with fetch_all_computers True and False. + + Ensures the _http_request is called with the correct parameters. + """ + from JamfProtectEventCollector import get_events_computer_type + + events, new_last_run = get_events_computer_type( + client=client, + start_date='', + max_fetch=200, + last_run={}, + fetch_all_computers=fetch_all_computers, + ) + + assert client._http_request.call_count > 0 # Use the existing client fixture for assertion + assert len(events) > 0 + assert "last_fetch" in new_last_run + + # Extract the actual query sent in the HTTP request + called_args = client._http_request.call_args.kwargs + actual_query = called_args["json_data"]["query"] + actual_variables = called_args["json_data"]["variables"] + + # Assertions for query content + if fetch_all_computers: + assert "$created: AWSDateTime" not in actual_query + else: + assert "$created: AWSDateTime" in actual_query + assert "created" in actual_variables diff --git a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/README.md b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/README.md index 8eee106de7b3..dc1451eabf8b 100644 --- a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/README.md +++ b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/README.md @@ -16,6 +16,13 @@ Use this integration to fetch audit logs, alerts and computer events from Jamf P | Max alert events per fetch | Maximum number of alert events to fetch at a time. Default is 1000| False | | Max audit events per fetch | Maximum number of audit events to fetch at a time. Default is 20,000| False | | Max computer events per fetch | Maximum number of computer events to fetch at a time. Default is 1000| False | + | Fetch all computers | When set to true, retrieves all available computers during the initial fetch, ignoring the Events Fetch Interval and not limited to recent changes. | False | + + + + + + 4. Click **Test** to validate the URLs, token, and connection. diff --git a/Packs/JamfProtect/ReleaseNotes/1_1_4.md b/Packs/JamfProtect/ReleaseNotes/1_1_4.md index e4f34462f573..8d787b9af463 100644 --- a/Packs/JamfProtect/ReleaseNotes/1_1_4.md +++ b/Packs/JamfProtect/ReleaseNotes/1_1_4.md @@ -3,4 +3,5 @@ ##### Jamf Protect Event Collector -- Added the fetch_all_computers parameter to enable fetching all computers without a date filter. \ No newline at end of file +- Added a **fetch_all_computers** parameter to enable fetch all the computers during the first fetch. +- Updated the Docker image to: *demisto/python3:3.11.10.116439*. \ No newline at end of file From 8794c270dc4d99611254d4c12b24ca8fdcbdf6ad Mon Sep 17 00:00:00 2001 From: yedidyacohenpalo <162107504+yedidyacohenpalo@users.noreply.github.com> Date: Mon, 18 Nov 2024 10:38:53 +0200 Subject: [PATCH 4/6] Update Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.yml Co-authored-by: JudithB <132264628+jbabazadeh@users.noreply.github.com> --- .../JamfProtectEventCollector/JamfProtectEventCollector.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.yml b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.yml index 43f4e8828ed0..afdbc8826163 100644 --- a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.yml +++ b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/JamfProtectEventCollector.yml @@ -63,7 +63,7 @@ configuration: required: false advanced: true section: Collect - additionalinfo: When set to true, retrieves all available computers during the initial fetch, ignoring the Events Fetch Interval and not limited to recent changes. + additionalinfo: When set to true, retrieves all available computers during the initial fetch. description: Use this integration to fetch audit logs, alerts and computer events from Jamf Protect as events in Cortex XSIAM. display: Jamf Protect Event Collector name: Jamf Protect Event Collector From 742862d9bf166a26027d7972d405f9ca71f57d6d Mon Sep 17 00:00:00 2001 From: yedidyacohenpalo <162107504+yedidyacohenpalo@users.noreply.github.com> Date: Mon, 18 Nov 2024 10:39:04 +0200 Subject: [PATCH 5/6] Update Packs/JamfProtect/Integrations/JamfProtectEventCollector/README.md Co-authored-by: JudithB <132264628+jbabazadeh@users.noreply.github.com> --- .../Integrations/JamfProtectEventCollector/README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/README.md b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/README.md index dc1451eabf8b..b476d86f8c08 100644 --- a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/README.md +++ b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/README.md @@ -18,12 +18,6 @@ Use this integration to fetch audit logs, alerts and computer events from Jamf P | Max computer events per fetch | Maximum number of computer events to fetch at a time. Default is 1000| False | | Fetch all computers | When set to true, retrieves all available computers during the initial fetch, ignoring the Events Fetch Interval and not limited to recent changes. | False | - - - - - - 4. Click **Test** to validate the URLs, token, and connection. From 23e0881173ded19a39c0ca1137084ef81526c021 Mon Sep 17 00:00:00 2001 From: yedidyacohenpalo <162107504+yedidyacohenpalo@users.noreply.github.com> Date: Mon, 18 Nov 2024 10:39:18 +0200 Subject: [PATCH 6/6] Update Packs/JamfProtect/Integrations/JamfProtectEventCollector/README.md Co-authored-by: JudithB <132264628+jbabazadeh@users.noreply.github.com> --- .../Integrations/JamfProtectEventCollector/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/README.md b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/README.md index b476d86f8c08..e8065bd68d24 100644 --- a/Packs/JamfProtect/Integrations/JamfProtectEventCollector/README.md +++ b/Packs/JamfProtect/Integrations/JamfProtectEventCollector/README.md @@ -16,7 +16,7 @@ Use this integration to fetch audit logs, alerts and computer events from Jamf P | Max alert events per fetch | Maximum number of alert events to fetch at a time. Default is 1000| False | | Max audit events per fetch | Maximum number of audit events to fetch at a time. Default is 20,000| False | | Max computer events per fetch | Maximum number of computer events to fetch at a time. Default is 1000| False | - | Fetch all computers | When set to true, retrieves all available computers during the initial fetch, ignoring the Events Fetch Interval and not limited to recent changes. | False | + | Fetch all computers | When set to true, retrieves all available computers during the initial fetch. | False | 4. Click **Test** to validate the URLs, token, and connection.