diff --git a/server/config/manager_v2.go b/server/config/manager_v2.go index 411c609..188708a 100644 --- a/server/config/manager_v2.go +++ b/server/config/manager_v2.go @@ -207,9 +207,15 @@ func (m *ConfigManager) Load(ctx context.Context) error { if err != nil { return err } + if err := contextError(ctx); err != nil { + return err + } if err := ValidateRuntimeSecrets(m.vault, runtime); err != nil { return err } + if err := contextError(ctx); err != nil { + return err + } if err := m.snapshots.Publish(runtime); err != nil { return err } diff --git a/server/config/manager_v2_test.go b/server/config/manager_v2_test.go index 4912314..88064bc 100644 --- a/server/config/manager_v2_test.go +++ b/server/config/manager_v2_test.go @@ -52,6 +52,45 @@ func validMySQLRuntimeConfig(t *testing.T, root string) RuntimeConfig { } return runtime } + +type cancelAfterFirstContext struct { + done chan struct{} + calls int +} + +func newCancelAfterFirstContext() *cancelAfterFirstContext { + return &cancelAfterFirstContext{done: make(chan struct{})} +} + +func (c *cancelAfterFirstContext) Deadline() (time.Time, bool) { + return time.Time{}, false +} + +func (c *cancelAfterFirstContext) Done() <-chan struct{} { + c.calls++ + if c.calls > 1 { + select { + case <-c.done: + default: + close(c.done) + } + } + return c.done +} + +func (c *cancelAfterFirstContext) Err() error { + select { + case <-c.done: + return context.Canceled + default: + return nil + } +} + +func (c *cancelAfterFirstContext) Value(any) any { + return nil +} + func authorizedConfigActor() AuditActor { return AuditActor{UserID: "1", Role: "super_admin", SessionID: "test-session", RecentAuth: true, RecoveryCodeConfigured: true} } @@ -188,6 +227,26 @@ func TestConfigManagerLoadRejectsUnavailableRuntimeSecretsWithoutChangingSnapsho } } +func TestConfigManagerLoadHonorsCancellationAfterReadingConfiguration(t *testing.T) { + root := t.TempDir() + options := ConfigLoaderOptions{Validation: RuntimeValidationOptions{HasSuperAdmin: true, Production: true}} + writeRuntimeFixture(t, root, validRuntimeConfig()) + manager, err := NewConfigManager(root, options) + if err != nil { + t.Fatal(err) + } + current := manager.Snapshot() + ctx := newCancelAfterFirstContext() + + if err := manager.Load(ctx); !errors.Is(err, context.Canceled) { + t.Fatalf("load error = %v, want context canceled", err) + } + loaded := manager.Snapshot() + if loaded.Generation != current.Generation { + t.Fatalf("canceled load changed active generation: got %d, want %d", loaded.Generation, current.Generation) + } +} + func TestConfigManagerApplyPreflightsSnapshotBeforePersisting(t *testing.T) { root := t.TempDir() writeRuntimeFixture(t, root, validRuntimeConfig())