zotregistry.io/zot@v1.4.4-0.20231124084042-02a8ed785457/pkg/cli/server/root_test.go (about) 1 package server_test 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "os" 7 "path" 8 "path/filepath" 9 "testing" 10 "time" 11 12 . "github.com/smartystreets/goconvey/convey" 13 14 "zotregistry.io/zot/pkg/api" 15 "zotregistry.io/zot/pkg/api/config" 16 cli "zotregistry.io/zot/pkg/cli/server" 17 storageConstants "zotregistry.io/zot/pkg/storage/constants" 18 . "zotregistry.io/zot/pkg/test/common" 19 ) 20 21 func TestServerUsage(t *testing.T) { 22 oldArgs := os.Args 23 24 defer func() { os.Args = oldArgs }() 25 26 Convey("Test usage", t, func(c C) { 27 os.Args = []string{"cli_test", "help"} 28 err := cli.NewServerRootCmd().Execute() 29 So(err, ShouldBeNil) 30 }) 31 32 Convey("Test version", t, func(c C) { 33 os.Args = []string{"cli_test", "--version"} 34 err := cli.NewServerRootCmd().Execute() 35 So(err, ShouldBeNil) 36 }) 37 } 38 39 func TestServe(t *testing.T) { 40 oldArgs := os.Args 41 42 defer func() { os.Args = oldArgs }() 43 44 Convey("Test serve help", t, func(c C) { 45 os.Args = []string{"cli_test", "serve", "-h"} 46 err := cli.NewServerRootCmd().Execute() 47 So(err, ShouldBeNil) 48 }) 49 50 Convey("Test serve config", t, func(c C) { 51 Convey("unknown config", func(c C) { 52 os.Args = []string{"cli_test", "serve", path.Join(os.TempDir(), "/x")} 53 err := cli.NewServerRootCmd().Execute() 54 So(err, ShouldNotBeNil) 55 }) 56 57 Convey("non-existent config", func(c C) { 58 os.Args = []string{"cli_test", "serve", path.Join(os.TempDir(), "/x.yaml")} 59 err := cli.NewServerRootCmd().Execute() 60 So(err, ShouldNotBeNil) 61 }) 62 63 Convey("bad config", func(c C) { 64 rootDir := t.TempDir() 65 66 tmpFile := path.Join(rootDir, "zot-test.json") 67 err := os.WriteFile(tmpFile, []byte(`{"log":{}}`), 0o0600) 68 So(err, ShouldBeNil) 69 70 os.Args = []string{"cli_test", "serve", tmpFile} 71 72 err = cli.NewServerRootCmd().Execute() 73 So(err, ShouldNotBeNil) 74 }) 75 76 Convey("config with missing rootDir", func(c C) { 77 rootDir := t.TempDir() 78 79 // missing storage config should result in an error in Controller.Init() 80 content := []byte(`{ 81 "distSpecVersion": "1.1.0-dev", 82 "http": { 83 "address":"127.0.0.1", 84 "port":"8080" 85 } 86 }`) 87 88 tmpFile := path.Join(rootDir, "zot-test.json") 89 err := os.WriteFile(tmpFile, content, 0o0600) 90 So(err, ShouldBeNil) 91 92 os.Args = []string{"cli_test", "serve", tmpFile} 93 94 err = cli.NewServerRootCmd().Execute() 95 So(err, ShouldNotBeNil) 96 97 // wait for the config reloader goroutine to start watching the config file 98 // if we end the test too fast it will delete the config file 99 // which will cause a panic and mark the test run as a failure 100 time.Sleep(1 * time.Second) 101 }) 102 }) 103 } 104 105 func TestVerify(t *testing.T) { 106 oldArgs := os.Args 107 108 defer func() { os.Args = oldArgs }() 109 110 Convey("Test verify bad config", t, func(c C) { 111 tmpfile, err := os.CreateTemp("", "zot-test*.json") 112 So(err, ShouldBeNil) 113 defer os.Remove(tmpfile.Name()) // clean up 114 content := []byte(`{"log":{}}`) 115 _, err = tmpfile.Write(content) 116 So(err, ShouldBeNil) 117 err = tmpfile.Close() 118 So(err, ShouldBeNil) 119 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 120 err = cli.NewServerRootCmd().Execute() 121 So(err, ShouldNotBeNil) 122 }) 123 124 Convey("Test verify CVE warn for remote storage", t, func(c C) { 125 tmpfile, err := os.CreateTemp("", "zot-test*.json") 126 So(err, ShouldBeNil) 127 defer os.Remove(tmpfile.Name()) // clean up 128 129 content := []byte(`{ 130 "storage":{ 131 "rootDirectory":"/tmp/zot", 132 "dedupe":true, 133 "remoteCache":false, 134 "storageDriver":{ 135 "name":"s3", 136 "rootdirectory":"/zot", 137 "region":"us-east-2", 138 "bucket":"zot-storage", 139 "secure":true, 140 "skipverify":false 141 } 142 }, 143 "http":{ 144 "address":"127.0.0.1", 145 "port":"8080" 146 }, 147 "extensions":{ 148 "search": { 149 "enable": true, 150 "cve": { 151 "updateInterval": "24h" 152 } 153 } 154 } 155 }`) 156 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 157 So(err, ShouldBeNil) 158 159 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 160 err = cli.NewServerRootCmd().Execute() 161 So(err, ShouldNotBeNil) 162 163 content = []byte(`{ 164 "storage":{ 165 "rootDirectory":"/tmp/zot", 166 "dedupe":true, 167 "remoteCache":false, 168 "subPaths":{ 169 "/a": { 170 "rootDirectory": "/tmp/zot1", 171 "dedupe": false, 172 "storageDriver":{ 173 "name":"s3", 174 "rootdirectory":"/zot-a", 175 "region":"us-east-2", 176 "bucket":"zot-storage", 177 "secure":true, 178 "skipverify":false 179 } 180 } 181 } 182 }, 183 "http":{ 184 "address":"127.0.0.1", 185 "port":"8080" 186 }, 187 "extensions":{ 188 "search": { 189 "enable": true, 190 "cve": { 191 "updateInterval": "24h" 192 } 193 } 194 } 195 }`) 196 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 197 So(err, ShouldBeNil) 198 199 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 200 err = cli.NewServerRootCmd().Execute() 201 So(err, ShouldNotBeNil) 202 }) 203 204 Convey("Test cached db config", t, func(c C) { 205 tmpfile, err := os.CreateTemp("", "zot-test*.json") 206 So(err, ShouldBeNil) 207 defer os.Remove(tmpfile.Name()) // clean up 208 209 // dedupe true, remote storage, remoteCache true, but no cacheDriver (remote) 210 content := []byte(`{ 211 "storage":{ 212 "rootDirectory":"/tmp/zot", 213 "dedupe":true, 214 "remoteCache":true, 215 "storageDriver":{ 216 "name":"s3", 217 "rootdirectory":"/zot", 218 "region":"us-east-2", 219 "bucket":"zot-storage", 220 "secure":true, 221 "skipverify":false 222 } 223 }, 224 "http":{ 225 "address":"127.0.0.1", 226 "port":"8080", 227 "realm":"zot", 228 "auth":{ 229 "htpasswd":{ 230 "path":"test/data/htpasswd" 231 }, 232 "failDelay":1 233 } 234 } 235 }`) 236 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 237 So(err, ShouldBeNil) 238 239 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 240 err = cli.NewServerRootCmd().Execute() 241 So(err, ShouldNotBeNil) 242 243 // local storage with remote caching 244 content = []byte(`{ 245 "storage":{ 246 "rootDirectory":"/tmp/zot", 247 "dedupe":true, 248 "remoteCache":true, 249 "cacheDriver":{ 250 "name":"dynamodb", 251 "endpoint":"http://localhost:4566", 252 "region":"us-east-2", 253 "cacheTablename":"BlobTable" 254 } 255 }, 256 "http":{ 257 "address":"127.0.0.1", 258 "port":"8080", 259 "realm":"zot", 260 "auth":{ 261 "htpasswd":{ 262 "path":"test/data/htpasswd" 263 }, 264 "failDelay":1 265 } 266 } 267 }`) 268 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 269 So(err, ShouldBeNil) 270 271 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 272 err = cli.NewServerRootCmd().Execute() 273 So(err, ShouldNotBeNil) 274 275 // unsupported cache driver 276 content = []byte(`{ 277 "storage":{ 278 "rootDirectory":"/tmp/zot", 279 "dedupe":true, 280 "remoteCache":true, 281 "cacheDriver":{ 282 "name":"unsupportedDriver" 283 }, 284 "storageDriver":{ 285 "name":"s3", 286 "rootdirectory":"/zot", 287 "region":"us-east-2", 288 "bucket":"zot-storage", 289 "secure":true, 290 "skipverify":false 291 } 292 }, 293 "http":{ 294 "address":"127.0.0.1", 295 "port":"8080", 296 "realm":"zot", 297 "auth":{ 298 "htpasswd":{ 299 "path":"test/data/htpasswd" 300 }, 301 "failDelay":1 302 } 303 } 304 }`) 305 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 306 So(err, ShouldBeNil) 307 308 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 309 err = cli.NewServerRootCmd().Execute() 310 So(err, ShouldNotBeNil) 311 312 // remoteCache false but provided cacheDriver config, ignored 313 content = []byte(`{ 314 "storage":{ 315 "rootDirectory":"/tmp/zot", 316 "dedupe":true, 317 "remoteCache":false, 318 "cacheDriver":{ 319 "name":"dynamodb", 320 "endpoint":"http://localhost:4566", 321 "region":"us-east-2", 322 "cacheTablename":"BlobTable" 323 }, 324 "storageDriver":{ 325 "name":"s3", 326 "rootdirectory":"/zot", 327 "region":"us-east-2", 328 "bucket":"zot-storage", 329 "secure":true, 330 "skipverify":false 331 } 332 }, 333 "http":{ 334 "address":"127.0.0.1", 335 "port":"8080", 336 "realm":"zot", 337 "auth":{ 338 "htpasswd":{ 339 "path":"test/data/htpasswd" 340 }, 341 "failDelay":1 342 } 343 } 344 }`) 345 346 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 347 So(err, ShouldBeNil) 348 349 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 350 err = cli.NewServerRootCmd().Execute() 351 So(err, ShouldBeNil) 352 353 // SubPaths 354 // dedupe true, remote storage, remoteCache true, but no cacheDriver (remote) 355 content = []byte(`{ 356 "storage":{ 357 "rootDirectory":"/tmp/zot", 358 "dedupe":false, 359 "subPaths":{ 360 "/a":{ 361 "rootDirectory":"/zot-a", 362 "dedupe":true, 363 "remoteCache":true, 364 "storageDriver":{ 365 "name":"s3", 366 "rootdirectory":"/zot", 367 "region":"us-east-2", 368 "bucket":"zot-storage", 369 "secure":true, 370 "skipverify":false 371 } 372 } 373 } 374 }, 375 "http":{ 376 "address":"127.0.0.1", 377 "port":"8080", 378 "realm":"zot", 379 "auth":{ 380 "htpasswd":{ 381 "path":"test/data/htpasswd" 382 }, 383 "failDelay":1 384 } 385 } 386 }`) 387 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 388 So(err, ShouldBeNil) 389 390 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 391 err = cli.NewServerRootCmd().Execute() 392 So(err, ShouldNotBeNil) 393 394 // local storage with remote caching 395 content = []byte(`{ 396 "storage":{ 397 "rootDirectory":"/tmp/zot", 398 "dedupe":false, 399 "subPaths":{ 400 "/a":{ 401 "rootDirectory":"/zot-a", 402 "dedupe":true, 403 "remoteCache":true, 404 "cacheDriver":{ 405 "name":"dynamodb", 406 "endpoint":"http://localhost:4566", 407 "region":"us-east-2", 408 "cacheTablename":"BlobTable" 409 } 410 } 411 } 412 }, 413 "http":{ 414 "address":"127.0.0.1", 415 "port":"8080", 416 "realm":"zot", 417 "auth":{ 418 "htpasswd":{ 419 "path":"test/data/htpasswd" 420 }, 421 "failDelay":1 422 } 423 } 424 }`) 425 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 426 So(err, ShouldBeNil) 427 428 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 429 err = cli.NewServerRootCmd().Execute() 430 So(err, ShouldNotBeNil) 431 432 // unsupported cache driver 433 content = []byte(`{ 434 "storage":{ 435 "rootDirectory":"/tmp/zot", 436 "dedupe":false, 437 "subPaths":{ 438 "/a":{ 439 "rootDirectory":"/zot-a", 440 "dedupe":true, 441 "remoteCache":true, 442 "cacheDriver":{ 443 "name":"badDriverName" 444 }, 445 "storageDriver":{ 446 "name":"s3", 447 "rootdirectory":"/zot", 448 "region":"us-east-2", 449 "bucket":"zot-storage", 450 "secure":true, 451 "skipverify":false 452 } 453 } 454 } 455 }, 456 "http":{ 457 "address":"127.0.0.1", 458 "port":"8080", 459 "realm":"zot", 460 "auth":{ 461 "htpasswd":{ 462 "path":"test/data/htpasswd" 463 }, 464 "failDelay":1 465 } 466 } 467 }`) 468 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 469 So(err, ShouldBeNil) 470 471 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 472 err = cli.NewServerRootCmd().Execute() 473 So(err, ShouldNotBeNil) 474 475 // remoteCache false but provided cacheDriver config, ignored 476 content = []byte(`{ 477 "storage":{ 478 "rootDirectory":"/tmp/zot", 479 "dedupe":false, 480 "subPaths":{ 481 "/a":{ 482 "rootDirectory":"/zot-a", 483 "dedupe":true, 484 "remoteCache":false, 485 "cacheDriver":{ 486 "name":"dynamodb", 487 "endpoint":"http://localhost:4566", 488 "region":"us-east-2", 489 "cacheTablename":"BlobTable" 490 } 491 } 492 } 493 }, 494 "http":{ 495 "address":"127.0.0.1", 496 "port":"8080", 497 "realm":"zot", 498 "auth":{ 499 "htpasswd":{ 500 "path":"test/data/htpasswd" 501 }, 502 "failDelay":1 503 } 504 } 505 }`) 506 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 507 So(err, ShouldBeNil) 508 509 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 510 err = cli.NewServerRootCmd().Execute() 511 So(err, ShouldBeNil) 512 }) 513 514 Convey("Test verify with bad gc retention repo patterns", t, func(c C) { 515 tmpfile, err := os.CreateTemp("", "zot-test*.json") 516 So(err, ShouldBeNil) 517 defer os.Remove(tmpfile.Name()) // clean up 518 content := []byte(`{ 519 "distSpecVersion": "1.1.0-dev", 520 "storage": { 521 "rootDirectory": "/tmp/zot", 522 "gc": true, 523 "retention": { 524 "policies": [ 525 { 526 "repositories": ["["], 527 "deleteReferrers": false 528 } 529 ] 530 }, 531 "subPaths":{ 532 "/a":{ 533 "rootDirectory":"/zot-a", 534 "retention": { 535 "policies": [ 536 { 537 "repositories": ["**"], 538 "deleteReferrers": true 539 } 540 ] 541 } 542 } 543 } 544 }, 545 "http": { 546 "address": "127.0.0.1", 547 "port": "8080" 548 }, 549 "log": { 550 "level": "debug" 551 } 552 }`) 553 554 _, err = tmpfile.Write(content) 555 So(err, ShouldBeNil) 556 err = tmpfile.Close() 557 So(err, ShouldBeNil) 558 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 559 So(cli.NewServerRootCmd().Execute(), ShouldNotBeNil) 560 }) 561 562 Convey("Test verify with bad gc image retention tag regex", t, func(c C) { 563 tmpfile, err := os.CreateTemp("", "zot-test*.json") 564 So(err, ShouldBeNil) 565 defer os.Remove(tmpfile.Name()) // clean up 566 content := []byte(`{ 567 "distSpecVersion": "1.1.0-dev", 568 "storage": { 569 "rootDirectory": "/tmp/zot", 570 "gc": true, 571 "retention": { 572 "dryRun": false, 573 "policies": [ 574 { 575 "repositories": ["infra/*"], 576 "deleteReferrers": false, 577 "deleteUntagged": true, 578 "keepTags": [{ 579 "names": ["["] 580 }] 581 } 582 ] 583 } 584 }, 585 "http": { 586 "address": "127.0.0.1", 587 "port": "8080" 588 }, 589 "log": { 590 "level": "debug" 591 } 592 }`) 593 594 _, err = tmpfile.Write(content) 595 So(err, ShouldBeNil) 596 err = tmpfile.Close() 597 So(err, ShouldBeNil) 598 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 599 So(cli.NewServerRootCmd().Execute(), ShouldNotBeNil) 600 }) 601 602 Convey("Test apply defaults cache db", t, func(c C) { 603 tmpfile, err := os.CreateTemp("", "zot-test*.json") 604 So(err, ShouldBeNil) 605 defer os.Remove(tmpfile.Name()) // clean up 606 607 // s3 dedup=false, check for previous dedup usage and set to true if cachedb found 608 cacheDir := t.TempDir() 609 existingDBPath := path.Join(cacheDir, storageConstants.BoltdbName+storageConstants.DBExtensionName) 610 _, err = os.Create(existingDBPath) 611 So(err, ShouldBeNil) 612 613 content := []byte(`{"storage":{"rootDirectory":"/tmp/zot", "dedupe": false, 614 "storageDriver": {"rootDirectory": "` + cacheDir + `"}}, 615 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 616 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) 617 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 618 So(err, ShouldBeNil) 619 620 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 621 err = cli.NewServerRootCmd().Execute() 622 So(err, ShouldNotBeNil) 623 624 // subpath s3 dedup=false, check for previous dedup usage and set to true if cachedb found 625 cacheDir = t.TempDir() 626 existingDBPath = path.Join(cacheDir, storageConstants.BoltdbName+storageConstants.DBExtensionName) 627 _, err = os.Create(existingDBPath) 628 So(err, ShouldBeNil) 629 630 content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", "dedupe": true, 631 "subpaths": {"/a": {"rootDirectory":"/tmp/zot1", "dedupe": false, 632 "storageDriver": {"rootDirectory": "` + cacheDir + `"}}}}, 633 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 634 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) 635 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 636 So(err, ShouldBeNil) 637 638 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 639 err = cli.NewServerRootCmd().Execute() 640 So(err, ShouldNotBeNil) 641 642 // subpath s3 dedup=false, check for previous dedup usage and set to true if cachedb found 643 cacheDir = t.TempDir() 644 645 content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", "dedupe": true, 646 "subpaths": {"/a": {"rootDirectory":"/tmp/zot1", "dedupe": true, 647 "storageDriver": {"rootDirectory": "` + cacheDir + `"}}}}, 648 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 649 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) 650 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 651 So(err, ShouldBeNil) 652 653 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 654 err = cli.NewServerRootCmd().Execute() 655 So(err, ShouldNotBeNil) 656 }) 657 658 Convey("Test verify storage driver different than s3", t, func(c C) { 659 tmpfile, err := os.CreateTemp("", "zot-test*.json") 660 So(err, ShouldBeNil) 661 defer os.Remove(tmpfile.Name()) // clean up 662 content := []byte(`{"storage":{"rootDirectory":"/tmp/zot", "storageDriver": {"name": "gcs"}}, 663 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 664 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) 665 _, err = tmpfile.Write(content) 666 So(err, ShouldBeNil) 667 err = tmpfile.Close() 668 So(err, ShouldBeNil) 669 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 670 err = cli.NewServerRootCmd().Execute() 671 So(err, ShouldNotBeNil) 672 }) 673 674 Convey("Test verify subpath storage driver different than s3", t, func(c C) { 675 tmpfile, err := os.CreateTemp("", "zot-test*.json") 676 So(err, ShouldBeNil) 677 defer os.Remove(tmpfile.Name()) // clean up 678 content := []byte(`{"storage":{"rootDirectory":"/tmp/zot", "storageDriver": {"name": "s3"}, 679 "subPaths": {"/a": {"rootDirectory": "/zot-a","storageDriver": {"name": "gcs"}}}}, 680 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 681 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) 682 _, err = tmpfile.Write(content) 683 So(err, ShouldBeNil) 684 err = tmpfile.Close() 685 So(err, ShouldBeNil) 686 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 687 err = cli.NewServerRootCmd().Execute() 688 So(err, ShouldNotBeNil) 689 }) 690 691 Convey("Test verify subpath storage config", t, func(c C) { 692 tmpfile, err := os.CreateTemp("", "zot-test*.json") 693 So(err, ShouldBeNil) 694 defer os.Remove(tmpfile.Name()) // clean up 695 content := []byte(`{"storage":{"rootDirectory":"/tmp/zot", 696 "subPaths": {"/a": {"rootDirectory": "/zot-a"},"/b": {"rootDirectory": "/zot-a"}}}, 697 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 698 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) 699 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 700 So(err, ShouldBeNil) 701 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 702 err = cli.NewServerRootCmd().Execute() 703 So(err, ShouldBeNil) 704 705 // sub paths that point to same directory should have same storage config. 706 content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", 707 "subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true"}, 708 "/b": {"rootDirectory": "/zot-a","dedupe":"false"}}}, 709 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 710 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) 711 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 712 So(err, ShouldBeNil) 713 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 714 err = cli.NewServerRootCmd().Execute() 715 So(err, ShouldNotBeNil) 716 717 // sub paths that point to default root directory should not be allowed. 718 content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", 719 "subPaths": {"/a": {"rootDirectory": "/tmp/zot","dedupe":"true"},"/b": {"rootDirectory": "/zot-a"}}}, 720 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 721 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) 722 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 723 So(err, ShouldBeNil) 724 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 725 err = cli.NewServerRootCmd().Execute() 726 So(err, ShouldNotBeNil) 727 728 content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", 729 "subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true"}, 730 "/b": {"rootDirectory": "/zot-a","dedupe":"true","gc":"false"}}}, 731 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 732 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) 733 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 734 So(err, ShouldBeNil) 735 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 736 err = cli.NewServerRootCmd().Execute() 737 So(err, ShouldNotBeNil) 738 739 content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", 740 "subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true"}, 741 "/b": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"1s"}}}, 742 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 743 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) 744 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 745 So(err, ShouldBeNil) 746 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 747 err = cli.NewServerRootCmd().Execute() 748 So(err, ShouldNotBeNil) 749 750 content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", 751 "subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"1s","gcInterval":"1s"}, 752 "/b": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"1s"}}}, 753 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 754 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) 755 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 756 So(err, ShouldBeNil) 757 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 758 err = cli.NewServerRootCmd().Execute() 759 So(err, ShouldNotBeNil) 760 761 content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", 762 "subPaths": {"/a": {"rootDirectory": "/tmp/zot","dedupe":"true","gc":"true","gcDelay":"1s","gcInterval":"1s"}, 763 "/b": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"1s"}}}, 764 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 765 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) 766 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 767 So(err, ShouldBeNil) 768 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 769 err = cli.NewServerRootCmd().Execute() 770 So(err, ShouldNotBeNil) 771 }) 772 773 Convey("Test verify w/ authorization and w/o authentication", t, func(c C) { 774 tmpfile, err := os.CreateTemp("", "zot-test*.json") 775 So(err, ShouldBeNil) 776 defer os.Remove(tmpfile.Name()) // clean up 777 content := []byte(`{"storage":{"rootDirectory":"/tmp/zot"}, 778 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 779 "accessControl":{"repositories":{},"adminPolicy":{"users":["admin"], 780 "actions":["read","create","update","delete"]}}}}`) 781 _, err = tmpfile.Write(content) 782 So(err, ShouldBeNil) 783 err = tmpfile.Close() 784 So(err, ShouldBeNil) 785 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 786 err = cli.NewServerRootCmd().Execute() 787 So(err, ShouldNotBeNil) 788 }) 789 790 Convey("Test verify w/ authorization and w/ authentication", t, func(c C) { 791 tmpfile, err := os.CreateTemp("", "zot-test*.json") 792 So(err, ShouldBeNil) 793 defer os.Remove(tmpfile.Name()) // clean up 794 content := []byte(`{"storage":{"rootDirectory":"/tmp/zot"}, 795 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 796 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}, 797 "accessControl":{"repositories":{},"adminPolicy":{"users":["admin"], 798 "actions":["read","create","update","delete"]}}}}`) 799 _, err = tmpfile.Write(content) 800 So(err, ShouldBeNil) 801 err = tmpfile.Close() 802 So(err, ShouldBeNil) 803 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 804 err = cli.NewServerRootCmd().Execute() 805 So(err, ShouldBeNil) 806 }) 807 808 Convey("Test verify anonymous authorization", t, func(c C) { 809 tmpfile, err := os.CreateTemp("", "zot-test*.json") 810 So(err, ShouldBeNil) 811 defer os.Remove(tmpfile.Name()) // clean up 812 content := []byte(`{"storage":{"rootDirectory":"/tmp/zot"}, 813 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 814 "accessControl":{"repositories":{"**":{"anonymousPolicy": ["read", "create"]}, 815 "/repo":{"anonymousPolicy": ["read", "create"]}} 816 }}}`) 817 _, err = tmpfile.Write(content) 818 So(err, ShouldBeNil) 819 err = tmpfile.Close() 820 So(err, ShouldBeNil) 821 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 822 err = cli.NewServerRootCmd().Execute() 823 So(err, ShouldBeNil) 824 }) 825 826 Convey("Test verify admin policy authz is not allowed if no authn is configured", t, func(c C) { 827 tmpfile, err := os.CreateTemp("", "zot-test*.json") 828 So(err, ShouldBeNil) 829 defer os.Remove(tmpfile.Name()) // clean up 830 content := []byte(`{"storage":{"rootDirectory":"/tmp/zot"}, 831 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 832 "accessControl":{ 833 "repositories":{ 834 "**":{"defaultPolicy": ["read", "create"]}, 835 "/repo":{"anonymousPolicy": ["read", "create"]}, 836 }, 837 "adminPolicy":{ 838 "users":["admin"], 839 "actions":["read","create","update","delete"] 840 } 841 } 842 }`) 843 _, err = tmpfile.Write(content) 844 So(err, ShouldBeNil) 845 err = tmpfile.Close() 846 So(err, ShouldBeNil) 847 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 848 err = cli.NewServerRootCmd().Execute() 849 So(err, ShouldNotBeNil) 850 }) 851 852 Convey("Test verify default policy authz is not allowed if no authn is configured", t, func(c C) { 853 tmpfile, err := os.CreateTemp("", "zot-test*.json") 854 So(err, ShouldBeNil) 855 defer os.Remove(tmpfile.Name()) // clean up 856 content := []byte(`{"storage":{"rootDirectory":"/tmp/zot"}, 857 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 858 "accessControl":{ 859 "repositories": { 860 "**":{"defaultPolicy": ["read", "create"]}, 861 "/repo":{"anonymousPolicy": ["read", "create"]} 862 } 863 } 864 }}`) 865 _, err = tmpfile.Write(content) 866 So(err, ShouldBeNil) 867 err = tmpfile.Close() 868 So(err, ShouldBeNil) 869 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 870 err = cli.NewServerRootCmd().Execute() 871 So(err, ShouldNotBeNil) 872 }) 873 874 Convey("Test verify authz per user policies fail if no authn is configured", t, func(c C) { 875 tmpfile, err := os.CreateTemp("", "zot-test*.json") 876 So(err, ShouldBeNil) 877 defer os.Remove(tmpfile.Name()) // clean up 878 content := []byte(`{"storage":{"rootDirectory":"/tmp/zot"}, 879 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 880 "accessControl":{ 881 "repositories": { 882 "/repo":{"anonymousPolicy": ["read", "create"]}, 883 "/repo2":{ 884 "policies": [{ 885 "users": ["charlie"], 886 "actions": ["read", "create", "update"] 887 }] 888 } 889 } 890 } 891 }}`) 892 _, err = tmpfile.Write(content) 893 So(err, ShouldBeNil) 894 err = tmpfile.Close() 895 So(err, ShouldBeNil) 896 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 897 err = cli.NewServerRootCmd().Execute() 898 So(err, ShouldNotBeNil) 899 }) 900 901 Convey("Test verify w/ sync and w/o filesystem storage", t, func(c C) { 902 tmpfile, err := os.CreateTemp("", "zot-test*.json") 903 So(err, ShouldBeNil) 904 defer os.Remove(tmpfile.Name()) // clean up 905 content := []byte(`{"storage":{"rootDirectory":"/tmp/zot", "storageDriver": {"name": "s3"}}, 906 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 907 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}, 908 "extensions":{"sync": {"registries": [{"urls":["localhost:9999"], 909 "maxRetries": 1, "retryDelay": "10s"}]}}}`) 910 _, err = tmpfile.Write(content) 911 So(err, ShouldBeNil) 912 err = tmpfile.Close() 913 So(err, ShouldBeNil) 914 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 915 err = cli.NewServerRootCmd().Execute() 916 So(err, ShouldNotBeNil) 917 }) 918 919 Convey("Test verify w/ sync and w/ filesystem storage", t, func(c C) { 920 tmpfile, err := os.CreateTemp("", "zot-test*.json") 921 So(err, ShouldBeNil) 922 defer os.Remove(tmpfile.Name()) // clean up 923 content := []byte(`{"storage":{"rootDirectory":"/tmp/zot"}, 924 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 925 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}, 926 "extensions":{"sync": {"registries": [{"urls":["localhost:9999"], 927 "maxRetries": 1, "retryDelay": "10s"}]}}}`) 928 _, err = tmpfile.Write(content) 929 So(err, ShouldBeNil) 930 err = tmpfile.Close() 931 So(err, ShouldBeNil) 932 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 933 err = cli.NewServerRootCmd().Execute() 934 So(err, ShouldBeNil) 935 }) 936 937 Convey("Test verify with bad sync prefixes", t, func(c C) { 938 tmpfile, err := os.CreateTemp("", "zot-test*.json") 939 So(err, ShouldBeNil) 940 defer os.Remove(tmpfile.Name()) // clean up 941 content := []byte(`{"storage":{"rootDirectory":"/tmp/zot"}, 942 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 943 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}, 944 "extensions":{"sync": {"registries": [{"urls":["localhost:9999"], 945 "maxRetries": 1, "retryDelay": "10s", 946 "content": [{"prefix":"[repo%^&"}]}]}}}`) 947 _, err = tmpfile.Write(content) 948 So(err, ShouldBeNil) 949 err = tmpfile.Close() 950 So(err, ShouldBeNil) 951 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 952 err = cli.NewServerRootCmd().Execute() 953 So(err, ShouldNotBeNil) 954 }) 955 956 Convey("Test verify with bad sync content config", t, func(c C) { 957 tmpfile, err := os.CreateTemp("", "zot-test*.json") 958 So(err, ShouldBeNil) 959 defer os.Remove(tmpfile.Name()) // clean up 960 content := []byte(`{"storage":{"rootDirectory":"/tmp/zot"}, 961 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 962 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}, 963 "extensions":{"sync": {"registries": [{"urls":["localhost:9999"], 964 "maxRetries": 1, "retryDelay": "10s", 965 "content": [{"prefix":"zot-repo","stripPrefix":true,"destination":"/"}]}]}}}`) 966 _, err = tmpfile.Write(content) 967 So(err, ShouldBeNil) 968 err = tmpfile.Close() 969 So(err, ShouldBeNil) 970 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 971 err = cli.NewServerRootCmd().Execute() 972 So(err, ShouldNotBeNil) 973 }) 974 975 Convey("Test verify with good sync content config", t, func(c C) { 976 tmpfile, err := os.CreateTemp("", "zot-test*.json") 977 So(err, ShouldBeNil) 978 defer os.Remove(tmpfile.Name()) // clean up 979 content := []byte(`{"storage":{"rootDirectory":"/tmp/zot"}, 980 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 981 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}, 982 "extensions":{"sync": {"registries": [{"urls":["localhost:9999"], 983 "maxRetries": 1, "retryDelay": "10s", 984 "content": [{"prefix":"zot-repo/*","stripPrefix":true,"destination":"/"}]}]}}}`) 985 _, err = tmpfile.Write(content) 986 So(err, ShouldBeNil) 987 err = tmpfile.Close() 988 So(err, ShouldBeNil) 989 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 990 err = cli.NewServerRootCmd().Execute() 991 So(err, ShouldBeNil) 992 }) 993 994 Convey("Test verify with bad authorization repo patterns", t, func(c C) { 995 tmpfile, err := os.CreateTemp("", "zot-test*.json") 996 So(err, ShouldBeNil) 997 defer os.Remove(tmpfile.Name()) // clean up 998 content := []byte(`{"storage":{"rootDirectory":"/tmp/zot"}, 999 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 1000 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}, 1001 "accessControl":{"repositories":{"[":{"policies":[],"anonymousPolicy":[]}}}}}`) 1002 _, err = tmpfile.Write(content) 1003 So(err, ShouldBeNil) 1004 err = tmpfile.Close() 1005 So(err, ShouldBeNil) 1006 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 1007 err = cli.NewServerRootCmd().Execute() 1008 So(err, ShouldNotBeNil) 1009 }) 1010 1011 Convey("Test verify sync config default tls value", t, func(c C) { 1012 tmpfile, err := os.CreateTemp("", "zot-test*.json") 1013 So(err, ShouldBeNil) 1014 defer os.Remove(tmpfile.Name()) // clean up 1015 content := []byte(`{"storage":{"rootDirectory":"/tmp/zot"}, 1016 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 1017 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}, 1018 "extensions":{"sync": {"registries": [{"urls":["localhost:9999"], 1019 "maxRetries": 1, "retryDelay": "10s", 1020 "content": [{"prefix":"repo**"}]}]}}}`) 1021 _, err = tmpfile.Write(content) 1022 So(err, ShouldBeNil) 1023 err = tmpfile.Close() 1024 So(err, ShouldBeNil) 1025 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 1026 err = cli.NewServerRootCmd().Execute() 1027 So(err, ShouldBeNil) 1028 }) 1029 1030 Convey("Test verify sync without retry options", t, func(c C) { 1031 tmpfile, err := os.CreateTemp("", "zot-test*.json") 1032 So(err, ShouldBeNil) 1033 defer os.Remove(tmpfile.Name()) // clean up 1034 content := []byte(`{"storage":{"rootDirectory":"/tmp/zot"}, 1035 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 1036 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}, 1037 "extensions":{"sync": {"registries": [{"urls":["localhost:9999"], 1038 "maxRetries": 10, "content": [{"prefix":"repo**"}]}]}}}`) 1039 _, err = tmpfile.Write(content) 1040 So(err, ShouldBeNil) 1041 err = tmpfile.Close() 1042 So(err, ShouldBeNil) 1043 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 1044 err = cli.NewServerRootCmd().Execute() 1045 So(err, ShouldNotBeNil) 1046 }) 1047 1048 Convey("Test verify config with unknown keys", t, func(c C) { 1049 tmpfile, err := os.CreateTemp("", "zot-test*.json") 1050 So(err, ShouldBeNil) 1051 defer os.Remove(tmpfile.Name()) // clean up 1052 content := []byte(`{"distSpecVersion": "1.0.0", "storage": {"rootDirectory": "/tmp/zot"}, 1053 "http": {"url": "127.0.0.1", "port": "8080"}, 1054 "log": {"level": "debug"}}`) 1055 _, err = tmpfile.Write(content) 1056 So(err, ShouldBeNil) 1057 err = tmpfile.Close() 1058 So(err, ShouldBeNil) 1059 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 1060 err = cli.NewServerRootCmd().Execute() 1061 So(err, ShouldNotBeNil) 1062 }) 1063 1064 Convey("Test verify openid config with missing parameter", t, func(c C) { 1065 tmpfile, err := os.CreateTemp("", "zot-test*.json") 1066 So(err, ShouldBeNil) 1067 defer os.Remove(tmpfile.Name()) // clean up 1068 content := []byte(`{"distSpecVersion":"1.1.0-dev","storage":{"rootDirectory":"/tmp/zot"}, 1069 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 1070 "auth":{"openid":{"providers":{"oidc":{"issuer":"http://127.0.0.1:5556/dex"}}}}}, 1071 "log":{"level":"debug"}}`) 1072 _, err = tmpfile.Write(content) 1073 So(err, ShouldBeNil) 1074 err = tmpfile.Close() 1075 So(err, ShouldBeNil) 1076 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 1077 err = cli.NewServerRootCmd().Execute() 1078 So(err, ShouldNotBeNil) 1079 }) 1080 1081 Convey("Test verify oauth2 config with missing parameter", t, func(c C) { 1082 tmpfile, err := os.CreateTemp("", "zot-test*.json") 1083 So(err, ShouldBeNil) 1084 defer os.Remove(tmpfile.Name()) // clean up 1085 content := []byte(`{"distSpecVersion":"1.1.0-dev","storage":{"rootDirectory":"/tmp/zot"}, 1086 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 1087 "auth":{"openid":{"providers":{"github":{"clientid":"client_id"}}}}}, 1088 "log":{"level":"debug"}}`) 1089 _, err = tmpfile.Write(content) 1090 So(err, ShouldBeNil) 1091 err = tmpfile.Close() 1092 So(err, ShouldBeNil) 1093 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 1094 err = cli.NewServerRootCmd().Execute() 1095 So(err, ShouldNotBeNil) 1096 }) 1097 1098 Convey("Test verify openid config with unsupported provider", t, func(c C) { 1099 tmpfile, err := os.CreateTemp("", "zot-test*.json") 1100 So(err, ShouldBeNil) 1101 defer os.Remove(tmpfile.Name()) // clean up 1102 content := []byte(`{"distSpecVersion":"1.1.0-dev","storage":{"rootDirectory":"/tmp/zot"}, 1103 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 1104 "auth":{"openid":{"providers":{"unsupported":{"issuer":"http://127.0.0.1:5556/dex"}}}}}, 1105 "log":{"level":"debug"}}`) 1106 _, err = tmpfile.Write(content) 1107 So(err, ShouldBeNil) 1108 err = tmpfile.Close() 1109 So(err, ShouldBeNil) 1110 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 1111 err = cli.NewServerRootCmd().Execute() 1112 So(err, ShouldNotBeNil) 1113 }) 1114 1115 Convey("Test verify openid config without apikey extension enabled", t, func(c C) { 1116 tmpfile, err := os.CreateTemp("", "zot-test*.json") 1117 So(err, ShouldBeNil) 1118 defer os.Remove(tmpfile.Name()) // clean up 1119 content := []byte(`{"distSpecVersion":"1.1.0-dev","storage":{"rootDirectory":"/tmp/zot"}, 1120 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 1121 "auth":{"openid":{"providers":{"oidc":{"issuer":"http://127.0.0.1:5556/dex", 1122 "clientid":"client_id","scopes":["openid"]}}}}}, 1123 "log":{"level":"debug"}}`) 1124 _, err = tmpfile.Write(content) 1125 So(err, ShouldBeNil) 1126 err = tmpfile.Close() 1127 So(err, ShouldBeNil) 1128 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 1129 err = cli.NewServerRootCmd().Execute() 1130 So(err, ShouldBeNil) 1131 }) 1132 1133 Convey("Test verify config with missing basedn key", t, func(c C) { 1134 tmpfile, err := os.CreateTemp("", "zot-test*.json") 1135 So(err, ShouldBeNil) 1136 defer os.Remove(tmpfile.Name()) // clean up 1137 content := []byte(`{"distSpecVersion": "1.0.0", "storage": {"rootDirectory": "/tmp/zot"}, 1138 "http": {"auth": {"ldap": {"address": "ldap", "userattribute": "uid"}}, 1139 "address": "127.0.0.1", "port": "8080"}, 1140 "log": {"level": "debug"}}`) 1141 _, err = tmpfile.Write(content) 1142 So(err, ShouldBeNil) 1143 err = tmpfile.Close() 1144 So(err, ShouldBeNil) 1145 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 1146 err = cli.NewServerRootCmd().Execute() 1147 So(err, ShouldNotBeNil) 1148 }) 1149 1150 Convey("Test verify config with missing address key", t, func(c C) { 1151 tmpfile, err := os.CreateTemp("", "zot-test*.json") 1152 So(err, ShouldBeNil) 1153 defer os.Remove(tmpfile.Name()) // clean up 1154 content := []byte(`{"distSpecVersion": "1.0.0", "storage": {"rootDirectory": "/tmp/zot"}, 1155 "http": {"auth": {"ldap": {"basedn": "ou=Users,dc=example,dc=org", "userattribute": "uid"}}, 1156 "address": "127.0.0.1", "port": "8080"}, 1157 "log": {"level": "debug"}}`) 1158 _, err = tmpfile.Write(content) 1159 So(err, ShouldBeNil) 1160 err = tmpfile.Close() 1161 So(err, ShouldBeNil) 1162 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 1163 err = cli.NewServerRootCmd().Execute() 1164 So(err, ShouldNotBeNil) 1165 }) 1166 1167 Convey("Test verify config with missing userattribute key", t, func(c C) { 1168 tmpfile, err := os.CreateTemp("", "zot-test*.json") 1169 So(err, ShouldBeNil) 1170 defer os.Remove(tmpfile.Name()) // clean up 1171 content := []byte(`{"distSpecVersion": "1.0.0", "storage": {"rootDirectory": "/tmp/zot"}, 1172 "http": {"auth": {"ldap": {"basedn": "ou=Users,dc=example,dc=org", "address": "ldap"}}, 1173 "address": "127.0.0.1", "port": "8080"}, 1174 "log": {"level": "debug"}}`) 1175 _, err = tmpfile.Write(content) 1176 So(err, ShouldBeNil) 1177 err = tmpfile.Close() 1178 So(err, ShouldBeNil) 1179 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 1180 err = cli.NewServerRootCmd().Execute() 1181 So(err, ShouldNotBeNil) 1182 }) 1183 1184 Convey("Test verify good config", t, func(c C) { 1185 tmpfile, err := os.CreateTemp("", "zot-test*.json") 1186 So(err, ShouldBeNil) 1187 defer os.Remove(tmpfile.Name()) // clean up 1188 content := []byte(`{"distSpecVersion": "1.0.0", "storage": {"rootDirectory": "/tmp/zot"}, 1189 "http": {"address": "127.0.0.1", "port": "8080"}, 1190 "log": {"level": "debug"}}`) 1191 _, err = tmpfile.Write(content) 1192 So(err, ShouldBeNil) 1193 err = tmpfile.Close() 1194 So(err, ShouldBeNil) 1195 os.Args = []string{"cli_test", "verify", tmpfile.Name()} 1196 err = cli.NewServerRootCmd().Execute() 1197 So(err, ShouldBeNil) 1198 }) 1199 } 1200 1201 func TestApiKeyConfig(t *testing.T) { 1202 Convey("Test API Keys are enabled if OpenID is enabled", t, func(c C) { 1203 config := config.New() 1204 tmpfile, err := os.CreateTemp("", "zot-test*.json") 1205 So(err, ShouldBeNil) 1206 defer os.Remove(tmpfile.Name()) 1207 1208 content := []byte(`{"distSpecVersion":"1.1.0-dev","storage":{"rootDirectory":"/tmp/zot"}, 1209 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 1210 "auth":{"openid":{"providers":{"oidc":{"issuer":"http://127.0.0.1:5556/dex", 1211 "clientid":"client_id","scopes":["openid"]}}}}}, 1212 "log":{"level":"debug"}}`) 1213 1214 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 1215 So(err, ShouldBeNil) 1216 err = cli.LoadConfiguration(config, tmpfile.Name()) 1217 So(err, ShouldBeNil) 1218 So(config.HTTP.Auth, ShouldNotBeNil) 1219 So(config.HTTP.Auth.APIKey, ShouldBeTrue) 1220 }) 1221 1222 Convey("Test API Keys are not enabled by default", t, func(c C) { 1223 config := config.New() 1224 tmpfile, err := os.CreateTemp("", "zot-test*.json") 1225 So(err, ShouldBeNil) 1226 defer os.Remove(tmpfile.Name()) 1227 1228 content := []byte(`{"distSpecVersion":"1.1.0-dev","storage":{"rootDirectory":"/tmp/zot"}, 1229 "http":{"address":"127.0.0.1","port":"8080","realm":"zot"}, 1230 "log":{"level":"debug"}}`) 1231 1232 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 1233 So(err, ShouldBeNil) 1234 err = cli.LoadConfiguration(config, tmpfile.Name()) 1235 So(err, ShouldBeNil) 1236 So(config.HTTP.Auth, ShouldNotBeNil) 1237 So(config.HTTP.Auth.APIKey, ShouldBeFalse) 1238 }) 1239 1240 Convey("Test API Keys are not enabled if OpenID is not enabled", t, func(c C) { 1241 config := config.New() 1242 tmpfile, err := os.CreateTemp("", "zot-test*.json") 1243 So(err, ShouldBeNil) 1244 defer os.Remove(tmpfile.Name()) 1245 1246 content := []byte(`{"distSpecVersion":"1.1.0-dev","storage":{"rootDirectory":"/tmp/zot"}, 1247 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 1248 "auth":{"htpasswd":{"path":"test/data/htpasswd"}}}, 1249 "log":{"level":"debug"}}`) 1250 1251 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 1252 So(err, ShouldBeNil) 1253 err = cli.LoadConfiguration(config, tmpfile.Name()) 1254 So(err, ShouldBeNil) 1255 So(config.HTTP.Auth, ShouldNotBeNil) 1256 So(config.HTTP.Auth.APIKey, ShouldBeFalse) 1257 }) 1258 } 1259 1260 func TestServeAPIKey(t *testing.T) { 1261 oldArgs := os.Args 1262 1263 defer func() { os.Args = oldArgs }() 1264 1265 Convey("apikey implicitly enabled", t, func(c C) { 1266 content := `{ 1267 "storage": { 1268 "rootDirectory": "%s" 1269 }, 1270 "http": { 1271 "address": "127.0.0.1", 1272 "port": "%s", 1273 "auth": { 1274 "apikey": true 1275 } 1276 }, 1277 "log": { 1278 "level": "debug", 1279 "output": "%s" 1280 } 1281 }` 1282 1283 logPath, err := runCLIWithConfig(t.TempDir(), content) 1284 So(err, ShouldBeNil) 1285 data, err := os.ReadFile(logPath) 1286 So(err, ShouldBeNil) 1287 defer os.Remove(logPath) // clean up 1288 So(string(data), ShouldContainSubstring, "\"APIKey\":true") 1289 }) 1290 1291 Convey("apikey disabled", t, func(c C) { 1292 content := `{ 1293 "storage": { 1294 "rootDirectory": "%s" 1295 }, 1296 "http": { 1297 "address": "127.0.0.1", 1298 "port": "%s", 1299 "auth": { 1300 "apikey": false 1301 } 1302 }, 1303 "log": { 1304 "level": "debug", 1305 "output": "%s" 1306 } 1307 }` 1308 1309 logPath, err := runCLIWithConfig(t.TempDir(), content) 1310 So(err, ShouldBeNil) 1311 data, err := os.ReadFile(logPath) 1312 So(err, ShouldBeNil) 1313 defer os.Remove(logPath) // clean up 1314 So(string(data), ShouldContainSubstring, "\"APIKey\":false") 1315 }) 1316 } 1317 1318 func TestLoadConfig(t *testing.T) { 1319 Convey("Test viper load config", t, func(c C) { 1320 config := config.New() 1321 err := cli.LoadConfiguration(config, "../../../examples/config-policy.json") 1322 So(err, ShouldBeNil) 1323 }) 1324 Convey("Test subpath config combination", t, func(c C) { 1325 config := config.New() 1326 tmpfile, err := os.CreateTemp("", "zot-test*.json") 1327 So(err, ShouldBeNil) 1328 defer os.Remove(tmpfile.Name()) 1329 content := []byte(`{"storage":{"rootDirectory":"/tmp/zot", 1330 "subPaths": {"/a": {"rootDirectory": "/tmp/zot","dedupe":"true","gc":"true","gcDelay":"1s","gcInterval":"1s"}, 1331 "/b": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"1s"}}}, 1332 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 1333 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) 1334 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 1335 So(err, ShouldBeNil) 1336 err = cli.LoadConfiguration(config, tmpfile.Name()) 1337 So(err, ShouldNotBeNil) 1338 1339 content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", 1340 "subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"1s","gcInterval":"1s"}, 1341 "/b": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"1s"}}}, 1342 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 1343 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) 1344 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 1345 So(err, ShouldBeNil) 1346 err = cli.LoadConfiguration(config, tmpfile.Name()) 1347 So(err, ShouldNotBeNil) 1348 1349 content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", 1350 "subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true"}, 1351 "/b": {"rootDirectory": "/zot-a","dedupe":"false"}}}, 1352 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 1353 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) 1354 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 1355 So(err, ShouldBeNil) 1356 err = cli.LoadConfiguration(config, tmpfile.Name()) 1357 So(err, ShouldNotBeNil) 1358 1359 content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", 1360 "subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true","gcDelay":"0s"}, 1361 "/b": {"rootDirectory": "/zot-a","dedupe":"true"}}}, 1362 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 1363 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) 1364 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 1365 So(err, ShouldBeNil) 1366 err = cli.LoadConfiguration(config, tmpfile.Name()) 1367 So(err, ShouldNotBeNil) 1368 1369 content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", 1370 "subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true","gc":"true"}, 1371 "/b": {"rootDirectory": "/b","dedupe":"true"}}}, 1372 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 1373 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) 1374 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 1375 So(err, ShouldBeNil) 1376 err = cli.LoadConfiguration(config, tmpfile.Name()) 1377 So(err, ShouldBeNil) 1378 1379 content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", 1380 "subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true"}, 1381 "/b": {"rootDirectory": "/zot-a","dedupe":"true"}}}, 1382 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 1383 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) 1384 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 1385 So(err, ShouldBeNil) 1386 err = cli.LoadConfiguration(config, tmpfile.Name()) 1387 So(err, ShouldBeNil) 1388 }) 1389 1390 Convey("Test HTTP port", t, func() { 1391 config := config.New() 1392 tmpfile, err := os.CreateTemp("", "zot-test*.json") 1393 So(err, ShouldBeNil) 1394 defer os.Remove(tmpfile.Name()) 1395 1396 content := []byte(`{"storage":{"rootDirectory":"/tmp/zot", 1397 "subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true"}, 1398 "/b": {"rootDirectory": "/zot-a","dedupe":"true"}}}, 1399 "http":{"address":"127.0.0.1","port":"8080","realm":"zot", 1400 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) 1401 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 1402 So(err, ShouldBeNil) 1403 err = cli.LoadConfiguration(config, tmpfile.Name()) 1404 So(err, ShouldBeNil) 1405 1406 content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", 1407 "subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true"}, 1408 "/b": {"rootDirectory": "/zot-a","dedupe":"true"}}}, 1409 "http":{"address":"127.0.0.1","port":"-1","realm":"zot", 1410 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) 1411 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 1412 So(err, ShouldBeNil) 1413 err = cli.LoadConfiguration(config, tmpfile.Name()) 1414 So(err, ShouldNotBeNil) 1415 1416 content = []byte(`{"storage":{"rootDirectory":"/tmp/zot", 1417 "subPaths": {"/a": {"rootDirectory": "/zot-a","dedupe":"true"}, 1418 "/b": {"rootDirectory": "/zot-a","dedupe":"true"}}}, 1419 "http":{"address":"127.0.0.1","port":"65536","realm":"zot", 1420 "auth":{"htpasswd":{"path":"test/data/htpasswd"},"failDelay":1}}}`) 1421 err = os.WriteFile(tmpfile.Name(), content, 0o0600) 1422 So(err, ShouldBeNil) 1423 err = cli.LoadConfiguration(config, tmpfile.Name()) 1424 So(err, ShouldNotBeNil) 1425 }) 1426 } 1427 1428 func TestGC(t *testing.T) { 1429 Convey("Test GC config", t, func(c C) { 1430 config := config.New() 1431 err := cli.LoadConfiguration(config, "../../../examples/config-multiple.json") 1432 So(err, ShouldBeNil) 1433 So(config.Storage.GCDelay, ShouldEqual, storageConstants.DefaultGCDelay) 1434 err = cli.LoadConfiguration(config, "../../../examples/config-gc.json") 1435 So(err, ShouldBeNil) 1436 So(config.Storage.GCDelay, ShouldNotEqual, storageConstants.DefaultGCDelay) 1437 err = cli.LoadConfiguration(config, "../../../examples/config-gc-periodic.json") 1438 So(err, ShouldBeNil) 1439 }) 1440 1441 Convey("Test GC config corner cases", t, func(c C) { 1442 contents, err := os.ReadFile("../../../examples/config-gc.json") 1443 So(err, ShouldBeNil) 1444 1445 Convey("GC delay without GC", func() { 1446 config := config.New() 1447 err = json.Unmarshal(contents, config) 1448 config.Storage.GC = false 1449 1450 file, err := os.CreateTemp("", "gc-config-*.json") 1451 So(err, ShouldBeNil) 1452 defer os.Remove(file.Name()) 1453 1454 contents, err = json.MarshalIndent(config, "", " ") 1455 So(err, ShouldBeNil) 1456 1457 err = os.WriteFile(file.Name(), contents, 0o600) 1458 So(err, ShouldBeNil) 1459 err = cli.LoadConfiguration(config, file.Name()) 1460 So(err, ShouldBeNil) 1461 }) 1462 1463 Convey("GC interval without GC", func() { 1464 config := config.New() 1465 err = json.Unmarshal(contents, config) 1466 config.Storage.GC = false 1467 config.Storage.GCDelay = 0 1468 config.Storage.GCInterval = 24 * time.Hour 1469 1470 file, err := os.CreateTemp("", "gc-config-*.json") 1471 So(err, ShouldBeNil) 1472 defer os.Remove(file.Name()) 1473 1474 contents, err = json.MarshalIndent(config, "", " ") 1475 So(err, ShouldBeNil) 1476 1477 err = os.WriteFile(file.Name(), contents, 0o600) 1478 So(err, ShouldBeNil) 1479 err = cli.LoadConfiguration(config, file.Name()) 1480 So(err, ShouldBeNil) 1481 }) 1482 1483 Convey("Negative GC delay", func() { 1484 config := config.New() 1485 err = json.Unmarshal(contents, config) 1486 config.Storage.GCDelay = -1 * time.Second 1487 1488 file, err := os.CreateTemp("", "gc-config-*.json") 1489 So(err, ShouldBeNil) 1490 defer os.Remove(file.Name()) 1491 1492 contents, err = json.MarshalIndent(config, "", " ") 1493 So(err, ShouldBeNil) 1494 1495 err = os.WriteFile(file.Name(), contents, 0o600) 1496 So(err, ShouldBeNil) 1497 err = cli.LoadConfiguration(config, file.Name()) 1498 So(err, ShouldNotBeNil) 1499 }) 1500 1501 Convey("GC delay when GC = false", func() { 1502 config := config.New() 1503 1504 file, err := os.CreateTemp("", "gc-false-config-*.json") 1505 So(err, ShouldBeNil) 1506 defer os.Remove(file.Name()) 1507 1508 content := []byte(`{"distSpecVersion": "1.0.0", "storage": {"rootDirectory": "/tmp/zot", 1509 "gc": false}, "http": {"address": "127.0.0.1", "port": "8080"}, 1510 "log": {"level": "debug"}}`) 1511 1512 err = os.WriteFile(file.Name(), content, 0o600) 1513 So(err, ShouldBeNil) 1514 err = cli.LoadConfiguration(config, file.Name()) 1515 So(err, ShouldBeNil) 1516 So(config.Storage.GCDelay, ShouldEqual, 0) 1517 }) 1518 1519 Convey("Negative GC interval", func() { 1520 config := config.New() 1521 err = json.Unmarshal(contents, config) 1522 config.Storage.GCInterval = -1 * time.Second 1523 1524 file, err := os.CreateTemp("", "gc-config-*.json") 1525 So(err, ShouldBeNil) 1526 defer os.Remove(file.Name()) 1527 1528 contents, err = json.MarshalIndent(config, "", " ") 1529 So(err, ShouldBeNil) 1530 1531 err = os.WriteFile(file.Name(), contents, 0o600) 1532 So(err, ShouldBeNil) 1533 err = cli.LoadConfiguration(config, file.Name()) 1534 So(err, ShouldNotBeNil) 1535 }) 1536 }) 1537 } 1538 1539 func TestScrub(t *testing.T) { 1540 oldArgs := os.Args 1541 1542 defer func() { os.Args = oldArgs }() 1543 1544 Convey("Test scrub help", t, func(c C) { 1545 os.Args = []string{"cli_test", "scrub", "-h"} 1546 err := cli.NewServerRootCmd().Execute() 1547 So(err, ShouldBeNil) 1548 }) 1549 1550 Convey("Test scrub no args", t, func(c C) { 1551 os.Args = []string{"cli_test", "scrub"} 1552 err := cli.NewServerRootCmd().Execute() 1553 So(err, ShouldBeNil) 1554 }) 1555 1556 Convey("Test scrub config", t, func(c C) { 1557 Convey("non-existent config", func(c C) { 1558 os.Args = []string{"cli_test", "scrub", path.Join(os.TempDir(), "/x.yaml")} 1559 err := cli.NewServerRootCmd().Execute() 1560 So(err, ShouldNotBeNil) 1561 }) 1562 1563 Convey("unknown config", func(c C) { 1564 os.Args = []string{"cli_test", "scrub", path.Join(os.TempDir(), "/x")} 1565 err := cli.NewServerRootCmd().Execute() 1566 So(err, ShouldNotBeNil) 1567 }) 1568 1569 Convey("bad config", func(c C) { 1570 tmpfile, err := os.CreateTemp("", "zot-test*.json") 1571 So(err, ShouldBeNil) 1572 defer os.Remove(tmpfile.Name()) // clean up 1573 content := []byte(`{"log":{}}`) 1574 _, err = tmpfile.Write(content) 1575 So(err, ShouldBeNil) 1576 err = tmpfile.Close() 1577 So(err, ShouldBeNil) 1578 os.Args = []string{"cli_test", "scrub", tmpfile.Name()} 1579 err = cli.NewServerRootCmd().Execute() 1580 So(err, ShouldNotBeNil) 1581 }) 1582 1583 Convey("server is running", func(c C) { 1584 port := GetFreePort() 1585 config := config.New() 1586 config.HTTP.Port = port 1587 controller := api.NewController(config) 1588 1589 dir := t.TempDir() 1590 1591 controller.Config.Storage.RootDirectory = dir 1592 ctrlManager := NewControllerManager(controller) 1593 ctrlManager.StartAndWait(port) 1594 1595 tmpfile, err := os.CreateTemp("", "zot-test*.json") 1596 So(err, ShouldBeNil) 1597 defer os.Remove(tmpfile.Name()) // clean up 1598 content := []byte(fmt.Sprintf(`{ 1599 "storage": { 1600 "rootDirectory": "%s" 1601 }, 1602 "http": { 1603 "port": %s 1604 }, 1605 "log": { 1606 "level": "debug" 1607 } 1608 } 1609 `, dir, port)) 1610 _, err = tmpfile.Write(content) 1611 So(err, ShouldBeNil) 1612 err = tmpfile.Close() 1613 So(err, ShouldBeNil) 1614 1615 os.Args = []string{"cli_test", "scrub", tmpfile.Name()} 1616 err = cli.NewServerRootCmd().Execute() 1617 So(err, ShouldNotBeNil) 1618 1619 defer ctrlManager.StopServer() 1620 }) 1621 1622 Convey("no image store provided", func(c C) { 1623 port := GetFreePort() 1624 1625 tmpfile, err := os.CreateTemp("", "zot-test*.json") 1626 So(err, ShouldBeNil) 1627 defer os.Remove(tmpfile.Name()) // clean up 1628 content := []byte(fmt.Sprintf(`{ 1629 "storage": { 1630 "rootDirectory": "" 1631 }, 1632 "http": { 1633 "port": %s 1634 }, 1635 "log": { 1636 "level": "debug" 1637 } 1638 } 1639 `, port)) 1640 _, err = tmpfile.Write(content) 1641 So(err, ShouldBeNil) 1642 err = tmpfile.Close() 1643 So(err, ShouldBeNil) 1644 os.Args = []string{"cli_test", "scrub", tmpfile.Name()} 1645 err = cli.NewServerRootCmd().Execute() 1646 So(err, ShouldNotBeNil) 1647 }) 1648 1649 Convey("bad index.json", func(c C) { 1650 port := GetFreePort() 1651 1652 dir := t.TempDir() 1653 1654 repoName := "badindex" 1655 1656 repo, err := os.MkdirTemp(dir, repoName) 1657 if err != nil { 1658 panic(err) 1659 } 1660 1661 if err := os.MkdirAll(fmt.Sprintf("%s/blobs", repo), 0o755); err != nil { 1662 panic(err) 1663 } 1664 1665 if _, err = os.Stat(fmt.Sprintf("%s/oci-layout", repo)); err != nil { 1666 content := []byte(`{"imageLayoutVersion": "1.0.0"}`) 1667 if err = os.WriteFile(fmt.Sprintf("%s/oci-layout", repo), content, 0o600); err != nil { 1668 panic(err) 1669 } 1670 } 1671 1672 if _, err = os.Stat(fmt.Sprintf("%s/index.json", repo)); err != nil { 1673 content := []byte(`not a JSON content`) 1674 if err = os.WriteFile(fmt.Sprintf("%s/index.json", repo), content, 0o600); err != nil { 1675 panic(err) 1676 } 1677 } 1678 1679 tmpfile, err := os.CreateTemp("", "zot-test*.json") 1680 So(err, ShouldBeNil) 1681 defer os.Remove(tmpfile.Name()) // clean up 1682 content := []byte(fmt.Sprintf(`{ 1683 "storage": { 1684 "rootDirectory": "%s" 1685 }, 1686 "http": { 1687 "port": %s 1688 }, 1689 "log": { 1690 "level": "debug" 1691 } 1692 } 1693 `, dir, port)) 1694 _, err = tmpfile.Write(content) 1695 So(err, ShouldBeNil) 1696 err = tmpfile.Close() 1697 So(err, ShouldBeNil) 1698 1699 os.Args = []string{"cli_test", "scrub", tmpfile.Name()} 1700 err = cli.NewServerRootCmd().Execute() 1701 So(err, ShouldNotBeNil) 1702 }) 1703 }) 1704 } 1705 1706 func TestUpdateLDAPConfig(t *testing.T) { 1707 Convey("updateLDAPConfig errors while unmarshaling ldap config", t, func() { 1708 tempDir := t.TempDir() 1709 ldapConfigContent := "bad-json" 1710 ldapConfigPath := filepath.Join(tempDir, "ldap.json") 1711 1712 err := os.WriteFile(ldapConfigPath, []byte(ldapConfigContent), 0o000) 1713 So(err, ShouldBeNil) 1714 1715 configStr := fmt.Sprintf(` 1716 { 1717 "Storage": { 1718 "RootDirectory": "%s" 1719 }, 1720 "HTTP": { 1721 "Address": "%s", 1722 "Port": "%s", 1723 "Auth": { 1724 "LDAP": { 1725 "CredentialsFile": "%s", 1726 "BaseDN": "%v", 1727 "UserAttribute": "uid", 1728 "UserGroupAttribute": "memberOf", 1729 "Insecure": true, 1730 "Address": "%v", 1731 "Port": %v 1732 } 1733 } 1734 } 1735 }`, tempDir, "127.0.0.1", "8000", ldapConfigPath, "LDAPBaseDN", "LDAPAddress", 1000) 1736 1737 configPath := filepath.Join(tempDir, "config.json") 1738 1739 err = os.WriteFile(configPath, []byte(configStr), 0o0600) 1740 So(err, ShouldBeNil) 1741 1742 server := cli.NewServerRootCmd() 1743 server.SetArgs([]string{"serve", configPath}) 1744 So(server.Execute(), ShouldNotBeNil) 1745 1746 err = os.Chmod(ldapConfigPath, 0o600) 1747 So(err, ShouldBeNil) 1748 1749 server = cli.NewServerRootCmd() 1750 server.SetArgs([]string{"serve", configPath}) 1751 So(server.Execute(), ShouldNotBeNil) 1752 }) 1753 1754 Convey("unauthenticated LDAP config", t, func() { 1755 tempDir := t.TempDir() 1756 1757 configStr := fmt.Sprintf(` 1758 { 1759 "Storage": { 1760 "RootDirectory": "%s" 1761 }, 1762 "HTTP": { 1763 "Address": "%s", 1764 "Port": "%s", 1765 "Auth": { 1766 "LDAP": { 1767 "BaseDN": "%v", 1768 "UserAttribute": "uid", 1769 "UserGroupAttribute": "memberOf", 1770 "Insecure": true, 1771 "Address": "%v", 1772 "Port": %v 1773 } 1774 } 1775 } 1776 }`, tempDir, "127.0.0.1", "8000", "LDAPBaseDN", "LDAPAddress", 1000) 1777 1778 configPath := filepath.Join(tempDir, "config.json") 1779 1780 err := os.WriteFile(configPath, []byte(configStr), 0o0600) 1781 So(err, ShouldBeNil) 1782 1783 err = cli.LoadConfiguration(config.New(), configPath) 1784 So(err, ShouldBeNil) 1785 }) 1786 } 1787 1788 // run cli and return output. 1789 func runCLIWithConfig(tempDir string, config string) (string, error) { 1790 port := GetFreePort() 1791 baseURL := GetBaseURL(port) 1792 1793 logFile, err := os.CreateTemp(tempDir, "zot-log*.txt") 1794 if err != nil { 1795 return "", err 1796 } 1797 1798 cfgfile, err := os.CreateTemp(tempDir, "zot-test*.json") 1799 if err != nil { 1800 return "", err 1801 } 1802 1803 config = fmt.Sprintf(config, tempDir, port, logFile.Name()) 1804 1805 _, err = cfgfile.WriteString(config) 1806 if err != nil { 1807 return "", err 1808 } 1809 1810 err = cfgfile.Close() 1811 if err != nil { 1812 return "", err 1813 } 1814 1815 os.Args = []string{"cli_test", "serve", cfgfile.Name()} 1816 1817 go func() { 1818 err = cli.NewServerRootCmd().Execute() 1819 if err != nil { 1820 panic(err) 1821 } 1822 }() 1823 1824 WaitTillServerReady(baseURL) 1825 1826 return logFile.Name(), nil 1827 }