22# -*- coding: utf-8 -*-
33
44import sys
5+ import tempfile
56from os import environ
67
8+ import requests
79from colorama import Fore , Style
810from colorama import init as colorama_init
911
1012from prowler .config .config import (
1113 EXTERNAL_TOOL_PROVIDERS ,
14+ cloud_api_base_url ,
1215 csv_file_suffix ,
1316 get_available_compliance_frameworks ,
1417 html_file_suffix ,
110113from prowler .lib .outputs .csv .csv import CSV
111114from prowler .lib .outputs .finding import Finding
112115from prowler .lib .outputs .html .html import HTML
116+ from prowler .lib .outputs .ocsf .ingestion import send_ocsf_to_api
113117from prowler .lib .outputs .ocsf .ocsf import OCSF
114118from prowler .lib .outputs .outputs import extract_findings_statistics , report
115119from prowler .lib .outputs .slack .slack import Slack
@@ -477,6 +481,7 @@ def streaming_callback(findings_batch):
477481 sys .exit (1 )
478482
479483 generated_outputs = {"regular" : [], "compliance" : []}
484+ ocsf_output = None
480485
481486 if args .output_formats :
482487 for mode in args .output_formats :
@@ -507,6 +512,7 @@ def streaming_callback(findings_batch):
507512 file_path = f"{ filename } { json_ocsf_file_suffix } " ,
508513 )
509514 generated_outputs ["regular" ].append (json_output )
515+ ocsf_output = json_output
510516 json_output .batch_write_data_to_file ()
511517 if mode == "html" :
512518 html_output = HTML (
@@ -518,6 +524,57 @@ def streaming_callback(findings_batch):
518524 provider = global_provider , stats = stats
519525 )
520526
527+ if getattr (args , "export_ocsf" , False ):
528+ if not ocsf_output or not getattr (ocsf_output , "file_path" , None ):
529+ tmp_ocsf = tempfile .NamedTemporaryFile (
530+ suffix = json_ocsf_file_suffix , delete = False
531+ )
532+ ocsf_output = OCSF (
533+ findings = finding_outputs ,
534+ file_path = tmp_ocsf .name ,
535+ )
536+ tmp_ocsf .close ()
537+ ocsf_output .batch_write_data_to_file ()
538+ print (
539+ f"{ Style .BRIGHT } \n Exporting OCSF to Prowler Cloud, please wait...{ Style .RESET_ALL } "
540+ )
541+ try :
542+ response = send_ocsf_to_api (ocsf_output .file_path )
543+ except ValueError :
544+ logger .warning (
545+ "OCSF export skipped: no API key configured. "
546+ "Set the PROWLER_API_KEY environment variable to enable it. "
547+ f"Scan results were saved to { ocsf_output .file_path } "
548+ )
549+ except requests .ConnectionError :
550+ logger .warning (
551+ "OCSF export skipped: could not reach the Prowler Cloud API at "
552+ f"{ cloud_api_base_url } . Check the URL and your network connection. "
553+ f"Scan results were saved to { ocsf_output .file_path } "
554+ )
555+ except requests .HTTPError as http_err :
556+ logger .warning (
557+ f"OCSF export failed: the API returned HTTP { http_err .response .status_code } . "
558+ "Verify your API key is valid and has the right permissions. "
559+ f"Scan results were saved to { ocsf_output .file_path } "
560+ )
561+ except Exception as error :
562+ logger .warning (
563+ f"OCSF export failed unexpectedly: { error } . "
564+ f"Scan results were saved to { ocsf_output .file_path } "
565+ )
566+ else :
567+ job_id = response .get ("data" , {}).get ("id" ) if response else None
568+ if job_id :
569+ print (
570+ f"{ Style .BRIGHT } { Fore .GREEN } \n OCSF export accepted. Ingestion job: { job_id } { Style .RESET_ALL } "
571+ )
572+ else :
573+ logger .warning (
574+ "OCSF export: unexpected API response (missing ingestion job ID). "
575+ f"Scan results were saved to { ocsf_output .file_path } "
576+ )
577+
521578 # Compliance Frameworks
522579 input_compliance_frameworks = set (output_options .output_modes ).intersection (
523580 get_available_compliance_frameworks (provider )
0 commit comments