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 implementations for new API: config profile with repository context #1054

Open
wants to merge 17 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
43 changes: 33 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,44 @@ 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)
validateXscVersion(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.
func validateXscVersion(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 minXscVersion is provided we assume we have a Xray version BEFORE Xsc migration to it (i.e. prior to 3.107.13)
// In this case we want to validate minimal required Xsc version
err = clientUtils.ValidateMinimumVersion(clientUtils.Xsc, currentXscVersion, minXscVersion)
if err != nil {
t.Skip(err)
}
}

if minXrayVersion != "" {
// If minXrayVersion is provided we assume we have a Xray version AFTER Xsc migration to it (3.107.13+)
// In this case we want to validate minimal required Xray version only
var currentXrayVersion string
currentXrayVersion, err = GetXrayDetails().GetVersion()
if err != nil {
t.Skip(err)
}
err = clientUtils.ValidateMinimumVersion(clientUtils.Xsc, currentXrayVersion, minXrayVersion)
if 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
62 changes: 55 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,32 @@ 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:
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 {

case 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)
default:
assert.Fail(t, "received an unexpected request")
}
}))
Expand All @@ -45,10 +88,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
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)
}
44 changes: 38 additions & 6 deletions xsc/services/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ import (

const (
ConfigProfileMinXscVersion = "1.11.0"
xscConfigProfileApi = "profile"
xscDeprecatedConfigProfileApiSuffix = "api/v1/" + xscConfigProfileApi
ConfigProfileByUrlMinXrayVersion = "3.110.0"
xscConfigProfileByNameApi = "profile"
xscConfigProfileByUrlApi = "profile_repos"
xscDeprecatedConfigProfileApiSuffix = "api/v1/" + xscConfigProfileByNameApi
)

type ConfigurationProfileService struct {
Expand Down Expand Up @@ -100,10 +102,10 @@ 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
}
Expand All @@ -114,8 +116,8 @@ func (cp *ConfigurationProfileService) sendConfigProfileRequest(profileName stri
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 +129,33 @@ 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 {
httpDetails := cp.XrayDetails.CreateHttpClientDetails()
url = fmt.Sprintf("%s%s%s", utils.AddTrailingSlashIfNeeded(cp.XrayDetails.GetUrl()), xscutils.XscInXraySuffix, xscConfigProfileByUrlApi)
requestContent := []byte(fmt.Sprintf("{\"repo_url\":\"%s\"}", repoUrl))
resp, body, err = cp.client.SendPost(url, requestContent, &httpDetails)
return
}
// Backward compatibility
httpDetails := cp.XscDetails.CreateHttpClientDetails()
url = fmt.Sprintf("%s%s/%s", utils.AddTrailingSlashIfNeeded(cp.XscDetails.GetUrl()), xscDeprecatedConfigProfileApiSuffix, xscConfigProfileByUrlApi)
requestContent := []byte(fmt.Sprintf("{\"repo_url\":\"%s\"}", 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
}
Loading