internal/ci/image_test.go
60 lines · 1660 bytes
1package ci
2
3import "strings"
4
5import "testing"
6
7// An image reference reaches `podman run` as an argument, so ci.Parse is
8// where a repository's config file is stopped from turning it into
9// something else (#144).
10func TestParseImageValidation(t *testing.T) {
11 good := []string{
12 "alpine",
13 "alpine:3.20",
14 "docker.io/library/alpine:3.20",
15 "ghcr.io/krz/builder:v1.2.3",
16 "registry.example.test:5000/team/img:tag",
17 "alpine@sha256:" + strings.Repeat("a", 64),
18 }
19 for _, img := range good {
20 if _, err := Parse([]byte("jobs:\n t:\n image: " + img + "\n steps:\n - echo ok\n")); err != nil {
21 t.Errorf("Parse rejected a valid image %q: %v", img, err)
22 }
23 }
24 bad := []string{
25 "alpine; rm -rf /",
26 "alpine && curl evil.test",
27 "alpine $(whoami)",
28 "alpine `id`",
29 "--privileged",
30 "-v /:/host",
31 "alpine --volume=/etc:/etc",
32 "alpine\nrm -rf /",
33 "alpine image with spaces",
34 "'alpine'",
35 "$IMAGE",
36 }
37 for _, img := range bad {
38 _, err := Parse([]byte("jobs:\n t:\n image: " + quoteYAML(img) + "\n steps:\n - echo ok\n"))
39 if err == nil {
40 t.Errorf("Parse accepted %q as an image", img)
41 continue
42 }
43 if !strings.Contains(err.Error(), "bad image") {
44 t.Errorf("image %q refused for the wrong reason: %v", img, err)
45 }
46 }
47}
48
49// No image means the runner's default, not an error.
50func TestParseImageOptional(t *testing.T) {
51 jobs, err := Parse([]byte("jobs:\n t:\n steps:\n - echo ok\n"))
52 if err != nil {
53 t.Fatal(err)
54 }
55 if jobs[0].Image != "" {
56 t.Errorf("Image = %q, want empty", jobs[0].Image)
57 }
58}
59
60func quoteYAML(s string) string { return "'" + strings.ReplaceAll(s, "'", "''") + "'" }