zotregistry.io/zot@v1.4.4-0.20231124084042-02a8ed785457/test/blackbox/sync.bats (about) 1 # Note: Intended to be run as "make run-blackbox-tests" or "make run-blackbox-ci" 2 # Makefile target installs & checks all necessary tooling 3 # Extra tools that are not covered in Makefile target needs to be added in verify_prerequisites() 4 5 load helpers_zot 6 load helpers_wait 7 8 9 function verify_prerequisites() { 10 if [ ! $(command -v curl) ]; then 11 echo "you need to install curl as a prerequisite to running the tests" >&3 12 return 1 13 fi 14 15 if [ ! $(command -v jq) ]; then 16 echo "you need to install jq as a prerequisite to running the tests" >&3 17 return 1 18 fi 19 20 return 0 21 } 22 23 function setup_file() { 24 export COSIGN_PASSWORD="" 25 export COSIGN_OCI_EXPERIMENTAL=1 26 export COSIGN_EXPERIMENTAL=1 27 28 # Verify prerequisites are available 29 if ! $(verify_prerequisites); then 30 exit 1 31 fi 32 33 # Download test data to folder common for the entire suite, not just this file 34 skopeo --insecure-policy copy --format=oci docker://ghcr.io/project-zot/golang:1.20 oci:${TEST_DATA_DIR}/golang:1.20 35 # Setup zot server 36 local zot_sync_per_root_dir=${BATS_FILE_TMPDIR}/zot-per 37 local zot_sync_ondemand_root_dir=${BATS_FILE_TMPDIR}/zot-ondemand 38 39 local zot_sync_per_config_file=${BATS_FILE_TMPDIR}/zot_sync_per_config.json 40 local zot_sync_ondemand_config_file=${BATS_FILE_TMPDIR}/zot_sync_ondemand_config.json 41 42 local zot_minimal_root_dir=${BATS_FILE_TMPDIR}/zot-minimal 43 local zot_minimal_config_file=${BATS_FILE_TMPDIR}/zot_minimal_config.json 44 45 local oci_data_dir=${BATS_FILE_TMPDIR}/oci 46 mkdir -p ${zot_sync_per_root_dir} 47 mkdir -p ${zot_sync_ondemand_root_dir} 48 mkdir -p ${zot_minimal_root_dir} 49 mkdir -p ${oci_data_dir} 50 zot_port1=$(get_free_port) 51 echo ${zot_port1} > ${BATS_FILE_TMPDIR}/zot.port1 52 zot_port2=$(get_free_port) 53 echo ${zot_port2} > ${BATS_FILE_TMPDIR}/zot.port2 54 zot_port3=$(get_free_port) 55 echo ${zot_port3} > ${BATS_FILE_TMPDIR}/zot.port3 56 57 cat >${zot_sync_per_config_file} <<EOF 58 { 59 "distSpecVersion": "1.1.0-dev", 60 "storage": { 61 "rootDirectory": "${zot_sync_per_root_dir}" 62 }, 63 "http": { 64 "address": "0.0.0.0", 65 "port": "${zot_port1}" 66 }, 67 "log": { 68 "level": "debug" 69 }, 70 "extensions": { 71 "sync": { 72 "registries": [ 73 { 74 "urls": [ 75 "http://localhost:${zot_port3}" 76 ], 77 "onDemand": false, 78 "tlsVerify": false, 79 "PollInterval": "1s", 80 "content": [ 81 { 82 "prefix": "**" 83 } 84 ] 85 } 86 ] 87 } 88 } 89 } 90 EOF 91 92 cat >${zot_sync_ondemand_config_file} <<EOF 93 { 94 "distSpecVersion": "1.1.0-dev", 95 "storage": { 96 "rootDirectory": "${zot_sync_ondemand_root_dir}" 97 }, 98 "http": { 99 "address": "0.0.0.0", 100 "port": "${zot_port2}" 101 }, 102 "log": { 103 "level": "debug" 104 }, 105 "extensions": { 106 "sync": { 107 "registries": [ 108 { 109 "urls": [ 110 "http://localhost:${zot_port3}" 111 ], 112 "onDemand": true, 113 "tlsVerify": false, 114 "content": [ 115 { 116 "prefix": "**" 117 } 118 ] 119 } 120 ] 121 } 122 } 123 } 124 EOF 125 cat >${zot_minimal_config_file} <<EOF 126 { 127 "distSpecVersion": "1.1.0-dev", 128 "storage": { 129 "rootDirectory": "${zot_minimal_root_dir}" 130 }, 131 "http": { 132 "address": "0.0.0.0", 133 "port": "${zot_port3}" 134 }, 135 "log": { 136 "level": "debug" 137 } 138 } 139 EOF 140 git -C ${BATS_FILE_TMPDIR} clone https://github.com/project-zot/helm-charts.git 141 142 zot_serve ${ZOT_PATH} ${zot_sync_per_config_file} 143 wait_zot_reachable ${zot_port1} 144 145 zot_serve ${ZOT_PATH} ${zot_sync_ondemand_config_file} 146 wait_zot_reachable ${zot_port2} 147 148 zot_serve ${ZOT_MINIMAL_PATH} ${zot_minimal_config_file} 149 wait_zot_reachable ${zot_port3} 150 } 151 152 function teardown_file() { 153 zot_stop_all 154 run rm -rf ${HOME}/.config/notation 155 } 156 157 # sync image 158 @test "sync golang image periodically" { 159 zot_port1=`cat ${BATS_FILE_TMPDIR}/zot.port1` 160 zot_port3=`cat ${BATS_FILE_TMPDIR}/zot.port3` 161 run skopeo --insecure-policy copy --dest-tls-verify=false \ 162 oci:${TEST_DATA_DIR}/golang:1.20 \ 163 docker://127.0.0.1:${zot_port3}/golang:1.20 164 [ "$status" -eq 0 ] 165 run curl http://127.0.0.1:${zot_port3}/v2/_catalog 166 [ "$status" -eq 0 ] 167 [ $(echo "${lines[-1]}" | jq '.repositories[]') = '"golang"' ] 168 run curl http://127.0.0.1:${zot_port1}/v2/_catalog 169 run curl http://127.0.0.1:${zot_port3}/v2/golang/tags/list 170 [ "$status" -eq 0 ] 171 [ $(echo "${lines[-1]}" | jq '.tags[]') = '"1.20"' ] 172 173 run sleep 20s 174 175 run curl http://127.0.0.1:${zot_port1}/v2/_catalog 176 [ "$status" -eq 0 ] 177 [ $(echo "${lines[-1]}" | jq '.repositories[]') = '"golang"' ] 178 179 run curl http://127.0.0.1:${zot_port1}/v2/golang/tags/list 180 [ "$status" -eq 0 ] 181 [ $(echo "${lines[-1]}" | jq '.tags[]') = '"1.20"' ] 182 } 183 184 @test "sync golang image ondemand" { 185 zot_port2=`cat ${BATS_FILE_TMPDIR}/zot.port2` 186 zot_port3=`cat ${BATS_FILE_TMPDIR}/zot.port3` 187 run skopeo --insecure-policy copy --dest-tls-verify=false \ 188 oci:${TEST_DATA_DIR}/golang:1.20 \ 189 docker://127.0.0.1:${zot_port3}/golang:1.20 190 [ "$status" -eq 0 ] 191 run curl http://127.0.0.1:${zot_port3}/v2/_catalog 192 [ "$status" -eq 0 ] 193 [ $(echo "${lines[-1]}" | jq '.repositories[]') = '"golang"' ] 194 195 # sync golang on demand 196 run curl http://127.0.0.1:${zot_port2}/v2/golang/manifests/1.20 197 [ "$status" -eq 0 ] 198 199 run curl http://127.0.0.1:${zot_port3}/v2/golang/tags/list 200 [ "$status" -eq 0 ] 201 [ $(echo "${lines[-1]}" | jq '.tags[]') = '"1.20"' ] 202 203 run curl http://127.0.0.1:${zot_port2}/v2/_catalog 204 [ "$status" -eq 0 ] 205 [ $(echo "${lines[-1]}" | jq '.repositories[]') = '"golang"' ] 206 207 run curl http://127.0.0.1:${zot_port2}/v2/golang/tags/list 208 [ "$status" -eq 0 ] 209 [ $(echo "${lines[-1]}" | jq '.tags[]') = '"1.20"' ] 210 } 211 212 # sync index 213 @test "sync image index periodically" { 214 zot_port1=`cat ${BATS_FILE_TMPDIR}/zot.port1` 215 zot_port3=`cat ${BATS_FILE_TMPDIR}/zot.port3` 216 # --multi-arch below pushes an image index (containing many images) instead 217 # of an image manifest (single image) 218 run skopeo --insecure-policy copy --format=oci --dest-tls-verify=false --multi-arch=all \ 219 docker://public.ecr.aws/docker/library/busybox:latest \ 220 docker://127.0.0.1:${zot_port3}/busybox:latest 221 [ "$status" -eq 0 ] 222 run curl http://127.0.0.1:${zot_port3}/v2/_catalog 223 [ "$status" -eq 0 ] 224 [ $(echo "${lines[-1]}" | jq '.repositories[0]') = '"busybox"' ] 225 run curl http://127.0.0.1:${zot_port3}/v2/busybox/tags/list 226 [ "$status" -eq 0 ] 227 [ $(echo "${lines[-1]}" | jq '.tags[]') = '"latest"' ] 228 229 run sleep 30s 230 231 run curl http://127.0.0.1:${zot_port1}/v2/_catalog 232 [ "$status" -eq 0 ] 233 [ $(echo "${lines[-1]}" | jq '.repositories[0]') = '"busybox"' ] 234 235 run curl http://127.0.0.1:${zot_port1}/v2/busybox/tags/list 236 [ "$status" -eq 0 ] 237 [ $(echo "${lines[-1]}" | jq '.tags[]') = '"latest"' ] 238 } 239 240 @test "sync image index on demand" { 241 zot_port2=`cat ${BATS_FILE_TMPDIR}/zot.port2` 242 zot_port3=`cat ${BATS_FILE_TMPDIR}/zot.port3` 243 # --multi-arch below pushes an image index (containing many images) instead 244 # of an image manifest (single image) 245 run skopeo --insecure-policy copy --format=oci --dest-tls-verify=false --multi-arch=all \ 246 docker://public.ecr.aws/docker/library/busybox:latest \ 247 docker://127.0.0.1:${zot_port3}/busybox:latest 248 [ "$status" -eq 0 ] 249 run curl http://127.0.0.1:${zot_port3}/v2/_catalog 250 [ "$status" -eq 0 ] 251 [ $(echo "${lines[-1]}" | jq '.repositories[1]') = '"golang"' ] 252 run curl http://127.0.0.1:${zot_port3}/v2/busybox/tags/list 253 [ "$status" -eq 0 ] 254 [ $(echo "${lines[-1]}" | jq '.tags[]') = '"latest"' ] 255 256 # sync busybox index on demand 257 run curl http://127.0.0.1:${zot_port2}/v2/busybox/manifests/latest 258 [ "$status" -eq 0 ] 259 260 run curl http://127.0.0.1:${zot_port2}/v2/_catalog 261 [ "$status" -eq 0 ] 262 [ $(echo "${lines[-1]}" | jq '.repositories[1]') = '"golang"' ] 263 264 run curl http://127.0.0.1:${zot_port2}/v2/busybox/tags/list 265 [ "$status" -eq 0 ] 266 [ $(echo "${lines[-1]}" | jq '.tags[]') = '"latest"' ] 267 } 268 269 # sign signatures 270 @test "sign/verify with cosign" { 271 zot_port3=`cat ${BATS_FILE_TMPDIR}/zot.port3` 272 run cosign initialize 273 [ "$status" -eq 0 ] 274 run cosign generate-key-pair --output-key-prefix "${BATS_FILE_TMPDIR}/cosign-sign-sync-test" 275 [ "$status" -eq 0 ] 276 run cosign sign --key ${BATS_FILE_TMPDIR}/cosign-sign-sync-test.key localhost:${zot_port3}/golang:1.20 --yes 277 [ "$status" -eq 0 ] 278 run cosign sign --registry-referrers-mode=oci-1-1 --key ${BATS_FILE_TMPDIR}/cosign-sign-sync-test.key localhost:${zot_port3}/golang:1.20 --yes 279 [ "$status" -eq 0 ] 280 run cosign verify --key ${BATS_FILE_TMPDIR}/cosign-sign-sync-test.pub localhost:${zot_port3}/golang:1.20 281 [ "$status" -eq 0 ] 282 } 283 284 @test "sign/verify with notation" { 285 zot_port3=`cat ${BATS_FILE_TMPDIR}/zot.port3` 286 run notation cert generate-test "notation-sign-sync-test" 287 [ "$status" -eq 0 ] 288 289 local trust_policy_file=${HOME}/.config/notation/trustpolicy.json 290 291 cat >${trust_policy_file} <<EOF 292 { 293 "version": "1.0", 294 "trustPolicies": [ 295 { 296 "name": "notation-sign-sync-test", 297 "registryScopes": [ "*" ], 298 "signatureVerification": { 299 "level" : "strict" 300 }, 301 "trustStores": [ "ca:notation-sign-sync-test" ], 302 "trustedIdentities": [ 303 "*" 304 ] 305 } 306 ] 307 } 308 EOF 309 310 run notation sign --key "notation-sign-sync-test" --insecure-registry localhost:${zot_port3}/golang:1.20 311 [ "$status" -eq 0 ] 312 run notation verify --insecure-registry localhost:${zot_port3}/golang:1.20 313 [ "$status" -eq 0 ] 314 run notation list --insecure-registry localhost:${zot_port3}/golang:1.20 315 [ "$status" -eq 0 ] 316 } 317 318 @test "sync signatures periodically" { 319 zot_port1=`cat ${BATS_FILE_TMPDIR}/zot.port1` 320 # wait for signatures to be copied 321 run sleep 15s 322 323 run notation verify --insecure-registry localhost:${zot_port1}/golang:1.20 324 [ "$status" -eq 0 ] 325 326 run cosign verify --key ${BATS_FILE_TMPDIR}/cosign-sign-sync-test.pub localhost:${zot_port1}/golang:1.20 327 [ "$status" -eq 0 ] 328 } 329 330 @test "sync signatures ondemand" { 331 zot_port2=`cat ${BATS_FILE_TMPDIR}/zot.port2` 332 run notation verify --insecure-registry localhost:${zot_port2}/golang:1.20 333 [ "$status" -eq 0 ] 334 335 run cosign verify --key ${BATS_FILE_TMPDIR}/cosign-sign-sync-test.pub localhost:${zot_port2}/golang:1.20 336 [ "$status" -eq 0 ] 337 } 338 339 # sync oras artifacts 340 @test "push oras artifact periodically" { 341 zot_port3=`cat ${BATS_FILE_TMPDIR}/zot.port3` 342 echo "{\"name\":\"foo\",\"value\":\"bar\"}" > config.json 343 echo "hello world" > artifact.txt 344 run oras push --plain-http 127.0.0.1:${zot_port3}/hello-artifact:v2 \ 345 --config config.json:application/vnd.acme.rocket.config.v1+json artifact.txt:text/plain -d -v 346 [ "$status" -eq 0 ] 347 rm -f artifact.txt 348 rm -f config.json 349 } 350 351 @test "sync oras artifact periodically" { 352 zot_port1=`cat ${BATS_FILE_TMPDIR}/zot.port1` 353 # wait for oras artifact to be copied 354 run sleep 15s 355 run oras pull --plain-http 127.0.0.1:${zot_port1}/hello-artifact:v2 -d -v 356 [ "$status" -eq 0 ] 357 grep -q "hello world" artifact.txt 358 rm -f artifact.txt 359 } 360 361 @test "sync oras artifact on demand" { 362 zot_port2=`cat ${BATS_FILE_TMPDIR}/zot.port2` 363 run oras pull --plain-http 127.0.0.1:${zot_port2}/hello-artifact:v2 -d -v 364 [ "$status" -eq 0 ] 365 grep -q "hello world" artifact.txt 366 rm -f artifact.txt 367 } 368 369 # sync helm chart 370 @test "push helm chart" { 371 zot_port3=`cat ${BATS_FILE_TMPDIR}/zot.port3` 372 run helm package ${BATS_FILE_TMPDIR}/helm-charts/charts/zot -d ${BATS_FILE_TMPDIR} 373 [ "$status" -eq 0 ] 374 local chart_version=$(awk '/version/{printf $2}' ${BATS_FILE_TMPDIR}/helm-charts/charts/zot/Chart.yaml) 375 run helm push ${BATS_FILE_TMPDIR}/zot-${chart_version}.tgz oci://localhost:${zot_port3}/zot-chart 376 [ "$status" -eq 0 ] 377 } 378 379 @test "sync helm chart periodically" { 380 zot_port1=`cat ${BATS_FILE_TMPDIR}/zot.port1` 381 # wait for helm chart to be copied 382 run sleep 15s 383 384 local chart_version=$(awk '/version/{printf $2}' ${BATS_FILE_TMPDIR}/helm-charts/charts/zot/Chart.yaml) 385 run helm pull oci://localhost:${zot_port1}/zot-chart/zot --version ${chart_version} -d ${BATS_FILE_TMPDIR} 386 [ "$status" -eq 0 ] 387 } 388 389 @test "sync helm chart on demand" { 390 zot_port2=`cat ${BATS_FILE_TMPDIR}/zot.port2` 391 local chart_version=$(awk '/version/{printf $2}' ${BATS_FILE_TMPDIR}/helm-charts/charts/zot/Chart.yaml) 392 run helm pull oci://localhost:${zot_port2}/zot-chart/zot --version ${chart_version} -d ${BATS_FILE_TMPDIR} 393 [ "$status" -eq 0 ] 394 } 395 396 # sync OCI artifacts 397 @test "push OCI artifact (oci image mediatype) with regclient" { 398 zot_port1=`cat ${BATS_FILE_TMPDIR}/zot.port1` 399 zot_port2=`cat ${BATS_FILE_TMPDIR}/zot.port2` 400 zot_port3=`cat ${BATS_FILE_TMPDIR}/zot.port3` 401 run regctl registry set localhost:${zot_port3} --tls disabled 402 run regctl registry set localhost:${zot_port1} --tls disabled 403 run regctl registry set localhost:${zot_port2} --tls disabled 404 405 run regctl artifact put localhost:${zot_port3}/artifact:demo <<EOF 406 this is an oci image artifact 407 EOF 408 [ "$status" -eq 0 ] 409 } 410 411 @test "sync OCI artifact (oci image mediatype) periodically" { 412 zot_port1=`cat ${BATS_FILE_TMPDIR}/zot.port1` 413 # wait for helm chart to be copied 414 run sleep 15s 415 run regctl manifest get localhost:${zot_port1}/artifact:demo 416 [ "$status" -eq 0 ] 417 run regctl artifact get localhost:${zot_port1}/artifact:demo 418 [ "$status" -eq 0 ] 419 [ "${lines[-1]}" == "this is an oci image artifact" ] 420 } 421 422 @test "sync OCI artifact (oci image mediatype) on demand" { 423 zot_port2=`cat ${BATS_FILE_TMPDIR}/zot.port2` 424 run regctl manifest get localhost:${zot_port2}/artifact:demo 425 [ "$status" -eq 0 ] 426 run regctl artifact get localhost:${zot_port2}/artifact:demo 427 [ "$status" -eq 0 ] 428 [ "${lines[-1]}" == "this is an oci image artifact" ] 429 } 430 431 @test "push OCI artifact (oci artifact mediatype) with regclient" { 432 zot_port3=`cat ${BATS_FILE_TMPDIR}/zot.port3` 433 run regctl artifact put --artifact-type "application/vnd.example.icecream.v1" localhost:${zot_port3}/newartifact:demo <<EOF 434 this is an oci artifact 435 EOF 436 [ "$status" -eq 0 ] 437 } 438 439 @test "sync OCI artifact (oci artifact mediatype) periodically" { 440 zot_port1=`cat ${BATS_FILE_TMPDIR}/zot.port1` 441 # wait for helm chart to be copied 442 run sleep 15s 443 run regctl manifest get localhost:${zot_port1}/newartifact:demo 444 [ "$status" -eq 0 ] 445 run regctl artifact get localhost:${zot_port1}/newartifact:demo 446 [ "$status" -eq 0 ] 447 [ "${lines[-1]}" == "this is an oci artifact" ] 448 } 449 450 @test "sync OCI artifact (oci artifact mediatype) on demand" { 451 zot_port2=`cat ${BATS_FILE_TMPDIR}/zot.port2` 452 run regctl manifest get localhost:${zot_port2}/newartifact:demo 453 [ "$status" -eq 0 ] 454 run regctl artifact get localhost:${zot_port2}/newartifact:demo 455 [ "$status" -eq 0 ] 456 [ "${lines[-1]}" == "this is an oci artifact" ] 457 } 458 459 @test "push OCI artifact references with regclient" { 460 zot_port3=`cat ${BATS_FILE_TMPDIR}/zot.port3` 461 run regctl artifact put localhost:${zot_port3}/manifest-ref:demo <<EOF 462 test artifact 463 EOF 464 [ "$status" -eq 0 ] 465 run regctl artifact list localhost:${zot_port3}/manifest-ref:demo --format raw-body 466 [ "$status" -eq 0 ] 467 [ $(echo "${lines[-1]}" | jq '.manifests | length') -eq 0 ] 468 run regctl artifact put --annotation demo=true --annotation format=oci --artifact-type "application/vnd.example.icecream.v1" --subject localhost:${zot_port3}/manifest-ref:demo << EOF 469 test reference 470 EOF 471 [ "$status" -eq 0 ] 472 # with artifact media-type 473 run regctl artifact put localhost:${zot_port3}/artifact-ref:demo <<EOF 474 test artifact 475 EOF 476 [ "$status" -eq 0 ] 477 run regctl artifact list localhost:${zot_port3}/artifact-ref:demo --format raw-body 478 [ "$status" -eq 0 ] 479 [ $(echo "${lines[-1]}" | jq '.manifests | length') -eq 0 ] 480 run regctl artifact put --annotation demo=true --annotation format=oci --artifact-type "application/vnd.example.icecream.v1" --subject localhost:${zot_port3}/artifact-ref:demo << EOF 481 test reference 482 EOF 483 [ "$status" -eq 0 ] 484 } 485 486 @test "sync OCI artifact references periodically" { 487 zot_port1=`cat ${BATS_FILE_TMPDIR}/zot.port1` 488 # wait for OCI artifacts to be copied 489 run sleep 20 490 run regctl artifact get localhost:${zot_port1}/manifest-ref:demo 491 [ "$status" -eq 0 ] 492 [ "${lines[-1]}" == "test artifact" ] 493 run regctl artifact list localhost:${zot_port1}/manifest-ref:demo --format raw-body 494 [ "$status" -eq 0 ] 495 [ $(echo "${lines[-1]}" | jq '.manifests | length') -eq 1 ] 496 run regctl artifact list --filter-artifact-type "application/vnd.example.icecream.v1" localhost:${zot_port1}/manifest-ref:demo --format raw-body 497 [ "$status" -eq 0 ] 498 [ $(echo "${lines[-1]}" | jq '.manifests | length') -eq 1 ] 499 run regctl artifact list --filter-artifact-type "application/invalid" localhost:${zot_port1}/manifest-ref:demo --format raw-body 500 [ "$status" -eq 0 ] 501 [ $(echo "${lines[-1]}" | jq '.manifests | length') -eq 0 ] 502 # with artifact media-type 503 run regctl artifact get localhost:${zot_port1}/artifact-ref:demo 504 [ "$status" -eq 0 ] 505 [ "${lines[-1]}" == "test artifact" ] 506 run regctl artifact list localhost:${zot_port1}/artifact-ref:demo --format raw-body 507 [ "$status" -eq 0 ] 508 [ $(echo "${lines[-1]}" | jq '.manifests | length') -eq 1 ] 509 run regctl artifact list --filter-artifact-type "application/vnd.example.icecream.v1" localhost:${zot_port1}/artifact-ref:demo --format raw-body 510 [ "$status" -eq 0 ] 511 [ $(echo "${lines[-1]}" | jq '.manifests | length') -eq 1 ] 512 run regctl artifact list --filter-artifact-type "application/invalid" localhost:${zot_port1}/artifact-ref:demo --format raw-body 513 [ "$status" -eq 0 ] 514 [ $(echo "${lines[-1]}" | jq '.manifests | length') -eq 0 ] 515 } 516 517 @test "sync OCI artifact references on demand" { 518 zot_port2=`cat ${BATS_FILE_TMPDIR}/zot.port2` 519 run regctl artifact get localhost:${zot_port2}/manifest-ref:demo 520 [ "$status" -eq 0 ] 521 [ "${lines[-1]}" == "test artifact" ] 522 run regctl artifact list localhost:${zot_port2}/manifest-ref:demo --format raw-body 523 [ "$status" -eq 0 ] 524 [ $(echo "${lines[-1]}" | jq '.manifests | length') -eq 1 ] 525 run regctl artifact list --filter-artifact-type "application/vnd.example.icecream.v1" localhost:${zot_port2}/manifest-ref:demo --format raw-body 526 [ "$status" -eq 0 ] 527 [ $(echo "${lines[-1]}" | jq '.manifests | length') -eq 1 ] 528 run regctl artifact list --filter-artifact-type "application/invalid" localhost:${zot_port2}/manifest-ref:demo --format raw-body 529 [ "$status" -eq 0 ] 530 [ $(echo "${lines[-1]}" | jq '.manifests | length') -eq 0 ] 531 # with artifact media-type 532 run regctl artifact get localhost:${zot_port2}/artifact-ref:demo 533 [ "$status" -eq 0 ] 534 [ "${lines[-1]}" == "test artifact" ] 535 run regctl artifact list localhost:${zot_port2}/artifact-ref:demo --format raw-body 536 [ "$status" -eq 0 ] 537 [ $(echo "${lines[-1]}" | jq '.manifests | length') -eq 1 ] 538 run regctl artifact list --filter-artifact-type "application/vnd.example.icecream.v1" localhost:${zot_port2}/artifact-ref:demo --format raw-body 539 [ "$status" -eq 0 ] 540 [ $(echo "${lines[-1]}" | jq '.manifests | length') -eq 1 ] 541 run regctl artifact list --filter-artifact-type "application/invalid" localhost:${zot_port2}/artifact-ref:demo --format raw-body 542 [ "$status" -eq 0 ] 543 [ $(echo "${lines[-1]}" | jq '.manifests | length') -eq 0 ] 544 }