ipn/ipnlocal: fix 'tailscale status --peers=false' missing user profile

Fixes #19894

Change-Id: I310504987170e0742480c8a02706eb0dbf4ec3dc
Signed-off-by: Brad Fitzpatrick <bradfitz@tailscale.com>
This commit is contained in:
Brad Fitzpatrick
2026-05-31 20:34:43 -07:00
committed by Brad Fitzpatrick
parent 3ef42d8b0b
commit 2ba426802f
2 changed files with 47 additions and 0 deletions
+9
View File
@@ -1514,6 +1514,15 @@ func (b *LocalBackend) updateStatusLocked(sb *ipnstate.StatusBuilder) {
// TODO: hostinfo, and its networkinfo
// TODO: EngineStatus copy (and deprecate it?)
// Always add the self user's profile, even when peers are omitted, so that
// callers can resolve the self node's owner to a login name.
// See https://github.com/tailscale/tailscale/issues/19894.
if nm != nil {
if up, ok := nm.UserProfiles[nm.User()]; ok {
sb.AddUser(nm.User(), up)
}
}
if sb.WantPeers {
b.populatePeerStatusLocked(sb)
}
+38
View File
@@ -2025,6 +2025,44 @@ func TestStatusPeerCapabilities(t *testing.T) {
}
}
// TestStatusWithoutPeersSelfUserProfile verifies that the self user's
// UserProfile is reported in Status.User even when peers are omitted, so that
// callers like `tailscale status --peers=false` can resolve the self node's
// owner to a login name rather than a bare user ID.
// Regression test for https://github.com/tailscale/tailscale/issues/19894.
func TestStatusWithoutPeersSelfUserProfile(t *testing.T) {
b := newTestLocalBackend(t)
const selfUID = tailcfg.UserID(42)
const loginName = "alice@example.com"
b.setNetMapLocked(&netmap.NetworkMap{
SelfNode: (&tailcfg.Node{
MachineAuthorized: true,
Addresses: ipps("100.101.101.101"),
User: selfUID,
}).View(),
UserProfiles: map[tailcfg.UserID]tailcfg.UserProfileView{
selfUID: (&tailcfg.UserProfile{
ID: selfUID,
LoginName: loginName,
}).View(),
},
})
st := b.StatusWithoutPeers()
if st.Self == nil {
t.Fatal("Status.Self is nil")
}
if got, want := st.Self.UserID, selfUID; got != want {
t.Errorf("Status.Self.UserID = %v; want %v", got, want)
}
up, ok := st.User[selfUID]
if !ok {
t.Fatalf("Status.User missing entry for self UserID %v; got %v", selfUID, st.User)
}
if got, want := up.LoginName, loginName; got != want {
t.Errorf("Status.User[%v].LoginName = %q; want %q", selfUID, got, want)
}
}
// legacyBackend was the interface between Tailscale frontends
// (e.g. cmd/tailscale, iOS/MacOS/Windows GUIs) and the tailscale
// backend (e.g. cmd/tailscaled) running on the same machine.