mirror of
https://github.com/netbirdio/netbird.git
synced 2026-08-07 02:28:53 -04:00
An Unimplemented answer to GetAgentNetworkSetup can only come from a server binary compiled without the regenerated management proto — the combined and management servers share the one registration path in boot.go. Make that failure mode self-diagnosing: - Log "ManagementService registered on gRPC server (agent-network setup RPC available)" at boot, so server logs prove which build is running. - Have the CLI name the management URL it dialed in every error, and map Unimplemented to an actionable message including the binary check (grep -ac GetAgentNetworkSetup <server binary>). - Pin the wire path with a round-trip test: a real gRPC server built from this tree routes the RPC through the NaCl envelope end to end. Verified live: a combined server built from this branch answers an unregistered probe with PermissionDenied "peer is not registered", never Unimplemented. Linear: NET-1399
90 lines
3.0 KiB
Go
90 lines
3.0 KiB
Go
package client
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"golang.zx2c4.com/wireguard/wgctrl/wgtypes"
|
|
"google.golang.org/grpc"
|
|
|
|
"github.com/netbirdio/netbird/encryption"
|
|
mgmtProto "github.com/netbirdio/netbird/shared/management/proto"
|
|
)
|
|
|
|
// agentNetworkSetupServer is a minimal ManagementService that answers
|
|
// GetServerKey and GetAgentNetworkSetup with the real NaCl-box envelope,
|
|
// so the test pins the full wire path: gRPC method routing, request
|
|
// encryption, and response decryption.
|
|
type agentNetworkSetupServer struct {
|
|
mgmtProto.UnimplementedManagementServiceServer
|
|
key wgtypes.Key
|
|
}
|
|
|
|
func (s *agentNetworkSetupServer) GetServerKey(_ context.Context, _ *mgmtProto.Empty) (*mgmtProto.ServerKeyResponse, error) {
|
|
return &mgmtProto.ServerKeyResponse{Key: s.key.PublicKey().String()}, nil
|
|
}
|
|
|
|
func (s *agentNetworkSetupServer) GetAgentNetworkSetup(_ context.Context, msg *mgmtProto.EncryptedMessage) (*mgmtProto.EncryptedMessage, error) {
|
|
peerKey, err := wgtypes.ParseKey(msg.WgPubKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
req := &mgmtProto.AgentNetworkSetupRequest{}
|
|
if err := encryption.DecryptMessage(peerKey, s.key, msg.Body, req); err != nil {
|
|
return nil, err
|
|
}
|
|
resp := &mgmtProto.AgentNetworkSetupResponse{
|
|
Configured: true,
|
|
Endpoint: "https://violet.eu.proxy.example.com",
|
|
Providers: []*mgmtProto.AgentNetworkProviderInfo{
|
|
{
|
|
Name: "Anthropic prod",
|
|
CatalogId: "anthropic_api",
|
|
ApiFlavor: "anthropic",
|
|
Models: []string{"claude-sonnet-4-5"},
|
|
},
|
|
},
|
|
}
|
|
body, err := encryption.EncryptMessage(peerKey, s.key, resp)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return &mgmtProto.EncryptedMessage{WgPubKey: s.key.PublicKey().String(), Body: body}, nil
|
|
}
|
|
|
|
// TestGetAgentNetworkSetup_RoundTrip proves the RPC is routable on any
|
|
// server built from this tree and that the encrypt→invoke→decrypt path
|
|
// the CLI uses round-trips. A server answering this call with
|
|
// codes.Unimplemented is by definition running a binary compiled without
|
|
// the regenerated management proto.
|
|
func TestGetAgentNetworkSetup_RoundTrip(t *testing.T) {
|
|
serverKey, err := wgtypes.GeneratePrivateKey()
|
|
require.NoError(t, err)
|
|
|
|
lis, err := net.Listen("tcp", "127.0.0.1:0")
|
|
require.NoError(t, err)
|
|
|
|
srv := grpc.NewServer()
|
|
mgmtProto.RegisterManagementServiceServer(srv, &agentNetworkSetupServer{key: serverKey})
|
|
go func() { _ = srv.Serve(lis) }()
|
|
t.Cleanup(srv.Stop)
|
|
|
|
clientKey, err := wgtypes.GeneratePrivateKey()
|
|
require.NoError(t, err)
|
|
|
|
client, err := NewClient(context.Background(), lis.Addr().String(), clientKey, false)
|
|
require.NoError(t, err)
|
|
t.Cleanup(func() { _ = client.Close() })
|
|
|
|
setup, err := client.GetAgentNetworkSetup(context.Background())
|
|
require.NoError(t, err)
|
|
assert.True(t, setup.Configured)
|
|
assert.Equal(t, "https://violet.eu.proxy.example.com", setup.Endpoint)
|
|
require.Len(t, setup.Providers, 1)
|
|
assert.Equal(t, "anthropic_api", setup.Providers[0].CatalogId)
|
|
assert.Equal(t, []string{"claude-sonnet-4-5"}, setup.Providers[0].Models)
|
|
}
|