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

feat: support per-host scope hints #604

Merged
merged 29 commits into from
Sep 27, 2023
Merged
Changes from 1 commit
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
Prev Previous commit
Next Next commit
fix + test
Signed-off-by: Lixia (Sylvia) Lei <lixlei@microsoft.com>
Wwwsylvia committed Sep 26, 2023
commit 65c4acb13448160419dfd81d10c5541f998ce499
17 changes: 11 additions & 6 deletions registry/remote/auth/scope.go
Original file line number Diff line number Diff line change
@@ -57,7 +57,7 @@ func ScopeRepository(repository string, actions ...string) string {
// scopesContextKey is the context key for scopes.
type scopesContextKey struct{}

type perRegistryScopesContextKey struct{}
type ScopesPerRegistryContextKey struct{}

// WithScopes returns a context with scopes added. Scopes are de-duplicated.
// Scopes are used as hints for the auth client to fetch bearer tokens with
@@ -82,11 +82,16 @@ func WithScopes(ctx context.Context, scopes ...string) context.Context {
return context.WithValue(ctx, scopesContextKey{}, scopes)
}

func WithPerRegistryScopes(ctx context.Context, registry string, scopes ...string) context.Context {
func WithScopesPerRegistry(ctx context.Context, registry string, scopes ...string) context.Context {
var regMap map[string][]string
var ok bool
regMap, ok = ctx.Value(ScopesPerRegistryContextKey{}).(map[string][]string)
if !ok {
regMap = make(map[string][]string, 0)
}
scopes = CleanScopes(scopes)
regMap := make(map[string][]string, 0)
regMap[registry] = scopes
return context.WithValue(ctx, perRegistryScopesContextKey{}, regMap)
return context.WithValue(ctx, ScopesPerRegistryContextKey{}, regMap)
}

// AppendScopes appends additional scopes to the existing scopes in the context
@@ -107,8 +112,8 @@ func GetScopes(ctx context.Context) []string {
return nil
}

func GetPerRegistryScopes(ctx context.Context, registry string) []string {
if regMap, ok := ctx.Value(perRegistryScopesContextKey{}).(map[string][]string); ok {
func GetScopesPerRegistry(ctx context.Context, registry string) []string {
if regMap, ok := ctx.Value(ScopesPerRegistryContextKey{}).(map[string][]string); ok {
return append([]string(nil), regMap[registry]...)
}
return nil
79 changes: 79 additions & 0 deletions registry/remote/auth/scope_test.go
Original file line number Diff line number Diff line change
@@ -148,6 +148,85 @@ func TestWithScopes(t *testing.T) {
}
}

func TestWithScopesPerRegistry(t *testing.T) {
ctx := context.Background()
reg1 := "registry1.example.com"
reg2 := "registry2.example.com"

// with single scope
want1 := []string{
"repository:foo:pull",
}
want2 := []string{
"repository:foo:push",
}
ctx = WithScopesPerRegistry(ctx, reg1, want1...)
ctx = WithScopesPerRegistry(ctx, reg2, want2...)
if got := GetScopesPerRegistry(ctx, reg1); !reflect.DeepEqual(got, want1) {
t.Errorf("GetScopes(WithScopes()) = %v, want %v", got, want1)
}
if got := GetScopesPerRegistry(ctx, reg2); !reflect.DeepEqual(got, want2) {
t.Errorf("GetScopes(WithScopes()) = %v, want %v", got, want2)
}

// overwrite scopes
want1 = []string{
"repository:bar:push",
}
want2 = []string{
"repository:bar:pull",
}
ctx = WithScopesPerRegistry(ctx, reg1, want1...)
ctx = WithScopesPerRegistry(ctx, reg2, want2...)
if got := GetScopesPerRegistry(ctx, reg1); !reflect.DeepEqual(got, want1) {
t.Errorf("GetScopes(WithScopes()) = %v, want %v", got, want1)
}
if got := GetScopesPerRegistry(ctx, reg2); !reflect.DeepEqual(got, want2) {
t.Errorf("GetScopes(WithScopes()) = %v, want %v", got, want2)
}

// overwrite scopes with de-duplication
scopes1 := []string{
"repository:hello-world:push",
"repository:alpine:delete",
"repository:hello-world:pull",
"repository:alpine:delete",
}
want1 = []string{
"repository:alpine:delete",
"repository:hello-world:pull,push",
}
scopes2 := []string{
"repository:goodbye-world:push",
"repository:nginx:delete",
"repository:goodbye-world:pull",
"repository:nginx:delete",
}
want2 = []string{
"repository:goodbye-world:pull,push",
"repository:nginx:delete",
}
ctx = WithScopesPerRegistry(ctx, reg1, scopes1...)
ctx = WithScopesPerRegistry(ctx, reg2, scopes2...)
if got := GetScopesPerRegistry(ctx, reg1); !reflect.DeepEqual(got, want1) {
t.Errorf("GetScopes(WithScopes()) = %v, want %v", got, want1)
}
if got := GetScopesPerRegistry(ctx, reg2); !reflect.DeepEqual(got, want2) {
t.Errorf("GetScopes(WithScopes()) = %v, want %v", got, want2)
}

// clean scopes
var want []string
ctx = WithScopesPerRegistry(ctx, reg1, want...)
ctx = WithScopesPerRegistry(ctx, reg2, want...)
if got := GetScopesPerRegistry(ctx, reg1); !reflect.DeepEqual(got, want) {
t.Errorf("GetScopes(WithScopes()) = %v, want %v", got, want)
}
if got := GetScopesPerRegistry(ctx, reg2); !reflect.DeepEqual(got, want) {
t.Errorf("GetScopes(WithScopes()) = %v, want %v", got, want)
}
}

func TestAppendScopes(t *testing.T) {
ctx := context.Background()