From 1bc810c1f3d1a825252ec59acdd1400cc6d0b261 Mon Sep 17 00:00:00 2001 From: content-bot <55035720+content-bot@users.noreply.github.com> Date: Tue, 31 Dec 2024 10:55:28 +0200 Subject: [PATCH] update: octoxlabs integration (#37676) (#37877) * initial: scroll * add: new commands * add: tests and fix docs and typo func names * fix: version number * fix: pre-commit problems * add: new tests for coverage * fix: yml file descriptions * fix: yml file descriptions-2 --------- Co-authored-by: ogulcanhero <99717065+ogulcanhero@users.noreply.github.com> Co-authored-by: ahmet kotan <6793206+ahmetkotan@users.noreply.github.com> --- Packs/OctoxLabs/.pack-ignore | 5 +- .../Integrations/OctoxLabs/OctoxLabs.py | 228 +++++++++++++++-- .../Integrations/OctoxLabs/OctoxLabs.yml | 228 ++++++++++++++++- .../Integrations/OctoxLabs/OctoxLabs_test.py | 179 ++++++++++++- .../Integrations/OctoxLabs/README.md | 235 +++++++++++++++++- .../Integrations/OctoxLabs/command_examples | 15 +- .../test_data/get_application_detail.json | 13 + .../OctoxLabs/test_data/get_applications.json | 35 +++ .../OctoxLabs/test_data/get_avm.json | 25 ++ .../test_data/get_device_detail.json | 15 ++ .../OctoxLabs/test_data/get_devices.json | 28 +++ .../test_data/get_user_inv_detail.json | 7 + .../OctoxLabs/test_data/get_users_inv.json | 16 ++ Packs/OctoxLabs/ReleaseNotes/2_1_0.md | 19 ++ Packs/OctoxLabs/pack_metadata.json | 2 +- 15 files changed, 1017 insertions(+), 33 deletions(-) create mode 100644 Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_application_detail.json create mode 100644 Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_applications.json create mode 100644 Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_avm.json create mode 100644 Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_device_detail.json create mode 100644 Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_devices.json create mode 100644 Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_user_inv_detail.json create mode 100644 Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_users_inv.json create mode 100644 Packs/OctoxLabs/ReleaseNotes/2_1_0.md diff --git a/Packs/OctoxLabs/.pack-ignore b/Packs/OctoxLabs/.pack-ignore index 9e9f85aab1ad..9722b4b9fdfe 100644 --- a/Packs/OctoxLabs/.pack-ignore +++ b/Packs/OctoxLabs/.pack-ignore @@ -5,4 +5,7 @@ Dict ldap URLs DBot -Boolean \ No newline at end of file +Boolean +HTTPS +AVM +SSL \ No newline at end of file diff --git a/Packs/OctoxLabs/Integrations/OctoxLabs/OctoxLabs.py b/Packs/OctoxLabs/Integrations/OctoxLabs/OctoxLabs.py index df459c9d3065..77552c86e96a 100644 --- a/Packs/OctoxLabs/Integrations/OctoxLabs/OctoxLabs.py +++ b/Packs/OctoxLabs/Integrations/OctoxLabs/OctoxLabs.py @@ -4,7 +4,10 @@ from octoxlabs import OctoxLabs import urllib3 -from typing import Any, Dict, List, Callable, Optional +from typing import Any +from collections.abc import Callable + +# from Packs.Base.Scripts.CommonServerPython.CommonServerPython import CommandResults # Disable insecure warnings urllib3.disable_warnings() # pylint: disable=no-member @@ -14,21 +17,26 @@ """ HELPER FUNCTIONS """ -def convert_to_json(obj: object, keys: List[str]) -> Dict[str, Any]: +def convert_to_json(obj: object, keys: list[str]) -> dict[str, Any]: return {k: getattr(obj, k, None) for k in keys} def run_command( - octox: OctoxLabs, command_name: str, args: Dict[str, Any] + octox: OctoxLabs, command_name: str, args: dict[str, Any] ) -> CommandResults: - commands: Dict[str, Callable] = { + commands: dict[str, Callable] = { "test-module": test_module, "octoxlabs-get-adapters": get_adapters, "octoxlabs-get-connections": get_connections, "octoxlabs-get-discoveries": get_discoveries, "octoxlabs-get-last-discovery": get_last_discovery, "octoxlabs-search-devices": search_devices, + "octoxlabs-search-users-inventory": search_users_inventory, + "octoxlabs-search-applications": search_applications, + "octoxlabs-search-avm": search_avm, "octoxlabs-get-device": get_device, + "octoxlabs-get-user-inventory-detail": get_user_inventory_detail, + "octoxlabs-get-application-detail": get_application_detail, "octoxlabs-get-queries": get_queries, "octoxlabs-get-query-by-id": get_query_by_id, "octoxlabs-get-query-by-name": get_query_by_name, @@ -43,8 +51,12 @@ def run_command( "octoxlabs-get-user-by-username": get_user_by_username, "octoxlabs-get-groups": get_groups, "octoxlabs-get-permissions": get_permissions, + "octoxlabs-search-scroll-devices": search_scroll_devices, + "octoxlabs-search-scroll-users": search_scroll_users, + "octoxlabs-search-scroll-applications": search_scroll_applications, + "octoxlabs-search-scroll-avm": search_scroll_avm, } - command_function: Optional[Callable] = commands.get(command_name, None) + command_function: Callable | None = commands.get(command_name, None) if command_function: return command_function(octox=octox, args=args) raise Exception("No command.") @@ -97,7 +109,7 @@ def get_adapters(octox: OctoxLabs, *_, **__) -> CommandResults: ) -def get_connections(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: +def get_connections(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: page = args.get("page", 1) count, connections = octox.get_connections(page=page) @@ -124,7 +136,7 @@ def get_connections(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: ) -def get_discoveries(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: +def get_discoveries(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: page = args.get("page", 1) count, discoveries = octox.get_discoveries(page=page) @@ -161,7 +173,7 @@ def get_last_discovery(octox: OctoxLabs, *_, **__) -> CommandResults: ) -def search_devices(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: +def search_devices(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: fields = args.get("fields", None) if isinstance(fields, str): fields = [f.strip() for f in fields.split(",")] @@ -183,14 +195,14 @@ def search_devices(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: ) -def get_device(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: +def get_device(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: device = octox.get_device_detail( hostname=args.get("hostname"), discovery_id=args.get("discovery_id", None) ) return CommandResults(outputs_prefix="OctoxLabs.Device", outputs=device) -def get_queries(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: +def get_queries(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: count, queries = octox.get_queries( page=args.get("page", 1), search=args.get("search", ""), @@ -223,7 +235,7 @@ def get_queries(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: ) -def get_query_by_id(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: +def get_query_by_id(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: query = octox.get_query_by_id(query_id=args.get("query_id")) return CommandResults( outputs_prefix="OctoxLabs.Query", @@ -245,7 +257,7 @@ def get_query_by_id(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: ) -def get_query_by_name(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: +def get_query_by_name(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: query = octox.get_query_by_name(query_name=args.get("query_name")) return CommandResults( outputs_prefix="OctoxLabs.Query", @@ -267,7 +279,7 @@ def get_query_by_name(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: ) -def get_companies(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: +def get_companies(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: count, companies = octox.get_companies( page=args.get("page", 1), search=args.get("search", ""), @@ -294,7 +306,7 @@ def get_companies(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: ) -def get_company_by_id(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: +def get_company_by_id(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: company = octox.get_company_by_id(company_id=args.get("company_id")) return CommandResults( @@ -311,7 +323,7 @@ def get_company_by_id(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: ) -def get_company_by_name(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: +def get_company_by_name(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: company = octox.get_company_by_name(company_name=args.get("company_name")) return CommandResults( @@ -328,7 +340,7 @@ def get_company_by_name(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResult ) -def get_domains(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: +def get_domains(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: count, domains = octox.get_domains( page=args.get("page", 1), search=args.get("search", ""), @@ -355,7 +367,7 @@ def get_domains(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: ) -def get_domain_by_id(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: +def get_domain_by_id(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: domain = octox.get_domain_by_id(domain_id=args.get("domain_id")) return CommandResults( @@ -372,7 +384,7 @@ def get_domain_by_id(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: ) -def get_domain_by_domain_name(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: +def get_domain_by_domain_name(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: domain = octox.get_domains_by_domain_name(domain_name=args.get("domain_name")) return CommandResults( @@ -383,13 +395,14 @@ def get_domain_by_domain_name(octox: OctoxLabs, args: Dict[str, Any]) -> Command "id", "domain", "tenant_name", - "tenant" "is_primary", + "tenant", + "is_primary", ], ), ) -def get_users(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: +def get_users(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: count, users = octox.get_users( page=args.get("page", 1), search=args.get("search", ""), @@ -421,7 +434,7 @@ def get_users(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: ) -def get_user_by_id(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: +def get_user_by_id(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: user = octox.get_user_by_id(user_id=args.get("user_id")) return CommandResults( outputs_prefix="OctoxLabs.User", @@ -442,7 +455,7 @@ def get_user_by_id(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: ) -def get_user_by_username(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: +def get_user_by_username(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: user = octox.get_user_by_username(username=args.get("username")) return CommandResults( outputs_prefix="OctoxLabs.User", @@ -463,7 +476,7 @@ def get_user_by_username(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResul ) -def get_groups(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: +def get_groups(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: count, groups = octox.get_groups( page=args.get("page", 1), search=args.get("search", ""), @@ -485,7 +498,7 @@ def get_groups(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: ) -def get_permissions(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: +def get_permissions(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: count, permissions = octox.get_permissions( page=args.get("page", 1), search=args.get("search", ""), @@ -507,6 +520,169 @@ def get_permissions(octox: OctoxLabs, args: Dict[str, Any]) -> CommandResults: ) +def search_users_inventory(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: + fields = args.get("fields", None) + if isinstance(fields, str): + fields = [f.strip() for f in fields.split(",")] + + count, users = octox.search_users( + query=args.get("query", ""), + fields=fields, + page=args.get("page", 1), + size=args.get("size", 50), + discovery_id=args.get("discovery_id", None), + ) + + return CommandResults( + outputs_prefix="OctoxLabs.UsersInventory", + outputs={ + "count": count, + "results": users, + }, + ) + + +def search_applications(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: + fields = args.get("fields", None) + if isinstance(fields, str): + fields = [f.strip() for f in fields.split(",")] + + count, applications = octox.search_applications( + query=args.get("query", ""), + fields=fields, + page=args.get("page", 1), + size=args.get("size", 50), + discovery_id=args.get("discovery_id", None), + ) + + return CommandResults( + outputs_prefix="OctoxLabs.Applications", + outputs={ + "count": count, + "results": applications, + }, + ) + + +def search_avm(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: + count, avm = octox.search_avm( + query=args.get("query", ""), + page=args.get("page", 1), + size=args.get("size", 50), + discovery_id=args.get("discovery_id", None), + ) + + return CommandResults( + outputs_prefix="OctoxLabs.AVM", + outputs={ + "count": count, + "results": avm, + }, + ) + + +def get_user_inventory_detail(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: + user = octox.get_user_inventory_detail( + username=args.get("username"), discovery_id=args.get("discovery_id", None) + ) + return CommandResults(outputs_prefix="OctoxLabs.UserInv", outputs=user) + + +def get_application_detail(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: + application = octox.get_application_detail( + application_id=args.get("application_id"), + discovery_id=args.get("discovery_id", None), + ) + return CommandResults(outputs_prefix="OctoxLabs.Application", outputs=application) + + +def search_scroll_devices(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: + fields = args.get("fields", None) + if isinstance(fields, str): + fields = [f.strip() for f in fields.split(",")] + + count, scroll_id, devices = octox.search_scroll_devices( + query=args.get("query", ""), + fields=fields, + scroll_id=args.get("scroll_id", None), + size=args.get("size", 50), + discovery_id=args.get("discovery_id", None), + ) + + return CommandResults( + outputs_prefix="OctoxLabs.ScrolledDevices", + outputs={ + "count": count, + "scroll_id": scroll_id, + "results": devices, + }, + ) + + +def search_scroll_users(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: + fields = args.get("fields", None) + if isinstance(fields, str): + fields = [f.strip() for f in fields.split(",")] + + count, scroll_id, users = octox.search_scroll_users( + query=args.get("query", ""), + fields=fields, + scroll_id=args.get("scroll_id", None), + size=args.get("size", 50), + discovery_id=args.get("discovery_id", None), + ) + + return CommandResults( + outputs_prefix="OctoxLabs.ScrolledUsers", + outputs={ + "count": count, + "scroll_id": scroll_id, + "results": users, + }, + ) + + +def search_scroll_applications(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: + fields = args.get("fields", None) + if isinstance(fields, str): + fields = [f.strip() for f in fields.split(",")] + + count, scroll_id, applications = octox.search_scroll_applications( + query=args.get("query", ""), + fields=fields, + scroll_id=args.get("scroll_id", None), + size=args.get("size", 50), + discovery_id=args.get("discovery_id", None), + ) + + return CommandResults( + outputs_prefix="OctoxLabs.ScrolledApplications", + outputs={ + "count": count, + "scroll_id": scroll_id, + "results": applications, + }, + ) + + +def search_scroll_avm(octox: OctoxLabs, args: dict[str, Any]) -> CommandResults: + count, scroll_id, avm = octox.search_scroll_avm( + query=args.get("query", ""), + scroll_id=args.get("scroll_id", None), + size=args.get("size", 50), + discovery_id=args.get("discovery_id", None), + ) + + return CommandResults( + outputs_prefix="OctoxLabs.ScrolledAVM", + outputs={ + "count": count, + "scroll_id": scroll_id, + "results": avm, + }, + ) + + """ MAIN FUNCTION """ @@ -518,10 +694,12 @@ def main() -> None: # pragma: no cover """ ip = demisto.params().get("octox_ip") token = demisto.params().get("octox_token", {"password": ""}).get("password") + https_proxy = demisto.params().get("https_proxy", None) + no_verify = demisto.params().get("no_verify", True) demisto.debug(f"Command being called is {demisto.command()}") try: - octox = OctoxLabs(ip=ip, token=token) + octox = OctoxLabs(ip=ip, token=token, https_proxy=https_proxy, no_verify=no_verify) return_results( run_command( octox=octox, command_name=demisto.command(), args=demisto.args() diff --git a/Packs/OctoxLabs/Integrations/OctoxLabs/OctoxLabs.yml b/Packs/OctoxLabs/Integrations/OctoxLabs/OctoxLabs.yml index bff736a12b76..4bffa0877ead 100644 --- a/Packs/OctoxLabs/Integrations/OctoxLabs/OctoxLabs.yml +++ b/Packs/OctoxLabs/Integrations/OctoxLabs/OctoxLabs.yml @@ -15,6 +15,17 @@ configuration: required: true hiddenusername: true type: 9 +- name: https_proxy + display: HTTPS Proxy + required: false + type: 0 + additionalinfo: Your HTTPS Proxy URL +- name: no_verify + required: false + type: 8 + display: No Verify + additionalinfo: Don't Verify SSL + description: 'Octox Labs Cyber Security Asset Management platform.' display: 'OctoxLabs' name: OctoxLabs @@ -584,12 +595,225 @@ script: - contextPath: OctoxLabs.Permissions.results.app description: 'Permission app.' type: String - + - name: octoxlabs-search-users-inventory + description: 'Search in your User Inventory.' + arguments: + - default: + description: 'Query.' + name: query + - default: + description: 'Fields.' + isArray: true + name: fields + - default: + description: 'Page (Default: 1).' + name: page + - default: + description: 'Size (Default: 50).' + name: size + - default: + description: 'Specific Discovery Id.' + name: discovery_id + outputs: + - contextPath: OctoxLabs.UserInventory.count + description: 'Total users count.' + type: Number + - contextPath: OctoxLabs.UserInventory.results + description: 'List User information.' + type: Unknown + - name: octoxlabs-search-applications + description: 'Search in your Applications' + arguments: + - default: + description: 'Query.' + name: query + - default: + description: 'Fields.' + isArray: true + name: fields + - default: + description: 'Page (Default: 1).' + name: page + - default: + description: 'Size (Default: 50).' + name: size + - default: + description: 'Specific Discovery Id.' + name: discovery_id + outputs: + - contextPath: OctoxLabs.Applications.count + description: 'Total applications count.' + type: Number + - contextPath: OctoxLabs.Applications.results + description: 'List Application information.' + type: Unknown + - name: octoxlabs-search-avm + description: 'Search in your AVM' + arguments: + - default: + description: 'Query.' + name: query + - default: + description: 'Fields.' + isArray: true + name: fields + - default: + description: 'Page (Default: 1).' + name: page + - default: + description: 'Size (Default: 50).' + name: size + - default: + description: 'Specific Discovery Id.' + name: discovery_id + outputs: + - contextPath: OctoxLabs.AVM.count + description: 'Total vulnerabilities count.' + type: Number + - contextPath: OctoxLabs.AVM.results + description: 'List Vulnerability information.' + type: Unknown + - name: octoxlabs-get-user-inventory-detail + description: 'Fetch your user.' + arguments: + - required: true + name: username + description: 'Your user username.' + - name: discovery_id + description: 'Your device at specific discovery.' + outputs: + - contextPath: OctoxLabs.UserInv + description: ' Octoxlabs User.' + type: Unknown + - name: octoxlabs-get-application-detail + description: 'Fetch your application.' + arguments: + - required: true + name: application_id + description: 'Your application id.' + - name: discovery_id + description: 'Your device at specific discovery.' + outputs: + - contextPath: OctoxLabs.Application + description: ' Octoxlabs Application.' + type: Unknown + - name: octoxlabs-search-scroll-devices + description: 'Search in your devices.' + arguments: + - default: + description: 'Query.' + name: query + - default: + description: 'Fields.' + isArray: true + name: fields + - default: + description: 'Size (Default: 50).' + name: size + - default: + description: 'Specific Discovery Id.' + name: discovery_id + - default: + description: 'Specific Scroll Id.' + name: scroll_id + outputs: + - contextPath: OctoxLabs.ScrolledDevices.count + description: 'Total devices count.' + type: Number + - contextPath: OctoxLabs.ScrolledDevices.scroll_id + description: 'Specific Scroll Id.' + type: String + - contextPath: OctoxLabs.ScrolledDevices.results + description: 'List Device information.' + type: Unknown + - name: octoxlabs-search-scroll-users + description: 'Search in your users.' + arguments: + - default: + description: 'Query.' + name: query + - default: + description: 'Fields.' + isArray: true + name: fields + - default: + description: 'Size (Default: 50).' + name: size + - default: + description: 'Specific Discovery Id.' + name: discovery_id + - default: + description: 'Specific Scroll Id.' + name: scroll_id + outputs: + - contextPath: OctoxLabs.ScrolledUsers.count + description: 'Total users count.' + type: Number + - contextPath: OctoxLabs.ScrolledUsers.scroll_id + description: 'Specific Scroll Id.' + type: String + - contextPath: OctoxLabs.ScrolledUsers.results + description: 'List Users information.' + type: Unknown + - name: octoxlabs-search-scroll-applications + description: 'Search in your applications.' + arguments: + - default: + description: 'Query.' + name: query + - default: + description: 'Fields.' + isArray: true + name: fields + - default: + description: 'Size (Default: 50).' + name: size + - default: + description: 'Specific Discovery Id.' + name: discovery_id + - default: + description: 'Specific Scroll Id.' + name: scroll_id + outputs: + - contextPath: OctoxLabs.ScrolledApplications.count + description: 'Total applications count.' + type: Number + - contextPath: OctoxLabs.ScrolledApplications.scroll_id + description: 'Specific Scroll Id.' + type: String + - contextPath: OctoxLabs.ScrolledApplications.results + description: 'List Application information.' + type: Unknown + - name: octoxlabs-search-scroll-avm + description: 'Search in your AVM.' + arguments: + - default: + description: 'Query.' + name: query + - default: + description: 'Size (Default: 50).' + name: size + - default: + description: 'Specific Discovery Id.' + name: discovery_id + - default: + description: 'Specific Scroll Id.' + name: scroll_id + outputs: + - contextPath: OctoxLabs.ScrolledAVM.count + description: 'Total vulnerabilities count.' + type: Number + - contextPath: OctoxLabs.ScrolledAVM.scroll_id + description: 'Specific Scroll Id.' + type: String + - contextPath: OctoxLabs.ScrolledAVM.results + description: 'List Vulnerability information.' + type: Unknown runonce: false script: '-' type: python subtype: python3 - dockerimage: demisto/octoxlabs:1.0.0.96081 + dockerimage: demisto/octoxlabs:1.0.0.1796617 fromversion: 6.0.0 tests: - No tests (auto formatted) diff --git a/Packs/OctoxLabs/Integrations/OctoxLabs/OctoxLabs_test.py b/Packs/OctoxLabs/Integrations/OctoxLabs/OctoxLabs_test.py index cfaee19ede2e..28dc66e8ab9c 100644 --- a/Packs/OctoxLabs/Integrations/OctoxLabs/OctoxLabs_test.py +++ b/Packs/OctoxLabs/Integrations/OctoxLabs/OctoxLabs_test.py @@ -8,7 +8,6 @@ you are implementing with your integration """ -import io import json import pytest @@ -26,7 +25,7 @@ def octox_client(requests_mock) -> OctoxLabs: def util_load_json(path): - with io.open(path, mode="r", encoding="utf-8") as f: + with open(path, encoding="utf-8") as f: return json.loads(f.read()) @@ -296,3 +295,179 @@ def test_get_permissions(requests_mock, octox_client): first_data = result.outputs assert first_data["count"] == 1 assert first_data["results"][0]["app"] == "activities" + + +def test_get_scroll_devices(requests_mock, octox_client): + devices_data = util_load_json(path="test_data/get_devices.json") + devices_data["scroll_id"] = "scroll-id" + requests_mock.post("/devices/devices", json=devices_data) + result = run_command( + octox=octox_client, command_name="octoxlabs-search-scroll-devices", args={} + ) + first_data = result.outputs + + assert first_data["count"] == 1 + assert first_data["results"][0]["Hostname"] == ["dev-1"] + devices_data["results"] = [] + requests_mock.post("/devices/devices", json=devices_data) + second_result = run_command( + octox=octox_client, + command_name="octoxlabs-search-scroll-devices", + args={"scroll_id": "scroll-id"}, + ) + second_data = second_result.outputs + assert second_data["count"] == 1 + assert not second_data["results"] + + +def test_get_scroll_users(requests_mock, octox_client): + users_data = util_load_json(path="test_data/get_users_inv.json") + users_data["scroll_id"] = "scroll-id" + requests_mock.post("/userinventory/users", json=users_data) + result = run_command( + octox=octox_client, command_name="octoxlabs-search-scroll-users", args={} + ) + first_data = result.outputs + + assert first_data["count"] == 1 + assert first_data["results"][0]["Username"] == ["octouser-1"] + users_data["results"] = [] + requests_mock.post("/userinventory/users", json=users_data) + second_result = run_command( + octox=octox_client, + command_name="octoxlabs-search-scroll-users", + args={"scroll_id": "scroll-id"}, + ) + second_data = second_result.outputs + assert second_data["count"] == 1 + assert not second_data["results"] + + +def test_get_scroll_applications(requests_mock, octox_client): + app_data = util_load_json(path="test_data/get_applications.json") + app_data["scroll_id"] = "scroll-id" + requests_mock.post("/appinventory/applications", json=app_data) + result = run_command( + octox=octox_client, command_name="octoxlabs-search-scroll-applications", args={} + ) + first_data = result.outputs + + assert first_data["count"] == 1 + assert first_data["results"][0]["Groups"] == ["hp"] + app_data["results"] = [] + requests_mock.post("/appinventory/applications", json=app_data) + second_result = run_command( + octox=octox_client, + command_name="octoxlabs-search-scroll-applications", + args={"scroll_id": "scroll-id"}, + ) + second_data = second_result.outputs + assert second_data["count"] == 1 + assert not second_data["results"] + + +def test_get_scroll_avm(requests_mock, octox_client): + avm_data = util_load_json(path="test_data/get_avm.json") + avm_data["scroll_id"] = "scroll-id" + requests_mock.post("/avm/vulnerabilities", json=avm_data) + result = run_command( + octox=octox_client, command_name="octoxlabs-search-scroll-avm", args={} + ) + first_data = result.outputs + + assert first_data["count"] == 1 + assert first_data["results"][0]["Id"] == ["CVE-2024-21423"] + avm_data["results"] = [] + requests_mock.post("/avm/vulnerabilities", json=avm_data) + second_result = run_command( + octox=octox_client, + command_name="octoxlabs-search-scroll-avm", + args={"scroll_id": "scroll-id"}, + ) + second_data = second_result.outputs + assert second_data["count"] == 1 + assert not second_data["results"] + + +def test_search_devices(requests_mock, octox_client): + devices_data = util_load_json(path="test_data/get_devices.json") + requests_mock.post("/devices/devices", json=devices_data) + result = run_command( + octox=octox_client, command_name="octoxlabs-search-devices", args={} + ) + first_data = result.outputs + + assert first_data["count"] == 1 + assert first_data["results"][0]["Hostname"] == ["dev-1"] + + +def test_search_users_inventory(requests_mock, octox_client): + users_data = util_load_json(path="test_data/get_users_inv.json") + requests_mock.post("/userinventory/users", json=users_data) + result = run_command( + octox=octox_client, command_name="octoxlabs-search-users-inventory", args={} + ) + first_data = result.outputs + + assert first_data["count"] == 1 + assert first_data["results"][0]["Username"] == ["octouser-1"] + + +def test_search_applications(requests_mock, octox_client): + app_data = util_load_json(path="test_data/get_applications.json") + requests_mock.post("/appinventory/applications", json=app_data) + result = run_command( + octox=octox_client, command_name="octoxlabs-search-applications", args={} + ) + first_data = result.outputs + + assert first_data["count"] == 1 + assert first_data["results"][0]["Groups"] == ["hp"] + + +def test_search_avm(requests_mock, octox_client): + avm_data = util_load_json(path="test_data/get_avm.json") + requests_mock.post("/avm/vulnerabilities", json=avm_data) + result = run_command( + octox=octox_client, command_name="octoxlabs-search-avm", args={} + ) + first_data = result.outputs + + assert first_data["count"] == 1 + assert first_data["results"][0]["Id"] == ["CVE-2024-21423"] + + +def test_get_user_detail(requests_mock, octox_client): + users_data = util_load_json(path="test_data/get_user_inv_detail.json") + requests_mock.post("/userinventory/users/None", json=users_data) + requests_mock.get("/discoveries/last", json={"id": 1}) + result = run_command( + octox=octox_client, command_name="octoxlabs-get-user-inventory-detail", args={} + ) + first_data = result.outputs + + assert first_data["Username"] == "octouser-1" + + +def test_get_application_detail(requests_mock, octox_client): + app_data = util_load_json(path="test_data/get_application_detail.json") + requests_mock.post("/appinventory/applications/None", json=app_data) + requests_mock.get("/discoveries/last", json={"id": 1}) + result = run_command( + octox=octox_client, command_name="octoxlabs-get-application-detail", args={} + ) + first_data = result.outputs + + assert first_data["Count"] == 1174 + + +def test_get_device_detail(requests_mock, octox_client): + device_data = util_load_json(path="test_data/get_device_detail.json") + requests_mock.post("/devices/devices/None", json=device_data) + requests_mock.get("/discoveries/last", json={"id": 1}) + result = run_command( + octox=octox_client, command_name="octoxlabs-get-device", args={} + ) + first_data = result.outputs + + assert first_data["Hostname"] == "dev-1" diff --git a/Packs/OctoxLabs/Integrations/OctoxLabs/README.md b/Packs/OctoxLabs/Integrations/OctoxLabs/README.md index 91eba71145b7..719e2bd182f9 100644 --- a/Packs/OctoxLabs/Integrations/OctoxLabs/README.md +++ b/Packs/OctoxLabs/Integrations/OctoxLabs/README.md @@ -1,13 +1,17 @@ Octox Labs Cyber Security Asset Management platform -This integration was integrated and tested with version 3.3.0 of OctoxLabs +This integration was integrated and tested with version 4.5.0 of OctoxLabs ## Configure OctoxLabs in Cortex + | **Parameter** | **Description** | **Required** | | --- | --- | --- | | IP | Your Octox Labs Platform IP | True | | API Key | Your Octox Labs API Key. \(https://github.com/octoxlabs/py-octoxlabs\#getting-started\) | True | +| HTTPS Proxy | Your HTTPS Proxy URL | False | +| No Verify | Don't Verify SSL | False | + ## Commands @@ -554,3 +558,232 @@ Fetch your User by id | OctoxLabs.User.results.is_active | Boolean | User is active | | OctoxLabs.User.results.is_ldap | Boolean | User is ldap | | OctoxLabs.User.results.groups | Unknown | List<Dict> User groups | +### octoxlabs-search-scroll-users + +*** +Search in your users. + +#### Base Command + +`octoxlabs-search-scroll-users` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| query | Query. | Optional | +| fields | Fields. | Optional | +| size | Size. (Default: 50). | Optional | +| discovery_id | Specific Discovery Id. | Optional | +| scroll_id | Specific Scroll Id. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| OctoxLabs.ScrolledUsers.count | Number | Total users count. | +| OctoxLabs.ScrolledUsers.scroll_id | String | Specific Scroll Id | +| OctoxLabs.ScrolledUsers.results | Unknown | List Users information. | + +### octoxlabs-get-application-detail + +*** +Fetch your application. + +#### Base Command + +`octoxlabs-get-application-detail` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| application_id | Your application id. | Required | +| discovery_id | Your device at specific discovery. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| OctoxLabs.Application | Unknown | <Dict> Octoxlabs Application. | + +### octoxlabs-search-scroll-avm + +*** +Search in your AVM. + +#### Base Command + +`octoxlabs-search-scroll-avm` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| query | Query. | Optional | +| size | Size. | Optional | +| discovery_id | Specific Discovery Id. | Optional | +| scroll_id | Specific Scroll Id. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| OctoxLabs.ScrolledAVM.count | Number | Total vulnerabilities count. | +| OctoxLabs.ScrolledAVM.scroll_id | String | Specific Scroll Id | +| OctoxLabs.ScrolledAVM.results | Unknown | List Vulnerability information. | + +### octoxlabs-search-scroll-devices + +*** +Search in your devices. + +#### Base Command + +`octoxlabs-search-scroll-devices` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| query | Query. | Optional | +| fields | Fields. | Optional | +| size | Size. (Default: 50). | Optional | +| discovery_id | Specific Discovery Id. | Optional | +| scroll_id | Specific Scroll Id. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| OctoxLabs.ScrolledDevices.count | Number | Total devices count. | +| OctoxLabs.ScrolledDevices.scroll_id | String | Specific Scroll Id | +| OctoxLabs.ScrolledDevices.results | Unknown | List Device information. | + +### octoxlabs-search-applications + +*** +Search in your Applications + +#### Base Command + +`octoxlabs-search-applications` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| query | Query. | Optional | +| fields | Fields. | Optional | +| page | Page. (Default: 1). | Optional | +| size | Size. (Default: 50). | Optional | +| discovery_id | Specific Discovery Id. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| OctoxLabs.Applications.count | Number | Total applications count. | +| OctoxLabs.Applications.results | Unknown | List Application information. | + +### octoxlabs-search-avm + +*** +Search in your AVM + +#### Base Command + +`octoxlabs-search-avm` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| query | Query. | Optional | +| fields | Fields. | Optional | +| page | Page. (Default: 1). | Optional | +| size | Size. (Default: 50). | Optional | +| discovery_id | Specific Discovery Id. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| OctoxLabs.AVM.count | Number | Total vulnerabilities count. | +| OctoxLabs.AVM.results | Unknown | List Vulnerability information. | + +### octoxlabs-search-scroll-applications + +*** +Search in your applications. + +#### Base Command + +`octoxlabs-search-scroll-applications` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| query | Query. | Optional | +| fields | Fields. | Optional | +| size | Size. (Default: 50). | Optional | +| discovery_id | Specific Discovery Id. | Optional | +| scroll_id | Specific Scroll Id. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| OctoxLabs.ScrolledApplications.count | Number | Total applications count. | +| OctoxLabs.ScrolledApplications.scroll_id | String | Specific Scroll Id | +| OctoxLabs.ScrolledApplications.results | Unknown | List Application information. | + +### octoxlabs-get-user-inventory-detail + +*** +Fetch your user. + +#### Base Command + +`octoxlabs-get-user-inventory-detail` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| username | Your user username. | Required | +| discovery_id | Your device at specific discovery. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| OctoxLabs.UserInv | Unknown | <Dict> Octoxlabs User. | + +### octoxlabs-search-users-inventory + +*** +Search in your User Inventory. + +#### Base Command + +`octoxlabs-search-users-inventory` + +#### Input + +| **Argument Name** | **Description** | **Required** | +| --- | --- | --- | +| query | Query. | Optional | +| fields | Fields. | Optional | +| page | Page. (Default: 1). | Optional | +| size | Size. (Default: 50). | Optional | +| discovery_id | Specific Discovery Id. | Optional | + +#### Context Output + +| **Path** | **Type** | **Description** | +| --- | --- | --- | +| OctoxLabs.UserInventory.count | Number | Total users count. | +| OctoxLabs.UserInventory.results | Unknown | List User information. | + diff --git a/Packs/OctoxLabs/Integrations/OctoxLabs/command_examples b/Packs/OctoxLabs/Integrations/OctoxLabs/command_examples index bae3fad5fe5d..9fb6e5c73f9e 100644 --- a/Packs/OctoxLabs/Integrations/OctoxLabs/command_examples +++ b/Packs/OctoxLabs/Integrations/OctoxLabs/command_examples @@ -14,4 +14,17 @@ !octoxlabs-get-user-by-id user_id=1 !octoxlabs-get-user-by-username username="xsoar" !octoxlabs-get-groups page=1 -!octoxlabs-get-permissions page=1 \ No newline at end of file +!octoxlabs-get-permissions page=1 +!octoxlabs-search-scroll-devices fields="Adapters,Hostname,Groups" size=100 +!octoxlabs-search-scroll-devices scroll_id="scroll-id" +!octoxlabs-search-scroll-users fields="Username" size=100 +!octoxlabs-search-scroll-users scroll_id="scroll-id" +!octoxlabs-search-scroll-applications fields="Name" size=100 +!octoxlabs-search-scroll-applications scroll_id="scroll-id" +!octoxlabs-search-scroll-avm size=100 +!octoxlabs-search-scroll-avm scroll_id="scroll-id" +!octoxlabs-search-users-inventory fields="Username" size=100 page=1 +!octoxlabs-search-applications fields="Name" size=100 page=1 +!octoxlabs-search-avm size=100 page=1 +!octoxlabs-get-user-inventory-detail username="octouser01" discovery_id=1232 +!octoxlabs-get-application-detail application_id="application-id" discovery_id=1232 \ No newline at end of file diff --git a/Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_application_detail.json b/Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_application_detail.json new file mode 100644 index 000000000000..7bf6a103ea2e --- /dev/null +++ b/Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_application_detail.json @@ -0,0 +1,13 @@ +{ + "Name": "Microsoft Visual C++ 2015-2022 Redistributable - 14.32.31326.0", + "Count": 1174, + "Version": "", + "Architecture": "x86", + "Description": "Microsoft Visual C++ 2015-2022 Redistributable (x86) - 14.32.31326 Description", + "Publisher": "Microsoft Corporation", + "Groups": [], + "Vulnerabilities": [], + "VulnerabilityMaxScore": null, + "VulnerabilityMaxSeverity": "", + "VulnerabilityCount": 0 +} \ No newline at end of file diff --git a/Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_applications.json b/Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_applications.json new file mode 100644 index 000000000000..ef1c9513f2b8 --- /dev/null +++ b/Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_applications.json @@ -0,0 +1,35 @@ +{ + "count": 1, + "results": [ + { + "VulnerabilityMaxSeverity": [ + "" + ], + "Description": [ + "HP Operations agent Consolidated Package Description" + ], + "Architecture": [ + "x86" + ], + "Version": [ + "" + ], + "VulnerabilityCount": [ + 0 + ], + "Groups": [ + "hp" + ], + "Count": [ + 625 + ], + "Publisher": [ + "" + ], + "Name": [ + "HP Operations agent Consolidated Package - 12.22.7" + ], + "Id": "7ppKz5MBusCvq4kXw1wZ" + } + ] +} \ No newline at end of file diff --git a/Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_avm.json b/Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_avm.json new file mode 100644 index 000000000000..73d1d295375e --- /dev/null +++ b/Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_avm.json @@ -0,0 +1,25 @@ +{ + "count": 1, + "results": [ + { + "Description": [ + "Microsoft Edge (Chromium-based) Information Disclosure Vulnerability" + ], + "AssetCount": [ + 645 + ], + "Cvss2Score": [ + 0 + ], + "Id": [ + "CVE-2024-21423" + ], + "ApplicationCount": [ + 1 + ], + "Cvss3Score": [ + 0 + ] + } + ] +} \ No newline at end of file diff --git a/Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_device_detail.json b/Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_device_detail.json new file mode 100644 index 000000000000..e9aef7e6ed74 --- /dev/null +++ b/Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_device_detail.json @@ -0,0 +1,15 @@ +{ + "Hostname":"dev-1", + "BiosSerial":"DEE97-B2B58-7D1B3-F5759", + "Relations":[], + "AgentVersions":[], + "LastSeenAdapter":"sccm", + "PrivateIps":[], + "FetchTime":"2024-12-12T17:13:49.256564", + "DeviceManufacturer":"VMware, Inc.", + "DeviceManufacturerSerial":null, + "Domain":"octoxlabs.com", + "MacAddresses":[ + "ae:21:29:e2:7d:82" + ] +} \ No newline at end of file diff --git a/Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_devices.json b/Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_devices.json new file mode 100644 index 000000000000..2024e397ea1b --- /dev/null +++ b/Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_devices.json @@ -0,0 +1,28 @@ +{ + "count": 1, + "results": [ + { + "Category": [ + "Server" + ], + "FirstFetchTime": [ + "2024-05-03T17:15:30.761Z" + ], + "Adapters": [ + "carbon-black" + ], + "Hostname": [ + "dev-1" + ], + "OS.Type": [ + "Windows" + ], + "Domain": [ + "octoxlabs.com" + ], + "LastSeen": [ + "2024-12-05T00:00:00.000Z" + ] + } + ] +} \ No newline at end of file diff --git a/Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_user_inv_detail.json b/Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_user_inv_detail.json new file mode 100644 index 000000000000..d9d5a7b2a32b --- /dev/null +++ b/Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_user_inv_detail.json @@ -0,0 +1,7 @@ +{ + "Username":"octouser-1", + "Domain":null, + "FetchTime":"2024-12-12T17:13:45.566925", + "FirstName":null, + "LastName":null +} \ No newline at end of file diff --git a/Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_users_inv.json b/Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_users_inv.json new file mode 100644 index 000000000000..e5902dd07f0a --- /dev/null +++ b/Packs/OctoxLabs/Integrations/OctoxLabs/test_data/get_users_inv.json @@ -0,0 +1,16 @@ +{ + "count": 1, + "results": [ + { + "Username": [ + "octouser-1" + ], + "Adapters": [ + "active-directory" + ], + "LastLogOnTime": [ + "2024-12-05T00:00:00.000Z" + ] + } + ] +} \ No newline at end of file diff --git a/Packs/OctoxLabs/ReleaseNotes/2_1_0.md b/Packs/OctoxLabs/ReleaseNotes/2_1_0.md new file mode 100644 index 000000000000..3bd721b9944b --- /dev/null +++ b/Packs/OctoxLabs/ReleaseNotes/2_1_0.md @@ -0,0 +1,19 @@ + +#### Integrations + +##### OctoxLabs + +- Updated the Docker image to: *demisto/octoxlabs:1.0.0.1796617*. +- Added new parameters: + - **https_proxy** + - **no_verify** +- Added new commands: + - **octoxlabs-search-scroll-devices** + - **octoxlabs-search-scroll-users** + - **octoxlabs-search-scroll-applications** + - **octoxlabs-search-scroll-avm** + - **octoxlabs-search-users-inventory** + - **octoxlabs-search-applications** + - **octoxlabs-search-avm** + - **octoxlabs-get-user-inventory-detail** + - **octoxlabs-get-application-detail** diff --git a/Packs/OctoxLabs/pack_metadata.json b/Packs/OctoxLabs/pack_metadata.json index 5b8bc430e070..c2d37bc253de 100644 --- a/Packs/OctoxLabs/pack_metadata.json +++ b/Packs/OctoxLabs/pack_metadata.json @@ -2,7 +2,7 @@ "name": "OctoxLabs", "description": "Octox Labs Cyber Security Asset Management platform", "support": "partner", - "currentVersion": "2.0.0", + "currentVersion": "2.1.0", "author": "OctoxLabs", "url": "https://octoxlabs.com", "email": "info@octoxlabs.com",