From f111b147d090734bbcc7420b25393878f8706060 Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Thu, 14 May 2026 14:09:29 -0700 Subject: [PATCH 1/3] Add external Connect interceptor factory --- service/pkg/server/options.go | 19 ++++++++++ service/pkg/server/options_test.go | 57 ++++++++++++++++++++++++++++++ service/pkg/server/start.go | 14 ++++++++ 3 files changed, 90 insertions(+) diff --git a/service/pkg/server/options.go b/service/pkg/server/options.go index db3952ceef..34e0577b95 100644 --- a/service/pkg/server/options.go +++ b/service/pkg/server/options.go @@ -5,6 +5,7 @@ import ( "connectrpc.com/connect" "github.com/casbin/casbin/v2/persist" + "github.com/opentdf/platform/sdk" "github.com/opentdf/platform/service/pkg/authz" "github.com/opentdf/platform/service/pkg/config" "github.com/opentdf/platform/service/pkg/serviceregistry" @@ -13,6 +14,12 @@ import ( type StartOptions func(StartConfig) StartConfig +type ExternalConnectInterceptorContext struct { + SDK *sdk.SDK +} + +type ExternalConnectInterceptorFactory func(ExternalConnectInterceptorContext) (connect.Interceptor, error) + type StartConfig struct { ConfigKey string ConfigFile string @@ -28,6 +35,7 @@ type StartConfig struct { extraConnectInterceptors []connect.Interceptor extraIPCInterceptors []connect.Interceptor + externalConnectFactories []ExternalConnectInterceptorFactory trustKeyManagerCtxs []trust.NamedKeyManagerCtxFactory @@ -178,6 +186,17 @@ func WithConnectInterceptors(interceptors ...connect.Interceptor) StartOptions { } } +// WithExternalConnectInterceptorFactories appends factories for external +// Connect interceptors that need access to startup-created clients, such as the +// IPC SDK connection. Factories are evaluated after the SDK is created and +// before externally reachable service handlers are registered. +func WithExternalConnectInterceptorFactories(factories ...ExternalConnectInterceptorFactory) StartOptions { + return func(c StartConfig) StartConfig { + c.externalConnectFactories = append(c.externalConnectFactories, factories...) + return c + } +} + // WithIPCInterceptors appends additional Connect interceptors for in-process IPC server. func WithIPCInterceptors(interceptors ...connect.Interceptor) StartOptions { return func(c StartConfig) StartConfig { diff --git a/service/pkg/server/options_test.go b/service/pkg/server/options_test.go index ff17bb4b12..23aa877c09 100644 --- a/service/pkg/server/options_test.go +++ b/service/pkg/server/options_test.go @@ -73,6 +73,63 @@ func TestWithConnectInterceptors(t *testing.T) { } } +func TestWithExternalConnectInterceptorFactories(t *testing.T) { + factory := func(ExternalConnectInterceptorContext) (connect.Interceptor, error) { + return noopInterceptor(), nil + } + + tests := []struct { + name string + apply func(*StartConfig) + wantCount int + }{ + { + name: "single factory is appended", + apply: func(c *StartConfig) { + *c = WithExternalConnectInterceptorFactories(factory)(*c) + }, + wantCount: 1, + }, + { + name: "multiple factories are appended in order", + apply: func(c *StartConfig) { + *c = WithExternalConnectInterceptorFactories(factory, factory, factory)(*c) + }, + wantCount: 3, + }, + { + name: "calling twice accumulates factories", + apply: func(c *StartConfig) { + *c = WithExternalConnectInterceptorFactories(factory)(*c) + *c = WithExternalConnectInterceptorFactories(factory, factory)(*c) + }, + wantCount: 3, + }, + { + name: "empty call leaves slice nil", + apply: func(c *StartConfig) { + *c = WithExternalConnectInterceptorFactories()(*c) + }, + wantCount: 0, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var cfg StartConfig + tt.apply(&cfg) + + if tt.wantCount == 0 { + assert.Nil(t, cfg.externalConnectFactories) + } else { + require.Len(t, cfg.externalConnectFactories, tt.wantCount) + } + assert.Nil(t, cfg.extraConnectInterceptors) + assert.Nil(t, cfg.extraIPCInterceptors) + }) + } +} + func TestWithIPCInterceptors(t *testing.T) { tests := []struct { name string diff --git a/service/pkg/server/start.go b/service/pkg/server/start.go index f3513a090d..8029a5250e 100644 --- a/service/pkg/server/start.go +++ b/service/pkg/server/start.go @@ -282,6 +282,20 @@ func Start(f ...StartOptions) error { defer client.Close() + if len(startConfig.externalConnectFactories) > 0 { + for _, factory := range startConfig.externalConnectFactories { + interceptor, err := factory(ExternalConnectInterceptorContext{ + SDK: client, + }) + if err != nil { + return fmt.Errorf("failed to create external connect interceptor: %w", err) + } + if interceptor != nil { + otdf.ConnectRPC.Interceptors = append(otdf.ConnectRPC.Interceptors, connect.WithInterceptors(interceptor)) + } + } + } + logger.Info("starting services") gatewayCleanup, err := startServices(ctx, startServicesParams{ cfg: cfg, From 7bf1548adc4e5266491af55617494a533cd65128 Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Fri, 15 May 2026 11:44:47 -0700 Subject: [PATCH 2/3] refactor(core): rename interceptor types and add logger to params Rename ExternalConnectInterceptorContext to InterceptorParams and thread the server logger through so external interceptor factories have access to the production logger. --- service/pkg/server/options.go | 16 +++++++++------- service/pkg/server/options_test.go | 18 +++++++++--------- service/pkg/server/start.go | 9 +++++---- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/service/pkg/server/options.go b/service/pkg/server/options.go index 34e0577b95..165d2b39b6 100644 --- a/service/pkg/server/options.go +++ b/service/pkg/server/options.go @@ -6,6 +6,7 @@ import ( "connectrpc.com/connect" "github.com/casbin/casbin/v2/persist" "github.com/opentdf/platform/sdk" + "github.com/opentdf/platform/service/logger" "github.com/opentdf/platform/service/pkg/authz" "github.com/opentdf/platform/service/pkg/config" "github.com/opentdf/platform/service/pkg/serviceregistry" @@ -14,11 +15,12 @@ import ( type StartOptions func(StartConfig) StartConfig -type ExternalConnectInterceptorContext struct { - SDK *sdk.SDK +type InterceptorParams struct { + SDK *sdk.SDK + Logger *logger.Logger } -type ExternalConnectInterceptorFactory func(ExternalConnectInterceptorContext) (connect.Interceptor, error) +type InterceptorFactory func(InterceptorParams) (connect.Interceptor, error) type StartConfig struct { ConfigKey string @@ -35,7 +37,7 @@ type StartConfig struct { extraConnectInterceptors []connect.Interceptor extraIPCInterceptors []connect.Interceptor - externalConnectFactories []ExternalConnectInterceptorFactory + externalInterceptorFactories []InterceptorFactory trustKeyManagerCtxs []trust.NamedKeyManagerCtxFactory @@ -186,13 +188,13 @@ func WithConnectInterceptors(interceptors ...connect.Interceptor) StartOptions { } } -// WithExternalConnectInterceptorFactories appends factories for external +// WithExternalInterceptorFactories appends factories for external // Connect interceptors that need access to startup-created clients, such as the // IPC SDK connection. Factories are evaluated after the SDK is created and // before externally reachable service handlers are registered. -func WithExternalConnectInterceptorFactories(factories ...ExternalConnectInterceptorFactory) StartOptions { +func WithExternalInterceptorFactories(factories ...InterceptorFactory) StartOptions { return func(c StartConfig) StartConfig { - c.externalConnectFactories = append(c.externalConnectFactories, factories...) + c.externalInterceptorFactories = append(c.externalInterceptorFactories, factories...) return c } } diff --git a/service/pkg/server/options_test.go b/service/pkg/server/options_test.go index 23aa877c09..77fc4159a6 100644 --- a/service/pkg/server/options_test.go +++ b/service/pkg/server/options_test.go @@ -73,8 +73,8 @@ func TestWithConnectInterceptors(t *testing.T) { } } -func TestWithExternalConnectInterceptorFactories(t *testing.T) { - factory := func(ExternalConnectInterceptorContext) (connect.Interceptor, error) { +func TestWithExternalInterceptorFactories(t *testing.T) { + factory := func(InterceptorParams) (connect.Interceptor, error) { return noopInterceptor(), nil } @@ -86,29 +86,29 @@ func TestWithExternalConnectInterceptorFactories(t *testing.T) { { name: "single factory is appended", apply: func(c *StartConfig) { - *c = WithExternalConnectInterceptorFactories(factory)(*c) + *c = WithExternalInterceptorFactories(factory)(*c) }, wantCount: 1, }, { name: "multiple factories are appended in order", apply: func(c *StartConfig) { - *c = WithExternalConnectInterceptorFactories(factory, factory, factory)(*c) + *c = WithExternalInterceptorFactories(factory, factory, factory)(*c) }, wantCount: 3, }, { name: "calling twice accumulates factories", apply: func(c *StartConfig) { - *c = WithExternalConnectInterceptorFactories(factory)(*c) - *c = WithExternalConnectInterceptorFactories(factory, factory)(*c) + *c = WithExternalInterceptorFactories(factory)(*c) + *c = WithExternalInterceptorFactories(factory, factory)(*c) }, wantCount: 3, }, { name: "empty call leaves slice nil", apply: func(c *StartConfig) { - *c = WithExternalConnectInterceptorFactories()(*c) + *c = WithExternalInterceptorFactories()(*c) }, wantCount: 0, }, @@ -120,9 +120,9 @@ func TestWithExternalConnectInterceptorFactories(t *testing.T) { tt.apply(&cfg) if tt.wantCount == 0 { - assert.Nil(t, cfg.externalConnectFactories) + assert.Nil(t, cfg.externalInterceptorFactories) } else { - require.Len(t, cfg.externalConnectFactories, tt.wantCount) + require.Len(t, cfg.externalInterceptorFactories, tt.wantCount) } assert.Nil(t, cfg.extraConnectInterceptors) assert.Nil(t, cfg.extraIPCInterceptors) diff --git a/service/pkg/server/start.go b/service/pkg/server/start.go index 8029a5250e..c481b34dc2 100644 --- a/service/pkg/server/start.go +++ b/service/pkg/server/start.go @@ -282,10 +282,11 @@ func Start(f ...StartOptions) error { defer client.Close() - if len(startConfig.externalConnectFactories) > 0 { - for _, factory := range startConfig.externalConnectFactories { - interceptor, err := factory(ExternalConnectInterceptorContext{ - SDK: client, + if len(startConfig.externalInterceptorFactories) > 0 { + for _, factory := range startConfig.externalInterceptorFactories { + interceptor, err := factory(InterceptorParams{ + SDK: client, + Logger: logger, }) if err != nil { return fmt.Errorf("failed to create external connect interceptor: %w", err) From 3388065d78f6c8cda30e60ed61d80c6e291300c2 Mon Sep 17 00:00:00 2001 From: jakedoublev Date: Fri, 15 May 2026 12:08:00 -0700 Subject: [PATCH 3/3] style(core): fix gofmt field alignment --- service/pkg/server/options.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/service/pkg/server/options.go b/service/pkg/server/options.go index 165d2b39b6..14440a15b6 100644 --- a/service/pkg/server/options.go +++ b/service/pkg/server/options.go @@ -35,8 +35,8 @@ type StartConfig struct { configLoaders []config.Loader configLoaderOrder []string - extraConnectInterceptors []connect.Interceptor - extraIPCInterceptors []connect.Interceptor + extraConnectInterceptors []connect.Interceptor + extraIPCInterceptors []connect.Interceptor externalInterceptorFactories []InterceptorFactory trustKeyManagerCtxs []trust.NamedKeyManagerCtxFactory