Skip to content

Commit

Permalink
Add XSC analytics metrics capabilities (#47)
Browse files Browse the repository at this point in the history
  • Loading branch information
gailazar300 authored Apr 7, 2024
1 parent f340cd4 commit c1b4b6a
Show file tree
Hide file tree
Showing 29 changed files with 694 additions and 87 deletions.
63 changes: 49 additions & 14 deletions audit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ package main
import (
"encoding/json"
"fmt"
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
"github.com/jfrog/jfrog-cli-security/formats"
"github.com/jfrog/jfrog-cli-security/utils"
xscservices "github.com/jfrog/jfrog-client-go/xsc/services"
"os"
"os/exec"
"path/filepath"
Expand Down Expand Up @@ -35,7 +38,7 @@ func TestXrayAuditNpmSimpleJson(t *testing.T) {
}

func testXrayAuditNpm(t *testing.T, format string) string {
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion)
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion, "")
tempDirPath, createTempDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t)
defer createTempDirCallback()
npmProjectPath := filepath.Join(filepath.FromSlash(securityTestUtils.GetTestResourcesPath()), "projects", "package-managers", "npm", "npm")
Expand All @@ -61,7 +64,7 @@ func TestXrayAuditPnpmSimpleJson(t *testing.T) {
}

func testXrayAuditPnpm(t *testing.T, format string) string {
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion)
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion, "")
tempDirPath, createTempDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t)
defer createTempDirCallback()
npmProjectPath := filepath.Join(filepath.FromSlash(securityTestUtils.GetTestResourcesPath()), "projects", "package-managers", "npm", "npm-no-lock")
Expand Down Expand Up @@ -117,7 +120,7 @@ func TestXrayAuditYarnV1SimpleJson(t *testing.T) {
}

func testXrayAuditYarn(t *testing.T, projectDirName string, yarnCmd func()) {
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion)
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion, "")
tempDirPath, createTempDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t)
defer createTempDirCallback()
yarnProjectPath := filepath.Join(filepath.FromSlash(securityTestUtils.GetTestResourcesPath()), "projects", "package-managers", "yarn", projectDirName)
Expand Down Expand Up @@ -232,7 +235,7 @@ func TestXrayAuditNugetSimpleJson(t *testing.T) {
}

func testXrayAuditNuget(t *testing.T, projectName, format string, restoreTech string) string {
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion)
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion, "")
tempDirPath, createTempDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t)
defer createTempDirCallback()
projectPath := filepath.Join(filepath.FromSlash(securityTestUtils.GetTestResourcesPath()), "projects", "package-managers", "nuget", projectName)
Expand Down Expand Up @@ -261,7 +264,7 @@ func TestXrayAuditGradleSimpleJson(t *testing.T) {
}

func testXrayAuditGradle(t *testing.T, format string) string {
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion)
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion, "")
tempDirPath, createTempDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t)
defer createTempDirCallback()
gradleProjectPath := filepath.Join(filepath.FromSlash(securityTestUtils.GetTestResourcesPath()), "projects", "package-managers", "gradle", "gradle")
Expand All @@ -285,7 +288,7 @@ func TestXrayAuditMavenSimpleJson(t *testing.T) {
}

func testXrayAuditMaven(t *testing.T, format string) string {
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion)
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion, "")
tempDirPath, createTempDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t)
defer createTempDirCallback()
mvnProjectPath := filepath.Join(filepath.FromSlash(securityTestUtils.GetTestResourcesPath()), "projects", "package-managers", "maven", "maven")
Expand All @@ -299,7 +302,7 @@ func testXrayAuditMaven(t *testing.T, format string) string {
}

func TestXrayAuditNoTech(t *testing.T) {
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion)
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion, "")
tempDirPath, createTempDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t)
defer createTempDirCallback()
prevWd := securityTestUtils.ChangeWD(t, tempDirPath)
Expand All @@ -310,7 +313,7 @@ func TestXrayAuditNoTech(t *testing.T) {
}

func TestXrayAuditMultiProjects(t *testing.T) {
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion)
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion, "")
tempDirPath, createTempDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t)
defer createTempDirCallback()
multiProject := filepath.Join(filepath.FromSlash(securityTestUtils.GetTestResourcesPath()), "projects")
Expand Down Expand Up @@ -350,7 +353,7 @@ func TestXrayAuditPipSimpleJsonWithRequirementsFile(t *testing.T) {
}

func testXrayAuditPip(t *testing.T, format, requirementsFile string) string {
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion)
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion, "")
tempDirPath, createTempDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t)
defer createTempDirCallback()
pipProjectPath := filepath.Join(filepath.FromSlash(securityTestUtils.GetTestResourcesPath()), "projects", "package-managers", "python", "pip", "pip-project")
Expand Down Expand Up @@ -379,7 +382,7 @@ func TestXrayAuditPipenvSimpleJson(t *testing.T) {
}

func testXrayAuditPipenv(t *testing.T, format string) string {
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion)
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion, "")
tempDirPath, createTempDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t)
defer createTempDirCallback()
pipenvProjectPath := filepath.Join(filepath.FromSlash(securityTestUtils.GetTestResourcesPath()), "projects", "package-managers", "python", "pipenv", "pipenv-project")
Expand All @@ -403,7 +406,7 @@ func TestXrayAuditPoetrySimpleJson(t *testing.T) {
}

func testXrayAuditPoetry(t *testing.T, format string) string {
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion)
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion, "")
tempDirPath, createTempDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t)
defer createTempDirCallback()
poetryProjectPath := filepath.Join(filepath.FromSlash(securityTestUtils.GetTestResourcesPath()), "projects", "package-managers", "python", "poetry", "poetry-project")
Expand Down Expand Up @@ -445,7 +448,7 @@ func TestXrayAuditJasNoViolationsSimpleJson(t *testing.T) {
}

func testXrayAuditJas(t *testing.T, format string, project string) string {
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion)
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion, "")
tempDirPath, createTempDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t)
defer createTempDirCallback()
projectDir := filepath.Join(filepath.FromSlash(securityTestUtils.GetTestResourcesPath()), filepath.Join("projects", project))
Expand All @@ -462,7 +465,7 @@ func testXrayAuditJas(t *testing.T, format string, project string) string {
}

func TestXrayAuditDetectTech(t *testing.T) {
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion)
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion, "")
tempDirPath, createTempDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t)
defer createTempDirCallback()
mvnProjectPath := filepath.Join(filepath.FromSlash(securityTestUtils.GetTestResourcesPath()), "projects", "package-managers", "maven", "maven")
Expand All @@ -480,7 +483,7 @@ func TestXrayAuditDetectTech(t *testing.T) {
}

func TestXrayRecursiveScan(t *testing.T) {
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion)
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion, "")
tempDirPath, createTempDirCallback := coreTests.CreateTempDirWithCallbackAndAssert(t)
defer createTempDirCallback()
projectDir := filepath.Join(filepath.FromSlash(securityTestUtils.GetTestResourcesPath()), "projects", "package-managers")
Expand Down Expand Up @@ -514,3 +517,35 @@ func TestXrayRecursiveScan(t *testing.T) {
// We anticipate receiving an array with a length of 2 to confirm that we have obtained results from two distinct inner projects.
assert.Len(t, results, 2)
}

func TestXscAnalyticsForAudit(t *testing.T) {
securityTestUtils.InitSecurityTest(t, scangraph.GraphScanMinXrayVersion, xscservices.AnalyticsMetricsMinXscVersion)
reportUsageCallBack := clientTests.SetEnvWithCallbackAndAssert(t, coreutils.ReportUsage, "true")
defer reportUsageCallBack()
// Scan npm project and verify that analytics general event were sent to XSC.
output := testXrayAuditNpm(t, string(format.SimpleJson))
validateAnalyticsBasicEvent(t, output)
}

func validateAnalyticsBasicEvent(t *testing.T, output string) {
// Get MSI.
var results formats.SimpleJsonResults
err := json.Unmarshal([]byte(output), &results)
assert.NoError(t, err)

// Verify analytics metrics.
am := utils.NewAnalyticsMetricsService(securityTests.XscDetails)
assert.NotNil(t, am)
assert.NotEmpty(t, results.MultiScanId)
event, err := am.GetGeneralEvent(results.MultiScanId)
assert.NoError(t, err)

// Event creation and addition information.
assert.Equal(t, "cli", event.Product)
assert.Equal(t, 1, event.EventType)
assert.NotEmpty(t, event.AnalyzerManagerVersion)
assert.NotEmpty(t, event.EventStatus)
// The information that was added after updating the event with the scan's results.
assert.NotEmpty(t, event.TotalScanDuration)
assert.True(t, event.TotalFindings > 0)
}
2 changes: 2 additions & 0 deletions cli/scancommands.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,8 @@ func createAuditCmd(c *components.Context) (*audit.AuditCommand, error) {
if err != nil {
return nil, err
}
auditCmd.SetAnalyticsMetricsService(utils.NewAnalyticsMetricsService(serverDetails))

auditCmd.SetTargetRepoPath(addTrailingSlashToRepoPathIfNeeded(c)).
SetProject(c.GetStringFlagValue(flags.Project)).
SetIncludeVulnerabilities(shouldIncludeVulnerabilities(c)).
Expand Down
51 changes: 34 additions & 17 deletions commands/audit/audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,30 @@ package audit

import (
"errors"
"github.com/jfrog/jfrog-cli-security/scangraph"
"os"

"fmt"
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
"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"
xscservices "github.com/jfrog/jfrog-client-go/xsc/services"
"golang.org/x/sync/errgroup"
"os"

xrayutils "github.com/jfrog/jfrog-cli-security/utils"
)

type AuditCommand struct {
watches []string
projectKey string
targetRepoPath string
IncludeVulnerabilities bool
IncludeLicenses bool
Fail bool
PrintExtendedTable bool
watches []string
projectKey string
targetRepoPath string
IncludeVulnerabilities bool
IncludeLicenses bool
Fail bool
PrintExtendedTable bool
analyticsMetricsService *xrayutils.AnalyticsMetricsService
AuditParams
}

Expand Down Expand Up @@ -66,6 +68,11 @@ func (auditCmd *AuditCommand) SetPrintExtendedTable(printExtendedTable bool) *Au
return auditCmd
}

func (auditCmd *AuditCommand) SetAnalyticsMetricsService(analyticsMetricsService *xrayutils.AnalyticsMetricsService) *AuditCommand {
auditCmd.analyticsMetricsService = analyticsMetricsService
return auditCmd
}

func (auditCmd *AuditCommand) CreateXrayGraphScanParams() *services.XrayGraphScanParams {
params := &services.XrayGraphScanParams{
RepoPath: auditCmd.targetRepoPath,
Expand All @@ -79,6 +86,17 @@ func (auditCmd *AuditCommand) CreateXrayGraphScanParams() *services.XrayGraphSca
}
params.IncludeVulnerabilities = auditCmd.IncludeVulnerabilities
params.IncludeLicenses = auditCmd.IncludeLicenses
params.MultiScanId = auditCmd.analyticsMetricsService.GetMsi()
if params.MultiScanId != "" {
xscManager := auditCmd.analyticsMetricsService.XscManager()
if xscManager != nil {
version, err := xscManager.GetVersion()
if err != nil {
log.Debug(fmt.Sprintf("Can't get XSC version for xray graph scan params. Cause: %s", err.Error()))
}
params.XscVersion = version
}
}
return params
}

Expand All @@ -90,6 +108,8 @@ func (auditCmd *AuditCommand) Run() (err error) {
return
}

// Should be called before creating the audit params, so the params will contain XSC information.
auditCmd.analyticsMetricsService.AddGeneralEvent(auditCmd.analyticsMetricsService.CreateGeneralEvent(xscservices.CliProduct, xscservices.CliEventType))
auditParams := NewAuditParams().
SetXrayGraphScanParams(auditCmd.CreateXrayGraphScanParams()).
SetWorkingDirs(workingDirs).
Expand All @@ -98,10 +118,12 @@ func (auditCmd *AuditCommand) Run() (err error) {
SetGraphBasicParams(auditCmd.AuditBasicParams).
SetThirdPartyApplicabilityScan(auditCmd.thirdPartyApplicabilityScan)
auditParams.SetIsRecursiveScan(isRecursiveScan).SetExclusions(auditCmd.Exclusions())

auditResults, err := RunAudit(auditParams)
if err != nil {
return
}
auditCmd.analyticsMetricsService.UpdateGeneralEvent(auditCmd.analyticsMetricsService.CreateXscAnalyticsGeneralEventFinalizeFromAuditResults(auditResults))
if auditCmd.Progress() != nil {
if err = auditCmd.Progress().Quit(); err != nil {
return
Expand Down Expand Up @@ -171,12 +193,7 @@ func RunAudit(auditParams *AuditParams) (results *xrayutils.Results, err error)
errGroup.Go(utils.DownloadAnalyzerManagerIfNeeded)
}

if auditParams.xrayGraphScanParams.XscGitInfoContext != nil {
if err = xrayutils.SendXscGitInfoRequestIfEnabled(auditParams.xrayGraphScanParams, xrayManager); err != nil {
return nil, err
}
results.MultiScanId = auditParams.xrayGraphScanParams.MultiScanId
}
results.MultiScanId = auditParams.XrayGraphScanParams().MultiScanId

// The sca scan doesn't require the analyzer manager, so it can run separately from the analyzer manager download routine.
results.ScaError = runScaScan(auditParams, results)
Expand All @@ -188,7 +205,7 @@ func RunAudit(auditParams *AuditParams) (results *xrayutils.Results, err error)

// Run scanners only if the user is entitled for Advanced Security
if results.ExtendedScanResults.EntitledForJas {
results.JasError = runJasScannersAndSetResults(results, auditParams.DirectDependencies(), serverDetails, auditParams.workingDirs, auditParams.Progress(), auditParams.thirdPartyApplicabilityScan)
results.JasError = runJasScannersAndSetResults(results, auditParams.DirectDependencies(), serverDetails, auditParams.workingDirs, auditParams.Progress(), auditParams.thirdPartyApplicabilityScan, auditParams.XrayGraphScanParams().MultiScanId)
}
return
}
Expand Down
41 changes: 41 additions & 0 deletions commands/audit/jas/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package jas
import (
"errors"
"fmt"
clientutils "github.com/jfrog/jfrog-client-go/utils"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -274,3 +275,43 @@ func GetExcludePatterns(module jfrogappsconfig.Module, scanner *jfrogappsconfig.
}
return excludePatterns
}

func SetAnalyticsMetricsDataForAnalyzerManager(msi string, technologies []coreutils.Technology) func() {
errMsg := "failed %s %s environment variable. Cause: %s"
resetAnalyzerManageJfMsiVar, err := clientutils.SetEnvWithResetCallback(utils.JfMsiEnvVariable, msi)
if err != nil {
log.Debug(fmt.Sprintf(errMsg, "setting", utils.JfMsiEnvVariable, err.Error()))
}
if len(technologies) != 1 {
// Only report analytics for one technology at a time.
return func() {
err = resetAnalyzerManageJfMsiVar()
if err != nil {
log.Debug(fmt.Sprintf(errMsg, "restoring", utils.JfMsiEnvVariable, err.Error()))
}
}
}
technology := technologies[0]
resetAnalyzerManagerPackageManagerVar, err := clientutils.SetEnvWithResetCallback(utils.JfPackageManagerEnvVariable, technology.String())
if err != nil {
log.Debug(fmt.Sprintf(errMsg, "setting", utils.JfPackageManagerEnvVariable, err.Error()))
}
resetAnalyzerManagerLanguageVar, err := clientutils.SetEnvWithResetCallback(utils.JfLanguageEnvVariable, string(utils.TechnologyToLanguage(technology)))
if err != nil {
log.Debug(fmt.Sprintf(errMsg, "setting", utils.JfLanguageEnvVariable, err.Error()))
}
return func() {
err = resetAnalyzerManageJfMsiVar()
if err != nil {
log.Debug(fmt.Sprintf(errMsg, "restoring", utils.JfMsiEnvVariable, err.Error()))
}
err = resetAnalyzerManagerPackageManagerVar()
if err != nil {
log.Debug(fmt.Sprintf(errMsg, "restoring", utils.JfPackageManagerEnvVariable, err.Error()))
}
err = resetAnalyzerManagerLanguageVar()
if err != nil {
log.Debug(fmt.Sprintf(errMsg, "restoring", utils.JfLanguageEnvVariable, err.Error()))
}
}
}
Loading

0 comments on commit c1b4b6a

Please sign in to comment.