Skip to content

Commit

Permalink
continue to implement recursive scan
Browse files Browse the repository at this point in the history
  • Loading branch information
attiasas committed Oct 16, 2023
1 parent f45589f commit aa27d55
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 58 deletions.
4 changes: 4 additions & 0 deletions utils/coreutils/techutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ func DetectedTechnologiesList() (technologies []string) {
return techStringsList
}

func DetectTechnologiesDescriptors(path string, requestedTechnologies []Technology) (t map[Technology][]string) {
return
}

// DetectTechnologies tries to detect all technologies types according to the files in the given path.
// 'isCiSetup' will limit the search of possible techs to Maven, Gradle, and npm.
// 'recursive' will determine if the search will be limited to files in the root path or not.
Expand Down
30 changes: 19 additions & 11 deletions xray/commands/audit/audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,23 +136,31 @@ func (auditCmd *AuditCommand) CommandName() string {
return "generic_audit"
}

type Results struct {
IsMultipleRootProject bool
ScaError error
JasError error
ExtendedScanResults *xrayutils.ExtendedScanResults
}
// type ScaScanResult struct {
// Technology coreutils.Technology
// XrayResults []services.ScanResponse
// Descriptors []string
// }

func NewAuditResults() *Results {
return &Results{ExtendedScanResults: &xrayutils.ExtendedScanResults{}}
}
// type Results struct {
// ScaResults []ScaScanResult
// IsMultipleRootProject bool
// ScaError error

// ExtendedScanResults *xrayutils.ExtendedScanResults
// JasError error
// }

// func NewAuditResults() *Results {
// return &Results{ExtendedScanResults: &xrayutils.ExtendedScanResults{}}
// }

// Runs an audit scan based on the provided auditParams.
// Returns an audit Results object containing all the scan results.
// If the current server is entitled for JAS, the advanced security results will be included in the scan results.
func RunAudit(auditParams *AuditParams) (results *Results, err error) {
func RunAudit(auditParams *AuditParams) (results *xrayutils.Results, err error) {
// Initialize Results struct
results = NewAuditResults()
results = xrayutils.NewAuditResults()

serverDetails, err := auditParams.ServerDetails()
if err != nil {
Expand Down
178 changes: 146 additions & 32 deletions xray/commands/audit/scarunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@ import (
"encoding/json"
"errors"
"fmt"
"os"
"time"

"github.com/jfrog/build-info-go/utils/pythonutils"
"github.com/jfrog/gofrog/datastructures"
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
"github.com/jfrog/jfrog-cli-core/v2/xray/commands/audit/sca"
_go "github.com/jfrog/jfrog-cli-core/v2/xray/commands/audit/sca/go"
Expand All @@ -19,77 +23,187 @@ import (
clientutils "github.com/jfrog/jfrog-client-go/utils"
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"github.com/jfrog/jfrog-client-go/utils/log"
"github.com/jfrog/jfrog-client-go/xray/services"
xrayCmdUtils "github.com/jfrog/jfrog-client-go/xray/services/utils"
"os"
"time"
)

type ScaScanResult struct {
workingDir string
Te
err error
}

func scaScan(params *AuditParams, results *Results) (err error) {
func scaScan(params *AuditParams, results *xrayutils.Results) (err error) {
// Prepare
currentWorkingDir, err := os.Getwd()
if errorutils.CheckError(err) != nil {
return
}
serverDetails, err := params.ServerDetails()
if err != nil {
return
}
scans := getScaScansToPreform(currentWorkingDir, params)
if len(scans) == 0 {
log.Info("Couldn't determine a package manager or build tool used by this project. Skipping the SCA scan...")
return
}
// Make sure to return to the original working directory, executeScaScan may change it.
defer func() {
// Make sure to return to the original working directory, each scan may change it.
err = errors.Join(err, os.Chdir(currentWorkingDir))
}()
for _, wd := range getDirectoriesToScan(currentWorkingDir, params) {
log.Info("Running SCA scan for vulnerable dependencies scan in", wd, "directory...")
wdScanErr := runScaScanInWorkingDir(params, results, wd)
if wdScanErr != nil {
err = errors.Join(err, fmt.Errorf("audit command in '%s' failed:\n%s\n", wd, wdScanErr.Error()))
for _, scan := range scans {
// Run the scan.
log.Info("Running SCA scan for vulnerable dependencies in", scan.WorkingDirectory, "directory...")
if wdScanErr := executeScaScan(serverDetails, params, &scan); wdScanErr != nil {
err = errors.Join(err, fmt.Errorf("audit command in '%s' failed:\n%s\n", scan.WorkingDirectory, wdScanErr.Error()))
continue
}
if len(scan.XrayResults) > 0 {
// Add the scan results to the results.
results.ScaResults = append(results.ScaResults, scan)
}
}
return
}

func getScaScansToPreform(currentWorkingDir string, params *AuditParams) (scansToPreform []xrayutils.ScaScanResult) {
directories := getDirectoriesToScan(currentWorkingDir, params)
for _, wd := range directories {
technologiesToDescriptors := coreutils.DetectTechnologiesDescriptors(wd, getTechnologiesToDetect(params))

scansToPreform = append(scansToPreform, xrayutils.ScaScanResult{WorkingDirectory: wd})
}
}

func getDirectoriesToScan(currentWorkingDir string, params *AuditParams) []string {
workingDirs := datastructures.MakeSet[string]()
if len(params.workingDirs) == 0 {
workingDirs.Add(currentWorkingDir)
}
for _, wd := range params.workingDirs {
workingDirs.Add(wd)
}
if workingDirs.Size() == 0 {
workingDirs.Add(currentWorkingDir)
}
return workingDirs.ToSlice()
}

func runScaScanInWorkingDir(params *AuditParams, results *Results, workingDir string) (err error) {
// Change to the working directory.
err = os.Chdir(workingDir)
// Preform the SCA scan for the given scan information.
// This method may change the working directory to the scan's working directory.
func executeScaScan(serverDetails *config.ServerDetails, params *AuditParams, scan *xrayutils.ScaScanResult) (err error) {
if scan.Technology == coreutils.Dotnet {
return
}
// Get the dependency tree for the technology in the working directory.
if err = os.Chdir(scan.WorkingDirectory); err != nil {
return
}
flattenTree, fullDependencyTrees, techErr := GetTechDependencyTree(params.AuditBasicParams, scan.Technology)
if techErr != nil {
return fmt.Errorf("failed while building '%s' dependency tree:\n%s\n", scan.Technology, techErr.Error())
}
if flattenTree == nil || len(flattenTree.Nodes) == 0 {
return errors.New("no dependencies were found. Please try to build your project and re-run the audit command")
}
// Scan the dependency tree.
scanResults, xrayErr := runScaWithTech(scan.Technology, params, serverDetails, flattenTree, fullDependencyTrees)
if xrayErr != nil {
err = errors.Join(err, )
return fmt.Errorf("'%s' Xray dependency tree scan request failed:\n%s\n", scan.Technology, xrayErr.Error())
}
addThirdPartyDependenciesToParams(params, scan.Technology, flattenTree, fullDependencyTrees)
scan.XrayResults = append(scan.XrayResults, scanResults...)
return
}

func runScaWithTech(tech coreutils.Technology, params *AuditParams, serverDetails *config.ServerDetails, flatTree *xrayCmdUtils.GraphNode, fullDependencyTrees []*xrayCmdUtils.GraphNode) (techResults []services.ScanResponse, err error) {
scanGraphParams := scangraph.NewScanGraphParams().
SetServerDetails(serverDetails).
SetXrayGraphScanParams(params.xrayGraphScanParams).
SetXrayVersion(params.xrayVersion).
SetFixableOnly(params.fixableOnly).
SetSeverityLevel(params.minSeverityFilter)
techResults, err = sca.RunXrayDependenciesTreeScanGraph(flatTree, params.Progress(), tech, scanGraphParams)
if err != nil {
return
}
techResults = sca.BuildImpactPathsForScanResponse(techResults, fullDependencyTrees)
return
}

func runScaScanInWorkingDir(params *AuditParams, results *xrayutils.Results, workingDir string) (err error) {
// Prepare the working directory information for the scan.
technologies := getWorkingDirTechnologies(workingDir, params)
technologies := coreutils.DetectTechnologiesDescriptors(workingDir, getTechnologiesToDetect(params))
if len(technologies) == 0 {
log.Info("Couldn't determine a package manager or build tool used by this project. Skipping the SCA scan...")
return
}
serverDetails, err := params.ServerDetails()
if err != nil {
return
}
// Run the scan for each technology.
for tech, detectedDescriptors := range technologies {
if tech == coreutils.Dotnet {
continue
}
// Get the dependency tree for the technology.
flattenTree, fullDependencyTrees, techErr := GetTechDependencyTree(params.AuditBasicParams, tech)
if techErr != nil {
err = errors.Join(err, fmt.Errorf("failed while building '%s' dependency tree:\n%s\n", tech, techErr.Error()))
continue
}
if flattenTree == nil || len(flattenTree.Nodes) == 0 {
err = errors.Join(err, errors.New("no dependencies were found. Please try to build your project and re-run the audit command"))
continue
}
// Scan the dependency tree.
scanResults, xrayErr := runScaOnTech(tech, params, serverDetails, flattenTree, fullDependencyTrees, results)
if xrayErr != nil {
err = errors.Join(err, fmt.Errorf("'%s' Xray dependency tree scan request failed:\n%s\n", tech, xrayErr.Error()))
continue
}
addThirdPartyDependenciesToParams(params, tech, flattenTree, fullDependencyTrees)
results.ScaResults = append(results.ScaResults, xrayutils.ScaScanResult{Technology: tech, XrayResults: scanResults, Descriptors: detectedDescriptors})
}
return
}

func getWorkingDirTechnologies(workingDir string, params *AuditParams) (technologies []string) {
//coreutils.Technology
requestedTechnologies := params.Technologies()
if len(requestedTechnologies) != 0 {
technologies = requestedTechnologies
func getTechnologiesToDetect(params *AuditParams) (technologies []coreutils.Technology) {
if len(params.Technologies()) != 0 {
technologies = coreutils.ToTechnologies(params.Technologies())
} else {
technologies = coreutils.DetectedTechnologiesList()
technologies = coreutils.GetAllTechnologiesList()
}
if len(technologies) == 0 {
log.Info("Couldn't determine a package manager or build tool used by this project. Skipping the SCA scan...")
return
}

func addThirdPartyDependenciesToParams(params *AuditParams, tech coreutils.Technology, flatTree *xrayCmdUtils.GraphNode, fullDependencyTrees []*xrayCmdUtils.GraphNode) {
var dependenciesForApplicabilityScan []string
if shouldUseAllDependencies(params.thirdPartyApplicabilityScan, tech) {
dependenciesForApplicabilityScan = getDirectDependenciesFromTree([]*xrayCmdUtils.GraphNode{flatTree})
} else {
dependenciesForApplicabilityScan = getDirectDependenciesFromTree(fullDependencyTrees)
}
params.AppendDependenciesForApplicabilityScan(dependenciesForApplicabilityScan)
}

func runScaOnTech(tech coreutils.Technology, params *AuditParams, serverDetails *config.ServerDetails, flatTree *xrayCmdUtils.GraphNode, fullDependencyTrees []*xrayCmdUtils.GraphNode, results *xrayutils.Results) (techResults []services.ScanResponse, err error) {
scanGraphParams := scangraph.NewScanGraphParams().
SetServerDetails(serverDetails).
SetXrayGraphScanParams(params.xrayGraphScanParams).
SetXrayVersion(params.xrayVersion).
SetFixableOnly(params.fixableOnly).
SetSeverityLevel(params.minSeverityFilter)
techResults, err = sca.RunXrayDependenciesTreeScanGraph(flatTree, params.Progress(), tech, scanGraphParams)
if err != nil {
return
}
techResults = sca.BuildImpactPathsForScanResponse(techResults, fullDependencyTrees)

// results.ExtendedScanResults.XrayResults = append(results.ExtendedScanResults.XrayResults, techResults...)
// if !results.IsMultipleRootProject {
// results.IsMultipleRootProject = len(fullDependencyTrees) > 1
// }

// results.ExtendedScanResults.ScannedTechnologies = append(results.ExtendedScanResults.ScannedTechnologies, tech)
return
}

func runScaScan(params *AuditParams, results *Results) (err error) {
func runScaScan(params *AuditParams, results *xrayutils.Results) (err error) {
rootDir, err := os.Getwd()
if errorutils.CheckError(err) != nil {
return
Expand All @@ -110,7 +224,7 @@ func runScaScan(params *AuditParams, results *Results) (err error) {
}

// Audits the project found in the current directory using Xray.
func runScaScanOnWorkingDir(params *AuditParams, results *Results, workingDir, rootDir string) (err error) {
func runScaScanOnWorkingDir(params *AuditParams, results *xrayutils.Results, workingDir, rootDir string) (err error) {
err = os.Chdir(workingDir)
if err != nil {
return
Expand Down
29 changes: 14 additions & 15 deletions xray/utils/analyzermanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import (
"github.com/jfrog/jfrog-client-go/utils/errorutils"
"github.com/jfrog/jfrog-client-go/utils/io/fileutils"
"github.com/jfrog/jfrog-client-go/utils/log"
"github.com/jfrog/jfrog-client-go/xray/services"
"github.com/owenrumney/go-sarif/v2/sarif"
)

const (
Expand Down Expand Up @@ -78,21 +76,22 @@ var exitCodeErrorsMap = map[int]string{
unsupportedOsExitCode: "got unsupported operating system error from analyzer manager",
}

type ExtendedScanResults struct {
XrayResults []services.ScanResponse
XrayVersion string
ScannedTechnologies []coreutils.Technology
// type ExtendedScanResults struct {
// XrayResults []services.ScanResponse
// XrayVersion string
// ScannedTechnologies []coreutils.Technology

ApplicabilityScanResults []*sarif.Run
SecretsScanResults []*sarif.Run
IacScanResults []*sarif.Run
SastScanResults []*sarif.Run
EntitledForJas bool
}
// // DependenciesResults []
// ApplicabilityScanResults []*sarif.Run
// SecretsScanResults []*sarif.Run
// IacScanResults []*sarif.Run
// SastScanResults []*sarif.Run
// EntitledForJas bool
// }

func (e *ExtendedScanResults) getXrayScanResults() []services.ScanResponse {
return e.XrayResults
}
// func (e *ExtendedScanResults) getXrayScanResults() []services.ScanResponse {
// return e.XrayResults
// }

type AnalyzerManager struct {
AnalyzerManagerFullPath string
Expand Down
46 changes: 46 additions & 0 deletions xray/utils/results.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package utils

import (
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
"github.com/jfrog/jfrog-client-go/xray/services"
"github.com/owenrumney/go-sarif/v2/sarif"
)

type Results struct {
ScaResults []ScaScanResult
XrayVersion string
ScaError error

IsMultipleRootProject bool // TODO: remove this
ExtendedScanResults *ExtendedScanResults
JasError error
}

func NewAuditResults() *Results {
return &Results{ExtendedScanResults: &ExtendedScanResults{}}
}

type ScaScanResult struct {
Technology coreutils.Technology
WorkingDirectory string
Descriptors []string
XrayResults []services.ScanResponse

// IsMultipleRootProject bool
}

type ExtendedScanResults struct {
XrayResults []services.ScanResponse // TODO: remove this
XrayVersion string // TODO: remove this
ScannedTechnologies []coreutils.Technology // TODO: remove this

ApplicabilityScanResults []*sarif.Run
SecretsScanResults []*sarif.Run
IacScanResults []*sarif.Run
SastScanResults []*sarif.Run
EntitledForJas bool
}

func (e *ExtendedScanResults) getXrayScanResults() []services.ScanResponse {
return e.XrayResults
}

0 comments on commit aa27d55

Please sign in to comment.