Skip to content

Commit 5573bc7

Browse files
committed
make persistent home for bubblewrap in .itch dir
1 parent 17f32f5 commit 5573bc7

File tree

2 files changed

+108
-1
lines changed

2 files changed

+108
-1
lines changed

runner/bubblewrap_linux.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,23 @@ func (br *bubblewrapRunner) Run() error {
7979
args = append(args, "--dev-bind", "/dev/snd", "/dev/snd")
8080
}
8181

82+
createdSandboxDirs := make(map[string]struct{})
83+
84+
// Give sandboxed apps a persistent per-game home directory.
85+
homeTarget, hasHome := envLookupWithPresence(params.Env, "HOME")
86+
if !hasHome {
87+
homeTarget = os.Getenv("HOME")
88+
}
89+
if params.InstallFolder != "" && filepath.IsAbs(homeTarget) {
90+
homeSource := filepath.Join(params.InstallFolder, ".itch", "home")
91+
if err := os.MkdirAll(homeSource, 0o755); err != nil {
92+
consumer.Warnf("Could not make sandbox home directory (%s): %s", homeSource, err.Error())
93+
} else {
94+
ensureSandboxParentDirs(&args, createdSandboxDirs, homeTarget)
95+
args = append(args, "--bind", homeSource, homeTarget)
96+
}
97+
}
98+
8299
// Game install folder (read-write)
83100
if params.InstallFolder != "" {
84101
args = append(args, "--bind", params.InstallFolder, params.InstallFolder)
@@ -99,7 +116,6 @@ func (br *bubblewrapRunner) Run() error {
99116
if xdgRuntimeDir == "" {
100117
xdgRuntimeDir = os.Getenv("XDG_RUNTIME_DIR")
101118
}
102-
createdSandboxDirs := make(map[string]struct{})
103119

104120
// X11
105121
if _, err := os.Stat("/tmp/.X11-unix"); err == nil {

runner/bubblewrap_linux_test.go

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package runner
55
import (
66
"context"
77
"os/exec"
8+
"path/filepath"
89
"testing"
910

1011
"github.com/itchio/headway/state"
@@ -22,6 +23,24 @@ func bubblewrapSetenvValues(args []string, key string) []string {
2223
return out
2324
}
2425

26+
func bubblewrapHasBind(args []string, source string, target string) bool {
27+
for i := 0; i+2 < len(args); i++ {
28+
if args[i] == "--bind" && args[i+1] == source && args[i+2] == target {
29+
return true
30+
}
31+
}
32+
return false
33+
}
34+
35+
func bubblewrapBindIndex(args []string, source string, target string) int {
36+
for i := 0; i+2 < len(args); i++ {
37+
if args[i] == "--bind" && args[i+1] == source && args[i+2] == target {
38+
return i
39+
}
40+
}
41+
return -1
42+
}
43+
2544
func TestEnsureSandboxParentDirs(t *testing.T) {
2645
var args []string
2746
seen := make(map[string]struct{})
@@ -212,3 +231,75 @@ func TestBubblewrapAllowEnvEmptyValueOverridesHost(t *testing.T) {
212231
require.NoError(t, br.Run())
213232
assert.Equal(t, []string{""}, bubblewrapSetenvValues(gotArgs, "SMAUG_ALLOW_ENV_EMPTY"))
214233
}
234+
235+
func TestBubblewrapMountsPersistentSandboxHome(t *testing.T) {
236+
origCommand := bubblewrapCommand
237+
t.Cleanup(func() {
238+
bubblewrapCommand = origCommand
239+
})
240+
241+
var gotArgs []string
242+
bubblewrapCommand = func(name string, args ...string) *exec.Cmd {
243+
gotArgs = append([]string{}, args...)
244+
return exec.Command("sh", "-c", "true")
245+
}
246+
247+
installFolder := t.TempDir()
248+
homeTarget := "/home/sandbox-user"
249+
homeSource := filepath.Join(installFolder, ".itch", "home")
250+
251+
br := &bubblewrapRunner{
252+
params: RunnerParams{
253+
Consumer: &state.Consumer{OnMessage: func(string, string) {}},
254+
Ctx: context.Background(),
255+
BubblewrapParams: BubblewrapParams{
256+
BinaryPath: "/fake/bwrap",
257+
},
258+
InstallFolder: installFolder,
259+
Env: []string{"HOME=" + homeTarget},
260+
FullTargetPath: "/bin/true",
261+
},
262+
}
263+
264+
require.NoError(t, br.Run())
265+
assert.DirExists(t, homeSource)
266+
assert.True(t, bubblewrapHasBind(gotArgs, homeSource, homeTarget))
267+
}
268+
269+
func TestBubblewrapInstallBindComesAfterSandboxHomeBind(t *testing.T) {
270+
origCommand := bubblewrapCommand
271+
t.Cleanup(func() {
272+
bubblewrapCommand = origCommand
273+
})
274+
275+
var gotArgs []string
276+
bubblewrapCommand = func(name string, args ...string) *exec.Cmd {
277+
gotArgs = append([]string{}, args...)
278+
return exec.Command("sh", "-c", "true")
279+
}
280+
281+
installFolder := "/home/leafo/.config/kitch/apps/sample-evil-app 2"
282+
homeTarget := "/home/leafo"
283+
homeSource := filepath.Join(installFolder, ".itch", "home")
284+
285+
br := &bubblewrapRunner{
286+
params: RunnerParams{
287+
Consumer: &state.Consumer{OnMessage: func(string, string) {}},
288+
Ctx: context.Background(),
289+
BubblewrapParams: BubblewrapParams{
290+
BinaryPath: "/fake/bwrap",
291+
},
292+
InstallFolder: installFolder,
293+
Env: []string{"HOME=" + homeTarget},
294+
FullTargetPath: "/bin/true",
295+
},
296+
}
297+
298+
require.NoError(t, br.Run())
299+
300+
homeBind := bubblewrapBindIndex(gotArgs, homeSource, homeTarget)
301+
installBind := bubblewrapBindIndex(gotArgs, installFolder, installFolder)
302+
require.NotEqual(t, -1, homeBind)
303+
require.NotEqual(t, -1, installBind)
304+
assert.Less(t, homeBind, installBind)
305+
}

0 commit comments

Comments
 (0)