cmd/gitbay-runner/env_test.go

e3632a550366fe23b2619edba30fc58fab19b598
gitbay/cmd/gitbay-runner/env_test.go history · blame · raw

90 lines · 2881 bytes

 1package main
 2
 3import (
 4	"os"
 5	"strings"
 6	"testing"
 7)
 8
 9// A step's environment is constructed, not inherited: repository content
10// must not see what the operator set on the runner service (#144).
11func TestStepEnvDoesNotInherit(t *testing.T) {
12	t.Setenv("GITBAY_RUNNER_TOKEN", "a-secret-the-service-was-given")
13	t.Setenv("AWS_SECRET_ACCESS_KEY", "also-not-for-builds")
14
15	env := stepEnv(job{Repo: "alice/app", SHA: "abc", Ref: "main", Job: "test"}, "/tmp/buildhome")
16
17	for _, e := range env {
18		if strings.HasPrefix(e, "GITBAY_RUNNER_TOKEN=") || strings.HasPrefix(e, "AWS_SECRET_ACCESS_KEY=") {
19			t.Errorf("the runner's own environment reached a build step: %q", e)
20		}
21	}
22	want := map[string]string{
23		"CI": "true", "GITBAY_REPO": "alice/app", "GITBAY_SHA": "abc",
24		"GITBAY_REF": "main", "GITBAY_JOB": "test",
25		// HOME is the shared build home, not the runner's own, so a
26		// build cannot read the dotfiles where tools keep credentials —
27		// and not the workspace, which is deleted after every build,
28		// taking every tool cache with it.
29		"HOME": "/tmp/buildhome",
30	}
31	got := map[string]string{}
32	for _, e := range env {
33		k, v, _ := strings.Cut(e, "=")
34		got[k] = v
35	}
36	for k, v := range want {
37		if got[k] != v {
38			t.Errorf("%s = %q, want %q", k, got[k], v)
39		}
40	}
41	if got["PATH"] == "" {
42		t.Error("PATH is empty; a step could not find any tool")
43	}
44}
45
46// Secrets are passed through when the server sent them, which it does
47// only for a trusted build.
48func TestStepEnvCarriesSecrets(t *testing.T) {
49	env := stepEnv(job{Secrets: map[string]string{"TOKEN": "s3cret"}}, "/tmp/buildhome")
50	if !containsEnv(env, "TOKEN=s3cret") {
51		t.Error("a trusted build's secret did not reach the step")
52	}
53	env = stepEnv(job{}, "/tmp/buildhome")
54	for _, e := range env {
55		if strings.HasPrefix(e, "TOKEN=") {
56			t.Errorf("a secret appeared with none sent: %q", e)
57		}
58	}
59}
60
61// PATH falls back rather than leaving a step unable to find anything.
62func TestStepEnvPathFallback(t *testing.T) {
63	old := os.Getenv("PATH")
64	os.Unsetenv("PATH")
65	defer os.Setenv("PATH", old)
66	if env := stepEnv(job{}, "/tmp/buildhome"); !containsEnv(env, "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin") {
67		t.Errorf("no PATH fallback: %v", env)
68	}
69}
70
71func containsEnv(env []string, want string) bool {
72	for _, e := range env {
73		if e == want {
74			return true
75		}
76	}
77	return false
78}
79
80// The build home must outlive a build. It was briefly the workspace,
81// which run() removes when the build ends, so every build re-downloaded
82// the Go module cache and the ~50MB sonar scanner.
83func TestStepEnvHomeIsNotTheWorkspace(t *testing.T) {
84	env := stepEnv(job{ID: 7}, "/var/lib/gitbay-runner/work/home")
85	for _, e := range env {
86		if strings.HasPrefix(e, "HOME=") && strings.Contains(e, "build-7") {
87			t.Errorf("HOME is the per-build workspace, which is deleted after the build: %q", e)
88		}
89	}
90}