package paths import ( "fmt" "os" "path/filepath" ) // PathManager handles the resolution of configuration and runtime directories. // By using a struct, we can instantiate different managers for parallel tests. type PathManager struct { ConfigDirOverride string RuntimeBaseOverride string } // NewPathManager creates a PathManager with the given overrides. func NewPathManager(configOverride, runtimeOverride string) *PathManager { return &PathManager{ ConfigDirOverride: configOverride, RuntimeBaseOverride: runtimeOverride, } } // ConfigDir returns the persistent storage path for .conf files. func (pm *PathManager) ConfigDir() string { if pm.ConfigDirOverride != "" { return pm.ConfigDirOverride } configHome := os.Getenv("XDG_CONFIG_HOME") if configHome == "" { home, err := os.UserHomeDir() if err != nil { return "/etc/wg-wrap/profiles" // Fallback } configHome = filepath.Join(home, ".config") } return filepath.Join(configHome, "wg-wrap", "profiles") } // RuntimeBaseDir returns the base ephemeral path. func (pm *PathManager) RuntimeBaseDir() string { if pm.RuntimeBaseOverride != "" { return pm.RuntimeBaseOverride } if envDir := os.Getenv("XDG_RUNTIME_DIR"); envDir != "" { return envDir } uid := os.Getuid() return fmt.Sprintf("/run/user/%d", uid) } // ProfileNamespacePath returns the specific path for a pinned namespace. func (pm *PathManager) ProfileNamespacePath(profile string) string { return filepath.Join(pm.RuntimeBaseDir(), "profiles", profile+".ns") } // ProfilePidsDir returns the path for PID tracking. func (pm *PathManager) ProfilePidsDir(profile string) string { return filepath.Join(pm.RuntimeBaseDir(), "profiles", profile, "pids") }