diff --git a/xray/manager.go b/xray/manager.go index 25256d90f..c34ea94aa 100644 --- a/xray/manager.go +++ b/xray/manager.go @@ -111,7 +111,7 @@ func (sm *XrayServicesManager) DeletePolicy(policyName string) error { return policyService.Delete(policyName) } -// CreatePolicy will create a new Xray ignore rule +// CreateIgnoreRule will create a new Xray ignore rule // The function returns the ignore rule id if succeeded or empty string and error message if fails func (sm *XrayServicesManager) CreateIgnoreRule(params utils.IgnoreRuleParams) (string, error) { ignoreRuleService := services.NewIgnoreRuleService(sm.client) @@ -119,22 +119,30 @@ func (sm *XrayServicesManager) CreateIgnoreRule(params utils.IgnoreRuleParams) ( return ignoreRuleService.Create(params) } -// CreatePolicy will create a new Xray ignore rule -// The function returns the ignore rule id if succeeded or empty string and error message if fails -func (sm *XrayServicesManager) GetIgnoreRule(ignoreRuleId string) (*utils.IgnoreRuleParams, error) { +// GetIgnoreRule will get an Xray ignore rule for the provided ignore rule id. +// The function returns a pointer to the utils.IgnoreRuleBody or nil and error message if fails +func (sm *XrayServicesManager) GetIgnoreRule(ignoreRuleId string) (*utils.IgnoreRuleBody, error) { ignoreRuleService := services.NewIgnoreRuleService(sm.client) ignoreRuleService.XrayDetails = sm.config.GetServiceDetails() return ignoreRuleService.Get(ignoreRuleId) } -// CreatePolicy will create a new Xray ignore rule -// The function returns the ignore rule id if succeeded or empty string and error message if fails +// DeleteIgnoreRule will delete the Xray ignore rule matching the id provided. +// The function returns a nil error if it succeeds, and an error if fails func (sm *XrayServicesManager) DeleteIgnoreRule(ignoreRuleId string) error { ignoreRuleService := services.NewIgnoreRuleService(sm.client) ignoreRuleService.XrayDetails = sm.config.GetServiceDetails() return ignoreRuleService.Delete(ignoreRuleId) } +// GetAllIgnoreRules Returns all Ignore Rules by specific filters. +// The function returns a pointer to utils.IgnoreRuleResponse or nil and error message if fails +func (sm *XrayServicesManager) GetAllIgnoreRules(params *utils.IgnoreRulesGetAllParams) (*utils.IgnoreRuleResponse, error) { + ignoreRuleService := services.NewIgnoreRuleService(sm.client) + ignoreRuleService.XrayDetails = sm.config.GetServiceDetails() + return ignoreRuleService.GetAll(params) +} + // AddBuildsToIndexing will add builds to Xray indexing configuration func (sm *XrayServicesManager) AddBuildsToIndexing(buildNames []string) error { binMgrService := services.NewBinMgrService(sm.client) diff --git a/xray/services/ignorerule.go b/xray/services/ignorerule.go index 440ca6ffe..6738cb700 100644 --- a/xray/services/ignorerule.go +++ b/xray/services/ignorerule.go @@ -16,7 +16,8 @@ import ( ) const ( - ignoreRuleAPIURL = "api/v1/ignore_rules" + ignoreRuleAPIURL = "api/v1/ignore_rules" + minXrayIgnoreRulesVersion = "3.11" ) // IgnoreRuleService defines the http client and Xray details @@ -40,6 +41,19 @@ func (xirs *IgnoreRuleService) GetJfrogHttpClient() *jfroghttpclient.JfrogHttpCl return xirs.client } +func (xirs *IgnoreRuleService) CheckMinimumVersion() error { + xrDetails := xirs.GetXrayDetails() + if xrDetails == nil { + return errorutils.CheckErrorf("Xray details not configured.") + } + version, err := xrDetails.GetVersion() + if err != nil { + return fmt.Errorf("couldn't get Xray version. Error: %w", err) + } + + return clientutils.ValidateMinimumVersion(clientutils.Xray, version, minXrayIgnoreRulesVersion) +} + // The getIgnoreRuleURL does not end with a slash // So, calling functions will need to add it func (xirs *IgnoreRuleService) getIgnoreRuleURL() string { @@ -48,6 +62,9 @@ func (xirs *IgnoreRuleService) getIgnoreRuleURL() string { // Delete will delete an ignore rule by id func (xirs *IgnoreRuleService) Delete(ignoreRuleId string) error { + if err := xirs.CheckMinimumVersion(); err != nil { + return err + } httpClientsDetails := xirs.XrayDetails.CreateHttpClientDetails() artUtils.SetContentType("application/json", &httpClientsDetails.Headers) @@ -65,8 +82,11 @@ 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) { + if err := xirs.CheckMinimumVersion(); err != nil { + return "", err + } ignoreRuleBody := utils.CreateIgnoreRuleBody(params) content, err := json.Marshal(ignoreRuleBody) if err != nil { @@ -114,26 +134,56 @@ func getIgnoreRuleIdFromBody(body []byte) (string, error) { // Get retrieves the details about an Xray ignore rule by its id // It will error if the ignore rule id can't be found. -func (xirs *IgnoreRuleService) Get(ignoreRuleId string) (ignoreRuleResp *utils.IgnoreRuleParams, err error) { +func (xirs *IgnoreRuleService) Get(ignoreRuleId string) (ignoreRuleResp *utils.IgnoreRuleBody, err error) { + if err = xirs.CheckMinimumVersion(); err != nil { + return nil, err + } httpClientsDetails := xirs.XrayDetails.CreateHttpClientDetails() log.Info(fmt.Sprintf("Getting ignore rule '%s'...", ignoreRuleId)) resp, body, _, err := xirs.client.SendGet(xirs.getIgnoreRuleURL()+"/"+ignoreRuleId, true, &httpClientsDetails) ignoreRule := &utils.IgnoreRuleBody{} if err != nil { - return &utils.IgnoreRuleParams{}, err + return nil, err } if err = errorutils.CheckResponseStatusWithBody(resp, body, http.StatusOK); err != nil { log.Debug("Xray response:", string(body), resp.Status) - return &utils.IgnoreRuleParams{}, err + return nil, err } if err = json.Unmarshal(body, ignoreRule); err != nil { - return &utils.IgnoreRuleParams{}, errorutils.CheckErrorf("failed unmarshalling %s for ignore rule %s", string(body), ignoreRuleId) + return nil, errorutils.CheckErrorf("failed unmarshalling %s for ignore rule %s", string(body), ignoreRuleId) } log.Debug("Xray response status:", resp.Status) log.Info("Done getting ignore rule.") - return &ignoreRule.IgnoreRuleParams, nil + return ignoreRule, nil +} + +// GetAll retrieves the details about all Xray ignore rules that match the given filters +func (xirs *IgnoreRuleService) GetAll(params *utils.IgnoreRulesGetAllParams) (ignoreRules *utils.IgnoreRuleResponse, err error) { + if err = xirs.CheckMinimumVersion(); err != nil { + return nil, err + } + httpClientsDetails := xirs.XrayDetails.CreateHttpClientDetails() + url, err := clientutils.BuildUrl(clientutils.AddTrailingSlashIfNeeded(xirs.XrayDetails.GetUrl()), ignoreRuleAPIURL, params.GetParamMap()) + if err != nil { + return nil, err + } + resp, body, _, err := xirs.client.SendGet(url, true, &httpClientsDetails) + ignoreRules = &utils.IgnoreRuleResponse{} + if err != nil { + return nil, err + } + log.Debug("Xray response:", resp.Status) + if err = errorutils.CheckResponseStatusWithBody(resp, body, http.StatusOK); err != nil { + return nil, err + } + err = json.Unmarshal(body, ignoreRules) + if err != nil { + return nil, errorutils.CheckErrorf("failed unmarshalling ignoreRules") + } + + return ignoreRules, nil } diff --git a/xray/services/utils/ignorerulebody.go b/xray/services/utils/ignorerulebody.go index 4b465a162..555396063 100644 --- a/xray/services/utils/ignorerulebody.go +++ b/xray/services/utils/ignorerulebody.go @@ -1,6 +1,9 @@ package utils -import "time" +import ( + "fmt" + "time" +) type IgnoreRuleParams struct { Notes string `json:"notes"` @@ -63,3 +66,101 @@ func CreateIgnoreRuleBody(ignoreRuleParams IgnoreRuleParams) IgnoreRuleBody { IgnoreRuleParams: ignoreRuleParams, } } + +type IgnoreRulesGetAllParams struct { + Vulnerability string `json:"vulnerability"` + License string `json:"license"` + Policy string `json:"policy"` + Watch string `json:"watch"` + ComponentName string `json:"component_name"` + ComponentVersion string `json:"component_version"` + ArtifactName string `json:"artifact_name"` + ArtifactVersion string `json:"artifact_version"` + BuildName string `json:"build_name"` + BuildVersion string `json:"build_version"` + ReleaseBundleName string `json:"release_bundle_name"` + ReleaseBundleVersion string `json:"release_bundle_version"` + DockerLayer string `json:"docker_layer"` + ExpiresBefore time.Time `json:"expires_before"` + ExpiresAfter time.Time `json:"expires_after"` + ProjectKey string `json:"project_key"` + OrderBy string `json:"order_by"` + Direction string `json:"direction"` + PageNum int `json:"page_num"` + NumOfRows int `json:"num_of_rows"` +} + +// IgnoreRuleResponse struct representing the entire JSON +type IgnoreRuleResponse struct { + Data []IgnoreRuleBody `json:"data"` + TotalCount int `json:"total_count"` +} + +func (p *IgnoreRulesGetAllParams) GetParamMap() map[string]string { + params := make(map[string]string) + if p == nil { + return params + } + if p.Vulnerability != "" { + params["vulnerability"] = p.Vulnerability + } + if p.License != "" { + params["license"] = p.License + } + if p.Policy != "" { + params["policy"] = p.Policy + } + if p.Watch != "" { + params["watch"] = p.Watch + } + if p.ComponentName != "" { + params["component_name"] = p.ComponentName + } + if p.ComponentVersion != "" { + params["component_version"] = p.ComponentVersion + } + if p.ArtifactName != "" { + params["artifact_name"] = p.ArtifactName + } + if p.ArtifactVersion != "" { + params["artifact_version"] = p.ArtifactVersion + } + if p.BuildName != "" { + params["build_name"] = p.BuildName + } + if p.BuildVersion != "" { + params["build_version"] = p.BuildVersion + } + if p.ReleaseBundleName != "" { + params["release_bundle_name"] = p.ReleaseBundleName + } + if p.ReleaseBundleVersion != "" { + params["release_bundle_version"] = p.ReleaseBundleVersion + } + if p.DockerLayer != "" { + params["docker_layer"] = p.DockerLayer + } + if p.OrderBy != "" { + params["order_by"] = p.OrderBy + } + if p.Direction != "" { + params["direction"] = p.Direction + } + if p.PageNum != 0 { + params["page_num"] = fmt.Sprintf("%d", p.PageNum) + } + if p.NumOfRows != 0 { + params["num_of_rows"] = fmt.Sprintf("%d", p.NumOfRows) + } + if !p.ExpiresBefore.IsZero() { + params["expires_before"] = p.ExpiresBefore.UTC().Format(time.RFC3339) + } + if !p.ExpiresAfter.IsZero() { + params["expires_after"] = p.ExpiresAfter.UTC().Format(time.RFC3339) + } + if p.ProjectKey != "" { + params["project_key"] = p.ProjectKey + } + + return params +}