zotregistry.dev/zot@v1.4.4-0.20240314164342-eec277e14d20/pkg/extensions/search/userprefs_test.go (about)

     1  //go:build search && userprefs
     2  
     3  package search_test
     4  
     5  import (
     6  	"encoding/json"
     7  	"fmt"
     8  	"net/http"
     9  	"net/url"
    10  	"os"
    11  	"testing"
    12  
    13  	. "github.com/smartystreets/goconvey/convey"
    14  	"gopkg.in/resty.v1"
    15  
    16  	"zotregistry.dev/zot/pkg/api"
    17  	"zotregistry.dev/zot/pkg/api/config"
    18  	"zotregistry.dev/zot/pkg/api/constants"
    19  	"zotregistry.dev/zot/pkg/common"
    20  	extconf "zotregistry.dev/zot/pkg/extensions/config"
    21  	"zotregistry.dev/zot/pkg/log"
    22  	test "zotregistry.dev/zot/pkg/test/common"
    23  	. "zotregistry.dev/zot/pkg/test/image-utils"
    24  	. "zotregistry.dev/zot/pkg/test/oci-utils"
    25  )
    26  
    27  //nolint:dupl
    28  func TestUserData(t *testing.T) {
    29  	Convey("Test user stars and bookmarks", t, func(c C) {
    30  		port := test.GetFreePort()
    31  		baseURL := test.GetBaseURL(port)
    32  		defaultVal := true
    33  
    34  		accessibleRepo := "accessible-repo"
    35  		forbiddenRepo := "forbidden-repo"
    36  		tag := "0.0.1"
    37  
    38  		adminUser := "alice"
    39  		adminPassword := "deepGoesTheRabbitBurrow"
    40  		simpleUser := "test"
    41  		simpleUserPassword := "test123"
    42  
    43  		content := test.GetCredString(adminUser, adminPassword) +
    44  			test.GetCredString(simpleUser, simpleUserPassword)
    45  		htpasswdPath := test.MakeHtpasswdFileFromString(content)
    46  		defer os.Remove(htpasswdPath)
    47  
    48  		conf := config.New()
    49  		conf.Storage.RootDirectory = t.TempDir()
    50  		conf.HTTP.Port = port
    51  		conf.HTTP.Auth = &config.AuthConfig{
    52  			HTPasswd: config.AuthHTPasswd{
    53  				Path: htpasswdPath,
    54  			},
    55  		}
    56  		conf.HTTP.AccessControl = &config.AccessControlConfig{
    57  			Repositories: config.Repositories{
    58  				"**": config.PolicyGroup{
    59  					Policies: []config.Policy{
    60  						{
    61  							Users:   []string{simpleUser},
    62  							Actions: []string{"read"},
    63  						},
    64  					},
    65  					AnonymousPolicy: []string{"read"},
    66  					DefaultPolicy:   []string{},
    67  				},
    68  				forbiddenRepo: config.PolicyGroup{
    69  					Policies: []config.Policy{
    70  						{
    71  							Users:   []string{},
    72  							Actions: []string{},
    73  						},
    74  					},
    75  					DefaultPolicy: []string{},
    76  				},
    77  			},
    78  			AdminPolicy: config.Policy{
    79  				Users:   []string{adminUser},
    80  				Actions: []string{"read", "create", "update"},
    81  			},
    82  		}
    83  		conf.Extensions = &extconf.ExtensionConfig{}
    84  		conf.Extensions.Search = &extconf.SearchConfig{}
    85  		conf.Extensions.Search.Enable = &defaultVal
    86  		conf.Extensions.Search.CVE = nil
    87  		conf.Extensions.UI = &extconf.UIConfig{}
    88  		conf.Extensions.UI.Enable = &defaultVal
    89  
    90  		ctlr := api.NewController(conf)
    91  
    92  		ctlrManager := test.NewControllerManager(ctlr)
    93  		ctlrManager.StartAndWait(port)
    94  		defer ctlrManager.StopServer()
    95  
    96  		image := CreateDefaultImage()
    97  
    98  		err := UploadImageWithBasicAuth(
    99  			image, baseURL, accessibleRepo, tag,
   100  			adminUser, adminPassword,
   101  		)
   102  		So(err, ShouldBeNil)
   103  
   104  		err = UploadImageWithBasicAuth(
   105  			image, baseURL, forbiddenRepo, tag,
   106  			adminUser, adminPassword,
   107  		)
   108  		So(err, ShouldBeNil)
   109  
   110  		userStaredReposQuery := `{
   111  			StarredRepos {
   112  				Results {
   113  					Name StarCount IsStarred
   114  					NewestImage { Tag }
   115  				}
   116  			}
   117  		}`
   118  
   119  		userBookmarkedReposQuery := `{
   120  			BookmarkedRepos {
   121  				Results {
   122  					Name IsBookmarked
   123  					NewestImage { Tag }
   124  				}
   125  			}
   126  		}`
   127  
   128  		userprefsBaseURL := baseURL + constants.FullUserPrefs
   129  
   130  		Convey("Flip starred repo authorized", func(c C) {
   131  			clientHTTP := resty.R().SetBasicAuth(simpleUser, simpleUserPassword)
   132  
   133  			resp, err := clientHTTP.Get(baseURL + constants.FullSearchPrefix +
   134  				"?query=" + url.QueryEscape(userStaredReposQuery))
   135  			So(err, ShouldBeNil)
   136  			So(resp, ShouldNotBeNil)
   137  			So(resp.StatusCode(), ShouldEqual, 200)
   138  
   139  			responseStruct := common.StarredReposResponse{}
   140  			err = json.Unmarshal(resp.Body(), &responseStruct)
   141  			So(err, ShouldBeNil)
   142  			So(len(responseStruct.Results), ShouldEqual, 0)
   143  
   144  			resp, err = clientHTTP.Put(userprefsBaseURL + PutRepoStarURL(accessibleRepo))
   145  			So(err, ShouldBeNil)
   146  			So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   147  
   148  			resp, err = clientHTTP.Get(baseURL + constants.FullSearchPrefix +
   149  				"?query=" + url.QueryEscape(userStaredReposQuery))
   150  			So(err, ShouldBeNil)
   151  			So(resp, ShouldNotBeNil)
   152  			So(resp.StatusCode(), ShouldEqual, 200)
   153  
   154  			responseStruct = common.StarredReposResponse{}
   155  			err = json.Unmarshal(resp.Body(), &responseStruct)
   156  			So(err, ShouldBeNil)
   157  			So(len(responseStruct.Results), ShouldEqual, 1)
   158  			So(responseStruct.Results[0].Name, ShouldEqual, accessibleRepo)
   159  			// need to update RepoSummary according to user settings
   160  			So(responseStruct.Results[0].IsStarred, ShouldEqual, true)
   161  			So(responseStruct.Results[0].StarCount, ShouldEqual, 1)
   162  
   163  			resp, err = clientHTTP.Put(userprefsBaseURL + PutRepoStarURL(accessibleRepo))
   164  			So(err, ShouldBeNil)
   165  			So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   166  
   167  			resp, err = clientHTTP.Get(baseURL + constants.FullSearchPrefix +
   168  				"?query=" + url.QueryEscape(userStaredReposQuery))
   169  			So(err, ShouldBeNil)
   170  			So(resp, ShouldNotBeNil)
   171  			So(resp.StatusCode(), ShouldEqual, 200)
   172  
   173  			responseStruct = common.StarredReposResponse{}
   174  			err = json.Unmarshal(resp.Body(), &responseStruct)
   175  			So(err, ShouldBeNil)
   176  			So(len(responseStruct.Results), ShouldEqual, 0)
   177  		})
   178  
   179  		Convey("Flip starred repo unauthenticated user", func(c C) {
   180  			clientHTTP := resty.R()
   181  
   182  			resp, err := clientHTTP.Get(baseURL + constants.FullSearchPrefix +
   183  				"?query=" + url.QueryEscape(userStaredReposQuery))
   184  			So(err, ShouldBeNil)
   185  			So(resp, ShouldNotBeNil)
   186  			So(resp.StatusCode(), ShouldEqual, 200)
   187  
   188  			responseStruct := common.StarredReposResponse{}
   189  			err = json.Unmarshal(resp.Body(), &responseStruct)
   190  			So(err, ShouldBeNil)
   191  			So(len(responseStruct.Results), ShouldEqual, 0)
   192  
   193  			resp, err = clientHTTP.Put(userprefsBaseURL + PutRepoStarURL(accessibleRepo))
   194  			So(err, ShouldBeNil)
   195  			So(resp.StatusCode(), ShouldEqual, http.StatusForbidden)
   196  
   197  			resp, err = clientHTTP.Get(baseURL + constants.FullSearchPrefix +
   198  				"?query=" + url.QueryEscape(userStaredReposQuery))
   199  			So(err, ShouldBeNil)
   200  			So(resp, ShouldNotBeNil)
   201  			So(resp.StatusCode(), ShouldEqual, 200)
   202  
   203  			responseStruct = common.StarredReposResponse{}
   204  			err = json.Unmarshal(resp.Body(), &responseStruct)
   205  			So(err, ShouldBeNil)
   206  			So(len(responseStruct.Results), ShouldEqual, 0)
   207  		})
   208  
   209  		Convey("Flip starred repo unauthorized", func(c C) {
   210  			clientHTTP := resty.R().SetBasicAuth(simpleUser, simpleUserPassword)
   211  
   212  			resp, err := clientHTTP.Get(baseURL + constants.FullSearchPrefix +
   213  				"?query=" + url.QueryEscape(userStaredReposQuery))
   214  			So(err, ShouldBeNil)
   215  			So(resp, ShouldNotBeNil)
   216  			So(resp.StatusCode(), ShouldEqual, 200)
   217  
   218  			responseStruct := common.StarredReposResponse{}
   219  			err = json.Unmarshal(resp.Body(), &responseStruct)
   220  			So(err, ShouldBeNil)
   221  			So(len(responseStruct.Results), ShouldEqual, 0)
   222  
   223  			resp, err = clientHTTP.Put(userprefsBaseURL + PutRepoStarURL(forbiddenRepo))
   224  			So(err, ShouldBeNil)
   225  			So(resp.StatusCode(), ShouldEqual, http.StatusForbidden)
   226  
   227  			resp, err = clientHTTP.Get(baseURL + constants.FullSearchPrefix +
   228  				"?query=" + url.QueryEscape(userStaredReposQuery))
   229  			So(err, ShouldBeNil)
   230  			So(resp, ShouldNotBeNil)
   231  			So(resp.StatusCode(), ShouldEqual, 200)
   232  
   233  			responseStruct = common.StarredReposResponse{}
   234  			err = json.Unmarshal(resp.Body(), &responseStruct)
   235  			So(err, ShouldBeNil)
   236  			So(len(responseStruct.Results), ShouldEqual, 0)
   237  		})
   238  
   239  		Convey("Flip starred repo with unauthorized repo and admin user", func(c C) {
   240  			clientHTTP := resty.R().SetBasicAuth(adminUser, adminPassword)
   241  
   242  			resp, err := clientHTTP.Get(baseURL + constants.FullSearchPrefix +
   243  				"?query=" + url.QueryEscape(userStaredReposQuery))
   244  			So(err, ShouldBeNil)
   245  			So(resp, ShouldNotBeNil)
   246  			So(resp.StatusCode(), ShouldEqual, 200)
   247  
   248  			responseStruct := common.StarredReposResponse{}
   249  			err = json.Unmarshal(resp.Body(), &responseStruct)
   250  			So(err, ShouldBeNil)
   251  			So(len(responseStruct.Results), ShouldEqual, 0)
   252  
   253  			resp, err = clientHTTP.Put(userprefsBaseURL + PutRepoStarURL(forbiddenRepo))
   254  			So(err, ShouldBeNil)
   255  			So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   256  
   257  			resp, err = clientHTTP.Get(baseURL + constants.FullSearchPrefix +
   258  				"?query=" + url.QueryEscape(userStaredReposQuery))
   259  			So(err, ShouldBeNil)
   260  			So(resp, ShouldNotBeNil)
   261  			So(resp.StatusCode(), ShouldEqual, 200)
   262  
   263  			responseStruct = common.StarredReposResponse{}
   264  			err = json.Unmarshal(resp.Body(), &responseStruct)
   265  			So(err, ShouldBeNil)
   266  			So(len(responseStruct.Results), ShouldEqual, 1)
   267  			So(responseStruct.Results[0].Name, ShouldEqual, forbiddenRepo)
   268  			// need to update RepoSummary according to user settings
   269  			So(responseStruct.Results[0].IsStarred, ShouldEqual, true)
   270  			So(responseStruct.Results[0].StarCount, ShouldEqual, 1)
   271  
   272  			resp, err = clientHTTP.Put(userprefsBaseURL + PutRepoStarURL(forbiddenRepo))
   273  			So(err, ShouldBeNil)
   274  			So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   275  
   276  			resp, err = clientHTTP.Get(baseURL + constants.FullSearchPrefix +
   277  				"?query=" + url.QueryEscape(userStaredReposQuery))
   278  			So(err, ShouldBeNil)
   279  			So(resp, ShouldNotBeNil)
   280  			So(resp.StatusCode(), ShouldEqual, 200)
   281  
   282  			responseStruct = common.StarredReposResponse{}
   283  			err = json.Unmarshal(resp.Body(), &responseStruct)
   284  			So(err, ShouldBeNil)
   285  			So(len(responseStruct.Results), ShouldEqual, 0)
   286  		})
   287  
   288  		Convey("Flip bookmark repo authorized", func(c C) {
   289  			clientHTTP := resty.R().SetBasicAuth(simpleUser, simpleUserPassword)
   290  
   291  			resp, err := clientHTTP.Get(baseURL + constants.FullSearchPrefix +
   292  				"?query=" + url.QueryEscape(userBookmarkedReposQuery))
   293  			So(err, ShouldBeNil)
   294  			So(resp, ShouldNotBeNil)
   295  			So(resp.StatusCode(), ShouldEqual, 200)
   296  
   297  			responseStruct := common.BookmarkedReposResponse{}
   298  			err = json.Unmarshal(resp.Body(), &responseStruct)
   299  			So(err, ShouldBeNil)
   300  			So(len(responseStruct.Results), ShouldEqual, 0)
   301  
   302  			resp, err = clientHTTP.Put(userprefsBaseURL + PutRepoBookmarkURL(accessibleRepo))
   303  			So(err, ShouldBeNil)
   304  			So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   305  
   306  			resp, err = clientHTTP.Get(baseURL + constants.FullSearchPrefix +
   307  				"?query=" + url.QueryEscape(userBookmarkedReposQuery))
   308  			So(err, ShouldBeNil)
   309  			So(resp, ShouldNotBeNil)
   310  			So(resp.StatusCode(), ShouldEqual, 200)
   311  
   312  			responseStruct = common.BookmarkedReposResponse{}
   313  			err = json.Unmarshal(resp.Body(), &responseStruct)
   314  			So(err, ShouldBeNil)
   315  			So(len(responseStruct.Results), ShouldEqual, 1)
   316  			So(responseStruct.Results[0].Name, ShouldEqual, accessibleRepo)
   317  			// need to update RepoSummary according to user settings
   318  			So(responseStruct.Results[0].IsBookmarked, ShouldEqual, true)
   319  
   320  			resp, err = clientHTTP.Put(userprefsBaseURL + PutRepoBookmarkURL(accessibleRepo))
   321  			So(err, ShouldBeNil)
   322  			So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   323  
   324  			resp, err = clientHTTP.Get(baseURL + constants.FullSearchPrefix +
   325  				"?query=" + url.QueryEscape(userBookmarkedReposQuery))
   326  			So(err, ShouldBeNil)
   327  			So(resp, ShouldNotBeNil)
   328  			So(resp.StatusCode(), ShouldEqual, 200)
   329  
   330  			responseStruct = common.BookmarkedReposResponse{}
   331  			err = json.Unmarshal(resp.Body(), &responseStruct)
   332  			So(err, ShouldBeNil)
   333  			So(len(responseStruct.Results), ShouldEqual, 0)
   334  		})
   335  
   336  		Convey("Flip bookmark repo unauthenticated user", func(c C) {
   337  			clientHTTP := resty.R()
   338  
   339  			resp, err := clientHTTP.Get(baseURL + constants.FullSearchPrefix +
   340  				"?query=" + url.QueryEscape(userBookmarkedReposQuery))
   341  			So(err, ShouldBeNil)
   342  			So(resp, ShouldNotBeNil)
   343  			So(resp.StatusCode(), ShouldEqual, 200)
   344  
   345  			responseStruct := common.BookmarkedReposResponse{}
   346  			err = json.Unmarshal(resp.Body(), &responseStruct)
   347  			So(err, ShouldBeNil)
   348  			So(len(responseStruct.Results), ShouldEqual, 0)
   349  
   350  			resp, err = clientHTTP.Put(userprefsBaseURL + PutRepoBookmarkURL(accessibleRepo))
   351  			So(err, ShouldBeNil)
   352  			So(resp.StatusCode(), ShouldEqual, http.StatusForbidden)
   353  
   354  			resp, err = clientHTTP.Get(baseURL + constants.FullSearchPrefix +
   355  				"?query=" + url.QueryEscape(userBookmarkedReposQuery))
   356  			So(err, ShouldBeNil)
   357  			So(resp, ShouldNotBeNil)
   358  			So(resp.StatusCode(), ShouldEqual, 200)
   359  
   360  			responseStruct = common.BookmarkedReposResponse{}
   361  			err = json.Unmarshal(resp.Body(), &responseStruct)
   362  			So(err, ShouldBeNil)
   363  			So(len(responseStruct.Results), ShouldEqual, 0)
   364  		})
   365  
   366  		Convey("Flip bookmark repo unauthorized", func(c C) {
   367  			clientHTTP := resty.R().SetBasicAuth(simpleUser, simpleUserPassword)
   368  
   369  			resp, err := clientHTTP.Get(baseURL + constants.FullSearchPrefix +
   370  				"?query=" + url.QueryEscape(userBookmarkedReposQuery))
   371  			So(err, ShouldBeNil)
   372  			So(resp, ShouldNotBeNil)
   373  			So(resp.StatusCode(), ShouldEqual, 200)
   374  
   375  			responseStruct := common.BookmarkedReposResponse{}
   376  			err = json.Unmarshal(resp.Body(), &responseStruct)
   377  			So(err, ShouldBeNil)
   378  			So(len(responseStruct.Results), ShouldEqual, 0)
   379  
   380  			resp, err = clientHTTP.Put(userprefsBaseURL + PutRepoBookmarkURL(forbiddenRepo))
   381  			So(err, ShouldBeNil)
   382  			So(resp.StatusCode(), ShouldEqual, http.StatusForbidden)
   383  
   384  			resp, err = clientHTTP.Get(baseURL + constants.FullSearchPrefix +
   385  				"?query=" + url.QueryEscape(userBookmarkedReposQuery))
   386  			So(err, ShouldBeNil)
   387  			So(resp, ShouldNotBeNil)
   388  			So(resp.StatusCode(), ShouldEqual, 200)
   389  
   390  			responseStruct = common.BookmarkedReposResponse{}
   391  			err = json.Unmarshal(resp.Body(), &responseStruct)
   392  			So(err, ShouldBeNil)
   393  			So(len(responseStruct.Results), ShouldEqual, 0)
   394  		})
   395  
   396  		Convey("Flip bookmarked unauthorized repo and admin user", func(c C) {
   397  			clientHTTP := resty.R().SetBasicAuth(adminUser, adminPassword)
   398  
   399  			resp, err := clientHTTP.Get(baseURL + constants.FullSearchPrefix +
   400  				"?query=" + url.QueryEscape(userBookmarkedReposQuery))
   401  			So(err, ShouldBeNil)
   402  			So(resp, ShouldNotBeNil)
   403  			So(resp.StatusCode(), ShouldEqual, 200)
   404  
   405  			responseStruct := common.BookmarkedReposResponse{}
   406  			err = json.Unmarshal(resp.Body(), &responseStruct)
   407  			So(err, ShouldBeNil)
   408  			So(len(responseStruct.Results), ShouldEqual, 0)
   409  
   410  			resp, err = clientHTTP.Put(userprefsBaseURL + PutRepoBookmarkURL(forbiddenRepo))
   411  			So(err, ShouldBeNil)
   412  			So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   413  
   414  			resp, err = clientHTTP.Get(baseURL + constants.FullSearchPrefix +
   415  				"?query=" + url.QueryEscape(userBookmarkedReposQuery))
   416  			So(err, ShouldBeNil)
   417  			So(resp, ShouldNotBeNil)
   418  			So(resp.StatusCode(), ShouldEqual, 200)
   419  
   420  			responseStruct = common.BookmarkedReposResponse{}
   421  			err = json.Unmarshal(resp.Body(), &responseStruct)
   422  			So(err, ShouldBeNil)
   423  			So(len(responseStruct.Results), ShouldEqual, 1)
   424  			So(responseStruct.Results[0].Name, ShouldEqual, forbiddenRepo)
   425  			// need to update RepoSummary according to user settings
   426  			So(responseStruct.Results[0].IsBookmarked, ShouldEqual, true)
   427  
   428  			resp, err = clientHTTP.Put(userprefsBaseURL + PutRepoBookmarkURL(forbiddenRepo))
   429  			So(err, ShouldBeNil)
   430  			So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   431  
   432  			resp, err = clientHTTP.Get(baseURL + constants.FullSearchPrefix +
   433  				"?query=" + url.QueryEscape(userBookmarkedReposQuery))
   434  			So(err, ShouldBeNil)
   435  			So(resp, ShouldNotBeNil)
   436  			So(resp.StatusCode(), ShouldEqual, 200)
   437  
   438  			responseStruct = common.BookmarkedReposResponse{}
   439  			err = json.Unmarshal(resp.Body(), &responseStruct)
   440  			So(err, ShouldBeNil)
   441  			So(len(responseStruct.Results), ShouldEqual, 0)
   442  		})
   443  	})
   444  }
   445  
   446  func TestChangingRepoState(t *testing.T) {
   447  	port := test.GetFreePort()
   448  	baseURL := test.GetBaseURL(port)
   449  	defaultVal := true
   450  
   451  	simpleUser := "test"
   452  	simpleUserPassword := "test123"
   453  
   454  	forbiddenRepo := "forbidden"
   455  	accesibleRepo := "accesible"
   456  
   457  	htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(simpleUser, simpleUserPassword))
   458  	defer os.Remove(htpasswdPath)
   459  
   460  	conf := config.New()
   461  	conf.Storage.RootDirectory = t.TempDir()
   462  	conf.HTTP.Port = port
   463  	conf.HTTP.Auth = &config.AuthConfig{
   464  		HTPasswd: config.AuthHTPasswd{
   465  			Path: htpasswdPath,
   466  		},
   467  	}
   468  	conf.HTTP.AccessControl = &config.AccessControlConfig{
   469  		Repositories: config.Repositories{
   470  			"**": config.PolicyGroup{
   471  				Policies: []config.Policy{
   472  					{
   473  						Users:   []string{simpleUser},
   474  						Actions: []string{"read"},
   475  					},
   476  				},
   477  				AnonymousPolicy: []string{"read"},
   478  				DefaultPolicy:   []string{},
   479  			},
   480  			forbiddenRepo: config.PolicyGroup{
   481  				Policies: []config.Policy{
   482  					{
   483  						Users:   []string{},
   484  						Actions: []string{},
   485  					},
   486  				},
   487  				DefaultPolicy: []string{},
   488  			},
   489  		},
   490  	}
   491  	conf.Extensions = &extconf.ExtensionConfig{}
   492  	conf.Extensions.Search = &extconf.SearchConfig{}
   493  	conf.Extensions.Search.Enable = &defaultVal
   494  	conf.Extensions.Search.CVE = nil
   495  	conf.Extensions.UI = &extconf.UIConfig{}
   496  	conf.Extensions.UI.Enable = &defaultVal
   497  
   498  	gqlStarredRepos := `
   499  	{
   500  		StarredRepos() {
   501  			Results {
   502  				Name
   503  				StarCount
   504  				IsBookmarked
   505  				IsStarred
   506  			}
   507  		}
   508  	}
   509  	`
   510  
   511  	gqlBookmarkedRepos := `
   512  	{
   513  		BookmarkedRepos() {
   514  			Results {
   515  				Name
   516  				StarCount
   517  				IsBookmarked
   518  				IsStarred
   519  			}
   520  		}
   521  	}
   522  	`
   523  
   524  	ctlr := api.NewController(conf)
   525  
   526  	img := CreateRandomImage()
   527  	storeCtlr := GetDefaultStoreController(conf.Storage.RootDirectory, log.NewLogger("debug", ""))
   528  
   529  	err := WriteImageToFileSystem(img, accesibleRepo, "tag", storeCtlr)
   530  	if err != nil {
   531  		t.FailNow()
   532  	}
   533  
   534  	err = WriteImageToFileSystem(img, forbiddenRepo, "tag", storeCtlr)
   535  	if err != nil {
   536  		t.FailNow()
   537  	}
   538  
   539  	ctlrManager := test.NewControllerManager(ctlr)
   540  
   541  	ctlrManager.StartAndWait(port)
   542  
   543  	defer ctlrManager.StopServer()
   544  
   545  	simpleUserClient := resty.R().SetBasicAuth(simpleUser, simpleUserPassword)
   546  	anonynousClient := resty.R()
   547  
   548  	userprefsBaseURL := baseURL + constants.FullUserPrefs
   549  
   550  	Convey("PutStars", t, func() {
   551  		resp, err := simpleUserClient.Put(userprefsBaseURL + PutRepoStarURL(accesibleRepo))
   552  		So(err, ShouldBeNil)
   553  		So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   554  
   555  		resp, err = simpleUserClient.Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(gqlStarredRepos))
   556  		So(err, ShouldBeNil)
   557  		So(resp, ShouldNotBeNil)
   558  		So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   559  
   560  		responseStruct := common.StarredReposResponse{}
   561  		err = json.Unmarshal(resp.Body(), &responseStruct)
   562  		So(err, ShouldBeNil)
   563  		So(len(responseStruct.Results), ShouldEqual, 1)
   564  		So(responseStruct.Results[0].IsStarred, ShouldBeTrue)
   565  		So(responseStruct.Results[0].Name, ShouldResemble, accesibleRepo)
   566  
   567  		resp, err = anonynousClient.Put(userprefsBaseURL + PutRepoStarURL(accesibleRepo))
   568  		So(err, ShouldBeNil)
   569  		So(resp.StatusCode(), ShouldEqual, http.StatusForbidden)
   570  	})
   571  	//
   572  	Convey("PutBookmark", t, func() {
   573  		resp, err := simpleUserClient.Put(userprefsBaseURL + PutRepoBookmarkURL(accesibleRepo))
   574  		So(err, ShouldBeNil)
   575  		So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   576  
   577  		resp, err = simpleUserClient.Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(gqlBookmarkedRepos))
   578  		So(err, ShouldBeNil)
   579  		So(resp, ShouldNotBeNil)
   580  		So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   581  
   582  		responseStruct := common.BookmarkedReposResponse{}
   583  		err = json.Unmarshal(resp.Body(), &responseStruct)
   584  		So(err, ShouldBeNil)
   585  		So(err, ShouldBeNil)
   586  		So(len(responseStruct.Results), ShouldEqual, 1)
   587  		So(responseStruct.Results[0].IsBookmarked, ShouldBeTrue)
   588  		So(responseStruct.Results[0].Name, ShouldResemble, accesibleRepo)
   589  
   590  		resp, err = anonynousClient.Put(userprefsBaseURL + PutRepoBookmarkURL(accesibleRepo))
   591  		So(err, ShouldBeNil)
   592  		So(resp.StatusCode(), ShouldEqual, http.StatusForbidden)
   593  	})
   594  }
   595  
   596  func TestGlobalSearchWithUserPrefFiltering(t *testing.T) {
   597  	Convey("Bookmarks and Stars filtering", t, func() {
   598  		dir := t.TempDir()
   599  		port := test.GetFreePort()
   600  		baseURL := test.GetBaseURL(port)
   601  		conf := config.New()
   602  		conf.HTTP.Port = port
   603  		conf.Storage.RootDirectory = dir
   604  
   605  		simpleUser := "simpleUser"
   606  		simpleUserPassword := "simpleUserPass"
   607  		htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(simpleUser, simpleUserPassword))
   608  		defer os.Remove(htpasswdPath)
   609  
   610  		conf.HTTP.Auth = &config.AuthConfig{
   611  			HTPasswd: config.AuthHTPasswd{
   612  				Path: htpasswdPath,
   613  			},
   614  		}
   615  
   616  		conf.HTTP.AccessControl = &config.AccessControlConfig{
   617  			Repositories: config.Repositories{
   618  				"**": config.PolicyGroup{
   619  					Policies: []config.Policy{
   620  						{
   621  							Users:   []string{simpleUser},
   622  							Actions: []string{"read", "create"},
   623  						},
   624  					},
   625  				},
   626  			},
   627  		}
   628  
   629  		defaultVal := true
   630  		conf.Extensions = &extconf.ExtensionConfig{}
   631  		conf.Extensions.Search = &extconf.SearchConfig{}
   632  		conf.Extensions.Search.Enable = &defaultVal
   633  		conf.Extensions.Search.CVE = nil
   634  		conf.Extensions.UI = &extconf.UIConfig{}
   635  		conf.Extensions.UI.Enable = &defaultVal
   636  
   637  		ctlr := api.NewController(conf)
   638  
   639  		ctlrManager := test.NewControllerManager(ctlr)
   640  		ctlrManager.StartAndWait(port)
   641  		defer ctlrManager.StopServer()
   642  
   643  		preferencesBaseURL := baseURL + constants.FullUserPrefs
   644  		simpleUserClient := resty.R().SetBasicAuth(simpleUser, simpleUserPassword)
   645  
   646  		// ------ Add simple repo
   647  		repo := "repo"
   648  		img := CreateRandomImage()
   649  
   650  		err := UploadImageWithBasicAuth(img, baseURL, repo, "tag", simpleUser, simpleUserPassword)
   651  		So(err, ShouldBeNil)
   652  
   653  		// ------ Add repo and star it
   654  		sRepo := "starred-repo"
   655  		img = CreateRandomImage()
   656  
   657  		err = UploadImageWithBasicAuth(img, baseURL, sRepo, "tag", simpleUser, simpleUserPassword)
   658  		So(err, ShouldBeNil)
   659  
   660  		resp, err := simpleUserClient.Put(preferencesBaseURL + PutRepoStarURL(sRepo))
   661  		So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   662  		So(err, ShouldBeNil)
   663  
   664  		// ------ Add repo and bookmark it
   665  		bRepo := "bookmarked-repo"
   666  		img = CreateRandomImage()
   667  
   668  		err = UploadImageWithBasicAuth(img, baseURL, bRepo, "tag", simpleUser, simpleUserPassword)
   669  		So(err, ShouldBeNil)
   670  
   671  		resp, err = simpleUserClient.Put(preferencesBaseURL + PutRepoBookmarkURL(bRepo))
   672  		So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   673  		So(err, ShouldBeNil)
   674  
   675  		// ------ Add repo, star and bookmark it
   676  		sbRepo := "starred-bookmarked-repo"
   677  		img = CreateRandomImage()
   678  
   679  		err = UploadImageWithBasicAuth(img, baseURL, sbRepo, "tag", simpleUser, simpleUserPassword)
   680  		So(err, ShouldBeNil)
   681  
   682  		resp, err = simpleUserClient.Put(preferencesBaseURL + PutRepoStarURL(sbRepo))
   683  		So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   684  		So(err, ShouldBeNil)
   685  		resp, err = simpleUserClient.Put(preferencesBaseURL + PutRepoBookmarkURL(sbRepo))
   686  		So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   687  		So(err, ShouldBeNil)
   688  
   689  		// Make global search requests filterin by IsStarred and IsBookmarked
   690  
   691  		query := `{ GlobalSearch(query:"repo", ){ Repos { Name } } }`
   692  
   693  		resp, err = simpleUserClient.Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
   694  		So(resp, ShouldNotBeNil)
   695  		So(err, ShouldBeNil)
   696  		So(resp.StatusCode(), ShouldEqual, 200)
   697  
   698  		responseStruct := &common.GlobalSearchResultResp{}
   699  
   700  		err = json.Unmarshal(resp.Body(), responseStruct)
   701  		So(err, ShouldBeNil)
   702  
   703  		foundRepos := responseStruct.Repos
   704  		So(len(foundRepos), ShouldEqual, 4)
   705  
   706  		// Filter by IsStarred = true
   707  		query = `{ GlobalSearch(query:"repo", filter:{ IsStarred:true }) { Repos { Name IsStarred IsBookmarked }}}`
   708  
   709  		resp, err = simpleUserClient.Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
   710  		So(resp, ShouldNotBeNil)
   711  		So(err, ShouldBeNil)
   712  		So(resp.StatusCode(), ShouldEqual, 200)
   713  
   714  		responseStruct = &common.GlobalSearchResultResp{}
   715  
   716  		err = json.Unmarshal(resp.Body(), responseStruct)
   717  		So(err, ShouldBeNil)
   718  
   719  		foundRepos = responseStruct.Repos
   720  		So(len(foundRepos), ShouldEqual, 2)
   721  		So(foundRepos, ShouldContain, common.RepoSummary{Name: sRepo, IsStarred: true, IsBookmarked: false})
   722  		So(foundRepos, ShouldContain, common.RepoSummary{Name: sbRepo, IsStarred: true, IsBookmarked: true})
   723  
   724  		// Filter by IsStarred = true && IsBookmarked = false
   725  		query = `{
   726  			GlobalSearch(query:"repo", filter:{ IsStarred:true, IsBookmarked:false }) {
   727  				Repos { Name IsStarred IsBookmarked }
   728  			}
   729  		}`
   730  
   731  		resp, err = simpleUserClient.Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
   732  		So(resp, ShouldNotBeNil)
   733  		So(err, ShouldBeNil)
   734  		So(resp.StatusCode(), ShouldEqual, 200)
   735  
   736  		responseStruct = &common.GlobalSearchResultResp{}
   737  
   738  		err = json.Unmarshal(resp.Body(), responseStruct)
   739  		So(err, ShouldBeNil)
   740  
   741  		foundRepos = responseStruct.Repos
   742  		So(len(foundRepos), ShouldEqual, 1)
   743  		So(foundRepos, ShouldContain, common.RepoSummary{Name: sRepo, IsStarred: true, IsBookmarked: false})
   744  
   745  		// Filter by IsBookmarked = true
   746  		query = `{
   747  			GlobalSearch(query:"repo", filter:{ IsBookmarked:true }) {
   748  				Repos { Name IsStarred IsBookmarked }
   749  			}
   750  		}`
   751  
   752  		resp, err = simpleUserClient.Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
   753  		So(resp, ShouldNotBeNil)
   754  		So(err, ShouldBeNil)
   755  		So(resp.StatusCode(), ShouldEqual, 200)
   756  
   757  		responseStruct = &common.GlobalSearchResultResp{}
   758  
   759  		err = json.Unmarshal(resp.Body(), responseStruct)
   760  		So(err, ShouldBeNil)
   761  
   762  		foundRepos = responseStruct.Repos
   763  		So(len(foundRepos), ShouldEqual, 2)
   764  		So(foundRepos, ShouldContain, common.RepoSummary{Name: bRepo, IsStarred: false, IsBookmarked: true})
   765  		So(foundRepos, ShouldContain, common.RepoSummary{Name: sbRepo, IsStarred: true, IsBookmarked: true})
   766  
   767  		// Filter by IsBookmarked = true && IsStarred = false
   768  		query = `{
   769  			GlobalSearch(query:"repo", filter:{ IsBookmarked:true, IsStarred:false }) {
   770  				Repos { Name IsStarred IsBookmarked }
   771  			}
   772  		}`
   773  
   774  		resp, err = simpleUserClient.Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
   775  		So(resp, ShouldNotBeNil)
   776  		So(err, ShouldBeNil)
   777  		So(resp.StatusCode(), ShouldEqual, 200)
   778  
   779  		responseStruct = &common.GlobalSearchResultResp{}
   780  
   781  		err = json.Unmarshal(resp.Body(), responseStruct)
   782  		So(err, ShouldBeNil)
   783  
   784  		foundRepos = responseStruct.Repos
   785  		So(len(foundRepos), ShouldEqual, 1)
   786  		So(foundRepos, ShouldContain, common.RepoSummary{Name: bRepo, IsStarred: false, IsBookmarked: true})
   787  	})
   788  }
   789  
   790  func TestExpandedRepoInfoWithUserPrefs(t *testing.T) {
   791  	Convey("ExpandedRepoInfo with User Prefs", t, func() {
   792  		dir := t.TempDir()
   793  		port := test.GetFreePort()
   794  		baseURL := test.GetBaseURL(port)
   795  		conf := config.New()
   796  		conf.HTTP.Port = port
   797  		conf.Storage.RootDirectory = dir
   798  
   799  		simpleUser := "simpleUser"
   800  		simpleUserPassword := "simpleUserPass"
   801  		htpasswdPath := test.MakeHtpasswdFileFromString(test.GetCredString(simpleUser, simpleUserPassword))
   802  		defer os.Remove(htpasswdPath)
   803  
   804  		conf.HTTP.Auth = &config.AuthConfig{
   805  			HTPasswd: config.AuthHTPasswd{
   806  				Path: htpasswdPath,
   807  			},
   808  		}
   809  
   810  		conf.HTTP.AccessControl = &config.AccessControlConfig{
   811  			Repositories: config.Repositories{
   812  				"**": config.PolicyGroup{
   813  					Policies: []config.Policy{
   814  						{
   815  							Users:   []string{simpleUser},
   816  							Actions: []string{"read", "create"},
   817  						},
   818  					},
   819  				},
   820  			},
   821  		}
   822  
   823  		defaultVal := true
   824  		conf.Extensions = &extconf.ExtensionConfig{}
   825  		conf.Extensions.Search = &extconf.SearchConfig{}
   826  		conf.Extensions.Search.Enable = &defaultVal
   827  		conf.Extensions.Search.CVE = nil
   828  		conf.Extensions.UI = &extconf.UIConfig{}
   829  		conf.Extensions.UI.Enable = &defaultVal
   830  
   831  		ctlr := api.NewController(conf)
   832  
   833  		ctlrManager := test.NewControllerManager(ctlr)
   834  		ctlrManager.StartAndWait(port)
   835  		defer ctlrManager.StopServer()
   836  
   837  		preferencesBaseURL := baseURL + constants.FullUserPrefs
   838  		simpleUserClient := resty.R().SetBasicAuth(simpleUser, simpleUserPassword)
   839  
   840  		// ------ Add sbrepo and star/bookmark it
   841  		sbrepo := "sbrepo"
   842  		img := CreateRandomImage()
   843  
   844  		err := UploadImageWithBasicAuth(img, baseURL, sbrepo, "tag", simpleUser, simpleUserPassword)
   845  		So(err, ShouldBeNil)
   846  
   847  		resp, err := simpleUserClient.Put(preferencesBaseURL + PutRepoStarURL(sbrepo))
   848  		So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   849  		So(err, ShouldBeNil)
   850  
   851  		resp, err = simpleUserClient.Put(preferencesBaseURL + PutRepoBookmarkURL(sbrepo))
   852  		So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   853  		So(err, ShouldBeNil)
   854  
   855  		// ExpandedRepoinfo
   856  
   857  		query := `
   858  		{
   859  			ExpandedRepoInfo(repo:"sbrepo"){
   860  				Summary {
   861  					Name IsStarred IsBookmarked
   862  				}
   863  			}
   864  		}`
   865  
   866  		resp, err = simpleUserClient.Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
   867  		So(resp, ShouldNotBeNil)
   868  		So(err, ShouldBeNil)
   869  		So(resp.StatusCode(), ShouldEqual, 200)
   870  
   871  		responseStruct := common.ExpandedRepoInfoResp{}
   872  
   873  		err = json.Unmarshal(resp.Body(), &responseStruct)
   874  		So(err, ShouldBeNil)
   875  
   876  		repoInfo := responseStruct.RepoInfo
   877  		So(repoInfo.Summary.IsBookmarked, ShouldBeTrue)
   878  		So(repoInfo.Summary.IsStarred, ShouldBeTrue)
   879  
   880  		// ------ Add srepo and star it
   881  		srepo := "srepo"
   882  		img = CreateRandomImage()
   883  
   884  		err = UploadImageWithBasicAuth(img, baseURL, srepo, "tag", simpleUser, simpleUserPassword)
   885  		So(err, ShouldBeNil)
   886  
   887  		resp, err = simpleUserClient.Put(preferencesBaseURL + PutRepoStarURL(srepo))
   888  		So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   889  		So(err, ShouldBeNil)
   890  
   891  		// ExpandedRepoinfo
   892  		query = `
   893  		{
   894  			ExpandedRepoInfo(repo:"srepo"){
   895  				Summary {
   896  					Name IsStarred IsBookmarked
   897  				}
   898  			}
   899  		}`
   900  
   901  		resp, err = simpleUserClient.Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
   902  		So(resp, ShouldNotBeNil)
   903  		So(err, ShouldBeNil)
   904  		So(resp.StatusCode(), ShouldEqual, 200)
   905  
   906  		responseStruct = common.ExpandedRepoInfoResp{}
   907  
   908  		err = json.Unmarshal(resp.Body(), &responseStruct)
   909  		So(err, ShouldBeNil)
   910  
   911  		repoInfo = responseStruct.RepoInfo
   912  		So(repoInfo.Summary.IsBookmarked, ShouldBeFalse)
   913  		So(repoInfo.Summary.IsStarred, ShouldBeTrue)
   914  
   915  		// ------ Add brepo and bookmark it
   916  		brepo := "brepo"
   917  		img = CreateRandomImage()
   918  
   919  		err = UploadImageWithBasicAuth(img, baseURL, brepo, "tag", simpleUser, simpleUserPassword)
   920  		So(err, ShouldBeNil)
   921  
   922  		resp, err = simpleUserClient.Put(preferencesBaseURL + PutRepoBookmarkURL(brepo))
   923  		So(resp.StatusCode(), ShouldEqual, http.StatusOK)
   924  		So(err, ShouldBeNil)
   925  
   926  		// ExpandedRepoinfo
   927  		query = `
   928  		{
   929  			ExpandedRepoInfo(repo:"brepo"){
   930  				Summary {
   931  					Name IsStarred IsBookmarked
   932  				}
   933  			}
   934  		}`
   935  
   936  		resp, err = simpleUserClient.Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
   937  		So(resp, ShouldNotBeNil)
   938  		So(err, ShouldBeNil)
   939  		So(resp.StatusCode(), ShouldEqual, 200)
   940  
   941  		responseStruct = common.ExpandedRepoInfoResp{}
   942  
   943  		err = json.Unmarshal(resp.Body(), &responseStruct)
   944  		So(err, ShouldBeNil)
   945  
   946  		repoInfo = responseStruct.RepoInfo
   947  		So(repoInfo.Summary.IsBookmarked, ShouldBeTrue)
   948  		So(repoInfo.Summary.IsStarred, ShouldBeFalse)
   949  
   950  		// ------ Add repo without star/bookmark
   951  		repo := "repo"
   952  		img = CreateRandomImage()
   953  
   954  		err = UploadImageWithBasicAuth(img, baseURL, repo, "tag", simpleUser, simpleUserPassword)
   955  		So(err, ShouldBeNil)
   956  
   957  		// ExpandedRepoinfo
   958  		query = `
   959  		{
   960  			ExpandedRepoInfo(repo:"repo"){
   961  				Summary {
   962  					Name IsStarred IsBookmarked
   963  				}
   964  			}
   965  		}`
   966  
   967  		resp, err = simpleUserClient.Get(baseURL + graphqlQueryPrefix + "?query=" + url.QueryEscape(query))
   968  		So(resp, ShouldNotBeNil)
   969  		So(err, ShouldBeNil)
   970  		So(resp.StatusCode(), ShouldEqual, 200)
   971  
   972  		responseStruct = common.ExpandedRepoInfoResp{}
   973  
   974  		err = json.Unmarshal(resp.Body(), &responseStruct)
   975  		So(err, ShouldBeNil)
   976  
   977  		repoInfo = responseStruct.RepoInfo
   978  		So(repoInfo.Summary.IsBookmarked, ShouldBeFalse)
   979  		So(repoInfo.Summary.IsStarred, ShouldBeFalse)
   980  	})
   981  }
   982  
   983  func PutRepoStarURL(repo string) string {
   984  	return fmt.Sprintf("?repo=%s&action=toggleStar", repo)
   985  }
   986  
   987  func PutRepoBookmarkURL(repo string) string {
   988  	return fmt.Sprintf("?repo=%s&action=toggleBookmark", repo)
   989  }