Skip to content

Commit b94e2fc

Browse files
authored
Merge pull request #3679 from mazzz1y/master
Add timezone validation
2 parents d877648 + 380679c commit b94e2fc

File tree

4 files changed

+144
-20
lines changed

4 files changed

+144
-20
lines changed

pkg/limayaml/defaults.go

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -135,26 +135,6 @@ func MACAddress(uniqueID string) string {
135135
return hw.String()
136136
}
137137

138-
func hostTimeZone() string {
139-
// WSL2 will automatically set the timezone
140-
if runtime.GOOS != "windows" {
141-
tz, err := os.ReadFile("/etc/timezone")
142-
if err == nil {
143-
return strings.TrimSpace(string(tz))
144-
}
145-
zoneinfoFile, err := filepath.EvalSymlinks("/etc/localtime")
146-
if err == nil {
147-
for baseDir := filepath.Dir(zoneinfoFile); baseDir != "/"; baseDir = filepath.Dir(baseDir) {
148-
if _, err = os.Stat(filepath.Join(baseDir, "Etc/UTC")); err == nil {
149-
return strings.TrimPrefix(zoneinfoFile, baseDir+"/")
150-
}
151-
}
152-
logrus.Warnf("could not locate zoneinfo directory from %q", zoneinfoFile)
153-
}
154-
}
155-
return ""
156-
}
157-
158138
func defaultCPUs() int {
159139
const x = 4
160140
if hostCPUs := runtime.NumCPU(); hostCPUs < x {

pkg/limayaml/defaults_unix.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//go:build !windows
2+
3+
// SPDX-FileCopyrightText: Copyright The Lima Authors
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
package limayaml
7+
8+
import (
9+
"errors"
10+
"fmt"
11+
"os"
12+
"path/filepath"
13+
"strings"
14+
"time"
15+
16+
"github.com/sirupsen/logrus"
17+
)
18+
19+
func hostTimeZone() string {
20+
if tzBytes, err := os.ReadFile("/etc/timezone"); err == nil {
21+
if tz := strings.TrimSpace(string(tzBytes)); tz != "" {
22+
if _, err := time.LoadLocation(tz); err != nil {
23+
logrus.Warnf("invalid timezone found in /etc/timezone: %v", err)
24+
} else {
25+
return tz
26+
}
27+
}
28+
}
29+
30+
if zoneinfoFile, err := filepath.EvalSymlinks("/etc/localtime"); err == nil {
31+
if tz, err := extractTZFromPath(zoneinfoFile); err != nil {
32+
logrus.Warnf("failed to extract timezone from %s: %v", zoneinfoFile, err)
33+
} else {
34+
return tz
35+
}
36+
}
37+
38+
logrus.Warn("unable to determine host timezone, falling back to default value")
39+
return ""
40+
}
41+
42+
func extractTZFromPath(zoneinfoFile string) (string, error) {
43+
if zoneinfoFile == "" {
44+
return "", errors.New("invalid zoneinfo file path")
45+
}
46+
47+
if _, err := os.Stat(zoneinfoFile); os.IsNotExist(err) {
48+
return "", fmt.Errorf("zoneinfo file does not exist: %s", zoneinfoFile)
49+
}
50+
51+
for dir := filepath.Dir(zoneinfoFile); dir != filepath.Dir(dir); dir = filepath.Dir(dir) {
52+
if _, err := os.Stat(filepath.Join(dir, "Etc", "UTC")); err == nil {
53+
return filepath.Rel(dir, zoneinfoFile)
54+
}
55+
}
56+
57+
return "", errors.New("timezone base directory not found")
58+
}

pkg/limayaml/defaults_unix_test.go

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
//go:build !windows
2+
3+
// SPDX-FileCopyrightText: Copyright The Lima Authors
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
package limayaml
7+
8+
import (
9+
"os"
10+
"path/filepath"
11+
"testing"
12+
13+
"gotest.tools/v3/assert"
14+
)
15+
16+
func TestExtractTimezoneFromPath(t *testing.T) {
17+
tmpDir := t.TempDir()
18+
19+
// Create test timezone directory structure
20+
assert.NilError(t, os.MkdirAll(filepath.Join(tmpDir, "Etc"), 0o755))
21+
assert.NilError(t, os.WriteFile(filepath.Join(tmpDir, "Etc", "UTC"), []byte{}, 0o644))
22+
assert.NilError(t, os.WriteFile(filepath.Join(tmpDir, "UTC"), []byte{}, 0o644))
23+
assert.NilError(t, os.MkdirAll(filepath.Join(tmpDir, "Antarctica"), 0o755))
24+
assert.NilError(t, os.WriteFile(filepath.Join(tmpDir, "Antarctica", "Troll"), []byte{}, 0o644))
25+
26+
tests := []struct {
27+
name string
28+
path string
29+
want string
30+
wantErr bool
31+
}{
32+
{
33+
"valid_timezone",
34+
filepath.Join(tmpDir, "Antarctica", "Troll"),
35+
"Antarctica/Troll",
36+
false,
37+
},
38+
{
39+
"root_level_zone",
40+
filepath.Join(tmpDir, "UTC"),
41+
"UTC",
42+
false,
43+
},
44+
{
45+
"outside_zoneinfo",
46+
"/tmp/somefile",
47+
"",
48+
true,
49+
},
50+
{
51+
"empty_path",
52+
"",
53+
"",
54+
true,
55+
},
56+
{
57+
"nonexistent_file",
58+
filepath.Join(tmpDir, "Invalid", "Zone"),
59+
"",
60+
true,
61+
},
62+
}
63+
64+
for _, tt := range tests {
65+
t.Run(tt.name, func(t *testing.T) {
66+
got, err := extractTZFromPath(tt.path)
67+
if tt.wantErr {
68+
assert.Assert(t, err != nil, "expected error but got none")
69+
} else {
70+
assert.NilError(t, err)
71+
}
72+
assert.Equal(t, tt.want, got)
73+
})
74+
}
75+
}

pkg/limayaml/defaults_windows.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
//go:build windows
2+
3+
// SPDX-FileCopyrightText: Copyright The Lima Authors
4+
// SPDX-License-Identifier: Apache-2.0
5+
6+
package limayaml
7+
8+
func hostTimeZone() string {
9+
// WSL2 will automatically set the timezone
10+
return ""
11+
}

0 commit comments

Comments
 (0)