ProofpointIsolationEventCollector
Proofpoint Isolation is an integration that supports fetching Browser and Email Isolation logs events.
Analytics & SIEM · Proofpoint Isolation
Details
| ID | ProofpointIsolationEventCollector |
|---|---|
| Provider | Thoma Bravo |
| Category | Analytics & SIEM |
| From Version | 6.10.0 |
| Docker Image | demisto/python3:3.12.13.10404775 |
| Supported Modules | XSIAM |
README
Proofpoint Isolation is an integration that supports fetching Browser and Email Isolation logs events within Cortex XSIAM.
This integration was integrated and tested with version V2 of ProofpointIsolation.
Configure Proofpoint Isolation in Cortex
| Parameter | Description | Required |
|---|---|---|
| Server URL | The endpoint URL. | True |
| API Key | The API Key to use for connection | True |
| Maximum number of events per fetch | Defines The maximum number of browser and email isolation events per fetch cycle. Default value: 50000. | True |
| Trust any certificate (not secure) | False | |
| Use system proxy settings | False |
How to Access Reporting API
- In Proofpoint Isolation, navigate to Product Settings > Reporting API. Proofpoint Isolation’s Reporting API tools and documentation display in the Console’s main viewing panel.
- Copy the reporting API key.

Commands
You can execute these commands from the CLI, as part of an automation, or in a playbook.
After you successfully execute a command, a DBot message appears in the War Room with the command details.
proofpoint-isolation-get-events
Retrieves a list of events from the Proofpoint Isolation instance.
Base Command
proofpoint-isolation-get-events
Input
| Argument Name | Description | Required |
|---|---|---|
| should_push_events | Set this argument to True in order to create events, otherwise it will only display them. Possible values are: true, false. Default is false. | Required |
| limit | Maximum number of events to return. Value range: 1-50000. | Required |
| start_date | From which date to fetch the events. | Required |
| end_date | Until which date to fetch the events. | Required |
Context Output
| Path | Type | Description |
|---|---|---|
| ProofpointIsolationEventCollector | List | The list of events. |
Command example
!proofpoint-isolation-get-events should_push_events=false limit=10 end_date=2025-01-12 start_date=2025-01-11T11:27:08
Configuration parameters
base_url— Server URL (required)credentials— (required)max_events_per_fetch— Maximum number of events per fetch (required)insecure— Trust any certificate (not secure)proxy— Use system proxy settings
Commands (1)
-
proofpoint-isolation-get-eventsRetrieves a list of events from the Proofpoint Isolation instance.
import json DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ" MOCK_BASEURL = "https://example.com" MOCK_API_KEY = "API_KEY" def create_client(): from ProofpointIsolationEventCollector import Client return Client(base_url=MOCK_BASEURL, verify=False, api_key=MOCK_API_KEY) def util_load_json(path): with open(path, encoding="utf-8") as f: return json.loads(f.read()) def test_get_and_reorganize_events(mocker): """ Given: A mock Proofpoint client with a set of raw events and a set of event IDs. When: Reorganizing events based on date and excluding the last event ID. Then: - Ensure the events are sorted in chronological order. - The number of reorganized events matches the expected count. - The last event is excluded because it is in ids set. """ from ProofpointIsolationEventCollector import get_and_reorganize_events, hash_user_name_and_url mocked_events = util_load_json("test_data/get_events_raw_response.json") mocker.patch("ProofpointIsolationEventCollector.Client.get_events", return_value=mocked_events) events = mocked_events["data"] client = create_client() hashed_id_last_event = hash_user_name_and_url(events[-1]) ids = {hashed_id_last_event} organized_events = get_and_reorganize_events(client, "2025-01-01T19:44:35Z", "2025-01-12", ids) assert all(organized_events[i]["date"] <= organized_events[i + 1]["date"] for i in range(len(organized_events) - 1)) assert len(organized_events) == len(events) - 1 organized_ids = {hash_user_name_and_url(event) for event in organized_events} assert hashed_id_last_event not in organized_ids assert organized_events[0]["date"] == "2025-01-01T19:44:35.000+0000" assert organized_events[-1]["date"] == "2025-01-09T19:44:35.000+0000" def test_remove_duplicate_events(): """ Given: A list of events sorted by date, with a specified start date and event IDs. When: Removing duplicate events for a given start date. Then: Ensure the number of events is reduced by the expected amount, and verify that no event with the same ID and start date remains after duplicates are removed. """ from ProofpointIsolationEventCollector import ( get_and_parse_date, hash_user_name_and_url, remove_duplicate_events, sort_events_by_date, ) mocked_events = util_load_json("test_data/get_events_raw_response.json") events = sort_events_by_date(mocked_events["data"]) start_date = "2025-01-01T19:44:35Z" ids = {hash_user_name_and_url(event) for event in events if get_and_parse_date(event) == start_date} remove_duplicate_events(start_date, ids, events) expected_event_count = len(mocked_events["data"]) - 5 assert len(events) == expected_event_count for event in events: assert hash_user_name_and_url(event) not in ids or get_and_parse_date(event) != start_date def test_get_and_parse_date(): """ Given: A valid event with a date in a specific format. When: Parsing the event's date using the `get_and_parse_date` function. Then: Ensure the date is correctly parsed and returned in the expected format. """ from ProofpointIsolationEventCollector import get_and_parse_date valid_event = { "date": "2025-01-01T19:44:35.000+0000", "userName": "user@example.com", } parsed_date = get_and_parse_date(valid_event) assert parsed_date == "2025-01-01T19:44:35Z" def test_hash_user_name_and_url(): """ Given: A dictionary containing event data with 'url' and 'userName' fields. When: The function hash_user_name_and_url is called. Then: Ensure the output matches the expected '<url>&<userName>' format. """ from ProofpointIsolationEventCollector import hash_user_name_and_url event = {"url": "example.com", "userName": "testUser", "extraField": "extraValue"} result = hash_user_name_and_url(event) assert result == "example.com&testUser" def test_sort_events_by_date(): """ Given: A list of events, each containing a 'date' field in ISO 8601 format. When: The function is called to sort the events by their 'date' field. Then: Ensure the events are sorted in ascending order by date. """ from ProofpointIsolationEventCollector import sort_events_by_date events = [ {"date": "2025-01-14T12:00:00.000+0000", "event_id": 1}, {"date": "2025-01-13T12:00:00.000+0000", "event_id": 2}, {"date": "2025-01-15T12:00:00.000+0000", "event_id": 3}, ] sorted_events = sort_events_by_date(events) assert sorted_events[0]["event_id"] == 2 assert sorted_events[1]["event_id"] == 1 assert sorted_events[2]["event_id"] == 3 events = [] sorted_events = sort_events_by_date(events) assert sorted_events == [] def test_no_more_events_after_second_call(mocker): """ Given: A mock Proofpoint client with event data and a last run timestamp. When: Fetching events with a specified limit across multiple calls. Then: Ensure the correct number of events are fetched on the first call, and no events are returned on the second call when there are no more events to fetch. """ from ProofpointIsolationEventCollector import fetch_events client = create_client() mocked_events = util_load_json("test_data/get_events_raw_response.json") last_event = {"data": [mocked_events.get("data")[-2]]} mocker.patch("ProofpointIsolationEventCollector.Client.get_events", side_effect=[mocked_events, last_event, {"data": []}]) last_run_mock = {"start_date": "2025-01-09T11:27:08"} mocker.patch("ProofpointIsolationEventCollector.demisto.getLastRun", return_value=last_run_mock) limit = 10 events, new_last_run = fetch_events(client, limit) assert len(events) == limit assert new_last_run["ids"] mocker.patch("ProofpointIsolationEventCollector.demisto.getLastRun", return_value=new_last_run) events, new_last_run = fetch_events(client, limit) assert len(events) == 1 def test_fetch_events(mocker): """ Given: A mock Proofpoint client with event data and no previous run data. When: Fetching events multiple times with a specified limit. Then: Ensure correct number of events are fetched, and `lastRun` updates correctly with unique event IDs. Also ensure the first fetch initializes `lastRun` properly. """ from ProofpointIsolationEventCollector import fetch_events client = create_client() mocked_events = util_load_json("test_data/get_events_raw_response.json") return_values_events = [mocked_events, {"data": mocked_events.get("data")[4:]}] mocker.patch("ProofpointIsolationEventCollector.Client.get_events", side_effect=return_values_events) mocker.patch("ProofpointIsolationEventCollector.demisto.getLastRun", return_value={}) limit = 5 events, new_last_run = fetch_events(client, limit) assert len(events) == limit assert "ids" in new_last_run assert "https://exmaple.k1.com/&user9@example.com" in new_last_run["ids"] assert "https://exmaple.k1.com/&user10@example.com" in new_last_run["ids"] assert "https://exmaple.k1.com/&user7@example.com" in new_last_run["ids"] assert "https://exmaple.k10.com/&user0@example.com" in new_last_run["ids"] assert "https://exmaple.k1.com/&user8@example.com" in new_last_run["ids"] assert new_last_run.get("start_date") == "2025-01-01T19:44:35Z" mocker.patch("ProofpointIsolationEventCollector.demisto.getLastRun", return_value=new_last_run) events, new_last_run = fetch_events(client, limit) assert len(events) == limit assert "ids" in new_last_run assert len(new_last_run.get("ids")) == 1 assert new_last_run.get("start_date") == "2025-01-06T19:44:35Z" def test_fetch_events_ids_reset_when_no_more_events(mocker): """ Given: A mock Proofpoint client where the first API call returns events and the second returns none, and a last_run containing stale IDs from a previous fetch cycle. When: Fetching events with a limit higher than the available event count (so the loop exhausts all events). Then: Ensure the returned last_run has an empty 'ids' list, confirming stale dedup IDs are cleared when the pagination loop ends with no more events. Also ensure start_date advances to the end date so the next fetch cycle starts from the correct point. """ from ProofpointIsolationEventCollector import fetch_events client = create_client() mocked_events = util_load_json("test_data/get_events_raw_response.json") end_date = "2025-02-01T00:00:00Z" # First call returns events, second call returns empty — simulating end of pagination. mocker.patch( "ProofpointIsolationEventCollector.Client.get_events", side_effect=[mocked_events, {"data": []}], ) stale_ids = ["https://stale.url/&staleUser@example.com"] last_run_mock = {"start_date": "2025-01-01T19:44:35Z", "ids": stale_ids} mocker.patch("ProofpointIsolationEventCollector.demisto.getLastRun", return_value=last_run_mock) mocker.patch( "ProofpointIsolationEventCollector.get_current_time", return_value=__import__("datetime").datetime.strptime(end_date, DATE_FORMAT), ) # Set limit higher than available events so the loop exhausts and hits the empty-response branch. limit = 100 events, new_last_run = fetch_events(client, limit) assert len(events) == len(mocked_events["data"]) # The critical assertion: when no more events are found, ids must be reset to an empty list. assert new_last_run["ids"] == [] # Verify the cursor advanced to the end date so the next cycle doesn't re-fetch old events. assert new_last_run["start_date"] == end_date def test_fetch_events_stops_at_limit(mocker): """ Given: A mock Proofpoint client that returns more events than the fetch limit allows. When: Fetching events with a limit smaller than the total available events. Then: - The loop exits via the limit branch (not the empty-response branch). - Exactly fetch_limit events are returned. - new_last_run is set so the next fetch cycle can continue from where it stopped. """ from ProofpointIsolationEventCollector import fetch_events client = create_client() mocked_events = util_load_json("test_data/get_events_raw_response.json") total_available = len(mocked_events["data"]) # 13 events # The API keeps returning the same batch — the loop must stop at the limit, not keep going. mocker.patch( "ProofpointIsolationEventCollector.Client.get_events", return_value=mocked_events, ) mocker.patch("ProofpointIsolationEventCollector.demisto.getLastRun", return_value={}) mocker.patch( "ProofpointIsolationEventCollector.get_current_time", return_value=__import__("datetime").datetime(2025, 2, 1, 0, 0, 0), ) limit = 3 assert limit < total_available, "Test requires limit < total events to verify the limit branch" events, new_last_run = fetch_events(client, limit) # Exactly fetch_limit events should be returned. assert len(events) == limit # new_last_run must have a start_date so the next cycle continues from the correct point. assert new_last_run["start_date"] # new_last_run must have ids so the next cycle can deduplicate. assert new_last_run["ids"] # The start_date should NOT be the end date — it should be the date of the last processed event. assert new_last_run["start_date"] != "2025-02-01T00:00:00Z"