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