Skip to content

[management] pass config to controller#4807

Merged
pascal-fischer merged 7 commits intomainfrom
fix/pass-config-to-nmap-controller
Nov 19, 2025
Merged

[management] pass config to controller#4807
pascal-fischer merged 7 commits intomainfrom
fix/pass-config-to-nmap-controller

Conversation

@pascal-fischer
Copy link
Copy Markdown
Collaborator

@pascal-fischer pascal-fischer commented Nov 18, 2025

Describe your changes

Issue ticket number and link

Stack

Checklist

  • Is it a bug fix
  • Is a typo/documentation fix
  • Is a feature enhancement
  • It is a refactor
  • Created tests that fail without the change (if possible)

By submitting this pull request, you confirm that you have read and agree to the terms of the Contributor License Agreement.

Documentation

Select exactly one:

  • I added/updated documentation for this change
  • Documentation is not needed for this change (explain why)

Docs PR URL (required if "docs added" is checked)

Paste the PR link from https://github.com/netbirdio/docs here:

https://github.com/netbirdio/docs/pull/__

Summary by CodeRabbit

  • Refactor
    • Sync behavior now sources HTTP and device-authorization settings from the central server configuration.
    • Sync payloads and peer updates include HTTP and device-authorization parameters so devices receive auth/HTTP data from server config.
    • Controller initialization now injects global configuration into update flows, making sync responses config-driven.
    • NetbirdConfig no longer exposes an embedded JWT config in sync payloads.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Nov 18, 2025

Walkthrough

Controller constructor now accepts and stores a *config.Config; that config is propagated into sync-response generation. gRPC conversion functions (toPeerConfig, ToSyncResponse, buildJWTConfig) signatures were expanded to accept HttpServerConfig and DeviceAuthorizationFlow; NetbirdConfig lost its jwt field.

Changes

Cohort / File(s) Summary
Controller implementation
management/internals/controllers/network_map/controller/controller.go
Added config *config.Config field to Controller; extended NewController(...) to accept config *config.Config; use c.config.HttpConfig and c.config.DeviceAuthorizationFlow when calling ToSyncResponse.
gRPC conversion & server-side sync
management/internals/shared/grpc/conversion.go, management/internals/shared/grpc/server.go
Expanded toPeerConfig, ToSyncResponse, and buildJWTConfig signatures to accept HttpServerConfig and DeviceAuthorizationFlow; updated JWT issuer/audience/keys derivation and propagated new args through call sites.
Proto changes
shared/management/proto/management.proto
Removed jwt (JWTConfig) field from NetbirdConfig message (field number 6).
Server call sites & start paths
management/internals/server/controllers.go, management/server/..., client/..., shared/management/client/client_test.go
Updated NewController(...) invocations to pass s.config or &config.Config{} as the new final parameter across server and client start/test paths.
Tests & test utilities
management/server/*_test.go, management/server/http/testing/testing_tools/channel/channel.go, client/cmd/testutil_test.go, client/internal/engine_test.go, client/server/server_test.go, management/server/peer_test.go, ...
Added imports for server config where needed and updated controller.NewController(...) calls to include a *config.Config argument; adjusted one test expectation related to NetbirdConfig presence.
Minor lint change
client/internal/engine.go
Added a nolint directive in toDNSConfig (no functional change).

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant Caller as startManagement / Tests
    participant Server as Management Server
    participant NMapCtor as network_map.NewController
    participant Controller as NetworkMap Controller
    participant GRPC as grpc.ToSyncResponse

    Caller->>Server: startManagement(...)
    Server->>NMapCtor: NewController(..., portForwardCtrl, config)
    NMapCtor-->>Controller: returns Controller{..., config: cfg}
    Controller->>GRPC: ToSyncResponse(ctx, cfg.HttpConfig, cfg.DeviceAuthorizationFlow, ...peer...)
    GRPC-->>Controller: SyncResponse (includes HTTP/JWT settings)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Inspect public API changes for breaking compatibility (controller.NewController, grpc.ToSyncResponse/toPeerConfig/buildJWTConfig).
  • Verify JWT config derivation and issuer fallback (HttpServerConfig.AuthIssuer vs device flow token endpoint).
  • Confirm all call sites updated (no missing nils) and tests adjusted for NetbirdConfig jwt removal.

Possibly related PRs

Suggested reviewers

  • crn4
  • mlsmaycon

Poem

🐰 I hopped through code with whiskers keen,
Sewed a config ribbon in the controller seam,
Syncs now carry HTTP and auth flow bright,
JWTs find their issuer in the twilight,
I nibble a carrot and twirl in pure delight.

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is largely incomplete with all key sections left empty: no details on what changed, no issue ticket linked, and no explanation of the bug fix despite being marked as one. Fill in the 'Describe your changes' section with details about passing config to the controller and why it's needed; add the issue ticket number and link; optionally provide an explanation for marking it as a bug fix.
Docstring Coverage ⚠️ Warning Docstring coverage is 13.04% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: passing configuration to the network map controller.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/pass-config-to-nmap-controller

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
management/internals/controllers/network_map/controller/controller.go (2)

51-51: Consider adding a documentation comment.

The config field stores the global configuration for sync response generation but lacks a comment explaining its purpose.

Apply this diff to add documentation:

 	// dnsDomain is used for peer resolution. This is appended to the peer's name
 	dnsDomain string
+	// config holds the global server configuration used in sync response generation
 	config    *config.Config

73-73: Validate that config is not nil.

The constructor accepts a config parameter but doesn't validate it's non-nil. If nil is passed, ToSyncResponse calls will receive nil for config, potentially reverting to the original bug.

Apply this diff to add validation:

 func NewController(ctx context.Context, store store.Store, metrics telemetry.AppMetrics, peersUpdateManager network_map.PeersUpdateManager, requestBuffer account.RequestBuffer, integratedPeerValidator integrated_validator.IntegratedValidator, settingsManager settings.Manager, dnsDomain string, proxyController port_forwarding.Controller, config *config.Config) *Controller {
+	if config == nil {
+		log.Fatal("config cannot be nil")
+	}
 	nMetrics, err := newMetrics(metrics.UpdateChannelMetrics())
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 05cbead and ca369e9.

📒 Files selected for processing (2)
  • management/internals/controllers/network_map/controller/controller.go (6 hunks)
  • management/internals/server/controllers.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
management/internals/controllers/network_map/controller/controller.go (1)
management/internals/shared/grpc/conversion.go (1)
  • ToSyncResponse (107-150)
management/internals/server/controllers.go (4)
management/internals/controllers/network_map/controller/controller.go (1)
  • NewController (73-108)
management/internals/controllers/network_map/update_channel.go (1)
  • PeersUpdateManager (5-13)
management/server/account_request_buffer.go (1)
  • AccountRequestBuffer (27-33)
management/server/integrations/integrated_validator/interface.go (1)
  • IntegratedValidator (12-23)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (22)
  • GitHub Check: Relay / Unit (386)
  • GitHub Check: Client / Unit (amd64)
  • GitHub Check: Client / Unit (386)
  • GitHub Check: Relay / Unit (amd64, -race)
  • GitHub Check: Management / Unit (amd64, mysql)
  • GitHub Check: Management / Unit (amd64, sqlite)
  • GitHub Check: Management / Benchmark (amd64, sqlite)
  • GitHub Check: Management / Unit (amd64, postgres)
  • GitHub Check: Management / Benchmark (amd64, postgres)
  • GitHub Check: Client (Docker) / Unit
  • GitHub Check: Linux
  • GitHub Check: Darwin
  • GitHub Check: Windows
  • GitHub Check: Client / Unit
  • GitHub Check: JS / Lint
  • GitHub Check: Client / Unit
  • GitHub Check: Android / Build
  • GitHub Check: iOS / Build
  • GitHub Check: Client / Unit
  • GitHub Check: release_ui_darwin
  • GitHub Check: release
  • GitHub Check: release_ui
🔇 Additional comments (4)
management/internals/controllers/network_map/controller/controller.go (3)

22-22: LGTM!

The import addition is necessary for the config dependency injection.


211-211: LGTM!

Correctly passes c.config to enable config-driven behavior in sync response generation. This fixes the bug where nil was previously passed.


329-329: All ToSyncResponse call sites correctly pass the config object.

Verification confirms all four call sites in the codebase pass a config object as the second parameter: management/server/peer_test.go:1180, management/internals/controllers/network_map/controller/controller.go:211, management/internals/controllers/network_map/controller/controller.go:329, and management/internals/shared/grpc/server.go:716. The change at line 329 is consistent with all other call sites.

management/internals/server/controllers.go (1)

73-73: LGTM! Verification confirms proper initialization.

BaseServer.config is correctly initialized in the NewServer constructor at management/internals/server/server.go:71-73, where the passed config parameter is directly assigned to the struct field. The code change at line 73 is safe and correct.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (6)
management/server/dns_test.go (1)

15-15: Config wiring for DNS tests looks correct

Importing the config package and passing &config.Config{} into NewController is consistent with the updated constructor and should be sufficient for these DNS‑focused tests. If you ever start asserting on NetbirdConfig fields in update messages here, consider reusing a more realistic config (e.g., from testdata) and passing the same instance both to NewController and BuildManager instead of nil.

Also applies to: 226-226

management/server/account_test.go (1)

28-28: NewController usage is correct; consider aligning config with BuildManager

Using &config.Config{} here satisfies the updated NewController signature and should work for these account tests, which don’t inspect NetbirdConfig details. If you later need config‑dependent behavior (e.g., STUN/TURN fields) in update messages, it may be worth threading a single, realistically initialised config instance into both NewController and BuildManager instead of mixing a zero‑value struct with nil.

Also applies to: 2962-2962

management/server/nameserver_test.go (1)

16-16: Nameserver tests correctly updated for the new controller signature

Importing config and passing &config.Config{} into NewController is consistent with the new API and should be fine for these nameserver‑centric tests. As with the account tests, if you ever need to validate config‑dependent fields in sync responses here, consider sharing a single initialised config instance between NewController and BuildManager instead of using nil in the latter.

Also applies to: 795-795

management/server/peer_test.go (1)

1293-1293: Peer‑related tests correctly inject config into the controller

All updated NewController call sites now pass &config.Config{}, which is consistent with the new constructor and enough for these registration/login and rollback tests that only inspect peer/account state and network maps. If you later extend these tests to assert on config‑driven fields (e.g., TURN/Signal in NetbirdConfig), it would be worth threading a realistic config (or shared helper) into both NewController and BuildManager instead of mixing a zero‑value struct with nil.

Also applies to: 1378-1378, 1531-1531, 1611-1611

management/server/http/testing/testing_tools/channel/channel.go (1)

13-13: Controller constructor update in HTTP black‑box tests is consistent

Importing internals/server/config and passing &config.Config{} into controller.NewController correctly matches the updated constructor signature and keeps this helper self‑contained for its channel/update assertions. If future tests start asserting on Netbird config values, you can extend this config struct there without touching the wiring again.

Also applies to: 75-75

management/server/route_test.go (1)

19-19: Route test controller wiring updated to match new signature

Adding the config import and passing &config.Config{} into controller.NewController brings the route test helper in line with the new constructor API while keeping the setup minimal. Given these tests focus on routing behavior and peer updates, an empty config here is adequate and can be extended later if tests start depending on config‑driven fields.

Also applies to: 1294-1294

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ca369e9 and 008d1d0.

📒 Files selected for processing (12)
  • client/cmd/testutil_test.go (1 hunks)
  • client/internal/engine_test.go (1 hunks)
  • client/server/server_test.go (1 hunks)
  • management/server/account_test.go (2 hunks)
  • management/server/dns_test.go (2 hunks)
  • management/server/http/testing/testing_tools/channel/channel.go (2 hunks)
  • management/server/management_proto_test.go (1 hunks)
  • management/server/management_test.go (1 hunks)
  • management/server/nameserver_test.go (2 hunks)
  • management/server/peer_test.go (4 hunks)
  • management/server/route_test.go (2 hunks)
  • shared/management/client/client_test.go (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (12)
management/server/peer_test.go (4)
management/internals/controllers/network_map/controller/controller.go (1)
  • NewController (73-108)
management/server/integrated_validator.go (6)
  • MockIntegratedValidator (125-128)
  • MockIntegratedValidator (153-155)
  • MockIntegratedValidator (157-159)
  • MockIntegratedValidator (161-163)
  • MockIntegratedValidator (165-167)
  • MockIntegratedValidator (169-171)
management/server/integrations/port_forwarding/controller.go (1)
  • NewControllerMock (20-22)
management/internals/server/config/config.go (1)
  • Config (37-60)
management/server/management_proto_test.go (3)
management/internals/controllers/network_map/controller/controller.go (1)
  • NewController (73-108)
management/server/integrated_validator.go (6)
  • MockIntegratedValidator (125-128)
  • MockIntegratedValidator (153-155)
  • MockIntegratedValidator (157-159)
  • MockIntegratedValidator (161-163)
  • MockIntegratedValidator (165-167)
  • MockIntegratedValidator (169-171)
management/server/integrations/port_forwarding/controller.go (1)
  • NewControllerMock (20-22)
management/server/http/testing/testing_tools/channel/channel.go (2)
management/internals/controllers/network_map/controller/controller.go (1)
  • NewController (73-108)
management/server/integrations/port_forwarding/controller.go (1)
  • NewControllerMock (20-22)
management/server/nameserver_test.go (3)
management/internals/controllers/network_map/controller/controller.go (1)
  • NewController (73-108)
management/server/integrated_validator.go (6)
  • MockIntegratedValidator (125-128)
  • MockIntegratedValidator (153-155)
  • MockIntegratedValidator (157-159)
  • MockIntegratedValidator (161-163)
  • MockIntegratedValidator (165-167)
  • MockIntegratedValidator (169-171)
management/server/integrations/port_forwarding/controller.go (1)
  • NewControllerMock (20-22)
management/server/dns_test.go (1)
management/internals/controllers/network_map/controller/controller.go (1)
  • NewController (73-108)
management/server/account_test.go (2)
management/internals/controllers/network_map/controller/controller.go (1)
  • NewController (73-108)
management/server/integrations/port_forwarding/controller.go (1)
  • NewControllerMock (20-22)
client/internal/engine_test.go (3)
management/internals/controllers/network_map/controller/controller.go (1)
  • NewController (73-108)
management/server/integrated_validator.go (6)
  • MockIntegratedValidator (125-128)
  • MockIntegratedValidator (153-155)
  • MockIntegratedValidator (157-159)
  • MockIntegratedValidator (161-163)
  • MockIntegratedValidator (165-167)
  • MockIntegratedValidator (169-171)
management/server/integrations/port_forwarding/controller.go (1)
  • NewControllerMock (20-22)
shared/management/client/client_test.go (2)
management/internals/controllers/network_map/controller/controller.go (1)
  • NewController (73-108)
management/server/integrations/port_forwarding/controller.go (1)
  • NewControllerMock (20-22)
management/server/route_test.go (1)
management/internals/controllers/network_map/controller/controller.go (1)
  • NewController (73-108)
management/server/management_test.go (3)
management/internals/controllers/network_map/controller/controller.go (1)
  • NewController (73-108)
management/server/integrated_validator.go (6)
  • MockIntegratedValidator (125-128)
  • MockIntegratedValidator (153-155)
  • MockIntegratedValidator (157-159)
  • MockIntegratedValidator (161-163)
  • MockIntegratedValidator (165-167)
  • MockIntegratedValidator (169-171)
management/server/integrations/port_forwarding/controller.go (1)
  • NewControllerMock (20-22)
client/server/server_test.go (1)
management/internals/controllers/network_map/controller/controller.go (1)
  • NewController (73-108)
client/cmd/testutil_test.go (2)
management/internals/controllers/network_map/controller/controller.go (1)
  • NewController (73-108)
management/server/integrated_validator.go (6)
  • MockIntegratedValidator (125-128)
  • MockIntegratedValidator (153-155)
  • MockIntegratedValidator (157-159)
  • MockIntegratedValidator (161-163)
  • MockIntegratedValidator (165-167)
  • MockIntegratedValidator (169-171)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (23)
  • GitHub Check: Relay / Unit (386)
  • GitHub Check: Management / Unit (amd64, mysql)
  • GitHub Check: Management / Benchmark (API) (amd64, postgres)
  • GitHub Check: Management / Benchmark (API) (amd64, sqlite)
  • GitHub Check: Relay / Unit (amd64, -race)
  • GitHub Check: Management / Unit (amd64, postgres)
  • GitHub Check: Client / Unit (386)
  • GitHub Check: Client / Unit (amd64)
  • GitHub Check: Management / Unit (amd64, sqlite)
  • GitHub Check: Management / Integration (amd64, postgres)
  • GitHub Check: Management / Benchmark (amd64, postgres)
  • GitHub Check: Management / Benchmark (amd64, sqlite)
  • GitHub Check: Client (Docker) / Unit
  • GitHub Check: Windows
  • GitHub Check: Linux
  • GitHub Check: Darwin
  • GitHub Check: Client / Unit
  • GitHub Check: release_ui_darwin
  • GitHub Check: JS / Lint
  • GitHub Check: Client / Unit
  • GitHub Check: release
  • GitHub Check: Android / Build
  • GitHub Check: Client / Unit
🔇 Additional comments (6)
shared/management/client/client_test.go (1)

28-28: Controller now uses the same parsed config as the rest of the stack

Passing the JSON‑loaded config into NewController (and already into BuildManager/gRPC server wiring) keeps the management and network‑map paths consistent and gives ToSyncResponse full access to the real server configuration. Looks good.

Also applies to: 120-121

client/cmd/testutil_test.go (1)

22-22: Test utility now passes the real management config into NewController

Using the JSON‑loaded config for both BuildManager and controller.NewController keeps the test wiring aligned with production and ensures ToSyncResponse can rely on the same configuration used elsewhere. No issues spotted.

Also applies to: 119-119

management/server/management_proto_test.go (1)

366-366: Wiring controller with test config looks correct

Passing config into controller.NewController aligns the controller with the same *config.Config used for the rest of the test server stack, which is important for consistent SyncResponse content. This change looks correct and self‑contained here.

management/server/management_test.go (1)

208-208: Consistent config injection into network map controller

Both startServer and startManagement now pass the same *config.Config instance into controller.NewController that is used to configure the management server itself. This keeps controller behavior aligned with the server config and matches the new constructor contract.

Also applies to: 1627-1627

client/internal/engine_test.go (1)

1627-1627: startManagement helper correctly forwards config to controller

controller.NewController now receives the populated config used to start the test management server, which is consistent with the updated API and ensures the controller has access to the full management configuration during engine tests.

client/server/server_test.go (1)

319-319: Management test harness now passes config into controller

The startManagement helper’s networkMapController now receives the same *config.Config used elsewhere in the test server setup, which properly satisfies the extended NewController signature and keeps configuration consistent.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (3)
management/server/peer_test.go (3)

1374-1380: Same config wiring pattern as earlier controller construction

This is the same NewController call pattern as in Test_RegisterPeerByUser; see that comment for details.


1527-1533: Repeated controller config pattern

This matches the earlier NewController usage with &config.Config{}; refer to the first comment for rationale and optional refactor suggestion.


1607-1613: Repeated controller config pattern

Same change as the other controller constructions in this file; see the initial comment around line 1292.

🧹 Nitpick comments (1)
management/server/peer_test.go (1)

1289-1295: Config injection into controller looks correct; consider centralizing test config

Passing a non-nil &config.Config{} into controller.NewController matches the new constructor signature and should prevent nil‑config paths. If more tests start depending on specific config fields, consider extracting a small helper (e.g. newTestConfig() *config.Config) so you can reuse and evolve a realistic test config in one place.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 008d1d0 and 551b10d.

📒 Files selected for processing (1)
  • management/server/peer_test.go (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
management/server/peer_test.go (2)
management/internals/controllers/network_map/controller/controller.go (1)
  • NewController (73-108)
management/internals/server/config/config.go (1)
  • Config (37-60)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (26)
  • GitHub Check: Management / Integration (amd64, sqlite)
  • GitHub Check: Management / Integration (amd64, postgres)
  • GitHub Check: Management / Benchmark (API) (amd64, postgres)
  • GitHub Check: Management / Benchmark (API) (amd64, sqlite)
  • GitHub Check: Management / Unit (amd64, mysql)
  • GitHub Check: Management / Unit (amd64, postgres)
  • GitHub Check: Management / Unit (amd64, sqlite)
  • GitHub Check: Management / Benchmark (amd64, sqlite)
  • GitHub Check: Management / Benchmark (amd64, postgres)
  • GitHub Check: Relay / Unit (386)
  • GitHub Check: Client / Unit (386)
  • GitHub Check: Signal / Unit (386)
  • GitHub Check: Relay / Unit (amd64, -race)
  • GitHub Check: Client (Docker) / Unit
  • GitHub Check: Client / Unit (amd64)
  • GitHub Check: Client / Unit
  • GitHub Check: Client / Unit
  • GitHub Check: Linux
  • GitHub Check: Darwin
  • GitHub Check: Windows
  • GitHub Check: Android / Build
  • GitHub Check: iOS / Build
  • GitHub Check: release
  • GitHub Check: JS / Lint
  • GitHub Check: release_ui_darwin
  • GitHub Check: Client / Unit

lixmal
lixmal previously approved these changes Nov 18, 2025
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
management/internals/shared/grpc/server.go (1)

640-654: Update prepareLoginResponse to match new toPeerConfig signature

toPeerConfig now expects (*nbconfig.HttpServerConfig, *nbconfig.DeviceAuthorizationFlow), but prepareLoginResponse still passes s.config as the last argument. In Go, this will not compile once the package is rebuilt.

Update the call to pass the HTTP and device-flow sub-config:

-	loginResp := &proto.LoginResponse{
-		NetbirdConfig: toNetbirdConfig(s.config, nil, relayToken, nil),
-		PeerConfig:    toPeerConfig(peer, netMap.Network, s.networkMapController.GetDNSDomain(settings), settings, s.config),
-		Checks:        toProtocolChecks(ctx, postureChecks),
-	}
+	loginResp := &proto.LoginResponse{
+		NetbirdConfig: toNetbirdConfig(s.config, nil, relayToken, nil),
+		PeerConfig:    toPeerConfig(
+			peer,
+			netMap.Network,
+			s.networkMapController.GetDNSDomain(settings),
+			settings,
+			s.config.HttpConfig,
+			s.config.DeviceAuthorizationFlow,
+		),
+		Checks: toProtocolChecks(ctx, postureChecks),
+	}
management/internals/controllers/network_map/controller/controller.go (1)

171-216: Fix closure bug when merging proxy network maps in sendUpdateAccountPeers

Inside the goroutine you call proxyNetworkMaps[peer.ID], but peer is the loop variable from the outer for and is captured by reference. This creates a classic closure bug: when goroutines run, peer may already have advanced to another element, so you can read the wrong proxy map for a given p.

Use the function argument p instead:

-			proxyNetworkMap, ok := proxyNetworkMaps[peer.ID]
+			proxyNetworkMap, ok := proxyNetworkMaps[p.ID]
 			if ok {
 				remotePeerNetworkMap.Merge(proxyNetworkMap)
 			}

This aligns the map lookup with the peer actually being processed by the goroutine and removes the data race on the loop variable.

🧹 Nitpick comments (4)
management/server/peer_test.go (2)

1168-1185: TestToSyncResponse wiring matches new API; consider extending coverage

The grpc.ToSyncResponse invocation is correctly updated to pass config, config.HttpConfig, and config.DeviceAuthorizationFlow per the new signature. Since both HttpConfig and DeviceAuthorizationFlow are nil in this test, the new JWT-related behavior isn’t exercised; if you want regression coverage for SSH/JWT config derived from these fields, a dedicated test setting them would be useful.


1288-1295: NewController calls are consistent; optional: factor out a small helper

All updated controller.NewController call sites now pass a *config.Config (&config.Config{}), which matches the new constructor signature and prevents c.config from being nil in tests.

If this pattern grows further, consider a small helper like newTestNetworkMapController(...) that encapsulates repeated wiring (store, metrics, updateManager, requestBuffer, settingsMockManager, proxy controller, config) to reduce duplication and keep tests focused on behavior.

Also applies to: 1373-1380, 1526-1533, 1606-1613

management/internals/controllers/network_map/controller/controller.go (2)

38-63: Controller now holds server config; consider enforcing non-nil or guarding accesses

Adding config *config.Config to Controller and threading it via NewController(...) looks fine and keeps configuration centralized.

However, both sendUpdateAccountPeers and UpdateAccountPeer later dereference c.config (via c.config.HttpConfig / .DeviceAuthorizationFlow) without a nil check. If any call site ever passes a nil config, those paths will panic.

Two options:

  • Treat config as required: document it and panic early in NewController if config == nil.
  • Or make it optional: compute local httpCfg / deviceFlowCfg with a nil guard before calling ToSyncResponse.

Example of the latter:

-func NewController(..., config *config.Config) *Controller {
+func NewController(..., config *config.Config) *Controller {
+	if config == nil {
+		config = &config.Config{}
+	}
 	return &Controller{
 		// ...
-		config:                  config,
+		config:                  config,
 	}
}

Also applies to: 73-108


207-213: ToSyncResponse calls correctly pass HTTP and device-flow config, but rely on c.config being non-nil

Both sendUpdateAccountPeers and UpdateAccountPeer now call:

grpc.ToSyncResponse(ctx, nil, c.config.HttpConfig, c.config.DeviceAuthorizationFlow, ...)

This matches the new signature and lets sync responses pick up HTTP/device-flow settings, while still omitting the full *config.Config (first arg) as before.

Once c.config is guaranteed non-nil (see previous comment), these calls look good. If you decide to allow config to be optional, ensure you guard c.config before dereferencing.

Also applies to: 327-331

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 551b10d and 9956202.

📒 Files selected for processing (4)
  • management/internals/controllers/network_map/controller/controller.go (6 hunks)
  • management/internals/shared/grpc/conversion.go (4 hunks)
  • management/internals/shared/grpc/server.go (1 hunks)
  • management/server/peer_test.go (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (4)
management/internals/controllers/network_map/controller/controller.go (1)
management/internals/shared/grpc/conversion.go (1)
  • ToSyncResponse (107-150)
management/internals/shared/grpc/server.go (1)
management/internals/shared/grpc/conversion.go (1)
  • ToSyncResponse (107-150)
management/server/peer_test.go (2)
management/internals/shared/grpc/conversion.go (1)
  • ToSyncResponse (107-150)
management/internals/controllers/network_map/controller/controller.go (1)
  • NewController (73-108)
management/internals/shared/grpc/conversion.go (1)
management/internals/server/config/config.go (1)
  • HttpServerConfig (93-113)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (22)
  • GitHub Check: Management / Unit (amd64, mysql)
  • GitHub Check: Relay / Unit (386)
  • GitHub Check: Management / Unit (amd64, sqlite)
  • GitHub Check: Management / Unit (amd64, postgres)
  • GitHub Check: Relay / Unit (amd64, -race)
  • GitHub Check: Client / Unit (amd64)
  • GitHub Check: Client / Unit (386)
  • GitHub Check: Management / Benchmark (amd64, sqlite)
  • GitHub Check: Management / Benchmark (amd64, postgres)
  • GitHub Check: Signal / Unit (amd64)
  • GitHub Check: Client (Docker) / Unit
  • GitHub Check: JS / Lint
  • GitHub Check: Client / Unit
  • GitHub Check: release_ui_darwin
  • GitHub Check: iOS / Build
  • GitHub Check: release
  • GitHub Check: Client / Unit
  • GitHub Check: Android / Build
  • GitHub Check: Client / Unit
  • GitHub Check: Linux
  • GitHub Check: Windows
  • GitHub Check: Darwin
🔇 Additional comments (2)
management/internals/shared/grpc/server.go (1)

686-736: sendInitialSync: config propagation into ToSyncResponse looks correct

Passing s.config, s.config.HttpConfig, and s.config.DeviceAuthorizationFlow into ToSyncResponse matches the new signature and ensures sync responses see the full server config. No issues here.

management/internals/shared/grpc/conversion.go (1)

86-105: toPeerConfig/ToSyncResponse wiring for HTTP & device-flow config looks consistent

The extended signatures:

  • toPeerConfig(..., httpConfig *nbconfig.HttpServerConfig, deviceFlowConfig *nbconfig.DeviceAuthorizationFlow)
  • ToSyncResponse(..., config *nbconfig.Config, httpConfig *nbconfig.HttpServerConfig, deviceFlowConfig *nbconfig.DeviceAuthorizationFlow, ...)

and the call:

PeerConfig: toPeerConfig(peer, networkMap.Network, dnsName, settings, httpConfig, deviceFlowConfig),

are consistent with the design of deriving SSH JWT config from HTTP server and device authorization flow settings. No structural issues here; behavior will depend on buildJWTConfig, see next comment.

Also applies to: 107-120

Comment on lines 365 to 389
// buildJWTConfig constructs JWT configuration for SSH servers from management server config
func buildJWTConfig(config *nbconfig.Config) *proto.JWTConfig {
if config == nil {
return nil
}

if config.HttpConfig == nil || config.HttpConfig.AuthAudience == "" {
func buildJWTConfig(config *nbconfig.HttpServerConfig, deviceFlowConfig *nbconfig.DeviceAuthorizationFlow) *proto.JWTConfig {
if config == nil || config.AuthAudience == "" {
return nil
}

issuer := strings.TrimSpace(config.HttpConfig.AuthIssuer)
if issuer == "" {
if config.DeviceAuthorizationFlow != nil {
if d := deriveIssuerFromTokenEndpoint(config.DeviceAuthorizationFlow.ProviderConfig.TokenEndpoint); d != "" {
issuer = d
}
issuer := strings.TrimSpace(config.AuthIssuer)
if issuer == "" || deviceFlowConfig != nil {
if d := deriveIssuerFromTokenEndpoint(deviceFlowConfig.ProviderConfig.TokenEndpoint); d != "" {
issuer = d
}
}
if issuer == "" {
return nil
}

keysLocation := strings.TrimSpace(config.HttpConfig.AuthKeysLocation)
keysLocation := strings.TrimSpace(config.AuthKeysLocation)
if keysLocation == "" {
keysLocation = strings.TrimSuffix(issuer, "/") + "/.well-known/jwks.json"
}

return &proto.JWTConfig{
Issuer: issuer,
Audience: config.HttpConfig.AuthAudience,
Audience: config.AuthAudience,
KeysLocation: keysLocation,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

❓ Verification inconclusive

Fix nil-pointer and issuer precedence in buildJWTConfig

buildJWTConfig currently has:

func buildJWTConfig(config *nbconfig.HttpServerConfig, deviceFlowConfig *nbconfig.DeviceAuthorizationFlow) *proto.JWTConfig {
	if config == nil || config.AuthAudience == "" {
		return nil
	}

	issuer := strings.TrimSpace(config.AuthIssuer)
	if issuer == "" || deviceFlowConfig != nil {
		if d := deriveIssuerFromTokenEndpoint(deviceFlowConfig.ProviderConfig.TokenEndpoint); d != "" {
			issuer = d
		}
	}
	// ...
}

Issues:

  1. Nil-pointer risk:
    If config.AuthIssuer == "" and deviceFlowConfig == nil (common when device auth flow isn’t configured), the if issuer == "" || deviceFlowConfig != nil condition is true and deviceFlowConfig.ProviderConfig... dereferences a nil pointer.

  2. Surprising precedence:
    As written, any non-nil deviceFlowConfig will overwrite a non-empty AuthIssuer. That’s a significant behavior change versus “use AuthIssuer if provided, otherwise fall back to token endpoint”.

A safer implementation is:

 func buildJWTConfig(config *nbconfig.HttpServerConfig, deviceFlowConfig *nbconfig.DeviceAuthorizationFlow) *proto.JWTConfig {
 	if config == nil || config.AuthAudience == "" {
 		return nil
 	}
 
-	issuer := strings.TrimSpace(config.AuthIssuer)
-	if issuer == "" || deviceFlowConfig != nil {
-		if d := deriveIssuerFromTokenEndpoint(deviceFlowConfig.ProviderConfig.TokenEndpoint); d != "" {
-			issuer = d
-		}
-	}
+	issuer := strings.TrimSpace(config.AuthIssuer)
+	// Only fall back to device flow token endpoint if issuer is not explicitly set
+	if issuer == "" && deviceFlowConfig != nil {
+		if d := deriveIssuerFromTokenEndpoint(deviceFlowConfig.ProviderConfig.TokenEndpoint); d != "" {
+			issuer = d
+		}
+	}
 	if issuer == "" {
 		return nil
 	}
 
 	keysLocation := strings.TrimSpace(config.AuthKeysLocation)
 	if keysLocation == "" {
 		keysLocation = strings.TrimSuffix(issuer, "/") + "/.well-known/jwks.json"
 	}
 
 	return &proto.JWTConfig{
 		Issuer:       issuer,
-		Audience:     config.AuthAudience,
+		Audience:     config.AuthAudience,
 		KeysLocation: keysLocation,
 	}
 }

This:

  • Eliminates the nil dereference when deviceFlowConfig is nil.
  • Treats AuthIssuer as authoritative when set, falling back to a derived issuer only when it’s empty.

Please double-check that this precedence (explicit issuer > derived-from-device-flow) matches your intended behavior.


I'll verify the review comment by examining the actual code and its context.

Now let me examine the actual code in the repository.

#!/bin/bash
# Find and display the buildJWTConfig function
rg -n -A 30 "func buildJWTConfig" --type=go

[/run_scripts]


Fix nil-pointer dereference and issuer precedence in buildJWTConfig

The analysis in the original review comment is correct. The current condition if issuer == "" || deviceFlowConfig != nil has two critical issues:

  1. Nil-pointer dereference: When issuer == "" and deviceFlowConfig == nil, the OR condition is true (first part is satisfied), causing the code to dereference deviceFlowConfig.ProviderConfig.TokenEndpoint on a nil pointer, resulting in a runtime panic.

  2. Incorrect precedence: The OR condition allows deviceFlowConfig to override a non-empty AuthIssuer, which is likely unintended behavior.

The proposed fix to change the condition to if issuer == "" && deviceFlowConfig != nil is correct. This ensures:

  • The dereferencing only occurs when deviceFlowConfig is not nil
  • AuthIssuer is treated as authoritative and only falls back to the device flow token endpoint when explicitly empty

Apply the suggested fix as written.

🤖 Prompt for AI Agents
In management/internals/shared/grpc/conversion.go around lines 365 to 389,
change the conditional that attempts to derive the issuer so it does not
dereference deviceFlowConfig when nil and so AuthIssuer takes precedence:
replace the current OR condition with a check that only attempts to derive from
deviceFlowConfig when issuer is empty AND deviceFlowConfig is non-nil (i.e., use
issuer == "" && deviceFlowConfig != nil), leaving the rest of the logic
unchanged so the token endpoint is only used as a fallback.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
management/internals/shared/grpc/server.go (2)

646-651: Ensure toPeerConfig does not leak sensitive DeviceAuthorizationFlow/HTTP config

Threading s.config.HttpConfig and s.config.DeviceAuthorizationFlow into toPeerConfig makes sense for giving clients richer configuration, but it also means whatever toPeerConfig serializes is now client-visible. Please double‑check that it only exposes safe fields (e.g., URLs, non‑secret identifiers) and not things like OAuth client secrets or internal‑only values. If needed, consider introducing a sanitized DTO type that is derived from DeviceAuthorizationFlow/HttpConfig before passing it down.


716-716: Config propagation to ToSyncResponse looks correct; verify nil‑safety and validation

The updated ToSyncResponse call wires (s.config, s.config.HttpConfig, s.config.DeviceAuthorizationFlow, …) in the expected order and matches the new signature. One thing to verify is that s.config, s.config.HttpConfig, and s.config.DeviceAuthorizationFlow are either always non‑nil on a running server or are explicitly handled as nil in ToSyncResponse/toPeerConfig (and any downstream config consumers), to avoid panics on misconfiguration. You might also want a startup‑time validation hook on nbconfig.Config to fail fast if required sub‑configs are missing.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9956202 and f457278.

📒 Files selected for processing (1)
  • management/internals/shared/grpc/server.go (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
management/internals/shared/grpc/server.go (1)
management/internals/shared/grpc/conversion.go (1)
  • ToSyncResponse (107-150)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (27)
  • GitHub Check: Client / Unit (386)
  • GitHub Check: Management / Unit (amd64, mysql)
  • GitHub Check: Management / Benchmark (API) (amd64, postgres)
  • GitHub Check: Management / Unit (amd64, postgres)
  • GitHub Check: Management / Benchmark (API) (amd64, sqlite)
  • GitHub Check: Management / Benchmark (amd64, sqlite)
  • GitHub Check: Management / Unit (amd64, sqlite)
  • GitHub Check: Management / Benchmark (amd64, postgres)
  • GitHub Check: Relay / Unit (amd64, -race)
  • GitHub Check: Signal / Unit (386)
  • GitHub Check: Management / Integration (amd64, sqlite)
  • GitHub Check: Relay / Unit (386)
  • GitHub Check: Signal / Unit (amd64)
  • GitHub Check: Management / Integration (amd64, postgres)
  • GitHub Check: Client / Unit (amd64)
  • GitHub Check: Client (Docker) / Unit
  • GitHub Check: Client / Unit
  • GitHub Check: Darwin
  • GitHub Check: Windows
  • GitHub Check: Linux
  • GitHub Check: Client / Unit
  • GitHub Check: JS / Lint
  • GitHub Check: Client / Unit
  • GitHub Check: iOS / Build
  • GitHub Check: Android / Build
  • GitHub Check: release
  • GitHub Check: release_ui_darwin

@sonarqubecloud
Copy link
Copy Markdown

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
management/server/peer_test.go (3)

1178-1180: ToSyncResponse arguments updated; consider asserting behavior of new config inputs

The additional configuration parameters are wired correctly into grpc.ToSyncResponse. To better guard against regressions, consider extending this test to populate HttpConfig / DeviceAuthorizationFlow on config and add assertions that the resulting SyncResponse reflects those values as expected.


1230-1231: Clarify and scope the //nolint directive

A bare //nolint suppresses all linters for this line and can mask unrelated problems. Prefer narrowing it, e.g. //nolint:<linter>(reason), so future readers know what is being suppressed and why.


1293-1293: Shared controller construction with realistic config would improve test fidelity

Passing &config.Config{} into controller.NewController satisfies the new parameter but leaves all config fields at zero values and duplicates the same construction in several tests. To keep tests closer to production behavior and make future config changes easier to adopt, consider:

  • Extracting a small helper (e.g. newTestNetworkMapController(...)) that builds the controller for tests, and
  • Initializing the returned *config.Config with minimal but realistic values for any fields the controller depends on (such as HTTP / device-auth flow settings), so tests also exercise config-dependent logic.

Also applies to: 1378-1378, 1531-1531, 1611-1611

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 49f2f03 and 7ce4c7b.

📒 Files selected for processing (2)
  • client/internal/engine.go (1 hunks)
  • management/server/peer_test.go (6 hunks)
✅ Files skipped from review due to trivial changes (1)
  • client/internal/engine.go
🧰 Additional context used
🧬 Code graph analysis (1)
management/server/peer_test.go (3)
management/internals/shared/grpc/conversion.go (1)
  • ToSyncResponse (107-150)
management/internals/server/config/config.go (2)
  • DeviceAuthorizationFlow (127-130)
  • Config (37-60)
management/internals/controllers/network_map/controller/controller.go (1)
  • NewController (73-108)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (25)
  • GitHub Check: Management / Unit (amd64, sqlite)
  • GitHub Check: Management / Benchmark (amd64, sqlite)
  • GitHub Check: Management / Unit (amd64, mysql)
  • GitHub Check: Management / Unit (amd64, postgres)
  • GitHub Check: Management / Benchmark (API) (amd64, postgres)
  • GitHub Check: Management / Benchmark (amd64, postgres)
  • GitHub Check: Management / Integration (amd64, postgres)
  • GitHub Check: Relay / Unit (amd64, -race)
  • GitHub Check: Management / Benchmark (API) (amd64, sqlite)
  • GitHub Check: Relay / Unit (386)
  • GitHub Check: Signal / Unit (386)
  • GitHub Check: Management / Integration (amd64, sqlite)
  • GitHub Check: Signal / Unit (amd64)
  • GitHub Check: Client (Docker) / Unit
  • GitHub Check: Client / Unit (386)
  • GitHub Check: Client / Unit (amd64)
  • GitHub Check: release
  • GitHub Check: Client / Unit
  • GitHub Check: release_ui
  • GitHub Check: Linux
  • GitHub Check: JS / Lint
  • GitHub Check: Windows
  • GitHub Check: Client / Unit
  • GitHub Check: Android / Build
  • GitHub Check: Client / Unit

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants