mirror of
https://github.com/netbirdio/netbird.git
synced 2026-08-13 11:11:29 +02:00
Compare commits
5 Commits
revert/com
...
revert/com
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
931598e593 | ||
|
|
9bb1db28c3 | ||
|
|
4952f2e8cf | ||
|
|
32c7918c80 | ||
|
|
56d1607f72 |
9
.github/workflows/golang-test-linux.yml
vendored
9
.github/workflows/golang-test-linux.yml
vendored
@@ -729,6 +729,11 @@ jobs:
|
||||
- name: Install modules
|
||||
run: go mod tidy
|
||||
|
||||
- name: Run Mage
|
||||
uses: magefile/mage-action@v4
|
||||
with:
|
||||
install-only: true
|
||||
|
||||
- name: check git status
|
||||
run: git --no-pager diff --exit-code
|
||||
|
||||
@@ -737,9 +742,7 @@ jobs:
|
||||
CGO_ENABLED=1 GOARCH=${{ matrix.arch }} \
|
||||
NETBIRD_STORE_ENGINE=${{ matrix.store }} \
|
||||
CI=true \
|
||||
go test -tags=integration -coverprofile=coverage.txt \
|
||||
-exec 'sudo --preserve-env=CI,NETBIRD_STORE_ENGINE' \
|
||||
-timeout 20m ./management/server/http/...
|
||||
mage integrationtest:all -gotestflags="-coverprofile=coverage.txt"
|
||||
|
||||
- name: Upload coverage reports to Codecov
|
||||
if: matrix.arch == 'amd64'
|
||||
|
||||
1
go.mod
1
go.mod
@@ -76,6 +76,7 @@ require (
|
||||
github.com/libp2p/go-nat v0.2.0
|
||||
github.com/libp2p/go-netroute v0.4.0
|
||||
github.com/lrh3321/ipset-go v0.0.0-20250619021614-54a0a98ace81
|
||||
github.com/magefile/mage v1.17.2
|
||||
github.com/mdlayher/socket v0.5.1
|
||||
github.com/mdp/qrterminal/v3 v3.2.1
|
||||
github.com/miekg/dns v1.1.72
|
||||
|
||||
2
go.sum
2
go.sum
@@ -415,6 +415,8 @@ github.com/lrh3321/ipset-go v0.0.0-20250619021614-54a0a98ace81 h1:J56rFEfUTFT9j9
|
||||
github.com/lrh3321/ipset-go v0.0.0-20250619021614-54a0a98ace81/go.mod h1:RD8ML/YdXctQ7qbcizZkw5mZ6l8Ogrl1dodBzVJduwI=
|
||||
github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae h1:dIZY4ULFcto4tAFlj1FYZl8ztUZ13bdq+PLY+NOfbyI=
|
||||
github.com/lufia/plan9stats v0.0.0-20240513124658-fba389f38bae/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k=
|
||||
github.com/magefile/mage v1.17.2 h1:fyXVu1eadI8Ap1HCCNgEhJ5McIWiYhLR8uol64ZZc40=
|
||||
github.com/magefile/mage v1.17.2/go.mod h1:Yj51kqllmsgFpvvSzgrZPK9WtluG3kUhFaBUVLo4feA=
|
||||
github.com/magiconair/properties v1.8.10 h1:s31yESBquKXCV9a/ScB3ESkOjUYYv+X0rg8SYxI99mE=
|
||||
github.com/magiconair/properties v1.8.10/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/matryer/is v1.4.1 h1:55ehd8zaGABKLXQUe2awZ99BD/PTc2ls+KV/dXphgEQ=
|
||||
|
||||
10
magefiles/magefile.go
Normal file
10
magefiles/magefile.go
Normal file
@@ -0,0 +1,10 @@
|
||||
//mage:multiline
|
||||
|
||||
// Set the general description you want to have displayed with mage -l here.
|
||||
package main
|
||||
|
||||
// mg contains helpful utility functions, like Deps
|
||||
|
||||
// Default target to run when none is specified
|
||||
// If not set, running mage will list available targets
|
||||
//var Default = Integrationtest.All
|
||||
65
magefiles/test.go
Normal file
65
magefiles/test.go
Normal file
@@ -0,0 +1,65 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/magefile/mage/mg"
|
||||
"github.com/magefile/mage/sh"
|
||||
)
|
||||
|
||||
var defaultcli = []string{"test", "-tags=integration", "-timeout=20m"}
|
||||
|
||||
type Integrationtest mg.Namespace
|
||||
|
||||
func (i Integrationtest) All(gotestflags *string) error {
|
||||
var errs []error
|
||||
if err := i.Api(gotestflags); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if err := i.NmapDb(gotestflags); err != nil {
|
||||
errs = append(errs, err)
|
||||
}
|
||||
if len(errs) > 0 {
|
||||
return errors.Join(errs...)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (Integrationtest) NmapDb(gotestflags *string) error {
|
||||
cli := defaultcli
|
||||
if gotestflags != nil {
|
||||
cli = append(cli, strings.Split(*gotestflags, " ")...)
|
||||
}
|
||||
cli = append(cli, "./integration_tests/management/network_map_db/...")
|
||||
|
||||
return sh.RunV("go", cli...)
|
||||
}
|
||||
|
||||
func (Integrationtest) NmapDbPostgres(gotestflags *string) error {
|
||||
cli := defaultcli
|
||||
if gotestflags != nil {
|
||||
cli = append(cli, strings.Split(*gotestflags, " ")...)
|
||||
}
|
||||
cli = append(cli, "./integration_tests/management/network_map_db/...")
|
||||
|
||||
return sh.RunWithV(map[string]string{"NETBIRD_STORE_ENGINE": "postgres"}, "go", cli...)
|
||||
}
|
||||
|
||||
func (Integrationtest) NmapDbSqlite(gotestflags *string) error {
|
||||
cli := defaultcli
|
||||
if gotestflags != nil {
|
||||
cli = append(cli, strings.Split(*gotestflags, " ")...)
|
||||
}
|
||||
cli = append(cli, "./integration_tests/management/network_map_db/...")
|
||||
return sh.RunWithV(map[string]string{"NETBIRD_STORE_ENGINE": "sqlite"}, "go", cli...)
|
||||
}
|
||||
|
||||
func (Integrationtest) Api(gotestflags *string) error {
|
||||
cli := defaultcli
|
||||
if gotestflags != nil {
|
||||
cli = append(cli, strings.Split(*gotestflags, " ")...)
|
||||
}
|
||||
cli = append(cli, "./management/server/http/...")
|
||||
return sh.RunV("go", cli...)
|
||||
}
|
||||
@@ -173,10 +173,9 @@ func (e *componentEncoder) appendPeer(p *nmdata.Peer) uint32 {
|
||||
return idx
|
||||
}
|
||||
|
||||
// indexRouterPeers ensures every router peer is in the peer dedup table
|
||||
// (c.RouterPeers may contain peers not in c.Peers when validation rules drop
|
||||
// them) and returns their wire indexes for the RouterPeerIndexes field. Must
|
||||
// run before any encoder that resolves peer ids via e.peerOrder.
|
||||
// indexRouterPeers ensures every router peer is in the peer dedup table and
|
||||
// returns their wire indexes for the RouterPeerIndexes field. Must run before
|
||||
// any encoder that resolves peer ids via e.peerOrder.
|
||||
func (e *componentEncoder) indexRouterPeers(routers map[string]*nmdata.Peer) []uint32 {
|
||||
if len(routers) == 0 {
|
||||
return nil
|
||||
@@ -333,16 +332,15 @@ func unionPolicies(policies []*nmdata.Policy, resourcePolicies map[string][]*nmd
|
||||
}
|
||||
|
||||
// encodeAuthorizedGroups translates rule.AuthorizedGroups (map keyed by
|
||||
// group xid → local-user names) to the wire form (map keyed by group
|
||||
// account_seq_id → UserNameList). Groups without a seq id are dropped —
|
||||
// matches how source/destination group references handle the same case.
|
||||
// group xid → local-user names) to the wire form (map keyed by
|
||||
// authorizedGroupKey → UserNameList).
|
||||
func (e *componentEncoder) encodeAuthorizedGroups(m map[string][]string) map[string]*proto.UserNameList {
|
||||
if len(m) == 0 {
|
||||
return nil
|
||||
}
|
||||
out := make(map[string]*proto.UserNameList, len(m))
|
||||
for groupID, names := range m {
|
||||
id, ok := e.groupPublicXid(groupID)
|
||||
id, ok := e.authorizedGroupKey(groupID)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
@@ -351,6 +349,24 @@ func (e *componentEncoder) encodeAuthorizedGroups(m map[string][]string) map[str
|
||||
return out
|
||||
}
|
||||
|
||||
// authorizedGroupKey resolves the wire key for a group that grants SSH access.
|
||||
// These are user groups: they hold no peers, so nothing puts them in
|
||||
// components.Groups and groupPublicXid cannot see them. Dropping them the way a
|
||||
// missing source/destination group is dropped would strip every authorized user
|
||||
// from the envelope while PeerConfig still reports SSH enabled, leaving the peer
|
||||
// running sshd with nobody able to log in — so the id is passed through instead.
|
||||
// AuthorizedGroups and GroupIDToUserIDs are only ever used against each other,
|
||||
// on both sides of the wire, so they just have to agree.
|
||||
func (e *componentEncoder) authorizedGroupKey(groupID string) (string, bool) {
|
||||
if groupID == "" {
|
||||
return "", false
|
||||
}
|
||||
if id, ok := e.groupPublicXid(groupID); ok {
|
||||
return id, true
|
||||
}
|
||||
return groupID, true
|
||||
}
|
||||
|
||||
func (e *componentEncoder) groupPublicXid(groupID string) (string, bool) {
|
||||
g, ok := e.components.Groups[groupID]
|
||||
if !ok {
|
||||
@@ -650,7 +666,7 @@ func (e *componentEncoder) encodeGroupIDToUserIDs(m map[string][]string) map[str
|
||||
}
|
||||
out := make(map[string]*proto.UserIDList, len(m))
|
||||
for groupID, userIDs := range m {
|
||||
id, ok := e.groupPublicXid(groupID)
|
||||
id, ok := e.authorizedGroupKey(groupID)
|
||||
if !ok || len(userIDs) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -697,15 +697,20 @@ func TestEncodeNetworkMapEnvelope_RouterPeerNotInComponentsPeers(t *testing.T) {
|
||||
func TestEncodeNetworkMapEnvelope_GroupIDToUserIDs(t *testing.T) {
|
||||
c := newTestComponents()
|
||||
c.GroupIDToUserIDs = map[string][]string{
|
||||
"group-src": {"user-1", "user-2"},
|
||||
"group-missing": {"user-4"}, // group not in components → drop
|
||||
"group-src": {"user-1", "user-2"},
|
||||
"group-users": {"user-4"},
|
||||
}
|
||||
|
||||
full := EncodeNetworkMapEnvelope(ComponentsEnvelopeInput{Components: c}).GetFull()
|
||||
|
||||
require.Len(t, full.GroupIdToUserIds, 1, "only present groups survive")
|
||||
require.Len(t, full.GroupIdToUserIds, 2,
|
||||
"a peer group is keyed by its public id, and a user group — which never appears in "+
|
||||
"components.Groups — keeps its own id rather than being dropped, or the peer would "+
|
||||
"receive no authorized SSH users at all")
|
||||
require.Contains(t, full.GroupIdToUserIds, "1")
|
||||
assert.ElementsMatch(t, []string{"user-1", "user-2"}, full.GroupIdToUserIds["1"].UserIds)
|
||||
require.Contains(t, full.GroupIdToUserIds, "group-users")
|
||||
assert.ElementsMatch(t, []string{"user-4"}, full.GroupIdToUserIds["group-users"].UserIds)
|
||||
}
|
||||
|
||||
func TestToProxyPatch_EmptyInputReturnsNil(t *testing.T) {
|
||||
|
||||
@@ -105,7 +105,7 @@ func (nmd *NetworkMapData) GetPeerNetworkMapComponents(peerID string, peersCusto
|
||||
}
|
||||
|
||||
for _, policy := range policies {
|
||||
if policy == nil || len(policy.Rules) == 0 || policy.Rules[0] == nil {
|
||||
if policy == nil || !policy.Enabled || len(policy.Rules) == 0 || policy.Rules[0] == nil {
|
||||
continue
|
||||
}
|
||||
if addSourcePeers {
|
||||
@@ -147,7 +147,7 @@ func (nmd *NetworkMapData) GetPeerNetworkMapComponents(peerID string, peersCusto
|
||||
}
|
||||
|
||||
for _, rule := range policy.Rules {
|
||||
if rule == nil {
|
||||
if rule == nil || !rule.Enabled {
|
||||
continue
|
||||
}
|
||||
for _, srcGroupID := range rule.Sources {
|
||||
@@ -171,15 +171,21 @@ func (nmd *NetworkMapData) GetPeerNetworkMapComponents(peerID string, peersCusto
|
||||
if addSourcePeers {
|
||||
components.RoutersMap[resource.NetworkID] = networkRoutingPeers
|
||||
for peerIDKey := range networkRoutingPeers {
|
||||
if p := nmd.Peers[peerIDKey]; p != nil {
|
||||
if _, exists := components.RouterPeers[peerIDKey]; !exists {
|
||||
components.RouterPeers[peerIDKey] = p
|
||||
}
|
||||
if _, exists := components.Peers[peerIDKey]; !exists {
|
||||
if _, validated := nmd.ValidatedPeers[peerIDKey]; validated {
|
||||
components.Peers[peerIDKey] = p
|
||||
}
|
||||
}
|
||||
p := nmd.Peers[peerIDKey]
|
||||
if p == nil {
|
||||
continue
|
||||
}
|
||||
// An unapproved peer must not carry traffic, so it is kept out of
|
||||
// RouterPeers as well: the envelope encoder indexes that map into
|
||||
// the wire peer table, from which the client restores every entry.
|
||||
if _, validated := nmd.ValidatedPeers[peerIDKey]; !validated {
|
||||
continue
|
||||
}
|
||||
if _, exists := components.RouterPeers[peerIDKey]; !exists {
|
||||
components.RouterPeers[peerIDKey] = p
|
||||
}
|
||||
if _, exists := components.Peers[peerIDKey]; !exists {
|
||||
components.Peers[peerIDKey] = p
|
||||
}
|
||||
}
|
||||
components.NetworkResources = append(components.NetworkResources, resource)
|
||||
|
||||
@@ -1103,8 +1103,9 @@ func TestGetPeerNetworkMapComponents_NetworkResources_SourceSide(t *testing.T) {
|
||||
assert.Equal(t, []*nmdata.NetworkResource{res}, c.NetworkResources)
|
||||
assert.Equal(t, map[string][]*nmdata.Policy{"res-1": {rp}}, c.ResourcePoliciesMap)
|
||||
assert.Equal(t, map[string]map[string]*nmdata.NetworkRouter{"net-1": routers}, c.RoutersMap)
|
||||
assert.ElementsMatch(t, []string{routerOK.ID, routerUnval.ID}, peerIDSet(c.RouterPeers),
|
||||
"RouterPeers carries all routing peers regardless of validation")
|
||||
assert.ElementsMatch(t, []string{routerOK.ID}, peerIDSet(c.RouterPeers),
|
||||
"an unvalidated routing peer is withheld from RouterPeers too, since the envelope encoder "+
|
||||
"indexes that map into the wire peer table and the client restores every entry from it")
|
||||
assert.ElementsMatch(t, []string{targetID, routerOK.ID}, peerIDSet(c.Peers),
|
||||
"only validated routing peers are connected")
|
||||
assert.ElementsMatch(t, []string{"g-clients", "g-resource"}, groupIDSet(c.Groups))
|
||||
|
||||
@@ -819,7 +819,7 @@ func (c *NetworkMapComponents) processResourcePolicies(
|
||||
var routes []*nmdata.Route
|
||||
|
||||
for _, policy := range c.ResourcePoliciesMap[resource.ID] {
|
||||
if policy == nil || len(policy.Rules) == 0 || policy.Rules[0] == nil {
|
||||
if policy == nil || !policy.Enabled || len(policy.Rules) == 0 || policy.Rules[0] == nil {
|
||||
continue
|
||||
}
|
||||
peers := c.getResourcePolicyPeers(policy)
|
||||
|
||||
Reference in New Issue
Block a user