github.com/containers/podman/v5@v5.1.0-rc1/test/system/012-manifest.bats (about)

     1  #!/usr/bin/env bats
     2  
     3  load helpers
     4  load helpers.network
     5  load helpers.registry
     6  
     7  function teardown() {
     8      # Enumerate every one of the manifest names used everywhere below
     9      echo "[ teardown - ignore 'image not known' errors below ]"
    10      run_podman '?' manifest rm test:1.0 \
    11                 localhost:${PODMAN_LOGIN_REGISTRY_PORT}/test:1.0
    12  
    13      basic_teardown
    14  }
    15  
    16  # Helper function for several of the tests which verifies compression.
    17  #
    18  #  Usage:  validate_instance_compression INDEX MANIFEST ARCH COMPRESSION
    19  #
    20  #     INDEX             instance which needs to be verified in
    21  #                       provided manifest list.
    22  #
    23  #     MANIFEST          OCI manifest specification in json format
    24  #
    25  #     ARCH              instance architecture
    26  #
    27  #     COMPRESSION       compression algorithm name; e.g "zstd".
    28  #
    29  function validate_instance_compression {
    30    case $4 in
    31  
    32     gzip)
    33      run jq -r '.manifests['$1'].annotations' <<< $2
    34      # annotation is `null` for gzip compression
    35      assert "$output" = "null" ".manifests[$1].annotations (null means gzip)"
    36      ;;
    37  
    38    zstd)
    39      # annotation `'"io.github.containers.compression.zstd": "true"'` must be there for zstd compression
    40      run jq -r '.manifests['$1'].annotations."io.github.containers.compression.zstd"' <<< $2
    41      assert "$output" = "true" ".manifests[$1].annotations.'io.github.containers.compression.zstd' (io.github.containers.compression.zstd must be set)"
    42      ;;
    43    esac
    44  
    45    run jq -r '.manifests['$1'].platform.architecture' <<< $2
    46    assert "$output" = $3 ".manifests[$1].platform.architecture"
    47  }
    48  
    49  # Regression test for #8931
    50  @test "podman images - bare manifest list" {
    51      # Create an empty manifest list and list images.
    52  
    53      run_podman inspect --format '{{.ID}}' $IMAGE
    54      iid=$output
    55  
    56      run_podman manifest create test:1.0
    57      mid=$output
    58      run_podman manifest inspect --verbose $mid
    59      is "$output" ".*\"mediaType\": \"application/vnd.docker.distribution.manifest.list.v2+json\"" "--insecure is a noop want to make sure manifest inspect is successful"
    60      run_podman manifest inspect -v $mid
    61      is "$output" ".*\"mediaType\": \"application/vnd.docker.distribution.manifest.list.v2+json\"" "--insecure is a noop want to make sure manifest inspect is successful"
    62      run_podman images --format '{{.ID}}' --no-trunc
    63      is "$output" ".*sha256:$iid" "Original image ID still shown in podman-images output"
    64      run_podman rmi test:1.0
    65  }
    66  
    67  @test "podman manifest --tls-verify and --authfile" {
    68      skip_if_remote "running a local registry doesn't work with podman-remote"
    69      start_registry
    70      authfile=${PODMAN_LOGIN_WORKDIR}/auth-$(random_string 10).json
    71      run_podman login --tls-verify=false \
    72                 --username ${PODMAN_LOGIN_USER} \
    73                 --password-stdin \
    74                 --authfile=$authfile \
    75                 localhost:${PODMAN_LOGIN_REGISTRY_PORT} <<<"${PODMAN_LOGIN_PASS}"
    76      is "$output" "Login Succeeded!" "output from podman login"
    77  
    78      manifest1="localhost:${PODMAN_LOGIN_REGISTRY_PORT}/test:1.0"
    79      run_podman manifest create $manifest1
    80      mid=$output
    81      run_podman manifest push --authfile=$authfile \
    82          --tls-verify=false $mid \
    83          $manifest1
    84      run_podman manifest rm $manifest1
    85  
    86      # Default is to require TLS; also test explicit opts
    87      for opt in '' '--insecure=false' '--tls-verify=true' "--authfile=$authfile"; do
    88          run_podman 125 manifest inspect $opt $manifest1
    89          assert "$output" =~ "Error: reading image \"docker://$manifest1\": pinging container registry localhost:${PODMAN_LOGIN_REGISTRY_PORT}:.*x509" \
    90                 "TLE check: fails (as expected) with ${opt:-default}"
    91      done
    92  
    93      run_podman manifest inspect --authfile=$authfile --tls-verify=false $manifest1
    94      is "$output" ".*\"mediaType\": \"application/vnd.docker.distribution.manifest.list.v2+json\"" "Verify --tls-verify=false --authfile works against an insecure registry"
    95      run_podman manifest inspect --authfile=$authfile --insecure $manifest1
    96      is "$output" ".*\"mediaType\": \"application/vnd.docker.distribution.manifest.list.v2+json\"" "Verify --insecure --authfile works against an insecure registry"
    97      REGISTRY_AUTH_FILE=$authfile run_podman manifest inspect --tls-verify=false $manifest1
    98      is "$output" ".*\"mediaType\": \"application/vnd.docker.distribution.manifest.list.v2+json\"" "Verify --tls-verify=false with REGISTRY_AUTH_FILE works against an insecure registry"
    99  }
   100  
   101  @test "manifest list --add-compression with zstd" {
   102      skip_if_remote "running a local registry doesn't work with podman-remote"
   103      start_registry
   104  
   105      # Using TARGETARCH gives us distinct images for each arch
   106      dockerfile=$PODMAN_TMPDIR/Dockerfile
   107      cat >$dockerfile <<EOF
   108  FROM scratch
   109  ARG TARGETARCH
   110  COPY Dockerfile /i-am-\${TARGETARCH}
   111  EOF
   112      authfile=${PODMAN_LOGIN_WORKDIR}/auth-$(random_string 10).json
   113      run_podman login --tls-verify=false \
   114                 --username ${PODMAN_LOGIN_USER} \
   115                 --password-stdin \
   116                 --authfile=$authfile \
   117                 localhost:${PODMAN_LOGIN_REGISTRY_PORT} <<<"${PODMAN_LOGIN_PASS}"
   118      is "$output" "Login Succeeded!" "output from podman login"
   119  
   120      # Build two images, different arches, and add each to one manifest list
   121      local manifestlocal="test:1.0"
   122      run_podman manifest create $manifestlocal
   123      for arch in amd arm;do
   124          # This leaves behind a <none>:<none> image that must be purged, below
   125          run_podman build -t image_$arch --platform linux/${arch}64 -f $dockerfile
   126          run_podman manifest add $manifestlocal containers-storage:localhost/image_$arch:latest
   127      done
   128  
   129      # (for debugging)
   130      run_podman images -a
   131  
   132      # Push to local registry; the magic key here is --add-compression...
   133      local manifestpushed="localhost:${PODMAN_LOGIN_REGISTRY_PORT}/test:1.0"
   134      run_podman manifest push --authfile=$authfile --all --compression-format gzip --add-compression zstd --tls-verify=false $manifestlocal $manifestpushed
   135  
   136      # ...and use skopeo to confirm that each component has the right settings
   137      echo "$_LOG_PROMPT skopeo inspect ... $manifestpushed"
   138      list=$(skopeo inspect --authfile=$authfile --tls-verify=false --raw docker://$manifestpushed)
   139      jq . <<<"$list"
   140  
   141      validate_instance_compression "0" "$list" "amd64" "gzip"
   142      validate_instance_compression "1" "$list" "arm64" "gzip"
   143      validate_instance_compression "2" "$list" "amd64" "zstd"
   144      validate_instance_compression "3" "$list" "arm64" "zstd"
   145  
   146      run_podman rmi image_amd image_arm
   147      run_podman manifest rm $manifestlocal
   148  
   149      # Needed because the above build leaves a dangling <none>
   150      run_podman image prune -f
   151  }
   152  
   153  function manifestListAddArtifactOnce() {
   154      echo listFlags="$listFlags"
   155      echo platformFlags="$platformFlags"
   156      echo typeFlag="$typeFlag"
   157      echo layerTypeFlag="$layerTypeFlag"
   158      echo configTypeFlag="$configTypeFlag"
   159      echo configFlag="$configFlag"
   160      echo titleFlag="$titleFlag"
   161      local index artifact firstdigest seconddigest config configSize defaulttype filetitle requested expected actual
   162      run_podman manifest create $listFlags $list
   163      run_podman manifest add $list ${platformFlags} --artifact ${typeFlag} ${layerTypeFlag} ${configTypeFlag} ${configFlag} ${titleFlag} ${PODMAN_TMPDIR}/listed.txt
   164      run_podman manifest add $list ${platformFlags} --artifact ${typeFlag} ${layerTypeFlag} ${configTypeFlag} ${configFlag} ${titleFlag} ${PODMAN_TMPDIR}/zeroes
   165      run_podman manifest inspect $list
   166      run_podman tag $list localhost:${PODMAN_LOGIN_REGISTRY_PORT}/test
   167      run_podman manifest push --tls-verify=false localhost:${PODMAN_LOGIN_REGISTRY_PORT}/test
   168      run skopeo inspect --tls-verify=false --raw docker://localhost:${PODMAN_LOGIN_REGISTRY_PORT}/test
   169      assert $status -eq 0
   170      echo "$output"
   171      index="$output"
   172      if [[ -n "$listFlags" ]] ; then
   173          assert $(jq -r '.annotations["global"]' <<<"$index") == local
   174      fi
   175      if [[ -n "$platformFlags" ]] ; then
   176          assert $(jq -r '.manifests[1].platform.os' <<<"$index") == linux
   177          assert $(jq -r '.manifests[1].platform.architecture' <<<"$index") == amd64
   178      fi
   179      if [[ -n "$typeFlag" ]] ; then
   180          actual=$(jq -r '.manifests[0].artifactType' <<<"$index")
   181          assert "${actual#null}" == "${typeFlag#--artifact-type=}"
   182          actual=$(jq -r '.manifests[1].artifactType' <<<"$index")
   183          assert "${actual#null}" == "${typeFlag#--artifact-type=}"
   184      fi
   185      firstdigest=$(jq -r '.manifests[0].digest' <<<"$index")
   186      seconddigest=$(jq -r '.manifests[1].digest' <<<"$index")
   187      for digest in $firstdigest $seconddigest ; do
   188          case $digest in
   189          $firstdigest)
   190              filetitle=listed.txt
   191              defaulttype=text/plain
   192              ;;
   193          $seconddigest)
   194              filetitle=zeroes
   195              defaulttype=application/octet-stream
   196              ;;
   197          *)
   198              false
   199              ;;
   200          esac
   201          run skopeo inspect --raw --tls-verify=false docker://localhost:${PODMAN_LOGIN_REGISTRY_PORT}/test@${digest}
   202          assert $status -eq 0
   203          echo "$output"
   204          artifact="$output"
   205          if [[ -n "$typeFlag" ]] ; then
   206              actual=$(jq -r '.artifactType' <<<"$artifact")
   207              assert "${actual#null}" == "${typeFlag#--artifact-type=}"
   208          else
   209              actual=$(jq -r '.artifactType' <<<"$artifact")
   210              assert "${actual}" == application/vnd.unknown.artifact.v1
   211          fi
   212          if [ -n "$layerTypeFlag" ] ; then
   213              actual=$(jq -r '.layers[0].mediaType' <<<"$artifact")
   214              assert "${actual}" == "${layerTypeFlag#--artifact-layer-type=}"
   215          else
   216              actual=$(jq -r '.layers[0].mediaType' <<<"$artifact")
   217              assert "${actual}" == "$defaulttype"
   218          fi
   219          requested=${configTypeFlag#--artifact-config-type=}
   220          actual=$(jq -r '.config.mediaType' <<<"$artifact")
   221          if test -n "$requested" ; then
   222              assert "$actual" == "$requested"
   223          else
   224              config=${configFlag#--artifact-config=}
   225              if [ -z "$config" ] ; then
   226                  expected=application/vnd.oci.empty.v1+json
   227              else
   228                  configSize=$(wc -c <"$config")
   229                  if [ $configSize -gt 0 ] ; then
   230                      expected=application/vnd.oci.image.config.v1+json
   231                  else
   232                      expected=application/vnd.oci.empty.v1+json
   233                  fi
   234              fi
   235              assert "$actual" == "$expected"
   236          fi
   237          if test -n "$titleFlag" ; then
   238              assert $(jq -r '.layers[0].annotations["org.opencontainers.image.title"]' <<<"$artifact") == null
   239          else
   240              assert $(jq -r '.layers[0].annotations["org.opencontainers.image.title"]' <<<"$artifact") == $filetitle
   241          fi
   242      done
   243      run_podman rmi $list localhost:${PODMAN_LOGIN_REGISTRY_PORT}/test
   244  }
   245  
   246  @test "manifest list --add --artifact" {
   247      # Build a list and add some files to it, making sure to exercise and verify
   248      # every flag available.
   249      skip_if_remote "running a local registry doesn't work with podman-remote"
   250      start_registry
   251      run_podman login --tls-verify=false \
   252                 --username ${PODMAN_LOGIN_USER} \
   253                 --password-stdin \
   254                 --authfile=$authfile \
   255                 localhost:${PODMAN_LOGIN_REGISTRY_PORT} <<<"${PODMAN_LOGIN_PASS}"
   256      local list="test:1.0"
   257      truncate -s 20M ${PODMAN_TMPDIR}/zeroes
   258      echo oh yeah > ${PODMAN_TMPDIR}/listed.txt
   259      echo '{}' > ${PODMAN_TMPDIR}/minimum-config.json
   260      local listFlags platformFlags typeFlag configTypeFlag configFlag layerTypeFlag titleFlag
   261      for listFlags in "" "--annotation global=local" ; do
   262          manifestListAddArtifactOnce
   263      done
   264      for platformFlags in "" "--os=linux --arch=amd64" ; do
   265          manifestListAddArtifactOnce
   266      done
   267      for typeFlag in "" --artifact-type="" --artifact-type=application/octet-stream --artifact-type=text/plain ; do
   268          manifestListAddArtifactOnce
   269      done
   270      for configTypeFlag in "" --artifact-config-type=application/octet-stream --artifact-config-type=text/plain ; do
   271          for configFlag in "" --artifact-config= --artifact-config=${PODMAN_TMPDIR}/minimum-config.json ; do
   272              manifestListAddArtifactOnce
   273          done
   274      done
   275      for layerTypeFlag in "" --artifact-layer-type=application/octet-stream --artifact-layer-type=text/plain ; do
   276          manifestListAddArtifactOnce
   277      done
   278      for titleFlag in "" "--artifact-exclude-titles" ; do
   279          manifestListAddArtifactOnce
   280      done
   281      stop_registry
   282  }
   283  # vim: filetype=sh