diff --git a/Packs/SentinelOne/Integrations/SentinelOne-V2/SentinelOne-V2.py b/Packs/SentinelOne/Integrations/SentinelOne-V2/SentinelOne-V2.py index 457a65462b4a..5e2b61edd4e7 100644 --- a/Packs/SentinelOne/Integrations/SentinelOne-V2/SentinelOne-V2.py +++ b/Packs/SentinelOne/Integrations/SentinelOne-V2/SentinelOne-V2.py @@ -3448,13 +3448,13 @@ def list_installed_singu_mark_apps_command(client: Client, args: dict) -> Comman installed_applications = [] # Get arguments query_params = assign_params( - accountIds=args.get('account_ids'), + accountIds=argToList(args.get('account_ids')), applicationCatalogId=args.get('application_catalog_id'), creator__contains=args.get('creator_contains'), - id=args.get('id'), + id=argToList(args.get('id')), limit=1000, name__contains=args.get('name_contains'), - siteIds=args.get('site_ids') + siteIds=argToList(args.get('site_ids')) ) # Make request and get raw response @@ -3475,12 +3475,10 @@ def list_installed_singu_mark_apps_command(client: Client, args: dict) -> Comman all_scopes = [] if installed_applications: for each_app in installed_applications: - scopes = each_app.get("scopes") - if scopes is not None and len(scopes) > 0: - for scope in scopes: - scope["applicationCatalogId"] = each_app["applicationCatalogId"] - scope["applicationCatalogName"] = each_app["name"] - all_scopes.append(scope) + for scope in each_app.get("scopes", []): + scope["applicationCatalogId"] = each_app["applicationCatalogId"] + scope["applicationCatalogName"] = each_app["name"] + all_scopes.append(scope) meta = "Provides summary information and details for all the installed applications that matched specified filter values" else: meta = "The search filters provided are returning no results. Please review and adjust them accordingly." @@ -3531,11 +3529,11 @@ def get_service_users_command(client: Client, args: dict) -> CommandResults: service_users = [] # Get arguments query_params = assign_params( - accountIds=args.get('account_ids'), - roleIds=args.get('role_ids'), + accountIds=argToList(args.get('account_ids')), + roleIds=argToList(args.get('role_ids')), ids=args.get('ids'), limit=1000, - siteIds=args.get('site_ids') + siteIds=argToList(args.get('site_ids')) ) # Make request and get raw response service_users_page, pagination = client.get_service_users_request(query_params) diff --git a/Packs/SentinelOne/Integrations/SentinelOne-V2/SentinelOne-V2_test.py b/Packs/SentinelOne/Integrations/SentinelOne-V2/SentinelOne-V2_test.py index b2db1a72f854..d734a274e5fd 100644 --- a/Packs/SentinelOne/Integrations/SentinelOne-V2/SentinelOne-V2_test.py +++ b/Packs/SentinelOne/Integrations/SentinelOne-V2/SentinelOne-V2_test.py @@ -816,9 +816,15 @@ def test_list_installed_singularity_mark_apps(mocker, requests_mock): Then - returns a table of result had the list of installed singularity marketplace applications """ - json_output = util_load_json('test_data/get_singularity_marketplace_apps_response.json') + json_page_1 = util_load_json('test_data/get_singularity_marketplace_apps_page_1_response.json') + + json_page_2 = util_load_json('test_data/get_singularity_marketplace_apps_page_2_response.json') + requests_mock.get("https://usea1.sentinelone.net/web/api/v2.1/singularity-marketplace/applications", - json=json_output) + json=json_page_1) + requests_mock.get("https://usea1.sentinelone.net/web/api/v2.1/singularity-marketplace/applications?cursor=1234", + json=json_page_2) + mocker.patch.object(demisto, 'params', return_value={'token': 'token', 'url': 'https://usea1.sentinelone.net', 'api_version': '2.1', @@ -832,7 +838,53 @@ def test_list_installed_singularity_mark_apps(mocker, requests_mock): call = sentinelone_v2.return_results.call_args_list command_results = call[0].args[0] - assert command_results.outputs == [{'ID': '123456', 'Account': 'SentinelOne', 'AccountId': '1234567890', 'ApplicationCatalogId': '90909090909090', 'ApplicationCatalogName': 'SentinelOne Threat Intelligence IOC Ingestion', 'AlertMessage': '', 'CreatedAt': '2025-01-23T13:11:23.12758', 'Creator': 'admin@user.sentinelone.net', 'CreatorId': '212212121211212', 'DesiredStatus': 'active', 'HasAlert': False, 'LastEntityCreatedAt': '2025-01-23T13:11:23.127579', 'Modifier': 'admin@user.sentinelone.net', 'ModifierId': '212212121211212', 'ScopeId': '1230123012301230', 'ScopeLevel': 'account', 'Status': 'active', 'UpdatedAt': '2025-01-23T13:11:25.96604', 'ApplicationInstanceName': 'SentinelOne Threat Intelligence IOC Ingestion'}] # noqa + + expected_outputs = expected_outputs = [ + { + 'ID': '123456', + 'Account': 'SentinelOne', + 'AccountId': '1234567890', + 'ApplicationCatalogId': '90909090909090', + 'ApplicationCatalogName': 'SentinelOne Threat Intelligence IOC Ingestion', + 'AlertMessage': '', + 'CreatedAt': '2025-01-23T13:11:23.12758', + 'Creator': 'admin@user.sentinelone.net', + 'CreatorId': '212212121211212', + 'DesiredStatus': 'active', + 'HasAlert': False, + 'LastEntityCreatedAt': '2025-01-23T13:11:23.127579', + 'Modifier': 'admin@user.sentinelone.net', + 'ModifierId': '212212121211212', + 'ScopeId': '1230123012301230', + 'ScopeLevel': 'account', + 'Status': 'active', + 'UpdatedAt': '2025-01-23T13:11:25.96604', + 'ApplicationInstanceName': 'SentinelOne Threat Intelligence IOC Ingestion' + }, + { + 'ID': '123457', + 'Account': 'SentinelOne', + 'AccountId': '1234567890', + 'ApplicationCatalogId': '90909090909090', + 'ApplicationCatalogName': 'SentinelOne Threat Intelligence IOC Ingestion', + 'AlertMessage': '', + 'CreatedAt': '2025-01-23T13:11:23.12758', + 'Creator': 'admin@user.sentinelone.net', + 'CreatorId': '212212121211212', + 'DesiredStatus': 'active', + 'HasAlert': False, + 'LastEntityCreatedAt': '2025-01-23T13:11:23.127579', + 'Modifier': 'admin@user.sentinelone.net', + 'ModifierId': '212212121211212', + 'ScopeId': '1230123012301230', + 'ScopeLevel': 'account', + 'Status': 'active', + 'UpdatedAt': '2025-01-23T13:11:25.96604', + 'ApplicationInstanceName': 'SentinelOne Threat Intelligence IOC Ingestion' + } + ] + assert command_results.outputs == expected_outputs + assert requests_mock.call_count == 2, f"Expected 2 API calls, but got {requests_mock.call_count}" def test_get_service_users(mocker, requests_mock): @@ -844,9 +896,12 @@ def test_get_service_users(mocker, requests_mock): Then - returns a table of result had the list of service users """ - json_output = util_load_json('test_data/get_service_users_response.json') + json_page_1 = util_load_json('test_data/get_service_users_page_1_response.json') + json_page_2 = util_load_json('test_data/get_service_users_page_2_response.json') requests_mock.get("https://usea1.sentinelone.net/web/api/v2.1/service-users", - json=json_output) + json=json_page_1) + requests_mock.get("https://usea1.sentinelone.net/web/api/v2.1/service-users?cursor=1234", + json=json_page_2) mocker.patch.object(demisto, 'params', return_value={'token': 'token', 'url': 'https://usea1.sentinelone.net', 'api_version': '2.1', @@ -860,7 +915,49 @@ def test_get_service_users(mocker, requests_mock): call = sentinelone_v2.return_results.call_args_list command_results = call[0].args[0] - assert command_results.outputs == [{'ID': '123456', 'ApiTokenCreatedAt': '2025-01-30T10:12:09.458490Z', 'ApiTokenExpiresAt': '2025-03-01T10:12:08Z', 'CreatedAt': '2025-01-30T10:12:09.407923Z', 'CreatedById': '123456789099', 'CreatedByName': 'sentinelone', 'Description': None, 'LastActivation': '2025-02-04T10:00:07.637184Z', 'Name': 'Service user for SentinelOne Alert Ingestion app for 0101010101010 site id', 'Scope': 'site', 'UpdatedAt': '2025-01-30T10:12:09.405748Z', 'UpdatedById': '2323232323232323', 'UpdatedByName': 'sentinelone', 'ScopeRolesRoleId': '999999999', 'ScopeRolesRoleName': 'Admin', 'ScopeRolesAccountName': 'SentinelOne', 'ScopeRolesId': '0101010101010'}] # noqa + expected_outputs = [ + { + 'ID': '123456', + 'ApiTokenCreatedAt': '2025-01-30T10:12:09.458490Z', + 'ApiTokenExpiresAt': '2025-03-01T10:12:08Z', + 'CreatedAt': '2025-01-30T10:12:09.407923Z', + 'CreatedById': '123456789099', + 'CreatedByName': 'sentinelone', + 'Description': None, + 'LastActivation': '2025-02-04T10:00:07.637184Z', + 'Name': 'Service user for SentinelOne Alert Ingestion app for 0101010101010 site id', + 'Scope': 'site', + 'UpdatedAt': '2025-01-30T10:12:09.405748Z', + 'UpdatedById': '2323232323232323', + 'UpdatedByName': 'sentinelone', + 'ScopeRolesRoleId': '999999999', + 'ScopeRolesRoleName': 'Admin', + 'ScopeRolesAccountName': 'SentinelOne', + 'ScopeRolesId': '0101010101010' + }, + { + 'ID': '123457', + 'ApiTokenCreatedAt': '2025-01-30T10:12:09.458490Z', + 'ApiTokenExpiresAt': '2025-03-01T10:12:08Z', + 'CreatedAt': '2025-01-30T10:12:09.407923Z', + 'CreatedById': '123456789099', + 'CreatedByName': 'sentinelone', + 'Description': None, + 'LastActivation': '2025-02-04T10:00:07.637184Z', + 'Name': 'Service user for SentinelOne Alert Ingestion app for 0101010101010 site id', + 'Scope': 'site', + 'UpdatedAt': '2025-01-30T10:12:09.405748Z', + 'UpdatedById': '2323232323232323', + 'UpdatedByName': 'sentinelone', + 'ScopeRolesRoleId': '999999999', + 'ScopeRolesRoleName': 'Admin', + 'ScopeRolesAccountName': 'SentinelOne', + 'ScopeRolesId': '0101010101010' + } + ] + + assert command_results.outputs == expected_outputs + assert requests_mock.call_count == 2, f"Expected 2 API calls, but got {requests_mock.call_count}" def test_get_modified_remote_data_command(mocker, requests_mock): diff --git a/Packs/SentinelOne/Integrations/SentinelOne-V2/test_data/get_service_users_page_1_response.json b/Packs/SentinelOne/Integrations/SentinelOne-V2/test_data/get_service_users_page_1_response.json new file mode 100644 index 000000000000..8e37b75becdb --- /dev/null +++ b/Packs/SentinelOne/Integrations/SentinelOne-V2/test_data/get_service_users_page_1_response.json @@ -0,0 +1,41 @@ +{ + "data": [ + { + "apiToken": { + "createdAt": "2025-01-30T10:12:09.458490Z", + "expiresAt": "2025-03-01T10:12:08Z" + }, + "createdAt": "2025-01-30T10:12:09.407923Z", + "createdBy": { + "id": "123456789099", + "name": "sentinelone" + }, + "description": null, + "id": "123456", + "lastActivation": "2025-02-04T10:00:07.637184Z", + "name": "Service user for SentinelOne Alert Ingestion app for 0101010101010 site id", + "scope": "site", + "scopeRoles": [ + { + "accountName": "SentinelOne", + "id": "0101010101010", + "name": "Default site", + "roleId": "999999999", + "roleName": "Admin", + "roles": [ + "Admin" + ] + } + ], + "updatedAt": "2025-01-30T10:12:09.405748Z", + "updatedBy": { + "id": "2323232323232323", + "name": "sentinelone" + } + } + ], + "pagination": { + "nextCursor": "1234", + "totalItems": 1 + } +} \ No newline at end of file diff --git a/Packs/SentinelOne/Integrations/SentinelOne-V2/test_data/get_service_users_page_2_response.json b/Packs/SentinelOne/Integrations/SentinelOne-V2/test_data/get_service_users_page_2_response.json new file mode 100644 index 000000000000..2d8a4b1487f7 --- /dev/null +++ b/Packs/SentinelOne/Integrations/SentinelOne-V2/test_data/get_service_users_page_2_response.json @@ -0,0 +1,41 @@ +{ + "data": [ + { + "apiToken": { + "createdAt": "2025-01-30T10:12:09.458490Z", + "expiresAt": "2025-03-01T10:12:08Z" + }, + "createdAt": "2025-01-30T10:12:09.407923Z", + "createdBy": { + "id": "123456789099", + "name": "sentinelone" + }, + "description": null, + "id": "123457", + "lastActivation": "2025-02-04T10:00:07.637184Z", + "name": "Service user for SentinelOne Alert Ingestion app for 0101010101010 site id", + "scope": "site", + "scopeRoles": [ + { + "accountName": "SentinelOne", + "id": "0101010101010", + "name": "Default site", + "roleId": "999999999", + "roleName": "Admin", + "roles": [ + "Admin" + ] + } + ], + "updatedAt": "2025-01-30T10:12:09.405748Z", + "updatedBy": { + "id": "2323232323232323", + "name": "sentinelone" + } + } + ], + "pagination": { + "nextCursor": "", + "totalItems": 1 + } +} \ No newline at end of file diff --git a/Packs/SentinelOne/Integrations/SentinelOne-V2/test_data/get_singularity_marketplace_apps_response.json b/Packs/SentinelOne/Integrations/SentinelOne-V2/test_data/get_singularity_marketplace_apps_page_1_response.json similarity index 97% rename from Packs/SentinelOne/Integrations/SentinelOne-V2/test_data/get_singularity_marketplace_apps_response.json rename to Packs/SentinelOne/Integrations/SentinelOne-V2/test_data/get_singularity_marketplace_apps_page_1_response.json index 97723f840d90..30756c09f082 100644 --- a/Packs/SentinelOne/Integrations/SentinelOne-V2/test_data/get_singularity_marketplace_apps_response.json +++ b/Packs/SentinelOne/Integrations/SentinelOne-V2/test_data/get_singularity_marketplace_apps_page_1_response.json @@ -31,7 +31,7 @@ } ], "pagination": { - "nextCursor": "", + "nextCursor": "1234", "totalItems": 1 } } \ No newline at end of file diff --git a/Packs/SentinelOne/Integrations/SentinelOne-V2/test_data/get_singularity_marketplace_apps_page_2_response.json b/Packs/SentinelOne/Integrations/SentinelOne-V2/test_data/get_singularity_marketplace_apps_page_2_response.json new file mode 100644 index 000000000000..7659508823c3 --- /dev/null +++ b/Packs/SentinelOne/Integrations/SentinelOne-V2/test_data/get_singularity_marketplace_apps_page_2_response.json @@ -0,0 +1,37 @@ +{ + "data": [ + { + "applicationCatalogId": "90909090909090", + "hasAlert": false, + "icon": "data:image/png;base64,iVBORw0KGgoAAAAN", + "lastInstalledAt": "2025-01-23T13:11:23.12758", + "name": "SentinelOne Threat Intelligence IOC Ingestion", + "applicationCatalogIsHidden": true, + "scopes": [ + { + "account": "SentinelOne", + "accountId": "1234567890", + "alertMessage": "", + "createdAt": "2025-01-23T13:11:23.12758", + "creator": "admin@user.sentinelone.net", + "creatorId": "212212121211212", + "desiredStatus": "active", + "hasAlert": false, + "id": "123457", + "lastEntityCreatedAt": "2025-01-23T13:11:23.127579", + "modifier": "admin@user.sentinelone.net", + "modifierId": "212212121211212", + "scopeId": "1230123012301230", + "scopeLevel": "account", + "status": "active", + "updatedAt": "2025-01-23T13:11:25.96604", + "applicationInstanceName": "SentinelOne Threat Intelligence IOC Ingestion" + } + ] + } + ], + "pagination": { + "nextCursor": "", + "totalItems": 1 + } +} \ No newline at end of file