From ca9aa202559c9c3f94da5a4115fc6caf6c377e9f Mon Sep 17 00:00:00 2001 From: Gesa Stupperich Date: Thu, 19 Mar 2026 21:46:55 +0000 Subject: [PATCH] ipn/ipnlocal: populate Groups field in profileFromView This populates UserProfile.Groups in the WhoIs response from the local backend with the groups of the corresponding user in the netmap. This allows tsnet apps to see (and e.g. forward) which groups a user making a request belongs to - as long as the tsnet app runs on a node that been granted the tailscale.com/visible-groups capability via node attributes. If that's not the case or the user doesn't belong to any groups allow-listed via the node attribute, Groups won't be populated. Updates tailscale/corp#31529 Signed-off-by: Gesa Stupperich --- ipn/ipnlocal/local.go | 1 + ipn/ipnlocal/local_test.go | 21 +++++++++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/ipn/ipnlocal/local.go b/ipn/ipnlocal/local.go index 969e4433a..915e6ddd7 100644 --- a/ipn/ipnlocal/local.go +++ b/ipn/ipnlocal/local.go @@ -1473,6 +1473,7 @@ func profileFromView(v tailcfg.UserProfileView) tailcfg.UserProfile { LoginName: v.LoginName(), DisplayName: v.DisplayName(), ProfilePicURL: v.ProfilePicURL(), + Groups: v.Groups().AsSlice(), } } return tailcfg.UserProfile{} diff --git a/ipn/ipnlocal/local_test.go b/ipn/ipnlocal/local_test.go index b9d8da046..544bc60ad 100644 --- a/ipn/ipnlocal/local_test.go +++ b/ipn/ipnlocal/local_test.go @@ -2070,19 +2070,21 @@ func TestWhoIs(t *testing.T) { }).View(), 20: (&tailcfg.UserProfile{ DisplayName: "Peer", + Groups: []string{"group:foo"}, }).View(), }, }) tests := []struct { - q string - want tailcfg.NodeID // 0 means want ok=false - wantName string + q string + want tailcfg.NodeID // 0 means want ok=false + wantName string + wantGroups []string }{ - {"100.101.102.103:0", 1, "Myself"}, - {"100.101.102.103:123", 1, "Myself"}, - {"100.200.200.200:0", 2, "Peer"}, - {"100.200.200.200:123", 2, "Peer"}, - {"100.4.0.4:404", 0, ""}, + {"100.101.102.103:0", 1, "Myself", nil}, + {"100.101.102.103:123", 1, "Myself", nil}, + {"100.200.200.200:0", 2, "Peer", []string{"group:foo"}}, + {"100.200.200.200:123", 2, "Peer", []string{"group:foo"}}, + {"100.4.0.4:404", 0, "", nil}, } for _, tt := range tests { t.Run(tt.q, func(t *testing.T) { @@ -2097,6 +2099,9 @@ func TestWhoIs(t *testing.T) { if up.DisplayName != tt.wantName { t.Errorf("got name %q; want %q", up.DisplayName, tt.wantName) } + if !slices.Equal(up.Groups, tt.wantGroups) { + t.Errorf("got groups %q; want %q", up.Groups, tt.wantGroups) + } }) } }