github.com/opcr-io/oras-go/v2@v2.0.0-20231122155130-eb4260d8a0ae/registry/remote/auth/scope_test.go (about)

     1  /*
     2  Copyright The ORAS Authors.
     3  Licensed under the Apache License, Version 2.0 (the "License");
     4  you may not use this file except in compliance with the License.
     5  You may obtain a copy of the License at
     6  
     7  http://www.apache.org/licenses/LICENSE-2.0
     8  
     9  Unless required by applicable law or agreed to in writing, software
    10  distributed under the License is distributed on an "AS IS" BASIS,
    11  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  See the License for the specific language governing permissions and
    13  limitations under the License.
    14  */
    15  
    16  package auth
    17  
    18  import (
    19  	"context"
    20  	"reflect"
    21  	"testing"
    22  )
    23  
    24  func TestScopeRepository(t *testing.T) {
    25  	tests := []struct {
    26  		name       string
    27  		repository string
    28  		actions    []string
    29  		want       string
    30  	}{
    31  		{
    32  			name: "empty repository",
    33  			actions: []string{
    34  				"pull",
    35  			},
    36  		},
    37  		{
    38  			name:       "nil actions",
    39  			repository: "foo",
    40  		},
    41  		{
    42  			name:       "empty actions",
    43  			repository: "foo",
    44  			actions:    []string{},
    45  		},
    46  		{
    47  			name:       "empty actions list",
    48  			repository: "foo",
    49  			actions:    []string{},
    50  		},
    51  		{
    52  			name:       "empty actions",
    53  			repository: "foo",
    54  			actions: []string{
    55  				"",
    56  			},
    57  		},
    58  		{
    59  			name:       "single action",
    60  			repository: "foo",
    61  			actions: []string{
    62  				"pull",
    63  			},
    64  			want: "repository:foo:pull",
    65  		},
    66  		{
    67  			name:       "multiple actions",
    68  			repository: "foo",
    69  			actions: []string{
    70  				"pull",
    71  				"push",
    72  			},
    73  			want: "repository:foo:pull,push",
    74  		},
    75  		{
    76  			name:       "unordered actions",
    77  			repository: "foo",
    78  			actions: []string{
    79  				"push",
    80  				"pull",
    81  			},
    82  			want: "repository:foo:pull,push",
    83  		},
    84  		{
    85  			name:       "duplicated actions",
    86  			repository: "foo",
    87  			actions: []string{
    88  				"push",
    89  				"pull",
    90  				"pull",
    91  				"delete",
    92  				"push",
    93  			},
    94  			want: "repository:foo:delete,pull,push",
    95  		},
    96  	}
    97  	for _, tt := range tests {
    98  		t.Run(tt.name, func(t *testing.T) {
    99  			if got := ScopeRepository(tt.repository, tt.actions...); got != tt.want {
   100  				t.Errorf("ScopeRepository() = %v, want %v", got, tt.want)
   101  			}
   102  		})
   103  	}
   104  }
   105  
   106  func TestWithScopes(t *testing.T) {
   107  	ctx := context.Background()
   108  
   109  	// with single scope
   110  	want := []string{
   111  		"repository:foo:pull",
   112  	}
   113  	ctx = WithScopes(ctx, want...)
   114  	if got := GetScopes(ctx); !reflect.DeepEqual(got, want) {
   115  		t.Errorf("GetScopes(WithScopes()) = %v, want %v", got, want)
   116  	}
   117  
   118  	// overwrite scopes
   119  	want = []string{
   120  		"repository:bar:push",
   121  	}
   122  	ctx = WithScopes(ctx, want...)
   123  	if got := GetScopes(ctx); !reflect.DeepEqual(got, want) {
   124  		t.Errorf("GetScopes(WithScopes()) = %v, want %v", got, want)
   125  	}
   126  
   127  	// overwrite scopes with de-duplication
   128  	scopes := []string{
   129  		"repository:hello-world:push",
   130  		"repository:alpine:delete",
   131  		"repository:hello-world:pull",
   132  		"repository:alpine:delete",
   133  	}
   134  	want = []string{
   135  		"repository:alpine:delete",
   136  		"repository:hello-world:pull,push",
   137  	}
   138  	ctx = WithScopes(ctx, scopes...)
   139  	if got := GetScopes(ctx); !reflect.DeepEqual(got, want) {
   140  		t.Errorf("GetScopes(WithScopes()) = %v, want %v", got, want)
   141  	}
   142  
   143  	// clean scopes
   144  	want = nil
   145  	ctx = WithScopes(ctx, want...)
   146  	if got := GetScopes(ctx); !reflect.DeepEqual(got, want) {
   147  		t.Errorf("GetScopes(WithScopes()) = %v, want %v", got, want)
   148  	}
   149  }
   150  
   151  func TestAppendScopes(t *testing.T) {
   152  	ctx := context.Background()
   153  
   154  	// append single scope
   155  	want := []string{
   156  		"repository:foo:pull",
   157  	}
   158  	ctx = AppendScopes(ctx, want...)
   159  	if got := GetScopes(ctx); !reflect.DeepEqual(got, want) {
   160  		t.Errorf("GetScopes(AppendScopes()) = %v, want %v", got, want)
   161  	}
   162  
   163  	// append scopes with de-duplication
   164  	scopes := []string{
   165  		"repository:hello-world:push",
   166  		"repository:alpine:delete",
   167  		"repository:hello-world:pull",
   168  		"repository:alpine:delete",
   169  	}
   170  	want = []string{
   171  		"repository:alpine:delete",
   172  		"repository:foo:pull",
   173  		"repository:hello-world:pull,push",
   174  	}
   175  	ctx = AppendScopes(ctx, scopes...)
   176  	if got := GetScopes(ctx); !reflect.DeepEqual(got, want) {
   177  		t.Errorf("GetScopes(AppendScopes()) = %v, want %v", got, want)
   178  	}
   179  
   180  	// append empty scopes
   181  	ctx = AppendScopes(ctx)
   182  	if got := GetScopes(ctx); !reflect.DeepEqual(got, want) {
   183  		t.Errorf("GetScopes(AppendScopes()) = %v, want %v", got, want)
   184  	}
   185  }
   186  
   187  func TestCleanScopes(t *testing.T) {
   188  	tests := []struct {
   189  		name   string
   190  		scopes []string
   191  		want   []string
   192  	}{
   193  		{
   194  			name: "nil scope",
   195  		},
   196  		{
   197  			name:   "empty scope",
   198  			scopes: []string{},
   199  		},
   200  		{
   201  			name: "single scope",
   202  			scopes: []string{
   203  				"repository:foo:pull",
   204  			},
   205  			want: []string{
   206  				"repository:foo:pull",
   207  			},
   208  		},
   209  		{
   210  			name: "single scope with unordered actions",
   211  			scopes: []string{
   212  				"repository:foo:push,pull,delete",
   213  			},
   214  			want: []string{
   215  				"repository:foo:delete,pull,push",
   216  			},
   217  		},
   218  		{
   219  			name: "single scope with duplicated actions",
   220  			scopes: []string{
   221  				"repository:foo:push,pull,push,pull,push,push,pull",
   222  			},
   223  			want: []string{
   224  				"repository:foo:pull,push",
   225  			},
   226  		},
   227  		{
   228  			name: "single scope with wild cards",
   229  			scopes: []string{
   230  				"repository:foo:pull,*,push",
   231  			},
   232  			want: []string{
   233  				"repository:foo:*",
   234  			},
   235  		},
   236  		{
   237  			name: "single scope with no actions",
   238  			scopes: []string{
   239  				"repository:foo:,",
   240  			},
   241  			want: nil,
   242  		},
   243  		{
   244  			name: "multiple scopes",
   245  			scopes: []string{
   246  				"repository:bar:push",
   247  				"repository:foo:pull",
   248  			},
   249  			want: []string{
   250  				"repository:bar:push",
   251  				"repository:foo:pull",
   252  			},
   253  		},
   254  		{
   255  			name: "multiple unordered scopes",
   256  			scopes: []string{
   257  				"repository:foo:pull",
   258  				"repository:bar:push",
   259  			},
   260  			want: []string{
   261  				"repository:bar:push",
   262  				"repository:foo:pull",
   263  			},
   264  		},
   265  		{
   266  			name: "multiple scopes with duplicates",
   267  			scopes: []string{
   268  				"repository:foo:pull",
   269  				"repository:bar:push",
   270  				"repository:foo:push",
   271  				"repository:bar:push,delete,pull",
   272  				"repository:bar:delete,pull",
   273  				"repository:foo:pull",
   274  				"registry:catalog:*",
   275  				"registry:catalog:pull",
   276  			},
   277  			want: []string{
   278  				"registry:catalog:*",
   279  				"repository:bar:delete,pull,push",
   280  				"repository:foo:pull,push",
   281  			},
   282  		},
   283  		{
   284  			name: "multiple scopes with no actions",
   285  			scopes: []string{
   286  				"repository:foo:,",
   287  				"repository:bar:,",
   288  			},
   289  			want: nil,
   290  		},
   291  		{
   292  			name: "single unknown or invalid scope",
   293  			scopes: []string{
   294  				"unknown",
   295  			},
   296  			want: []string{
   297  				"unknown",
   298  			},
   299  		},
   300  		{
   301  			name: "multiple unknown or invalid scopes",
   302  			scopes: []string{
   303  				"repository:foo:pull",
   304  				"unknown",
   305  				"invalid:scope",
   306  				"no:actions:",
   307  				"repository:foo:push",
   308  			},
   309  			want: []string{
   310  				"invalid:scope",
   311  				"repository:foo:pull,push",
   312  				"unknown",
   313  			},
   314  		},
   315  	}
   316  	for _, tt := range tests {
   317  		t.Run(tt.name, func(t *testing.T) {
   318  			if got := CleanScopes(tt.scopes); !reflect.DeepEqual(got, tt.want) {
   319  				t.Errorf("CleanScopes() = %v, want %v", got, tt.want)
   320  			}
   321  		})
   322  	}
   323  }
   324  
   325  func Test_cleanActions(t *testing.T) {
   326  	tests := []struct {
   327  		name    string
   328  		actions []string
   329  		want    []string
   330  	}{
   331  		{
   332  			name: "nil action",
   333  		},
   334  		{
   335  			name:    "empty action",
   336  			actions: []string{},
   337  		},
   338  		{
   339  			name: "single action",
   340  			actions: []string{
   341  				"pull",
   342  			},
   343  			want: []string{
   344  				"pull",
   345  			},
   346  		},
   347  		{
   348  			name: "single empty action",
   349  			actions: []string{
   350  				"",
   351  			},
   352  		},
   353  		{
   354  			name: "multiple actions",
   355  			actions: []string{
   356  				"pull",
   357  				"push",
   358  			},
   359  			want: []string{
   360  				"pull",
   361  				"push",
   362  			},
   363  		},
   364  		{
   365  			name: "multiple actions with empty action",
   366  			actions: []string{
   367  				"pull",
   368  				"",
   369  				"push",
   370  			},
   371  			want: []string{
   372  				"pull",
   373  				"push",
   374  			},
   375  		},
   376  		{
   377  			name: "multiple actions with all empty action",
   378  			actions: []string{
   379  				"",
   380  				"",
   381  				"",
   382  			},
   383  			want: nil,
   384  		},
   385  		{
   386  			name: "unordered actions",
   387  			actions: []string{
   388  				"push",
   389  				"pull",
   390  				"delete",
   391  			},
   392  			want: []string{
   393  				"delete",
   394  				"pull",
   395  				"push",
   396  			},
   397  		},
   398  		{
   399  			name: "wildcard",
   400  			actions: []string{
   401  				"*",
   402  			},
   403  			want: []string{
   404  				"*",
   405  			},
   406  		},
   407  		{
   408  			name: "wildcard at the begining",
   409  			actions: []string{
   410  				"*",
   411  				"push",
   412  				"pull",
   413  				"delete",
   414  			},
   415  			want: []string{
   416  				"*",
   417  			},
   418  		},
   419  		{
   420  			name: "wildcard in the middle",
   421  			actions: []string{
   422  				"push",
   423  				"pull",
   424  				"*",
   425  				"delete",
   426  			},
   427  			want: []string{
   428  				"*",
   429  			},
   430  		},
   431  		{
   432  			name: "wildcard at the end",
   433  			actions: []string{
   434  				"push",
   435  				"pull",
   436  				"delete",
   437  				"*",
   438  			},
   439  			want: []string{
   440  				"*",
   441  			},
   442  		},
   443  	}
   444  	for _, tt := range tests {
   445  		t.Run(tt.name, func(t *testing.T) {
   446  			if got := cleanActions(tt.actions); !reflect.DeepEqual(got, tt.want) {
   447  				t.Errorf("cleanActions() = %v, want %v", got, tt.want)
   448  			}
   449  		})
   450  	}
   451  }