Skip to content

Commit 7dff8ba

Browse files
authored
Merge pull request #1946 from alexandear/pkg-osutil-refactor-regexp
pkg/osutil: refactor LimaUser and LimaGroup functions
2 parents 045a640 + 7fffa9d commit 7dff8ba

File tree

6 files changed

+48
-27
lines changed

6 files changed

+48
-27
lines changed

.golangci.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,3 +151,8 @@ linters-settings:
151151
- typeUnparen
152152
- unnamedResult
153153
- unnecessaryBlock
154+
issues:
155+
exclude-rules:
156+
# Allow using Uid, Gid in pkg/osutil.
157+
- path: "pkg/osutil/"
158+
text: "uid"

pkg/osutil/osutil_linux.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ const UnixPathMax = 108
1010

1111
// Stat is a selection of syscall.Stat_t
1212
type Stat struct {
13-
Uid uint32 //nolint:revive
13+
Uid uint32
1414
Gid uint32
1515
}
1616

pkg/osutil/osutil_others.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const UnixPathMax = 104
1313

1414
// Stat is a selection of syscall.Stat_t
1515
type Stat struct {
16-
Uid uint32 //nolint:revive
16+
Uid uint32
1717
Gid uint32
1818
}
1919

pkg/osutil/osutil_windows.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const UnixPathMax = 108
1313

1414
// Stat is a selection of syscall.Stat_t
1515
type Stat struct {
16-
Uid uint32 //nolint:revive
16+
Uid uint32
1717
Gid uint32
1818
}
1919

pkg/osutil/user.go

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import (
1616

1717
type User struct {
1818
User string
19-
Uid uint32 //nolint:revive
19+
Uid uint32
2020
Group string
2121
Gid uint32
2222
Home string
@@ -30,6 +30,14 @@ type Group struct {
3030
var users map[string]User
3131
var groups map[string]Group
3232

33+
// regexUsername matches user and group names to be valid for `useradd`.
34+
// `useradd` allows names with a trailing '$', but it feels prudent to map those
35+
// names to the fallback user as well, so the regex does not allow them.
36+
var regexUsername = regexp.MustCompile("^[a-z_][a-z0-9_-]*$")
37+
38+
// regexPath detects valid Linux path.
39+
var regexPath = regexp.MustCompile("^[/a-zA-Z0-9_-]+$")
40+
3341
func LookupUser(name string) (User, error) {
3442
if users == nil {
3543
users = make(map[string]User)
@@ -43,15 +51,15 @@ func LookupUser(name string) (User, error) {
4351
if err != nil {
4452
return User{}, err
4553
}
46-
uid, err := strconv.ParseUint(u.Uid, 10, 32)
54+
uid, err := parseUidGid(u.Uid)
4755
if err != nil {
4856
return User{}, err
4957
}
50-
gid, err := strconv.ParseUint(u.Gid, 10, 32)
58+
gid, err := parseUidGid(u.Gid)
5159
if err != nil {
5260
return User{}, err
5361
}
54-
users[name] = User{User: u.Username, Uid: uint32(uid), Group: g.Name, Gid: uint32(gid), Home: u.HomeDir}
62+
users[name] = User{User: u.Username, Uid: uid, Group: g.Name, Gid: gid, Home: u.HomeDir}
5563
}
5664
return users[name], nil
5765
}
@@ -65,18 +73,18 @@ func LookupGroup(name string) (Group, error) {
6573
if err != nil {
6674
return Group{}, err
6775
}
68-
gid, err := strconv.ParseUint(g.Gid, 10, 32)
76+
gid, err := parseUidGid(g.Gid)
6977
if err != nil {
7078
return Group{}, err
7179
}
72-
groups[name] = Group{Name: g.Name, Gid: uint32(gid)}
80+
groups[name] = Group{Name: g.Name, Gid: gid}
7381
}
7482
return groups[name], nil
7583
}
7684

7785
const (
7886
fallbackUser = "lima"
79-
fallbackUid = 1000 //nolint:revive
87+
fallbackUid = 1000
8088
fallbackGid = 1000
8189
)
8290

@@ -101,12 +109,9 @@ func LimaUser(warn bool) (*user.User, error) {
101109
cache.Do(func() {
102110
cache.u, cache.err = user.Current()
103111
if cache.err == nil {
104-
// `useradd` only allows user and group names matching the following pattern:
105-
// (it allows a trailing '$', but it feels prudent to map those to the fallback user as well)
106-
validName := "^[a-z_][a-z0-9_-]*$"
107-
if !regexp.MustCompile(validName).Match([]byte(cache.u.Username)) {
112+
if !regexUsername.MatchString(cache.u.Username) {
108113
warning := fmt.Sprintf("local user %q is not a valid Linux username (must match %q); using %q username instead",
109-
cache.u.Username, validName, fallbackUser)
114+
cache.u.Username, regexUsername.String(), fallbackUser)
110115
cache.warnings = append(cache.warnings, warning)
111116
cache.u.Username = fallbackUser
112117
}
@@ -115,29 +120,29 @@ func LimaUser(warn bool) (*user.User, error) {
115120
if err != nil {
116121
logrus.Debug(err)
117122
}
118-
uid, err := strconv.ParseUint(idu, 10, 32)
123+
uid, err := parseUidGid(idu)
119124
if err != nil {
120125
uid = fallbackUid
121126
}
122-
if !regexp.MustCompile("^[0-9]+$").Match([]byte(cache.u.Uid)) {
127+
if _, err := parseUidGid(cache.u.Uid); err != nil {
123128
warning := fmt.Sprintf("local uid %q is not a valid Linux uid (must be integer); using %d uid instead",
124129
cache.u.Uid, uid)
125130
cache.warnings = append(cache.warnings, warning)
126-
cache.u.Uid = fmt.Sprintf("%d", uid)
131+
cache.u.Uid = formatUidGid(uid)
127132
}
128133
idg, err := call([]string{"id", "-g"})
129134
if err != nil {
130135
logrus.Debug(err)
131136
}
132-
gid, err := strconv.ParseUint(idg, 10, 32)
137+
gid, err := parseUidGid(idg)
133138
if err != nil {
134139
gid = fallbackGid
135140
}
136-
if !regexp.MustCompile("^[0-9]+$").Match([]byte(cache.u.Gid)) {
141+
if _, err := parseUidGid(cache.u.Gid); err != nil {
137142
warning := fmt.Sprintf("local gid %q is not a valid Linux gid (must be integer); using %d gid instead",
138143
cache.u.Gid, gid)
139144
cache.warnings = append(cache.warnings, warning)
140-
cache.u.Gid = fmt.Sprintf("%d", gid)
145+
cache.u.Gid = formatUidGid(gid)
141146
}
142147
home, err := call([]string{"cygpath", cache.u.HomeDir})
143148
if err != nil {
@@ -150,10 +155,9 @@ func LimaUser(warn bool) (*user.User, error) {
150155
prefix := strings.ToLower(fmt.Sprintf("/%c", drive[0]))
151156
home = strings.Replace(home, drive, prefix, 1)
152157
}
153-
validPath := "^[/a-zA-Z0-9_-]+$"
154-
if !regexp.MustCompile(validPath).Match([]byte(cache.u.HomeDir)) {
158+
if !regexPath.MatchString(cache.u.HomeDir) {
155159
warning := fmt.Sprintf("local home %q is not a valid Linux path (must match %q); using %q home instead",
156-
cache.u.HomeDir, validPath, home)
160+
cache.u.HomeDir, regexPath.String(), home)
157161
cache.warnings = append(cache.warnings, warning)
158162
cache.u.HomeDir = home
159163
}
@@ -167,3 +171,17 @@ func LimaUser(warn bool) (*user.User, error) {
167171
}
168172
return cache.u, cache.err
169173
}
174+
175+
// parseUidGid converts string value to Linux uid or gid.
176+
func parseUidGid(uidOrGid string) (uint32, error) {
177+
res, err := strconv.ParseUint(uidOrGid, 10, 32)
178+
if err != nil {
179+
return 0, err
180+
}
181+
return uint32(res), nil
182+
}
183+
184+
// formatUidGid converts uid or gid to string value.
185+
func formatUidGid(uidOrGid uint32) string {
186+
return strconv.FormatUint(uint64(uidOrGid), 10)
187+
}

pkg/osutil/user_test.go

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package osutil
22

33
import (
44
"path"
5-
"regexp"
65
"strconv"
76
"testing"
87

@@ -15,8 +14,7 @@ func TestLimaUserWarn(t *testing.T) {
1514
}
1615

1716
func validUsername(username string) bool {
18-
validName := "^[a-z_][a-z0-9_-]*$"
19-
return regexp.MustCompile(validName).Match([]byte(username))
17+
return regexUsername.MatchString(username)
2018
}
2119

2220
func TestLimaUsername(t *testing.T) {

0 commit comments

Comments
 (0)