Skip to content

Commit

Permalink
Add implementations for new API: config profile with repository conte…
Browse files Browse the repository at this point in the history
…xt (#1057)
  • Loading branch information
eranturgeman authored Dec 16, 2024
1 parent 96c11f5 commit 80abb8e
Show file tree
Hide file tree
Showing 8 changed files with 135 additions and 33 deletions.
37 changes: 27 additions & 10 deletions tests/xsc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
)

func TestXscVersion(t *testing.T) {
initXscTest(t, "")
initXscTest(t, "", "")
version, err := GetXscDetails().GetVersion()
if err != nil {
t.Error(err)
Expand All @@ -16,21 +16,38 @@ func TestXscVersion(t *testing.T) {
}
}

func initXscTest(t *testing.T, minVersion string) {
func initXscTest(t *testing.T, minXscVersion string, minXrayVersion string) {
if !*TestXsc {
t.Skip("Skipping xsc test. To run xsc test add the '-test.xsc=true' option.")
}
validateXscVersion(t, minVersion)
validateXscAndXrayVersion(t, minXscVersion, minXrayVersion)
}
func validateXscVersion(t *testing.T, minVersion string) {
// Validate active XSC server.
version, err := GetXscDetails().GetVersion()

// This func validates minimal Xsc version.
// Since Xsc was migrated into Xray from version 3.107.13, we need to check minimal Xray version from this version forward instead of Xsc version.
// For features that are available before the migration we pass minXscVersion to check. If the utilized Xray version >= 3.107.13, the returned Xsc version will always suffice the check.
// For features that were introduced only after the migration we pass only minXrayVersion to check and can leave minXscVersion blank.
// In general minXscVersion should be provided only for features that were introduced before Xsc migration to Xray
func validateXscAndXrayVersion(t *testing.T, minXscVersion string, minXrayVersion string) {
// Validate active Xsc server
currentXscVersion, err := GetXscDetails().GetVersion()
if err != nil {
t.Skip(err)
}
// Validate minimum XSC version.
err = clientUtils.ValidateMinimumVersion(clientUtils.Xsc, version, minVersion)
if err != nil {
t.Skip(err)

if minXscVersion != "" {
if err = clientUtils.ValidateMinimumVersion(clientUtils.Xsc, currentXscVersion, minXscVersion); err != nil {
t.Skip(err)
}
}

if minXrayVersion != "" {
var currentXrayVersion string
if currentXrayVersion, err = GetXrayDetails().GetVersion(); err != nil {
t.Skip(err)
}
if err = clientUtils.ValidateMinimumVersion(clientUtils.Xsc, currentXrayVersion, minXrayVersion); err != nil {
t.Skip(err)
}
}
}
2 changes: 1 addition & 1 deletion tests/xscanalyticsevent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func isValidUUID(str string) bool {

func initXscEventTest(t *testing.T) (xscDetails auth.ServiceDetails, client *jfroghttpclient.JfrogHttpClient) {
var err error
initXscTest(t, services.AnalyticsMetricsMinXscVersion)
initXscTest(t, services.AnalyticsMetricsMinXscVersion, "")
xscDetails = GetXscDetails()
client, err = jfroghttpclient.JfrogClientBuilder().
SetClientCertPath(xscDetails.GetClientCertPath()).
Expand Down
56 changes: 49 additions & 7 deletions tests/xscconfigprofile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,48 @@ import (
"encoding/json"
"github.com/jfrog/jfrog-client-go/http/jfroghttpclient"
"github.com/jfrog/jfrog-client-go/xsc/services"
xscutils "github.com/jfrog/jfrog-client-go/xsc/services/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
)

func TestGetConfigurationProfile(t *testing.T) {
initXscTest(t, services.ConfigProfileMinXscVersion)
const configProfileWithoutRepo = "default-test-profile"

mockServer, configProfileService := createXscMockServerForConfigProfile(t)
func TestGetConfigurationProfileByName(t *testing.T) {
initXscTest(t, services.ConfigProfileMinXscVersion, "")

xrayVersion, err := GetXrayDetails().GetVersion()
require.NoError(t, err)

mockServer, configProfileService := createXscMockServerForConfigProfile(t, xrayVersion)
defer mockServer.Close()

configProfile, err := configProfileService.GetConfigurationProfileByName(configProfileWithoutRepo)
assert.NoError(t, err)

profileFileContent, err := os.ReadFile("testdata/configprofile/configProfileExample.json")
assert.NoError(t, err)
var configProfileForComparison services.ConfigProfile
err = json.Unmarshal(profileFileContent, &configProfileForComparison)
assert.NoError(t, err)
assert.Equal(t, &configProfileForComparison, configProfile)
}

func TestGetConfigurationProfileByUrl(t *testing.T) {
initXscTest(t, "", services.ConfigProfileByUrlMinXrayVersion)

xrayVersion, err := GetXrayDetails().GetVersion()
require.NoError(t, err)

mockServer, configProfileService := createXscMockServerForConfigProfile(t, xrayVersion)
defer mockServer.Close()

configProfile, err := configProfileService.GetConfigurationProfile("default-test-profile")
configProfile, err := configProfileService.GetConfigurationProfileByUrl(mockServer.URL)
assert.NoError(t, err)

profileFileContent, err := os.ReadFile("testdata/configprofile/configProfileExample.json")
Expand All @@ -26,17 +54,26 @@ func TestGetConfigurationProfile(t *testing.T) {
err = json.Unmarshal(profileFileContent, &configProfileForComparison)
assert.NoError(t, err)
assert.Equal(t, &configProfileForComparison, configProfile)

}

func createXscMockServerForConfigProfile(t *testing.T) (mockServer *httptest.Server, configProfileService *services.ConfigurationProfileService) {
func createXscMockServerForConfigProfile(t *testing.T, xrayVersion string) (mockServer *httptest.Server, configProfileService *services.ConfigurationProfileService) {
mockServer = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.RequestURI == "/xsc/api/v1/profile/default-test-profile" && r.Method == http.MethodGet {
apiUrlPart := "api/v1/"
var isXrayAfterXscMigration bool
if isXrayAfterXscMigration = xscutils.IsXscXrayInnerService(xrayVersion); isXrayAfterXscMigration {
apiUrlPart = ""
}

switch {
case (strings.Contains(r.RequestURI, "/xsc/"+apiUrlPart+"profile/"+configProfileWithoutRepo) && r.Method == http.MethodGet) ||
strings.Contains(r.RequestURI, "xray/api/v1/xsc/profile_repos") && r.Method == http.MethodPost && isXrayAfterXscMigration:
w.WriteHeader(http.StatusOK)
content, err := os.ReadFile("testdata/configprofile/configProfileExample.json")
assert.NoError(t, err)
_, err = w.Write(content)
assert.NoError(t, err)
} else {
default:
assert.Fail(t, "received an unexpected request")
}
}))
Expand All @@ -45,10 +82,15 @@ func createXscMockServerForConfigProfile(t *testing.T) (mockServer *httptest.Ser
xscDetails.SetUrl(mockServer.URL + "/xsc")
xscDetails.SetAccessToken("")

xrayDetails := GetXrayDetails()
xrayDetails.SetUrl(mockServer.URL + "/xray")
xrayDetails.SetAccessToken("")

client, err := jfroghttpclient.JfrogClientBuilder().Build()
assert.NoError(t, err)

configProfileService = services.NewConfigurationProfileService(client)
configProfileService.XscDetails = xscDetails
configProfileService.XrayDetails = xrayDetails
return
}
2 changes: 1 addition & 1 deletion tests/xsclogerrorevent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
const errorMessageContentForTest = "THIS IS NOT A REAL ERROR! This Error is posted as part of TestXscSendLogErrorEvent test"

func TestXscSendLogErrorEvent(t *testing.T) {
initXscTest(t, services.LogErrorMinXscVersion)
initXscTest(t, services.LogErrorMinXscVersion, "")
mockServer, logErrorService := createXscMockServerForLogEvent(t)
defer mockServer.Close()

Expand Down
10 changes: 8 additions & 2 deletions xray/services/xsc/xsc.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,14 @@ func (xs *XscInnerService) GetAnalyticsGeneralEvent(msi string) (*services.XscAn
return eventService.GetGeneralEvent(msi)
}

func (xs *XscInnerService) GetConfigProfile(profileName string) (*services.ConfigProfile, error) {
func (xs *XscInnerService) GetConfigProfileByName(profileName string) (*services.ConfigProfile, error) {
configProfileService := services.NewConfigurationProfileService(xs.client)
configProfileService.XrayDetails = xs.XrayDetails
return configProfileService.GetConfigurationProfile(profileName)
return configProfileService.GetConfigurationProfileByName(profileName)
}

func (xs *XscInnerService) GetConfigProfileByUrl(repoUrl string) (*services.ConfigProfile, error) {
configProfileService := services.NewConfigurationProfileService(xs.client)
configProfileService.XrayDetails = xs.XrayDetails
return configProfileService.GetConfigurationProfileByUrl(repoUrl)
}
9 changes: 7 additions & 2 deletions xsc/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,13 @@ func (sm *XscServicesManager) GetAnalyticsGeneralEvent(msi string) (*services.Xs
return eventService.GetGeneralEvent(msi)
}

func (sm *XscServicesManager) GetConfigProfile(profileName string) (*services.ConfigProfile, error) {
func (sm *XscServicesManager) GetConfigProfileByName(profileName string) (*services.ConfigProfile, error) {
configProfileService := services.NewConfigurationProfileService(sm.client)
configProfileService.XscDetails = sm.config.GetServiceDetails()
return configProfileService.GetConfigurationProfile(profileName)
return configProfileService.GetConfigurationProfileByName(profileName)
}

func (sm *XscServicesManager) GetConfigProfileByUrl(_ string) (*services.ConfigProfile, error) {
// Empty implementation required for alignment with interface, implemented only at the new service inside the Xray service
return nil, nil
}
6 changes: 4 additions & 2 deletions xsc/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ type XscService interface {
UpdateAnalyticsGeneralEvent(event services.XscAnalyticsGeneralEventFinalize) error
// GetAnalyticsGeneralEvent returns general event that match the msi provided.
GetAnalyticsGeneralEvent(msi string) (*services.XscAnalyticsGeneralEvent, error)
// GetConfigProfile returns the configuration profile that match the profile name provided.
GetConfigProfile(profileName string) (*services.ConfigProfile, error)
// GetConfigProfileByName returns the configuration profile that match the profile name provided.
GetConfigProfileByName(profileName string) (*services.ConfigProfile, error)
// GetConfigProfileByUrl returns the configuration profile related to the provided repository url.
GetConfigProfileByUrl(profileUrl string) (*services.ConfigProfile, error)
}
46 changes: 38 additions & 8 deletions xsc/services/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package services

import (
"encoding/json"
"errors"
"fmt"
"net/http"

Expand All @@ -13,9 +14,12 @@ import (
)

const (
ConfigProfileMinXscVersion = "1.11.0"
xscConfigProfileApi = "profile"
xscDeprecatedConfigProfileApiSuffix = "api/v1/" + xscConfigProfileApi
ConfigProfileMinXscVersion = "1.11.0"
ConfigProfileByUrlMinXrayVersion = "3.110.0"
xscConfigProfileByNameApi = "profile"
xscConfigProfileByUrlApi = "profile_repos"
xscDeprecatedConfigProfileByNameApiSuffix = "api/v1/" + xscConfigProfileByNameApi
getProfileByUrlBody = "{\"repo_url\":\"%s\"}"
)

type ConfigurationProfileService struct {
Expand Down Expand Up @@ -100,22 +104,22 @@ type ServicesScannerConfig struct {
ExcludePatterns []string `json:"exclude_patterns,omitempty"`
}

func (cp *ConfigurationProfileService) sendConfigProfileRequest(profileName string) (url string, resp *http.Response, body []byte, err error) {
func (cp *ConfigurationProfileService) sendConfigProfileByNameRequest(profileName string) (url string, resp *http.Response, body []byte, err error) {
if cp.XrayDetails != nil {
httpDetails := cp.XrayDetails.CreateHttpClientDetails()
url = fmt.Sprintf("%s%s%s/%s", utils.AddTrailingSlashIfNeeded(cp.XrayDetails.GetUrl()), xscutils.XscInXraySuffix, xscConfigProfileApi, profileName)
url = fmt.Sprintf("%s%s%s/%s", utils.AddTrailingSlashIfNeeded(cp.XrayDetails.GetUrl()), xscutils.XscInXraySuffix, xscConfigProfileByNameApi, profileName)
resp, body, _, err = cp.client.SendGet(url, true, &httpDetails)
return
}
// Backward compatibility
httpDetails := cp.XscDetails.CreateHttpClientDetails()
url = fmt.Sprintf("%s%s/%s", utils.AddTrailingSlashIfNeeded(cp.XscDetails.GetUrl()), xscDeprecatedConfigProfileApiSuffix, profileName)
url = fmt.Sprintf("%s%s/%s", utils.AddTrailingSlashIfNeeded(cp.XscDetails.GetUrl()), xscDeprecatedConfigProfileByNameApiSuffix, profileName)
resp, body, _, err = cp.client.SendGet(url, true, &httpDetails)
return
}

func (cp *ConfigurationProfileService) GetConfigurationProfile(profileName string) (*ConfigProfile, error) {
url, res, body, err := cp.sendConfigProfileRequest(profileName)
func (cp *ConfigurationProfileService) GetConfigurationProfileByName(profileName string) (*ConfigProfile, error) {
url, res, body, err := cp.sendConfigProfileByNameRequest(profileName)
if err != nil {
return nil, fmt.Errorf("failed to send GET query to '%s': %q", url, err)
}
Expand All @@ -127,3 +131,29 @@ func (cp *ConfigurationProfileService) GetConfigurationProfile(profileName strin
err = errorutils.CheckError(json.Unmarshal(body, &profile))
return &profile, err
}

func (cp *ConfigurationProfileService) sendConfigProfileByUrlRequest(repoUrl string) (url string, resp *http.Response, body []byte, err error) {
if cp.XrayDetails == nil {
err = errors.New("received empty Xray details")
return
}
httpDetails := cp.XrayDetails.CreateHttpClientDetails()
url = fmt.Sprintf("%s%s%s", utils.AddTrailingSlashIfNeeded(cp.XrayDetails.GetUrl()), xscutils.XscInXraySuffix, xscConfigProfileByUrlApi)
requestContent := []byte(fmt.Sprintf(getProfileByUrlBody, repoUrl))
resp, body, err = cp.client.SendPost(url, requestContent, &httpDetails)
return
}

func (cp *ConfigurationProfileService) GetConfigurationProfileByUrl(url string) (*ConfigProfile, error) {
url, res, body, err := cp.sendConfigProfileByUrlRequest(url)
if err != nil {
return nil, fmt.Errorf("failed to send POST query to '%s': %q", url, err)
}
if err = errorutils.CheckResponseStatusWithBody(res, body, http.StatusOK); err != nil {
return nil, err
}

var profile ConfigProfile
err = errorutils.CheckError(json.Unmarshal(body, &profile))
return &profile, err
}

0 comments on commit 80abb8e

Please sign in to comment.