[client] Profile ownership migration (#7508)

* Implement OwnsProfile on Server

* (WIP) List profiles based on ownership by Identity

* (WIP) Migrate active_profile

* Fix status and list profiles

* Add profile stamping as active migration

* Add one-shot migration

* Only default profile fail open

* Use restricted write for config json

* Fix stale server config after stamp

* Fix OwnsProfile fallback to active profile

* Fix config concurrent reload during OwnsProfile check

* Move known check to inside stamp owner

* Update client/internal/profilemanager/service.go

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* Recover from dup active profiles that cannot be resolved with username.

* Add test for already owned profile during migration

* Improve stamping of fields in the config

* Apply suggestion from @cubic-dev-ai[bot]

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>

* Fix codespell and test comment

---------

Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
This commit is contained in:
Theodor Midtlien
2026-09-17 11:20:12 +02:00
committed by GitHub
co-authored by cubic-dev-ai[bot]
parent 15ed6f8f15
commit 52b16e7a5c
19 changed files with 2050 additions and 270 deletions
+13 -1
View File
@@ -4,10 +4,12 @@ import (
"context"
"os"
"os/user"
"path/filepath"
"testing"
"time"
"github.com/netbirdio/netbird/client/internal"
"github.com/netbirdio/netbird/client/internal/ipcauth"
"github.com/netbirdio/netbird/client/internal/profilemanager"
)
@@ -18,8 +20,11 @@ func TestUpDaemon(t *testing.T) {
tempDir := t.TempDir()
origDefaultProfileDir := profilemanager.DefaultConfigPathDir
origActiveProfileStatePath := profilemanager.ActiveProfileStatePath
origDefaultConfigPath := profilemanager.DefaultConfigPath
profilemanager.DefaultConfigPathDir = tempDir
profilemanager.ActiveProfileStatePath = tempDir + "/active_profile.json"
// Without this the loader reads the real /var/lib/netbird/default.json.
profilemanager.DefaultConfigPath = filepath.Join(tempDir, "default.json")
profilemanager.ConfigDirOverride = tempDir
currUser, err := user.Current()
@@ -28,8 +33,14 @@ func TestUpDaemon(t *testing.T) {
return
}
identity, err := ipcauth.CurrentProcessIdentity()
if err != nil {
t.Fatalf("failed to read this process's identity: %v", err)
return
}
sm := profilemanager.ServiceManager{}
created, err := sm.AddProfile("test1", currUser.Username, nil)
created, err := sm.AddProfile("test1", &identity)
if err != nil {
t.Fatalf("failed to add profile: %v", err)
return
@@ -47,6 +58,7 @@ func TestUpDaemon(t *testing.T) {
t.Cleanup(func() {
profilemanager.DefaultConfigPathDir = origDefaultProfileDir
profilemanager.ActiveProfileStatePath = origActiveProfileStatePath
profilemanager.DefaultConfigPath = origDefaultConfigPath
profilemanager.ConfigDirOverride = ""
})