Skip to content

Commit

Permalink
Merge branch 'dev' into releaseBundleV2
Browse files Browse the repository at this point in the history
  • Loading branch information
oshratZairi authored Jan 6, 2025
2 parents aab504a + e342ed5 commit 6b6e8d6
Show file tree
Hide file tree
Showing 16 changed files with 347 additions and 103 deletions.
18 changes: 10 additions & 8 deletions artifactory/services/utils/tests/xray/consts.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package xray

import xrayServices "github.com/jfrog/jfrog-client-go/xray/services"
import (
xscServices "github.com/jfrog/jfrog-client-go/xsc/services"
)

const ScanResponse = `
{
Expand Down Expand Up @@ -1437,15 +1439,15 @@ const XscGitInfoResponse = `{"multi_scan_id": "3472b4e2-bddc-11ee-a9c9-acde48001

const XscGitInfoBadResponse = `"failed create git info request: git_repo_url field must contain value"`

var GitInfoContextWithMinimalRequiredFields = xrayServices.XscGitInfoContext{
GitRepoUrl: "https://git.jfrog.info/projects/XSC/repos/xsc-service",
BranchName: "feature/XRAY-123-cool-feature",
CommitHash: "acc5e24e69a-d3c1-4022-62eb-69e4a1e5",
var GitInfoContextWithMinimalRequiredFields = xscServices.XscGitInfoContext{
GitRepoHttpsCloneUrl: "https://git.jfrog.info/projects/XSC/repos/xsc-service",
BranchName: "feature/XRAY-123-cool-feature",
LastCommitHash: "acc5e24e69a-d3c1-4022-62eb-69e4a1e5",
}

var GitInfoContextWithMissingFields = xrayServices.XscGitInfoContext{
GitRepoUrl: "https://git.jfrog.info/projects/XSC/repos/xsc-service",
BranchName: "feature/XRAY-123-cool-feature",
var GitInfoContextWithMissingFields = xscServices.XscGitInfoContext{
GitRepoHttpsCloneUrl: "https://git.jfrog.info/projects/XSC/repos/xsc-service",
BranchName: "feature/XRAY-123-cool-feature",
}

const TestMultiScanId = "3472b4e2-bddc-11ee-a9c9-acde48001122"
Expand Down
21 changes: 5 additions & 16 deletions artifactory/usage/call_home.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ import (
"github.com/jfrog/jfrog-client-go/utils/io/httputils"
)

const minArtifactoryVersion = "6.9.0"

type ReportUsageAttribute struct {
AttributeName string
AttributeValue string
Expand All @@ -28,7 +26,7 @@ func (rua *ReportUsageAttribute) isEmpty() bool {
return rua.AttributeName == ""
}

func (ach *ArtifactoryCallHome) validateAndGetUsageServerInfo(serviceManager artifactory.ArtifactoryServicesManager) (url string, clientDetails httputils.HttpClientDetails, err error) {
func (ach *ArtifactoryCallHome) getUsageServerInfo(serviceManager artifactory.ArtifactoryServicesManager) (url string, clientDetails httputils.HttpClientDetails, err error) {
config := serviceManager.GetConfig()
if config == nil {
err = errorutils.CheckErrorf("expected full config, but no configuration exists.")
Expand All @@ -39,15 +37,6 @@ func (ach *ArtifactoryCallHome) validateAndGetUsageServerInfo(serviceManager art
err = errorutils.CheckErrorf("Artifactory details not configured.")
return
}
// Check Artifactory version
artifactoryVersion, err := rtDetails.GetVersion()
if err != nil {
err = errors.New("Couldn't get Artifactory version. Error: " + err.Error())
return
}
if err = clientutils.ValidateMinimumVersion(clientutils.Artifactory, artifactoryVersion, minArtifactoryVersion); err != nil {
return
}
url, err = clientutils.BuildUrl(rtDetails.GetUrl(), "api/system/usage", make(map[string]string))
if err != nil {
return
Expand All @@ -69,8 +58,8 @@ func (ach *ArtifactoryCallHome) sendReport(url string, serviceManager artifactor
return nil
}

func (ach *ArtifactoryCallHome) SendUsageToArtifactory(productId string, serviceManager artifactory.ArtifactoryServicesManager, features ...Feature) error {
url, clientDetails, err := ach.validateAndGetUsageServerInfo(serviceManager)
func (ach *ArtifactoryCallHome) SendToArtifactory(productId string, serviceManager artifactory.ArtifactoryServicesManager, features ...Feature) error {
url, clientDetails, err := ach.getUsageServerInfo(serviceManager)
if err != nil || url == "" {
return err
}
Expand All @@ -81,8 +70,8 @@ func (ach *ArtifactoryCallHome) SendUsageToArtifactory(productId string, service
return ach.sendReport(url, serviceManager, clientDetails, bodyContent)
}

func (ach *ArtifactoryCallHome) SendUsage(productId, commandName string, serviceManager artifactory.ArtifactoryServicesManager, attributes ...ReportUsageAttribute) error {
url, clientDetails, err := ach.validateAndGetUsageServerInfo(serviceManager)
func (ach *ArtifactoryCallHome) Send(productId, commandName string, serviceManager artifactory.ArtifactoryServicesManager, attributes ...ReportUsageAttribute) error {
url, clientDetails, err := ach.getUsageServerInfo(serviceManager)
if err != nil || url == "" {
return err
}
Expand Down
1 change: 1 addition & 0 deletions jfconnect/services/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func (jcs *JfConnectService) PostVisibilityMetric(metric VisibilityMetric) error

type Labels struct {
ProductID string `json:"product_id"`
ProductVersion string `json:"product_version"`
FeatureID string `json:"feature_id"`
OIDCUsed string `json:"oidc_used"`
JobID string `json:"job_id"`
Expand Down
7 changes: 3 additions & 4 deletions xray/services/enrich.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,7 @@ func (es *EnrichService) GetImportGraphResults(scanId string) (*ScanResponse, er
type XrayGraphImportParams struct {
// A path in Artifactory that this Artifact is intended to be deployed to.
// This will provide a way to extract the watches that should be applied on this graph
ScanType ScanType
SBOMInput []byte
XscGitInfoContext *XscGitInfoContext
XscVersion string
ScanType ScanType
SBOMInput []byte
XscVersion string
}
23 changes: 22 additions & 1 deletion xray/services/ignorerule.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,12 @@ func (xirs *IgnoreRuleService) Delete(ignoreRuleId string) error {
}

// Create will create a new Xray ignore rule
// The function creates the ignore rule and returns its id which is recieved after post
// The function creates the ignore rule and returns its id which is received after post
func (xirs *IgnoreRuleService) Create(params utils.IgnoreRuleParams) (ignoreRuleId string, err error) {
ignoreRuleBody := utils.CreateIgnoreRuleBody(params)
if err = validateIgnoreFilters(ignoreRuleBody.IgnoreFilters); err != nil {
return "", err
}
content, err := json.Marshal(ignoreRuleBody)
if err != nil {
return "", errorutils.CheckError(err)
Expand Down Expand Up @@ -98,6 +101,24 @@ func (xirs *IgnoreRuleService) Create(params utils.IgnoreRuleParams) (ignoreRule
return ignoreRuleId, nil
}

func validateIgnoreFilters(ignoreFilters utils.IgnoreFilters) error {
filters := []string{}
if len(ignoreFilters.CVEs) > 0 {
filters = append(filters, "CVEs")
}
if ignoreFilters.Exposures != nil {
filters = append(filters, "Exposures")
}
if ignoreFilters.Sast != nil {
filters = append(filters, "Sast")
}
// if more than one filter is set, notify the user
if len(filters) > 1 {
return errorutils.CheckErrorf("more than one ignore filter is set, split them to multiple ignore rules: %v", filters)
}
return nil
}

func getIgnoreRuleIdFromBody(body []byte) (string, error) {
str := string(body)

Expand Down
59 changes: 27 additions & 32 deletions xray/services/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ import (
"strings"
"time"

clientUtils "github.com/jfrog/jfrog-client-go/utils"
"github.com/jfrog/jfrog-client-go/utils/log"
xrayUtils "github.com/jfrog/jfrog-client-go/xray/services/utils"
"github.com/jfrog/jfrog-client-go/xsc/services/utils"
xscUtils "github.com/jfrog/jfrog-client-go/xsc/services/utils"

"github.com/jfrog/jfrog-client-go/auth"
"github.com/jfrog/jfrog-client-go/http/jfroghttpclient"
Expand Down Expand Up @@ -46,7 +47,8 @@ const (

scanTechQueryParam = "tech="

XscVersionAPI = "system/version"
gitRepoKeyQueryParam = "git_repo="
MinXrayVersionGitRepoKey = "3.111.0"
)

type ScanType string
Expand Down Expand Up @@ -75,28 +77,33 @@ func createScanGraphQueryParams(scanParams XrayGraphScanParams) string {
}
}
}

// Xsc params are used only when XSC is enabled and MultiScanId is provided
if scanParams.XscVersion != "" && scanParams.MultiScanId != "" {
params = append(params, multiScanIdParam+scanParams.MultiScanId)
gitInfoContext := scanParams.XscGitInfoContext
if gitInfoContext != nil {
if len(gitInfoContext.Technologies) > 0 {
// Append the tech type, each graph can contain only one tech type
params = append(params, scanTechQueryParam+gitInfoContext.Technologies[0])
}
if scanParams.Technology != "" {
params = append(params, scanTechQueryParam+scanParams.Technology)
}
}

if scanParams.ScanType != "" {
params = append(params, scanTypeQueryParam+string(scanParams.ScanType))
}

if isGitRepoUrlSupported(scanParams.XrayVersion) && scanParams.GitRepoHttpsCloneUrl != "" {
// Add git repo key to the query params to produce violations defined in the git repo policy
params = append(params, gitRepoKeyQueryParam+xscUtils.GetGitRepoUrlKey(scanParams.GitRepoHttpsCloneUrl))
}

if len(params) == 0 {
return ""
}
return "?" + strings.Join(params, "&")
}

func isGitRepoUrlSupported(xrayVersion string) bool {
return clientUtils.ValidateMinimumVersion(clientUtils.Xray, xrayVersion, MinXrayVersionGitRepoKey) == nil
}

func (ss *ScanService) ScanGraph(scanParams XrayGraphScanParams) (string, error) {
httpClientsDetails := ss.XrayDetails.CreateHttpClientDetails()
httpClientsDetails.SetContentTypeApplicationJson()
Expand All @@ -114,7 +121,7 @@ func (ss *ScanService) ScanGraph(scanParams XrayGraphScanParams) (string, error)

// When XSC is enabled and MultiScanId is provided, modify the URL to use XSC scan graph (analytics enabled)
if scanParams.XrayVersion != "" && scanParams.XscVersion != "" && scanParams.MultiScanId != "" {
url = utils.XrayUrlToXscUrl(ss.XrayDetails.GetUrl(), scanParams.XrayVersion) + XscGraphAPI
url = xscUtils.XrayUrlToXscUrl(ss.XrayDetails.GetUrl(), scanParams.XrayVersion) + XscGraphAPI
}
url += createScanGraphQueryParams(scanParams)
resp, body, err := ss.client.SendPost(url, requestBody, &httpClientsDetails)
Expand Down Expand Up @@ -144,7 +151,7 @@ func (ss *ScanService) GetScanGraphResults(scanId, xrayVersion string, includeVu
endPoint := ss.XrayDetails.GetUrl() + scanGraphAPI
// Modify endpoint if XSC is enabled
if xscEnabled {
endPoint = utils.XrayUrlToXscUrl(ss.XrayDetails.GetUrl(), xrayVersion) + XscGraphAPI
endPoint = xscUtils.XrayUrlToXscUrl(ss.XrayDetails.GetUrl(), xrayVersion) + XscGraphAPI
}
endPoint += "/" + scanId

Expand Down Expand Up @@ -183,7 +190,10 @@ func (ss *ScanService) GetScanGraphResults(scanId, xrayVersion string, includeVu
type XrayGraphScanParams struct {
// A path in Artifactory that this Artifact is intended to be deployed to.
// This will provide a way to extract the watches that should be applied on this graph
RepoPath string
RepoPath string
// This will provide a way to extract the watches that should be applied on this graph
GitRepoHttpsCloneUrl string
// This will provide a way to extract the watches that should be applied on this graph
ProjectKey string
Watches []string
ScanType ScanType
Expand All @@ -193,9 +203,9 @@ type XrayGraphScanParams struct {
BinaryGraph *xrayUtils.BinaryGraphNode
IncludeVulnerabilities bool
IncludeLicenses bool
XscGitInfoContext *XscGitInfoContext
XscVersion string
XrayVersion string
Technology string
MultiScanId string
}

Expand Down Expand Up @@ -231,6 +241,7 @@ type Violation struct {
LicenseKey string `json:"license_key,omitempty"`
LicenseName string `json:"license_name,omitempty"`
IgnoreUrl string `json:"ignore_url,omitempty"`
Policies []Policy `json:"policies,omitempty"`
RiskReason string `json:"risk_reason,omitempty"`
IsEol *bool `json:"is_eol,omitempty"`
EolMessage string `json:"eol_message,omitempty"`
Expand Down Expand Up @@ -308,25 +319,9 @@ type JfrogResearchSeverityReason struct {
IsPositive bool `json:"is_positive,omitempty"`
}

type XscPostContextResponse struct {
MultiScanId string `json:"multi_scan_id,omitempty"`
}

type XscVersionResponse struct {
Version string `json:"xsc_version"`
}

type XscGitInfoContext struct {
GitRepoUrl string `json:"git_repo_url"`
GitRepoName string `json:"git_repo_name,omitempty"`
GitProject string `json:"git_project,omitempty"`
GitProvider string `json:"git_provider,omitempty"`
Technologies []string `json:"technologies,omitempty"`
BranchName string `json:"branch_name"`
LastCommit string `json:"last_commit,omitempty"`
CommitHash string `json:"commit_hash"`
CommitMessage string `json:"commit_message,omitempty"`
CommitAuthor string `json:"commit_author,omitempty"`
type Policy struct {
Policy string `json:"policy,omitempty"`
Rule string `json:"rule,omitempty"`
}

func (gp *XrayGraphScanParams) GetProjectKey() string {
Expand Down
65 changes: 37 additions & 28 deletions xray/services/scan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,39 +8,48 @@ import (
func TestCreateScanGraphQueryParams(t *testing.T) {
tests := []struct {
testName string
projectKey string
repoPath string
watches []string
scanType ScanType
params XrayGraphScanParams
expectedQuery string
}{
{"with_project_key", "p1", "", nil, Binary,
fmt.Sprintf("?%s%s&%s%s", projectQueryParam, "p1", scanTypeQueryParam, Binary)},

{"with_repo_path", "", "r1", nil, Binary,
fmt.Sprintf("?%s%s&%s%s", repoPathQueryParam, "r1", scanTypeQueryParam, Binary)},

{"with_watches", "", "", []string{"w1", "w2"}, Binary,
fmt.Sprintf("?%s%s&%s%s&%s%s", watchesQueryParam, "w1", watchesQueryParam, "w2", scanTypeQueryParam, Binary)},

{"with_empty_watch_string", "", "", []string{""}, "",
""},

{"without_context", "", "", nil, Dependency,
fmt.Sprintf("?%s%s", scanTypeQueryParam, Dependency)},

{"without_scan_type", "", "", []string{"w1", "w2"}, "",
fmt.Sprintf("?%s%s&%s%s", watchesQueryParam, "w1", watchesQueryParam, "w2")},
{
testName: "with_project_key",
params: XrayGraphScanParams{ProjectKey: "p1", ScanType: Binary},
expectedQuery: fmt.Sprintf("?%s%s&%s%s", projectQueryParam, "p1", scanTypeQueryParam, Binary),
},
{
testName: "with_repo_path",
params: XrayGraphScanParams{RepoPath: "r1", ScanType: Binary},
expectedQuery: fmt.Sprintf("?%s%s&%s%s", repoPathQueryParam, "r1", scanTypeQueryParam, Binary),
},
{
testName: "with_watches",
params: XrayGraphScanParams{Watches: []string{"w1", "w2"}, ScanType: Binary},
expectedQuery: fmt.Sprintf("?%s%s&%s%s&%s%s", watchesQueryParam, "w1", watchesQueryParam, "w2", scanTypeQueryParam, Binary),
},
{
testName: "with_empty_watch_string",
params: XrayGraphScanParams{Watches: []string{""}},
expectedQuery: "",
},
{
testName: "without_context",
params: XrayGraphScanParams{ScanType: Dependency, XrayVersion: MinXrayVersionGitRepoKey},
expectedQuery: fmt.Sprintf("?%s%s", scanTypeQueryParam, Dependency),
},
{
testName: "without_scan_type",
params: XrayGraphScanParams{Watches: []string{"w1", "w2"}},
expectedQuery: fmt.Sprintf("?%s%s&%s%s", watchesQueryParam, "w1", watchesQueryParam, "w2"),
},
{
testName: "with_git_repo_url",
params: XrayGraphScanParams{GitRepoHttpsCloneUrl: "http://some-url", ScanType: Dependency, XrayVersion: MinXrayVersionGitRepoKey},
expectedQuery: fmt.Sprintf("?%s%s&%s%s", scanTypeQueryParam, Dependency, gitRepoKeyQueryParam, "some-url.git"),
},
}
for _, test := range tests {
t.Run(test.testName, func(t *testing.T) {
params := XrayGraphScanParams{
RepoPath: test.repoPath,
Watches: test.watches,
ProjectKey: test.projectKey,
ScanType: test.scanType,
}
actualQuery := createScanGraphQueryParams(params)
actualQuery := createScanGraphQueryParams(test.params)
if actualQuery != test.expectedQuery {
t.Error(test.testName, "Expecting:", test.expectedQuery, "Got:", actualQuery)
}
Expand Down
Loading

0 comments on commit 6b6e8d6

Please sign in to comment.