github.com/adevinta/lava@v0.7.2/cmd/lava/internal/run/run_test.go (about) 1 // Copyright 2024 Adevinta 2 3 package run 4 5 import ( 6 "context" 7 "flag" 8 "fmt" 9 "log/slog" 10 "os" 11 "testing" 12 13 agentconfig "github.com/adevinta/vulcan-agent/config" 14 "github.com/docker/docker/api/types/filters" 15 "github.com/docker/docker/api/types/image" 16 "github.com/jroimartin/clilog" 17 18 "github.com/adevinta/lava/internal/containers" 19 "github.com/adevinta/lava/internal/report" 20 ) 21 22 const checktype = "vulcansec/vulcan-gitleaks:ea42ea5-b6abd8a" 23 24 var testRuntime containers.Runtime 25 26 func TestMain(m *testing.M) { 27 flag.Parse() 28 29 level := slog.LevelError 30 if testing.Verbose() { 31 level = slog.LevelDebug 32 } 33 34 h := clilog.NewCLIHandler(os.Stderr, &clilog.HandlerOptions{Level: level}) 35 slog.SetDefault(slog.New(h)) 36 37 rt, err := containers.GetenvRuntime() 38 if err != nil { 39 fmt.Fprintf(os.Stderr, "error: get env runtime: %v", err) 40 os.Exit(2) 41 } 42 testRuntime = rt 43 44 os.Exit(m.Run()) 45 } 46 47 func TestRunRun(t *testing.T) { 48 tests := []struct { 49 name string 50 path string 51 wantExitCode int 52 }{ 53 { 54 name: "good path", 55 path: "testdata/goodpath", 56 wantExitCode: 0, 57 }, 58 { 59 name: "vulnerable path", 60 path: "testdata/vulnpath", 61 wantExitCode: 103, 62 }, 63 } 64 65 for _, tt := range tests { 66 t.Run(tt.name, func(t *testing.T) { 67 oldPwd := mustGetwd() 68 oldOsExit := osExit 69 oldRunO := runO 70 oldRunOptfile := runOptfile 71 defer func() { 72 mustChdir(oldPwd) 73 osExit = oldOsExit 74 runO = oldRunO 75 runOptfile = oldRunOptfile 76 }() 77 78 runO = "output.txt" 79 runOptfile = "options.json" 80 81 var exitCode int 82 osExit = func(status int) { 83 exitCode = status 84 } 85 86 mustChdir(tt.path) 87 if err := runRun([]string{checktype, "."}); err != nil { 88 t.Fatalf("unexpected error: %v", err) 89 } 90 91 if exitCode != tt.wantExitCode { 92 t.Errorf("unexpected exit code: got: %v, want: %v", exitCode, tt.wantExitCode) 93 } 94 }) 95 } 96 } 97 98 func TestRunRun_path_checktype(t *testing.T) { 99 oldPwd := mustGetwd() 100 oldOsExit := osExit 101 oldRunO := runO 102 defer func() { 103 mustChdir(oldPwd) 104 osExit = oldOsExit 105 runO = oldRunO 106 }() 107 108 runO = "output.txt" 109 110 var exitCode int 111 osExit = func(status int) { 112 exitCode = status 113 } 114 115 cli, err := containers.NewDockerdClient(testRuntime) 116 if err != nil { 117 t.Fatalf("could not create dockerd client: %v", err) 118 } 119 defer cli.Close() 120 121 mustChdir("testdata/lava-run-test") 122 if err := runRun([]string{".", "."}); err != nil { 123 t.Fatalf("unexpected error: %v", err) 124 } 125 defer func() { 126 const imgRef = "lava-run-test:lava-run" 127 rmOpts := image.RemoveOptions{Force: true, PruneChildren: true} 128 if _, err := cli.ImageRemove(context.Background(), imgRef, rmOpts); err != nil { 129 t.Logf("could not delete test Docker image %q: %v", imgRef, err) 130 } 131 }() 132 133 if exitCode != int(report.ExitCodeCritical) { 134 t.Errorf("unexpected exit code: %v", exitCode) 135 } 136 } 137 138 func TestRunRun_path_checktype_same_id(t *testing.T) { 139 oldPwd := mustGetwd() 140 oldOsExit := osExit 141 oldRunO := runO 142 oldPull := runPull 143 defer func() { 144 mustChdir(oldPwd) 145 osExit = oldOsExit 146 runO = oldRunO 147 runPull = oldPull 148 }() 149 150 runO = "output.txt" 151 runPull = agentconfig.PullPolicyNever 152 153 var exitCode int 154 osExit = func(status int) { 155 exitCode = status 156 } 157 158 cli, err := containers.NewDockerdClient(testRuntime) 159 if err != nil { 160 t.Fatalf("could not create dockerd client: %v", err) 161 } 162 defer cli.Close() 163 164 mustChdir("testdata/lava-run-test") 165 166 const ref = "lava-run-test:lava-run" 167 168 defer func() { 169 rmOpts := image.RemoveOptions{Force: true, PruneChildren: true} 170 if _, err := cli.ImageRemove(context.Background(), ref, rmOpts); err != nil { 171 t.Logf("could not delete test Docker image %q: %v", ref, err) 172 } 173 }() 174 175 var ids [2]string 176 for i := 0; i < 2; i++ { 177 exitCode = 0 178 if err := runRun([]string{".", "."}); err != nil { 179 t.Fatalf("unexpected error in run %v: %v", i, err) 180 } 181 if exitCode != int(report.ExitCodeCritical) { 182 t.Errorf("unexpected exit code in run %v: %v", i, exitCode) 183 } 184 185 summ, err := cli.ImageList(context.Background(), image.ListOptions{ 186 Filters: filters.NewArgs(filters.Arg("reference", ref)), 187 }) 188 if err != nil { 189 t.Fatalf("could not get image details in run %v: %v", i, err) 190 } 191 if len(summ) != 1 { 192 t.Fatalf("wrong number of images in run %v: %v", i, err) 193 } 194 ids[i] = summ[0].ID 195 } 196 197 if ids[0] != ids[1] { 198 t.Errorf("image IDs do not match: %q != %q", ids[0], ids[1]) 199 } 200 } 201 202 // mustGetwd returns a rooted path name corresponding to the current 203 // directory. It panics on error. 204 func mustGetwd() string { 205 wd, err := os.Getwd() 206 if err != nil { 207 panic(err) 208 } 209 return wd 210 } 211 212 // mustChdir changes the current working directory to the named 213 // directory. It panics on error. 214 func mustChdir(path string) { 215 if err := os.Chdir(path); err != nil { 216 panic(err) 217 } 218 }