From 76db9ab94f4cc314c41dbc137f1b8c1f385b61cc Mon Sep 17 00:00:00 2001 From: pascal Date: Mon, 3 Aug 2026 12:11:35 +0200 Subject: [PATCH] update integrated validator --- go.mod | 2 +- go.sum | 2 + .../network_map/controller/controller.go | 12 ++--- .../internals/network_map_db/pgsql/group.go | 4 +- .../internals/network_map_db/pgsql/peer.go | 50 +++++++++++-------- management/server/integrated_validator.go | 5 +- .../integrated_validator/interface.go | 3 +- .../validator/validator.go | 3 +- .../server/types/account_networkmapdata.go | 15 +++++- management/server/types/aliases.go | 2 +- shared/management/networkmap/nmdata/group.go | 2 + shared/management/networkmap/nmdata/peer.go | 7 +++ 12 files changed, 70 insertions(+), 37 deletions(-) diff --git a/go.mod b/go.mod index ca798decc..0b5cab64e 100644 --- a/go.mod +++ b/go.mod @@ -80,7 +80,7 @@ require ( github.com/miekg/dns v1.1.72 github.com/mitchellh/hashstructure/v2 v2.0.2 github.com/moby/moby/api v1.54.1 - github.com/netbirdio/management-integrations/integrations v0.0.0-20260416123949-2355d972be42 + github.com/netbirdio/management-integrations/integrations v0.0.0-20260803100840-78e79ba20f87 github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20250805121659-6b4ac470ca45 github.com/oapi-codegen/runtime v1.1.2 github.com/okta/okta-sdk-golang/v2 v2.18.0 diff --git a/go.sum b/go.sum index 58e30a580..2760b51f3 100644 --- a/go.sum +++ b/go.sum @@ -486,6 +486,8 @@ github.com/netbirdio/ice/v4 v4.0.0-20250908184934-6202be846b51 h1:Ov4qdafATOgGMB github.com/netbirdio/ice/v4 v4.0.0-20250908184934-6202be846b51/go.mod h1:ZSIbPdBn5hePO8CpF1PekH2SfpTxg1PDhEwtbqZS7R8= github.com/netbirdio/management-integrations/integrations v0.0.0-20260416123949-2355d972be42 h1:F3zS5fT9xzD1OFLfcdAE+3FfyiwjGukF1hvj0jErgs8= github.com/netbirdio/management-integrations/integrations v0.0.0-20260416123949-2355d972be42/go.mod h1:n47r67ZSPgwSmT/Z1o48JjZQW9YJ6m/6Bd/uAXkL3Pg= +github.com/netbirdio/management-integrations/integrations v0.0.0-20260803100840-78e79ba20f87 h1:iJeUvSMC0BTpkw7u4JyWcY4/3dl7fEL9DR/TpKf2+1w= +github.com/netbirdio/management-integrations/integrations v0.0.0-20260803100840-78e79ba20f87/go.mod h1:pmsCPx1S0nuZRxCextGpc9AV4hLgGSuTsc4NMuwGeCo= github.com/netbirdio/service v0.0.0-20240911161631-f62744f42502 h1:3tHlFmhTdX9axERMVN63dqyFqnvuD+EMJHzM7mNGON8= github.com/netbirdio/service v0.0.0-20240911161631-f62744f42502/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= github.com/netbirdio/signal-dispatcher/dispatcher v0.0.0-20250805121659-6b4ac470ca45 h1:ujgviVYmx243Ksy7NdSwrdGPSRNE3pb8kEDSpH0QuAQ= diff --git a/management/internals/controllers/network_map/controller/controller.go b/management/internals/controllers/network_map/controller/controller.go index 8d0c4269d..3f58883e2 100644 --- a/management/internals/controllers/network_map/controller/controller.go +++ b/management/internals/controllers/network_map/controller/controller.go @@ -167,7 +167,7 @@ func (c *Controller) sendUpdateAccountPeers(ctx context.Context, accountID strin return nil } - approvedPeersMap, err := c.integratedPeerValidator.GetValidatedPeers(ctx, account.Id, maps.Values(account.Groups), maps.Values(account.Peers), account.Settings.Extra) + approvedPeersMap, err := c.integratedPeerValidator.GetValidatedPeers(ctx, account.Id, types.TwinGroups(maps.Values(account.Groups)), types.TwinPeers(maps.Values(account.Peers)), account.Settings.Extra) if err != nil { return fmt.Errorf("failed to get validate peers: %v", err) } @@ -340,7 +340,7 @@ func (c *Controller) sendUpdateForAffectedPeers(ctx context.Context, accountID s log.WithContext(ctx).Tracef("sendUpdateForAffectedPeers: sending network map to %d connected peers", len(peersToUpdate)) - approvedPeersMap, err := c.integratedPeerValidator.GetValidatedPeers(ctx, account.Id, maps.Values(account.Groups), maps.Values(account.Peers), account.Settings.Extra) + approvedPeersMap, err := c.integratedPeerValidator.GetValidatedPeers(ctx, account.Id, types.TwinGroups(maps.Values(account.Groups)), types.TwinPeers(maps.Values(account.Peers)), account.Settings.Extra) if err != nil { return fmt.Errorf("failed to get validate peers: %v", err) } @@ -504,7 +504,7 @@ func (c *Controller) UpdateAccountPeer(ctx context.Context, accountId string, pe return fmt.Errorf("peer %s doesn't exists in account %s", peerId, accountId) } - approvedPeersMap, err := c.integratedPeerValidator.GetValidatedPeers(ctx, account.Id, maps.Values(account.Groups), maps.Values(account.Peers), account.Settings.Extra) + approvedPeersMap, err := c.integratedPeerValidator.GetValidatedPeers(ctx, account.Id, types.TwinGroups(maps.Values(account.Groups)), types.TwinPeers(maps.Values(account.Peers)), account.Settings.Extra) if err != nil { return fmt.Errorf("failed to get validated peers: %v", err) } @@ -651,7 +651,7 @@ func (c *Controller) GetValidatedPeerWithComponents(ctx context.Context, isRequi c.injectAllProxyPolicies(ctx, account) - approvedPeersMap, err := c.integratedPeerValidator.GetValidatedPeers(ctx, account.Id, maps.Values(account.Groups), maps.Values(account.Peers), account.Settings.Extra) + approvedPeersMap, err := c.integratedPeerValidator.GetValidatedPeers(ctx, account.Id, types.TwinGroups(maps.Values(account.Groups)), types.TwinPeers(maps.Values(account.Peers)), account.Settings.Extra) if err != nil { return nil, nil, nil, nil, 0, err } @@ -806,7 +806,7 @@ func (c *Controller) GetValidatedPeerWithMap(ctx context.Context, isRequiresAppr c.injectAllProxyPolicies(ctx, account) - approvedPeersMap, err := c.integratedPeerValidator.GetValidatedPeers(ctx, account.Id, maps.Values(account.Groups), maps.Values(account.Peers), account.Settings.Extra) + approvedPeersMap, err := c.integratedPeerValidator.GetValidatedPeers(ctx, account.Id, types.TwinGroups(maps.Values(account.Groups)), types.TwinPeers(maps.Values(account.Peers)), account.Settings.Extra) if err != nil { return nil, nil, 0, err } @@ -1055,7 +1055,7 @@ func (c *Controller) GetNetworkMap(ctx context.Context, peerID string) (*types.N groups[groupID] = group.Peers } - validatedPeers, err := c.integratedPeerValidator.GetValidatedPeers(ctx, account.Id, maps.Values(account.Groups), maps.Values(account.Peers), account.Settings.Extra) + validatedPeers, err := c.integratedPeerValidator.GetValidatedPeers(ctx, account.Id, types.TwinGroups(maps.Values(account.Groups)), types.TwinPeers(maps.Values(account.Peers)), account.Settings.Extra) if err != nil { return nil, err } diff --git a/management/internals/network_map_db/pgsql/group.go b/management/internals/network_map_db/pgsql/group.go index eda43dd82..2c827e597 100644 --- a/management/internals/network_map_db/pgsql/group.go +++ b/management/internals/network_map_db/pgsql/group.go @@ -56,7 +56,7 @@ func GetGroupsViaPgxConnection(ctx context.Context, con *pgx.Conn, accountId str if _, ok := resourceToGroupIdx[resource.ID]; !ok { resourceToGroupIdx[resource.ID] = make(map[string]any) } - resourceToGroupIdx[resource.ID][g.Id] = struct{}{} + resourceToGroupIdx[resource.ID][g.ID] = struct{}{} } } @@ -64,7 +64,7 @@ func GetGroupsViaPgxConnection(ctx context.Context, con *pgx.Conn, accountId str } type group struct { - Id string `nmap:"skip"` + ID string Name sql.NullString PublicID sql.NullString Resources json.RawMessage diff --git a/management/internals/network_map_db/pgsql/peer.go b/management/internals/network_map_db/pgsql/peer.go index 40bafd3d5..688506c94 100644 --- a/management/internals/network_map_db/pgsql/peer.go +++ b/management/internals/network_map_db/pgsql/peer.go @@ -14,7 +14,8 @@ import ( const ( GetPeersQuery = ` select id, key, ssh_key, dns_label, user_id, ssh_enabled, login_expiration_enabled, last_login, ip, ipv6, - meta_wt_version, meta_go_os, meta_os_version, meta_kernel_version, meta_network_addresses, meta_files, meta_capabilities, meta_flags, + peer_status_requires_approval, proxy_meta_embedded, + meta_wt_version, meta_go_os, meta_os_version, meta_kernel_version, meta_network_addresses, meta_files, meta_capabilities, meta_flags, location_country_code, location_city_name, location_connection_ip from peers where account_id = $1 @@ -49,6 +50,9 @@ func GetPeersViaPgxConnection(ctx context.Context, con *pgx.Conn, accountId stri return nil, err } + if p.ProxyMetaEmbedded.Valid { + dp.ProxyMeta.Embedded = p.ProxyMetaEmbedded.Bool + } if p.MetaWtVersion.Valid { dp.Meta.WtVersion = p.MetaWtVersion.String } @@ -104,25 +108,27 @@ func GetPeersViaPgxConnection(ctx context.Context, con *pgx.Conn, accountId stri // TODO add support for creating struct fields from denormalized fields type peer struct { - ID string - Key sql.NullString - SSHKey sql.NullString - DNSLabel sql.NullString - UserID sql.NullString - LastLogin sql.NullTime - SSHEnabled sql.NullBool - LoginExpirationEnabled sql.NullBool - IP json.RawMessage - IPv6 json.RawMessage - LocationConnectionIp json.RawMessage `nmap:"skip"` - MetaFiles json.RawMessage `nmap:"skip"` - MetaCapabilities json.RawMessage `nmap:"skip"` - MetaFlags json.RawMessage `nmap:"skip"` - MetaNetworkAddresses json.RawMessage `nmap:"skip"` - MetaWtVersion sql.NullString `nmap:"skip"` - MetaGoOS sql.NullString `nmap:"skip"` - MetaOSVersion sql.NullString `nmap:"skip"` - MetaKernelVersion sql.NullString `nmap:"skip"` - LocationCountryCode sql.NullString `nmap:"skip"` - LocationCityName sql.NullString `nmap:"skip"` + ID string + Key sql.NullString + SSHKey sql.NullString + DNSLabel sql.NullString + UserID sql.NullString + LastLogin sql.NullTime + SSHEnabled sql.NullBool + LoginExpirationEnabled sql.NullBool + PeerStatusRequiresApproval sql.NullBool `nmap:"mapTo=RequiresApproval"` + ProxyMetaEmbedded sql.NullBool `nmap:"skip"` + IP json.RawMessage + IPv6 json.RawMessage + LocationConnectionIp json.RawMessage `nmap:"skip"` + MetaFiles json.RawMessage `nmap:"skip"` + MetaCapabilities json.RawMessage `nmap:"skip"` + MetaFlags json.RawMessage `nmap:"skip"` + MetaNetworkAddresses json.RawMessage `nmap:"skip"` + MetaWtVersion sql.NullString `nmap:"skip"` + MetaGoOS sql.NullString `nmap:"skip"` + MetaOSVersion sql.NullString `nmap:"skip"` + MetaKernelVersion sql.NullString `nmap:"skip"` + LocationCountryCode sql.NullString `nmap:"skip"` + LocationCityName sql.NullString `nmap:"skip"` } diff --git a/management/server/integrated_validator.go b/management/server/integrated_validator.go index 69ea668ad..9ec1f491e 100644 --- a/management/server/integrated_validator.go +++ b/management/server/integrated_validator.go @@ -11,6 +11,7 @@ import ( nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/store" "github.com/netbirdio/netbird/management/server/types" + "github.com/netbirdio/netbird/shared/management/networkmap/nmdata" ) // UpdateIntegratedValidator updates the integrated validator groups for a specified account. @@ -109,7 +110,7 @@ func (am *DefaultAccountManager) GetValidatedPeers(ctx context.Context, accountI return nil, nil, err } - validPeers, err := am.integratedPeerValidator.GetValidatedPeers(ctx, accountID, groups, peers, settings.Extra) + validPeers, err := am.integratedPeerValidator.GetValidatedPeers(ctx, accountID, types.TwinGroups(groups), types.TwinPeers(peers), settings.Extra) if err != nil { return nil, nil, err } @@ -138,7 +139,7 @@ func (a MockIntegratedValidator) ValidatePeer(_ context.Context, update *nbpeer. return update, false, nil } -func (a MockIntegratedValidator) GetValidatedPeers(_ context.Context, accountID string, groups []*types.Group, peers []*nbpeer.Peer, extraSettings *types.ExtraSettings) (map[string]struct{}, error) { +func (a MockIntegratedValidator) GetValidatedPeers(_ context.Context, accountID string, groups []*nmdata.Group, peers []*nmdata.Peer, extraSettings *types.ExtraSettings) (map[string]struct{}, error) { validatedPeers := make(map[string]struct{}) for _, peer := range peers { validatedPeers[peer.ID] = struct{}{} diff --git a/management/server/integrations/integrated_validator/interface.go b/management/server/integrations/integrated_validator/interface.go index 326fbfaf0..9c534abde 100644 --- a/management/server/integrations/integrated_validator/interface.go +++ b/management/server/integrations/integrated_validator/interface.go @@ -5,6 +5,7 @@ import ( nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/types" + "github.com/netbirdio/netbird/shared/management/networkmap/nmdata" "github.com/netbirdio/netbird/shared/management/proto" ) @@ -14,7 +15,7 @@ type IntegratedValidator interface { ValidatePeer(ctx context.Context, update *nbpeer.Peer, peer *nbpeer.Peer, userID string, accountID string, dnsDomain string, peersGroup []string, extraSettings *types.ExtraSettings) (*nbpeer.Peer, bool, error) PreparePeer(ctx context.Context, accountID string, peer *nbpeer.Peer, peersGroup []string, extraSettings *types.ExtraSettings, temporary bool) *nbpeer.Peer IsNotValidPeer(ctx context.Context, accountID string, peer *nbpeer.Peer, peersGroup []string, extraSettings *types.ExtraSettings) (bool, bool, error) - GetValidatedPeers(ctx context.Context, accountID string, groups []*types.Group, peers []*nbpeer.Peer, extraSettings *types.ExtraSettings) (map[string]struct{}, error) + GetValidatedPeers(ctx context.Context, accountID string, groups []*nmdata.Group, peers []*nmdata.Peer, extraSettings *types.ExtraSettings) (map[string]struct{}, error) GetInvalidPeers(ctx context.Context, accountID string, extraSettings *types.ExtraSettings) (map[string]string, error) PeerDeleted(ctx context.Context, accountID, peerID string, extraSettings *types.ExtraSettings) error SetPeerInvalidationListener(fn func(accountID string, peerIDs []string)) diff --git a/management/server/integrations/integrated_validator/validator/validator.go b/management/server/integrations/integrated_validator/validator/validator.go index db1d34373..33199c065 100644 --- a/management/server/integrations/integrated_validator/validator/validator.go +++ b/management/server/integrations/integrated_validator/validator/validator.go @@ -10,6 +10,7 @@ import ( nbpeer "github.com/netbirdio/netbird/management/server/peer" "github.com/netbirdio/netbird/management/server/settings" "github.com/netbirdio/netbird/management/server/types" + "github.com/netbirdio/netbird/shared/management/networkmap/nmdata" "github.com/netbirdio/netbird/shared/management/proto" ) @@ -35,7 +36,7 @@ func (v *IntegratedValidatorImpl) IsNotValidPeer(_ context.Context, _ string, _ return false, false, nil } -func (v *IntegratedValidatorImpl) GetValidatedPeers(_ context.Context, _ string, _ []*types.Group, peers []*nbpeer.Peer, _ *types.ExtraSettings) (map[string]struct{}, error) { +func (v *IntegratedValidatorImpl) GetValidatedPeers(_ context.Context, _ string, _ []*nmdata.Group, peers []*nmdata.Peer, _ *types.ExtraSettings) (map[string]struct{}, error) { validatedPeers := make(map[string]struct{}) for _, p := range peers { validatedPeers[p.ID] = struct{}{} diff --git a/management/server/types/account_networkmapdata.go b/management/server/types/account_networkmapdata.go index 68a874761..2681f1270 100644 --- a/management/server/types/account_networkmapdata.go +++ b/management/server/types/account_networkmapdata.go @@ -144,6 +144,8 @@ func twinPeer(p *nbpeer.Peer) *nmdata.Peer { LastLogin: p.LastLogin, IP: p.IP, IPv6: p.IPv6, + RequiresApproval: p.Status != nil && p.Status.RequiresApproval, + ProxyMeta: nmdata.ProxyMeta{Embedded: p.ProxyMeta.Embedded}, Meta: nmdata.PeerSystemMeta{ WtVersion: p.Meta.WtVersion, GoOS: p.Meta.GoOS, @@ -171,7 +173,8 @@ func TwinPeer(p *nbpeer.Peer) *nmdata.Peer { return twinPeer(p) } -func twinPeers(peers []*nbpeer.Peer) []*nmdata.Peer { +// TwinPeers converts real peers to their slim nmdata twins. +func TwinPeers(peers []*nbpeer.Peer) []*nmdata.Peer { out := make([]*nmdata.Peer, len(peers)) for i, p := range peers { out[i] = twinPeer(p) @@ -179,11 +182,21 @@ func twinPeers(peers []*nbpeer.Peer) []*nmdata.Peer { return out } +// TwinGroups converts real groups to their slim nmdata twins. +func TwinGroups(groups []*Group) []*nmdata.Group { + out := make([]*nmdata.Group, len(groups)) + for i, g := range groups { + out[i] = twinGroup(g) + } + return out +} + func twinGroup(g *Group) *nmdata.Group { if g == nil { return nil } return &nmdata.Group{ + ID: g.ID, Name: g.Name, PublicID: g.PublicID, Peers: g.Peers, diff --git a/management/server/types/aliases.go b/management/server/types/aliases.go index d7053ba86..8246b58e2 100644 --- a/management/server/types/aliases.go +++ b/management/server/types/aliases.go @@ -84,7 +84,7 @@ func CalculateNetworkMapFromComponents(ctx context.Context, components *NetworkM } func GenerateRouteFirewallRules(ctx context.Context, route *nbroute.Route, rule *PolicyRule, groupPeers []*nbpeer.Peer, direction int, includeIPv6 bool) []*RouteFirewallRule { - return sharedtypes.GenerateRouteFirewallRules(ctx, twinRoute(route), twinRule(rule), twinPeers(groupPeers), direction, includeIPv6) + return sharedtypes.GenerateRouteFirewallRules(ctx, twinRoute(route), twinRule(rule), TwinPeers(groupPeers), direction, includeIPv6) } func AllocateIPv6Subnet(r *rand.Rand) net.IPNet { diff --git a/shared/management/networkmap/nmdata/group.go b/shared/management/networkmap/nmdata/group.go index a49c76240..9e795a06a 100644 --- a/shared/management/networkmap/nmdata/group.go +++ b/shared/management/networkmap/nmdata/group.go @@ -6,6 +6,7 @@ const groupAllName = "All" // Group is the slim twin of types.Group. type Group struct { + ID string Name string PublicID string Peers []string @@ -18,6 +19,7 @@ func (g *Group) IsGroupAll() bool { func (g *Group) Copy() *Group { return &Group{ + ID: g.ID, Name: g.Name, PublicID: g.PublicID, Peers: slices.Clone(g.Peers), diff --git a/shared/management/networkmap/nmdata/peer.go b/shared/management/networkmap/nmdata/peer.go index a0ee43fc1..46a98a0c5 100644 --- a/shared/management/networkmap/nmdata/peer.go +++ b/shared/management/networkmap/nmdata/peer.go @@ -24,10 +24,17 @@ type Peer struct { LastLogin *time.Time IP netip.Addr IPv6 netip.Addr + RequiresApproval bool Meta PeerSystemMeta + ProxyMeta ProxyMeta Location PeerLocation } +// ProxyMeta is the slim twin of peer.ProxyMeta. +type ProxyMeta struct { + Embedded bool +} + // PeerSystemMeta is the slim twin of peer.PeerSystemMeta. type PeerSystemMeta struct { WtVersion string