mirror of
https://github.com/juanfont/headscale.git
synced 2026-04-25 01:59:07 +02:00
make tags first class node owner (#2885)
This PR changes tags to be something that exists on nodes in addition to users, to being its own thing. It is part of moving our tags support towards the correct tailscale compatible implementation. There are probably rough edges in this PR, but the intention is to get it in, and then start fixing bugs from 0.28.0 milestone (long standing tags issue) to discover what works and what doesnt. Updates #2417 Closes #2619
This commit is contained in:
@@ -32,11 +32,11 @@ func TestApproveRoutesWithPolicy_NeverRemovesApprovedRoutes(t *testing.T) {
|
||||
MachineKey: key.NewMachine().Public(),
|
||||
NodeKey: key.NewNode().Public(),
|
||||
Hostname: "test-node",
|
||||
UserID: user1.ID,
|
||||
User: user1,
|
||||
UserID: ptr.To(user1.ID),
|
||||
User: ptr.To(user1),
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
IPv4: ptr.To(netip.MustParseAddr("100.64.0.1")),
|
||||
ForcedTags: []string{"tag:test"},
|
||||
Tags: []string{"tag:test"},
|
||||
}
|
||||
|
||||
node2 := &types.Node{
|
||||
@@ -44,8 +44,8 @@ func TestApproveRoutesWithPolicy_NeverRemovesApprovedRoutes(t *testing.T) {
|
||||
MachineKey: key.NewMachine().Public(),
|
||||
NodeKey: key.NewNode().Public(),
|
||||
Hostname: "other-node",
|
||||
UserID: user2.ID,
|
||||
User: user2,
|
||||
UserID: ptr.To(user2.ID),
|
||||
User: ptr.To(user2),
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
IPv4: ptr.To(netip.MustParseAddr("100.64.0.2")),
|
||||
}
|
||||
@@ -304,8 +304,8 @@ func TestApproveRoutesWithPolicy_NilAndEmptyCases(t *testing.T) {
|
||||
MachineKey: key.NewMachine().Public(),
|
||||
NodeKey: key.NewNode().Public(),
|
||||
Hostname: "testnode",
|
||||
UserID: user.ID,
|
||||
User: user,
|
||||
UserID: ptr.To(user.ID),
|
||||
User: ptr.To(user),
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
IPv4: ptr.To(netip.MustParseAddr("100.64.0.1")),
|
||||
ApprovedRoutes: tt.currentApproved,
|
||||
|
||||
@@ -168,15 +168,15 @@ func TestApproveRoutesWithPolicy_NeverRemovesRoutes(t *testing.T) {
|
||||
MachineKey: key.NewMachine().Public(),
|
||||
NodeKey: key.NewNode().Public(),
|
||||
Hostname: tt.nodeHostname,
|
||||
UserID: user.ID,
|
||||
User: user,
|
||||
UserID: ptr.To(user.ID),
|
||||
User: ptr.To(user),
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: tt.announcedRoutes,
|
||||
},
|
||||
IPv4: ptr.To(netip.MustParseAddr("100.64.0.1")),
|
||||
ApprovedRoutes: tt.currentApproved,
|
||||
ForcedTags: tt.nodeTags,
|
||||
Tags: tt.nodeTags,
|
||||
}
|
||||
nodes := types.Nodes{&node}
|
||||
|
||||
@@ -294,8 +294,8 @@ func TestApproveRoutesWithPolicy_EdgeCases(t *testing.T) {
|
||||
MachineKey: key.NewMachine().Public(),
|
||||
NodeKey: key.NewNode().Public(),
|
||||
Hostname: "testnode",
|
||||
UserID: user.ID,
|
||||
User: user,
|
||||
UserID: ptr.To(user.ID),
|
||||
User: ptr.To(user),
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: tt.announcedRoutes,
|
||||
@@ -343,8 +343,8 @@ func TestApproveRoutesWithPolicy_NilPolicyManagerCase(t *testing.T) {
|
||||
MachineKey: key.NewMachine().Public(),
|
||||
NodeKey: key.NewNode().Public(),
|
||||
Hostname: "testnode",
|
||||
UserID: user.ID,
|
||||
User: user,
|
||||
UserID: ptr.To(user.ID),
|
||||
User: ptr.To(user),
|
||||
RegisterMethod: util.RegisterMethodAuthKey,
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: announcedRoutes,
|
||||
|
||||
@@ -14,6 +14,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"gorm.io/gorm"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/ptr"
|
||||
)
|
||||
|
||||
var ap = func(ipStr string) *netip.Addr {
|
||||
@@ -44,17 +45,17 @@ func TestReduceNodes(t *testing.T) {
|
||||
&types.Node{
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
User: types.User{Name: "joe"},
|
||||
User: &types.User{Name: "joe"},
|
||||
},
|
||||
&types.Node{
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
User: types.User{Name: "marc"},
|
||||
User: &types.User{Name: "marc"},
|
||||
},
|
||||
&types.Node{
|
||||
ID: 3,
|
||||
IPv4: ap("100.64.0.3"),
|
||||
User: types.User{Name: "mickael"},
|
||||
User: &types.User{Name: "mickael"},
|
||||
},
|
||||
},
|
||||
rules: []tailcfg.FilterRule{
|
||||
@@ -68,19 +69,19 @@ func TestReduceNodes(t *testing.T) {
|
||||
node: &types.Node{ // current nodes
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
User: types.User{Name: "joe"},
|
||||
User: &types.User{Name: "joe"},
|
||||
},
|
||||
},
|
||||
want: types.Nodes{
|
||||
&types.Node{
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
User: types.User{Name: "marc"},
|
||||
User: &types.User{Name: "marc"},
|
||||
},
|
||||
&types.Node{
|
||||
ID: 3,
|
||||
IPv4: ap("100.64.0.3"),
|
||||
User: types.User{Name: "mickael"},
|
||||
User: &types.User{Name: "mickael"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -91,17 +92,17 @@ func TestReduceNodes(t *testing.T) {
|
||||
&types.Node{
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
User: types.User{Name: "joe"},
|
||||
User: &types.User{Name: "joe"},
|
||||
},
|
||||
&types.Node{
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
User: types.User{Name: "marc"},
|
||||
User: &types.User{Name: "marc"},
|
||||
},
|
||||
&types.Node{
|
||||
ID: 3,
|
||||
IPv4: ap("100.64.0.3"),
|
||||
User: types.User{Name: "mickael"},
|
||||
User: &types.User{Name: "mickael"},
|
||||
},
|
||||
},
|
||||
rules: []tailcfg.FilterRule{ // list of all ACLRules registered
|
||||
@@ -115,14 +116,14 @@ func TestReduceNodes(t *testing.T) {
|
||||
node: &types.Node{ // current nodes
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
User: types.User{Name: "joe"},
|
||||
User: &types.User{Name: "joe"},
|
||||
},
|
||||
},
|
||||
want: types.Nodes{
|
||||
&types.Node{
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
User: types.User{Name: "marc"},
|
||||
User: &types.User{Name: "marc"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -133,17 +134,17 @@ func TestReduceNodes(t *testing.T) {
|
||||
&types.Node{
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
User: types.User{Name: "joe"},
|
||||
User: &types.User{Name: "joe"},
|
||||
},
|
||||
&types.Node{
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
User: types.User{Name: "marc"},
|
||||
User: &types.User{Name: "marc"},
|
||||
},
|
||||
&types.Node{
|
||||
ID: 3,
|
||||
IPv4: ap("100.64.0.3"),
|
||||
User: types.User{Name: "mickael"},
|
||||
User: &types.User{Name: "mickael"},
|
||||
},
|
||||
},
|
||||
rules: []tailcfg.FilterRule{ // list of all ACLRules registered
|
||||
@@ -157,14 +158,14 @@ func TestReduceNodes(t *testing.T) {
|
||||
node: &types.Node{ // current nodes
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
User: types.User{Name: "marc"},
|
||||
User: &types.User{Name: "marc"},
|
||||
},
|
||||
},
|
||||
want: types.Nodes{
|
||||
&types.Node{
|
||||
ID: 3,
|
||||
IPv4: ap("100.64.0.3"),
|
||||
User: types.User{Name: "mickael"},
|
||||
User: &types.User{Name: "mickael"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -175,17 +176,17 @@ func TestReduceNodes(t *testing.T) {
|
||||
&types.Node{
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
User: types.User{Name: "joe"},
|
||||
User: &types.User{Name: "joe"},
|
||||
},
|
||||
&types.Node{
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
User: types.User{Name: "marc"},
|
||||
User: &types.User{Name: "marc"},
|
||||
},
|
||||
&types.Node{
|
||||
ID: 3,
|
||||
IPv4: ap("100.64.0.3"),
|
||||
User: types.User{Name: "mickael"},
|
||||
User: &types.User{Name: "mickael"},
|
||||
},
|
||||
},
|
||||
rules: []tailcfg.FilterRule{ // list of all ACLRules registered
|
||||
@@ -199,14 +200,14 @@ func TestReduceNodes(t *testing.T) {
|
||||
node: &types.Node{ // current nodes
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
User: types.User{Name: "joe"},
|
||||
User: &types.User{Name: "joe"},
|
||||
},
|
||||
},
|
||||
want: types.Nodes{
|
||||
&types.Node{
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
User: types.User{Name: "marc"},
|
||||
User: &types.User{Name: "marc"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -217,17 +218,17 @@ func TestReduceNodes(t *testing.T) {
|
||||
&types.Node{
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
User: types.User{Name: "joe"},
|
||||
User: &types.User{Name: "joe"},
|
||||
},
|
||||
&types.Node{
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
User: types.User{Name: "marc"},
|
||||
User: &types.User{Name: "marc"},
|
||||
},
|
||||
&types.Node{
|
||||
ID: 3,
|
||||
IPv4: ap("100.64.0.3"),
|
||||
User: types.User{Name: "mickael"},
|
||||
User: &types.User{Name: "mickael"},
|
||||
},
|
||||
},
|
||||
rules: []tailcfg.FilterRule{ // list of all ACLRules registered
|
||||
@@ -241,19 +242,19 @@ func TestReduceNodes(t *testing.T) {
|
||||
node: &types.Node{ // current nodes
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
User: types.User{Name: "marc"},
|
||||
User: &types.User{Name: "marc"},
|
||||
},
|
||||
},
|
||||
want: types.Nodes{
|
||||
&types.Node{
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
User: types.User{Name: "joe"},
|
||||
User: &types.User{Name: "joe"},
|
||||
},
|
||||
&types.Node{
|
||||
ID: 3,
|
||||
IPv4: ap("100.64.0.3"),
|
||||
User: types.User{Name: "mickael"},
|
||||
User: &types.User{Name: "mickael"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -264,17 +265,17 @@ func TestReduceNodes(t *testing.T) {
|
||||
&types.Node{
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
User: types.User{Name: "joe"},
|
||||
User: &types.User{Name: "joe"},
|
||||
},
|
||||
&types.Node{
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
User: types.User{Name: "marc"},
|
||||
User: &types.User{Name: "marc"},
|
||||
},
|
||||
&types.Node{
|
||||
ID: 3,
|
||||
IPv4: ap("100.64.0.3"),
|
||||
User: types.User{Name: "mickael"},
|
||||
User: &types.User{Name: "mickael"},
|
||||
},
|
||||
},
|
||||
rules: []tailcfg.FilterRule{ // list of all ACLRules registered
|
||||
@@ -288,19 +289,19 @@ func TestReduceNodes(t *testing.T) {
|
||||
node: &types.Node{ // current nodes
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
User: types.User{Name: "marc"},
|
||||
User: &types.User{Name: "marc"},
|
||||
},
|
||||
},
|
||||
want: types.Nodes{
|
||||
&types.Node{
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
User: types.User{Name: "joe"},
|
||||
User: &types.User{Name: "joe"},
|
||||
},
|
||||
&types.Node{
|
||||
ID: 3,
|
||||
IPv4: ap("100.64.0.3"),
|
||||
User: types.User{Name: "mickael"},
|
||||
User: &types.User{Name: "mickael"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -311,17 +312,17 @@ func TestReduceNodes(t *testing.T) {
|
||||
&types.Node{
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
User: types.User{Name: "joe"},
|
||||
User: &types.User{Name: "joe"},
|
||||
},
|
||||
&types.Node{
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
User: types.User{Name: "marc"},
|
||||
User: &types.User{Name: "marc"},
|
||||
},
|
||||
&types.Node{
|
||||
ID: 3,
|
||||
IPv4: ap("100.64.0.3"),
|
||||
User: types.User{Name: "mickael"},
|
||||
User: &types.User{Name: "mickael"},
|
||||
},
|
||||
},
|
||||
rules: []tailcfg.FilterRule{ // list of all ACLRules registered
|
||||
@@ -329,7 +330,7 @@ func TestReduceNodes(t *testing.T) {
|
||||
node: &types.Node{ // current nodes
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
User: types.User{Name: "marc"},
|
||||
User: &types.User{Name: "marc"},
|
||||
},
|
||||
},
|
||||
want: nil,
|
||||
@@ -347,28 +348,28 @@ func TestReduceNodes(t *testing.T) {
|
||||
Hostname: "ts-head-upcrmb",
|
||||
IPv4: ap("100.64.0.3"),
|
||||
IPv6: ap("fd7a:115c:a1e0::3"),
|
||||
User: types.User{Name: "user1"},
|
||||
User: &types.User{Name: "user1"},
|
||||
},
|
||||
&types.Node{
|
||||
ID: 2,
|
||||
Hostname: "ts-unstable-rlwpvr",
|
||||
IPv4: ap("100.64.0.4"),
|
||||
IPv6: ap("fd7a:115c:a1e0::4"),
|
||||
User: types.User{Name: "user1"},
|
||||
User: &types.User{Name: "user1"},
|
||||
},
|
||||
&types.Node{
|
||||
ID: 3,
|
||||
Hostname: "ts-head-8w6paa",
|
||||
IPv4: ap("100.64.0.1"),
|
||||
IPv6: ap("fd7a:115c:a1e0::1"),
|
||||
User: types.User{Name: "user2"},
|
||||
User: &types.User{Name: "user2"},
|
||||
},
|
||||
&types.Node{
|
||||
ID: 4,
|
||||
Hostname: "ts-unstable-lys2ib",
|
||||
IPv4: ap("100.64.0.2"),
|
||||
IPv6: ap("fd7a:115c:a1e0::2"),
|
||||
User: types.User{Name: "user2"},
|
||||
User: &types.User{Name: "user2"},
|
||||
},
|
||||
},
|
||||
rules: []tailcfg.FilterRule{ // list of all ACLRules registered
|
||||
@@ -390,7 +391,7 @@ func TestReduceNodes(t *testing.T) {
|
||||
Hostname: "ts-head-8w6paa",
|
||||
IPv4: ap("100.64.0.1"),
|
||||
IPv6: ap("fd7a:115c:a1e0::1"),
|
||||
User: types.User{Name: "user2"},
|
||||
User: &types.User{Name: "user2"},
|
||||
},
|
||||
},
|
||||
want: types.Nodes{
|
||||
@@ -399,14 +400,14 @@ func TestReduceNodes(t *testing.T) {
|
||||
Hostname: "ts-head-upcrmb",
|
||||
IPv4: ap("100.64.0.3"),
|
||||
IPv6: ap("fd7a:115c:a1e0::3"),
|
||||
User: types.User{Name: "user1"},
|
||||
User: &types.User{Name: "user1"},
|
||||
},
|
||||
&types.Node{
|
||||
ID: 2,
|
||||
Hostname: "ts-unstable-rlwpvr",
|
||||
IPv4: ap("100.64.0.4"),
|
||||
IPv6: ap("fd7a:115c:a1e0::4"),
|
||||
User: types.User{Name: "user1"},
|
||||
User: &types.User{Name: "user1"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -418,13 +419,13 @@ func TestReduceNodes(t *testing.T) {
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
Hostname: "peer1",
|
||||
User: types.User{Name: "mini"},
|
||||
User: &types.User{Name: "mini"},
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.3"),
|
||||
Hostname: "peer2",
|
||||
User: types.User{Name: "peer2"},
|
||||
User: &types.User{Name: "peer2"},
|
||||
},
|
||||
},
|
||||
rules: []tailcfg.FilterRule{
|
||||
@@ -440,7 +441,7 @@ func TestReduceNodes(t *testing.T) {
|
||||
ID: 0,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
Hostname: "mini",
|
||||
User: types.User{Name: "mini"},
|
||||
User: &types.User{Name: "mini"},
|
||||
},
|
||||
},
|
||||
want: []*types.Node{
|
||||
@@ -448,7 +449,7 @@ func TestReduceNodes(t *testing.T) {
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.3"),
|
||||
Hostname: "peer2",
|
||||
User: types.User{Name: "peer2"},
|
||||
User: &types.User{Name: "peer2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -460,19 +461,19 @@ func TestReduceNodes(t *testing.T) {
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
Hostname: "user1-2",
|
||||
User: types.User{Name: "user1"},
|
||||
User: &types.User{Name: "user1"},
|
||||
},
|
||||
{
|
||||
ID: 0,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
Hostname: "user1-1",
|
||||
User: types.User{Name: "user1"},
|
||||
User: &types.User{Name: "user1"},
|
||||
},
|
||||
{
|
||||
ID: 3,
|
||||
IPv4: ap("100.64.0.4"),
|
||||
Hostname: "user2-2",
|
||||
User: types.User{Name: "user2"},
|
||||
User: &types.User{Name: "user2"},
|
||||
},
|
||||
},
|
||||
rules: []tailcfg.FilterRule{
|
||||
@@ -509,7 +510,7 @@ func TestReduceNodes(t *testing.T) {
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.3"),
|
||||
Hostname: "user-2-1",
|
||||
User: types.User{Name: "user2"},
|
||||
User: &types.User{Name: "user2"},
|
||||
},
|
||||
},
|
||||
want: []*types.Node{
|
||||
@@ -517,19 +518,19 @@ func TestReduceNodes(t *testing.T) {
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
Hostname: "user1-2",
|
||||
User: types.User{Name: "user1"},
|
||||
User: &types.User{Name: "user1"},
|
||||
},
|
||||
{
|
||||
ID: 0,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
Hostname: "user1-1",
|
||||
User: types.User{Name: "user1"},
|
||||
User: &types.User{Name: "user1"},
|
||||
},
|
||||
{
|
||||
ID: 3,
|
||||
IPv4: ap("100.64.0.4"),
|
||||
Hostname: "user2-2",
|
||||
User: types.User{Name: "user2"},
|
||||
User: &types.User{Name: "user2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -541,19 +542,19 @@ func TestReduceNodes(t *testing.T) {
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
Hostname: "user1-2",
|
||||
User: types.User{Name: "user1"},
|
||||
User: &types.User{Name: "user1"},
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.3"),
|
||||
Hostname: "user-2-1",
|
||||
User: types.User{Name: "user2"},
|
||||
User: &types.User{Name: "user2"},
|
||||
},
|
||||
{
|
||||
ID: 3,
|
||||
IPv4: ap("100.64.0.4"),
|
||||
Hostname: "user2-2",
|
||||
User: types.User{Name: "user2"},
|
||||
User: &types.User{Name: "user2"},
|
||||
},
|
||||
},
|
||||
rules: []tailcfg.FilterRule{
|
||||
@@ -590,7 +591,7 @@ func TestReduceNodes(t *testing.T) {
|
||||
ID: 0,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
Hostname: "user1-1",
|
||||
User: types.User{Name: "user1"},
|
||||
User: &types.User{Name: "user1"},
|
||||
},
|
||||
},
|
||||
want: []*types.Node{
|
||||
@@ -598,19 +599,19 @@ func TestReduceNodes(t *testing.T) {
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
Hostname: "user1-2",
|
||||
User: types.User{Name: "user1"},
|
||||
User: &types.User{Name: "user1"},
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.3"),
|
||||
Hostname: "user-2-1",
|
||||
User: types.User{Name: "user2"},
|
||||
User: &types.User{Name: "user2"},
|
||||
},
|
||||
{
|
||||
ID: 3,
|
||||
IPv4: ap("100.64.0.4"),
|
||||
Hostname: "user2-2",
|
||||
User: types.User{Name: "user2"},
|
||||
User: &types.User{Name: "user2"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -622,13 +623,13 @@ func TestReduceNodes(t *testing.T) {
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
Hostname: "user1",
|
||||
User: types.User{Name: "user1"},
|
||||
User: &types.User{Name: "user1"},
|
||||
},
|
||||
{
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
Hostname: "router",
|
||||
User: types.User{Name: "router"},
|
||||
User: &types.User{Name: "router"},
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("10.33.0.0/16")},
|
||||
},
|
||||
@@ -649,7 +650,7 @@ func TestReduceNodes(t *testing.T) {
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
Hostname: "user1",
|
||||
User: types.User{Name: "user1"},
|
||||
User: &types.User{Name: "user1"},
|
||||
},
|
||||
},
|
||||
want: []*types.Node{
|
||||
@@ -657,7 +658,7 @@ func TestReduceNodes(t *testing.T) {
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
Hostname: "router",
|
||||
User: types.User{Name: "router"},
|
||||
User: &types.User{Name: "router"},
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("10.33.0.0/16")},
|
||||
},
|
||||
@@ -673,7 +674,7 @@ func TestReduceNodes(t *testing.T) {
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
Hostname: "router",
|
||||
User: types.User{Name: "router"},
|
||||
User: &types.User{Name: "router"},
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("10.99.0.0/16")},
|
||||
},
|
||||
@@ -683,7 +684,7 @@ func TestReduceNodes(t *testing.T) {
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
Hostname: "node",
|
||||
User: types.User{Name: "node"},
|
||||
User: &types.User{Name: "node"},
|
||||
},
|
||||
},
|
||||
rules: []tailcfg.FilterRule{
|
||||
@@ -700,7 +701,7 @@ func TestReduceNodes(t *testing.T) {
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
Hostname: "router",
|
||||
User: types.User{Name: "router"},
|
||||
User: &types.User{Name: "router"},
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("10.99.0.0/16")},
|
||||
},
|
||||
@@ -712,7 +713,7 @@ func TestReduceNodes(t *testing.T) {
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
Hostname: "node",
|
||||
User: types.User{Name: "node"},
|
||||
User: &types.User{Name: "node"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -724,7 +725,7 @@ func TestReduceNodes(t *testing.T) {
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
Hostname: "router",
|
||||
User: types.User{Name: "router"},
|
||||
User: &types.User{Name: "router"},
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("10.99.0.0/16")},
|
||||
},
|
||||
@@ -734,7 +735,7 @@ func TestReduceNodes(t *testing.T) {
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
Hostname: "node",
|
||||
User: types.User{Name: "node"},
|
||||
User: &types.User{Name: "node"},
|
||||
},
|
||||
},
|
||||
rules: []tailcfg.FilterRule{
|
||||
@@ -751,7 +752,7 @@ func TestReduceNodes(t *testing.T) {
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
Hostname: "node",
|
||||
User: types.User{Name: "node"},
|
||||
User: &types.User{Name: "node"},
|
||||
},
|
||||
},
|
||||
want: []*types.Node{
|
||||
@@ -759,7 +760,7 @@ func TestReduceNodes(t *testing.T) {
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
Hostname: "router",
|
||||
User: types.User{Name: "router"},
|
||||
User: &types.User{Name: "router"},
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("10.99.0.0/16")},
|
||||
},
|
||||
@@ -804,7 +805,7 @@ func TestReduceNodesFromPolicy(t *testing.T) {
|
||||
ID: id,
|
||||
IPv4: ap(ip),
|
||||
Hostname: hostname,
|
||||
User: types.User{Name: username},
|
||||
User: &types.User{Name: username},
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: routes,
|
||||
},
|
||||
@@ -812,8 +813,6 @@ func TestReduceNodesFromPolicy(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
type args struct {
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
nodes types.Nodes
|
||||
@@ -1075,22 +1074,22 @@ func TestSSHPolicyRules(t *testing.T) {
|
||||
nodeUser1 := types.Node{
|
||||
Hostname: "user1-device",
|
||||
IPv4: ap("100.64.0.1"),
|
||||
UserID: 1,
|
||||
User: users[0],
|
||||
UserID: ptr.To(uint(1)),
|
||||
User: ptr.To(users[0]),
|
||||
}
|
||||
nodeUser2 := types.Node{
|
||||
Hostname: "user2-device",
|
||||
IPv4: ap("100.64.0.2"),
|
||||
UserID: 2,
|
||||
User: users[1],
|
||||
UserID: ptr.To(uint(2)),
|
||||
User: ptr.To(users[1]),
|
||||
}
|
||||
|
||||
taggedClient := types.Node{
|
||||
Hostname: "tagged-client",
|
||||
IPv4: ap("100.64.0.4"),
|
||||
UserID: 2,
|
||||
User: users[1],
|
||||
ForcedTags: []string{"tag:client"},
|
||||
Hostname: "tagged-client",
|
||||
IPv4: ap("100.64.0.4"),
|
||||
UserID: ptr.To(uint(2)),
|
||||
User: ptr.To(users[1]),
|
||||
Tags: []string{"tag:client"},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
@@ -1447,7 +1446,7 @@ func TestReduceRoutes(t *testing.T) {
|
||||
node: &types.Node{
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
User: types.User{Name: "user1"},
|
||||
User: &types.User{Name: "user1"},
|
||||
},
|
||||
routes: []netip.Prefix{
|
||||
netip.MustParsePrefix("10.0.0.0/24"),
|
||||
@@ -1475,7 +1474,7 @@ func TestReduceRoutes(t *testing.T) {
|
||||
node: &types.Node{
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
User: types.User{Name: "user1"},
|
||||
User: &types.User{Name: "user1"},
|
||||
},
|
||||
routes: []netip.Prefix{
|
||||
netip.MustParsePrefix("10.0.0.0/24"),
|
||||
@@ -1501,7 +1500,7 @@ func TestReduceRoutes(t *testing.T) {
|
||||
node: &types.Node{
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
User: types.User{Name: "user1"},
|
||||
User: &types.User{Name: "user1"},
|
||||
},
|
||||
routes: []netip.Prefix{
|
||||
netip.MustParsePrefix("10.0.0.0/24"),
|
||||
@@ -1529,7 +1528,7 @@ func TestReduceRoutes(t *testing.T) {
|
||||
node: &types.Node{
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
User: types.User{Name: "user1"},
|
||||
User: &types.User{Name: "user1"},
|
||||
},
|
||||
routes: []netip.Prefix{
|
||||
netip.MustParsePrefix("10.0.0.0/24"),
|
||||
@@ -1556,7 +1555,7 @@ func TestReduceRoutes(t *testing.T) {
|
||||
node: &types.Node{
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
User: types.User{Name: "user1"},
|
||||
User: &types.User{Name: "user1"},
|
||||
},
|
||||
routes: []netip.Prefix{
|
||||
netip.MustParsePrefix("10.0.0.0/24"),
|
||||
@@ -1581,7 +1580,7 @@ func TestReduceRoutes(t *testing.T) {
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"),
|
||||
IPv6: ap("fd7a:115c:a1e0::1"),
|
||||
User: types.User{Name: "user1"},
|
||||
User: &types.User{Name: "user1"},
|
||||
},
|
||||
routes: []netip.Prefix{
|
||||
netip.MustParsePrefix("10.0.0.0/24"),
|
||||
@@ -1614,7 +1613,7 @@ func TestReduceRoutes(t *testing.T) {
|
||||
node: &types.Node{
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"), // Node IP
|
||||
User: types.User{Name: "node"},
|
||||
User: &types.User{Name: "node"},
|
||||
},
|
||||
routes: []netip.Prefix{
|
||||
netip.MustParsePrefix("10.10.10.0/24"),
|
||||
@@ -1646,7 +1645,7 @@ func TestReduceRoutes(t *testing.T) {
|
||||
node: &types.Node{
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
User: types.User{Name: "node"},
|
||||
User: &types.User{Name: "node"},
|
||||
},
|
||||
routes: []netip.Prefix{
|
||||
netip.MustParsePrefix("10.10.10.0/24"),
|
||||
@@ -1673,7 +1672,7 @@ func TestReduceRoutes(t *testing.T) {
|
||||
node: &types.Node{
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
User: types.User{Name: "node"},
|
||||
User: &types.User{Name: "node"},
|
||||
},
|
||||
routes: []netip.Prefix{
|
||||
netip.MustParsePrefix("10.10.10.0/24"),
|
||||
@@ -1701,7 +1700,7 @@ func TestReduceRoutes(t *testing.T) {
|
||||
node: &types.Node{
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"),
|
||||
User: types.User{Name: "node"},
|
||||
User: &types.User{Name: "node"},
|
||||
},
|
||||
routes: []netip.Prefix{
|
||||
netip.MustParsePrefix("10.10.10.0/24"),
|
||||
@@ -1739,7 +1738,7 @@ func TestReduceRoutes(t *testing.T) {
|
||||
node: &types.Node{
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"), // node with IP 100.64.0.2
|
||||
User: types.User{Name: "node"},
|
||||
User: &types.User{Name: "node"},
|
||||
},
|
||||
routes: []netip.Prefix{
|
||||
netip.MustParsePrefix("10.10.10.0/24"),
|
||||
@@ -1774,7 +1773,7 @@ func TestReduceRoutes(t *testing.T) {
|
||||
node: &types.Node{
|
||||
ID: 1,
|
||||
IPv4: ap("100.64.0.1"), // router with IP 100.64.0.1
|
||||
User: types.User{Name: "router"},
|
||||
User: &types.User{Name: "router"},
|
||||
},
|
||||
routes: []netip.Prefix{
|
||||
netip.MustParsePrefix("10.10.10.0/24"),
|
||||
@@ -1816,7 +1815,7 @@ func TestReduceRoutes(t *testing.T) {
|
||||
node: &types.Node{
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"), // node
|
||||
User: types.User{Name: "node"},
|
||||
User: &types.User{Name: "node"},
|
||||
},
|
||||
routes: []netip.Prefix{
|
||||
netip.MustParsePrefix("10.10.10.0/24"),
|
||||
@@ -1850,7 +1849,7 @@ func TestReduceRoutes(t *testing.T) {
|
||||
node: &types.Node{
|
||||
ID: 2,
|
||||
IPv4: ap("100.64.0.2"), // node
|
||||
User: types.User{Name: "node"},
|
||||
User: &types.User{Name: "node"},
|
||||
},
|
||||
routes: []netip.Prefix{
|
||||
netip.MustParsePrefix("10.10.10.0/24"),
|
||||
@@ -1887,7 +1886,7 @@ func TestReduceRoutes(t *testing.T) {
|
||||
node: &types.Node{
|
||||
ID: 2,
|
||||
IPv4: ap("100.123.45.89"), // Node B - regular node
|
||||
User: types.User{Name: "node-b"},
|
||||
User: &types.User{Name: "node-b"},
|
||||
},
|
||||
routes: []netip.Prefix{
|
||||
netip.MustParsePrefix("192.168.1.0/24"), // Subnet connected to Node A
|
||||
@@ -1917,7 +1916,7 @@ func TestReduceRoutes(t *testing.T) {
|
||||
node: &types.Node{
|
||||
ID: 1,
|
||||
IPv4: ap("100.123.45.67"), // Node A - router node
|
||||
User: types.User{Name: "router"},
|
||||
User: &types.User{Name: "router"},
|
||||
},
|
||||
routes: []netip.Prefix{
|
||||
netip.MustParsePrefix("192.168.1.0/24"), // Subnet connected to this router
|
||||
@@ -1946,7 +1945,7 @@ func TestReduceRoutes(t *testing.T) {
|
||||
node: &types.Node{
|
||||
ID: 2,
|
||||
IPv4: ap("100.123.45.89"), // Node B - regular node that should be reachable
|
||||
User: types.User{Name: "node-b"},
|
||||
User: &types.User{Name: "node-b"},
|
||||
},
|
||||
routes: []netip.Prefix{
|
||||
netip.MustParsePrefix("192.168.1.0/24"), // Subnet behind router
|
||||
@@ -1984,7 +1983,7 @@ func TestReduceRoutes(t *testing.T) {
|
||||
node: &types.Node{
|
||||
ID: 3,
|
||||
IPv4: ap("100.123.45.99"), // Node C - isolated node
|
||||
User: types.User{Name: "isolated-node"},
|
||||
User: &types.User{Name: "isolated-node"},
|
||||
},
|
||||
routes: []netip.Prefix{
|
||||
netip.MustParsePrefix("192.168.1.0/24"), // Subnet behind router
|
||||
@@ -2027,7 +2026,7 @@ func TestReduceRoutes(t *testing.T) {
|
||||
node: &types.Node{
|
||||
ID: 2,
|
||||
IPv4: ap("100.123.45.89"), // Node B - regular node
|
||||
User: types.User{Name: "node-b"},
|
||||
User: &types.User{Name: "node-b"},
|
||||
},
|
||||
routes: []netip.Prefix{
|
||||
netip.MustParsePrefix("192.168.1.0/14"), // Network 192.168.1.0/14 as mentioned in original issue
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
"gorm.io/gorm"
|
||||
"tailscale.com/net/tsaddr"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/ptr"
|
||||
"tailscale.com/util/must"
|
||||
)
|
||||
|
||||
@@ -143,13 +144,13 @@ func TestReduceFilterRules(t *testing.T) {
|
||||
node: &types.Node{
|
||||
IPv4: ap("100.64.0.1"),
|
||||
IPv6: ap("fd7a:115c:a1e0:ab12:4843:2222:6273:2221"),
|
||||
User: users[0],
|
||||
User: ptr.To(users[0]),
|
||||
},
|
||||
peers: types.Nodes{
|
||||
&types.Node{
|
||||
IPv4: ap("100.64.0.2"),
|
||||
IPv6: ap("fd7a:115c:a1e0:ab12:4843:2222:6273:2222"),
|
||||
User: users[0],
|
||||
User: ptr.To(users[0]),
|
||||
},
|
||||
},
|
||||
want: []tailcfg.FilterRule{},
|
||||
@@ -190,7 +191,7 @@ func TestReduceFilterRules(t *testing.T) {
|
||||
node: &types.Node{
|
||||
IPv4: ap("100.64.0.1"),
|
||||
IPv6: ap("fd7a:115c:a1e0::1"),
|
||||
User: users[1],
|
||||
User: ptr.To(users[1]),
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: []netip.Prefix{
|
||||
netip.MustParsePrefix("10.33.0.0/16"),
|
||||
@@ -201,7 +202,7 @@ func TestReduceFilterRules(t *testing.T) {
|
||||
&types.Node{
|
||||
IPv4: ap("100.64.0.2"),
|
||||
IPv6: ap("fd7a:115c:a1e0::2"),
|
||||
User: users[1],
|
||||
User: ptr.To(users[1]),
|
||||
},
|
||||
},
|
||||
want: []tailcfg.FilterRule{
|
||||
@@ -282,19 +283,19 @@ func TestReduceFilterRules(t *testing.T) {
|
||||
node: &types.Node{
|
||||
IPv4: ap("100.64.0.1"),
|
||||
IPv6: ap("fd7a:115c:a1e0::1"),
|
||||
User: users[1],
|
||||
User: ptr.To(users[1]),
|
||||
},
|
||||
peers: types.Nodes{
|
||||
&types.Node{
|
||||
IPv4: ap("100.64.0.2"),
|
||||
IPv6: ap("fd7a:115c:a1e0::2"),
|
||||
User: users[2],
|
||||
User: ptr.To(users[2]),
|
||||
},
|
||||
// "internal" exit node
|
||||
&types.Node{
|
||||
IPv4: ap("100.64.0.100"),
|
||||
IPv6: ap("fd7a:115c:a1e0::100"),
|
||||
User: users[3],
|
||||
User: ptr.To(users[3]),
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: tsaddr.ExitRoutes(),
|
||||
},
|
||||
@@ -343,7 +344,7 @@ func TestReduceFilterRules(t *testing.T) {
|
||||
node: &types.Node{
|
||||
IPv4: ap("100.64.0.100"),
|
||||
IPv6: ap("fd7a:115c:a1e0::100"),
|
||||
User: users[3],
|
||||
User: ptr.To(users[3]),
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: tsaddr.ExitRoutes(),
|
||||
},
|
||||
@@ -352,12 +353,12 @@ func TestReduceFilterRules(t *testing.T) {
|
||||
&types.Node{
|
||||
IPv4: ap("100.64.0.2"),
|
||||
IPv6: ap("fd7a:115c:a1e0::2"),
|
||||
User: users[2],
|
||||
User: ptr.To(users[2]),
|
||||
},
|
||||
&types.Node{
|
||||
IPv4: ap("100.64.0.1"),
|
||||
IPv6: ap("fd7a:115c:a1e0::1"),
|
||||
User: users[1],
|
||||
User: ptr.To(users[1]),
|
||||
},
|
||||
},
|
||||
want: []tailcfg.FilterRule{
|
||||
@@ -452,7 +453,7 @@ func TestReduceFilterRules(t *testing.T) {
|
||||
node: &types.Node{
|
||||
IPv4: ap("100.64.0.100"),
|
||||
IPv6: ap("fd7a:115c:a1e0::100"),
|
||||
User: users[3],
|
||||
User: ptr.To(users[3]),
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: tsaddr.ExitRoutes(),
|
||||
},
|
||||
@@ -461,12 +462,12 @@ func TestReduceFilterRules(t *testing.T) {
|
||||
&types.Node{
|
||||
IPv4: ap("100.64.0.2"),
|
||||
IPv6: ap("fd7a:115c:a1e0::2"),
|
||||
User: users[2],
|
||||
User: ptr.To(users[2]),
|
||||
},
|
||||
&types.Node{
|
||||
IPv4: ap("100.64.0.1"),
|
||||
IPv6: ap("fd7a:115c:a1e0::1"),
|
||||
User: users[1],
|
||||
User: ptr.To(users[1]),
|
||||
},
|
||||
},
|
||||
want: []tailcfg.FilterRule{
|
||||
@@ -564,7 +565,7 @@ func TestReduceFilterRules(t *testing.T) {
|
||||
node: &types.Node{
|
||||
IPv4: ap("100.64.0.100"),
|
||||
IPv6: ap("fd7a:115c:a1e0::100"),
|
||||
User: users[3],
|
||||
User: ptr.To(users[3]),
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("8.0.0.0/16"), netip.MustParsePrefix("16.0.0.0/16")},
|
||||
},
|
||||
@@ -573,12 +574,12 @@ func TestReduceFilterRules(t *testing.T) {
|
||||
&types.Node{
|
||||
IPv4: ap("100.64.0.2"),
|
||||
IPv6: ap("fd7a:115c:a1e0::2"),
|
||||
User: users[2],
|
||||
User: ptr.To(users[2]),
|
||||
},
|
||||
&types.Node{
|
||||
IPv4: ap("100.64.0.1"),
|
||||
IPv6: ap("fd7a:115c:a1e0::1"),
|
||||
User: users[1],
|
||||
User: ptr.To(users[1]),
|
||||
},
|
||||
},
|
||||
want: []tailcfg.FilterRule{
|
||||
@@ -654,7 +655,7 @@ func TestReduceFilterRules(t *testing.T) {
|
||||
node: &types.Node{
|
||||
IPv4: ap("100.64.0.100"),
|
||||
IPv6: ap("fd7a:115c:a1e0::100"),
|
||||
User: users[3],
|
||||
User: ptr.To(users[3]),
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("8.0.0.0/8"), netip.MustParsePrefix("16.0.0.0/8")},
|
||||
},
|
||||
@@ -663,12 +664,12 @@ func TestReduceFilterRules(t *testing.T) {
|
||||
&types.Node{
|
||||
IPv4: ap("100.64.0.2"),
|
||||
IPv6: ap("fd7a:115c:a1e0::2"),
|
||||
User: users[2],
|
||||
User: ptr.To(users[2]),
|
||||
},
|
||||
&types.Node{
|
||||
IPv4: ap("100.64.0.1"),
|
||||
IPv6: ap("fd7a:115c:a1e0::1"),
|
||||
User: users[1],
|
||||
User: ptr.To(users[1]),
|
||||
},
|
||||
},
|
||||
want: []tailcfg.FilterRule{
|
||||
@@ -736,17 +737,17 @@ func TestReduceFilterRules(t *testing.T) {
|
||||
node: &types.Node{
|
||||
IPv4: ap("100.64.0.100"),
|
||||
IPv6: ap("fd7a:115c:a1e0::100"),
|
||||
User: users[3],
|
||||
User: ptr.To(users[3]),
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: []netip.Prefix{netip.MustParsePrefix("172.16.0.0/24")},
|
||||
},
|
||||
ForcedTags: []string{"tag:access-servers"},
|
||||
Tags: []string{"tag:access-servers"},
|
||||
},
|
||||
peers: types.Nodes{
|
||||
&types.Node{
|
||||
IPv4: ap("100.64.0.1"),
|
||||
IPv6: ap("fd7a:115c:a1e0::1"),
|
||||
User: users[1],
|
||||
User: ptr.To(users[1]),
|
||||
},
|
||||
},
|
||||
want: []tailcfg.FilterRule{
|
||||
@@ -803,13 +804,13 @@ func TestReduceFilterRules(t *testing.T) {
|
||||
node: &types.Node{
|
||||
IPv4: ap("100.64.0.2"),
|
||||
IPv6: ap("fd7a:115c:a1e0::2"),
|
||||
User: users[3],
|
||||
User: ptr.To(users[3]),
|
||||
},
|
||||
peers: types.Nodes{
|
||||
&types.Node{
|
||||
IPv4: ap("100.64.0.1"),
|
||||
IPv6: ap("fd7a:115c:a1e0::1"),
|
||||
User: users[1],
|
||||
User: ptr.To(users[1]),
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RoutableIPs: []netip.Prefix{p("172.16.0.0/24"), p("10.10.11.0/24"), p("10.10.12.0/24")},
|
||||
},
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"gorm.io/gorm"
|
||||
"tailscale.com/types/ptr"
|
||||
)
|
||||
|
||||
func TestNodeCanApproveRoute(t *testing.T) {
|
||||
@@ -24,34 +25,34 @@ func TestNodeCanApproveRoute(t *testing.T) {
|
||||
ID: 1,
|
||||
Hostname: "user1-device",
|
||||
IPv4: ap("100.64.0.1"),
|
||||
UserID: 1,
|
||||
User: users[0],
|
||||
UserID: ptr.To(uint(1)),
|
||||
User: ptr.To(users[0]),
|
||||
}
|
||||
|
||||
exitNode := types.Node{
|
||||
ID: 2,
|
||||
Hostname: "user2-device",
|
||||
IPv4: ap("100.64.0.2"),
|
||||
UserID: 2,
|
||||
User: users[1],
|
||||
UserID: ptr.To(uint(2)),
|
||||
User: ptr.To(users[1]),
|
||||
}
|
||||
|
||||
taggedNode := types.Node{
|
||||
ID: 3,
|
||||
Hostname: "tagged-server",
|
||||
IPv4: ap("100.64.0.3"),
|
||||
UserID: 3,
|
||||
User: users[2],
|
||||
ForcedTags: []string{"tag:router"},
|
||||
ID: 3,
|
||||
Hostname: "tagged-server",
|
||||
IPv4: ap("100.64.0.3"),
|
||||
UserID: ptr.To(uint(3)),
|
||||
User: ptr.To(users[2]),
|
||||
Tags: []string{"tag:router"},
|
||||
}
|
||||
|
||||
multiTagNode := types.Node{
|
||||
ID: 4,
|
||||
Hostname: "multi-tag-node",
|
||||
IPv4: ap("100.64.0.4"),
|
||||
UserID: 2,
|
||||
User: users[1],
|
||||
ForcedTags: []string{"tag:router", "tag:server"},
|
||||
ID: 4,
|
||||
Hostname: "multi-tag-node",
|
||||
IPv4: ap("100.64.0.4"),
|
||||
UserID: ptr.To(uint(2)),
|
||||
User: ptr.To(users[1]),
|
||||
Tags: []string{"tag:router", "tag:server"},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
|
||||
@@ -168,7 +168,7 @@ func (pol *Policy) compileACLWithAutogroupSelf(
|
||||
// Pre-filter to same-user untagged devices once - reuse for both sources and destinations
|
||||
sameUserNodes := make([]types.NodeView, 0)
|
||||
for _, n := range nodes.All() {
|
||||
if n.User().ID == node.User().ID && !n.IsTagged() {
|
||||
if n.User().ID() == node.User().ID() && !n.IsTagged() {
|
||||
sameUserNodes = append(sameUserNodes, n)
|
||||
}
|
||||
}
|
||||
@@ -349,7 +349,7 @@ func (pol *Policy) compileSSHPolicy(
|
||||
// Build destination set for autogroup:self (same-user untagged devices only)
|
||||
var dest netipx.IPSetBuilder
|
||||
for _, n := range nodes.All() {
|
||||
if n.User().ID == node.User().ID && !n.IsTagged() {
|
||||
if n.User().ID() == node.User().ID() && !n.IsTagged() {
|
||||
n.AppendToIPSet(&dest)
|
||||
}
|
||||
}
|
||||
@@ -365,7 +365,7 @@ func (pol *Policy) compileSSHPolicy(
|
||||
// Pre-filter to same-user untagged devices for efficiency
|
||||
sameUserNodes := make([]types.NodeView, 0)
|
||||
for _, n := range nodes.All() {
|
||||
if n.User().ID == node.User().ID && !n.IsTagged() {
|
||||
if n.User().ID() == node.User().ID() && !n.IsTagged() {
|
||||
sameUserNodes = append(sameUserNodes, n)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"gorm.io/gorm"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/ptr"
|
||||
)
|
||||
|
||||
// aliasWithPorts creates an AliasWithPorts structure from an alias and ports.
|
||||
@@ -381,7 +382,7 @@ func TestParsing(t *testing.T) {
|
||||
},
|
||||
&types.Node{
|
||||
IPv4: ap("200.200.200.200"),
|
||||
User: users[0],
|
||||
User: &users[0],
|
||||
Hostinfo: &tailcfg.Hostinfo{},
|
||||
},
|
||||
}.ViewSlice())
|
||||
@@ -409,14 +410,14 @@ func TestCompileSSHPolicy_UserMapping(t *testing.T) {
|
||||
nodeUser1 := types.Node{
|
||||
Hostname: "user1-device",
|
||||
IPv4: createAddr("100.64.0.1"),
|
||||
UserID: 1,
|
||||
User: users[0],
|
||||
UserID: ptr.To(users[0].ID),
|
||||
User: ptr.To(users[0]),
|
||||
}
|
||||
nodeUser2 := types.Node{
|
||||
Hostname: "user2-device",
|
||||
IPv4: createAddr("100.64.0.2"),
|
||||
UserID: 2,
|
||||
User: users[1],
|
||||
UserID: ptr.To(users[1].ID),
|
||||
User: ptr.To(users[1]),
|
||||
}
|
||||
|
||||
nodes := types.Nodes{&nodeUser1, &nodeUser2}
|
||||
@@ -621,14 +622,14 @@ func TestCompileSSHPolicy_CheckAction(t *testing.T) {
|
||||
nodeUser1 := types.Node{
|
||||
Hostname: "user1-device",
|
||||
IPv4: createAddr("100.64.0.1"),
|
||||
UserID: 1,
|
||||
User: users[0],
|
||||
UserID: ptr.To(users[0].ID),
|
||||
User: ptr.To(users[0]),
|
||||
}
|
||||
nodeUser2 := types.Node{
|
||||
Hostname: "user2-device",
|
||||
IPv4: createAddr("100.64.0.2"),
|
||||
UserID: 2,
|
||||
User: users[1],
|
||||
UserID: ptr.To(users[1].ID),
|
||||
User: ptr.To(users[1]),
|
||||
}
|
||||
|
||||
nodes := types.Nodes{&nodeUser1, &nodeUser2}
|
||||
@@ -682,15 +683,15 @@ func TestSSHIntegrationReproduction(t *testing.T) {
|
||||
node1 := &types.Node{
|
||||
Hostname: "user1-node",
|
||||
IPv4: createAddr("100.64.0.1"),
|
||||
UserID: 1,
|
||||
User: users[0],
|
||||
UserID: ptr.To(users[0].ID),
|
||||
User: ptr.To(users[0]),
|
||||
}
|
||||
|
||||
node2 := &types.Node{
|
||||
Hostname: "user2-node",
|
||||
IPv4: createAddr("100.64.0.2"),
|
||||
UserID: 2,
|
||||
User: users[1],
|
||||
UserID: ptr.To(users[1].ID),
|
||||
User: ptr.To(users[1]),
|
||||
}
|
||||
|
||||
nodes := types.Nodes{node1, node2}
|
||||
@@ -741,11 +742,12 @@ func TestSSHJSONSerialization(t *testing.T) {
|
||||
{Name: "user1", Model: gorm.Model{ID: 1}},
|
||||
}
|
||||
|
||||
uid := uint(1)
|
||||
node := &types.Node{
|
||||
Hostname: "test-node",
|
||||
IPv4: createAddr("100.64.0.1"),
|
||||
UserID: 1,
|
||||
User: users[0],
|
||||
UserID: &uid,
|
||||
User: &users[0],
|
||||
}
|
||||
|
||||
nodes := types.Nodes{node}
|
||||
@@ -804,32 +806,32 @@ func TestCompileFilterRulesForNodeWithAutogroupSelf(t *testing.T) {
|
||||
|
||||
nodes := types.Nodes{
|
||||
{
|
||||
User: users[0],
|
||||
User: ptr.To(users[0]),
|
||||
IPv4: ap("100.64.0.1"),
|
||||
},
|
||||
{
|
||||
User: users[0],
|
||||
User: ptr.To(users[0]),
|
||||
IPv4: ap("100.64.0.2"),
|
||||
},
|
||||
{
|
||||
User: users[1],
|
||||
User: ptr.To(users[1]),
|
||||
IPv4: ap("100.64.0.3"),
|
||||
},
|
||||
{
|
||||
User: users[1],
|
||||
User: ptr.To(users[1]),
|
||||
IPv4: ap("100.64.0.4"),
|
||||
},
|
||||
// Tagged device for user1
|
||||
{
|
||||
User: users[0],
|
||||
IPv4: ap("100.64.0.5"),
|
||||
ForcedTags: []string{"tag:test"},
|
||||
User: &users[0],
|
||||
IPv4: ap("100.64.0.5"),
|
||||
Tags: []string{"tag:test"},
|
||||
},
|
||||
// Tagged device for user2
|
||||
{
|
||||
User: users[1],
|
||||
IPv4: ap("100.64.0.6"),
|
||||
ForcedTags: []string{"tag:test"},
|
||||
User: &users[1],
|
||||
IPv4: ap("100.64.0.6"),
|
||||
Tags: []string{"tag:test"},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -925,6 +927,251 @@ func TestCompileFilterRulesForNodeWithAutogroupSelf(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestTagUserMutualExclusivity tests that user-owned nodes and tagged nodes
|
||||
// are treated as separate identity classes and cannot inadvertently access each other.
|
||||
func TestTagUserMutualExclusivity(t *testing.T) {
|
||||
users := types.Users{
|
||||
{Model: gorm.Model{ID: 1}, Name: "user1"},
|
||||
{Model: gorm.Model{ID: 2}, Name: "user2"},
|
||||
}
|
||||
|
||||
nodes := types.Nodes{
|
||||
// User-owned nodes
|
||||
{
|
||||
User: ptr.To(users[0]),
|
||||
IPv4: ap("100.64.0.1"),
|
||||
},
|
||||
{
|
||||
User: ptr.To(users[1]),
|
||||
IPv4: ap("100.64.0.2"),
|
||||
},
|
||||
// Tagged nodes
|
||||
{
|
||||
User: &users[0], // "created by" tracking
|
||||
IPv4: ap("100.64.0.10"),
|
||||
Tags: []string{"tag:server"},
|
||||
},
|
||||
{
|
||||
User: &users[1], // "created by" tracking
|
||||
IPv4: ap("100.64.0.11"),
|
||||
Tags: []string{"tag:database"},
|
||||
},
|
||||
}
|
||||
|
||||
policy := &Policy{
|
||||
TagOwners: TagOwners{
|
||||
Tag("tag:server"): Owners{ptr.To(Username("user1@"))},
|
||||
Tag("tag:database"): Owners{ptr.To(Username("user2@"))},
|
||||
},
|
||||
ACLs: []ACL{
|
||||
// Rule 1: user1 (user-owned) should NOT be able to reach tagged nodes
|
||||
{
|
||||
Action: "accept",
|
||||
Sources: []Alias{up("user1@")},
|
||||
Destinations: []AliasWithPorts{
|
||||
aliasWithPorts(tp("tag:server"), tailcfg.PortRangeAny),
|
||||
},
|
||||
},
|
||||
// Rule 2: tag:server should be able to reach tag:database
|
||||
{
|
||||
Action: "accept",
|
||||
Sources: []Alias{tp("tag:server")},
|
||||
Destinations: []AliasWithPorts{
|
||||
aliasWithPorts(tp("tag:database"), tailcfg.PortRangeAny),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := policy.validate()
|
||||
if err != nil {
|
||||
t.Fatalf("policy validation failed: %v", err)
|
||||
}
|
||||
|
||||
// Test user1's user-owned node (100.64.0.1)
|
||||
userNode := nodes[0].View()
|
||||
|
||||
userRules, err := policy.compileFilterRulesForNode(users, userNode, nodes.ViewSlice())
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error for user node: %v", err)
|
||||
}
|
||||
|
||||
// User1's user-owned node should NOT reach tag:server (100.64.0.10)
|
||||
// because user1@ as a source only matches user1's user-owned devices, NOT tagged devices
|
||||
for _, rule := range userRules {
|
||||
for _, dst := range rule.DstPorts {
|
||||
if dst.IP == "100.64.0.10" {
|
||||
t.Errorf("SECURITY: user-owned node should NOT reach tagged node (got dest %s in rule)", dst.IP)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test tag:server node (100.64.0.10)
|
||||
// compileFilterRulesForNode returns rules for what the node can ACCESS (as source)
|
||||
taggedNode := nodes[2].View()
|
||||
|
||||
taggedRules, err := policy.compileFilterRulesForNode(users, taggedNode, nodes.ViewSlice())
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error for tagged node: %v", err)
|
||||
}
|
||||
|
||||
// Tag:server (as source) should be able to reach tag:database (100.64.0.11)
|
||||
// Check destinations in the rules for this node
|
||||
foundDatabaseDest := false
|
||||
|
||||
for _, rule := range taggedRules {
|
||||
// Check if this rule applies to tag:server as source
|
||||
if !slices.Contains(rule.SrcIPs, "100.64.0.10/32") {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if tag:database is in destinations
|
||||
for _, dst := range rule.DstPorts {
|
||||
if dst.IP == "100.64.0.11/32" {
|
||||
foundDatabaseDest = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if foundDatabaseDest {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !foundDatabaseDest {
|
||||
t.Errorf("tag:server should reach tag:database but didn't find 100.64.0.11 in destinations")
|
||||
}
|
||||
}
|
||||
|
||||
// TestAutogroupTagged tests that autogroup:tagged correctly selects all devices
|
||||
// with tag-based identity (IsTagged() == true or has requested tags in tagOwners).
|
||||
func TestAutogroupTagged(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
users := types.Users{
|
||||
{Model: gorm.Model{ID: 1}, Name: "user1"},
|
||||
{Model: gorm.Model{ID: 2}, Name: "user2"},
|
||||
}
|
||||
|
||||
nodes := types.Nodes{
|
||||
// User-owned nodes (not tagged)
|
||||
{
|
||||
User: ptr.To(users[0]),
|
||||
IPv4: ap("100.64.0.1"),
|
||||
},
|
||||
{
|
||||
User: ptr.To(users[1]),
|
||||
IPv4: ap("100.64.0.2"),
|
||||
},
|
||||
// Tagged nodes
|
||||
{
|
||||
User: &users[0], // "created by" tracking
|
||||
IPv4: ap("100.64.0.10"),
|
||||
Tags: []string{"tag:server"},
|
||||
},
|
||||
{
|
||||
User: &users[1], // "created by" tracking
|
||||
IPv4: ap("100.64.0.11"),
|
||||
Tags: []string{"tag:database"},
|
||||
},
|
||||
{
|
||||
User: &users[0],
|
||||
IPv4: ap("100.64.0.12"),
|
||||
Tags: []string{"tag:web", "tag:prod"},
|
||||
},
|
||||
}
|
||||
|
||||
policy := &Policy{
|
||||
TagOwners: TagOwners{
|
||||
Tag("tag:server"): Owners{ptr.To(Username("user1@"))},
|
||||
Tag("tag:database"): Owners{ptr.To(Username("user2@"))},
|
||||
Tag("tag:web"): Owners{ptr.To(Username("user1@"))},
|
||||
Tag("tag:prod"): Owners{ptr.To(Username("user1@"))},
|
||||
},
|
||||
ACLs: []ACL{
|
||||
// Rule: autogroup:tagged can reach user-owned nodes
|
||||
{
|
||||
Action: "accept",
|
||||
Sources: []Alias{agp("autogroup:tagged")},
|
||||
Destinations: []AliasWithPorts{
|
||||
aliasWithPorts(up("user1@"), tailcfg.PortRangeAny),
|
||||
aliasWithPorts(up("user2@"), tailcfg.PortRangeAny),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
err := policy.validate()
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify autogroup:tagged includes all tagged nodes
|
||||
taggedIPs, err := AutoGroupTagged.Resolve(policy, users, nodes.ViewSlice())
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, taggedIPs)
|
||||
|
||||
// Should contain all tagged nodes
|
||||
assert.True(t, taggedIPs.Contains(*ap("100.64.0.10")), "should include tag:server")
|
||||
assert.True(t, taggedIPs.Contains(*ap("100.64.0.11")), "should include tag:database")
|
||||
assert.True(t, taggedIPs.Contains(*ap("100.64.0.12")), "should include tag:web,tag:prod")
|
||||
|
||||
// Should NOT contain user-owned nodes
|
||||
assert.False(t, taggedIPs.Contains(*ap("100.64.0.1")), "should not include user1 node")
|
||||
assert.False(t, taggedIPs.Contains(*ap("100.64.0.2")), "should not include user2 node")
|
||||
|
||||
// Test ACL filtering: all tagged nodes should be able to reach user nodes
|
||||
tests := []struct {
|
||||
name string
|
||||
sourceNode types.NodeView
|
||||
shouldReach []string // IP strings for comparison
|
||||
}{
|
||||
{
|
||||
name: "tag:server can reach user-owned nodes",
|
||||
sourceNode: nodes[2].View(),
|
||||
shouldReach: []string{"100.64.0.1", "100.64.0.2"},
|
||||
},
|
||||
{
|
||||
name: "tag:database can reach user-owned nodes",
|
||||
sourceNode: nodes[3].View(),
|
||||
shouldReach: []string{"100.64.0.1", "100.64.0.2"},
|
||||
},
|
||||
{
|
||||
name: "tag:web,tag:prod can reach user-owned nodes",
|
||||
sourceNode: nodes[4].View(),
|
||||
shouldReach: []string{"100.64.0.1", "100.64.0.2"},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
rules, err := policy.compileFilterRulesForNode(users, tt.sourceNode, nodes.ViewSlice())
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify all expected destinations are reachable
|
||||
for _, expectedDest := range tt.shouldReach {
|
||||
found := false
|
||||
|
||||
for _, rule := range rules {
|
||||
for _, dstPort := range rule.DstPorts {
|
||||
// DstPort.IP is CIDR notation like "100.64.0.1/32"
|
||||
if strings.HasPrefix(dstPort.IP, expectedDest+"/") || dstPort.IP == expectedDest {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if found {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
assert.True(t, found, "Expected to find destination %s in rules", expectedDest)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAutogroupSelfInSourceIsRejected(t *testing.T) {
|
||||
// Test that autogroup:self cannot be used in sources (per Tailscale spec)
|
||||
policy := &Policy{
|
||||
@@ -959,10 +1206,10 @@ func TestAutogroupSelfWithSpecificUserSource(t *testing.T) {
|
||||
}
|
||||
|
||||
nodes := types.Nodes{
|
||||
{User: users[0], IPv4: ap("100.64.0.1")},
|
||||
{User: users[0], IPv4: ap("100.64.0.2")},
|
||||
{User: users[1], IPv4: ap("100.64.0.3")},
|
||||
{User: users[1], IPv4: ap("100.64.0.4")},
|
||||
{User: ptr.To(users[0]), IPv4: ap("100.64.0.1")},
|
||||
{User: ptr.To(users[0]), IPv4: ap("100.64.0.2")},
|
||||
{User: ptr.To(users[1]), IPv4: ap("100.64.0.3")},
|
||||
{User: ptr.To(users[1]), IPv4: ap("100.64.0.4")},
|
||||
}
|
||||
|
||||
policy := &Policy{
|
||||
@@ -1026,11 +1273,11 @@ func TestAutogroupSelfWithGroupSource(t *testing.T) {
|
||||
}
|
||||
|
||||
nodes := types.Nodes{
|
||||
{User: users[0], IPv4: ap("100.64.0.1")},
|
||||
{User: users[0], IPv4: ap("100.64.0.2")},
|
||||
{User: users[1], IPv4: ap("100.64.0.3")},
|
||||
{User: users[1], IPv4: ap("100.64.0.4")},
|
||||
{User: users[2], IPv4: ap("100.64.0.5")},
|
||||
{User: ptr.To(users[0]), IPv4: ap("100.64.0.1")},
|
||||
{User: ptr.To(users[0]), IPv4: ap("100.64.0.2")},
|
||||
{User: ptr.To(users[1]), IPv4: ap("100.64.0.3")},
|
||||
{User: ptr.To(users[1]), IPv4: ap("100.64.0.4")},
|
||||
{User: ptr.To(users[2]), IPv4: ap("100.64.0.5")},
|
||||
}
|
||||
|
||||
policy := &Policy{
|
||||
@@ -1095,13 +1342,13 @@ func TestSSHWithAutogroupSelfInDestination(t *testing.T) {
|
||||
|
||||
nodes := types.Nodes{
|
||||
// User1's nodes
|
||||
{User: users[0], IPv4: ap("100.64.0.1"), Hostname: "user1-node1"},
|
||||
{User: users[0], IPv4: ap("100.64.0.2"), Hostname: "user1-node2"},
|
||||
{User: ptr.To(users[0]), IPv4: ap("100.64.0.1"), Hostname: "user1-node1"},
|
||||
{User: ptr.To(users[0]), IPv4: ap("100.64.0.2"), Hostname: "user1-node2"},
|
||||
// User2's nodes
|
||||
{User: users[1], IPv4: ap("100.64.0.3"), Hostname: "user2-node1"},
|
||||
{User: users[1], IPv4: ap("100.64.0.4"), Hostname: "user2-node2"},
|
||||
{User: ptr.To(users[1]), IPv4: ap("100.64.0.3"), Hostname: "user2-node1"},
|
||||
{User: ptr.To(users[1]), IPv4: ap("100.64.0.4"), Hostname: "user2-node2"},
|
||||
// Tagged node for user1 (should be excluded)
|
||||
{User: users[0], IPv4: ap("100.64.0.5"), Hostname: "user1-tagged", ForcedTags: []string{"tag:server"}},
|
||||
{User: ptr.To(users[0]), IPv4: ap("100.64.0.5"), Hostname: "user1-tagged", Tags: []string{"tag:server"}},
|
||||
}
|
||||
|
||||
policy := &Policy{
|
||||
@@ -1173,10 +1420,10 @@ func TestSSHWithAutogroupSelfAndSpecificUser(t *testing.T) {
|
||||
}
|
||||
|
||||
nodes := types.Nodes{
|
||||
{User: users[0], IPv4: ap("100.64.0.1")},
|
||||
{User: users[0], IPv4: ap("100.64.0.2")},
|
||||
{User: users[1], IPv4: ap("100.64.0.3")},
|
||||
{User: users[1], IPv4: ap("100.64.0.4")},
|
||||
{User: ptr.To(users[0]), IPv4: ap("100.64.0.1")},
|
||||
{User: ptr.To(users[0]), IPv4: ap("100.64.0.2")},
|
||||
{User: ptr.To(users[1]), IPv4: ap("100.64.0.3")},
|
||||
{User: ptr.To(users[1]), IPv4: ap("100.64.0.4")},
|
||||
}
|
||||
|
||||
policy := &Policy{
|
||||
@@ -1227,11 +1474,11 @@ func TestSSHWithAutogroupSelfAndGroup(t *testing.T) {
|
||||
}
|
||||
|
||||
nodes := types.Nodes{
|
||||
{User: users[0], IPv4: ap("100.64.0.1")},
|
||||
{User: users[0], IPv4: ap("100.64.0.2")},
|
||||
{User: users[1], IPv4: ap("100.64.0.3")},
|
||||
{User: users[1], IPv4: ap("100.64.0.4")},
|
||||
{User: users[2], IPv4: ap("100.64.0.5")},
|
||||
{User: ptr.To(users[0]), IPv4: ap("100.64.0.1")},
|
||||
{User: ptr.To(users[0]), IPv4: ap("100.64.0.2")},
|
||||
{User: ptr.To(users[1]), IPv4: ap("100.64.0.3")},
|
||||
{User: ptr.To(users[1]), IPv4: ap("100.64.0.4")},
|
||||
{User: ptr.To(users[2]), IPv4: ap("100.64.0.5")},
|
||||
}
|
||||
|
||||
policy := &Policy{
|
||||
@@ -1284,10 +1531,10 @@ func TestSSHWithAutogroupSelfExcludesTaggedDevices(t *testing.T) {
|
||||
}
|
||||
|
||||
nodes := types.Nodes{
|
||||
{User: users[0], IPv4: ap("100.64.0.1"), Hostname: "untagged1"},
|
||||
{User: users[0], IPv4: ap("100.64.0.2"), Hostname: "untagged2"},
|
||||
{User: users[0], IPv4: ap("100.64.0.3"), Hostname: "tagged1", ForcedTags: []string{"tag:server"}},
|
||||
{User: users[0], IPv4: ap("100.64.0.4"), Hostname: "tagged2", ForcedTags: []string{"tag:web"}},
|
||||
{User: ptr.To(users[0]), IPv4: ap("100.64.0.1"), Hostname: "untagged1"},
|
||||
{User: ptr.To(users[0]), IPv4: ap("100.64.0.2"), Hostname: "untagged2"},
|
||||
{User: ptr.To(users[0]), IPv4: ap("100.64.0.3"), Hostname: "tagged1", Tags: []string{"tag:server"}},
|
||||
{User: ptr.To(users[0]), IPv4: ap("100.64.0.4"), Hostname: "tagged2", Tags: []string{"tag:web"}},
|
||||
}
|
||||
|
||||
policy := &Policy{
|
||||
@@ -1344,10 +1591,10 @@ func TestSSHWithAutogroupSelfAndMixedDestinations(t *testing.T) {
|
||||
}
|
||||
|
||||
nodes := types.Nodes{
|
||||
{User: users[0], IPv4: ap("100.64.0.1"), Hostname: "user1-device"},
|
||||
{User: users[0], IPv4: ap("100.64.0.2"), Hostname: "user1-device2"},
|
||||
{User: users[1], IPv4: ap("100.64.0.3"), Hostname: "user2-device"},
|
||||
{User: users[1], IPv4: ap("100.64.0.4"), Hostname: "user2-router", ForcedTags: []string{"tag:router"}},
|
||||
{User: ptr.To(users[0]), IPv4: ap("100.64.0.1"), Hostname: "user1-device"},
|
||||
{User: ptr.To(users[0]), IPv4: ap("100.64.0.2"), Hostname: "user1-device2"},
|
||||
{User: ptr.To(users[1]), IPv4: ap("100.64.0.3"), Hostname: "user2-device"},
|
||||
{User: ptr.To(users[1]), IPv4: ap("100.64.0.4"), Hostname: "user2-router", Tags: []string{"tag:router"}},
|
||||
}
|
||||
|
||||
policy := &Policy{
|
||||
|
||||
@@ -697,14 +697,14 @@ func (pm *PolicyManager) invalidateAutogroupSelfCache(oldNodes, newNodes views.S
|
||||
// Check for removed nodes
|
||||
for nodeID, oldNode := range oldNodeMap {
|
||||
if _, exists := newNodeMap[nodeID]; !exists {
|
||||
affectedUsers[oldNode.User().ID] = struct{}{}
|
||||
affectedUsers[oldNode.User().ID()] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for added nodes
|
||||
for nodeID, newNode := range newNodeMap {
|
||||
if _, exists := oldNodeMap[nodeID]; !exists {
|
||||
affectedUsers[newNode.User().ID] = struct{}{}
|
||||
affectedUsers[newNode.User().ID()] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -712,26 +712,26 @@ func (pm *PolicyManager) invalidateAutogroupSelfCache(oldNodes, newNodes views.S
|
||||
for nodeID, newNode := range newNodeMap {
|
||||
if oldNode, exists := oldNodeMap[nodeID]; exists {
|
||||
// Check if user changed
|
||||
if oldNode.User().ID != newNode.User().ID {
|
||||
affectedUsers[oldNode.User().ID] = struct{}{}
|
||||
affectedUsers[newNode.User().ID] = struct{}{}
|
||||
if oldNode.User().ID() != newNode.User().ID() {
|
||||
affectedUsers[oldNode.User().ID()] = struct{}{}
|
||||
affectedUsers[newNode.User().ID()] = struct{}{}
|
||||
}
|
||||
|
||||
// Check if tag status changed
|
||||
if oldNode.IsTagged() != newNode.IsTagged() {
|
||||
affectedUsers[newNode.User().ID] = struct{}{}
|
||||
affectedUsers[newNode.User().ID()] = struct{}{}
|
||||
}
|
||||
|
||||
// Check if IPs changed (simple check - could be more sophisticated)
|
||||
oldIPs := oldNode.IPs()
|
||||
newIPs := newNode.IPs()
|
||||
if len(oldIPs) != len(newIPs) {
|
||||
affectedUsers[newNode.User().ID] = struct{}{}
|
||||
affectedUsers[newNode.User().ID()] = struct{}{}
|
||||
} else {
|
||||
// Check if any IPs are different
|
||||
for i, oldIP := range oldIPs {
|
||||
if i >= len(newIPs) || oldIP != newIPs[i] {
|
||||
affectedUsers[newNode.User().ID] = struct{}{}
|
||||
affectedUsers[newNode.User().ID()] = struct{}{}
|
||||
break
|
||||
}
|
||||
}
|
||||
@@ -750,7 +750,7 @@ func (pm *PolicyManager) invalidateAutogroupSelfCache(oldNodes, newNodes views.S
|
||||
// Check in new nodes first
|
||||
for _, node := range newNodes.All() {
|
||||
if node.ID() == nodeID {
|
||||
nodeUserID = node.User().ID
|
||||
nodeUserID = node.User().ID()
|
||||
found = true
|
||||
break
|
||||
}
|
||||
@@ -760,7 +760,7 @@ func (pm *PolicyManager) invalidateAutogroupSelfCache(oldNodes, newNodes views.S
|
||||
if !found {
|
||||
for _, node := range oldNodes.All() {
|
||||
if node.ID() == nodeID {
|
||||
nodeUserID = node.User().ID
|
||||
nodeUserID = node.User().ID()
|
||||
found = true
|
||||
break
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
"gorm.io/gorm"
|
||||
"tailscale.com/tailcfg"
|
||||
"tailscale.com/types/ptr"
|
||||
)
|
||||
|
||||
func node(name, ipv4, ipv6 string, user types.User, hostinfo *tailcfg.Hostinfo) *types.Node {
|
||||
@@ -19,8 +20,8 @@ func node(name, ipv4, ipv6 string, user types.User, hostinfo *tailcfg.Hostinfo)
|
||||
Hostname: name,
|
||||
IPv4: ap(ipv4),
|
||||
IPv6: ap(ipv6),
|
||||
User: user,
|
||||
UserID: user.ID,
|
||||
User: ptr.To(user),
|
||||
UserID: ptr.To(user.ID),
|
||||
Hostinfo: hostinfo,
|
||||
}
|
||||
}
|
||||
@@ -456,8 +457,8 @@ func TestAutogroupSelfWithOtherRules(t *testing.T) {
|
||||
Hostname: "test-1-device",
|
||||
IPv4: ap("100.64.0.1"),
|
||||
IPv6: ap("fd7a:115c:a1e0::1"),
|
||||
User: users[0],
|
||||
UserID: users[0].ID,
|
||||
User: ptr.To(users[0]),
|
||||
UserID: ptr.To(users[0].ID),
|
||||
Hostinfo: &tailcfg.Hostinfo{},
|
||||
}
|
||||
|
||||
@@ -467,9 +468,9 @@ func TestAutogroupSelfWithOtherRules(t *testing.T) {
|
||||
Hostname: "test-2-router",
|
||||
IPv4: ap("100.64.0.2"),
|
||||
IPv6: ap("fd7a:115c:a1e0::2"),
|
||||
User: users[1],
|
||||
UserID: users[1].ID,
|
||||
ForcedTags: []string{"tag:node-router"},
|
||||
User: ptr.To(users[1]),
|
||||
UserID: ptr.To(users[1].ID),
|
||||
Tags: []string{"tag:node-router"},
|
||||
Hostinfo: &tailcfg.Hostinfo{},
|
||||
}
|
||||
|
||||
|
||||
@@ -206,7 +206,12 @@ func (u Username) Resolve(_ *Policy, users types.Users, nodes views.Slice[types.
|
||||
continue
|
||||
}
|
||||
|
||||
if node.User().ID == user.ID {
|
||||
// Skip nodes without a user (defensive check for tests)
|
||||
if !node.User().Valid() {
|
||||
continue
|
||||
}
|
||||
|
||||
if node.User().ID() == user.ID {
|
||||
node.AppendToIPSet(&ips)
|
||||
}
|
||||
}
|
||||
@@ -311,8 +316,8 @@ func (t Tag) Resolve(p *Policy, users types.Users, nodes views.Slice[types.NodeV
|
||||
}
|
||||
|
||||
for _, node := range nodes.All() {
|
||||
// Check if node has this tag in all tags (ForcedTags + AuthKey.Tags)
|
||||
if slices.Contains(node.Tags(), string(t)) {
|
||||
// Check if node has this tag
|
||||
if node.HasTag(string(t)) {
|
||||
node.AppendToIPSet(&ips)
|
||||
}
|
||||
|
||||
|
||||
@@ -1549,7 +1549,17 @@ func TestResolvePolicy(t *testing.T) {
|
||||
"groupuser1": {Model: gorm.Model{ID: 3}, Name: "groupuser1"},
|
||||
"groupuser2": {Model: gorm.Model{ID: 4}, Name: "groupuser2"},
|
||||
"notme": {Model: gorm.Model{ID: 5}, Name: "notme"},
|
||||
"testuser2": {Model: gorm.Model{ID: 6}, Name: "testuser2"},
|
||||
}
|
||||
|
||||
// Extract users to variables so we can take their addresses
|
||||
testuser := users["testuser"]
|
||||
groupuser := users["groupuser"]
|
||||
groupuser1 := users["groupuser1"]
|
||||
groupuser2 := users["groupuser2"]
|
||||
notme := users["notme"]
|
||||
testuser2 := users["testuser2"]
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
nodes types.Nodes
|
||||
@@ -1579,29 +1589,27 @@ func TestResolvePolicy(t *testing.T) {
|
||||
nodes: types.Nodes{
|
||||
// Not matching other user
|
||||
{
|
||||
User: users["notme"],
|
||||
User: ptr.To(notme),
|
||||
IPv4: ap("100.100.101.1"),
|
||||
},
|
||||
// Not matching forced tags
|
||||
{
|
||||
User: users["testuser"],
|
||||
ForcedTags: []string{"tag:anything"},
|
||||
User: ptr.To(testuser),
|
||||
Tags: []string{"tag:anything"},
|
||||
IPv4: ap("100.100.101.2"),
|
||||
},
|
||||
// not matching pak tag
|
||||
// not matching because it's tagged (tags copied from AuthKey)
|
||||
{
|
||||
User: users["testuser"],
|
||||
AuthKey: &types.PreAuthKey{
|
||||
Tags: []string{"alsotagged"},
|
||||
},
|
||||
User: ptr.To(testuser),
|
||||
Tags: []string{"alsotagged"},
|
||||
IPv4: ap("100.100.101.3"),
|
||||
},
|
||||
{
|
||||
User: users["testuser"],
|
||||
User: ptr.To(testuser),
|
||||
IPv4: ap("100.100.101.103"),
|
||||
},
|
||||
{
|
||||
User: users["testuser"],
|
||||
User: ptr.To(testuser),
|
||||
IPv4: ap("100.100.101.104"),
|
||||
},
|
||||
},
|
||||
@@ -1613,29 +1621,27 @@ func TestResolvePolicy(t *testing.T) {
|
||||
nodes: types.Nodes{
|
||||
// Not matching other user
|
||||
{
|
||||
User: users["notme"],
|
||||
User: ptr.To(notme),
|
||||
IPv4: ap("100.100.101.4"),
|
||||
},
|
||||
// Not matching forced tags
|
||||
{
|
||||
User: users["groupuser"],
|
||||
ForcedTags: []string{"tag:anything"},
|
||||
User: ptr.To(groupuser),
|
||||
Tags: []string{"tag:anything"},
|
||||
IPv4: ap("100.100.101.5"),
|
||||
},
|
||||
// not matching pak tag
|
||||
// not matching because it's tagged (tags copied from AuthKey)
|
||||
{
|
||||
User: users["groupuser"],
|
||||
AuthKey: &types.PreAuthKey{
|
||||
Tags: []string{"tag:alsotagged"},
|
||||
},
|
||||
User: ptr.To(groupuser),
|
||||
Tags: []string{"tag:alsotagged"},
|
||||
IPv4: ap("100.100.101.6"),
|
||||
},
|
||||
{
|
||||
User: users["groupuser"],
|
||||
User: ptr.To(groupuser),
|
||||
IPv4: ap("100.100.101.203"),
|
||||
},
|
||||
{
|
||||
User: users["groupuser"],
|
||||
User: ptr.To(groupuser),
|
||||
IPv4: ap("100.100.101.204"),
|
||||
},
|
||||
},
|
||||
@@ -1653,12 +1659,12 @@ func TestResolvePolicy(t *testing.T) {
|
||||
nodes: types.Nodes{
|
||||
// Not matching other user
|
||||
{
|
||||
User: users["notme"],
|
||||
User: ptr.To(notme),
|
||||
IPv4: ap("100.100.101.9"),
|
||||
},
|
||||
// Not matching forced tags
|
||||
{
|
||||
ForcedTags: []string{"tag:anything"},
|
||||
Tags: []string{"tag:anything"},
|
||||
IPv4: ap("100.100.101.10"),
|
||||
},
|
||||
// not matching pak tag
|
||||
@@ -1670,14 +1676,12 @@ func TestResolvePolicy(t *testing.T) {
|
||||
},
|
||||
// Not matching forced tags
|
||||
{
|
||||
ForcedTags: []string{"tag:test"},
|
||||
Tags: []string{"tag:test"},
|
||||
IPv4: ap("100.100.101.234"),
|
||||
},
|
||||
// not matching pak tag
|
||||
// matching tag (tags copied from AuthKey during registration)
|
||||
{
|
||||
AuthKey: &types.PreAuthKey{
|
||||
Tags: []string{"tag:test"},
|
||||
},
|
||||
Tags: []string{"tag:test"},
|
||||
IPv4: ap("100.100.101.239"),
|
||||
},
|
||||
},
|
||||
@@ -1706,11 +1710,11 @@ func TestResolvePolicy(t *testing.T) {
|
||||
toResolve: ptr.To(Group("group:testgroup")),
|
||||
nodes: types.Nodes{
|
||||
{
|
||||
User: users["groupuser1"],
|
||||
User: ptr.To(groupuser1),
|
||||
IPv4: ap("100.100.101.203"),
|
||||
},
|
||||
{
|
||||
User: users["groupuser2"],
|
||||
User: ptr.To(groupuser2),
|
||||
IPv4: ap("100.100.101.204"),
|
||||
},
|
||||
},
|
||||
@@ -1731,7 +1735,7 @@ func TestResolvePolicy(t *testing.T) {
|
||||
toResolve: ptr.To(Username("invaliduser@")),
|
||||
nodes: types.Nodes{
|
||||
{
|
||||
User: users["testuser"],
|
||||
User: ptr.To(testuser),
|
||||
IPv4: ap("100.100.101.103"),
|
||||
},
|
||||
},
|
||||
@@ -1742,7 +1746,7 @@ func TestResolvePolicy(t *testing.T) {
|
||||
toResolve: tp("tag:invalid"),
|
||||
nodes: types.Nodes{
|
||||
{
|
||||
ForcedTags: []string{"tag:test"},
|
||||
Tags: []string{"tag:test"},
|
||||
IPv4: ap("100.100.101.234"),
|
||||
},
|
||||
},
|
||||
@@ -1763,18 +1767,18 @@ func TestResolvePolicy(t *testing.T) {
|
||||
nodes: types.Nodes{
|
||||
// Node with no tags (should be included)
|
||||
{
|
||||
User: users["testuser"],
|
||||
User: ptr.To(testuser),
|
||||
IPv4: ap("100.100.101.1"),
|
||||
},
|
||||
// Node with forced tags (should be excluded)
|
||||
{
|
||||
User: users["testuser"],
|
||||
ForcedTags: []string{"tag:test"},
|
||||
User: ptr.To(testuser),
|
||||
Tags: []string{"tag:test"},
|
||||
IPv4: ap("100.100.101.2"),
|
||||
},
|
||||
// Node with allowed requested tag (should be excluded)
|
||||
{
|
||||
User: users["testuser"],
|
||||
User: ptr.To(testuser),
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RequestTags: []string{"tag:test"},
|
||||
},
|
||||
@@ -1782,7 +1786,7 @@ func TestResolvePolicy(t *testing.T) {
|
||||
},
|
||||
// Node with non-allowed requested tag (should be included)
|
||||
{
|
||||
User: users["testuser"],
|
||||
User: ptr.To(testuser),
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RequestTags: []string{"tag:notallowed"},
|
||||
},
|
||||
@@ -1790,7 +1794,7 @@ func TestResolvePolicy(t *testing.T) {
|
||||
},
|
||||
// Node with multiple requested tags, one allowed (should be excluded)
|
||||
{
|
||||
User: users["testuser"],
|
||||
User: ptr.To(testuser),
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RequestTags: []string{"tag:test", "tag:notallowed"},
|
||||
},
|
||||
@@ -1798,7 +1802,7 @@ func TestResolvePolicy(t *testing.T) {
|
||||
},
|
||||
// Node with multiple requested tags, none allowed (should be included)
|
||||
{
|
||||
User: users["testuser"],
|
||||
User: ptr.To(testuser),
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RequestTags: []string{"tag:notallowed1", "tag:notallowed2"},
|
||||
},
|
||||
@@ -1822,18 +1826,18 @@ func TestResolvePolicy(t *testing.T) {
|
||||
nodes: types.Nodes{
|
||||
// Node with no tags (should be excluded)
|
||||
{
|
||||
User: users["testuser"],
|
||||
User: ptr.To(testuser),
|
||||
IPv4: ap("100.100.101.1"),
|
||||
},
|
||||
// Node with forced tag (should be included)
|
||||
{
|
||||
User: users["testuser"],
|
||||
ForcedTags: []string{"tag:test"},
|
||||
User: ptr.To(testuser),
|
||||
Tags: []string{"tag:test"},
|
||||
IPv4: ap("100.100.101.2"),
|
||||
},
|
||||
// Node with allowed requested tag (should be included)
|
||||
{
|
||||
User: users["testuser"],
|
||||
User: ptr.To(testuser),
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RequestTags: []string{"tag:test"},
|
||||
},
|
||||
@@ -1841,7 +1845,7 @@ func TestResolvePolicy(t *testing.T) {
|
||||
},
|
||||
// Node with non-allowed requested tag (should be excluded)
|
||||
{
|
||||
User: users["testuser"],
|
||||
User: ptr.To(testuser),
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RequestTags: []string{"tag:notallowed"},
|
||||
},
|
||||
@@ -1849,7 +1853,7 @@ func TestResolvePolicy(t *testing.T) {
|
||||
},
|
||||
// Node with multiple requested tags, one allowed (should be included)
|
||||
{
|
||||
User: users["testuser"],
|
||||
User: ptr.To(testuser),
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RequestTags: []string{"tag:test", "tag:notallowed"},
|
||||
},
|
||||
@@ -1857,7 +1861,7 @@ func TestResolvePolicy(t *testing.T) {
|
||||
},
|
||||
// Node with multiple requested tags, none allowed (should be excluded)
|
||||
{
|
||||
User: users["testuser"],
|
||||
User: ptr.To(testuser),
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RequestTags: []string{"tag:notallowed1", "tag:notallowed2"},
|
||||
},
|
||||
@@ -1865,8 +1869,8 @@ func TestResolvePolicy(t *testing.T) {
|
||||
},
|
||||
// Node with multiple forced tags (should be included)
|
||||
{
|
||||
User: users["testuser"],
|
||||
ForcedTags: []string{"tag:test", "tag:other"},
|
||||
User: ptr.To(testuser),
|
||||
Tags: []string{"tag:test", "tag:other"},
|
||||
IPv4: ap("100.100.101.7"),
|
||||
},
|
||||
},
|
||||
@@ -1886,20 +1890,20 @@ func TestResolvePolicy(t *testing.T) {
|
||||
toResolve: ptr.To(AutoGroupSelf),
|
||||
nodes: types.Nodes{
|
||||
{
|
||||
User: users["testuser"],
|
||||
User: ptr.To(testuser),
|
||||
IPv4: ap("100.100.101.1"),
|
||||
},
|
||||
{
|
||||
User: users["testuser2"],
|
||||
User: ptr.To(testuser2),
|
||||
IPv4: ap("100.100.101.2"),
|
||||
},
|
||||
{
|
||||
User: users["testuser"],
|
||||
ForcedTags: []string{"tag:test"},
|
||||
User: ptr.To(testuser),
|
||||
Tags: []string{"tag:test"},
|
||||
IPv4: ap("100.100.101.3"),
|
||||
},
|
||||
{
|
||||
User: users["testuser2"],
|
||||
User: ptr.To(testuser2),
|
||||
Hostinfo: &tailcfg.Hostinfo{
|
||||
RequestTags: []string{"tag:test"},
|
||||
},
|
||||
@@ -1961,23 +1965,23 @@ func TestResolveAutoApprovers(t *testing.T) {
|
||||
nodes := types.Nodes{
|
||||
{
|
||||
IPv4: ap("100.64.0.1"),
|
||||
User: users[0],
|
||||
User: &users[0],
|
||||
},
|
||||
{
|
||||
IPv4: ap("100.64.0.2"),
|
||||
User: users[1],
|
||||
User: &users[1],
|
||||
},
|
||||
{
|
||||
IPv4: ap("100.64.0.3"),
|
||||
User: users[2],
|
||||
User: &users[2],
|
||||
},
|
||||
{
|
||||
IPv4: ap("100.64.0.4"),
|
||||
ForcedTags: []string{"tag:testtag"},
|
||||
Tags: []string{"tag:testtag"},
|
||||
},
|
||||
{
|
||||
IPv4: ap("100.64.0.5"),
|
||||
ForcedTags: []string{"tag:exittest"},
|
||||
Tags: []string{"tag:exittest"},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2280,15 +2284,15 @@ func TestNodeCanApproveRoute(t *testing.T) {
|
||||
nodes := types.Nodes{
|
||||
{
|
||||
IPv4: ap("100.64.0.1"),
|
||||
User: users[0],
|
||||
User: &users[0],
|
||||
},
|
||||
{
|
||||
IPv4: ap("100.64.0.2"),
|
||||
User: users[1],
|
||||
User: &users[1],
|
||||
},
|
||||
{
|
||||
IPv4: ap("100.64.0.3"),
|
||||
User: users[2],
|
||||
User: &users[2],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2413,15 +2417,15 @@ func TestResolveTagOwners(t *testing.T) {
|
||||
nodes := types.Nodes{
|
||||
{
|
||||
IPv4: ap("100.64.0.1"),
|
||||
User: users[0],
|
||||
User: &users[0],
|
||||
},
|
||||
{
|
||||
IPv4: ap("100.64.0.2"),
|
||||
User: users[1],
|
||||
User: &users[1],
|
||||
},
|
||||
{
|
||||
IPv4: ap("100.64.0.3"),
|
||||
User: users[2],
|
||||
User: &users[2],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2498,15 +2502,15 @@ func TestNodeCanHaveTag(t *testing.T) {
|
||||
nodes := types.Nodes{
|
||||
{
|
||||
IPv4: ap("100.64.0.1"),
|
||||
User: users[0],
|
||||
User: &users[0],
|
||||
},
|
||||
{
|
||||
IPv4: ap("100.64.0.2"),
|
||||
User: users[1],
|
||||
User: &users[1],
|
||||
},
|
||||
{
|
||||
IPv4: ap("100.64.0.3"),
|
||||
User: users[2],
|
||||
User: &users[2],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -2580,6 +2584,49 @@ func TestNodeCanHaveTag(t *testing.T) {
|
||||
tag: "tag:test",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "node-with-unauthorized-tag-different-user",
|
||||
policy: &Policy{
|
||||
TagOwners: TagOwners{
|
||||
Tag("tag:prod"): Owners{ptr.To(Username("user1@"))},
|
||||
},
|
||||
},
|
||||
node: nodes[2], // user3's node
|
||||
tag: "tag:prod",
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "node-with-multiple-tags-one-unauthorized",
|
||||
policy: &Policy{
|
||||
TagOwners: TagOwners{
|
||||
Tag("tag:web"): Owners{ptr.To(Username("user1@"))},
|
||||
Tag("tag:database"): Owners{ptr.To(Username("user2@"))},
|
||||
},
|
||||
},
|
||||
node: nodes[0], // user1's node
|
||||
tag: "tag:database",
|
||||
want: false, // user1 cannot have tag:database (owned by user2)
|
||||
},
|
||||
{
|
||||
name: "empty-tagowners-map",
|
||||
policy: &Policy{
|
||||
TagOwners: TagOwners{},
|
||||
},
|
||||
node: nodes[0],
|
||||
tag: "tag:test",
|
||||
want: false, // No one can have tags if tagOwners is empty
|
||||
},
|
||||
{
|
||||
name: "tag-not-in-tagowners",
|
||||
policy: &Policy{
|
||||
TagOwners: TagOwners{
|
||||
Tag("tag:prod"): Owners{ptr.To(Username("user1@"))},
|
||||
},
|
||||
},
|
||||
node: nodes[0],
|
||||
tag: "tag:dev", // This tag is not defined in tagOwners
|
||||
want: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
|
||||
Reference in New Issue
Block a user