1package bootstrap
2
3import (
4 "os"
5 "path/filepath"
6 "testing"
7
8 "github.com/stretchr/testify/require"
9)
10
11func TestApplyDevelopmentEnvironment_DevIsolatesHomeAndXDGDirectories(t *testing.T) {
12 worktree := t.TempDir()
13 t.Chdir(worktree)
14 t.Setenv("ENV", developmentEnvironmentName)
15 t.Setenv("HOME", "/home/production")
16 t.Setenv("XDG_CONFIG_HOME", "/production/config")
17 t.Setenv("XDG_DATA_HOME", "/production/data")
18 t.Setenv("XDG_STATE_HOME", "/production/state")
19 t.Setenv("XDG_CACHE_HOME", "/production/cache")
20 t.Setenv("XDG_RUNTIME_DIR", "/run/user/1000")
21
22 require.NoError(t, ApplyDevelopmentEnvironment())
23
24 root := filepath.Join(worktree, ".dev", "dumber")
25 want := map[string]string{
26 "HOME": filepath.Join(root, "home"),
27 "XDG_CONFIG_HOME": filepath.Join(root, "config"),
28 "XDG_DATA_HOME": filepath.Join(root, "data"),
29 "XDG_STATE_HOME": filepath.Join(root, "state"),
30 "XDG_CACHE_HOME": filepath.Join(root, "cache"),
31 }
32 for name, path := range want {
33 require.Equal(t, path, os.Getenv(name), name)
34 info, err := os.Stat(path)
35 require.NoError(t, err, name)
36 require.True(t, info.IsDir(), name)
37 require.Equal(t, os.FileMode(0o700), info.Mode().Perm(), name)
38 }
39 require.Equal(t, "/run/user/1000", os.Getenv("XDG_RUNTIME_DIR"))
40}
41
42func TestApplyDevelopmentEnvironment_DevTightensExistingDevDirectoryPermissions(t *testing.T) {
43 worktree := t.TempDir()
44 t.Chdir(worktree)
45 t.Setenv("ENV", developmentEnvironmentName)
46
47 devDir := filepath.Join(worktree, ".dev")
48 require.NoError(t, os.Mkdir(devDir, 0o777))
49 require.NoError(t, os.Chmod(devDir, 0o777))
50
51 require.NoError(t, ApplyDevelopmentEnvironment())
52
53 info, err := os.Stat(devDir)
54 require.NoError(t, err)
55 require.Equal(t, os.FileMode(0o700), info.Mode().Perm())
56}
57
58func TestApplyDevelopmentEnvironment_DevRejectsSandboxSymlink(t *testing.T) {
59 worktree := t.TempDir()
60 t.Chdir(worktree)
61 t.Setenv("ENV", developmentEnvironmentName)
62 t.Setenv("HOME", "/home/production")
63
64 devDir := filepath.Join(worktree, ".dev")
65 require.NoError(t, os.Mkdir(devDir, 0o755))
66 target := t.TempDir()
67 require.NoError(t, os.Symlink(target, filepath.Join(devDir, "dumber")))
68
69 err := ApplyDevelopmentEnvironment()
70 require.Error(t, err)
71 require.Contains(t, err.Error(), "must be a directory")
72 require.Equal(t, "/home/production", os.Getenv("HOME"))
73}
74
75func TestApplyDevelopmentEnvironment_DevRejectsSandboxChildSymlinks(t *testing.T) {
76 for _, child := range []string{"logs", "engines"} {
77 t.Run(child, func(t *testing.T) {
78 worktree := t.TempDir()
79 t.Chdir(worktree)
80 t.Setenv("ENV", developmentEnvironmentName)
81
82 root := filepath.Join(worktree, ".dev", "dumber")
83 require.NoError(t, os.MkdirAll(root, 0o700))
84 require.NoError(t, os.Symlink(t.TempDir(), filepath.Join(root, child)))
85
86 err := ApplyDevelopmentEnvironment()
87 require.Error(t, err)
88 require.Contains(t, err.Error(), "must be a directory")
89 })
90 }
91}
92
93func TestApplyDevelopmentEnvironment_DevTightensExistingSandboxPermissions(t *testing.T) {
94 worktree := t.TempDir()
95 t.Chdir(worktree)
96 t.Setenv("ENV", developmentEnvironmentName)
97
98 root := filepath.Join(worktree, ".dev", "dumber")
99 require.NoError(t, os.MkdirAll(root, 0o755))
100 require.NoError(t, os.Chmod(root, 0o755))
101
102 require.NoError(t, ApplyDevelopmentEnvironment())
103
104 info, err := os.Stat(root)
105 require.NoError(t, err)
106 require.Equal(t, os.FileMode(0o700), info.Mode().Perm())
107}
108
109func TestApplyDevelopmentEnvironment_ProductionPreservesEnvironment(t *testing.T) {
110 t.Setenv("ENV", "")
111 t.Setenv("HOME", "/home/production")
112 t.Setenv("XDG_CONFIG_HOME", "/production/config")
113 t.Setenv("XDG_DATA_HOME", "/production/data")
114 t.Setenv("XDG_STATE_HOME", "/production/state")
115 t.Setenv("XDG_CACHE_HOME", "/production/cache")
116
117 require.NoError(t, ApplyDevelopmentEnvironment())
118
119 require.Equal(t, "/home/production", os.Getenv("HOME"))
120 require.Equal(t, "/production/config", os.Getenv("XDG_CONFIG_HOME"))
121 require.Equal(t, "/production/data", os.Getenv("XDG_DATA_HOME"))
122 require.Equal(t, "/production/state", os.Getenv("XDG_STATE_HOME"))
123 require.Equal(t, "/production/cache", os.Getenv("XDG_CACHE_HOME"))
124}