(WIP) Migrate active_profile

This commit is contained in:
Theodor S. Midtlien
2026-09-16 10:50:56 +02:00
parent 684820c09e
commit dadcffaec1
10 changed files with 423 additions and 208 deletions
+42 -26
View File
@@ -2,6 +2,7 @@ package server
import (
"context"
"os"
"path/filepath"
"testing"
"time"
@@ -69,6 +70,7 @@ func TestLogout_OtherProfileStaysGatedWhenProfilesDisabled(t *testing.T) {
_, err := profilemanager.UpdateOrCreateConfig(profilemanager.ConfigInput{
ConfigPath: filepath.Join(profilemanager.DefaultConfigPathDir, other+".json"),
ManagementURL: unreachableManagementURL,
Owner: testProfileOwner(),
})
require.NoError(t, err)
@@ -86,28 +88,18 @@ func TestLogout_OtherProfileStaysGatedWhenProfilesDisabled(t *testing.T) {
// A legacy profile ID is a display name, so two users can hold the same ID in
// their own profile directories. Matching on the ID alone would let one user's
// logout pass the gate against the other user's active profile, so the username
// is part of the comparison.
// logout pass the gate against the other user's active profile, so the config
// file, not the ID, decides which profile is the active one.
func TestLogout_ForeignUserProfileStaysGatedWhenProfilesDisabled(t *testing.T) {
s, _, _, username, _ := setupServerWithProfile(t)
s.rootCtx = internal.CtxInitState(context.Background())
// A legacy-style profile whose ID is its filename stem, and an active state
// claiming that same ID for a different user.
shared := "shared-legacy-name"
_, err := profilemanager.UpdateOrCreateConfig(profilemanager.ConfigInput{
ConfigPath: filepath.Join(profilemanager.DefaultConfigPathDir, shared+".json"),
ManagementURL: unreachableManagementURL,
})
require.NoError(t, err)
require.NoError(t, s.profileManager.SetActiveProfileState(&profilemanager.ActiveProfileState{
ID: profilemanager.ID(shared),
Username: "someone-else",
}))
plantNamesakeProfiles(t, s, shared)
s.profilesDisabled = true
_, err = s.Logout(userCtx(), &proto.LogoutRequest{
_, err := s.Logout(userCtx(), &proto.LogoutRequest{
ProfileName: &shared,
Username: &username,
})
@@ -117,6 +109,35 @@ func TestLogout_ForeignUserProfileStaysGatedWhenProfilesDisabled(t *testing.T) {
"another user's profile must not pass the gate on an ID match alone: %v", err)
}
// plantNamesakeProfiles creates two profiles that share one legacy ID: the
// caller's own, and another user's in that user's legacy profile directory,
// which is the one made active. Only the caller's copy carries an owner, so
// that is the one a handle resolves to, while the active profile stays the
// other file.
func plantNamesakeProfiles(t *testing.T, s *Server, id string) {
t.Helper()
foreignDir := filepath.Join(profilemanager.DefaultConfigPathDir, "someone-else")
require.NoError(t, os.MkdirAll(foreignDir, 0700))
_, err := profilemanager.UpdateOrCreateConfig(profilemanager.ConfigInput{
ConfigPath: filepath.Join(foreignDir, id+".json"),
ManagementURL: unreachableManagementURL,
})
require.NoError(t, err)
_, err = profilemanager.UpdateOrCreateConfig(profilemanager.ConfigInput{
ConfigPath: filepath.Join(profilemanager.DefaultConfigPathDir, id+".json"),
ManagementURL: unreachableManagementURL,
Owner: testProfileOwner(),
})
require.NoError(t, err)
require.NoError(t, s.profileManager.SetActiveProfileState(&profilemanager.ActiveProfileState{
ID: profilemanager.ID(id),
Username: "someone-else",
}))
}
// Deregistering a namesake profile must not go out with the running config.
// logoutFromProfile reuses the connected client's config when the target is the
// active profile, and on an ID-only match a shared legacy ID made it reuse it
@@ -135,15 +156,7 @@ func TestLogout_ForeignUserProfileDoesNotUseTheRunningConfig(t *testing.T) {
s.connectClient = newDummyConnectClient(context.Background())
shared := "shared-legacy-name"
_, err = profilemanager.UpdateOrCreateConfig(profilemanager.ConfigInput{
ConfigPath: filepath.Join(profilemanager.DefaultConfigPathDir, shared+".json"),
ManagementURL: unreachableManagementURL,
})
require.NoError(t, err)
require.NoError(t, s.profileManager.SetActiveProfileState(&profilemanager.ActiveProfileState{
ID: profilemanager.ID(shared),
Username: "someone-else",
}))
plantNamesakeProfiles(t, s, shared)
// Bounded so the deregistration the fixed path attempts fails on the dial
// rather than sitting in gRPC backoff for the whole test timeout.
@@ -165,18 +178,21 @@ func TestLogout_ForeignUserProfileDoesNotUseTheRunningConfig(t *testing.T) {
// guardedConfigMu, which the logout path does not hold, so a login that landed
// meanwhile must keep its connection.
func TestCleanupAfterProfileLogout_FollowsTheCurrentActiveProfile(t *testing.T) {
s, _, activeProfile, username, _ := setupServerWithProfile(t)
s, _, activeProfile, _, cfgPath := setupServerWithProfile(t)
s.rootCtx = internal.CtxInitState(context.Background())
state := internal.CtxGetState(s.rootCtx)
s.cleanupAfterProfileLogout("some-other-profile", username)
s.cleanupAfterProfileLogout(&profilemanager.Profile{ID: "some-other-profile"})
status, err := state.Status()
require.NoError(t, err)
require.NotEqual(t, internal.StatusNeedsLogin, status,
"logging out of a profile that is not active must not ask for a new login")
s.cleanupAfterProfileLogout(profilemanager.ID(activeProfile), username)
s.cleanupAfterProfileLogout(&profilemanager.Profile{
ID: profilemanager.ID(activeProfile),
Path: cfgPath,
})
status, err = state.Status()
require.NoError(t, err)
require.Equal(t, internal.StatusNeedsLogin, status,