functions/ConvertFrom-ValgrindToCodeDx.ps1

<#
.SYNOPSIS
Converts a Valgrind XML report to a Code Dx report for importing results.
 
.DESCRIPTION
Used to convert a Valgrind XML report file to a Code Dx XML format so it can be imported.
  
.EXAMPLE
ConvertFrom-ValgrindToCodeDx [scan_file_to_process] [output_directory]
#>

    
Function ConvertFrom-ValgrindToCodeDX
{
    [cmdletbinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]$SourceScanFilepath,
        [Parameter(Mandatory=$true)]
        [string]$OutputDir
    )
    
    #Setup variables
    $CDate = Get-Date -format "yyyy-MM-dd-HHmmss"
    $OutputFilePath = $OutputDir.Trim("""") + "\VG2CDX-" + $CDate + ".xml"
        
    $SourceScanFile = $SourceScanFilepath.Trim("""")
    $ToolName
    $NativeIDName = "Valgrind Scan uniqueId"
    $NativeID
    $cwe
    $description
    $locationFile
    $locationLine
    $reportDate

    #Setup Code Dx output doc
    [xml]$doc = New-Object System.Xml.XmlDocument
    $dec = $doc.CreateXmlDeclaration("1.0","UTF-8",$null)
    $updateXML= $doc.AppendChild($dec)
    $reportComment = "Valgrind to Code Dx - Generated $CDate"
    $updateXML= $doc.AppendChild($doc.CreateComment($reportComment))
    $root = $doc.CreateNode("element","report",$null)
    
    #read source Valgrind file and create custom PSO
    [xml]$SourceScanData1 = Get-Content -Encoding UTF8 -Raw -Path $SourceScanFile
    $SourceScanData = $SourceScanData1.valgrindoutput
    $ToolName = $SourceScanData.tool
    $NativeID = $SourceScanData.pid

    #pull report date attributes and reformat for Code Dx file
    $reportDate = $CDate.Substring(0,10)

    #Set Root attributes
    $root.SetAttribute("date",$reportDate)
    $root.SetAttribute("tool",$ToolName)

    #create findings Element
    $fds = $doc.CreateNode("element","findings",$null)

    #Get parent array of results
    $Results = $SourceScanData.error

    $Results | ForEach-Object{

        #Create Code Dx elements
        $fd = $doc.CreateNode("element","finding",$null)
        $id = $doc.CreateNode("element","native-id",$null)
        $cwe = $doc.CreateNode("element","cwe",$null)
        $desc = $doc.CreateNode("element","description",$null)
        $tl = $doc.CreateNode("element","tool",$null)
        $loc = $doc.CreateNode("element","location",$null)
        $ln = $doc.CreateNode("element","line",$null)
        $md = $doc.CreateNode("element","metadata",$null)

        #Set finding "fd" attributes
        $fd.SetAttribute("severity", "critical")
        $fd.SetAttribute("type","static")
        $fd.SetAttribute("status", "new")

        #Set Native ID attributes
        $id.SetAttribute("name",$NativeIDName)
        $id.SetAttribute("value", $_.unique)

        #Set Tool attributes
        $tl.SetAttribute("name",$ToolName)
        $tl.SetAttribute("category","Security")
        $tl.SetAttribute("code", $_.kind)

        #Set description attributes
        $desc.SetAttribute("format", "plain-text")
        if($_.PSobject.Properties.Name -contains "xwhat") {
            $desc.InnerText=$_.xwhat.text
        }
        elseif($_.PSobject.Properties.Name -contains "what") {
            $desc.InnerText=$_.what
        }
        else {
            $desc.InnerText = "*** Unable to locate description ***"
        }
        

        $finding = $_.stack
        
        if($finding.Length -gt 0) {
            $stack = $finding[0]
        } else {
            $stack = $finding
        }

        $df = $doc.CreateNode("element","variants",$null)

        $dataflowtext = ""
        $stackElement = ""
        foreach ($element in $stack.frame) {
            if ($dataflowtext.length -ne 0) {
                $dataflowtext = $dataflowtext + " --> "
            }
            $dataflowtext = $dataflowtext + "Function " + $element.fn + "()"
            $dataflowtext = $dataflowtext + " at line " + $element.line
            $dataflowtext = $dataflowtext + " in file " + $element.dir + "/" + $element.file
            
            if ($stackElement.length -eq 0) {
                if(-Not ($element.obj.Contains("/valgrind/"))) {
                    $stackElement = $element
                }
            }
        }

        $e = $doc.CreateNode("element","value",$null)
        $e.SetAttribute("key","User Input Flow")
        $e.InnerText = $dataflowtext
        $updateXML = $md.AppendChild($e)
        
        #set line attributes
        $ln.SetAttribute("end", $stackElement.line)
        $ln.SetAttribute("start", $stackElement.line)
        $updateXML= $loc.AppendChild($ln)

        #Add function element to Metadata
        $e = $doc.CreateNode("element","value",$null)
        $e.SetAttribute("key","Function Call name")
        $e.InnerText = $stackElement.fn + "()"
        $updateXML= $md.AppendChild($e)

        #Add function element to Metadata
        $e = $doc.CreateNode("element","value",$null)
        $e.SetAttribute("key","Function Call file")
        $e.InnerText = $stackElement.dir + "/" + $stackElement.file
        $updateXML= $md.AppendChild($e)

        #Add function line element to Metadata
        $e = $doc.CreateNode("element","value",$null)
        $e.SetAttribute("key","Function Call line")
        $e.InnerText = $stackElement.line
        $updateXML= $md.AppendChild($e)

        #Add object element to Metadata
        $e = $doc.CreateNode("element","value",$null)
        $e.SetAttribute("key","Object file")
        $e.InnerText = $stackElement.obj
        $updateXML= $md.AppendChild($e)

        #build location node and attributes
        $loc.SetAttribute("type","file")
        $loc.SetAttribute("path", $stackElement.dir + "/" + $stackElement.file)

        #append remaining children to finding
        $updateXML= $fd.AppendChild($id)
        $updateXML= $fd.AppendChild($tl)
        $updateXML= $fd.AppendChild($loc)
        $updateXML= $fd.AppendChild($desc)
        $updateXML= $fd.AppendChild($md)

        #append finding to findings
        $updateXML= $fds.AppendChild($fd)
    }


    $updateXML= $root.AppendChild($fds)
    $updateXML= $doc.AppendChild($root) | Out-Null
    Write-Host "Outputing file to: $OutputFilePath"
    $doc.Save($OutputFilePath)
}