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