diff --git a/go/.tool-versions b/go/.tool-versions new file mode 100644 index 000000000..1a59aeb0b --- /dev/null +++ b/go/.tool-versions @@ -0,0 +1 @@ +golang 1.23.0 diff --git a/go/appencryption/go.work.sum b/go/appencryption/go.work.sum index 569518e7b..03a93143a 100644 --- a/go/appencryption/go.work.sum +++ b/go/appencryption/go.work.sum @@ -227,7 +227,6 @@ github.com/containerd/typeurl v1.0.2 h1:Chlt8zIieDbzQFzXzAeBEF92KhExuE4p9p92/QmY github.com/containerd/typeurl v1.0.2/go.mod h1:9trJWW2sRlGub4wZJRTW83VtbOLS6hwcDZXTn6oPz9s= github.com/containerd/typeurl/v2 v2.1.1 h1:3Q4Pt7i8nYwy2KmQWIw2+1hTvwTE/6w9FqcttATPO/4= github.com/containerd/typeurl/v2 v2.1.1/go.mod h1:IDp2JFvbwZ31H8dQbEIY7sDl2L3o3HZj1hsSQlywkQ0= -github.com/containerd/typeurl/v2 v2.2.0/go.mod h1:8XOOxnyatxSWuG8OfsZXVnAF4iZfedjS/8UHSPJnX4g= github.com/containerd/zfs v1.0.0 h1:cXLJbx+4Jj7rNsTiqVfm6i+RNLx6FFA2fMmDlEf+Wm8= github.com/containerd/zfs v1.1.0 h1:n7OZ7jZumLIqNJqXrEc/paBM840mORnmGdJDmAmJZHM= github.com/containerd/zfs v1.1.0/go.mod h1:oZF9wBnrnQjpWLaPKEinrx3TQ9a+W/RJO7Zb41d8YLE= @@ -324,7 +323,6 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo= @@ -410,11 +408,8 @@ github.com/moby/locker v1.0.1 h1:fOXqR41zeveg4fFODix+1Ch4mj/gT0NE1XJbp/epuBg= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= -github.com/moby/sys/mount v0.3.4/go.mod h1:KcQJMbQdJHPlq5lcYT+/CjatWM4PuxKe+XLSVS4J6Os= github.com/moby/sys/mountinfo v0.6.2 h1:BzJjoreD5BMFNmD9Rus6gdd1pLuecOFPt8wC+Vygl78= github.com/moby/sys/mountinfo v0.6.2/go.mod h1:IJb6JQeOklcdMU9F5xQ8ZALD+CUr5VlGpwtX+VE0rpI= -github.com/moby/sys/mountinfo v0.7.2/go.mod h1:1YOa8w8Ih7uW0wALDUgT1dTTSBrZ+HiBLGws92L2RU4= -github.com/moby/sys/reexec v0.1.0/go.mod h1:EqjBg8F3X7iZe5pU6nRZnYCMUTXoxsjiIfHup5wYIN8= github.com/moby/sys/signal v0.6.0 h1:aDpY94H8VlhTGa9sNYUFCFsMZIUh5wm0B6XkIoJj/iY= github.com/moby/sys/signal v0.7.0 h1:25RW3d5TnQEoKvRbEKUGay6DCQ46IxAVTT9CUMgmsSI= github.com/moby/sys/signal v0.7.0/go.mod h1:GQ6ObYZfqacOwTtlXvcmh9A26dVRul/hbOZn88Kg8Tg= @@ -472,7 +467,6 @@ github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0 github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/safchain/ethtool v0.0.0-20190326074333-42ed695e3de8 h1:2c1EFnZHIPCW8qKWgHMH/fX2PkSabFc5mrVzfUNdg5U= -github.com/santhosh-tekuri/jsonschema/v5 v5.3.1/go.mod h1:uToXkOrWAZ6/Oc07xWQrPOhJotwFIyu2bBVN41fcDUY= github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= github.com/sclevine/spec v1.2.0 h1:1Jwdf9jSfDl9NVmt8ndHqbTZ7XCCPbh1jI3hkDBHVYA= github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646 h1:RpforrEYXWkmGwJHIGnLZ3tTWStkjVVstwzNGqxX2Ds= @@ -575,6 +569,7 @@ golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= diff --git a/go/appencryption/session.go b/go/appencryption/session.go index 205dc6610..19c688186 100644 --- a/go/appencryption/session.go +++ b/go/appencryption/session.go @@ -89,15 +89,40 @@ func NewSessionFactory(config *Config, store Metastore, kms KeyManagementService // Close will close any open resources owned by this factory (e.g. cache of system keys). It should be called // when the factory is no longer required. func (f *SessionFactory) Close() error { + var errs []error + if f.Config.Policy.CacheSessions { f.sessionCache.Close() } if f.Config.Policy.SharedIntermediateKeyCache { - f.intermediateKeys.Close() + if err := f.intermediateKeys.Close(); err != nil { + errs = append(errs, err) + } + } + + if err := f.systemKeys.Close(); err != nil { + errs = append(errs, err) + } + + if len(errs) == 0 { + return nil + } + + if len(errs) == 1 { + return errs[0] } - return f.systemKeys.Close() + // Combine multiple errors into a single error message + var msg string + for i, err := range errs { + if i == 0 { + msg = err.Error() + } else { + msg = msg + "; " + err.Error() + } + } + return errors.New(msg) } // GetSession returns a new session for the provided partition ID. diff --git a/go/appencryption/session_test.go b/go/appencryption/session_test.go index af20048dc..3a66132af 100644 --- a/go/appencryption/session_test.go +++ b/go/appencryption/session_test.go @@ -479,3 +479,92 @@ func TestSessionFactory_GetSession_SessionCache(t *testing.T) { assert.NotNil(t, sess) cache.AssertCalled(t, "Get", "testing") } + +func TestSessionFactory_Close_ErrorHandling(t *testing.T) { + tests := []struct { + name string + intermediateError error + systemError error + sharedCache bool + expectedError string + }{ + { + name: "intermediate_error_only", + intermediateError: fmt.Errorf("intermediate cache close failed"), + systemError: nil, + sharedCache: true, + expectedError: "intermediate cache close failed", + }, + { + name: "system_error_only", + intermediateError: nil, + systemError: fmt.Errorf("system cache close failed"), + sharedCache: true, + expectedError: "system cache close failed", + }, + { + name: "both_errors", + intermediateError: fmt.Errorf("intermediate cache close failed"), + systemError: fmt.Errorf("system cache close failed"), + sharedCache: true, + expectedError: "intermediate cache close failed; system cache close failed", + }, + { + name: "no_shared_cache_system_error", + intermediateError: nil, + systemError: fmt.Errorf("system cache close failed"), + sharedCache: false, + expectedError: "system cache close failed", + }, + { + name: "no_errors", + intermediateError: nil, + systemError: nil, + sharedCache: true, + expectedError: "", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + testSessionFactoryCloseError(t, tt.intermediateError, tt.systemError, tt.sharedCache, tt.expectedError) + }) + } +} + +func testSessionFactoryCloseError(t *testing.T, intermediateError, systemError error, sharedCache bool, expectedError string) { + // Create factory with test configuration + config := &Config{ + Policy: &CryptoPolicy{ + SharedIntermediateKeyCache: sharedCache, + }, + } + factory := NewSessionFactory(config, nil, nil, nil) + + // Setup mock caches + mockSystemCache := new(MockCache) + mockSystemCache.On("Close").Return(systemError) + factory.systemKeys = mockSystemCache + + if sharedCache { + mockIntermediateCache := new(MockCache) + mockIntermediateCache.On("Close").Return(intermediateError) + factory.intermediateKeys = mockIntermediateCache + } + + // Test the Close method + err := factory.Close() + + // Verify expectations + if expectedError == "" { + assert.NoError(t, err) + } else { + assert.EqualError(t, err, expectedError) + } + + // Verify all expected calls were made + mockSystemCache.AssertCalled(t, "Close") + if sharedCache { + factory.intermediateKeys.(*MockCache).AssertCalled(t, "Close") + } +}