mirror of
https://github.com/netbirdio/netbird.git
synced 2026-08-25 09:01:29 +02:00
156 lines
4.7 KiB
Go
156 lines
4.7 KiB
Go
package getent
|
|
|
|
import (
|
|
"os/user"
|
|
"runtime"
|
|
"strconv"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestLookupUser_CurrentUser(t *testing.T) {
|
|
// The current user should always be resolvable on any platform
|
|
current, err := user.Current()
|
|
require.NoError(t, err)
|
|
|
|
u, err := LookupUser(current.Username)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, current.Username, u.Username)
|
|
assert.Equal(t, current.Uid, u.Uid)
|
|
assert.Equal(t, current.Gid, u.Gid)
|
|
}
|
|
|
|
func TestLookupUser_NonexistentUser(t *testing.T) {
|
|
_, err := LookupUser("nonexistent_user_xyzzy_12345")
|
|
require.Error(t, err, "should fail for nonexistent user")
|
|
}
|
|
|
|
func TestLookupUserID_CurrentUser(t *testing.T) {
|
|
current, err := user.Current()
|
|
require.NoError(t, err)
|
|
|
|
u, err := LookupUserID(current.Uid)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, current.Username, u.Username)
|
|
assert.Equal(t, current.Uid, u.Uid)
|
|
}
|
|
|
|
func TestCurrentUser(t *testing.T) {
|
|
stdUser, err := user.Current()
|
|
require.NoError(t, err)
|
|
|
|
u, err := CurrentUser()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, stdUser.Uid, u.Uid)
|
|
assert.Equal(t, stdUser.Username, u.Username)
|
|
}
|
|
|
|
func TestGroupIDs_CurrentUser(t *testing.T) {
|
|
current, err := user.Current()
|
|
require.NoError(t, err)
|
|
|
|
groups, err := GroupIDs(current)
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, groups, "current user should have at least one group")
|
|
|
|
if runtime.GOOS != "windows" {
|
|
for _, gid := range groups {
|
|
_, err := strconv.ParseUint(gid, 10, 32)
|
|
assert.NoError(t, err, "group ID %q should be a valid uint32", gid)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestUserShell_CurrentUser(t *testing.T) {
|
|
current, err := user.Current()
|
|
require.NoError(t, err)
|
|
|
|
// getent may not be available on all systems (e.g., macOS without
|
|
// Homebrew getent), and Windows has no login shells at all.
|
|
shell, err := UserShell(current.Uid)
|
|
if err != nil {
|
|
t.Logf("UserShell failed, getent may not be available: %v", err)
|
|
return
|
|
}
|
|
if shell == "" {
|
|
t.Log("UserShell returned empty, the user has no shell set")
|
|
return
|
|
}
|
|
assert.True(t, shell[0] == '/', "shell should be an absolute path, got %q", shell)
|
|
}
|
|
|
|
func TestLookupUser_RootUser(t *testing.T) {
|
|
if runtime.GOOS == "windows" {
|
|
t.Skip("no root user on Windows")
|
|
}
|
|
|
|
u, err := LookupUser("root")
|
|
if err != nil {
|
|
t.Skip("root user not available on this system")
|
|
}
|
|
assert.Equal(t, "0", u.Uid, "root should have UID 0")
|
|
}
|
|
|
|
// TestIntegration_FullLookupChain exercises the complete user lookup chain
|
|
// against the real system, testing that all wrappers (LookupUser,
|
|
// CurrentUser, GroupIDs, UserShell) produce consistent and correct results
|
|
// when composed together.
|
|
func TestIntegration_FullLookupChain(t *testing.T) {
|
|
// Step 1: CurrentUser must resolve the running user.
|
|
current, err := CurrentUser()
|
|
require.NoError(t, err, "CurrentUser must resolve the running user")
|
|
require.NotEmpty(t, current.Uid)
|
|
require.NotEmpty(t, current.Username)
|
|
|
|
// Step 2: LookupUser by the same username must return matching identity.
|
|
byName, err := LookupUser(current.Username)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, current.Uid, byName.Uid, "lookup by name should return same UID")
|
|
assert.Equal(t, current.Gid, byName.Gid, "lookup by name should return same GID")
|
|
assert.Equal(t, current.HomeDir, byName.HomeDir, "lookup by name should return same home")
|
|
|
|
// Step 3: GroupIDs must return at least the primary GID.
|
|
groups, err := GroupIDs(current)
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, groups, "user must have at least one group")
|
|
|
|
foundPrimary := false
|
|
for _, gid := range groups {
|
|
if runtime.GOOS != "windows" {
|
|
_, err := strconv.ParseUint(gid, 10, 32)
|
|
require.NoError(t, err, "group ID %q must be a valid uint32", gid)
|
|
}
|
|
if gid == current.Gid {
|
|
foundPrimary = true
|
|
}
|
|
}
|
|
assert.True(t, foundPrimary, "primary GID %s should appear in supplementary groups", current.Gid)
|
|
}
|
|
|
|
// TestIntegration_LookupAndGroupsConsistency verifies that a user resolved via
|
|
// LookupUser can have their groups resolved via GroupIDs, testing the handoff
|
|
// between the two functions as used by the SSH server.
|
|
func TestIntegration_LookupAndGroupsConsistency(t *testing.T) {
|
|
current, err := user.Current()
|
|
require.NoError(t, err)
|
|
|
|
// Simulate the SSH server flow: lookup user, then get their groups.
|
|
resolved, err := LookupUser(current.Username)
|
|
require.NoError(t, err)
|
|
|
|
groups, err := GroupIDs(resolved)
|
|
require.NoError(t, err)
|
|
require.NotEmpty(t, groups, "resolved user must have groups")
|
|
|
|
// On Unix, all returned GIDs must be valid numeric values.
|
|
// On Windows, group IDs are SIDs (e.g., "S-1-5-32-544").
|
|
if runtime.GOOS != "windows" {
|
|
for _, gid := range groups {
|
|
_, err := strconv.ParseUint(gid, 10, 32)
|
|
assert.NoError(t, err, "group ID %q should be numeric", gid)
|
|
}
|
|
}
|
|
}
|