CreatePrismaCloudComputeResourceComplianceReportButton

Generate a compliance report for Prisma Cloud resources - host, container or image.

python · Prisma Cloud Compute by Palo Alto Networks

Details

IDCreatePrismaCloudComputeResourceComplianceReportButton
Languagepython
From Version6.10.0
Docker Imagedemisto/python3:3.12.13.10116658

README

Generate a compliance report for Prisma Cloud resources - host, container or image.

Script Data


Name Description
Script Type python3
Cortex XSOAR Version 6.10.0

Dependencies


This script uses the following commands and scripts.

  • send-mail
  • ExportToXLSX
  • ConvertTableToHTML

Inputs


Argument Name Description
table The table of data.
title The title of the report.
to The to email address.
headers The headers for the HTML table.
resource_type The resource type.
output_type Whether to send the compliance issues as an html table or attached in xlsx file.
desired_severities A comma-separated list of severities which will be included in the compliance report. If no value is provided, all of the severities will be included. Example: “Critical, High”.”
desired_resources A comma-separated list of resources. In case the report should contain results only for specific resources, whether it’s a host, container ID or an image ID, provide the resources here.

Outputs


There are no outputs for this script.

import json
from unittest.mock import patch

import demistomock as demisto  # noqa: F401
import pytest
from CommonServerPython import *  # noqa: F401
from CreatePrismaCloudComputeResourceComplianceReportButton import (
    filter_resources,
    filter_severities,
    main,
    send_html_email,
    send_xlsx_email,
    transform_html_for_resource,
)

# Test transformation functions

# "Table" Test data
with open("test_data/hosts_table.json") as file:
    test_table_data = json.load(file)


def test_filter_resources_no_desired_resources():
    """
    Given:
        Hosts table.

    When:
        Running filter_resources

    Then:
        Assert the returned output matches the given hosts table.
    """
    # Test with no desired resources
    filtered_data = filter_resources(test_table_data, "host", [])
    # Assert that the filtered data matches the input data
    assert filtered_data == test_table_data


def test_filter_resources_with_desired_resources():
    """
    Given:
        Hosts table and a desired resource.

    When:
        Running filter_resources

    Then:
        Assert the returned output matches filtered hosts table based on the given desired resource.
    """
    desired_resource = "VM001-MYRESOURCEGROUPNAT-abc123-def456-ghi789-jkl012"
    # Test with a desired resource
    filtered_data = filter_resources(test_table_data, "host", [desired_resource])
    # Assert that the filtered data contains only the desired resource
    assert filtered_data == [test_table_data[0]]


def test_filter_severities_no_desired_severities():
    """
    Given:
        Hosts table.

    When:
        Running filter_severities

    Then:
        Assert the returned output matches the given hosts table.
    """
    # Test with no desired severities
    filtered_data = filter_severities(test_table_data, [])
    # Assert that the filtered data matches the input data
    assert filtered_data == test_table_data


def test_filter_severities_with_critical_severity():
    """
    Given:
        Hosts table and a desired severity.

    When:
        Running filter_severities

    Then:
        Assert the returned output matches filtered hosts table based on the given desired severity.
    """
    # Test with critical severity only
    filtered_data = filter_severities(test_table_data, ["critical"])
    # Assert that the filtered data contains only entries with critical severity
    expected_data = [entry for entry in test_table_data if "critical" in entry["complianceissues"].lower()]
    assert filtered_data == expected_data


# "HTML" test data

with open("test_data/html_hosts_table_pre_transform.html") as file:
    html_hosts_test_data = file.read()

with open("test_data/html_containers_table_pre_transform.html") as file:
    html_containers_test_data = file.read()

with open("test_data/html_images_table_pre_transform.html") as file:
    html_images_test_data = file.read()


def test_transform_html_for_resource_host():
    """
    Given:
        Hosts HTML data.

    When:
        Running transform_html_for_resource

    Then:
        Assert the returned output contains the desired changes.
    """
    # Test transformation for resource type 'host'
    transformed_html = transform_html_for_resource(html_hosts_test_data, "host")
    # Assert transformations for 'host'
    assert 'cellpadding="3" width="100%" style="word-break: break-all;">' in transformed_html
    assert '<th width="40%">Compliance Issues' in transformed_html
    assert '<th width="25%">Cloud MetaData' in transformed_html
    assert '<th width="15%">Compliance Distribution' in transformed_html
    assert '<th width="20%">Hostname' in transformed_html


def test_transform_html_for_resource_container():
    """
    Given:
        Containers HTML data.

    When:
        Running transform_html_for_resource

    Then:
        Assert the returned output contains the desired changes.
    """
    # Test transformation for resource type 'container'
    transformed_html = transform_html_for_resource(html_containers_test_data, "container")
    # Assert transformations for 'container'
    assert 'cellpadding="3" width="120%" style="word-break: break-all;">' in transformed_html
    assert '<th width="23%">Compliance Issues' in transformed_html
    assert '<th width="15%">Cloud MetaData' in transformed_html
    assert '<th width="8%">Compliance Distribution' in transformed_html
    assert '<th width="15%">Container ID' in transformed_html
    assert '<th width="15%">Hostname' in transformed_html
    assert '<th width="15%">Image Name' in transformed_html


def test_transform_html_for_resource_image():
    """
    Given:
        Images HTML data.

    When:
        Running transform_html_for_resource

    Then:
        Assert the returned output contains the desired changes.
    """
    # Test transformation for resource type 'image'
    transformed_html = transform_html_for_resource(html_images_test_data, "image")
    # Assert transformations for 'image'
    assert 'cellpadding="3" width="120%" style="word-break: break-all;">' in transformed_html
    assert '<th width="23%">Compliance Issues' in transformed_html
    assert '<th width="15%">Cloud MetaData' in transformed_html
    assert '<th width="8%">Compliance Distribution' in transformed_html
    assert '<th width="15%">Image ID' in transformed_html
    assert '<th width="15%">Hosts' in transformed_html
    assert '<th width="15%">Image Instances' in transformed_html


@pytest.fixture
def html_content():
    return "<html><body><h1>Hello, World!</h1></body></html>"


@pytest.fixture
def email_data():
    return {"html": "<html><body><h1>Hello, World!</h1></body></html>", "resource_type": "vm", "to_email": "example@example.com"}


@patch("CreatePrismaCloudComputeResourceComplianceReportButton.demisto.executeCommand")
def test_send_html_email(mock_executeCommand, html_content, email_data):
    """
    Given:
        Email data and html content

    When:
        Running send_html_email

    Then:
        Assert the mocked send command with the expected body and output.
    """
    mock_executeCommand.return_value = [{"Type": EntryType.NOTE, "Contents": "Email sent successfully"}]
    send_html_email(**email_data)
    expected_html_body = email_data["html"].strip()
    mock_executeCommand.assert_called_once_with(
        "send-mail",
        {
            "to": email_data["to_email"],
            "subject": f"IMPORTANT: Prisma Cloud Compute {email_data['resource_type'].capitalize()} Compliance",
            "htmlBody": f"""
    Hello,

    Please see below the details for the compliance report from Prisma Cloud Compute

    {expected_html_body}
    """,
        },
    )


@pytest.fixture
def email_xlsx_data():
    return {
        "file_id": "file_id_123",
        "file_name": "compliance_report.xlsx",
        "to_email": "example@example.com",
        "resource_type": "vm",
    }


@patch("CreatePrismaCloudComputeResourceComplianceReportButton.demisto.executeCommand")
def test_send_xlsx_email(mock_executeCommand, email_xlsx_data):
    """
    Given:
        Email data and xlsx data

    When:
        Running send_xlsx_email

    Then:
        Assert the mocked send command with the expected body and output.
    """
    mock_executeCommand.return_value = [{"Type": "NOTE", "Contents": "Email sent successfully"}]
    send_xlsx_email(**email_xlsx_data)
    mock_executeCommand.assert_called_once_with(
        "send-mail",
        {
            "to": email_xlsx_data["to_email"],
            "subject": f"IMPORTANT: Prisma Cloud Compute {email_xlsx_data['resource_type'].capitalize()} Compliance",
            "attachIDs": email_xlsx_data["file_id"],
            "attachNames": email_xlsx_data["file_name"],
            "body": "Please find attached file for the compliance report from Prisma Cloud Compute.",
        },
    )


RETURN_ERROR_TARGET = "CreatePrismaCloudComputeResourceComplianceReportButton.return_error"


def test_main_function_with_error(mocker):
    """
    Given:
        An invalid output_type

    When:
        Running main

    Then:
        Assert the returned error matches the expected error.
    """
    # Mock the necessary components
    mocker.patch.object(
        demisto,
        "args",
        return_value={"table": test_table_data, "to": "example@example.com", "output_type": "invalid", "resource_type": "host"},
    )
    return_error_mock = mocker.patch(RETURN_ERROR_TARGET)
    main()
    err_msg = return_error_mock.call_args_list[0][0][0]
    assert "Invalid output type. Supported types: 'html', 'xlsx'." in err_msg