github.com/metasources/buildx@v0.0.0-20230418141019-7aa1459cedea/test/cli/packages_cmd_test.go (about) 1 package cli 2 3 import ( 4 "fmt" 5 "path/filepath" 6 "testing" 7 ) 8 9 func TestPackagesCmdFlags(t *testing.T) { 10 hiddenPackagesImage := "docker-archive:" + getFixtureImage(t, "image-hidden-packages") 11 coverageImage := "docker-archive:" + getFixtureImage(t, "image-pkg-coverage") 12 nodeBinaryImage := "docker-archive:" + getFixtureImage(t, "image-node-binary") 13 //badBinariesImage := "docker-archive:" + getFixtureImage(t, "image-bad-binaries") 14 tmp := t.TempDir() + "/" 15 16 tests := []struct { 17 name string 18 args []string 19 env map[string]string 20 assertions []traitAssertion 21 }{ 22 { 23 name: "no-args-shows-help", 24 args: []string{"packages"}, 25 assertions: []traitAssertion{ 26 assertInOutput("an image/directory argument is required"), // specific error that should be shown 27 assertInOutput("Generate a packaged-based Software Bill Of Materials"), // excerpt from help description 28 assertFailingReturnCode, 29 }, 30 }, 31 { 32 name: "json-output-flag", 33 args: []string{"packages", "-o", "json", coverageImage}, 34 assertions: []traitAssertion{ 35 assertJsonReport, 36 assertSuccessfulReturnCode, 37 }, 38 }, 39 { 40 name: "multiple-output-flags", 41 args: []string{"packages", "-o", "table", "-o", "json=" + tmp + ".tmp/multiple-output-flag-test.json", coverageImage}, 42 assertions: []traitAssertion{ 43 assertTableReport, 44 assertFileExists(tmp + ".tmp/multiple-output-flag-test.json"), 45 assertSuccessfulReturnCode, 46 }, 47 }, 48 // I haven't been able to reproduce locally yet, but in CI this has proven to be unstable: 49 // For the same commit: 50 // pass: https://github.com/metasources/buildx/runs/4611344142?check_suite_focus=true 51 // fail: https://github.com/metasources/buildx/runs/4611343586?check_suite_focus=true 52 // For the meantime this test will be commented out, but should be added back in as soon as possible. 53 // 54 //{ 55 // name: "regression-survive-bad-binaries", 56 // // this image has all sorts of rich binaries from the clang-13 test suite that should do pretty bad things 57 // // to the go cataloger binary path. We should NEVER let a panic stop the cataloging process for these 58 // // specific cases. 59 // 60 // // this is more of an integration test, however, to assert the output we want to see from the application 61 // // a CLI test is much easier. 62 // args: []string{"packages", "-vv", badBinariesImage}, 63 // assertions: []traitAssertion{ 64 // assertInOutput("could not parse possible go binary"), 65 // assertSuccessfulReturnCode, 66 // }, 67 //}, 68 { 69 name: "output-env-binding", 70 env: map[string]string{ 71 "BUILDX_OUTPUT": "json", 72 }, 73 args: []string{"packages", coverageImage}, 74 assertions: []traitAssertion{ 75 assertJsonReport, 76 assertSuccessfulReturnCode, 77 }, 78 }, 79 { 80 name: "table-output-flag", 81 args: []string{"packages", "-o", "table", coverageImage}, 82 assertions: []traitAssertion{ 83 assertTableReport, 84 assertSuccessfulReturnCode, 85 }, 86 }, 87 { 88 name: "default-output-flag", 89 args: []string{"packages", coverageImage}, 90 assertions: []traitAssertion{ 91 assertTableReport, 92 assertSuccessfulReturnCode, 93 }, 94 }, 95 { 96 name: "squashed-scope-flag", 97 args: []string{"packages", "-o", "json", "-s", "squashed", coverageImage}, 98 assertions: []traitAssertion{ 99 assertPackageCount(37), 100 assertSuccessfulReturnCode, 101 }, 102 }, 103 { 104 name: "squashed-scope-flag-hidden-packages", 105 args: []string{"packages", "-o", "json", "-s", "squashed", hiddenPackagesImage}, 106 assertions: []traitAssertion{ 107 assertPackageCount(163), 108 assertNotInOutput("vsftpd"), // hidden package 109 assertSuccessfulReturnCode, 110 }, 111 }, 112 { 113 name: "all-layers-scope-flag", 114 args: []string{"packages", "-o", "json", "-s", "all-layers", hiddenPackagesImage}, 115 assertions: []traitAssertion{ 116 assertPackageCount(164), // packages are now deduplicated for this case 117 assertInOutput("all-layers"), 118 assertInOutput("vsftpd"), // hidden package 119 assertSuccessfulReturnCode, 120 }, 121 }, 122 { 123 name: "all-layers-scope-flag-by-env", 124 args: []string{"packages", "-o", "json", hiddenPackagesImage}, 125 env: map[string]string{ 126 "BUILDX_PACKAGE_CATALOGER_SCOPE": "all-layers", 127 }, 128 assertions: []traitAssertion{ 129 assertPackageCount(164), // packages are now deduplicated for this case 130 assertInOutput("all-layers"), 131 assertInOutput("vsftpd"), // hidden package 132 assertSuccessfulReturnCode, 133 }, 134 }, 135 { 136 // we want to make certain that buildx can catalog a single go binary and get a SBOM report that is not empty 137 name: "catalog-single-go-binary", 138 args: []string{"packages", "-o", "json", getBuildxBinaryLocation(t)}, 139 assertions: []traitAssertion{ 140 assertJsonReport, 141 assertStdoutLengthGreaterThan(1000), 142 assertSuccessfulReturnCode, 143 }, 144 }, 145 { 146 name: "catalog-node-js-binary", 147 args: []string{"packages", "-o", "json", nodeBinaryImage}, 148 assertions: []traitAssertion{ 149 assertJsonReport, 150 assertInOutput("node.js"), 151 assertSuccessfulReturnCode, 152 }, 153 }, 154 { 155 name: "responds-to-package-cataloger-search-options", 156 args: []string{"packages", "-vv"}, 157 env: map[string]string{ 158 "BUILDX_PACKAGE_SEARCH_UNINDEXED_ARCHIVES": "true", 159 "BUILDX_PACKAGE_SEARCH_INDEXED_ARCHIVES": "false", 160 }, 161 assertions: []traitAssertion{ 162 // the application config in the log matches that of what we expect to have been configured. Note: 163 // we are not testing further wiring of this option, only that the config responds to 164 // package-cataloger-level options. 165 assertInOutput("search-unindexed-archives: true"), 166 assertInOutput("search-indexed-archives: false"), 167 }, 168 }, 169 { 170 name: "platform-option-wired-up", 171 args: []string{"packages", "--platform", "arm64", "-o", "json", "registry:busybox:1.31"}, 172 assertions: []traitAssertion{ 173 assertInOutput("sha256:1ee006886991ad4689838d3a288e0dd3fd29b70e276622f16b67a8922831a853"), // linux/arm64 image digest 174 assertSuccessfulReturnCode, 175 }, 176 }, 177 { 178 name: "json-file-flag", 179 args: []string{"packages", "-o", "json", "--file", filepath.Join(tmp, "output-1.json"), coverageImage}, 180 assertions: []traitAssertion{ 181 assertSuccessfulReturnCode, 182 assertFileOutput(t, filepath.Join(tmp, "output-1.json"), 183 assertJsonReport, 184 ), 185 }, 186 }, 187 { 188 name: "json-output-flag-to-file", 189 args: []string{"packages", "-o", fmt.Sprintf("json=%s", filepath.Join(tmp, "output-2.json")), coverageImage}, 190 assertions: []traitAssertion{ 191 assertSuccessfulReturnCode, 192 assertFileOutput(t, filepath.Join(tmp, "output-2.json"), 193 assertJsonReport, 194 ), 195 }, 196 }, 197 { 198 name: "catalogers-option", 199 // This will detect enable python-index-cataloger, python-package-cataloger and ruby-gemspec cataloger 200 args: []string{"packages", "-o", "json", "--catalogers", "python,ruby-gemspec", coverageImage}, 201 assertions: []traitAssertion{ 202 assertPackageCount(13), 203 assertSuccessfulReturnCode, 204 }, 205 }, 206 { 207 name: "override-default-parallelism", 208 args: []string{"packages", "-vvv", "-o", "json", coverageImage}, 209 env: map[string]string{ 210 "BUILDX_PARALLELISM": "2", 211 }, 212 assertions: []traitAssertion{ 213 // the application config in the log matches that of what we expect to have been configured. 214 assertInOutput("parallelism: 2"), 215 assertInOutput("parallelism=2"), 216 assertPackageCount(37), 217 assertSuccessfulReturnCode, 218 }, 219 }, 220 { 221 name: "default-parallelism", 222 args: []string{"packages", "-vvv", "-o", "json", coverageImage}, 223 assertions: []traitAssertion{ 224 // the application config in the log matches that of what we expect to have been configured. 225 assertInOutput("parallelism: 1"), 226 assertInOutput("parallelism=1"), 227 assertPackageCount(37), 228 assertSuccessfulReturnCode, 229 }, 230 }, 231 { 232 name: "password and key not in config output", 233 args: []string{"packages", "-vvv", "-o", "json", coverageImage}, 234 env: map[string]string{ 235 "BUILDX_ATTEST_PASSWORD": "secret_password", 236 "BUILDX_ATTEST_KEY": "secret_key_path", 237 }, 238 assertions: []traitAssertion{ 239 assertNotInOutput("secret_password"), 240 assertNotInOutput("secret_key_path"), 241 assertPackageCount(37), 242 assertSuccessfulReturnCode, 243 }, 244 }, 245 } 246 247 for _, test := range tests { 248 t.Run(test.name, func(t *testing.T) { 249 cmd, stdout, stderr := runBuildx(t, test.env, test.args...) 250 for _, traitFn := range test.assertions { 251 traitFn(t, stdout, stderr, cmd.ProcessState.ExitCode()) 252 } 253 logOutputOnFailure(t, cmd, stdout, stderr) 254 }) 255 } 256 } 257 258 func TestRegistryAuth(t *testing.T) { 259 host := "localhost:17" 260 image := fmt.Sprintf("%s/something:latest", host) 261 args := []string{"packages", "-vv", fmt.Sprintf("registry:%s", image)} 262 263 tests := []struct { 264 name string 265 args []string 266 env map[string]string 267 assertions []traitAssertion 268 }{ 269 { 270 name: "fallback to keychain", 271 args: args, 272 assertions: []traitAssertion{ 273 assertInOutput("source=OciRegistry"), 274 assertInOutput(image), 275 assertInOutput("no registry credentials configured, using the default keychain"), 276 }, 277 }, 278 { 279 name: "use creds", 280 args: args, 281 env: map[string]string{ 282 "BUILDX_REGISTRY_AUTH_AUTHORITY": host, 283 "BUILDX_REGISTRY_AUTH_USERNAME": "username", 284 "BUILDX_REGISTRY_AUTH_PASSWORD": "password", 285 }, 286 assertions: []traitAssertion{ 287 assertInOutput("source=OciRegistry"), 288 assertInOutput(image), 289 assertInOutput(fmt.Sprintf(`using basic auth for registry "%s"`, host)), 290 }, 291 }, 292 { 293 name: "use token", 294 args: args, 295 env: map[string]string{ 296 "BUILDX_REGISTRY_AUTH_AUTHORITY": host, 297 "BUILDX_REGISTRY_AUTH_TOKEN": "token", 298 }, 299 assertions: []traitAssertion{ 300 assertInOutput("source=OciRegistry"), 301 assertInOutput(image), 302 assertInOutput(fmt.Sprintf(`using token for registry "%s"`, host)), 303 }, 304 }, 305 { 306 name: "not enough info fallsback to keychain", 307 args: args, 308 env: map[string]string{ 309 "BUILDX_REGISTRY_AUTH_AUTHORITY": host, 310 }, 311 assertions: []traitAssertion{ 312 assertInOutput("source=OciRegistry"), 313 assertInOutput(image), 314 assertInOutput(`no registry credentials configured, using the default keychain`), 315 }, 316 }, 317 { 318 name: "allows insecure http flag", 319 args: args, 320 env: map[string]string{ 321 "BUILDX_REGISTRY_INSECURE_USE_HTTP": "true", 322 }, 323 assertions: []traitAssertion{ 324 assertInOutput("insecure-use-http: true"), 325 }, 326 }, 327 } 328 329 for _, test := range tests { 330 t.Run(test.name, func(t *testing.T) { 331 cmd, stdout, stderr := runBuildx(t, test.env, test.args...) 332 for _, traitAssertionFn := range test.assertions { 333 traitAssertionFn(t, stdout, stderr, cmd.ProcessState.ExitCode()) 334 } 335 logOutputOnFailure(t, cmd, stdout, stderr) 336 }) 337 } 338 }