Skip to content

Commit

Permalink
Run contextual analysis and secret detection in Docker scans jfrog#10
Browse files Browse the repository at this point in the history
  • Loading branch information
guyshe-jfrog committed Feb 19, 2024
1 parent 0fc5abe commit 9a72b94
Show file tree
Hide file tree
Showing 11 changed files with 195 additions and 33 deletions.
12 changes: 1 addition & 11 deletions commands/audit/audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"github.com/jfrog/jfrog-cli-security/scangraph"
"github.com/jfrog/jfrog-cli-security/utils"
clientutils "github.com/jfrog/jfrog-client-go/utils"
"github.com/jfrog/jfrog-client-go/utils/log"
"github.com/jfrog/jfrog-client-go/xray"
"github.com/jfrog/jfrog-client-go/xray/services"
"golang.org/x/sync/errgroup"
Expand Down Expand Up @@ -161,7 +160,7 @@ func RunAudit(auditParams *AuditParams) (results *xrayutils.Results, err error)
return
}
results.XrayVersion = auditParams.xrayVersion
results.ExtendedScanResults.EntitledForJas, err = isEntitledForJas(xrayManager, auditParams.xrayVersion)
results.ExtendedScanResults.EntitledForJas, err = xrayutils.IsEntitledForJas(xrayManager, auditParams.xrayVersion)
if err != nil {
return
}
Expand All @@ -186,12 +185,3 @@ func RunAudit(auditParams *AuditParams) (results *xrayutils.Results, err error)
}
return
}

func isEntitledForJas(xrayManager *xray.XrayServicesManager, xrayVersion string) (entitled bool, err error) {
if e := clientutils.ValidateMinimumVersion(clientutils.Xray, xrayVersion, xrayutils.EntitlementsMinVersion); e != nil {
log.Debug(e)
return
}
entitled, err = xrayManager.IsEntitled(xrayutils.ApplicabilityFeatureId)
return
}
43 changes: 39 additions & 4 deletions commands/audit/jas/applicability/applicabilitymanager.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ import (
)

const (
applicabilityScanType = "analyze-applicability"
applicabilityScanCommand = "ca"
applicabilityDocsUrlSuffix = "contextual-analysis"
applicabilityScanType = "analyze-applicability"
applicabilityScanCommand = "ca"
applicabilityDocsUrlSuffix = "contextual-analysis"
applicabilityDockerScanScanType = "analyze-applicability-docker-scan"
)

type ApplicabilityScanManager struct {
Expand All @@ -29,6 +30,7 @@ type ApplicabilityScanManager struct {
xrayResults []services.ScanResponse
scanner *jas.JasScanner
thirdPartyScan bool
commandType string
}

// The getApplicabilityScanResults function runs the applicability scan flow, which includes the following steps:
Expand All @@ -55,6 +57,37 @@ func RunApplicabilityScan(xrayResults []services.ScanResponse, directDependencie
return
}

// The getApplicabilityScanResults function runs the applicability scan flow, which includes the following steps:
// Creating an ApplicabilityScanManager object.
// Checking if the scanned project is eligible for applicability scan.
// Running the analyzer manager executable.
// Parsing the analyzer manager results.
// Return values:
// map[string]string: A map containing the applicability result of each XRAY CVE.
// bool: true if the user is entitled to the applicability scan, false otherwise.
// error: An error object (if any).
func RunApplicabilityWithScanCves(xrayResults []services.ScanResponse, cveList []string,
scannedTechnologies []coreutils.Technology, scanner *jas.JasScanner) (results []*sarif.Run, err error) {
applicabilityScanManager := newApplicabilityScanManagerCves(xrayResults, cveList, scanner)
if err = applicabilityScanManager.scanner.Run(applicabilityScanManager); err != nil {
err = utils.ParseAnalyzerManagerError(utils.Applicability, err)
return
}
results = applicabilityScanManager.applicabilityScanResults
return
}

func newApplicabilityScanManagerCves(xrayScanResults []services.ScanResponse, cveList []string, scanner *jas.JasScanner) (manager *ApplicabilityScanManager) {
return &ApplicabilityScanManager{
applicabilityScanResults: []*sarif.Run{},
directDependenciesCves: cveList,
xrayResults: xrayScanResults,
scanner: scanner,
thirdPartyScan: false,
commandType: applicabilityDockerScanScanType,
}
}

func newApplicabilityScanManager(xrayScanResults []services.ScanResponse, directDependencies []string, scanner *jas.JasScanner, thirdPartyScan bool) (manager *ApplicabilityScanManager) {
directDependenciesCves, indirectDependenciesCves := extractDependenciesCvesFromScan(xrayScanResults, directDependencies)
return &ApplicabilityScanManager{
Expand All @@ -64,6 +97,7 @@ func newApplicabilityScanManager(xrayScanResults []services.ScanResponse, direct
xrayResults: xrayScanResults,
scanner: scanner,
thirdPartyScan: thirdPartyScan,
commandType: applicabilityScanType,
}
}

Expand Down Expand Up @@ -152,6 +186,7 @@ type scanConfiguration struct {
CveWhitelist []string `yaml:"cve-whitelist"`
IndirectCveWhitelist []string `yaml:"indirect-cve-whitelist"`
SkippedDirs []string `yaml:"skipped-folders"`
ScanType string `yaml:"scantype"`
}

func (asm *ApplicabilityScanManager) createConfigFile(module jfrogappsconfig.Module) error {
Expand All @@ -169,7 +204,7 @@ func (asm *ApplicabilityScanManager) createConfigFile(module jfrogappsconfig.Mod
{
Roots: roots,
Output: asm.scanner.ResultsFileName,
Type: applicabilityScanType,
Type: asm.commandType,
GrepDisable: false,
CveWhitelist: asm.directDependenciesCves,
IndirectCveWhitelist: asm.indirectDependenciesCves,
Expand Down
33 changes: 33 additions & 0 deletions commands/audit/jas/applicability/applicabilitymanager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
)

var mockDirectDependencies = []string{"issueId_2_direct_dependency", "issueId_1_direct_dependency"}
var mockCves = []string{"CVE-00000", "CVE-000AA"}
var mockMultiRootDirectDependencies = []string{"issueId_2_direct_dependency", "issueId_1_direct_dependency", "issueId_3_direct_dependency", "issueId_4_direct_dependency"}

func TestNewApplicabilityScanManager_InputIsValid(t *testing.T) {
Expand All @@ -29,6 +30,21 @@ func TestNewApplicabilityScanManager_InputIsValid(t *testing.T) {
}
}

func TestNewApplicabilityScanManager_Docker_InputIsValid(t *testing.T) {
scanner, cleanUp := jas.InitJasTest(t)
defer cleanUp()
// Act
applicabilityManager := newApplicabilityScanManagerCves(jas.FakeBasicXrayResults, mockCves, scanner)

// Assert
if assert.NotNil(t, applicabilityManager) {
assert.NotEmpty(t, applicabilityManager.scanner.ConfigFileName)
assert.NotEmpty(t, applicabilityManager.scanner.ResultsFileName)
print(applicabilityManager.directDependenciesCves)
assert.Len(t, applicabilityManager.directDependenciesCves, 2)
}
}

func TestNewApplicabilityScanManager_DependencyTreeDoesntExist(t *testing.T) {
scanner, cleanUp := jas.InitJasTest(t)
defer cleanUp()
Expand Down Expand Up @@ -318,6 +334,23 @@ func TestParseResults_ApplicableCveExist(t *testing.T) {
}
}

func TestParseResults_DockerApplicableCveExist(t *testing.T) {
// Arrange
scanner, cleanUp := jas.InitJasTest(t)
defer cleanUp()
applicabilityManager := newApplicabilityScanManagerCves(jas.FakeBasicXrayResults, mockCves, scanner)
applicabilityManager.scanner.ResultsFileName = filepath.Join(jas.GetTestDataPath(), "applicability-scan", "applicable-cve-results.sarif")

// Act
var err error
applicabilityManager.applicabilityScanResults, err = jas.ReadJasScanRunsFromFile(applicabilityManager.scanner.ResultsFileName, scanner.JFrogAppsConfig.Modules[0].SourceRoot, applicabilityDocsUrlSuffix)

if assert.NoError(t, err) && assert.NotNil(t, applicabilityManager.applicabilityScanResults) {
assert.Len(t, applicabilityManager.applicabilityScanResults, 1)
assert.NotEmpty(t, applicabilityManager.applicabilityScanResults[0].Results)
}
}

func TestParseResults_AllCvesNotApplicable(t *testing.T) {
// Arrange
scanner, cleanUp := jas.InitJasTest(t)
Expand Down
17 changes: 10 additions & 7 deletions commands/audit/jas/secrets/secretsscanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,16 @@ import (
)

const (
secretsScanCommand = "sec"
secretsScannerType = "secrets-scan"
secretsDocsUrlSuffix = "secrets"
secretsScanCommand = "sec"
SecretsScannerType = "secrets-scan" // #nosec
SecretsScannerDockerScanType = "secrets-docker-scan" // #nosec
secretsDocsUrlSuffix = "secrets"
)

type SecretScanManager struct {
secretsScannerResults []*sarif.Run
scanner *jas.JasScanner
scanType string
}

// The getSecretsScanResults function runs the secrets scan flow, which includes the following steps:
Expand All @@ -29,8 +31,8 @@ type SecretScanManager struct {
// Return values:
// []utils.IacOrSecretResult: a list of the secrets that were found.
// error: An error object (if any).
func RunSecretsScan(scanner *jas.JasScanner) (results []*sarif.Run, err error) {
secretScanManager := newSecretsScanManager(scanner)
func RunSecretsScan(scanner *jas.JasScanner, scanType string) (results []*sarif.Run, err error) {
secretScanManager := newSecretsScanManager(scanner, scanType)
log.Info("Running secrets scanning...")
if err = secretScanManager.scanner.Run(secretScanManager); err != nil {
err = utils.ParseAnalyzerManagerError(utils.Secrets, err)
Expand All @@ -43,10 +45,11 @@ func RunSecretsScan(scanner *jas.JasScanner) (results []*sarif.Run, err error) {
return
}

func newSecretsScanManager(scanner *jas.JasScanner) (manager *SecretScanManager) {
func newSecretsScanManager(scanner *jas.JasScanner, scanType string) (manager *SecretScanManager) {
return &SecretScanManager{
secretsScannerResults: []*sarif.Run{},
scanner: scanner,
scanType: scanType,
}
}

Expand Down Expand Up @@ -89,7 +92,7 @@ func (s *SecretScanManager) createConfigFile(module jfrogappsconfig.Module) erro
{
Roots: roots,
Output: s.scanner.ResultsFileName,
Type: secretsScannerType,
Type: s.scanType,
SkippedDirs: jas.GetExcludePatterns(module, module.Scanners.Secrets),
},
},
Expand Down
13 changes: 7 additions & 6 deletions commands/audit/jas/secrets/secretsscanner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ import (
"github.com/stretchr/testify/assert"
)

// TODO: Add docker scan applicablity and seacrets
func TestNewSecretsScanManager(t *testing.T) {
scanner, cleanUp := jas.InitJasTest(t)
defer cleanUp()
secretScanManager := newSecretsScanManager(scanner)
secretScanManager := newSecretsScanManager(scanner, SecretsScannerType)

assert.NotEmpty(t, secretScanManager)
assert.NotEmpty(t, secretScanManager.scanner.ConfigFileName)
Expand All @@ -26,7 +27,7 @@ func TestNewSecretsScanManager(t *testing.T) {
func TestSecretsScan_CreateConfigFile_VerifyFileWasCreated(t *testing.T) {
scanner, cleanUp := jas.InitJasTest(t)
defer cleanUp()
secretScanManager := newSecretsScanManager(scanner)
secretScanManager := newSecretsScanManager(scanner, SecretsScannerType)

currWd, err := coreutils.GetWorkingDirectory()
assert.NoError(t, err)
Expand All @@ -53,15 +54,15 @@ func TestRunAnalyzerManager_ReturnsGeneralError(t *testing.T) {
scanner, cleanUp := jas.InitJasTest(t)
defer cleanUp()

secretScanManager := newSecretsScanManager(scanner)
secretScanManager := newSecretsScanManager(scanner, SecretsScannerType)
assert.Error(t, secretScanManager.runAnalyzerManager())
}

func TestParseResults_EmptyResults(t *testing.T) {
scanner, cleanUp := jas.InitJasTest(t)
defer cleanUp()
// Arrange
secretScanManager := newSecretsScanManager(scanner)
secretScanManager := newSecretsScanManager(scanner, SecretsScannerType)
secretScanManager.scanner.ResultsFileName = filepath.Join(jas.GetTestDataPath(), "secrets-scan", "no-secrets.sarif")

// Act
Expand All @@ -84,7 +85,7 @@ func TestParseResults_ResultsContainSecrets(t *testing.T) {
scanner, cleanUp := jas.InitJasTest(t)
defer cleanUp()

secretScanManager := newSecretsScanManager(scanner)
secretScanManager := newSecretsScanManager(scanner, SecretsScannerType)
secretScanManager.scanner.ResultsFileName = filepath.Join(jas.GetTestDataPath(), "secrets-scan", "contain-secrets.sarif")

// Act
Expand All @@ -107,7 +108,7 @@ func TestGetSecretsScanResults_AnalyzerManagerReturnsError(t *testing.T) {
scanner, cleanUp := jas.InitJasTest(t)
defer cleanUp()

secretsResults, err := RunSecretsScan(scanner)
secretsResults, err := RunSecretsScan(scanner, SecretsScannerType)

assert.Error(t, err)
assert.ErrorContains(t, err, "failed to run Secrets scan")
Expand Down
3 changes: 2 additions & 1 deletion commands/audit/jasrunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package audit

import (
"errors"

"github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-cli-security/commands/audit/jas"
"github.com/jfrog/jfrog-cli-security/commands/audit/jas/applicability"
Expand Down Expand Up @@ -41,7 +42,7 @@ func runJasScannersAndSetResults(scanResults *utils.Results, directDependencies
if progress != nil {
progress.SetHeadlineMsg("Running secrets scanning")
}
scanResults.ExtendedScanResults.SecretsScanResults, err = secrets.RunSecretsScan(scanner)
scanResults.ExtendedScanResults.SecretsScanResults, err = secrets.RunSecretsScan(scanner, secrets.SecretsScannerType)
if err != nil {
return
}
Expand Down
44 changes: 44 additions & 0 deletions commands/scan/jasrunner_cves.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package scan

import (
"errors"
"fmt"

"github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-cli-security/commands/audit/jas"
"github.com/jfrog/jfrog-cli-security/commands/audit/jas/applicability"
"github.com/jfrog/jfrog-cli-security/commands/audit/jas/secrets"

"github.com/jfrog/jfrog-cli-security/utils"
"github.com/jfrog/jfrog-client-go/utils/log"
)

func runJasScannersAndSetResults(scanResults *utils.Results, cveList []string,
serverDetails *config.ServerDetails, workingDirs []string) (err error) {

if serverDetails == nil || len(serverDetails.Url) == 0 {
log.Warn("To include 'Advanced Security' scan as part of the audit output, please run the 'jf c add' command before running this command.")
return
}
scanner, err := jas.NewJasScanner(workingDirs, serverDetails)
if err != nil {
return
}

defer func() {
cleanup := scanner.ScannerDirCleanupFunc
err = errors.Join(err, cleanup())
}()

scanResults.ExtendedScanResults.ApplicabilityScanResults, err = applicability.RunApplicabilityWithScanCves(scanResults.GetScaScansXrayResults(), cveList, scanResults.GetScaScannedTechnologies(), scanner)
if err != nil {
fmt.Println("there was an error:", err)
return
}

scanResults.ExtendedScanResults.SecretsScanResults, err = secrets.RunSecretsScan(scanner, secrets.SecretsScannerDockerScanType)
if err != nil {
return
}
return
}
Loading

0 comments on commit 9a72b94

Please sign in to comment.