From 93c26da9da23d3b19e865047a42eb4b3b5727a53 Mon Sep 17 00:00:00 2001 From: Alano Terblanche <18033717+Benehiko@users.noreply.github.com> Date: Tue, 27 Jan 2026 14:37:52 +0100 Subject: [PATCH] feat: factory function provides more context Signed-off-by: Alano Terblanche <18033717+Benehiko@users.noreply.github.com> --- plugins/pass/store/store.go | 4 +++- store/keychain/cmd/main.go | 2 +- store/keychain/keychain_darwin.go | 14 +++++++------- store/keychain/keychain_darwin_test.go | 3 ++- store/keychain/keychain_linux.go | 14 +++++++------- store/keychain/keychain_test.go | 8 ++++---- store/keychain/keychain_windows.go | 14 +++++++------- store/posixage/store.go | 6 +++--- store/posixage/store_test.go | 22 +++++++++++----------- store/store.go | 2 +- 10 files changed, 46 insertions(+), 43 deletions(-) diff --git a/plugins/pass/store/store.go b/plugins/pass/store/store.go index 034445a4..1b954f47 100644 --- a/plugins/pass/store/store.go +++ b/plugins/pass/store/store.go @@ -1,6 +1,8 @@ package store import ( + "context" + "github.com/docker/secrets-engine/store" "github.com/docker/secrets-engine/store/keychain" ) @@ -32,7 +34,7 @@ func PassStore(serviceGroup string, opts ...keychain.Option) (store.Store, error kc, err := keychain.New( serviceGroup, "docker-pass-cli", - func() *PassValue { + func(_ context.Context, _ store.ID) *PassValue { return &PassValue{} }, opts..., diff --git a/store/keychain/cmd/main.go b/store/keychain/cmd/main.go index 36b84060..3d261445 100644 --- a/store/keychain/cmd/main.go +++ b/store/keychain/cmd/main.go @@ -20,7 +20,7 @@ func newCommand() (*cobra.Command, error) { kc, err := keychain.New( "io.docker.Secrets", "docker-example-cli", - func() *mocks.MockCredential { + func(_ context.Context, _ store.ID) *mocks.MockCredential { return &mocks.MockCredential{} }, ) diff --git a/store/keychain/keychain_darwin.go b/store/keychain/keychain_darwin.go index bb3e88f6..b0931e3e 100644 --- a/store/keychain/keychain_darwin.go +++ b/store/keychain/keychain_darwin.go @@ -19,7 +19,7 @@ var ( type keychainStore[T store.Secret] struct { serviceGroup string serviceName string - factory func() T + factory store.Factory[T] useDataProtectionKeychain bool } @@ -102,7 +102,7 @@ func (k *keychainStore[T]) Delete(_ context.Context, id store.ID) error { return nil } -func (k *keychainStore[T]) Get(_ context.Context, id store.ID) (store.Secret, error) { +func (k *keychainStore[T]) Get(ctx context.Context, id store.ID) (store.Secret, error) { result, err := getItemWithData(id.String(), k) if err != nil { return nil, err @@ -114,7 +114,7 @@ func (k *keychainStore[T]) Get(_ context.Context, id store.ID) (store.Secret, er } safelyCleanMetadata(attributes) - secret := k.factory() + secret := k.factory(ctx, id) if err := secret.SetMetadata(attributes); err != nil { return nil, err } @@ -124,7 +124,7 @@ func (k *keychainStore[T]) Get(_ context.Context, id store.ID) (store.Secret, er return secret, nil } -func (k *keychainStore[T]) GetAllMetadata(context.Context) (map[store.ID]store.Secret, error) { +func (k *keychainStore[T]) GetAllMetadata(ctx context.Context) (map[store.ID]store.Secret, error) { item := newKeychainItem("", k) // We use the MatchLimitAll attribute to query for multiple items from the @@ -149,7 +149,7 @@ func (k *keychainStore[T]) GetAllMetadata(context.Context) (map[store.ID]store.S } safelyCleanMetadata(attributes) - secret := k.factory() + secret := k.factory(ctx, id) if err := secret.SetMetadata(attributes); err != nil { return nil, err } @@ -184,7 +184,7 @@ func (k *keychainStore[T]) Save(_ context.Context, id store.ID, secret store.Sec return mapKeychainError(kc.AddItem(item)) } -func (k *keychainStore[T]) Filter(_ context.Context, pattern store.Pattern) (map[store.ID]store.Secret, error) { +func (k *keychainStore[T]) Filter(ctx context.Context, pattern store.Pattern) (map[store.ID]store.Secret, error) { // Note: Filter on macOS cannot filter by generic attributes and thus we // cannot split the ID and store it in the keychain as parts for later // pattern matching. @@ -242,7 +242,7 @@ func (k *keychainStore[T]) Filter(_ context.Context, pattern store.Pattern) (map return nil, err } - secret := k.factory() + secret := k.factory(ctx, id) if err := secret.SetMetadata(attr); err != nil { return nil, err } diff --git a/store/keychain/keychain_darwin_test.go b/store/keychain/keychain_darwin_test.go index 3b1d4b63..e21b8b4b 100644 --- a/store/keychain/keychain_darwin_test.go +++ b/store/keychain/keychain_darwin_test.go @@ -4,6 +4,7 @@ package keychain import ( "bytes" + "context" "testing" "github.com/google/uuid" @@ -22,7 +23,7 @@ func TestMacosKeychain(t *testing.T) { keychainStore := keychainStore[*mocks.MockCredential]{ serviceGroup: serviceGroup, serviceName: serviceName, - factory: func() *mocks.MockCredential { + factory: func(_ context.Context, _ store.ID) *mocks.MockCredential { return &mocks.MockCredential{} }, } diff --git a/store/keychain/keychain_linux.go b/store/keychain/keychain_linux.go index 728ecb00..6f3abc7b 100644 --- a/store/keychain/keychain_linux.go +++ b/store/keychain/keychain_linux.go @@ -97,7 +97,7 @@ func isCollectionUnlocked(collectionPath dbus.ObjectPath, service *kc.SecretServ type keychainStore[T store.Secret] struct { serviceGroup string serviceName string - factory func() T + factory store.Factory[T] } func (k *keychainStore[T]) Delete(_ context.Context, id store.ID) error { @@ -143,7 +143,7 @@ func (k *keychainStore[T]) Delete(_ context.Context, id store.ID) error { return service.DeleteItem(items[0]) } -func (k *keychainStore[T]) Get(_ context.Context, id store.ID) (store.Secret, error) { +func (k *keychainStore[T]) Get(ctx context.Context, id store.ID) (store.Secret, error) { service, err := kc.NewService() if err != nil { return nil, err @@ -193,7 +193,7 @@ func (k *keychainStore[T]) Get(_ context.Context, id store.ID) (store.Secret, er if err != nil { return nil, err } - secret := k.factory() + secret := k.factory(ctx, id) if err := secret.SetMetadata(attributes); err != nil { return nil, err } @@ -204,7 +204,7 @@ func (k *keychainStore[T]) Get(_ context.Context, id store.ID) (store.Secret, er return secret, nil } -func (k *keychainStore[T]) GetAllMetadata(context.Context) (map[store.ID]store.Secret, error) { +func (k *keychainStore[T]) GetAllMetadata(ctx context.Context) (map[store.ID]store.Secret, error) { service, err := kc.NewService() if err != nil { return nil, err @@ -261,7 +261,7 @@ func (k *keychainStore[T]) GetAllMetadata(context.Context) (map[store.ID]store.S } safelyCleanMetadata(attributes) - secret := k.factory() + secret := k.factory(ctx, secretID) if err := secret.SetMetadata(attributes); err != nil { return nil, err } @@ -326,7 +326,7 @@ func (k *keychainStore[T]) Save(_ context.Context, id store.ID, secret store.Sec } //gocyclo:ignore -func (k *keychainStore[T]) Filter(_ context.Context, pattern store.Pattern) (map[store.ID]store.Secret, error) { +func (k *keychainStore[T]) Filter(ctx context.Context, pattern store.Pattern) (map[store.ID]store.Secret, error) { service, err := kc.NewService() if err != nil { return nil, err @@ -402,7 +402,7 @@ func (k *keychainStore[T]) Filter(_ context.Context, pattern store.Pattern) (map } safelyCleanMetadata(attributes) - secret := k.factory() + secret := k.factory(ctx, secretID) if err := secret.SetMetadata(attributes); err != nil { return nil, err } diff --git a/store/keychain/keychain_test.go b/store/keychain/keychain_test.go index de8efd7f..5bd085c5 100644 --- a/store/keychain/keychain_test.go +++ b/store/keychain/keychain_test.go @@ -50,10 +50,10 @@ func (m *mustUnmarshalError) Unmarshal([]byte) error { return errors.New("i am failing on purpose") } -func setupKeychain(t *testing.T, secretFactory func() store.Secret) store.Store { +func setupKeychain(t *testing.T, secretFactory func(context.Context, store.ID) store.Secret) store.Store { t.Helper() if secretFactory == nil { - secretFactory = func() store.Secret { + secretFactory = func(_ context.Context, _ store.ID) store.Secret { return &mocks.MockCredential{} } } @@ -266,7 +266,7 @@ func TestKeychain(t *testing.T) { }) t.Run("unmarshal error on get", func(t *testing.T) { - kc := setupKeychain(t, func() store.Secret { + kc := setupKeychain(t, func(_ context.Context, _ store.ID) store.Secret { return &mustUnmarshalError{} }) id, err := store.ParseID("something/will/fail") @@ -280,7 +280,7 @@ func TestKeychain(t *testing.T) { }) t.Run("set metadata error on getAllMetadata", func(t *testing.T) { - kc := setupKeychain(t, func() store.Secret { + kc := setupKeychain(t, func(_ context.Context, _ store.ID) store.Secret { return &mustUnmarshalError{} }) id, err := store.ParseID("something/will/fail") diff --git a/store/keychain/keychain_windows.go b/store/keychain/keychain_windows.go index 650181b3..e84997e2 100644 --- a/store/keychain/keychain_windows.go +++ b/store/keychain/keychain_windows.go @@ -54,7 +54,7 @@ func decodeSecret(blob []byte, secret store.Secret) error { type keychainStore[T store.Secret] struct { serviceGroup string serviceName string - factory func() T + factory store.Factory[T] } func (k *keychainStore[T]) Delete(_ context.Context, id store.ID) error { @@ -66,7 +66,7 @@ func (k *keychainStore[T]) Delete(_ context.Context, id store.ID) error { return nil } -func (k *keychainStore[T]) Get(_ context.Context, id store.ID) (store.Secret, error) { +func (k *keychainStore[T]) Get(ctx context.Context, id store.ID) (store.Secret, error) { gc, err := wincred.GetGenericCredential(k.itemLabel(id.String())) if err != nil { return nil, mapWindowsCredentialError(err) @@ -75,7 +75,7 @@ func (k *keychainStore[T]) Get(_ context.Context, id store.ID) (store.Secret, er attributes := mapFromWindowsAttributes(gc.Attributes) safelyCleanMetadata(attributes) - secret := k.factory() + secret := k.factory(ctx, id) if err := secret.SetMetadata(attributes); err != nil { return nil, err } @@ -148,7 +148,7 @@ func mapFromWindowsAttributes(winAttrs []wincred.CredentialAttribute) map[string return attributes } -func (k *keychainStore[T]) GetAllMetadata(context.Context) (map[store.ID]store.Secret, error) { +func (k *keychainStore[T]) GetAllMetadata(ctx context.Context) (map[store.ID]store.Secret, error) { credentials, err := wincred.List() if err != nil { return nil, mapWindowsCredentialError(err) @@ -169,7 +169,7 @@ func (k *keychainStore[T]) GetAllMetadata(context.Context) (map[store.ID]store.S attributes := mapFromWindowsAttributes(cred.Attributes) safelyCleanMetadata(attributes) - secret := k.factory() + secret := k.factory(ctx, id) if err := secret.SetMetadata(attributes); err != nil { return nil, err } @@ -198,7 +198,7 @@ func (k *keychainStore[T]) Save(_ context.Context, id store.ID, secret store.Sec return mapWindowsCredentialError(g.Write()) } -func (k *keychainStore[T]) Filter(_ context.Context, pattern store.Pattern) (map[store.ID]store.Secret, error) { +func (k *keychainStore[T]) Filter(ctx context.Context, pattern store.Pattern) (map[store.ID]store.Secret, error) { // Note: there is no notion of a filter on Windows inside the wincred API. // It has no way to even filter on known attributes. // This means we need to retrieve the entire list of ALL secrets, that @@ -241,7 +241,7 @@ func (k *keychainStore[T]) Filter(_ context.Context, pattern store.Pattern) (map gcAttributes := mapFromWindowsAttributes(gc.Attributes) safelyCleanMetadata(gcAttributes) - secret := k.factory() + secret := k.factory(ctx, id) if err := secret.SetMetadata(gcAttributes); err != nil { return nil, err } diff --git a/store/posixage/store.go b/store/posixage/store.go index e1f4a582..c1105f1f 100644 --- a/store/posixage/store.go +++ b/store/posixage/store.go @@ -201,7 +201,7 @@ func (f *fileStore[T]) Filter(ctx context.Context, pattern store.Pattern) (map[s return err } - secret := f.factory() + secret := f.factory(ctx, id) if err := secret.SetMetadata(metadata); err != nil { return err } @@ -241,7 +241,7 @@ func (f *fileStore[T]) Get(ctx context.Context, id store.ID) (store.Secret, erro return nil, err } - secret := f.factory() + secret := f.factory(ctx, id) if err := secret.SetMetadata(metadata); err != nil { return nil, err } @@ -286,7 +286,7 @@ func (f *fileStore[T]) GetAllMetadata(ctx context.Context) (map[store.ID]store.S return err } - secret := f.factory() + secret := f.factory(ctx, id) if err := secret.SetMetadata(metadata); err != nil { return err } diff --git a/store/posixage/store_test.go b/store/posixage/store_test.go index d66bd73e..a4737fa2 100644 --- a/store/posixage/store_test.go +++ b/store/posixage/store_test.go @@ -70,7 +70,7 @@ func TestPOSIXAge(t *testing.T) { masterKey := uuid.NewString() s, err := New(root, - func() *mocks.MockCredential { + func(_ context.Context, _ store.ID) *mocks.MockCredential { return &mocks.MockCredential{} }, WithLogger(&testLogger{t}), @@ -143,7 +143,7 @@ func TestPOSIXAge(t *testing.T) { masterKey := uuid.NewString() s, err := New(root, - func() *mocks.MockCredential { + func(_ context.Context, _ store.ID) *mocks.MockCredential { return &mocks.MockCredential{} }, WithLogger(&testLogger{t}), @@ -182,7 +182,7 @@ func TestPOSIXAge(t *testing.T) { masterKey := uuid.NewString() s, err := New(root, - func() *mocks.MockCredential { + func(_ context.Context, _ store.ID) *mocks.MockCredential { return &mocks.MockCredential{} }, WithLogger(&testLogger{t}), @@ -240,7 +240,7 @@ func TestPOSIXAge(t *testing.T) { masterKey := uuid.NewString() s, err := New(root, - func() *mocks.MockCredential { + func(_ context.Context, _ store.ID) *mocks.MockCredential { return &mocks.MockCredential{} }, WithLogger(&testLogger{t}), @@ -301,7 +301,7 @@ func TestPOSIXAge(t *testing.T) { require.NoError(t, err) s, err := New(root, - func() *mocks.MockCredential { + func(_ context.Context, _ store.ID) *mocks.MockCredential { return &mocks.MockCredential{} }, WithLogger(&testLogger{t}), @@ -384,7 +384,7 @@ func TestPOSIXAge(t *testing.T) { require.NoError(t, err) s, err := New(root, - func() *mocks.MockCredential { + func(_ context.Context, _ store.ID) *mocks.MockCredential { return &mocks.MockCredential{} }, WithLogger(&testLogger{t}), @@ -463,7 +463,7 @@ func TestPOSIXAge(t *testing.T) { }) s, err := New(root, - func() *mocks.MockCredential { + func(_ context.Context, _ store.ID) *mocks.MockCredential { return &mocks.MockCredential{} }, WithLogger(&testLogger{t}), @@ -530,7 +530,7 @@ func TestPOSIXAge(t *testing.T) { require.NoError(t, err) s, err := New(root, - func() *mocks.MockCredential { + func(_ context.Context, _ store.ID) *mocks.MockCredential { return &mocks.MockCredential{} }, WithLogger(&testLogger{t}), @@ -602,7 +602,7 @@ func TestPOSIXAge(t *testing.T) { }) s, err := New(root, - func() *mocks.MockCredential { + func(_ context.Context, _ store.ID) *mocks.MockCredential { return &mocks.MockCredential{} }, WithLogger(&testLogger{t}), @@ -651,7 +651,7 @@ func TestPOSIXAge(t *testing.T) { encryptError := errors.New("something went wrong inside the encryption callbackFunc") s, err := New(root, - func() *mocks.MockCredential { + func(_ context.Context, _ store.ID) *mocks.MockCredential { return &mocks.MockCredential{} }, WithLogger(&testLogger{t}), @@ -684,7 +684,7 @@ func TestPOSIXAge(t *testing.T) { decryptError := errors.New("something went wrong inside the decryption callbackFunc") s, err := New(root, - func() *mocks.MockCredential { + func(_ context.Context, _ store.ID) *mocks.MockCredential { return &mocks.MockCredential{} }, WithLogger(&testLogger{t}), diff --git a/store/store.go b/store/store.go index f48857ac..fcb37e95 100644 --- a/store/store.go +++ b/store/store.go @@ -78,4 +78,4 @@ type Store interface { Filter(ctx context.Context, pattern Pattern) (map[ID]Secret, error) } -type Factory[T Secret] func() T +type Factory[T Secret] func(context.Context, ID) T