diff --git a/Packs/DSPM/Integrations/DSPM/DSPM.py b/Packs/DSPM/Integrations/DSPM/DSPM.py index 97fc572b2f6..6c1446f8910 100644 --- a/Packs/DSPM/Integrations/DSPM/DSPM.py +++ b/Packs/DSPM/Integrations/DSPM/DSPM.py @@ -11,6 +11,7 @@ urllib3.disable_warnings() """ CONSTANTS """ MAX_PAGE_SIZE: int = 50 +DEFAULT_LIMIT: str = "50" DATE_FORMAT = "%Y-%m-%dT%H:%M:%SZ" # ISO8601 format with UTC, default in XSOAR GET_RISK_FINDINGS_ENDPOINT = "/v1/risk-findings" GET_ASSET_LISTS = "/v1/assets" @@ -249,28 +250,28 @@ def test_module(client: Client) -> str: return f"Error: An unknown exception occurred: {e}" -def dspm_get_risk_findings( +def get_list_risk_findings( client: Client, args: dict[str, Any], page: int ) -> list[dict]: """Fetch list of DSPM Risk findings""" # Validate and process cloudProvider parameters - cloudProviderIn = args.get("cloudProviderIn", "") - cloudProviderEqual = args.get("cloudProviderEqual", "") + cloud_provider_in = args.get("cloud_provider_in", "") + cloud_provider_equal = args.get("cloud_provider_equal", "") validate_parameter( - "cloudProvider", cloudProviderIn, cloudProviderEqual, SUPPORTED_CLOUD_PROVIDERS + "cloudProvider", cloud_provider_in, cloud_provider_equal, SUPPORTED_CLOUD_PROVIDERS ) # Check supported affects - affectsIn = args.get("affectsIn", "") - affectsEqual = args.get("affectsEqual", "") + affects_in = args.get("affects_in", "") + affects_equal = args.get("affects_equal", "") validate_parameter( - "affects", affectsIn, affectsEqual, SUPPORTED_CATEGORIES + "affects", affects_in, affects_equal, SUPPORTED_CATEGORIES ) # Check supported Status - statusIn = args.get("statusIn", "") - statusEqual = args.get("statusEqual", "") - validate_parameter("status", statusIn, statusEqual, SUPPORTED_STATUSES) + status_in = args.get("status_in", "") + status_equal = args.get("status_equal", "") + validate_parameter("status", status_in, status_equal, SUPPORTED_STATUSES) # Check supported sorting order sort_order = args.get("sort") @@ -281,20 +282,20 @@ def dspm_get_risk_findings( raise ValueError(f'This "{sort_order}" sorting order is not supported') params = { - "ruleName.in": args.get("ruleNameIn"), - "ruleName.equals": args.get("ruleNameEqual"), - "dspmTagKey.in": args.get("dspmTagKeyIn"), - "dspmTagKey.equals": args.get("dspmTagKeyEqual"), - "dspmTagValue.in": args.get("dspmTagValueIn"), - "dspmTagValue.equals": args.get("dspmTagValueEqual"), - "projectId.in": args.get("projectIdIn"), - "projectId.equals": args.get("projectIdEqual"), - "cloudProvider.in": args.get("cloudProviderIn"), - "cloudProvider.equals": args.get("cloudProviderEqual"), - "affects.in": args.get("affectsIn"), - "affects.equals": args.get("affectsEqual"), - "status.in": args.get("statusIn"), - "status.equals": args.get("statusEqual"), + "ruleName.in": args.get("rule_name_in"), + "ruleName.equals": args.get("rule_name_equal"), + "dspmTagKey.in": args.get("dspm_tag_key_in"), + "dspmTagKey.equals": args.get("dspm_tag_key_equal"), + "dspmTagValue.in": args.get("dspm_tag_value_in"), + "dspmTagValue.equals": args.get("dspm_tag_value_equal"), + "projectId.in": args.get("projectId_in"), + "projectId.equals": args.get("projectId_equal"), + "cloudProvider.in": args.get("cloud_provider_in"), + "cloudProvider.equals": args.get("cloud_provider_equal"), + "affects.in": args.get("affects_in"), + "affects.equals": args.get("affects_equal"), + "status.in": args.get("status_in"), + "status.equals": args.get("status_equal"), "sort": args.get("sort"), "page": page, "size": MAX_PAGE_SIZE, @@ -309,23 +310,7 @@ def dspm_get_risk_findings( if not findings: return [] # No more findings to fetch - parsed_findings = [ - { - "ID": finding.get("id", ""), - "Rule Name": finding.get("ruleName", ""), - "Severity": finding.get("severity", ""), - "Asset Name": finding.get("asset", {}).get("name", ""), - "Asset ID": finding.get("asset", {}).get("assetId", ""), - "Status": finding.get("status", ""), - "Project ID": finding.get("projectId", ""), - "Cloud Provider": finding.get("cloudProvider", ""), - "Cloud Environment": finding.get("cloudEnvironment", ""), - "First Discovered": finding.get("firstDiscovered", ""), - "Compliance Standards": finding.get("complianceStandards", {}), - } - for finding in findings - ] - return parsed_findings + return findings def get_risk_finding_by_id( @@ -343,49 +328,35 @@ def get_risk_finding_by_id( finding = response if isinstance(response, dict) else response[0] - parsed_finding = { - "ID": finding.get("id", ""), - "Rule Name": finding.get("ruleName", ""), - "Severity": finding.get("severity", ""), - "Asset Name": finding.get("asset", {}).get("name", ""), - "Asset ID": finding.get("asset", {}).get("assetId", ""), - "Status": finding.get("status", ""), - "Project ID": finding.get("projectId", ""), - "Cloud Provider": finding.get("cloudProvider", ""), - "Cloud Environment": finding.get("cloudEnvironment", ""), - "First Discovered": finding.get("firstDiscovered", ""), - "Compliance Standards": finding.get("complianceStandards", {}), - } - - headers = parsed_finding.keys() - readable_output = tableToMarkdown("Risk Finding", parsed_finding, headers=headers, headerTransform=pascalToSpace) + readable_output = tableToMarkdown("Risk Finding", finding, headerTransform=pascalToSpace) return CommandResults( outputs_prefix="DSPM.RiskFinding", outputs_key_field="id", - outputs=parsed_finding, - readable_output=readable_output + outputs=finding, + readable_output=readable_output, + raw_response=finding ) def get_list_of_assets(client: Client, args: dict[str, Any], page: int) -> list[dict]: # Validate and process cloudProvider parameters - cloudProviderIn = args.get("cloudProviderIn", "") - cloudProviderEqual = args.get("cloudProviderEqual", "") + cloud_provider_in = args.get("cloud_provider_in", "") + cloud_provider_equal = args.get("cloud_provider_equal", "") validate_parameter( - "cloudProvider", cloudProviderIn, cloudProviderEqual, SUPPORTED_CLOUD_PROVIDERS + "cloudProvider", cloud_provider_in, cloud_provider_equal, SUPPORTED_CLOUD_PROVIDERS ) # Validate and process serviceType parameters - service_Type_In = args.get("serviceTypeIn", "") - service_Type_Equal = args.get("serviceTypeEqual", "") + service_Type_In = args.get("service_type_in", "") + service_Type_Equal = args.get("service_type_equal", "") validate_parameter( "serviceType", service_Type_In, service_Type_Equal, SUPPORTED_SERVICE_TYPES ) # Validate and process lifecycle parameters - lifecycle_In = args.get("lifecycleIn", "") - lifecycle_Equal = args.get("lifecycleEqual", "") + lifecycle_In = args.get("lifecycle_in", "") + lifecycle_Equal = args.get("lifecycle_equal", "") validate_parameter( "lifecycle", lifecycle_In, lifecycle_Equal, SUPPORTED_LIFECYCLE ) @@ -399,16 +370,16 @@ def get_list_of_assets(client: Client, args: dict[str, Any], page: int) -> list[ raise ValueError(f'This "{sort_order}" sorting order is not supported') params = { - "region.in": args.get("regionIn"), - "region.equals": args.get("regionEqual"), - "cloudProvider.in": args.get("cloudProviderIn"), - "cloudProvider.equals": args.get("cloudProviderEqual"), - "serviceType.in": args.get("serviceTypeIn"), - "serviceType.equals": args.get("serviceTypeEqual"), - "digTagKey.contains": args.get("digTagKeyContains"), - "digTagValue.contains": args.get("digTagValueContains"), - "lifecycle.in": args.get("lifecycleIn"), - "lifecycle.equals": args.get("lifecycleEqual"), + "region.in": args.get("region_in"), + "region.equals": args.get("region_equal"), + "cloudProvider.in": args.get("cloud_provider_in"), + "cloudProvider.equals": args.get("cloud_provider_equal"), + "serviceType.in": args.get("service_type_in"), + "serviceType.equals": args.get("service_type_equal"), + "digTagKey.contains": args.get("dig_tag_key_contains"), + "digTagValue.contains": args.get("dig_tag_value_contains"), + "lifecycle.in": args.get("lifecycle_in"), + "lifecycle.equals": args.get("lifecycle_equal"), "sort": args.get("sort"), "page": page, "size": MAX_PAGE_SIZE, @@ -424,26 +395,7 @@ def get_list_of_assets(client: Client, args: dict[str, Any], page: int) -> list[ if not assets: return [] # No more assets to fetch - parsed_assets = [ - { - "ID": asset.get("id", ""), - "Project ID": asset.get("projectId", ""), - "Project Name": asset.get("projectName", ""), - "Name": asset.get("name", ""), - "Cloud Provider": asset.get("cloudProvider", ""), - "Cloud Environment": asset.get("cloudEnvironment", ""), - "Service Type": asset.get("serviceType", ""), - "Lifecycle": asset.get("lifecycle", ""), - "Open Risks Count": asset.get("openRisksCount", 0), - "Open Alerts Count": asset.get("openAlertsCount", 0), - "Encrypted": asset.get("encrypted", False), - "Open To World": asset.get("openToWorld", False), - "Tags": asset.get("tags", {}), - "Asset Dig Tags": asset.get("assetDigTags", []), - } - for asset in assets - ] - return parsed_assets + return assets def get_asset_details(client: Client, args: dict[str, Any]) -> CommandResults: @@ -452,18 +404,14 @@ def get_asset_details(client: Client, args: dict[str, Any]) -> CommandResults: raise ValueError("asset_id not specified") asset_details = client.get_asset_details(asset_id) - demisto.debug(f"Asset details of : {asset_id}") - demisto.debug(asset_details) - headers = ["assetDigTags", "cloudEnvironment", "cloudProvider", "dataTypeGroups", "dataTypes", "encrypted", "id", - "lifecycle", "name", "openAlertsCount", "openRisksCount", "openToWorld", "projectId", - "projectName", "serviceType", "tags"] - readable_output = tableToMarkdown("Asset Details", asset_details, headers=headers, headerTransform=pascalToSpace) + readable_output = tableToMarkdown("Asset Details", asset_details, headerTransform=pascalToSpace) return CommandResults( outputs_prefix="DSPM.AssetDetails", outputs_key_field="id", outputs=asset_details, readable_output=readable_output, + raw_response=asset_details ) @@ -498,13 +446,13 @@ def get_asset_files_by_id(client: Client, args: dict[str, Any]) -> CommandResult files_count = len(all_files) # Return the result without formatting the files structure - headers = ["filename", "path", "type", "size", "openToWorld", "isDeleted", "isMalicious", "dataTypes", "labels", "isDbDump"] - readable_output = tableToMarkdown("Asset Files", all_files, headers=headers, headerTransform=pascalToSpace) + readable_output = tableToMarkdown("Asset Files", all_files, headerTransform=pascalToSpace) return CommandResults( outputs_prefix="DSPM.AssetFiles", outputs_key_field="filename", outputs={"files": all_files, "filesCount": files_count}, - readable_output=readable_output + readable_output=readable_output, + raw_response=all_files ) @@ -517,16 +465,14 @@ def get_data_types(client: Client) -> CommandResults: table_name = "Data Types" headers = ['No', 'Key'] - if data_types_formatted: - readable_output = tableToMarkdown(table_name, data_types_formatted, headers=headers) - else: - readable_output = tableToMarkdown(table_name, [], headers=headers) + readable_output = tableToMarkdown(table_name, data_types_formatted, headers=headers) return CommandResults( outputs_prefix="DSPM.DataTypes", outputs_key_field="Key", outputs=data_types_formatted, readable_output=readable_output, + raw_response=data_types ) @@ -535,24 +481,24 @@ def get_data_type_findings( ) -> list[dict]: """Fetch data type findings for a specific page.""" # check supported cloud providers - cloudProviderIn = args.get("cloudProviderIn", "") - cloudProviderEqual = args.get("cloudProviderEqual", "") + cloud_provider_in = args.get("cloud_provider_in", "") + cloud_provider_equal = args.get("cloud_provider_equal", "") validate_parameter( - "cloudProvider", cloudProviderIn, cloudProviderEqual, SUPPORTED_CLOUD_PROVIDERS + "cloudProvider", cloud_provider_in, cloud_provider_equal, SUPPORTED_CLOUD_PROVIDERS ) # check supported service type - serviceTypeIn = args.get("serviceTypeIn", "") - serviceTypeEqual = args.get("serviceTypeEqual", "") + service_type_in = args.get("service_type_in", "") + service_type_equal = args.get("service_type_equal", "") validate_parameter( - "serviceType", serviceTypeIn, serviceTypeEqual, SUPPORTED_SERVICE_TYPES + "serviceType", service_type_in, service_type_equal, SUPPORTED_SERVICE_TYPES ) # check supported lifecycle - lifecycleIn = args.get("lifecycleIn", "") - lifecycleEqual = args.get("lifecycleEqual", "") + lifecycle_in = args.get("lifecycle_in", "") + lifecycle_equal = args.get("lifecycle_equal", "") validate_parameter( - "lifecycle", lifecycleIn, lifecycleEqual, SUPPORTED_LIFECYCLE + "lifecycle", lifecycle_in, lifecycle_equal, SUPPORTED_LIFECYCLE ) # Check supported sorting order @@ -564,27 +510,30 @@ def get_data_type_findings( raise ValueError(f'This "{sort_order}" sorting order is not supported') params = { - "region.in": args.get("regionIn"), - "region.equals": args.get("regionEqual"), - "projectId.in": args.get("projectIdIn"), - "projectId.equals": args.get("projectIdEqual"), - "cloudProvider.in": args.get("cloudProviderIn"), - "cloudProvider.equals": args.get("cloudProviderEqual"), - "serviceType.in": args.get("serviceTypeIn"), - "serviceType.equals": args.get("serviceTypeEqual"), - "lifecycle.in": args.get("lifecycleIn"), - "lifecycle.equals": args.get("lifecycleEqual"), + "region.in": args.get("region_in"), + "region.equals": args.get("region_equal"), + "projectId.in": args.get("projectId_in"), + "projectId.equals": args.get("projectId_equal"), + "cloudProvider.in": args.get("cloud_provider_in"), + "cloudProvider.equals": args.get("cloud_provider_equal"), + "serviceType.in": args.get("service_type_in"), + "serviceType.equals": args.get("service_type_equal"), + "lifecycle.in": args.get("lifecycle_in"), + "lifecycle.equals": args.get("lifecycle_equal"), "sort": args.get("sort"), "page": page, "size": MAX_PAGE_SIZE, } + # Remove None values from params + params = {k: v for k, v in params.items() if v is not None} + data_type_findings = client.get_data_type_findings(params) return data_type_findings def update_risk_finding_status(client, args): - finding_id = args.get("riskFindingId") + finding_id = args.get("risk_finding_id") status = args.get("status") if status and status not in SUPPORTED_STATUSES: raise ValueError(f'This "{status}" status is not supported') @@ -592,20 +541,14 @@ def update_risk_finding_status(client, args): try: response = client.update_risk_status(finding_id, status) # Format the response for display - headers = ["Risk Finding ID", "Old Status", "New Status"] - data = { - "Risk Finding ID": response.get("riskFindingId"), - "Old Status": response.get("oldStatus"), - "New Status": response.get("newStatus"), - } - - markdown = tableToMarkdown("Risk Status Update", [data], headers=headers, headerTransform=pascalToSpace) + markdown = tableToMarkdown("Risk Status Update", [response], headerTransform=pascalToSpace) return CommandResults( readable_output=markdown, outputs_prefix="DSPM.RiskFindingStatusUpdate", outputs_key_field="riskFindingId", - outputs=data, + outputs=response, + raw_response=response ) except Exception as e: return_error( @@ -618,38 +561,38 @@ def get_list_of_alerts( ) -> list[dict]: """fetch list of dspm alerts""" # check supported cloud providers - cloudProviderIn = args.get("cloudProviderIn", "") - cloudProviderEqual = args.get("cloudProviderEqual", "") + cloud_provider_in = args.get("cloud_provider_in", "") + cloud_provider_equal = args.get("cloud_provider_equal", "") validate_parameter( - "cloudProvider", cloudProviderIn, cloudProviderEqual, SUPPORTED_CLOUD_PROVIDERS + "cloudProvider", cloud_provider_in, cloud_provider_equal, SUPPORTED_CLOUD_PROVIDERS ) # check supported cloud environments - cloudEnvironmentIn = args.get("cloudEnvironmentIn", "") - cloudEnvironmentEqual = args.get("cloudEnvironmentEqual", "") + cloud_environment_in = args.get("cloud_environment_in", "") + cloud_environment_equal = args.get("cloud_environment_equal", "") validate_parameter( - "cloudEnvironment", cloudEnvironmentIn, cloudEnvironmentEqual, SUPPORTED_CLOUD_ENVIRONMENTS + "cloudEnvironment", cloud_environment_in, cloud_environment_equal, SUPPORTED_CLOUD_ENVIRONMENTS ) # check supported policy severity - policySeverityIn = args.get("policySeverityIn", "") - policySeverityEqual = args.get("policySeverityEqual", "") + policy_severity_in = args.get("policy_severity_in", "") + policy_severity_equal = args.get("policy_severity_equal", "") validate_parameter( - "policySeverity", policySeverityIn, policySeverityEqual, SUPPORTED_POLICY_SEVERITIES + "policySeverity", policy_severity_in, policy_severity_equal, SUPPORTED_POLICY_SEVERITIES ) # check supported category type - categoryTypeIn = args.get("categoryTypeIn", "") - categoryTypeEqual = args.get("categoryTypeEqual", "") + category_type_in = args.get("category_type_in", "") + category_type_equal = args.get("category_type_equal", "") validate_parameter( - "categoryType", categoryTypeIn, categoryTypeEqual, SUPPORTED_CATEGORY_TYPES + "categoryType", category_type_in, category_type_equal, SUPPORTED_CATEGORY_TYPES ) # check supported category type - statusIn = args.get("statusIn", "") - statusEqual = args.get("statusEqual", "") + status_in = args.get("status_in", "") + status_equal = args.get("status_equal", "") validate_parameter( - "status", statusIn, statusEqual, SUPPORTED_STATUSES + "status", status_in, status_equal, SUPPORTED_STATUSES ) # Check supported sorting order @@ -661,27 +604,27 @@ def get_list_of_alerts( raise ValueError(f'This "{sort_order}" sorting order is not supported') params = { - "detectionTime.equals": args.get("detectionTimeEquals"), - "detectionTime.greaterThanOrEqual": args.get("detectionTimeGreaterThanOrEqual"), - "detectionTime.greaterThan": args.get("detectionTimeGreaterThan"), - "detectionTime.lessThanOrEqual": args.get("detectionTimeLessThanOrEqual"), - "detectionTime.lessThan": args.get("detectionTimeLessThan"), - "policyName.in": args.get("policyNameIn"), - "policyName.equals": args.get("policyNameEquals"), - "assetName.in": args.get("assetNameIn"), - "assetName.equals": args.get("assetNameEquals"), - "cloudProvider.in": args.get("cloudProviderIn"), - "cloudProvider.equals": args.get("cloudProviderEquals"), - "destinationProjectVendorName.in": args.get("destinationProjectVendorNameIn"), - "destinationProjectVendorName.equals": args.get("destinationProjectVendorNameEquals"), - "cloudEnvironment.in": args.get("cloudEnvironmentIn"), - "cloudEnvironment.equals": args.get("cloudEnvironmentEquals"), - "policySeverity.in": args.get("policySeverityIn"), - "policySeverity.equals": args.get("policySeverityEquals"), - "categoryType.in": args.get("categoryTypeIn"), - "categoryType.equals": args.get("categoryTypeEquals"), - "status.in": args.get("statusIn"), - "status.equals": args.get("statusEquals"), + "detectionTime.equals": args.get("detection_time_equals"), + "detectionTime.greaterThanOrEqual": args.get("detection_time_greater_than_or_equal"), + "detectionTime.greaterThan": args.get("detection_time_greater_than"), + "detectionTime.lessThanOrEqual": args.get("detection_time_less_than_or_equal"), + "detectionTime.lessThan": args.get("detection_time_less_than"), + "policyName.in": args.get("policy_name_in"), + "policyName.equals": args.get("policy_name_equals"), + "assetName.in": args.get("asset_name_in"), + "assetName.equals": args.get("asset_name_equals"), + "cloudProvider.in": args.get("cloud_provider_in"), + "cloudProvider.equals": args.get("cloud_provider_equals"), + "destinationProjectVendorName.in": args.get("destination_project_vendor_name_in"), + "destinationProjectVendorName.equals": args.get("destination_project_vendor_name_equals"), + "cloudEnvironment.in": args.get("cloud_environment_in"), + "cloudEnvironment.equals": args.get("cloud_environment_equals"), + "policySeverity.in": args.get("policy_severity_in"), + "policySeverity.equals": args.get("policy_severity_equals"), + "categoryType.in": args.get("category_type_in"), + "categoryType.equals": args.get("category_type_equals"), + "status.in": args.get("status_in"), + "status.equals": args.get("status_equals"), "sort": args.get("sort"), "page": page, "size": MAX_PAGE_SIZE @@ -695,7 +638,7 @@ def get_list_of_alerts( def update_dspm_alert_status(client, args): - alert_id = args.get("alertId") + alert_id = args.get("alert_id") status = args.get("status") if status and status not in SUPPORTED_STATUSES: raise ValueError(f'This "{status}" status is not supported') @@ -703,20 +646,15 @@ def update_dspm_alert_status(client, args): try: response = client.update_alert_status(alert_id, status) # Format the response for display - headers = ["Alert ID", "Old Status", "New Status"] - data = { - "Alert ID": response.get("alertId"), - "Old Status": response.get("oldStatus"), - "New Status": response.get("newStatus"), - } - markdown = tableToMarkdown("Alert Status Update", [data], headers=headers, headerTransform=pascalToSpace) + markdown = tableToMarkdown("Alert Status Update", [response], headerTransform=pascalToSpace) return CommandResults( readable_output=markdown, outputs_prefix="DSPM.AlertStatusUpdate", outputs_key_field="alertId", - outputs=data, + outputs=response, + raw_response=response ) except Exception as e: return_error( @@ -727,7 +665,6 @@ def update_dspm_alert_status(client, args): def get_integration_config(): integration_config = { - "dspmApiKey": demisto.params().get("dspmApiKey", {}).get("password"), "slackMsgLifetime": demisto.params().get("slackMsgLifetime"), "defaultSlackUser": demisto.params().get("defaultSlackUser"), } @@ -749,6 +686,7 @@ def get_integration_config(): outputs_prefix="DSPM.IntegrationConfig", outputs_key_field="config", outputs={"integration_config": integration_config}, + raw_response=integration_config ) @@ -761,162 +699,177 @@ def get_list_of_labels(client: Client): table_name = "Labels" headers = ['No', 'Key'] - if labels_formatted: - readable_output = tableToMarkdown(table_name, labels_formatted, headers=headers) - else: - readable_output = tableToMarkdown(table_name, "No data found", headers=headers) + readable_output = tableToMarkdown(table_name, labels_formatted, headers=headers) return CommandResults( - outputs_prefix="DSPM.Labels", + outputs_prefix="DSPM.Label", outputs_key_field="Key", outputs=labels_formatted, readable_output=readable_output, + raw_response=labels ) -def dspm_get_risk_findings_command(client, args): +def dspm_list_risk_findings_command(client, args): + limit = args.get("limit", DEFAULT_LIMIT) + if not limit.isdigit(): + raise ValueError("The 'limit' parameter must be an integer.") + limit = int(limit) page = 0 - headers = ["ID", "Rule Name", "Severity", "Asset Name", "Asset ID", "Status", "Project ID", - "Cloud Provider", "Cloud Environment", "First Discovered", "Compliance Standards"] - while True: - findings = dspm_get_risk_findings(client, args, page) + findings_collected: list = [] + + while len(findings_collected) < limit: + findings = get_list_risk_findings(client, args, page) if not findings: - if page == 0: + if page == 0 and not findings_collected: demisto.info("No risks were fetched") - readable_output = tableToMarkdown("Risk Findings", [], headers=headers, headerTransform=pascalToSpace) return_results( CommandResults( - outputs_prefix="DSPM.RiskFindings", - outputs_key_field="id", - readable_output=readable_output, + readable_output="No Risk Findings found." ) ) break # No more findings to fetch - readable_output = tableToMarkdown("Risk Findings", findings, headers=headers, headerTransform=pascalToSpace) - return_results( - CommandResults( - outputs_prefix="DSPM.RiskFindings", - outputs_key_field="id", - outputs=findings, - readable_output=readable_output, - ) - ) + findings_collected.extend(findings) + if len(findings_collected) >= limit: + break + page += 1 + # Trim findings to match the limit + findings_collected = findings_collected[:limit] + + # Prepare the readable output + readable_output = tableToMarkdown("Risk Findings", findings_collected, headerTransform=pascalToSpace) -def dspm_get_list_of_assets_command(client, args): + # Return a single CommandResults with all findings + return CommandResults( + outputs_prefix="DSPM.RiskFinding", + outputs_key_field="id", + outputs=findings_collected, + readable_output=readable_output, + raw_response=findings_collected + ) + + +def dspm_list_assets_command(client, args): + limit = args.get("limit", DEFAULT_LIMIT) + if not limit.isdigit(): + raise ValueError("The 'limit' parameter must be an integer.") + limit = int(limit) page = 0 - headers = ["ID", "Project ID", "Project Name", "Name", "Cloud Provider", "Cloud Environment", "Service Type", - "Lifecycle", "Open Risks Count", "Open Alerts Count", "Encrypted", "Open To World", - "Tags", "Asset Dig Tags"] - while True: + collected_assets: list = [] + + while len(collected_assets) < limit: assets = get_list_of_assets(client, args, page) if not assets: - if page == 0: - readable_output = tableToMarkdown("List of assets", [], headers=headers, headerTransform=pascalToSpace) - + if page == 0 and not collected_assets: return_results( CommandResults( - outputs_prefix="DSPM.Assets", - outputs_key_field="id", - outputs=[], - readable_output=readable_output, + readable_output="No assets found." ) ) break - readable_output = tableToMarkdown("List of assets", assets, headers=headers, headerTransform=pascalToSpace) + collected_assets.extend(assets) + if len(collected_assets) >= limit: + break - return_results( - CommandResults( - outputs_prefix="DSPM.Assets", - outputs_key_field="id", - outputs=assets, - readable_output=readable_output, - ) - ) page += 1 + # Trim the results to match the limit + collected_assets = collected_assets[:limit] + + # Generate readable output + readable_output = tableToMarkdown("List of Assets", collected_assets, headerTransform=pascalToSpace) + + # Return the collected assets directly without parsing + return CommandResults( + outputs_prefix="DSPM.Asset", + outputs_key_field="id", + outputs=collected_assets, + readable_output=readable_output, + raw_response=collected_assets + ) + -def dspm_get_data_types_findings_command(client, args): +def dspm_list_data_types_findings_command(client, args): + limit = args.get("limit", DEFAULT_LIMIT) + if not limit.isdigit(): + raise ValueError("The 'limit' parameter must be an integer.") + limit = int(limit) page = 0 - all_data_type_findings = [] - headers = ['No', 'Key'] + collected_data_types: list = [] - while True: + while len(collected_data_types) < limit: data_type_findings = get_data_type_findings( client, args, page ) - if not data_type_findings: - if page == 0: - readable_output = tableToMarkdown("Data Types", [], headers=headers) + if page == 0 and not collected_data_types: return_results( CommandResults( - outputs_prefix="DSPM.DataTypesFindings", - outputs_key_field="Key", - outputs=[], - readable_output=readable_output, + readable_output="No Data Types findings found.", ) ) break - all_data_type_findings.extend(data_type_findings) + collected_data_types.extend(data_type_findings) + if len(collected_data_types) >= limit: + break - data_type_findings_formatted = [ - { - "No": index + 1 + (page * MAX_PAGE_SIZE), - "Key": dt["dataTypeName"], - } - for index, dt in enumerate(data_type_findings) - ] - - readable_output = tableToMarkdown("Data Types", data_type_findings_formatted, headers=headers) - return_results( - CommandResults( - outputs_prefix="DSPM.DataTypesFindings", - outputs_key_field="Key", - outputs=data_type_findings_formatted, - readable_output=readable_output, - ) - ) page += 1 + # Trim the results to match the limit + collected_data_types = collected_data_types[:limit] + + readable_output = tableToMarkdown("Data Types Finding", collected_data_types, headerTransform=pascalToSpace) + return CommandResults( + outputs_prefix="DSPM.DataTypesFinding", + outputs_key_field="dataTypeName", + outputs=collected_data_types, + readable_output=readable_output, + raw_response=collected_data_types + ) + -def dspm_get_list_of_alerts_command(client, args): +def dspm_list_alerts_command(client, args): + limit = args.get("limit", DEFAULT_LIMIT) + if not limit.isdigit(): + raise ValueError("The 'limit' parameter must be an integer.") + limit = int(limit) page = 0 - headers = ["id", "detectionTime", "policyName", "assetName", "assetLabels", "cloudProvider", "destinationProjects", - "cloudEnvironment", "policySeverity", "policyCategoryType", "status", "eventActor", "eventUserAgent", - "eventActionMedium", "eventSource", "policyFrameWorks", "eventRawData"] - while True: + collected_alerts: list = [] + + while len(collected_alerts) < limit: alerts = get_list_of_alerts(client, args, page) if not alerts: - if page == 0: - readable_output = tableToMarkdown("List Of Alerts", [], headers=headers, headerTransform=pascalToSpace) - + if page == 0 and not collected_alerts: return_results( CommandResults( - outputs_prefix="DSPM.Alerts", - outputs_key_field="id", - outputs=[], - readable_output=readable_output, + readable_output="No alerts found.", ) ) break - readable_output = tableToMarkdown("List Of Alerts", alerts, headers=headers, headerTransform=pascalToSpace) - return_results( - CommandResults( - outputs_prefix="DSPM.Alerts", - outputs_key_field="id", - outputs=alerts, - readable_output=readable_output, - ) - ) + collected_alerts.extend(alerts) + if len(collected_alerts) >= limit: + break page += 1 + # Trim the results to match the limit + collected_alerts = collected_alerts[:limit] + + readable_output = tableToMarkdown("List Of Alerts", collected_alerts, headerTransform=pascalToSpace) + return CommandResults( + outputs_prefix="DSPM.Alert", + outputs_key_field="id", + outputs=collected_alerts, + readable_output=readable_output, + raw_response=collected_alerts + ) + def dspm_get_list_of_asset_fields_command(client: Client, args: dict[str, Any]) -> CommandResults: asset_id = args.get("assetId", None) @@ -1003,14 +956,14 @@ def main() -> None: # # labels-resource # - elif demisto.command() == "dspm-get-list-of-labels": + elif demisto.command() == "dspm-list-labels": return_results(get_list_of_labels(client)) # # risk-resource # - elif demisto.command() == "dspm-get-risk-findings": - return_results(dspm_get_risk_findings_command(client, demisto.args())) + elif demisto.command() == "dspm-list-risk-findings": + return_results(dspm_list_risk_findings_command(client, demisto.args())) elif demisto.command() == "dspm-get-risk-finding-by-id": return_results(get_risk_finding_by_id(client, demisto.args())) elif demisto.command() == "dspm-update-risk-finding-status": @@ -1020,8 +973,8 @@ def main() -> None: # asset-resource # - elif demisto.command() == "dspm-get-list-of-assets": - return_results(dspm_get_list_of_assets_command(client, demisto.args())) + elif demisto.command() == "dspm-list-assets": + return_results(dspm_list_assets_command(client, demisto.args())) elif demisto.command() == "dspm-get-asset-details": return_results(get_asset_details(client, demisto.args())) @@ -1038,16 +991,16 @@ def main() -> None: # # data-type-findings-resource # - elif demisto.command() == "dspm-get-data-types-findings": - return_results(dspm_get_data_types_findings_command(client, demisto.args())) + elif demisto.command() == "dspm-list-data-types-findings": + return_results(dspm_list_data_types_findings_command(client, demisto.args())) # # alert-resource # elif demisto.command() == "dspm-update-alert-status": return_results(update_dspm_alert_status(client, demisto.args())) - elif demisto.command() == "dspm-get-list-of-alerts": - return_results(dspm_get_list_of_alerts_command(client, demisto.args())) + elif demisto.command() == "dspm-list-alerts": + return_results(dspm_list_alerts_command(client, demisto.args())) except Exception as e: return_error( diff --git a/Packs/DSPM/Integrations/DSPM/DSPM.yml b/Packs/DSPM/Integrations/DSPM/DSPM.yml index 54149cf1cdf..260afb2c424 100644 --- a/Packs/DSPM/Integrations/DSPM/DSPM.yml +++ b/Packs/DSPM/Integrations/DSPM/DSPM.yml @@ -45,47 +45,47 @@ script: - arguments: - description: 'List of rule names.' isArray: true - name: ruleNameIn + name: rule_name_in required: false secret: false - description: 'Exact rule name.' isArray: false - name: ruleNameEqual + name: rule_name_equal required: false secret: false - description: 'List of DSPM tag keys.' isArray: true - name: dspmTagKeyIn + name: dspm_tag_key_in required: false secret: false - description: 'Exact DSPM tag key.' isArray: false - name: dspmTagKeyEqual + name: dspm_tag_key_equal required: false secret: false - description: 'List of DSPM tag values.' isArray: true - name: dspmTagValueIn + name: dspm_tag_value_in required: false secret: false - description: 'Exact DSPM tag value.' isArray: false - name: dspmTagValueEqual + name: dspm_tag_value_equal required: false secret: false - description: 'List of project IDs.' isArray: true - name: projectIdIn + name: projectId_in required: false secret: false - description: 'Exact project ID.' isArray: false - name: projectIdEqual + name: projectId_equal required: false secret: false - description: 'List of cloud providers ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"].' isArray: false - name: cloudProviderIn + name: cloud_provider_in required: false secret: false auto: PREDEFINED @@ -99,7 +99,7 @@ script: defaultValue: 'AWS' - description: 'Exact cloud provider ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"].' isArray: false - name: cloudProviderEqual + name: cloud_provider_equal required: false secret: false auto: PREDEFINED @@ -112,7 +112,7 @@ script: - 'O365' - description: 'List of affects ["SECURITY", "COMPLIANCE", "GOVERNANCE", "SECURITY_AND_COMPLIANCE", "SECURITY_AND_GOVERNANCE", "COMPLIANCE_AND_GOVERNANCE","SECURITY_AND_COMPLIANCE_AND_GOVERNANCE"].' isArray: true - name: affectsIn + name: affects_in required: false secret: false auto: PREDEFINED @@ -126,7 +126,7 @@ script: - 'SECURITY_AND_COMPLIANCE_AND_GOVERNANCE' - description: 'Exact affect ["SECURITY", "COMPLIANCE", "GOVERNANCE", "SECURITY_AND_COMPLIANCE", "SECURITY_AND_GOVERNANCE", "COMPLIANCE_AND_GOVERNANCE","SECURITY_AND_COMPLIANCE_AND_GOVERNANCE"].' isArray: false - name: affectsEqual + name: affects_equal required: false secret: false auto: PREDEFINED @@ -140,7 +140,7 @@ script: - 'SECURITY_AND_COMPLIANCE_AND_GOVERNANCE' - description: 'List of statuses ["OPEN", "CLOSED", "UNIMPORTANT", "WRONG", "HANDLED", "INVESTIGATING"].' isArray: true - name: statusIn + name: status_in required: false secret: false auto: PREDEFINED @@ -153,7 +153,7 @@ script: - 'INVESTIGATING' - description: 'Exact status ["OPEN", "CLOSED", "UNIMPORTANT", "WRONG", "HANDLED", "INVESTIGATING"].' isArray: false - name: statusEqual + name: status_equal required: false secret: false auto: PREDEFINED @@ -169,40 +169,43 @@ script: name: sort required: false secret: false + - description: 'The maximum number of risk findings to retrieve. If not specified, the default value is 50.' + isArray: false + name: limit + required: false + secret: false + defaultValue: 50 description: Retrieves risk findings matching the input criteria. - name: dspm-get-risk-findings + name: dspm-list-risk-findings outputs: - - contextPath: DSPM.RiskFindings.AssetID - description: 'The ID of the asset associated with the risk finding.' - type: String - - contextPath: DSPM.RiskFindings.AssetName - description: 'The name of the asset associated with the risk finding.' - type: String - - contextPath: DSPM.RiskFindings.CloudEnvironment + - contextPath: DSPM.RiskFinding.asset + description: 'The asset details associated with the risk finding.' + type: Unknown + - contextPath: DSPM.RiskFinding.cloudEnvironment description: 'The cloud environment (public or private) associated with the risk finding.' type: String - - contextPath: DSPM.RiskFindings.CloudProvider + - contextPath: DSPM.RiskFinding.cloudProvider description: 'The cloud provider associated with the risk finding (e.g., AWS, Azure, GCP).' type: String - - contextPath: DSPM.RiskFindings.ComplianceStandards + - contextPath: DSPM.RiskFinding.complianceStandards description: 'The compliance standards relevant to the risk finding.' type: Unknown - - contextPath: DSPM.RiskFindings.FirstDiscovered + - contextPath: DSPM.RiskFinding.firstDiscovered description: 'The date the risk finding was first discovered.' type: Date - - contextPath: DSPM.RiskFindings.ID + - contextPath: DSPM.RiskFinding.id description: 'The unique ID of the risk finding.' type: String - - contextPath: DSPM.RiskFindings.ProjectID + - contextPath: DSPM.RiskFinding.projectId description: 'The project ID where the asset resides.' type: String - - contextPath: DSPM.RiskFindings.RuleName + - contextPath: DSPM.RiskFinding.ruleName description: 'The rule name associated with the risk finding.' type: String - - contextPath: DSPM.RiskFindings.Severity + - contextPath: DSPM.RiskFinding.severity description: 'The severity of the risk finding (e.g., Low, Medium, High).' type: String - - contextPath: DSPM.RiskFindings.Status + - contextPath: DSPM.RiskFinding.status description: 'The current status of the risk finding (e.g., Open, Closed).' type: String - arguments: @@ -212,54 +215,51 @@ script: description: Retrieves the details of a risk for the provided risk ID. name: dspm-get-risk-finding-by-id outputs: - - contextPath: DSPM.RiskFinding.AssetID - description: 'The ID of the asset associated with the risk finding.' - type: String - - contextPath: DSPM.RiskFinding.AssetName - description: 'The name of the asset associated with the risk finding.' - type: String - - contextPath: DSPM.RiskFinding.CloudEnvironment + - contextPath: DSPM.RiskFinding.asset + description: 'The asset details associated with the risk finding.' + type: Unknown + - contextPath: DSPM.RiskFinding.cloudEnvironment description: 'The cloud environment (public or private) associated with the risk finding.' type: String - - contextPath: DSPM.RiskFinding.CloudProvider + - contextPath: DSPM.RiskFinding.cloudProvider description: 'The cloud provider associated with the risk finding (e.g., AWS, Azure, GCP).' type: String - - contextPath: DSPM.RiskFinding.ComplianceStandards + - contextPath: DSPM.RiskFinding.complianceStandards description: 'The compliance standards relevant to the risk finding.' type: Unknown - - contextPath: DSPM.RiskFinding.FirstDiscovered + - contextPath: DSPM.RiskFinding.firstDiscovered description: 'The date the risk finding was first discovered.' type: Date - - contextPath: DSPM.RiskFinding.ID + - contextPath: DSPM.RiskFinding.id description: 'The unique ID of the risk finding.' type: String - - contextPath: DSPM.RiskFinding.ProjectID + - contextPath: DSPM.RiskFinding.projectId description: 'The project ID where the asset resides.' type: String - - contextPath: DSPM.RiskFinding.RuleName + - contextPath: DSPM.RiskFinding.ruleName description: 'The rule name associated with the risk finding.' type: String - - contextPath: DSPM.RiskFinding.Severity + - contextPath: DSPM.RiskFinding.severity description: 'The severity of the risk finding (e.g., Low, Medium, High).' type: String - - contextPath: DSPM.RiskFinding.Status + - contextPath: DSPM.RiskFinding.status description: 'The current status of the risk finding (e.g., Open, Closed).' type: String - arguments: - description: List of regions (comma separated values). isArray: false - name: regionIn + name: region_in required: false secret: false - description: Exact region. isArray: false - name: regionEqual + name: region_equal required: false secret: false - description: 'List of cloud providers ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"] (comma separated values).' isArray: false - name: cloudProviderIn + name: cloud_provider_in required: false secret: false auto: PREDEFINED @@ -273,7 +273,7 @@ script: - description: 'Exact cloud provider ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"].' isArray: false - name: cloudProviderEqual + name: cloud_provider_equal required: false secret: false auto: PREDEFINED @@ -286,17 +286,17 @@ script: - 'O365' - description: List of Service Types (comma separated values). isArray: false - name: serviceTypeIn + name: service_type_in required: false secret: false - description: Exact Service Type. isArray: false - name: serviceTypeEqual + name: service_type_equal required: false secret: false - description: List of Life Cycles egs.['RUNNING', 'STOPPED', 'DELETED'](comma separated values). isArray: false - name: lifecycleIn + name: lifecycle_in required: false secret: false auto: PREDEFINED @@ -306,7 +306,7 @@ script: - 'DELETED' - description: Exact Life Cycle ['RUNNING', 'STOPPED', 'DELETED']. isArray: false - name: lifecycleEqual + name: lifecycle_equal required: false secret: false auto: PREDEFINED @@ -320,49 +320,61 @@ script: name: sort required: false secret: false + - description: 'The maximum number of assets to retrieve. If not specified, the default value is 50.' + isArray: false + name: limit + required: false + secret: false + defaultValue: 50 description: Retrieves a list of assets for the company. - name: dspm-get-list-of-assets + name: dspm-list-assets outputs: - - contextPath: DSPM.Assets.AssetDigTags - description: 'Digital tags associated with the asset.' + - contextPath: DSPM.Asset.dataTypes + description: 'dataTypes associated with the asset.' type: Unknown - - contextPath: DSPM.Assets.CloudEnvironment + - contextPath: DSPM.Asset.dataTypeGroups + description: 'dataTypeGroups associated with the asset.' + type: Unknown + - contextPath: DSPM.Asset.assetDigTags + description: 'Dig tags associated with the asset.' + type: Unknown + - contextPath: DSPM.Asset.cloudEnvironment description: 'The cloud environment in which the asset exists.' type: String - - contextPath: DSPM.Assets.CloudProvider + - contextPath: DSPM.Asset.cloudProvider description: 'The cloud provider for the asset.' type: String - - contextPath: DSPM.Assets.Encrypted + - contextPath: DSPM.Asset.encrypted description: 'Indicates if the asset is encrypted.' type: Boolean - - contextPath: DSPM.Assets.ID + - contextPath: DSPM.Asset.id description: 'The unique identifier of the asset.' type: String - - contextPath: DSPM.Assets.Lifecycle + - contextPath: DSPM.Asset.lifecycle description: 'Lifecycle status of the asset.' type: String - - contextPath: DSPM.Assets.Name + - contextPath: DSPM.Asset.name description: 'The name of the asset.' type: String - - contextPath: DSPM.Assets.OpenAlertsCount + - contextPath: DSPM.Asset.openAlertsCount description: 'The count of open alerts for the asset.' type: Number - - contextPath: DSPM.Assets.OpenRisksCount + - contextPath: DSPM.Asset.openRisksCount description: 'The count of open risks for the asset.' type: Number - - contextPath: DSPM.Assets.OpenToWorld + - contextPath: DSPM.Asset.openToWorld description: 'Indicates if the asset is open to the world.' type: Boolean - - contextPath: DSPM.Assets.ProjectID + - contextPath: DSPM.Asset.projectId description: 'The ID of the project associated with the asset.' type: String - - contextPath: DSPM.Assets.ProjectName + - contextPath: DSPM.Asset.projectName description: 'The name of the project associated with the asset.' type: String - - contextPath: DSPM.Assets.ServiceType + - contextPath: DSPM.Asset.serviceType description: 'The type of service associated with the asset.' type: String - - contextPath: DSPM.Assets.Tags + - contextPath: DSPM.Asset.tags description: 'Tags related to the asset.' type: Unknown - arguments: @@ -373,7 +385,7 @@ script: name: dspm-get-asset-details outputs: - contextPath: DSPM.AssetDetails.assetDigTags - description: 'The digital tags associated with the asset.' + description: 'The dig tags associated with the asset.' type: Unknown - contextPath: DSPM.AssetDetails.cloudEnvironment description: 'The cloud environment in which the asset exists.' @@ -527,7 +539,7 @@ script: type: Number - arguments: [] description: Returns list of label names based on company - name: dspm-get-list-of-labels + name: dspm-list-labels outputs: - contextPath: DSPM.Label.Key description: 'Label key.' @@ -537,17 +549,17 @@ script: - arguments: - description: List of regions (comma-separated values). isArray: false - name: regionIn + name: region_in required: false secret: false - description: Exact region. isArray: false - name: regionEqual + name: region_equal required: false secret: false - description: 'List of cloud providers ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"].' isArray: false - name: cloudProviderIn + name: cloud_provider_in required: false secret: false auto: PREDEFINED @@ -561,7 +573,7 @@ script: - description: 'Exact cloud provider ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"].' isArray: false - name: cloudProviderEqual + name: cloud_provider_equal required: false secret: false auto: PREDEFINED @@ -574,32 +586,32 @@ script: - 'O365' - description: List of Service Types (comma separated values). isArray: false - name: serviceTypeIn + name: service_type_in required: false secret: false - description: Exact Service Type. isArray: false - name: serviceTypeEqual + name: service_type_equal required: false secret: false - description: List of Life Cycles (comma separated values). isArray: false - name: lifecycleIn + name: lifecycle_in required: false secret: false - description: 'List of project IDs.' isArray: true - name: projectIdIn + name: projectId_in required: false secret: false - description: 'Exact project ID.' isArray: false - name: projectIdEqual + name: projectId_equal required: false secret: false - description: Exact Life Cycle. isArray: false - name: lifecycleEqual + name: lifecycle_equal required: false secret: false - description: 'Sorting criteria in the format: property,(asc|desc). Default sort @@ -608,15 +620,48 @@ script: name: sort required: false secret: false + - description: 'The maximum number of data types findings to retrieve. If not specified, the default value is 50.' + isArray: false + name: limit + required: false + secret: false + defaultValue: 50 description: Retrieves a list of data type findings for the company. - name: dspm-get-data-types-findings + name: dspm-list-data-types-findings outputs: - - contextPath: DSPM.DataTypeFindings.Key - description: 'Data type finding key.' - type: String - - contextPath: DSPM.DataTypeFindings.No - description: 'Data type finding number.' - type: Number + - contextPath: DSPM.DataTypesFinding.dataTypeName + description: 'Represents the name of the data type being analyzed.' + type: String + - contextPath: DSPM.DataTypesFinding.label + description: 'Label associated with the data type, such as PII.' + type: String + - contextPath: DSPM.DataTypesFinding.records + description: 'The number of records associated with the data type.' + type: Integer + - contextPath: DSPM.DataTypesFinding.publicRecords + description: 'The number of public records found for this data type.' + type: Integer + - contextPath: DSPM.DataTypesFinding.assets + description: 'The number of assets associated with this data type.' + type: Integer + - contextPath: DSPM.DataTypesFinding.clouds + description: 'The clouds where the data type was found (e.g., AWS, Azure).' + type: String + - contextPath: DSPM.DataTypesFinding.regions + description: 'The regions where the data type was found.' + type: String + - contextPath: DSPM.DataTypesFinding.lastFound + description: 'The timestamp when the data type was last found.' + type: Date + - contextPath: DSPM.DataTypesFinding.recordsAtRisk.high + description: 'The number of high-risk records found for this data type.' + type: Integer + - contextPath: DSPM.DataTypesFinding.recordsAtRisk.medium + description: 'The number of medium-risk records found for this data type.' + type: Integer + - contextPath: DSPM.DataTypesFinding.recordsAtRisk.low + description: 'The number of low-risk records found for this data type.' + type: Integer - arguments: [] description: Retrieves integration configuration. name: dspm-get-integration-config @@ -627,7 +672,7 @@ script: - arguments: - description: 'Risk Finding ID.' isArray: false - name: riskFindingId + name: risk_finding_id required: true - description: 'List of supported status [ "OPEN", "CLOSED", "UNIMPORTANT", "WRONG", "HANDLED", "INVESTIGATING" ].' isArray: false @@ -657,7 +702,7 @@ script: - arguments: - description: 'Alert ID.' isArray: false - name: alertId + name: alert_id required: true - description: 'List of supported status [ "OPEN", "UNIMPORTANT", "WRONG", "HANDLED", "INVESTIGATING" ].' isArray: false @@ -686,52 +731,52 @@ script: - arguments: - description: 'Exact detection time (equals).' isArray: false - name: detectionTimeEquals + name: detection_time_equals required: false secret: false - description: 'Detection time (greater than or equal).' isArray: false - name: detectionTimeGreaterThanOrEqual + name: detection_time_greater_than_or_equal required: false secret: false - description: 'Detection time (greater than).' isArray: false - name: detectionTimeGreaterThan + name: detection_time_greater_than required: false secret: false - description: 'Detection time (less than or equal).' isArray: false - name: detectionTimeLessThanOrEqual + name: detection_time_less_than_or_equal required: false secret: false - description: 'Detection time (less than).' isArray: false - name: detectionTimeLessThan + name: detection_time_less_than required: false secret: false - description: 'List of policy names.' isArray: true - name: policyNameIn + name: policy_name_in required: false secret: false - description: 'Exact policy name.' isArray: false - name: policyNameEquals + name: policy_name_equals required: false secret: false - description: 'List of asset names.' isArray: true - name: assetNameIn + name: asset_name_in required: false secret: false - description: 'Exact asset name.' isArray: false - name: assetNameEquals + name: asset_name_equals required: false secret: false - description: 'List of cloud providers ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"].' isArray: true - name: cloudProviderIn + name: cloud_provider_in required: false secret: false auto: PREDEFINED @@ -744,7 +789,7 @@ script: - 'O365' - description: 'Exact cloud provider ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"].' isArray: false - name: cloudProviderEquals + name: cloud_provider_equals required: false secret: false auto: PREDEFINED @@ -757,17 +802,17 @@ script: - 'O365' - description: 'List of destination project vendor names.' isArray: true - name: destinationProjectVendorNameIn + name: destination_project_vendor_name_in required: false secret: false - description: 'Exact destination project vendor name.' isArray: false - name: destinationProjectVendorNameEquals + name: destination_project_vendor_name_equals required: false secret: false - description: 'List of cloud environments ["UNKNOWN", "DEVELOPMENT", "STAGING", "TESTING", "PRODUCTION"].' isArray: true - name: cloudEnvironmentIn + name: cloud_environment_in required: false secret: false auto: PREDEFINED @@ -779,7 +824,7 @@ script: - 'PRODUCTION' - description: 'Exact cloud environment ["UNKNOWN", "DEVELOPMENT", "STAGING", "TESTING", "PRODUCTION"].' isArray: false - name: cloudEnvironmentEquals + name: cloud_environment_equals required: false secret: false auto: PREDEFINED @@ -791,7 +836,7 @@ script: - 'PRODUCTION' - description: 'List of policy severities ["HIGH", "MEDIUM", "LOW"].' isArray: true - name: policySeverityIn + name: policy_severity_in required: false secret: false auto: PREDEFINED @@ -801,7 +846,7 @@ script: - 'LOW' - description: 'Exact policy severity ["HIGH", "MEDIUM", "LOW"].' isArray: false - name: policySeverityEquals + name: policy_severity_equals required: false secret: false auto: PREDEFINED @@ -811,7 +856,7 @@ script: - 'LOW' - description: 'List of category types ["FIRST_MOVE", "ATTACK", "COMPLIANCE", "ASSET_AT_RISK", "RECONNAISSANCE"].' isArray: true - name: categoryTypeIn + name: category_type_in required: false secret: false auto: PREDEFINED @@ -823,7 +868,7 @@ script: - 'RECONNAISSANCE' - description: 'Exact category type ["FIRST_MOVE", "ATTACK", "COMPLIANCE", "ASSET_AT_RISK", "RECONNAISSANCE"].' isArray: false - name: categoryTypeEquals + name: category_type_equals required: false secret: false auto: PREDEFINED @@ -835,7 +880,7 @@ script: - 'RECONNAISSANCE' - description: 'List of statuses ["OPEN", "UNIMPORTANT", "WRONG", "HANDLED", "INVESTIGATING"].' isArray: true - name: statusIn + name: status_in required: false secret: false auto: PREDEFINED @@ -848,7 +893,7 @@ script: - 'INVESTIGATING' - description: 'Exact status ["OPEN", "UNIMPORTANT", "WRONG", "HANDLED", "INVESTIGATING"].' isArray: false - name: statusEquals + name: status_equals required: false secret: false auto: PREDEFINED @@ -864,58 +909,64 @@ script: name: sort required: false secret: false + - description: 'The maximum number of alerts to retrieve. If not specified, the default value is 50.' + isArray: false + name: limit + required: false + secret: false + defaultValue: 50 description: Fetch list of alerts. - name: dspm-get-list-of-alerts + name: dspm-list-alerts outputs: - - contextPath: DSPM.Alerts.id + - contextPath: DSPM.Alert.id description: 'Alert ID.' type: String - - contextPath: DSPM.Alerts.detectionTime + - contextPath: DSPM.Alert.detectionTime description: 'Alert detection time.' type: Date - - contextPath: DSPM.Alerts.policyName + - contextPath: DSPM.Alert.policyName description: 'Alert policy name.' type: String - - contextPath: DSPM.Alerts.assetName + - contextPath: DSPM.Alert.assetName description: 'Alert asset name.' type: String - - contextPath: DSPM.Alerts.assetLabels + - contextPath: DSPM.Alert.assetLabels description: 'Alert asset label.' type: Unknown - - contextPath: DSPM.Alerts.cloudProvider + - contextPath: DSPM.Alert.cloudProvider description: 'Alert cloud provider.' type: String - - contextPath: DSPM.Alerts.destinationProjects + - contextPath: DSPM.Alert.destinationProjects description: 'Alert destination projects.' type: Unknown - - contextPath: DSPM.Alerts.cloudEnvironment + - contextPath: DSPM.Alert.cloudEnvironment description: 'Alert cloud enviroment.' type: String - - contextPath: DSPM.Alerts.policySeverity + - contextPath: DSPM.Alert.policySeverity description: 'Alert policy severity.' type: String - - contextPath: DSPM.Alerts.policyCategoryType + - contextPath: DSPM.Alert.policyCategoryType description: 'Alert policy category type.' type: String - - contextPath: DSPM.Alerts.status + - contextPath: DSPM.Alert.status description: 'Alert status.' type: String - - contextPath: DSPM.Alerts.eventActor + - contextPath: DSPM.Alert.eventActor description: 'Alert event actor.' type: String - - contextPath: DSPM.Alerts.eventUserAgent + - contextPath: DSPM.Alert.eventUserAgent description: 'Alert event user agent.' type: String - - contextPath: DSPM.Alerts.eventActionMedium + - contextPath: DSPM.Alert.eventActionMedium description: 'Alert event action medium.' type: String - - contextPath: DSPM.Alerts.eventSource + - contextPath: DSPM.Alert.eventSource description: 'Alert event source.' type: String - - contextPath: DSPM.Alerts.policyFrameWorks + - contextPath: DSPM.Alert.policyFrameWorks description: 'Alert policy frameworks.' type: String - - contextPath: DSPM.Alerts.eventRawData + - contextPath: DSPM.Alert.eventRawData description: 'Alert event raw data.' type: String diff --git a/Packs/DSPM/Integrations/DSPM/DSPM_test.py b/Packs/DSPM/Integrations/DSPM/DSPM_test.py index 1e6e38d1ab3..f87c627c1a7 100644 --- a/Packs/DSPM/Integrations/DSPM/DSPM_test.py +++ b/Packs/DSPM/Integrations/DSPM/DSPM_test.py @@ -7,7 +7,7 @@ get_list_of_assets, get_asset_files_by_id, test_module, - dspm_get_risk_findings, + get_list_risk_findings, get_asset_details, update_risk_finding_status, get_data_types, @@ -17,10 +17,10 @@ update_dspm_alert_status, get_risk_finding_by_id, validate_parameter, - dspm_get_risk_findings_command, - dspm_get_list_of_assets_command, - dspm_get_data_types_findings_command, - dspm_get_list_of_alerts_command, + dspm_list_risk_findings_command, + dspm_list_assets_command, + dspm_list_data_types_findings_command, + dspm_list_alerts_command, dspm_get_list_of_asset_fields_command ) @@ -68,36 +68,38 @@ def test_test_module(client, mocker): def test_dspm_get_risk_findings(client): expected_output = { - "ID": "7e9a3891-8970-4c08-961a-03f49e239d68", - "Rule Name": "Sensitive asset without storage versioning", - "Severity": "MEDIUM", - "Asset Name": "****", - "Asset ID": "****", - "Status": "OPEN", - "Project ID": "****", - "Cloud Provider": "AZURE", - "Cloud Environment": "DEVELOPMENT", - "First Discovered": "2024-04-25T17:08:11.020304Z", - "Compliance Standards": {} + "id": "7e9a3891-8970-4c08-961a-03f49e239d68", + "ruleName": "Sensitive asset without storage versioning", + "severity": "MEDIUM", + "asset": { + "name": "****", + "assetId": "****" + }, + "status": "OPEN", + "projectId": "****", + "cloudProvider": "AZURE", + "cloudEnvironment": "DEVELOPMENT", + "firstDiscovered": "2024-04-25T17:08:11.020304Z", + "complianceStandards": {} } args = { - "ruleNameIn": "InvalidRule,AnotherInvalidRule", - "ruleNameEqual": "NotARealRule", - "dspmTagKeyIn": "InvalidKey,AnotherInvalidKey", - "dspmTagKeyEqual": "NotARealKey", - "dspmTagValueIn": "InvalidValue,AnotherInvalidValue", - "dspmTagValueEqual": "NotARealValue", - "projectIdIn": "InvalidProjectID123", - "projectIdEqual": "NotARealProjectID", - "cloudProviderIn": "AWS,AZURE", - "cloudProviderEqual": "AZURE", - "affectsIn": "SECURITY,COMPLIANCE", - "affectsEqual": "SECURITY", - "statusIn": "OPEN", - "statusEqual": "OPEN", + "rule_name_in": "InvalidRule,AnotherInvalidRule", + "rule_name_equal": "NotARealRule", + "dspm_tag_key_in": "InvalidKey,AnotherInvalidKey", + "dspm_tag_key_equal": "NotARealKey", + "dspm_tag_value_in": "InvalidValue,AnotherInvalidValue", + "dspm_tag_value_equal": "NotARealValue", + "projectId_in": "InvalidProjectID123", + "projectId_equal": "NotARealProjectID", + "cloud_provider_in": "AWS,AZURE", + "cloud_provider_equal": "AZURE", + "affects_in": "SECURITY,COMPLIANCE", + "affects_equal": "SECURITY", + "status_in": "OPEN", + "status_equal": "OPEN", "sort": "status,desc" } - result = dspm_get_risk_findings(client, args, page=0) + result = get_list_risk_findings(client, args, page=0) finding = result[0] # type: ignore assert isinstance(result, List) @@ -105,37 +107,47 @@ def test_dspm_get_risk_findings(client): # Check the structure of one finding required_keys = [ - 'ID', 'Rule Name', 'Severity', 'Asset Name', 'Asset ID', - 'Status', 'Project ID', 'Cloud Provider', 'Cloud Environment', - 'First Discovered', 'Compliance Standards' + 'id', 'ruleName', 'severity', 'asset', + 'status', 'projectId', 'cloudProvider', 'cloudEnvironment', + 'firstDiscovered', 'complianceStandards' ] assert all(key in finding for key in required_keys) def test_dspm_get_risk_findings_with_valid_args(client): expected_output = { - "ID": "7e9a3891-8970-4c08-961a-03f49e239d68", - "Rule Name": "Sensitive asset without storage versioning", - "Severity": "MEDIUM", - "Asset Name": "****", - "Asset ID": "****", - "Status": "OPEN", - "Project ID": "****", - "Cloud Provider": "AZURE", - "Cloud Environment": "DEVELOPMENT", - "First Discovered": "2024-04-25T17:08:11.020304Z", - "Compliance Standards": {} + "id": "7e9a3891-8970-4c08-961a-03f49e239d68", + "ruleName": "Sensitive asset without storage versioning", + "severity": "MEDIUM", + "asset": { + "name": "****", + "assetId": "****" + }, + "status": "OPEN", + "projectId": "****", + "cloudProvider": "AZURE", + "cloudEnvironment": "DEVELOPMENT", + "firstDiscovered": "2024-04-25T17:08:11.020304Z", + "complianceStandards": {} + } + args = { + "cloud_provider_in": "AWS,AZURE", + "affects_in": "SECURITY,COMPLIANCE", + "status_in": "OPEN,CLOSED", + "sort": "records,asc" } - args = {"cloudProviderIn": "AWS,AZURE", "affectsIn": "SECURITY,COMPLIANCE", - "statusIn": "OPEN,CLOSED", "sort": "records,asc"} - result = dspm_get_risk_findings(client, args, page=0) + result = get_list_risk_findings(client, args, page=0) assert isinstance(result, List) assert result[0] == expected_output - args = {"cloudProviderEqual": "AWS", "affectsEqual": "SECURITY", - "statusEqual": "OPEN", "sort": "records,desc"} - result = dspm_get_risk_findings(client, args, page=0) + args = { + "cloud_provider_equal": "AWS", + "affects_equal": "SECURITY", + "status_equal": "OPEN", + "sort": "records,desc" + } + result = get_list_risk_findings(client, args, page=0) assert isinstance(result, List) assert result[0] == expected_output @@ -144,19 +156,19 @@ def test_dspm_get_risk_findings_with_valid_args(client): def test_dspm_get_risk_findings_with_invalid_args(client): test_cases = [ - ({"cloudProviderIn": "AWS,AZURE12"}, 'This "AZURE12" cloudProvider is not supported'), - ({"cloudProviderEqual": "INVALID"}, 'This "INVALID" cloudProvider is not supported'), - ({"affectsIn": "SECURITY,INVALID"}, 'This "INVALID" affects is not supported'), - ({"affectsEqual": "WRONG"}, 'This "WRONG" affects is not supported'), - ({"statusIn": "INVALID,CLOSED"}, 'This "INVALID" status is not supported'), - ({"statusEqual": "IN"}, 'This "IN" status is not supported'), + ({"cloud_provider_in": "AWS,AZURE12"}, 'This "AZURE12" cloudProvider is not supported'), + ({"cloud_provider_equal": "INVALID"}, 'This "INVALID" cloudProvider is not supported'), + ({"affects_in": "SECURITY,INVALID"}, 'This "INVALID" affects is not supported'), + ({"affects_equal": "WRONG"}, 'This "WRONG" affects is not supported'), + ({"status_in": "INVALID,CLOSED"}, 'This "INVALID" status is not supported'), + ({"status_equal": "IN"}, 'This "IN" status is not supported'), ({"sort": "records,wrongOrder"}, 'This "records,wrongOrder" sorting order is not supported'), ] # Iterate over the test cases for args, expected_error in test_cases: with pytest.raises(ValueError, match=expected_error): - dspm_get_risk_findings(client, args, 0) + get_list_risk_findings(client, args, 0) def test_get_list_of_assets_with_valid_args(client): @@ -182,27 +194,35 @@ def test_get_list_of_assets_with_valid_args(client): }] client.get_asset_lists = MagicMock(return_value=mock_response) - args = {"cloudProviderIn": "AWS,AZURE", "serviceTypeIn": "EFS,RDS", - "lifecycleIn": "RUNNING,STOPPED", "sort": "name,DESC"} + args = { + "cloud_provider_in": "AWS,AZURE", + "service_type_in": "EFS,RDS", + "lifecycle_in": "RUNNING,STOPPED", + "sort": "status,DESC" + } result = get_list_of_assets(client, args, page=0) assert isinstance(result, List) - assert result[0].get('ID') == "asset2" + assert result[0].get('id') == "asset2" - args = {"cloudProviderEqual": "AWS", "serviceTypeEqual": "RDS", - "lifecycleEqual": "RUNNING", "sort": "name,ASC"} + args = { + "cloud_provider_equal": "AWS", + "service_type_equal": "RDS", + "lifecycle_equal": "RUNNING", + "sort": "status,ASC" + } result = get_list_of_assets(client, args, page=0) assert isinstance(result, List) - assert result[0].get('ID') == "asset2" + assert result[0].get('id') == "asset2" def test_get_list_of_assets_with_invalid_args(client): # List of invalid args and their expected error messages invalid_test_cases = [ - ({"cloudProviderIn": "INVALID_CLOUD_PROVIDER"}, 'This "INVALID_CLOUD_PROVIDER" cloudProvider is not supported'), - ({"serviceTypeIn": "INVALID_SERVICE_TYPE"}, 'This "INVALID_SERVICE_TYPE" serviceType is not supported'), - ({"lifecycleIn": "INVALID_LIFECYCLE"}, 'This "INVALID_LIFECYCLE" lifecycle is not supported'), + ({"cloud_provider_in": "INVALID_CLOUD_PROVIDER"}, 'This "INVALID_CLOUD_PROVIDER" cloudProvider is not supported'), + ({"service_type_in": "INVALID_SERVICE_TYPE"}, 'This "INVALID_SERVICE_TYPE" serviceType is not supported'), + ({"lifecycle_in": "INVALID_LIFECYCLE"}, 'This "INVALID_LIFECYCLE" lifecycle is not supported'), ({"sort": "invalid_sort_order"}, 'This "invalid_sort_order" sorting order is not supported'), ] @@ -213,15 +233,15 @@ def test_get_list_of_assets_with_invalid_args(client): def test_get_data_type_findings_with_valid_args(client): - args = {"cloudProviderIn": "AWS,AZURE", "serviceTypeIn": "DYNAMODB,RDS", - "lifecycleIn": "DELETED,STOPPED", "sort": "records,DESC"} + args = {"cloud_provider_in": "AWS,AZURE", "service_type_in": "DYNAMODB,RDS", + "lifecycle_in": "DELETED,STOPPED", "sort": "records,DESC"} result = get_data_type_findings(client, args, page=0) assert isinstance(result, List) assert len(result) == 4 - args = {"cloudProviderEqual": "AWS", "serviceTypeEqual": "DYNAMODB", - "lifecycleEqual": "DELETED", "sort": "records,ASC"} + args = {"cloud_provider_equal": "AWS", "service_type_equal": "DYNAMODB", + "lifecycle_equal": "DELETED", "sort": "records,ASC"} result = get_data_type_findings(client, args, page=0) assert isinstance(result, List) @@ -231,9 +251,9 @@ def test_get_data_type_findings_with_valid_args(client): def test_get_data_type_findings_with_invalid_args(client): # List of invalid args and their expected error messages invalid_test_cases = [ - ({"cloudProviderIn": "INVALID_CLOUD_PROVIDER"}, 'This "INVALID_CLOUD_PROVIDER" cloudProvider is not supported'), - ({"serviceTypeIn": "INVALID_SERVICE_TYPE"}, 'This "INVALID_SERVICE_TYPE" serviceType is not supported'), - ({"lifecycleIn": "INVALID_LIFECYCLE"}, 'This "INVALID_LIFECYCLE" lifecycle is not supported'), + ({"cloud_provider_in": "INVALID_CLOUD_PROVIDER"}, 'This "INVALID_CLOUD_PROVIDER" cloudProvider is not supported'), + ({"service_type_in": "INVALID_SERVICE_TYPE"}, 'This "INVALID_SERVICE_TYPE" serviceType is not supported'), + ({"lifecycle_in": "INVALID_LIFECYCLE"}, 'This "INVALID_LIFECYCLE" lifecycle is not supported'), ({"sort": "invalid_sort_order"}, 'This "invalid_sort_order" sorting order is not supported'), ] @@ -284,12 +304,12 @@ def test_get_list_of_alerts_with_valid_args(client): client.get_alerts_list = MagicMock(return_value=mock_response) args = { - "cloudProviderIn": "AWS,AZURE", - "cloudEnvironmentIn": "DEVELOPMENT,STAGING", - "policySeverityIn": "MEDIUM,LOW", - "categoryTypeIn": "ATTACK,FIRST_MOVE", - "statusIn": "CLOSED,OPEN", - "sort": "name,DESC" + "cloud_provider_in": "AWS,AZURE", + "cloud_environment_in": "DEVELOPMENT,STAGING", + "policy_severity_in": "MEDIUM,LOW", + "category_type_in": "ATTACK,FIRST_MOVE", + "status_in": "CLOSED,OPEN", + "sort": "status,DESC" } result = get_list_of_alerts(client, args, 0) @@ -297,12 +317,12 @@ def test_get_list_of_alerts_with_valid_args(client): assert result[0].get('id') == "274314608" args = { - "cloudProviderEqual": "AWS", - "cloudEnvironmentEqual": "STAGING", - "policySeverityEqual": "MEDIUM", - "categoryTypeEqual": "FIRST_MOVE", - "statusEqual": "OPEN", - "sort": "name,ASC" + "cloud_provider_equal": "AWS", + "cloud_environment_equal": "STAGING", + "policy_severity_equal": "MEDIUM", + "category_type_equal": "FIRST_MOVE", + "status_equal": "OPEN", + "sort": "status,ASC" } result = get_list_of_alerts(client, args, 0) @@ -352,16 +372,16 @@ def test_get_list_of_alerts_with_invalid_args(client): # List of test cases with invalid args and expected error messages test_cases = [ - ({"cloudProviderIn": "AWS,AZURE12"}, 'This "AZURE12" cloudProvider is not supported'), - ({"cloudEnvironmentIn": "Wrong,AZURE1"}, 'This "Wrong" cloudEnvironment is not supported'), - ({"policySeverityIn": "AWS32"}, 'This "AWS32" policySeverity is not supported'), - ({"categoryTypeIn": "AWS,INVALID"}, 'This "AWS" categoryType is not supported'), - ({"statusIn": "IN,OPEN"}, 'This "IN" status is not supported'), - ({"cloudProviderEqual": "AZURE12"}, 'This "AZURE12" cloudProvider is not supported'), - ({"cloudEnvironmentEqual": "Wrong"}, 'This "Wrong" cloudEnvironment is not supported'), - ({"policySeverityEqual": "AWS32"}, 'This "AWS32" policySeverity is not supported'), - ({"categoryTypeEqual": "AWS"}, 'This "AWS" categoryType is not supported'), - ({"statusEqual": "IN"}, 'This "IN" status is not supported') + ({"cloud_provider_in": "AWS,AZURE12"}, 'This "AZURE12" cloudProvider is not supported'), + ({"cloud_environment_in": "Wrong,AZURE1"}, 'This "Wrong" cloudEnvironment is not supported'), + ({"policy_severity_in": "AWS32"}, 'This "AWS32" policySeverity is not supported'), + ({"category_type_in": "AWS,INVALID"}, 'This "AWS" categoryType is not supported'), + ({"status_in": "IN,OPEN"}, 'This "IN" status is not supported'), + ({"cloud_provider_equal": "AZURE12"}, 'This "AZURE12" cloudProvider is not supported'), + ({"cloud_environment_equal": "Wrong"}, 'This "Wrong" cloudEnvironment is not supported'), + ({"policy_severity_equal": "AWS32"}, 'This "AWS32" policySeverity is not supported'), + ({"category_type_equal": "AWS"}, 'This "AWS" categoryType is not supported'), + ({"status_equal": "IN"}, 'This "IN" status is not supported') ] # Iterate over the test cases @@ -419,7 +439,7 @@ def test_get_labels(client): result = get_list_of_labels(client) assert isinstance(result, CommandResults) - assert result.outputs_prefix == 'DSPM.Labels' + assert result.outputs_prefix == 'DSPM.Label' assert result.outputs_key_field == 'Key' assert result.outputs == [{"No": 1, "Key": "label1"}, {"No": 2, "Key": "label2"}, {"No": 3, "Key": "label3"}] @@ -429,7 +449,7 @@ def test_get_labels_empty_response(client): result = get_list_of_labels(client) assert isinstance(result, CommandResults) - assert result.outputs_prefix == 'DSPM.Labels' + assert result.outputs_prefix == 'DSPM.Label' assert result.outputs_key_field == 'Key' assert result.outputs == [] @@ -439,7 +459,7 @@ def test_get_labels_single_label(client): result = get_list_of_labels(client) assert isinstance(result, CommandResults) - assert result.outputs_prefix == 'DSPM.Labels' + assert result.outputs_prefix == 'DSPM.Label' assert result.outputs_key_field == 'Key' assert result.outputs == [{"No": 1, "Key": "Label1"}] @@ -614,14 +634,12 @@ def test_get_asset_files_by_id_with_invalid_key_name(client): @patch('DSPM.demisto') def test_get_integration_config(mock_demisto): mock_params = { - "dspmApiKey": {"password": "mocked_dspm_api_key"}, "slackMsgLifetime": 4, "defaultSlackUser": "mock_user" } expected_result = { "integration_config": { "defaultSlackUser": "mock_user", - "dspmApiKey": "mocked_dspm_api_key", "slackMsgLifetime": 4 } } @@ -645,11 +663,11 @@ def test_get_list_of_assets_empty_response(client, mocker): # Define the arguments for the command args = { - 'regionIn': 'us-east', - 'cloudProviderIn': 'AWS', - 'serviceTypeEqual': 'UNMANAGED_AWS_REDIS', - 'digTagKeyContains': 'env', - 'lifecycleIn': 'RUNNING', + 'region_in': 'us-east', + 'cloud_provider_in': 'AWS', + 'service_type_equal': 'UNMANAGED_AWS_REDIS', + 'dig_tag_key_contains': 'env', + 'lifecycle_in': 'RUNNING', 'sort': 'status,DESC', 'size': 10 } @@ -715,20 +733,20 @@ def test_get_list_of_assets_empty_response(client, mocker): ], [ { - 'ID': 'asset1', - 'Project ID': 'project1', - 'Project Name': 'Project One', - 'Name': 'Asset One', - 'Cloud Provider': 'GCP', - 'Cloud Environment': 'TESTING', - 'Service Type': 'UNMANAGED_GCP_MS_SQL', - 'Lifecycle': 'RUNNING', - 'Open Risks Count': 5, - 'Open Alerts Count': 3, - 'Encrypted': True, - 'Open To World': False, - 'Tags': {"example_tag_key": "example_tag_value"}, - 'Asset Dig Tags': [ + 'id': 'asset1', + 'projectId': 'project1', + 'projectName': 'Project One', + 'name': 'Asset One', + 'cloudProvider': 'GCP', + 'cloudEnvironment': 'TESTING', + 'serviceType': 'UNMANAGED_GCP_MS_SQL', + 'lifecycle': 'RUNNING', + 'openRisksCount': 5, + 'openAlertsCount': 3, + 'encrypted': True, + 'openToWorld': False, + 'tags': {"example_tag_key": "example_tag_value"}, + 'assetDigTags': [ {"digTagId": 1, "key": "tag1", "value": "value1"}, {"digTagId": 2, "key": "tag2", "value": "value2"} ] @@ -743,20 +761,20 @@ def test_get_list_of_assets_empty_response(client, mocker): ], [ { - 'ID': 'asset1', - 'Project ID': 'project1', - 'Project Name': 'Project One', - 'Name': 'Asset One', - 'Cloud Provider': 'GCP', - 'Cloud Environment': 'TESTING', - 'Service Type': 'UNMANAGED_GCP_MS_SQL', - 'Lifecycle': 'RUNNING', - 'Open Risks Count': 5, - 'Open Alerts Count': 3, - 'Encrypted': True, - 'Open To World': False, - 'Tags': {"example_tag_key": "example_tag_value"}, - 'Asset Dig Tags': [ + 'id': 'asset1', + 'projectId': 'project1', + 'projectName': 'Project One', + 'name': 'Asset One', + 'cloudProvider': 'GCP', + 'cloudEnvironment': 'TESTING', + 'serviceType': 'UNMANAGED_GCP_MS_SQL', + 'lifecycle': 'RUNNING', + 'openRisksCount': 5, + 'openAlertsCount': 3, + 'encrypted': True, + 'openToWorld': False, + 'tags': {"example_tag_key": "example_tag_value"}, + 'assetDigTags': [ {"digTagId": 1, "key": "tag1", "value": "value1"}, {"digTagId": 2, "key": "tag2", "value": "value2"} ] @@ -791,7 +809,7 @@ def test_get_asset_details(mocker): def test_update_risk_status_with_valid_status(client): - args = {'riskFindingId': '1', 'status': 'INVESTIGATING'} + args = {'risk_finding_id': '1', 'status': 'INVESTIGATING'} mock_response = { "riskFindingId": '1', @@ -799,27 +817,22 @@ def test_update_risk_status_with_valid_status(client): "newStatus": 'INVESTIGATING', } - expected_output = { - "Risk Finding ID": '1', - "Old Status": 'OPEN', - "New Status": 'INVESTIGATING', - } client = MagicMock() client.update_risk_status.return_value = mock_response result = update_risk_finding_status(client, args) - assert result.outputs == expected_output + assert result.outputs == mock_response def test_update_alert_status_invalid_status(client): - args = {'alertId': '1', 'status': 'INVALID_STATUS'} + args = {'alert_id': '1', 'status': 'INVALID_STATUS'} with pytest.raises(ValueError, match='This "INVALID_STATUS" status is not supported'): update_dspm_alert_status(client, args) def test_update_alert_status_valid_status(client): - args = {'alertId': '1', 'status': 'INVESTIGATING'} + args = {'alert_id': '1', 'status': 'INVESTIGATING'} mock_response = { "alertId": '1', @@ -827,16 +840,11 @@ def test_update_alert_status_valid_status(client): "newStatus": 'INVESTIGATING', } - expected_output = { - "Alert ID": '1', - "Old Status": 'OPEN', - "New Status": 'INVESTIGATING', - } client = MagicMock() client.update_alert_status.return_value = mock_response result = update_dspm_alert_status(client, args) - assert result.outputs == expected_output + assert result.outputs == mock_response def test_get_risk_finding_by_id_with_missing_id(client): @@ -862,25 +870,13 @@ def test_risk_finding_by_id_with_valid_id(client): "firstDiscovered": "2024-04-25T17:08:11.020304Z", "complianceStandards": {} } - expected_output = { - "ID": "7e9a3891-8970-4c08-961a-03f49e239d68", - "Rule Name": "Sensitive asset without storage versioning", - "Severity": "MEDIUM", - "Asset Name": "****", - "Asset ID": "****", - "Status": "OPEN", - "Project ID": "****", - "Cloud Provider": "AZURE", - "Cloud Environment": "DEVELOPMENT", - "First Discovered": "2024-04-25T17:08:11.020304Z", - "Compliance Standards": {} - } + client = MagicMock() client.get_risk_information.return_value = mock_response args = {'finding_id': '7e9a3891-8970-4c08-961a-03f49e239d68'} result = get_risk_finding_by_id(client, args) - assert result.outputs == expected_output + assert result.outputs == mock_response def test_validate_parameter_valid_and_invalid(): @@ -934,26 +930,29 @@ def test_dspm_get_risk_findings_command(client): } ] args = { - "cloudProviderEqual": "AZURE", - "affectsEqual": "SECURITY", - "statusEqual": "OPEN", - "serviceTypeEqual": "UNMANAGED_AWS_REDIS", - "digTagKeyContains": "env", - "lifecycleIn": "RUNNING", + "cloud_provider_equal": "AZURE", + "affects_equal": "SECURITY", + "status_equal": "OPEN", + "service_type_equal": "UNMANAGED_AWS_REDIS", + "dig_tag_key_contains": "env", + "lifecycle_in": "RUNNING", "sort": "status,desc" } # Mock the client method client.fetch_risk_findings = MagicMock(side_effect=[mock_responses, None]) - with patch('DSPM.return_results') as mock_return_results: - dspm_get_risk_findings_command(client, args) - result = mock_return_results.call_args[0][0] + result = dspm_list_risk_findings_command(client, args) - # Assertions - assert isinstance(result, CommandResults) - assert result.outputs_prefix == "DSPM.RiskFindings" - assert result.outputs_key_field == "id" - assert len(result.outputs) == len(mock_responses) # type: ignore + # Assertions + assert isinstance(result, CommandResults) + assert result.outputs_prefix == "DSPM.RiskFinding" + assert result.outputs_key_field == "id" + assert len(result.outputs) == len(mock_responses) # type: ignore + + # with invalid - 'limit' param + with pytest.raises(ValueError, match="The 'limit' parameter must be an integer."): + args = {"limit": "123abc"} + dspm_list_risk_findings_command(client, args) def test_dspm_get_list_of_assets_command(client): @@ -997,26 +996,29 @@ def test_dspm_get_list_of_assets_command(client): } ] args = { - "cloudProviderEqual": "AZURE", - "affectsEqual": "SECURITY", - "statusEqual": "OPEN", - "serviceTypeEqual": "UNMANAGED_AWS_REDIS", - "digTagKeyContains": "env", - "lifecycleIn": "RUNNING", + "cloud_provider_equal": "AZURE", + "affects_equal": "SECURITY", + "status_equal": "OPEN", + "service_type_equal": "UNMANAGED_AWS_REDIS", + "dig_tag_key_contains": "env", + "lifecycle_in": "RUNNING", "sort": "status,desc" } # Mock the client method client.get_asset_lists = MagicMock(side_effect=[mock_responses, None]) - with patch('DSPM.return_results') as mock_return_results: - dspm_get_list_of_assets_command(client, args) - result = mock_return_results.call_args[0][0] + result = dspm_list_assets_command(client, args) + + # Assertions + assert isinstance(result, CommandResults) + assert result.outputs_prefix == "DSPM.Asset" + assert result.outputs_key_field == "id" + assert len(result.outputs) == len(mock_responses) # type: ignore - # Assertions - assert isinstance(result, CommandResults) - assert result.outputs_prefix == "DSPM.Assets" - assert result.outputs_key_field == "id" - assert len(result.outputs) == len(mock_responses) # type: ignore + # with invalid - 'limit' param + with pytest.raises(ValueError, match="The 'limit' parameter must be an integer."): + args = {"limit": "123abc"} + dspm_list_assets_command(client, args) def test_dspm_get_data_types_findings_command(client): @@ -1050,26 +1052,29 @@ def test_dspm_get_data_types_findings_command(client): } ] args = { - "cloudProviderEqual": "AZURE", - "affectsEqual": "SECURITY", - "statusEqual": "OPEN", - "serviceTypeEqual": "UNMANAGED_AWS_REDIS", - "digTagKeyContains": "env", - "lifecycleIn": "RUNNING", + "cloud_provider_equal": "AZURE", + "affects_equal": "SECURITY", + "status_equal": "OPEN", + "service_type_equal": "UNMANAGED_AWS_REDIS", + "dig_tag_key_contains": "env", + "lifecycle_in": "RUNNING", "sort": "status,desc" } # Mock the client method client.get_data_type_findings = MagicMock(side_effect=[mock_responses, None]) - with patch('DSPM.return_results') as mock_return_results: - dspm_get_data_types_findings_command(client, args) - result = mock_return_results.call_args[0][0] + result = dspm_list_data_types_findings_command(client, args) - # Assertions - assert isinstance(result, CommandResults) - assert result.outputs_prefix == "DSPM.DataTypesFindings" - assert result.outputs_key_field == "Key" - assert len(result.outputs) == len(mock_responses) # type: ignore + # Assertions + assert isinstance(result, CommandResults) + assert result.outputs_prefix == "DSPM.DataTypesFinding" + assert result.outputs_key_field == "dataTypeName" + assert len(result.outputs) == len(mock_responses) # type: ignore + + # with invalid - 'limit' param + with pytest.raises(ValueError, match="The 'limit' parameter must be an integer."): + args = {"limit": "123abc"} + dspm_list_data_types_findings_command(client, args) def test_dspm_get_list_of_alerts_command(client): @@ -1120,24 +1125,27 @@ def test_dspm_get_list_of_alerts_command(client): ] args = { - "cloudProviderEqual": "AZURE", - "policyNameIn": "SECURITY", - "statusEqual": "OPEN", - "assetNameIn": "assets1,assets2", - "cloudEnvironmentIn": "TESTING", - "policySeverityEquals": "HIGH", - "categoryTypeEquals": "FIRST_MOVE", + "cloud_provider_equal": "AZURE", + "policy_name_in": "SECURITY", + "status_equal": "OPEN", + "asset_name_in": "assets1,assets2", + "cloud_environment_in": "TESTING", + "policy_severity_equals": "HIGH", + "category_type_equals": "FIRST_MOVE", "sort": "status,desc" } # Mock the client method client.get_alerts_list = MagicMock(side_effect=[mock_responses, None]) - with patch('DSPM.return_results') as mock_return_results: - dspm_get_list_of_alerts_command(client, args) - result = mock_return_results.call_args[0][0] - - # Assertions - assert isinstance(result, CommandResults) - assert result.outputs_prefix == "DSPM.Alerts" - assert result.outputs_key_field == "id" - assert len(result.outputs) == len(mock_responses) # type: ignore + result = dspm_list_alerts_command(client, args) + + # Assertions + assert isinstance(result, CommandResults) + assert result.outputs_prefix == "DSPM.Alert" + assert result.outputs_key_field == "id" + assert len(result.outputs) == len(mock_responses) # type: ignore + + # with invalid - 'limit' param + with pytest.raises(ValueError, match="The 'limit' parameter must be an integer."): + args = {"limit": "123abc"} + dspm_list_alerts_command(client, args)(client, args) diff --git a/Packs/DSPM/Integrations/DSPM/README.md b/Packs/DSPM/Integrations/DSPM/README.md index 935ee7d5db0..cd0555ebd8a 100644 --- a/Packs/DSPM/Integrations/DSPM/README.md +++ b/Packs/DSPM/Integrations/DSPM/README.md @@ -26,9 +26,6 @@ The Prisma Cloud DSPM(Data Security Posture Management) Integration enhances the | DSPM server URL | The tenant URL of the Prisma Cloud DSPM | True | | DSPM API Key | API key to use for the connection | True | | Default Slack user for notifications | the default user to receive Slack notifications in case of any errors | True | - | Azure Storage Account name | | False | - | Azure Storage Shared Key | The shared API key available in the Azure Storage Account | False | - | GCP Service Account JSON | | False | | Lifetime for slack notification (in hours) | | True | | Trust any certificate (not secure) | | False | | Use system proxy settings | | False | @@ -42,71 +39,70 @@ Prisma Cloud DSPM pack allows the users to execute individual commands on the Co The following commands can be executed as a part of an automation or playbook. After you successfully execute a command, a DBot message appears in the War Room with the command details. -### dspm-get-risk-findings +### dspm-list-risk-findings *** Retrieves risk findings matching the input criteria. #### Base Command -`dspm-get-risk-findings` +`dspm-list-risk-findings` #### Input | **Argument Name** | **Description** | **Required** | | --- | --- | --- | -| ruleNameIn | List of rule names. | Optional | -| ruleNameEqual | Exact rule name. | Optional | -| dspmTagKeyIn | List of DSPM tag keys. | Optional | -| dspmTagKeyEqual | Exact DSPM tag key. | Optional | -| dspmTagValueIn | List of DSPM tag values. | Optional | -| dspmTagValueEqual | Exact DSPM tag value. | Optional | -| projectIdIn | List of project IDs. | Optional | -| projectIdEqual | Exact project ID. | Optional | -| cloudProviderIn | List of cloud providers ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"]. | Optional | -| cloudProviderEqual | Exact cloud provider ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"]. | Optional | -| affectsIn | List of affects ["SECURITY", "COMPLIANCE", "GOVERNANCE", "SECURITY_AND_COMPLIANCE", "SECURITY_AND_GOVERNANCE", "COMPLIANCE_AND_GOVERNANCE","SECURITY_AND_COMPLIANCE_AND_GOVERNANCE"]. | Optional | -| affectsEqual | Exact affect ["SECURITY", "COMPLIANCE", "GOVERNANCE", "SECURITY_AND_COMPLIANCE", "SECURITY_AND_GOVERNANCE", "COMPLIANCE_AND_GOVERNANCE","SECURITY_AND_COMPLIANCE_AND_GOVERNANCE"]. | Optional | -| statusIn | List of statuses ["OPEN", "CLOSED", "UNIMPORTANT", "WRONG", "HANDLED", "INVESTIGATING"]. | Optional | -| statusEqual | Exact status ["OPEN", "CLOSED", "UNIMPORTANT", "WRONG", "HANDLED", "INVESTIGATING"]. | Optional | +| rule_name_in | List of rule names. | Optional | +| rule_name_equal | Exact rule name. | Optional | +| dspm_tag_key_in | List of DSPM tag keys. | Optional | +| dspm_tag_key_equal | Exact DSPM tag key. | Optional | +| dspm_tag_value_in | List of DSPM tag values. | Optional | +| dspm_tag_value_equal | Exact DSPM tag value. | Optional | +| projectId_in | List of project IDs. | Optional | +| projectId_equal | Exact project ID. | Optional | +| limit | The maximum number of risk findings to retrieve. If not specified, the default value is 50. | Optional | +| cloud_provider_in | List of cloud providers ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"]. | Optional | +| cloud_provider_equal | Exact cloud provider ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"]. | Optional | +| affects_in | List of affects ["SECURITY", "COMPLIANCE", "GOVERNANCE", "SECURITY_AND_COMPLIANCE", "SECURITY_AND_GOVERNANCE", "COMPLIANCE_AND_GOVERNANCE","SECURITY_AND_COMPLIANCE_AND_GOVERNANCE"]. | Optional | +| affects_equal | Exact affect ["SECURITY", "COMPLIANCE", "GOVERNANCE", "SECURITY_AND_COMPLIANCE", "SECURITY_AND_GOVERNANCE", "COMPLIANCE_AND_GOVERNANCE","SECURITY_AND_COMPLIANCE_AND_GOVERNANCE"]. | Optional | +| status_in | List of statuses ["OPEN", "CLOSED", "UNIMPORTANT", "WRONG", "HANDLED", "INVESTIGATING"]. | Optional | +| status_equal | Exact status ["OPEN", "CLOSED", "UNIMPORTANT", "WRONG", "HANDLED", "INVESTIGATING"]. | Optional | | sort | Sort order. | Optional | #### Context Output | **Path** | **Type** | **Description** | | --- | --- | --- | -| DSPM.RiskFindings.ID | String |The unique ID of the risk finding. | -| DSPM.RiskFindings.AssetID | String |The ID of the asset associated with the risk finding. | -| DSPM.RiskFindings.AssetName | String |The name of the asset associated with the risk finding. | -| DSPM.RiskFindings.ComplianceStandards |String |The compliance standards relevant to the risk finding. | -| DSPM.RiskFindings.Severity | String |The severity of the risk finding (e.g., Low, Medium, High). | -| DSPM.RiskFindings.RuleName | String |The rule name associated with the risk finding. | -| DSPM.RiskFindings.FirstDiscovered | Date |The date the risk finding was first discovered. | -| DSPM.RiskFindings.CloudProvider | String |The cloud provider associated with the risk finding (e.g., AWS, Azure, GCP). | -| DSPM.RiskFindings.Status | String |The current status of the risk finding (e.g., Open, Closed). | -| DSPM.RiskFindings.CloudEnvironment | String |The cloud environment (public or private) associated with the risk finding. | -| DSPM.RiskFindings.ProjectID | String |The project ID where the asset resides. | +| DSPM.RiskFinding.id | String |The unique ID of the risk finding. | +| DSPM.RiskFinding.asset | String |The asset details associated with the risk finding. | +| DSPM.RiskFinding.complianceStandards |String |The compliance standards relevant to the risk finding. | +| DSPM.RiskFinding.severity | String |The severity of the risk finding (e.g., Low, Medium, High). | +| DSPM.RiskFinding.ruleName | String |The rule name associated with the risk finding. | +| DSPM.RiskFinding.firstDiscovered | Date |The date the risk finding was first discovered. | +| DSPM.RiskFinding.cloudProvider | String |The cloud provider associated with the risk finding (e.g., AWS, Azure, GCP). | +| DSPM.RiskFinding.status | String |The current status of the risk finding (e.g., Open, Closed). | +| DSPM.RiskFinding.cloudEnvironment | String |The cloud environment (public or private) associated with the risk finding. | +| DSPM.RiskFinding.projectId | String |The project ID where the asset resides. | #### Command example -```!dspm-get-risk-findings``` +```!dspm-list-risk-findings``` #### Context Example ```json { "DSPM": { - "RiskFindings": [ + "RiskFinding": [ { - "ID": "riskfinding123", - "AssetID": "asset123", - "AssetName": "Example Asset", - "ComplianceStandards": "PCI-DSS", - "Severity": "High", - "RuleName": "Sensitive Data Exposure", - "FirstDiscovered": "2024-09-01T12:00:00Z", - "CloudProvider": "AWS", - "Status": "Open", - "CloudEnvironment": "Public", - "ProjectID": "project123" - } + "id": "**************", + "ruleName": "Empty storage asset", + "severity": "LOW", + "asset": {}, + "status": "OPEN", + "projectId": "********", + "cloudProvider": "AWS", + "cloudEnvironment": "UNKNOWN", + "firstDiscovered": "2024-09-27T11:55:39.059125Z", + "complianceStandards": {} + } ] } } @@ -115,9 +111,9 @@ Retrieves risk findings matching the input criteria. #### Human Readable Output >### Results ->|Asset ID|Asset Name|Cloud Environment|Cloud Provider|Compliance Standards|First Discovered|ID|Project ID|Rule Name|Severity|Status| ->|---|---|---|---|---|---|---|---|---|---|---| ->| arn:aws:s3:::emptybucketdspm-test | emptybucketdspm-test | UNKNOWN | AWS | | 2024-09-05T13:40:33.565153Z | 00000000-0000-4f99-0000-616843b6b19e | 774305603864 | Empty storage asset | LOW | INVESTIGATING | +>|Asset|Cloud Environment|Cloud Provider|Compliance Standards|First Discovered|ID|Project ID|Rule Name|Severity|Status| +>|---|---|---|---|---|---|---|---|---|---| +>|{}|UNKNOWN|AWS|{}|2024-09-27T11:55:39.059125Z|00000000-0000-4f99-0000-616843b6b19e|********|Empty storage asset|LOW|OPEN| ### dspm-get-risk-finding-by-id @@ -139,17 +135,16 @@ Retrieves the details of a risk for the provided risk ID. | **Path** | **Type** | **Description** | | --- | --- | --- | -| DSPM.RiskFinding.ID | String |The unique ID of the risk finding. | -| DSPM.RiskFinding.AssetID | String |The ID of the asset associated with the risk finding. | -| DSPM.RiskFinding.AssetName | String |The name of the asset associated with the risk finding. | -| DSPM.RiskFinding.ComplianceStandards | String |The compliance standards relevant to the risk finding. | -| DSPM.RiskFinding.Severity | String |The severity of the risk finding (e.g., Low, Medium, High). | -| DSPM.RiskFinding.RuleName | String |The rule name associated with the risk finding. | -| DSPM.RiskFinding.FirstDiscovered | Date |The date the risk finding was first discovered. | -| DSPM.RiskFinding.CloudProvider | String |The cloud provider associated with the risk finding (e.g., AWS, Azure, GCP). | -| DSPM.RiskFinding.Status | String |The current status of the risk finding (e.g., Open, Closed). | -| DSPM.RiskFinding.CloudEnvironment | String |The cloud environment (public or private) associated with the risk finding. | -| DSPM.RiskFinding.ProjectID | String |The project ID where the asset resides. | +| DSPM.RiskFinding.id | String |The unique ID of the risk finding. | +| DSPM.RiskFinding.asset | String |The asset details associated with the risk finding. | +| DSPM.RiskFinding.complianceStandards | String |The compliance standards relevant to the risk finding. | +| DSPM.RiskFinding.severity | String |The severity of the risk finding (e.g., Low, Medium, High). | +| DSPM.RiskFinding.ruleName | String |The rule name associated with the risk finding. | +| DSPM.RiskFinding.firstDiscovered | Date |The date the risk finding was first discovered. | +| DSPM.RiskFinding.cloudProvider | String |The cloud provider associated with the risk finding (e.g., AWS, Azure, GCP). | +| DSPM.RiskFinding.status | String |The current status of the risk finding (e.g., Open, Closed). | +| DSPM.RiskFinding.cloudEnvironment | String |The cloud environment (public or private) associated with the risk finding. | +| DSPM.RiskFinding.projectId | String |The project ID where the asset resides. | #### Command example @@ -158,18 +153,17 @@ Retrieves the details of a risk for the provided risk ID. ```json { "DSPM": { - "RiskFinding": { - "Asset ID": "arn:aws:s3:::emptybucketdspm-test", - "Asset Name": "emptybucketdspm-test", - "Cloud Environment": "UNKNOWN", - "Cloud Provider": "AWS", - "Compliance Standards": {}, - "First Discovered": "2024-09-05T13:40:33.565153Z", - "ID": "00000000-0000-4f99-0000-616843b6b19e", - "Project ID": "774305603864", - "Rule Name": "Empty storage asset", - "Severity": "LOW", - "Status": "INVESTIGATING" + "RiskFinding": { + "id": "00000000-0000-4f99-0000-616843b6b19e", + "ruleName": "Empty storage asset", + "severity": "LOW", + "asset": {}, + "status": "OPEN", + "projectId": "********", + "cloudProvider": "AWS", + "cloudEnvironment": "UNKNOWN", + "firstDiscovered": "2024-09-27T11:55:39.059125Z", + "complianceStandards": {} } } } @@ -178,75 +172,80 @@ Retrieves the details of a risk for the provided risk ID. #### Human Readable Output >### Results ->|Asset ID|Asset Name|Cloud Environment|Cloud Provider|Compliance Standards|First Discovered|ID|Project ID|Rule Name|Severity|Status| ->|---|---|---|---|---|---|---|---|---|---|---| ->| arn:aws:s3:::emptybucketdspm-test | emptybucketdspm-test | UNKNOWN | AWS | | 2024-09-05T13:40:33.565153Z | 00000000-0000-4f99-0000-616843b6b19e | 774305603864 | Empty storage asset | LOW | INVESTIGATING | +>|Asset|Cloud Environment|Cloud Provider|Compliance Standards|First Discovered|ID|Project ID|Rule Name|Severity|Status| +>|---|---|---|---|---|---|---|---|---|---| +>|{}|UNKNOWN|AWS|{}|2024-09-27T11:55:39.059125Z|00000000-0000-4f99-0000-616843b6b19e|********|Empty storage asset|LOW|OPEN| -### dspm-get-list-of-assets +### dspm-list-assets *** Retrieves a list of assets for the company. #### Base Command -`dspm-get-list-of-assets` +`dspm-list-assets` #### Input | **Argument Name** | **Description** | **Required** | | --- | --- | --- | -| regionIn | List of regions (comma-separated values). | Optional | -| regionEqual | Exact region. | Optional | -| cloudProviderIn | List of cloud providers ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"] (comma separated values). | Optional | -| cloudProviderEqual | Exact cloud provider ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"]. | Optional | -| serviceTypeIn | List of Service Types (comma separated values). | Optional | -| serviceTypeEqual | Exact Service Type. | Optional | -| lifecycleIn | List of Life Cycles egs.['RUNNING', 'STOPPED', 'DELETED'](comma separated values). | Optional | -| lifecycleEqual | Exact Life Cycle ['RUNNING', 'STOPPED', 'DELETED']. | Optional | +| region_in | List of regions (comma-separated values). | Optional | +| region_equal | Exact region. | Optional | +| limit | The maximum number of assets to retrieve. If not specified, the default value is 50. | Optional | +| cloud_provider_in | List of cloud providers ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"] (comma separated values). | Optional | +| cloud_provider_equal | Exact cloud provider ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"]. | Optional | +| service_type_in | List of Service Types (comma separated values). | Optional | +| service_type_equal | Exact Service Type. | Optional | +| lifecycle_in | List of Life Cycles egs.['RUNNING', 'STOPPED', 'DELETED'](comma separated values). | Optional | +| lifecycle_equal | Exact Life Cycle ['RUNNING', 'STOPPED', 'DELETED']. | Optional | | sort | Sorting criteria in the format: property,(asc\|desc). Default sort order is ascending. Multiple sort criteria are supported. | Optional | #### Context Outputs | **Path** | **Type** | **Description** | | --- | --- | --- | -| DSPM.Assets.ProjectID | String | The ID of the project associated with the asset. | -| DSPM.Assets.OpenAlertsCount | Number | The count of open alerts for the asset. | -| DSPM.Assets.AssetDigTags | String | Digital tags associated with the asset. | -| DSPM.Assets.OpenToWorld | Boolean | Indicates if the asset is open to the world. | -| DSPM.Assets.OpenRisksCount | Number | The count of open risks for the asset. | -| DSPM.Assets.Lifecycle | String | Lifecycle status of the asset. | -| DSPM.Assets.ServiceType | String | The type of service associated with the asset. | -| DSPM.Assets.Tags | String | Tags related to the asset. | -| DSPM.Assets.ProjectName | String | The name of the project associated with the asset. | -| DSPM.Assets.CloudEnvironment | String | The cloud environment in which the asset exists. | -| DSPM.Assets.ID | String | The unique identifier of the asset. | -| DSPM.Assets.CloudProvider | String | The cloud provider for the asset. | -| DSPM.Assets.Encrypted | Boolean | Indicates if the asset is encrypted. | -| DSPM.Assets.Name | String | The name of the asset. | +| DSPM.Asset.projectId | String | The ID of the project associated with the asset. | +| DSPM.Asset.openAlertsCount | Number | The count of open alerts for the asset. | +| DSPM.Asset.assetDigTags | String | Dig tags associated with the asset. | +| DSPM.Asset.openToWorld | Boolean | Indicates if the asset is open to the world. | +| DSPM.Asset.openRisksCount | Number | The count of open risks for the asset. | +| DSPM.Asset.lifecycle | String | Lifecycle status of the asset. | +| DSPM.Asset.serviceType | String | The type of service associated with the asset. | +| DSPM.Asset.tags | String | Tags related to the asset. | +| DSPM.Asset.projectName | String | The name of the project associated with the asset. | +| DSPM.Asset.cloudEnvironment | String | The cloud environment in which the asset exists. | +| DSPM.Asset.id | String | The unique identifier of the asset. | +| DSPM.Asset.cloudProvider | String | The cloud provider for the asset. | +| DSPM.Asset.encrypted | Boolean | Indicates if the asset is encrypted. | +| DSPM.Asset.name | String | The name of the asset. | +| DSPM.Asset.dataTypeGroups | String | Groups of data types associated with the asset. | +| DSPM.Asset.dataTypes | String | Data types associated with the asset. | #### Command example -```!dspm-get-list-of-assets cloudProviderEqual=AWS serviceTypeEqual=S3``` +```!dspm-list-assets cloudProviderEqual=AWS serviceTypeEqual=S3``` #### Context Example ```json { "DSPM": { "Assets": { - "Asset Dig Tags": [], - "Cloud Environment": "TESTING", - "Cloud Provider": "AWS", - "Encrypted": true, - "ID": "arn:aws:s3:::dummyS3-cifp-us-east-1", - "Lifecycle": "RUNNING", - "Name": "appcomposer-ci0jq3kgvjnccdfp-us-east-1", - "Open Alerts Count": 0, - "Open Risks Count": 0, - "Open To World": false, - "Project ID": "590183896679", - "Project Name": "590183896679", - "Service Type": "S3", - "Tags": {} - } + "projectId": "************", + "projectName": "************", + "name": "dymmy-ci0jq3kgvjnccdfp-us-east-1", + "cloudProvider": "AWS", + "cloudEnvironment": "TESTING", + "serviceType": "S3", + "dataTypeGroups": [], + "dataTypes": [], + "lifecycle": "RUNNING", + "openRisksCount": 0, + "openAlertsCount": 0, + "encrypted": true, + "openToWorld": false, + "tags": {}, + "assetDigTags": [], + "id": "arn:aws:s3:::dymmy-ci0jq3kgvjnccdfp-us-east-1" + } } } ``` @@ -254,9 +253,9 @@ Retrieves a list of assets for the company. #### Human Readable Output >### Results ->|Asset Dig Tags|Cloud Environment|Cloud Provider|Encrypted|ID|Lifecycle|Name|Open Alerts Count|Open Risks Count|Open To World|Project ID|Project Name|Service Type|Tags| ->|---|---|---|---|---|---|---|---|---|---|---|---|---|---| ->| | TESTING | AWS | true | arn:aws:s3:::dummyS3-cifp-us-east-1 | RUNNING | appcomposer-ci0jq3kgvjnccdfp-us-east-1 | 0 | 0 | false | 590183896679 | 590183896679 | S3 | | +>|Asset Dig Tags|Cloud Environment|Cloud Provider|Encrypted|ID|Lifecycle|Name|Open Alerts Count|Open Risks Count|Open To World|Project ID|Project Name|Service Type|Tags|Data Type Groups|Data Types| +>|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---| +>| | TESTING | AWS | true | arn:aws:s3:::dymmy-ci0jq3kgvjnccdfp-us-east-1 | RUNNING | dymmy-ci0jq3kgvjnccdfp-us-east-1 | 0 | 0 | false | ************ | ************ | S3 | | | | ### dspm-get-asset-details @@ -278,7 +277,7 @@ Retrieves details for the specified asset ID | **Path** | **Type** | **Description** | | --- | --- | --- | -| DSPM.AssetDetails.assetDigTags | Unknown | The digital tags associated with the asset. | +| DSPM.AssetDetails.assetDigTags | Unknown | The dig tags associated with the asset. | | DSPM.AssetDetails.cloudEnvironment | String | The cloud environment in which the asset exists. | | DSPM.AssetDetails.cloudProvider | String | The cloud provider for the asset (e.g., AWS, Azure, GCP). | | DSPM.AssetDetails.dataTypeGroups | Unknown | Groups of data types associated with the asset. | @@ -310,12 +309,12 @@ Retrieves details for the specified asset ID "encrypted": true, "id": "arn:aws:s3:::dummyS3-cifp-us-east-1", "lifecycle": "RUNNING", - "name": "appcomposer-ci0jq3kgvjnccdfp-us-east-1", + "name": "dymmy-ci0jq3kgvjnccdfp-us-east-1", "openAlertsCount": 0, "openRisksCount": 0, "openToWorld": false, - "projectId": "590183896679", - "projectName": "590183896679", + "projectId": "************", + "projectName": "************", "serviceType": "S3", "tags": {} } @@ -328,7 +327,7 @@ Retrieves details for the specified asset ID >### Results >|assetDigTags|cloudEnvironment|cloudProvider|dataTypeGroups|dataTypes|encrypted|id|lifecycle|name|openAlertsCount|openRisksCount|openToWorld|projectId|projectName|serviceType|tags| >|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---| ->| | TESTING | AWS | | | true | arn:aws:s3:::dummyS3-cifp-us-east-1 | RUNNING | appcomposer-ci0jq3kgvjnccdfp-us-east-1 | 0 | 0 | false | 590183896679 | 590183896679 | S3 | | +>| | TESTING | AWS | | | true | arn:aws:s3:::dummyS3-cifp-us-east-1 | RUNNING | dymmy-ci0jq3kgvjnccdfp-us-east-1 | 0 | 0 | false | ************ | ************ | S3 | | ### dspm-get-asset-files-by-id @@ -607,11 +606,11 @@ There are no input arguments for this command. >| 5 | Certificate | -### dspm-get-list-of-labels +### dspm-list-labels #### Base Command -`dspm-get-list-of-labels` +`dspm-list-labels` #### Input @@ -625,7 +624,7 @@ There are no input arguments for this command. | DSPM.Label.No | Number | Data types number. | #### Command example -```!dspm-get-list-of-labels``` +```!dspm-list-labels``` #### Context Example ```json { @@ -668,50 +667,71 @@ There are no input arguments for this command. >| 5 | Sensitive | -### dspm-get-data-types-findings +### dspm-list-data-types-findings *** Retrieves a list of data type findings for the company. #### Base Command -`dspm-get-data-types-findings` +`dspm-list-data-types-findings` #### Input | **Argument Name** | **Description** | **Required** | | --- | --- | --- | -| regionIn | List of regions (comma-separated values). | Optional | -| regionEqual | Exact region. | Optional | -| cloudProviderIn | List of cloud providers ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"]. | Optional | -| cloudProviderEqual | Exact cloud provider ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"]. | Optional | -| serviceTypeIn | List of Service Types (comma separated values). | Optional | -| serviceTypeEqual | Exact Service Type. | Optional | -| lifecycleIn | List of Life Cycles (comma separated values). | Optional | -| projectIdIn | List of project IDs. | Optional | -| projectIdEqual | Exact project ID. | Optional | -| lifecycleEqual | Exact Life Cycle. | Optional | +| region_in | List of regions (comma-separated values). | Optional | +| region_equal | Exact region. | Optional | +| cloud_provider_in | List of cloud providers ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"]. | Optional | +| cloud_provider_equal | Exact cloud provider ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"]. | Optional | +| service_type_in | List of Service Types (comma separated values). | Optional | +| service_type_equal | Exact Service Type. | Optional | +| lifecycle_in | List of Life Cycles (comma separated values). | Optional | +| projectId_in | List of project IDs. | Optional | +| projectId_equal | Exact project ID. | Optional | +| lifecycle_equal | Exact Life Cycle. | Optional | +| limit | The maximum number of data types findings to retrieve. If not specified, the default value is 50. | Optional | | sort | Sorting criteria in the format: property,(asc\|desc). Default sort order is ascending. Multiple sort criteria are supported. | Optional | #### Context Output | **Path** | **Type** | **Description** | | --- | --- | --- | -| DSPM.DataTypeFindings.Key | String | Data type finding key. | -| DSPM.DataTypeFindings.No | Number | Data type finding number. | +| DSPM.DataTypesFinding.dataTypeName | String | Represents the name of the data type being analyzed. | +| DSPM.DataTypesFinding.label | String | Label associated with the data type, such as PII. | +| DSPM.DataTypesFinding.records | Number | The number of records associated with the data type. | +| DSPM.DataTypesFinding.publicRecords | Number | The number of public records found for this data type. | +| DSPM.DataTypesFinding.assets | Number | The number of assets associated with this data type. | +| DSPM.DataTypesFinding.clouds | String | The clouds where the data type was found (e.g., AWS). | +| DSPM.DataTypesFinding.regions | String | The regions where the data type was found. | +| DSPM.DataTypesFinding.lastFound | Date | The timestamp when the data type was last found. | +| DSPM.DataTypesFinding.recordsAtRisk.high | Number | The number of high-risk records found for this data type. | +| DSPM.DataTypesFinding.recordsAtRisk.medium | Number | The number of medium-risk records found for this data type. | +| DSPM.DataTypesFinding.recordsAtRisk.low | Number | The number of low-risk records found for this data type. | #### Command example -```!dspm-get-data-types-findings cloudProviderEqual=AWS``` +```!dspm-list-data-types-findings cloudProviderEqual=AWS``` #### Context Example ```json -{ - "DSPM": { - "DataTypesFindings": { - "Key": "AADHAAR_INDIVIDUAL_IDENTIFICATION", - "No": 1 +[{ + "dataTypeName": "AADHAAR_INDIVIDUAL_IDENTIFICATION", + "label": "PII", + "records": 4, + "publicRecords": 0, + "assets": 1, + "clouds": [ + "AWS" + ], + "regions": [ + "us-east-1" + ], + "lastFound": "2024-05-09T03:24:29Z", + "recordsAtRisk": { + "high": 0, + "medium": 4, + "low": 0 } - } -} +}] ``` #### Human Readable Output @@ -735,7 +755,7 @@ Updates the status of a risk finding. | **Argument Name** | **Description** | **Required** | | --- | --- | --- | -| riskFindingId | Risk Finding ID. | Required | +| risk_finding_id | Risk Finding ID. | Required | | status | Updated Status. | Required | #### Context Output @@ -771,40 +791,41 @@ Updates the status of a risk finding. ---------------- -### dspm-get-list-of-alerts +### dspm-list-alerts *** Fetch list of alerts. #### Base Command -`dspm-get-list-of-alerts` +`dspm-list-alerts` #### Input | **Argument Name** | **Description** | **Required** | | --- | --- | --- | -| detectionTimeEquals | Exact detection time (equals). | Optional | -| detectionTimeGreaterThanOrEqual | Detection time (greater than or equal). | Optional | -| detectionTimeGreaterThan | Detection time (greater than). | Optional | -| detectionTimeLessThanOrEqual | Detection time (less than or equal). | Optional | -| detectionTimeLessThan | Detection time (less than). | Optional | -| policyNameIn | List of policy names. | Optional | -| policyNameEquals | Exact policy name. | Optional | -| assetNameIn | List of asset names. | Optional | -| assetNameEquals | Exact asset name. | Optional | -| cloudProviderIn | List of cloud providers ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"]. | Optional | -| cloudProviderEquals | Exact cloud provider ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"]. | Optional | -| destinationProjectVendorNameIn | List of destination project vendor names. | Optional | -| destinationProjectVendorNameEquals | Exact destination project vendor name. | Optional | -| cloudEnvironmentIn | List of cloud environments ["UNKNOWN", "DEVELOPMENT", "STAGING", "TESTING", "PRODUCTION"]. | Optional | -| cloudEnvironmentEquals | Exact cloud environment ["UNKNOWN", "DEVELOPMENT", "STAGING", "TESTING", "PRODUCTION"]. | Optional | -| policySeverityIn | List of policy severities ["HIGH", "MEDIUM", "LOW"]. | Optional | -| policySeverityEquals | Exact policy severity ["HIGH", "MEDIUM", "LOW"]. | Optional | -| categoryTypeIn | List of category types ["FIRST_MOVE", "ATTACK", "COMPLIANCE", "ASSET_AT_RISK", "RECONNAISSANCE"]. | Optional | -| categoryTypeEquals | Exact category type ["FIRST_MOVE", "ATTACK", "COMPLIANCE", "ASSET_AT_RISK", "RECONNAISSANCE"]. | Optional | -| statusIn | List of statuses ["OPEN", "UNIMPORTANT", "WRONG", "HANDLED", "INVESTIGATING"]. | Optional | -| statusEquals | Exact status ["OPEN", "UNIMPORTANT", "WRONG", "HANDLED", "INVESTIGATING"]. | Optional | +| detection_time_equals | Exact detection time (equals). | Optional | +| detection_time_greater_than_or_equal | Detection time (greater than or equal). | Optional | +| detection_time_greater_than | Detection time (greater than). | Optional | +| detection_time_less_than_or_equal | Detection time (less than or equal). | Optional | +| detection_time_less_than | Detection time (less than). | Optional | +| policy_name_in | List of policy names. | Optional | +| policy_name_equals | Exact policy name. | Optional | +| asset_name_in | List of asset names. | Optional | +| limit | The maximum number of alerts to retrieve. If not specified, the default value is 50. | Optional | +| asset_name_equals | Exact asset name. | Optional | +| cloud_provider_in | List of cloud providers ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"]. | Optional | +| cloud_provider_equals | Exact cloud provider ["AWS", "AZURE", "GCP", "SNOWFLAKE", "FILE_SHARE", "O365"]. | Optional | +| destination_project_vendor_name_in | List of destination project vendor names. | Optional | +| destination_project_vendor_name_equals | Exact destination project vendor name. | Optional | +| cloud_environment_in | List of cloud environments ["UNKNOWN", "DEVELOPMENT", "STAGING", "TESTING", "PRODUCTION"]. | Optional | +| cloud_environment_equals | Exact cloud environment ["UNKNOWN", "DEVELOPMENT", "STAGING", "TESTING", "PRODUCTION"]. | Optional | +| policy_severity_in | List of policy severities ["HIGH", "MEDIUM", "LOW"]. | Optional | +| policy_severity_equals | Exact policy severity ["HIGH", "MEDIUM", "LOW"]. | Optional | +| category_type_in | List of category types ["FIRST_MOVE", "ATTACK", "COMPLIANCE", "ASSET_AT_RISK", "RECONNAISSANCE"]. | Optional | +| category_type_equals | Exact category type ["FIRST_MOVE", "ATTACK", "COMPLIANCE", "ASSET_AT_RISK", "RECONNAISSANCE"]. | Optional | +| status_in | List of statuses ["OPEN", "UNIMPORTANT", "WRONG", "HANDLED", "INVESTIGATING"]. | Optional | +| status_equals | Exact status ["OPEN", "UNIMPORTANT", "WRONG", "HANDLED", "INVESTIGATING"]. | Optional | | sort | Sort order (property, asc|desc). | Optional | @@ -812,27 +833,27 @@ Fetch list of alerts. | **Path** | **Type** | **Description** | | --- | --- | --- | -| DSPM.Alerts.id | String | Alert ID. | -| DSPM.Alerts.detectionTime | Date | Alert detection time. | -| DSPM.Alerts.policyName | String | Alert policy name. | -| DSPM.Alerts.assetName | String | Alert asset name. | -| DSPM.Alerts.assetLabels | Unknown | Alert asset label. | -| DSPM.Alerts.cloudProvider | String | Alert cloud provider. | -| DSPM.Alerts.destinationProjects | Unknown | Alert destination projects. | -| DSPM.Alerts.cloudEnvironment | String | Alert cloud enviroment. | -| DSPM.Alerts.policySeverity | String | Alert policy severity. | -| DSPM.Alerts.policyCategoryType | String | Alert policy category type. | -| DSPM.Alerts.status | String | Alert status. | -| DSPM.Alerts.eventActor | String | Alert event actor. | -| DSPM.Alerts.eventUserAgent | String | Alert event user agent. | -| DSPM.Alerts.eventActionMedium | String | Alert event action medium. | -| DSPM.Alerts.eventSource | String | Alert event source. | -| DSPM.Alerts.policyFrameWorks | String | Alert policy frameworks. | -| DSPM.Alerts.eventRawData | String | Alert event raw data. | +| DSPM.Alert.id | String | Alert ID. | +| DSPM.Alert.detectionTime | Date | Alert detection time. | +| DSPM.Alert.policyName | String | Alert policy name. | +| DSPM.Alert.assetName | String | Alert asset name. | +| DSPM.Alert.assetLabels | Unknown | Alert asset label. | +| DSPM.Alert.cloudProvider | String | Alert cloud provider. | +| DSPM.Alert.destinationProjects | Unknown | Alert destination projects. | +| DSPM.Alert.cloudEnvironment | String | Alert cloud enviroment. | +| DSPM.Alert.policySeverity | String | Alert policy severity. | +| DSPM.Alert.policyCategoryType | String | Alert policy category type. | +| DSPM.Alert.status | String | Alert status. | +| DSPM.Alert.eventActor | String | Alert event actor. | +| DSPM.Alert.eventUserAgent | String | Alert event user agent. | +| DSPM.Alert.eventActionMedium | String | Alert event action medium. | +| DSPM.Alert.eventSource | String | Alert event source. | +| DSPM.Alert.policyFrameWorks | String | Alert policy frameworks. | +| DSPM.Alert.eventRawData | String | Alert event raw data. | #### Command example -```!dspm-get-list-of-alerts cloudEnvironmentEquals="TESTING"``` +```!dspm-list-alerts cloudEnvironmentEquals="TESTING"``` #### Context Example ```json { @@ -885,7 +906,7 @@ Updates the status of a alert. | **Argument Name** | **Description** | **Required** | | --- | --- | --- | -| alertId | Alert ID. | Required | +| alert_id | Alert ID. | Required | | status | Updated Status. | Required | #### Context Output