CreatePrismaCloudComputeResourceComplianceReportButton

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

python · Prisma Cloud Compute by Palo Alto Networks

Source

import demistomock as demisto  # noqa: F401
from CommonServerPython import *  # noqa: F401


def filter_severities(data: List[Dict[str, Any]], desired_severities: List[str]) -> List[Dict[str, Any]]:
    """
    Filters the data based on desired severities.

    Args:
        data (list): The input data containing compliance issues.
        desired_severities (list): A list of desired severities to filter the data.

    Returns:
        list: The filtered data based on the desired severities.
    """
    if not desired_severities or set(desired_severities) == {"critical", "high", "medium", "low"}:
        return data

    filtered_data = []

    for entry in data:
        entry_severities = entry.get("complianceissues", "").split("\n\n")
        filtered_issues = []

        for issue in entry_severities:
            for severity in map(str.strip, desired_severities):
                if severity.lower() in issue.lower():
                    filtered_issues.append(issue)
                    break

        if filtered_issues:
            entry["complianceissues"] = "\n\n".join(filtered_issues)
            filtered_data.append(entry)

    return filtered_data


def filter_resources(data: List[Dict[str, Any]], resource_type: str, desired_resources: List[str]) -> List[Dict[str, Any]]:
    """
    Filters the data based on desired resources and resource type.

    Args:
        data (list): The input data containing resource information.
        resource_type (str): The type of resource to filter (e.g., 'host', 'container', 'image').
        desired_resources (list): A list of desired resource values.

    Returns:
        list: The filtered data based on the desired resources and resource type.
    """
    if not desired_resources:
        return data

    filtered_data = []
    key_mapping = {"host": "hostname", "container": "containerid", "image": "imageid"}

    key = key_mapping.get(resource_type, None)
    if not key:
        raise DemistoException("Invalid resource_type. Supported types: 'host', 'container', 'image'.")

    for entry in data:
        resource_value = entry.get(key, "")
        if resource_value in desired_resources:
            filtered_data.append(entry)

    return filtered_data


def transform_html_for_resource(html: str, resource_type: str) -> str:
    """
    Transforms the HTML table based on the resource type.

    Args:
        html (str): The HTML table to transform.
        resource_type (str): The type of resource to determine the transformation.

    Returns:
        str: The transformed HTML table.
    """
    if resource_type == "host":
        html = html.replace('cellpadding="3">', 'cellpadding="3" width="100%" style="word-break: break-all;">')
        html = html.replace("<th>complianceissues", '<th width="40%">Compliance Issues')
        html = html.replace("<th>cloudmetadata", '<th width="25%">Cloud MetaData')
        html = html.replace("<th>compliancedistribution", '<th width="15%">Compliance Distribution')
        html = html.replace("<th>hostname", '<th width="20%">Hostname')

    elif resource_type == "container":
        html = html.replace('cellpadding="3">', 'cellpadding="3" width="120%" style="word-break: break-all;">')
        html = html.replace("<th>complianceissues", '<th width="23%">Compliance Issues')
        html = html.replace("<th>cloudmetadata", '<th width="15%">Cloud MetaData')
        html = html.replace("<th>compliancedistribution", '<th width="8%">Compliance Distribution')
        html = html.replace("<th>containerid", '<th width="15%">Container ID')
        html = html.replace("<th>hostname", '<th width="15%">Hostname')
        html = html.replace("<th>imagename", '<th width="15%">Image Name')

    elif resource_type == "image":
        html = html.replace('cellpadding="3">', 'cellpadding="3" width="120%" style="word-break: break-all;">')
        html = html.replace("<th>complianceissues", '<th width="23%">Compliance Issues')
        html = html.replace("<th>cloudmetadata", '<th width="15%">Cloud MetaData')
        html = html.replace("<th>compliancedistribution", '<th width="8%">Compliance Distribution')
        html = html.replace("<th>imageid", '<th width="15%">Image ID')
        html = html.replace("<th>hosts", '<th width="15%">Hosts')
        html = html.replace("<th>imageinstances", '<th width="15%">Image Instances')

    return html


def send_html_email(html: str, resource_type: str, to_email: str) -> None:
    """
    Sends an HTML email with the compliance report attached.

    Args:
        html (str): The HTML content of the compliance report.
        resource_type (str): The type of resource for the report.
        to_email (str): The email address to send the report to.

    Returns:
        None
    """
    body = f"""
    Hello,

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

    {html}
    """

    res = demisto.executeCommand(
        "send-mail",
        {"to": to_email, "subject": f"IMPORTANT: Prisma Cloud Compute {resource_type.capitalize()} Compliance", "htmlBody": body},
    )

    if is_error(res):
        raise DemistoException(f"Failed to create compliance report: {get_error(res)!s}")

    demisto.results(res)
    return_results(CommandResults(readable_output=res[0]["Contents"]))


def send_xlsx_email(file_id: str, file_name: str, to_email: str, resource_type: str) -> None:
    """
    Sends an email with an XLSX attachment containing the compliance report.

    Args:
        file_id (str): The ID of the XLSX file attachment.
        file_name (str): The name of the XLSX file.
        to_email (str): The email address to send the report to.
        resource_type (str): The type of resource for the report.

    Returns:
        None
    """
    res = demisto.executeCommand(
        "send-mail",
        {
            "to": to_email,
            "subject": f"IMPORTANT: Prisma Cloud Compute {resource_type.capitalize()} Compliance",
            "attachIDs": file_id,
            "attachNames": file_name,
            "body": "Please find attached file for the compliance report from Prisma Cloud Compute.",
        },
    )

    if is_error(res):
        raise DemistoException(f"Failed to send email with XLSX attachment: {get_error(res)!s}")

    demisto.results(res)
    return_results(CommandResults(readable_output=res[0]["Contents"]))


def main() -> None:
    """
    Main function to create and send compliance reports based on input parameters.

    Args:
        None

    Returns:
        None
    """
    args = demisto.args()

    try:
        output_type = args.get("output_type", "html")  # New argument for output type, default is HTML
        desired_severities = argToList(args.get("desired_severities", ""))
        desired_resources = argToList(args.get("desired_resources", ""))

        # Fetching the table data
        table_data = argToList(args.get("table", []))
        filtered_data = filter_resources(table_data, args.get("resource_type"), desired_resources)
        filtered_data = filter_severities(filtered_data, desired_severities)

        if not filtered_data:
            demisto.results("No data matching the specified criteria. Email not sent.")
            return

        if output_type.lower() == "html":
            res = demisto.executeCommand(
                "ConvertTableToHTML", {"table": filtered_data, "title": args.get("title"), "headers": args.get("headers")}
            )

            if is_error(res):
                raise DemistoException(f"Failed to create compliance report: {get_error(res)!s}")

            html = res[0]["EntryContext"]["HTMLTable"]
            html = html.replace("\n", "<br />")  # Add line break replacement

            resource_type = args.get("resource_type")
            html = transform_html_for_resource(html, resource_type)

            send_html_email(html, resource_type, args.get("to"))

        elif output_type.lower() == "xlsx":
            # New logic for XLSX output
            res = demisto.executeCommand(
                "ExportToXLSX", {"data": filtered_data, "file_name": "compliance_report.xlsx", "sheet_name": "Compliance Report"}
            )

            if is_error(res):
                raise DemistoException(f"Failed to create XLSX file: {get_error(res)!s}")

            file_id = res[0]["FileID"]
            file_name = res[0]["File"]

            send_xlsx_email(file_id, file_name, args.get("to"), args.get("resource_type"))

        else:
            return_error("Invalid output type. Supported types: 'html', 'xlsx'.")

    except Exception as e:
        return_error(e)


if __name__ in ["__main__", "__builtin__", "builtins"]:
    main()

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.