github.com/hernad/nomad@v1.6.112/helper/users/lookup_linux_test.go (about) 1 // Copyright (c) HashiCorp, Inc. 2 // SPDX-License-Identifier: MPL-2.0 3 4 //go:build linux 5 6 package users 7 8 import ( 9 "errors" 10 "fmt" 11 "os" 12 "os/user" 13 "path/filepath" 14 "syscall" 15 "testing" 16 17 "github.com/hernad/nomad/helper/testlog" 18 "github.com/shoenig/test/must" 19 "golang.org/x/sys/unix" 20 ) 21 22 func TestLookup_Linux(t *testing.T) { 23 cases := []struct { 24 username string 25 26 expErr error 27 expUser *user.User 28 }{ 29 {username: "nobody", expUser: &user.User{Username: "nobody", Uid: "65534", Gid: "65534", Name: "nobody", HomeDir: "/nonexistent"}}, // ubuntu 30 {username: "root", expUser: &user.User{Username: "root", Uid: "0", Gid: "0", Name: "root", HomeDir: "/root"}}, 31 {username: "doesnotexist", expErr: errors.New("user: unknown user doesnotexist")}, 32 } 33 34 for _, tc := range cases { 35 t.Run(tc.username, func(t *testing.T) { 36 u, err := Lookup(tc.username) 37 if tc.expErr != nil { 38 must.EqError(t, tc.expErr, err.Error()) 39 } else { 40 must.Eq(t, tc.expUser, u) 41 } 42 }) 43 } 44 } 45 46 func TestWriteFileFor_Linux(t *testing.T) { 47 // This is really how you have to retrieve umask. See `man 2 umask` 48 umask := unix.Umask(0) 49 unix.Umask(umask) 50 51 path := filepath.Join(t.TempDir(), "secret.txt") 52 contents := []byte("TOO MANY SECRETS") 53 54 must.NoError(t, WriteFileFor(path, contents, "nobody")) 55 56 stat, err := os.Lstat(path) 57 must.NoError(t, err) 58 must.True(t, stat.Mode().IsRegular(), 59 must.Sprintf("expected %s to be a regular file but found %#o", path, stat.Mode())) 60 61 linuxStat, ok := stat.Sys().(*syscall.Stat_t) 62 must.True(t, ok, must.Sprintf("expected stat.Sys() to be a *syscall.Stat_t but found %T", stat.Sys())) 63 64 current, err := Current() 65 must.NoError(t, err) 66 67 if current.Username == "root" { 68 t.Logf("Running as root: asserting %s is owned by nobody", path) 69 nobody, err := Lookup("nobody") 70 must.NoError(t, err) 71 must.Eq(t, nobody.Uid, fmt.Sprintf("%d", linuxStat.Uid)) 72 must.Eq(t, 0o600&(^umask), int(stat.Mode())) 73 } else { 74 t.Logf("Running as non-root: asserting %s is world readable", path) 75 must.Eq(t, current.Uid, fmt.Sprintf("%d", linuxStat.Uid)) 76 must.Eq(t, 0o666&(^umask), int(stat.Mode())) 77 } 78 } 79 80 // TestSocketFileFor_Linux asserts that when running as root on Linux socket 81 // files are created with least permissions. If running as non-root then we 82 // leave the socket file as world writable. 83 func TestSocketFileFor_Linux(t *testing.T) { 84 path := filepath.Join(t.TempDir(), "api.sock") 85 86 logger := testlog.HCLogger(t) 87 ln, err := SocketFileFor(logger, path, "nobody") 88 must.NoError(t, err) 89 must.NotNil(t, ln) 90 t.Cleanup(func() { 91 _ = ln.Close() 92 }) 93 94 stat, err := os.Lstat(path) 95 must.NoError(t, err) 96 must.False(t, stat.Mode().IsRegular(), 97 must.Sprintf("expected %s to be a regular file but found %#o", path, stat.Mode())) 98 99 linuxStat, ok := stat.Sys().(*syscall.Stat_t) 100 must.True(t, ok, must.Sprintf("expected stat.Sys() to be a *syscall.Stat_t but found %T", stat.Sys())) 101 102 current, err := Current() 103 must.NoError(t, err) 104 105 if current.Username == "root" { 106 t.Logf("Running as root: asserting %s is owned by nobody", path) 107 nobody, err := Lookup("nobody") 108 must.NoError(t, err) 109 must.Eq(t, nobody.Uid, fmt.Sprintf("%d", linuxStat.Uid)) 110 must.Eq(t, 0o600, int(stat.Mode().Perm())) 111 } else { 112 t.Logf("Running as non-root: asserting %s is world writable", path) 113 must.Eq(t, current.Uid, fmt.Sprintf("%d", linuxStat.Uid)) 114 must.Eq(t, 0o666, int(stat.Mode().Perm())) 115 } 116 }