Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add XSC analytics metrics capabilities #47

Merged
merged 37 commits into from
Apr 7, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
12dbe00
Add Xsc General Event
gailazar300 Mar 24, 2024
cbc4fcd
Add Xsc General Event
gailazar300 Mar 26, 2024
1951727
Before review fixes.
gailazar300 Mar 26, 2024
c834ad1
Add UpdateGeneralEvent.
gailazar300 Mar 27, 2024
f9c9c0e
Set environments variables for analyzer manager.
gailazar300 Mar 27, 2024
a4f0534
Add tests.
gailazar300 Mar 28, 2024
abc6553
Remove error handling for analytics.
gailazar300 Mar 28, 2024
e79cb1e
Change AnalyticsMetricsService creation.
gailazar300 Mar 28, 2024
b45d003
Merge remote-tracking branch 'upstream/dev' into feature/XRAY-36905
gailazar300 Mar 31, 2024
b3452da
go.mod+sum
gailazar300 Mar 31, 2024
fdb5051
Minor fixes.
gailazar300 Mar 31, 2024
4c68943
Review fixes.
gailazar300 Apr 1, 2024
2c9fcba
Add integration test.
gailazar300 Apr 1, 2024
fc0f2df
Minor fixes.
gailazar300 Apr 1, 2024
b9560da
Change add general event flow for Frogbot.
gailazar300 Apr 2, 2024
040ce9b
Second review fixes.
gailazar300 Apr 2, 2024
40884cb
Remove Frogbot's MSI validation - there is no common flow for cli and…
gailazar300 Apr 2, 2024
51de09a
Minor fix.
gailazar300 Apr 2, 2024
df4ef8f
Minor fix.
gailazar300 Apr 3, 2024
08b1764
Minor fix.
gailazar300 Apr 3, 2024
afc8843
Change UpdateGeneralEvent & moving relevant code from core
gailazar300 Apr 3, 2024
b133a9a
go.mod+sum
gailazar300 Apr 3, 2024
1a2c652
minor fix
gailazar300 Apr 3, 2024
abea15c
minor fix
gailazar300 Apr 3, 2024
f0fdb3a
Fix sending scan to xsc if available.
gailazar300 Apr 3, 2024
e30c3d2
Add CountScanResultsFindings.
gailazar300 Apr 3, 2024
07387e3
Review fixes.
gailazar300 Apr 7, 2024
ced6afd
Review fixes.
gailazar300 Apr 7, 2024
184a565
minor fix.
gailazar300 Apr 7, 2024
696433f
minor fix.
gailazar300 Apr 7, 2024
6848af9
Verify valid multi scan id.
gailazar300 Apr 7, 2024
d31a490
fix assert in test.
gailazar300 Apr 7, 2024
016e6a2
add skip.
gailazar300 Apr 7, 2024
8085c42
set ReportUsage to true for analytics unit tests.
gailazar300 Apr 7, 2024
d28471b
fix tests
gailazar300 Apr 7, 2024
b267bc4
add sleep for windows test
gailazar300 Apr 7, 2024
b730136
minor fix
gailazar300 Apr 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions cli/scancommands.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cli

import (
"fmt"
"os"
"strings"

Expand Down Expand Up @@ -349,6 +350,12 @@ func createAuditCmd(c *components.Context) (*audit.AuditCommand, error) {
if err != nil {
return nil, err
}
analytics, err := utils.NewAnalyticsMetricsService(serverDetails)
if err != nil {
log.Debug(fmt.Sprintf("Failed to create analytics metrics service. %s", err.Error()))
} else {
auditCmd.SetAnalyticsMetricsService(analytics)
}
auditCmd.SetTargetRepoPath(addTrailingSlashToRepoPathIfNeeded(c)).
SetProject(c.GetStringFlagValue(flags.Project)).
SetIncludeVulnerabilities(shouldIncludeVulnerabilities(c)).
Expand Down
36 changes: 22 additions & 14 deletions commands/audit/audit.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,28 @@ package audit

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

"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"
"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 +66,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 Down Expand Up @@ -98,10 +103,16 @@ func (auditCmd *AuditCommand) Run() (err error) {
SetGraphBasicParams(auditCmd.AuditBasicParams).
SetThirdPartyApplicabilityScan(auditCmd.thirdPartyApplicabilityScan)
auditParams.SetIsRecursiveScan(isRecursiveScan).SetExclusions(auditCmd.Exclusions())
if auditCmd.analyticsMetricsService != nil {
auditCmd.analyticsMetricsService.AddGeneralEventAndSetMsi(auditParams.xrayGraphScanParams)
}
auditResults, err := RunAudit(auditParams)
if err != nil {
return
}
if auditCmd.analyticsMetricsService != nil {
auditCmd.analyticsMetricsService.UpdateGeneralEvent(auditResults)
}
if auditCmd.Progress() != nil {
if err = auditCmd.Progress().Quit(); err != nil {
return
Expand Down Expand Up @@ -171,10 +182,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
}
if auditParams.xrayGraphScanParams.MultiScanId != "" {
results.MultiScanId = auditParams.xrayGraphScanParams.MultiScanId
}
gailazar300 marked this conversation as resolved.
Show resolved Hide resolved

Expand Down
27 changes: 27 additions & 0 deletions commands/audit/jas/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,3 +274,30 @@ func GetExcludePatterns(module jfrogappsconfig.Module, scanner *jfrogappsconfig.
}
return excludePatterns
}

func SetAnalyticsMetricsDataForAnalyzerManager(technologies []coreutils.Technology) {
// For now only one value is supported.
if len(technologies) != 1 {
return
}
technology := technologies[0]
err := os.Setenv("AM_PACKAGE_MANAGER", technology.String())
if err != nil {
log.Debug(fmt.Sprintf("failed setting AM_PACKAGE_MANAGER as environment variable. Cause: %s", err.Error()))
}
err = os.Setenv("AM_LANGUAGE", coreutils.TechnologyToLanguage(technology))
if err != nil {
log.Debug(fmt.Sprintf("failed setting AM_LANGUAGE as environment variable. Cause: %s", err.Error()))
}
}

func ResetAnalyticsMetricsDataForAnalyzerManager() {
err := os.Setenv("AM_PACKAGE_MANAGER", "")
if err != nil {
log.Debug(fmt.Sprintf("failed setting AM_PACKAGE_MANAGER as environment variable. Cause: %s", err.Error()))
}
gailazar300 marked this conversation as resolved.
Show resolved Hide resolved
err = os.Setenv("AM_LANGUAGE", "")
if err != nil {
log.Debug(fmt.Sprintf("failed setting AM_LANGUAGE as environment variable. Cause: %s", err.Error()))
}
gailazar300 marked this conversation as resolved.
Show resolved Hide resolved
}
3 changes: 3 additions & 0 deletions commands/audit/jasrunner.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ func runJasScannersAndSetResults(scanResults *utils.Results, directDependencies
if progress != nil {
progress.SetHeadlineMsg("Running applicability scanning")
}
// Set environments variables for analytics in analyzers manager.
jas.SetAnalyticsMetricsDataForAnalyzerManager(scanResults.GetScaScannedTechnologies())
defer jas.ResetAnalyticsMetricsDataForAnalyzerManager()
scanResults.ExtendedScanResults.ApplicabilityScanResults, err = applicability.RunApplicabilityScan(scanResults.GetScaScansXrayResults(), directDependencies, scanResults.GetScaScannedTechnologies(), scanner, thirdPartyApplicabilityScan)
if err != nil {
return
Expand Down
5 changes: 0 additions & 5 deletions commands/scan/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,11 +349,6 @@ func (scanCmd *ScanCommand) createIndexerHandlerFunc(file *spec.File, indexedFil
if err != nil {
return err
}
if params.XscGitInfoContext != nil {
if err = utils.SendXscGitInfoRequestIfEnabled(scanGraphParams.XrayGraphScanParams(), xrayManager); err != nil {
return err
}
}
scanResults, err := scangraph.RunScanGraphAndGetResults(scanGraphParams, xrayManager)
if err != nil {
log.Error(fmt.Sprintf("scanning '%s' failed with error: %s", graph.Id, err.Error()))
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,8 @@ require (
gopkg.in/warnings.v0 v0.1.2 // indirect
)

// replace github.com/jfrog/jfrog-cli-core/v2 => github.com/jfrog/jfrog-cli-core/v2 dev
replace github.com/jfrog/jfrog-cli-core/v2 => ../jfrog-cli-core

// replace github.com/jfrog/jfrog-client-go => github.com/jfrog/jfrog-client-go dev
replace github.com/jfrog/jfrog-client-go => ../jfrog-client-go

// replace github.com/jfrog/build-info-go => github.com/jfrog/build-info-go dev
4 changes: 0 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,6 @@ github.com/jfrog/gofrog v1.6.3 h1:F7He0+75HcgCe6SGTSHLFCBDxiE2Ja0tekvvcktW6wc=
github.com/jfrog/gofrog v1.6.3/go.mod h1:SZ1EPJUruxrVGndOzHd+LTiwWYKMlHqhKD+eu+v5Hqg=
github.com/jfrog/jfrog-apps-config v1.0.1 h1:mtv6k7g8A8BVhlHGlSveapqf4mJfonwvXYLipdsOFMY=
github.com/jfrog/jfrog-apps-config v1.0.1/go.mod h1:8AIIr1oY9JuH5dylz2S6f8Ym2MaadPLR6noCBO4C22w=
github.com/jfrog/jfrog-cli-core/v2 v2.49.0 h1:HhhwmenyAzRNXUY4KNHKmRH9fcaohCzvcWfzLx/Lt5M=
github.com/jfrog/jfrog-cli-core/v2 v2.49.0/go.mod h1:t7SigeX0Fbzsv0RIDGKkYnNQrwgf2cqIfoASoo5qZ2A=
github.com/jfrog/jfrog-client-go v1.38.0 h1:0QP4/dSmJe0oYUrAqzoPDpGdJHcrOeq9mycnb0pSxqQ=
github.com/jfrog/jfrog-client-go v1.38.0/go.mod h1:EHRLxpu0pIT7+ulYDNQ7IeieYBHMQeEPr8CoBHoJzQY=
github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/klauspost/compress v1.4.1/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
Expand Down
1 change: 1 addition & 0 deletions jfrogclisecurity_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ func setupIntegrationTests() {
// Init
utils.InitTestCliDetails()
utils.AuthenticateArtifactory()
utils.AuthenticateXsc()
utils.CreateRequiredRepositories()
}

Expand Down
154 changes: 154 additions & 0 deletions utils/analyticsmetrics.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package utils

import (
"fmt"
"github.com/jfrog/jfrog-cli-core/v2/utils/config"
"github.com/jfrog/jfrog-cli-core/v2/utils/coreutils"
clientutils "github.com/jfrog/jfrog-client-go/utils"
"github.com/jfrog/jfrog-client-go/utils/log"
"github.com/jfrog/jfrog-client-go/xray/services"
"github.com/jfrog/jfrog-client-go/xsc"
xscservices "github.com/jfrog/jfrog-client-go/xsc/services"
"os"
"strings"
"time"
)

const AnalyticsMetricsMinXscVersion = "1.7.1"

type AnalyticsMetricsService struct {
xscManager *xsc.XscServicesManager
// Should the CLI reports analytics metrics to XSC.
shouldReportEvents bool
msi string
startTime time.Time
}

func NewAnalyticsMetricsService(serviceDetails *config.ServerDetails) (*AnalyticsMetricsService, error) {
ams := AnalyticsMetricsService{}
xscManager, err := CreateXscServiceManager(serviceDetails)
if err != nil {
return nil, err
}
ams.xscManager = xscManager
ams.shouldReportEvents = ams.calcShouldReportEvents()
return &ams, nil
}

func (ams *AnalyticsMetricsService) calcShouldReportEvents() bool {
// A user who explicitly requests not to send reports will not receive XSC analytics metrics.
if os.Getenv(coreutils.ReportUsage) == "false" {
return false
}
// There is no need to report the event and generate a new msi for the cli scan if the msi was provided.
if os.Getenv(jfMsiEnvVariable) != "" {
return false
}
// Verify xsc version.
xscVersion, err := ams.xscManager.GetVersion()
if err != nil {
return false
}
if err = clientutils.ValidateMinimumVersion(clientutils.Xsc, xscVersion, AnalyticsMetricsMinXscVersion); err != nil {
return false
}
return true
}

func (ams *AnalyticsMetricsService) SetMsi(msi string) {
ams.msi = msi
}

func (ams *AnalyticsMetricsService) GetMsi() string {
return ams.msi
}

func (ams *AnalyticsMetricsService) SetStartTime() {
ams.startTime = time.Now()
}

func (ams *AnalyticsMetricsService) GetStartTime() time.Time {
return ams.startTime
}

func (ams *AnalyticsMetricsService) ShouldReportEvents() bool {
return ams.shouldReportEvents
}

func (ams *AnalyticsMetricsService) AddGeneralEventAndSetMsi(params *services.XrayGraphScanParams) {
if !ams.ShouldReportEvents() {
log.Debug("A general event request was not sent to XSC - analytics metrics are disabled.")
gailazar300 marked this conversation as resolved.
Show resolved Hide resolved
return
}
err := ams.AddGeneralEvent()
if err != nil {
log.Debug(fmt.Errorf("failed sending general event request to XSC service, error: %s ", err.Error()))
return
}
log.Debug(fmt.Sprintf("New General event added successfully. multi_scan_id %s", ams.GetMsi()))

if err = os.Setenv(jfMsiEnvVariable, ams.GetMsi()); err != nil {
// Not a fatal error, if not set the scan will not be shown at the XSC UI, should not fail the scan.
log.Debug(fmt.Sprintf("failed setting MSI as environment variable. Cause: %s", err.Error()))
}
// Before running the audit command, set the msi so the sca scan will be performed on the xsc rather than on the xray server.
params.MultiScanId = ams.GetMsi()
gailazar300 marked this conversation as resolved.
Show resolved Hide resolved
}
func (ams *AnalyticsMetricsService) AddGeneralEvent() error {
osAndArc, err := coreutils.GetOSAndArc()
if err != nil {
return err
}
splitOsAndArch := strings.Split(osAndArc, "-")
event := xscservices.XscAnalyticsBasicGeneralEvent{
EventType: 1,
EventStatus: xscservices.Started,
Product: "cli",
JfrogUser: ams.xscManager.Config().GetServiceDetails().GetUser(),
OsPlatform: splitOsAndArch[0],
OsArchitecture: splitOsAndArch[1],
AnalyzerManagerVersion: GetAnalyzerManagerVersion(),
JpdVersion: "", //TODO artifactory version,
}

msi, err := ams.xscManager.AddAnalyticsGeneralEvent(xscservices.XscAnalyticsGeneralEvent{XscAnalyticsBasicGeneralEvent: event})
if err != nil {
return err
}
// Set event's analytics data.
ams.SetMsi(msi)
ams.SetStartTime()
return nil
}

func (ams *AnalyticsMetricsService) UpdateGeneralEvent(auditResults *Results) {
if !ams.ShouldReportEvents() {
log.Debug("A general event update request was not sent to XSC - analytics metrics are disabled.")
return
}
gailazar300 marked this conversation as resolved.
Show resolved Hide resolved
event := xscservices.XscAnalyticsGeneralEventFinalize{
MultiScanId: ams.msi,
XscAnalyticsBasicGeneralEvent: ams.createAuditResultsFromXscAnalyticsBasicGeneralEvent(auditResults),
}
err := ams.xscManager.UpdateAnalyticsGeneralEvent(event)
if err != nil {
log.Debug(fmt.Sprintf("failed updading general event request in XSC service for multi_scan_id %s, error: %s \"", ams.GetMsi(), err.Error()))
}
}

func (ams *AnalyticsMetricsService) createAuditResultsFromXscAnalyticsBasicGeneralEvent(auditResults *Results) xscservices.XscAnalyticsBasicGeneralEvent {
totalDuration := time.Now().Sub(ams.GetStartTime())
totalFindings := len(auditResults.ScaResults)
if auditResults.ExtendedScanResults != nil {
totalFindings += len(auditResults.ExtendedScanResults.ApplicabilityScanResults) + len(auditResults.ExtendedScanResults.SecretsScanResults) + len(auditResults.ExtendedScanResults.IacScanResults) + len(auditResults.ExtendedScanResults.SastScanResults)
}
eventStatus := xscservices.Completed
if auditResults.ScaError != nil || auditResults.JasError != nil {
eventStatus = xscservices.Failed
}
return xscservices.XscAnalyticsBasicGeneralEvent{
EventStatus: eventStatus,
TotalFindings: totalFindings,
TotalScanDuration: totalDuration.String(),
}
}
Loading
Loading