diff --git a/management/cmd/management.go b/management/cmd/management.go index a8f9aa321..8723d309e 100644 --- a/management/cmd/management.go +++ b/management/cmd/management.go @@ -214,17 +214,27 @@ func LoadMgmtConfig(ctx context.Context, mgmtConfigPath string) (*nbconfig.Confi // ApplyCommandLineOverrides applies command-line flag overrides to the config func ApplyCommandLineOverrides(cfg *nbconfig.Config) { if mgmtLetsencryptDomain != "" { - cfg.HttpConfig.LetsEncryptDomain = mgmtLetsencryptDomain + ensureHttpConfig(cfg).LetsEncryptDomain = mgmtLetsencryptDomain } if mgmtDataDir != "" { cfg.Datadir = mgmtDataDir } if certKey != "" && certFile != "" { - cfg.HttpConfig.CertFile = certFile - cfg.HttpConfig.CertKey = certKey + httpConfig := ensureHttpConfig(cfg) + httpConfig.CertFile = certFile + httpConfig.CertKey = certKey } } +// ensureHttpConfig creates the HttpConfig section only when a flag writes to +// it, since the embedded IdP warns about any HttpConfig it finds. +func ensureHttpConfig(cfg *nbconfig.Config) *nbconfig.HttpServerConfig { + if cfg.HttpConfig == nil { + cfg.HttpConfig = &nbconfig.HttpServerConfig{} + } + return cfg.HttpConfig +} + // ApplyEmbeddedIdPConfig populates HttpConfig and EmbeddedIdP storage from config when embedded IdP is enabled. // This allows users to only specify EmbeddedIdP config without duplicating values in HttpConfig. func ApplyEmbeddedIdPConfig(ctx context.Context, cfg *nbconfig.Config) error { diff --git a/management/cmd/management_test.go b/management/cmd/management_test.go index e34e1975e..bf386e4ba 100644 --- a/management/cmd/management_test.go +++ b/management/cmd/management_test.go @@ -80,6 +80,55 @@ func TestApplyEmbeddedIdPConfigRequiresSingleAccountDomain(t *testing.T) { require.ErrorContains(t, ApplyEmbeddedIdPConfig(context.Background(), cfg), "embedded IdP requires single account mode") } +// A config without an HttpConfig section is valid with the embedded IdP, so the +// TLS flags must not assume the section exists. +func TestApplyCommandLineOverridesWithoutHttpConfig(t *testing.T) { + previousDomain, previousCertFile, previousCertKey := mgmtLetsencryptDomain, certFile, certKey + t.Cleanup(func() { + mgmtLetsencryptDomain, certFile, certKey = previousDomain, previousCertFile, previousCertKey + }) + + tests := []struct { + name string + domain string + certFile string + certKey string + want nbconfig.HttpServerConfig + }{ + { + name: "letsencrypt domain", + domain: "mgmt.example.com", + want: nbconfig.HttpServerConfig{LetsEncryptDomain: "mgmt.example.com"}, + }, + { + name: "certificate files", + certFile: "/etc/netbird/tls/tls.crt", + certKey: "/etc/netbird/tls/tls.key", + want: nbconfig.HttpServerConfig{CertFile: "/etc/netbird/tls/tls.crt", CertKey: "/etc/netbird/tls/tls.key"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + mgmtLetsencryptDomain, certFile, certKey = tt.domain, tt.certFile, tt.certKey + cfg := &nbconfig.Config{} + + ApplyCommandLineOverrides(cfg) + + require.NotNil(t, cfg.HttpConfig, "HttpConfig should be created for the TLS flags") + assert.Equal(t, tt.want, *cfg.HttpConfig, "HttpConfig should carry only the flag values") + }) + } + + t.Run("no TLS flags", func(t *testing.T) { + mgmtLetsencryptDomain, certFile, certKey = "", "", "" + cfg := &nbconfig.Config{} + + ApplyCommandLineOverrides(cfg) + + assert.Nil(t, cfg.HttpConfig, "HttpConfig should stay unset so the embedded IdP does not warn about it") + }) +} + func createConfig(config string) (string, error) { tmpfile, err := os.CreateTemp("", "config.json") if err != nil {