cmd/gitbay-runner/home_test.go
90 lines · 2821 bytes
3 symbols in this file
1package main
2
3import (
4 "os"
5 "path/filepath"
6 "strings"
7 "testing"
8)
9
10// A trusted build's home is its repository's, kept between builds so
11// tool caches survive: the same repository gets the same directory back,
12// another repository a different one (#184).
13func TestTrustedHomeIsPerRepositoryAndKept(t *testing.T) {
14 work := t.TempDir()
15 a, done, err := buildHome(work, job{ID: 1, Repo: "alice/app", Trusted: true})
16 if err != nil {
17 t.Fatal(err)
18 }
19 done()
20 if _, err := os.Stat(a); err != nil {
21 t.Fatalf("trusted home removed after its build: %v", err)
22 }
23 b, done, err := buildHome(work, job{ID: 2, Repo: "bob/app", Trusted: true})
24 if err != nil {
25 t.Fatal(err)
26 }
27 done()
28 if a == b {
29 t.Fatalf("two repositories share a build home: %s", a)
30 }
31 again, done, _ := buildHome(work, job{ID: 3, Repo: "alice/app", Trusted: true})
32 done()
33 if again != a {
34 t.Fatalf("build home moved between builds: %s then %s", a, again)
35 }
36 for _, dir := range []string{a, b} {
37 rel, err := filepath.Rel(filepath.Join(work, "trusted-home"), dir)
38 if err != nil || rel == "." || strings.HasPrefix(rel, "..") {
39 t.Fatalf("build home %s is not under %s/trusted-home", dir, work)
40 }
41 st, err := os.Stat(dir)
42 if err != nil {
43 t.Fatal(err)
44 }
45 if st.Mode().Perm() != 0o700 {
46 t.Fatalf("build home mode %o, want 0700", st.Mode().Perm())
47 }
48 }
49}
50
51// An untrusted build gets a home of its own, outside the trusted root,
52// removed when the build ends: nothing a fork's build writes reaches a
53// later build of the repository (#255).
54func TestUntrustedHomeIsDisposable(t *testing.T) {
55 work := t.TempDir()
56 trusted, done, err := buildHome(work, job{ID: 1, Repo: "alice/app", Trusted: true})
57 if err != nil {
58 t.Fatal(err)
59 }
60 done()
61 home, done, err := buildHome(work, job{ID: 2, Repo: "alice/app"})
62 if err != nil {
63 t.Fatal(err)
64 }
65 if home == trusted || strings.HasPrefix(home, filepath.Join(work, "trusted-home")) {
66 t.Fatalf("untrusted build got a trusted home: %s", home)
67 }
68 // What the Go module cache leaves behind: read-only directories.
69 cache := filepath.Join(home, "go", "pkg", "mod", "example.com", "m@v1")
70 if err := os.MkdirAll(cache, 0o755); err != nil {
71 t.Fatal(err)
72 }
73 if err := os.WriteFile(filepath.Join(cache, "go.mod"), []byte("module m\n"), 0o444); err != nil {
74 t.Fatal(err)
75 }
76 os.Chmod(cache, 0o555)
77 os.Chmod(filepath.Dir(cache), 0o555)
78 done()
79 if _, err := os.Stat(home); !os.IsNotExist(err) {
80 t.Fatalf("untrusted home left behind: %v", err)
81 }
82}
83
84// A repository path is server-validated, but a trusted home must still
85// never resolve outside the runner's home root.
86func TestBuildHomeRefusesTraversal(t *testing.T) {
87 if _, _, err := buildHome(t.TempDir(), job{Repo: "../../etc", Trusted: true}); err == nil {
88 t.Fatal("a traversing repository path produced a build home")
89 }
90}