github.com/containers/podman/v5@v5.1.0-rc1/test/e2e/login_logout_test.go (about) 1 package integration 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "os" 7 "path/filepath" 8 "strconv" 9 "strings" 10 11 . "github.com/containers/podman/v5/test/utils" 12 . "github.com/onsi/ginkgo/v2" 13 . "github.com/onsi/gomega" 14 ) 15 16 var _ = Describe("Podman login and logout", func() { 17 var ( 18 err error 19 authPath string 20 certPath string 21 certDirPath string 22 server string 23 testImg string 24 registriesConfWithSearch []byte 25 ) 26 27 BeforeEach(func() { 28 authPath = filepath.Join(podmanTest.TempDir, "auth") 29 err := os.Mkdir(authPath, os.ModePerm) 30 Expect(err).ToNot(HaveOccurred()) 31 32 htpasswd := SystemExec("htpasswd", []string{"-Bbn", "podmantest", "test"}) 33 htpasswd.WaitWithDefaultTimeout() 34 Expect(htpasswd).Should(ExitCleanly()) 35 36 f, err := os.Create(filepath.Join(authPath, "htpasswd")) 37 Expect(err).ToNot(HaveOccurred()) 38 defer f.Close() 39 40 _, err = f.WriteString(htpasswd.OutputToString()) 41 Expect(err).ToNot(HaveOccurred()) 42 err = f.Sync() 43 Expect(err).ToNot(HaveOccurred()) 44 port := GetPort() 45 server = strings.Join([]string{"localhost", strconv.Itoa(port)}, ":") 46 47 registriesConfWithSearch = []byte(fmt.Sprintf("[registries.search]\nregistries = ['%s']", server)) 48 49 testImg = strings.Join([]string{server, "test-alpine"}, "/") 50 51 certDirPath = filepath.Join(os.Getenv("HOME"), ".config/containers/certs.d", server) 52 err = os.MkdirAll(certDirPath, os.ModePerm) 53 Expect(err).ToNot(HaveOccurred()) 54 cwd, _ := os.Getwd() 55 certPath = filepath.Join(cwd, "../", "certs") 56 57 setup := SystemExec("cp", []string{filepath.Join(certPath, "domain.crt"), filepath.Join(certDirPath, "ca.crt")}) 58 setup.WaitWithDefaultTimeout() 59 60 session := podmanTest.Podman([]string{"run", "-d", "-p", strings.Join([]string{strconv.Itoa(port), strconv.Itoa(port)}, ":"), 61 "-e", strings.Join([]string{"REGISTRY_HTTP_ADDR=0.0.0.0", strconv.Itoa(port)}, ":"), "--name", "registry", "-v", 62 strings.Join([]string{authPath, "/auth:Z"}, ":"), "-e", "REGISTRY_AUTH=htpasswd", "-e", 63 "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm", "-e", "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd", 64 "-v", strings.Join([]string{certPath, "/certs:Z"}, ":"), "-e", "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt", 65 "-e", "REGISTRY_HTTP_TLS_KEY=/certs/domain.key", REGISTRY_IMAGE}) 66 session.WaitWithDefaultTimeout() 67 Expect(session).Should(ExitCleanly()) 68 69 if !WaitContainerReady(podmanTest, "registry", "listening on", 20, 1) { 70 Skip("Cannot start docker registry.") 71 } 72 73 // collision protection: each test uses a unique authfile 74 os.Setenv("REGISTRY_AUTH_FILE", filepath.Join(podmanTest.TempDir, "default-auth.json")) 75 }) 76 77 AfterEach(func() { 78 os.Unsetenv("REGISTRY_AUTH_FILE") 79 os.RemoveAll(authPath) 80 os.RemoveAll(certDirPath) 81 }) 82 83 readAuthInfo := func(filePath string) map[string]interface{} { 84 authBytes, err := os.ReadFile(filePath) 85 Expect(err).ToNot(HaveOccurred()) 86 87 var authInfo map[string]interface{} 88 err = json.Unmarshal(authBytes, &authInfo) 89 Expect(err).ToNot(HaveOccurred()) 90 GinkgoWriter.Println(authInfo) 91 92 const authsKey = "auths" 93 Expect(authInfo).To(HaveKey(authsKey)) 94 95 auths, ok := authInfo[authsKey].(map[string]interface{}) 96 Expect(ok).To(BeTrue(), "authInfo[%s]", authsKey) 97 98 return auths 99 } 100 101 It("podman login and logout", func() { 102 authFile := os.Getenv("REGISTRY_AUTH_FILE") 103 Expect(authFile).NotTo(BeEmpty(), "$REGISTRY_AUTH_FILE") 104 105 session := podmanTest.Podman([]string{"login", "-u", "podmantest", "-p", "test", server}) 106 session.WaitWithDefaultTimeout() 107 Expect(session).Should(ExitCleanly()) 108 109 // Confirm that file was created, with the desired credentials 110 auths := readAuthInfo(authFile) 111 Expect(auths).To(HaveKey(server)) 112 // base64-encoded "podmantest:test" 113 Expect(auths[server]).To(HaveKeyWithValue("auth", "cG9kbWFudGVzdDp0ZXN0")) 114 115 session = podmanTest.Podman([]string{"push", "-q", ALPINE, testImg}) 116 session.WaitWithDefaultTimeout() 117 Expect(session).Should(ExitCleanly()) 118 119 session = podmanTest.Podman([]string{"logout", server}) 120 session.WaitWithDefaultTimeout() 121 Expect(session).Should(ExitCleanly()) 122 123 session = podmanTest.Podman([]string{"push", "-q", ALPINE, testImg}) 124 session.WaitWithDefaultTimeout() 125 Expect(session).To(ExitWithError(125, ": authentication required")) 126 }) 127 128 It("podman login and logout without registry parameter", func() { 129 registriesConf, err := os.CreateTemp("", "TestLoginWithoutParameter") 130 Expect(err).ToNot(HaveOccurred()) 131 defer registriesConf.Close() 132 defer os.Remove(registriesConf.Name()) 133 134 err = os.WriteFile(registriesConf.Name(), registriesConfWithSearch, os.ModePerm) 135 Expect(err).ToNot(HaveOccurred()) 136 137 // Environment is per-process, so this looks very unsafe; actually it seems fine because tests are not 138 // run in parallel unless they opt in by calling t.Parallel(). So don’t do that. 139 oldRCP, hasRCP := os.LookupEnv("CONTAINERS_REGISTRIES_CONF") 140 defer func() { 141 if hasRCP { 142 os.Setenv("CONTAINERS_REGISTRIES_CONF", oldRCP) 143 } else { 144 os.Unsetenv("CONTAINERS_REGISTRIES_CONF") 145 } 146 }() 147 os.Setenv("CONTAINERS_REGISTRIES_CONF", registriesConf.Name()) 148 149 session := podmanTest.Podman([]string{"login", "-u", "podmantest", "-p", "test"}) 150 session.WaitWithDefaultTimeout() 151 Expect(session).Should(ExitCleanly()) 152 153 session = podmanTest.Podman([]string{"logout"}) 154 session.WaitWithDefaultTimeout() 155 Expect(session).Should(ExitCleanly()) 156 }) 157 158 It("podman login and logout with flag --authfile", func() { 159 authFile := filepath.Join(podmanTest.TempDir, "auth.json") 160 session := podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", "--authfile", authFile, server}) 161 session.WaitWithDefaultTimeout() 162 Expect(session).Should(ExitCleanly()) 163 164 readAuthInfo(authFile) 165 166 // push should fail with nonexistent authfile 167 session = podmanTest.Podman([]string{"push", "-q", "--authfile", "/tmp/nonexistent", ALPINE, testImg}) 168 session.WaitWithDefaultTimeout() 169 Expect(session).To(ExitWithError(125, "credential file is not accessible: faccessat /tmp/nonexistent: no such file or directory")) 170 171 session = podmanTest.Podman([]string{"push", "-q", "--authfile", authFile, ALPINE, testImg}) 172 session.WaitWithDefaultTimeout() 173 Expect(session).Should(ExitCleanly()) 174 175 session = podmanTest.Podman([]string{"run", "-q", "--authfile", authFile, testImg}) 176 session.WaitWithDefaultTimeout() 177 Expect(session).Should(ExitCleanly()) 178 179 // logout should fail with nonexistent authfile 180 session = podmanTest.Podman([]string{"logout", "--authfile", "/tmp/nonexistent", server}) 181 session.WaitWithDefaultTimeout() 182 Expect(session).To(ExitWithError(125, "credential file is not accessible: faccessat /tmp/nonexistent: no such file or directory")) 183 184 session = podmanTest.Podman([]string{"logout", "--authfile", authFile, server}) 185 session.WaitWithDefaultTimeout() 186 Expect(session).Should(ExitCleanly()) 187 }) 188 189 It("podman login and logout --compat-auth-file flag handling", func() { 190 // A minimal smoke test 191 compatAuthFile := filepath.Join(podmanTest.TempDir, "config.json") 192 session := podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", "--compat-auth-file", compatAuthFile, server}) 193 session.WaitWithDefaultTimeout() 194 Expect(session).Should(ExitCleanly()) 195 196 readAuthInfo(compatAuthFile) 197 198 session = podmanTest.Podman([]string{"logout", "--compat-auth-file", compatAuthFile, server}) 199 session.WaitWithDefaultTimeout() 200 Expect(session).Should(ExitCleanly()) 201 202 // logout should fail with nonexistent authfile 203 session = podmanTest.Podman([]string{"logout", "--compat-auth-file", "/tmp/nonexistent", server}) 204 session.WaitWithDefaultTimeout() 205 Expect(session).To(ExitWithError(125, "credential file is not accessible: faccessat /tmp/nonexistent: no such file or directory")) 206 207 // inconsistent command line flags are rejected 208 // Pre-create the files to make sure we are not hitting the “file not found” path 209 authFile := filepath.Join(podmanTest.TempDir, "auth.json") 210 err := os.WriteFile(authFile, []byte("{}"), 0o700) 211 Expect(err).ToNot(HaveOccurred()) 212 err = os.WriteFile(compatAuthFile, []byte("{}"), 0o700) 213 Expect(err).ToNot(HaveOccurred()) 214 215 session = podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", 216 "--authfile", authFile, "--compat-auth-file", compatAuthFile, server}) 217 session.WaitWithDefaultTimeout() 218 Expect(session).To(ExitWithError(125, "options for paths to the credential file and to the Docker-compatible credential file can not be set simultaneously")) 219 220 session = podmanTest.Podman([]string{"logout", "--authfile", authFile, "--compat-auth-file", compatAuthFile, server}) 221 session.WaitWithDefaultTimeout() 222 Expect(session).To(ExitWithError(125, "options for paths to the credential file and to the Docker-compatible credential file can not be set simultaneously")) 223 }) 224 225 It("podman manifest with --authfile", func() { 226 os.Unsetenv("REGISTRY_AUTH_FILE") 227 228 authFile := filepath.Join(podmanTest.TempDir, "auth.json") 229 session := podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", "--authfile", authFile, server}) 230 session.WaitWithDefaultTimeout() 231 Expect(session).Should(ExitCleanly()) 232 233 readAuthInfo(authFile) 234 235 session = podmanTest.Podman([]string{"manifest", "create", testImg}) 236 session.WaitWithDefaultTimeout() 237 Expect(session).Should(ExitCleanly()) 238 239 session = podmanTest.Podman([]string{"manifest", "push", "-q", testImg}) 240 session.WaitWithDefaultTimeout() 241 Expect(session).To(ExitWithError(125, ": authentication required")) 242 243 session = podmanTest.Podman([]string{"manifest", "push", "-q", "--authfile", authFile, testImg}) 244 session.WaitWithDefaultTimeout() 245 Expect(session).Should(ExitCleanly()) 246 247 // Now remove the local manifest to trigger remote inspection 248 session = podmanTest.Podman([]string{"manifest", "rm", testImg}) 249 session.WaitWithDefaultTimeout() 250 Expect(session).Should(ExitCleanly()) 251 252 session = podmanTest.Podman([]string{"manifest", "inspect", testImg}) 253 session.WaitWithDefaultTimeout() 254 Expect(session).To(ExitWithError(125, ": authentication required")) 255 256 session = podmanTest.Podman([]string{"manifest", "inspect", "--authfile", authFile, testImg}) 257 session.WaitWithDefaultTimeout() 258 Expect(session).Should(ExitCleanly()) 259 }) 260 261 It("podman login and logout with --tls-verify", func() { 262 session := podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", "--tls-verify=false", server}) 263 session.WaitWithDefaultTimeout() 264 Expect(session).Should(ExitCleanly()) 265 266 session = podmanTest.Podman([]string{"push", "-q", ALPINE, testImg}) 267 session.WaitWithDefaultTimeout() 268 Expect(session).Should(ExitCleanly()) 269 270 session = podmanTest.Podman([]string{"logout", server}) 271 session.WaitWithDefaultTimeout() 272 Expect(session).Should(ExitCleanly()) 273 }) 274 It("podman login and logout with --cert-dir", func() { 275 certDir := filepath.Join(podmanTest.TempDir, "certs") 276 err := os.MkdirAll(certDir, os.ModePerm) 277 Expect(err).ToNot(HaveOccurred()) 278 279 setup := SystemExec("cp", []string{filepath.Join(certPath, "domain.crt"), filepath.Join(certDir, "ca.crt")}) 280 setup.WaitWithDefaultTimeout() 281 282 session := podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", "--cert-dir", certDir, server}) 283 session.WaitWithDefaultTimeout() 284 Expect(session).Should(ExitCleanly()) 285 286 session = podmanTest.Podman([]string{"push", "-q", "--cert-dir", certDir, ALPINE, testImg}) 287 session.WaitWithDefaultTimeout() 288 Expect(session).Should(ExitCleanly()) 289 290 session = podmanTest.Podman([]string{"logout", server}) 291 session.WaitWithDefaultTimeout() 292 Expect(session).Should(ExitCleanly()) 293 }) 294 It("podman login and logout with multi registry", func() { 295 certDir := filepath.Join(os.Getenv("HOME"), ".config/containers/certs.d", "localhost:9001") 296 err = os.MkdirAll(certDir, os.ModePerm) 297 Expect(err).ToNot(HaveOccurred()) 298 299 cwd, _ := os.Getwd() 300 certPath = filepath.Join(cwd, "../", "certs") 301 302 setup := SystemExec("cp", []string{filepath.Join(certPath, "domain.crt"), filepath.Join(certDir, "ca.crt")}) 303 setup.WaitWithDefaultTimeout() 304 defer os.RemoveAll(certDir) 305 306 // N/B: This second registry container shares the same auth and cert dirs 307 // as the registry started from BeforeEach(). Since this one starts 308 // second, re-labeling the volumes should keep SELinux happy. 309 session := podmanTest.Podman([]string{"run", "-d", "-p", "9001:9001", "-e", "REGISTRY_HTTP_ADDR=0.0.0.0:9001", "--name", "registry1", "-v", 310 strings.Join([]string{authPath, "/auth:z"}, ":"), "-e", "REGISTRY_AUTH=htpasswd", "-e", 311 "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm", "-e", "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd", 312 "-v", strings.Join([]string{certPath, "/certs:z"}, ":"), "-e", "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt", 313 "-e", "REGISTRY_HTTP_TLS_KEY=/certs/domain.key", REGISTRY_IMAGE}) 314 session.WaitWithDefaultTimeout() 315 Expect(session).Should(ExitCleanly()) 316 317 if !WaitContainerReady(podmanTest, "registry1", "listening on", 20, 1) { 318 Skip("Cannot start docker registry.") 319 } 320 321 session = podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", server}) 322 session.WaitWithDefaultTimeout() 323 Expect(session).Should(ExitCleanly()) 324 325 session = podmanTest.Podman([]string{"push", "-q", ALPINE, testImg}) 326 session.WaitWithDefaultTimeout() 327 Expect(session).Should(ExitCleanly()) 328 329 session = podmanTest.Podman([]string{"push", "-q", ALPINE, "localhost:9001/test-alpine"}) 330 session.WaitWithDefaultTimeout() 331 Expect(session).To(ExitWithError(125, "/test-alpine: authentication required")) 332 333 session = podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", "localhost:9001"}) 334 session.WaitWithDefaultTimeout() 335 Expect(session).Should(ExitCleanly()) 336 337 session = podmanTest.Podman([]string{"push", "-q", ALPINE, testImg}) 338 session.WaitWithDefaultTimeout() 339 Expect(session).Should(ExitCleanly()) 340 341 session = podmanTest.Podman([]string{"push", "-q", ALPINE, "localhost:9001/test-alpine"}) 342 session.WaitWithDefaultTimeout() 343 Expect(session).Should(ExitCleanly()) 344 345 session = podmanTest.Podman([]string{"logout", server}) 346 session.WaitWithDefaultTimeout() 347 Expect(session).Should(ExitCleanly()) 348 349 session = podmanTest.Podman([]string{"push", "-q", ALPINE, testImg}) 350 session.WaitWithDefaultTimeout() 351 Expect(session).To(ExitWithError(125, "/test-alpine: authentication required")) 352 353 session = podmanTest.Podman([]string{"push", "-q", ALPINE, "localhost:9001/test-alpine"}) 354 session.WaitWithDefaultTimeout() 355 Expect(session).Should(ExitCleanly()) 356 357 session = podmanTest.Podman([]string{"login", "--username", "podmantest", "--password", "test", "localhost:9001"}) 358 session.WaitWithDefaultTimeout() 359 Expect(session).Should(ExitCleanly()) 360 361 session = podmanTest.Podman([]string{"logout", "-a"}) 362 session.WaitWithDefaultTimeout() 363 Expect(session).Should(ExitCleanly()) 364 365 session = podmanTest.Podman([]string{"push", "-q", ALPINE, testImg}) 366 session.WaitWithDefaultTimeout() 367 Expect(session).To(ExitWithError(125, "/test-alpine: authentication required")) 368 369 session = podmanTest.Podman([]string{"push", "-q", ALPINE, "localhost:9001/test-alpine"}) 370 session.WaitWithDefaultTimeout() 371 Expect(session).To(ExitWithError(125, "/test-alpine: authentication required")) 372 }) 373 374 It("podman login and logout with repository", func() { 375 authFile := filepath.Join(podmanTest.TempDir, "auth.json") 376 377 testRepository := server + "/podmantest" 378 session := podmanTest.Podman([]string{ 379 "login", 380 "-u", "podmantest", 381 "-p", "test", 382 "--authfile", authFile, 383 testRepository, 384 }) 385 session.WaitWithDefaultTimeout() 386 Expect(session).Should(ExitCleanly()) 387 388 authInfo := readAuthInfo(authFile) 389 Expect(authInfo).To(HaveKey(testRepository)) 390 391 session = podmanTest.Podman([]string{ 392 "logout", 393 "--authfile", authFile, 394 testRepository, 395 }) 396 session.WaitWithDefaultTimeout() 397 Expect(session).Should(ExitCleanly()) 398 399 authInfo = readAuthInfo(authFile) 400 Expect(authInfo).NotTo(HaveKey(testRepository)) 401 }) 402 403 It("podman login and logout with repository and specified image", func() { 404 authFile := filepath.Join(podmanTest.TempDir, "auth.json") 405 406 testTarget := server + "/podmantest/test-alpine" 407 session := podmanTest.Podman([]string{ 408 "login", 409 "-u", "podmantest", 410 "-p", "test", 411 "--authfile", authFile, 412 testTarget, 413 }) 414 session.WaitWithDefaultTimeout() 415 Expect(session).Should(ExitCleanly()) 416 417 authInfo := readAuthInfo(authFile) 418 Expect(authInfo).To(HaveKey(testTarget)) 419 420 session = podmanTest.Podman([]string{ 421 "push", "-q", 422 "--authfile", authFile, 423 ALPINE, testTarget, 424 }) 425 session.WaitWithDefaultTimeout() 426 Expect(session).Should(ExitCleanly()) 427 428 }) 429 430 It("podman login and logout with repository with fallback", func() { 431 authFile := filepath.Join(podmanTest.TempDir, "auth.json") 432 433 testRepos := []string{ 434 server + "/podmantest", 435 server, 436 } 437 for _, testRepo := range testRepos { 438 session := podmanTest.Podman([]string{ 439 "login", 440 "-u", "podmantest", 441 "-p", "test", 442 "--authfile", authFile, 443 testRepo, 444 }) 445 session.WaitWithDefaultTimeout() 446 Expect(session).Should(ExitCleanly()) 447 } 448 449 authInfo := readAuthInfo(authFile) 450 Expect(authInfo).To(HaveKey(testRepos[0])) 451 Expect(authInfo).To(HaveKey(testRepos[1])) 452 453 session := podmanTest.Podman([]string{ 454 "push", "-q", 455 "--authfile", authFile, 456 ALPINE, testRepos[0] + "/test-image-alpine", 457 }) 458 session.WaitWithDefaultTimeout() 459 Expect(session).Should(ExitCleanly()) 460 461 session = podmanTest.Podman([]string{ 462 "logout", 463 "--authfile", authFile, 464 testRepos[0], 465 }) 466 session.WaitWithDefaultTimeout() 467 Expect(session).Should(ExitCleanly()) 468 469 session = podmanTest.Podman([]string{ 470 "push", "-q", 471 "--authfile", authFile, 472 ALPINE, testRepos[0] + "/test-image-alpine", 473 }) 474 session.WaitWithDefaultTimeout() 475 Expect(session).Should(ExitCleanly()) 476 477 session = podmanTest.Podman([]string{ 478 "logout", 479 "--authfile", authFile, 480 testRepos[1], 481 }) 482 session.WaitWithDefaultTimeout() 483 Expect(session).Should(ExitCleanly()) 484 485 authInfo = readAuthInfo(authFile) 486 Expect(authInfo).NotTo(HaveKey(testRepos[0])) 487 Expect(authInfo).NotTo(HaveKey(testRepos[1])) 488 }) 489 490 It("podman login with http{s} prefix", func() { 491 authFile := filepath.Join(podmanTest.TempDir, "auth.json") 492 493 for _, invalidArg := range []string{ 494 "https://" + server + "/podmantest", 495 "http://" + server + "/podmantest/image:latest", 496 } { 497 session := podmanTest.Podman([]string{ 498 "login", 499 "-u", "podmantest", 500 "-p", "test", 501 "--authfile", authFile, 502 invalidArg, 503 }) 504 session.WaitWithDefaultTimeout() 505 Expect(session).To(ExitCleanly()) 506 } 507 }) 508 509 It("podman login and logout with repository push with invalid auth.json credentials", func() { 510 authFile := filepath.Join(podmanTest.TempDir, "auth.json") 511 // only `server` contains the correct login data 512 err := os.WriteFile(authFile, []byte(fmt.Sprintf(`{"auths": { 513 "%s/podmantest": { "auth": "cG9kbWFudGVzdDp3cm9uZw==" }, 514 "%s": { "auth": "cG9kbWFudGVzdDp0ZXN0" } 515 }}`, server, server)), 0644) 516 Expect(err).ToNot(HaveOccurred()) 517 518 session := podmanTest.Podman([]string{ 519 "push", "-q", 520 "--authfile", authFile, 521 ALPINE, server + "/podmantest/test-image", 522 }) 523 session.WaitWithDefaultTimeout() 524 Expect(session).To(ExitWithError(125, "/test-image: authentication required")) 525 526 session = podmanTest.Podman([]string{ 527 "push", "-q", 528 "--authfile", authFile, 529 ALPINE, server + "/test-image", 530 }) 531 session.WaitWithDefaultTimeout() 532 Expect(session).To(ExitCleanly()) 533 }) 534 535 It("podman login and logout with repository pull with wrong auth.json credentials", func() { 536 authFile := filepath.Join(podmanTest.TempDir, "auth.json") 537 538 testTarget := server + "/podmantest/test-alpine" 539 session := podmanTest.Podman([]string{ 540 "login", 541 "-u", "podmantest", 542 "-p", "test", 543 "--authfile", authFile, 544 testTarget, 545 }) 546 session.WaitWithDefaultTimeout() 547 Expect(session).Should(ExitCleanly()) 548 549 session = podmanTest.Podman([]string{ 550 "push", "-q", 551 "--authfile", authFile, 552 ALPINE, testTarget, 553 }) 554 session.WaitWithDefaultTimeout() 555 Expect(session).Should(ExitCleanly()) 556 557 // only `server + /podmantest` and `server` have the correct login data 558 err := os.WriteFile(authFile, []byte(fmt.Sprintf(`{"auths": { 559 "%s/podmantest/test-alpine": { "auth": "cG9kbWFudGVzdDp3cm9uZw==" }, 560 "%s/podmantest": { "auth": "cG9kbWFudGVzdDp0ZXN0" }, 561 "%s": { "auth": "cG9kbWFudGVzdDp0ZXN0" } 562 }}`, server, server, server)), 0644) 563 Expect(err).ToNot(HaveOccurred()) 564 565 session = podmanTest.Podman([]string{ 566 "pull", "-q", 567 "--authfile", authFile, 568 server + "/podmantest/test-alpine", 569 }) 570 session.WaitWithDefaultTimeout() 571 Expect(session).To(ExitWithError(125, "/test-alpine: authentication required")) 572 }) 573 })