zotregistry.dev/zot@v1.4.4-0.20240314164342-eec277e14d20/test/blackbox/annotations.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 7 function verify_prerequisites { 8 if [ ! $(command -v curl) ]; then 9 echo "you need to install curl as a prerequisite to running the tests" >&3 10 return 1 11 fi 12 13 if [ ! $(command -v jq) ]; then 14 echo "you need to install jq as a prerequisite to running the tests" >&3 15 return 1 16 fi 17 18 if [ ! $(command -v podman) ]; then 19 echo "you need to install podman as a prerequisite to running the tests" >&3 20 return 1 21 fi 22 23 return 0 24 } 25 26 function setup_file() { 27 export COSIGN_PASSWORD="" 28 # Verify prerequisites are available 29 if ! $(verify_prerequisites); then 30 exit 1 31 fi 32 # Download test data to folder common for the entire suite, not just this file 33 skopeo --insecure-policy copy --format=oci docker://ghcr.io/project-zot/golang:1.20 oci:${TEST_DATA_DIR}/golang:1.20 34 # Setup zot server 35 local zot_root_dir=${BATS_FILE_TMPDIR}/zot 36 local zot_config_file=${BATS_FILE_TMPDIR}/zot_config.json 37 mkdir -p ${zot_root_dir} 38 zot_port=$(get_free_port) 39 echo ${zot_port} > ${BATS_FILE_TMPDIR}/zot.port 40 cat > ${zot_config_file}<<EOF 41 { 42 "distSpecVersion": "1.1.0", 43 "storage": { 44 "rootDirectory": "${zot_root_dir}" 45 }, 46 "http": { 47 "address": "0.0.0.0", 48 "port": "${zot_port}" 49 }, 50 "log": { 51 "level": "debug", 52 "output": "${BATS_FILE_TMPDIR}/zot.log" 53 }, 54 "extensions":{ 55 "search": { 56 "enable": "true" 57 }, 58 "lint": { 59 "enable": "true", 60 "mandatoryAnnotations": ["org.opencontainers.image.licenses", "org.opencontainers.image.vendor"] 61 } 62 } 63 } 64 EOF 65 cat > ${BATS_FILE_TMPDIR}/stacker.yaml<<EOF 66 \${{IMAGE_NAME}}: 67 from: 68 type: docker 69 url: docker://\${{IMAGE_NAME}}:\${{IMAGE_TAG}} 70 annotations: 71 org.opencontainers.image.title: \${{IMAGE_NAME}} 72 org.opencontainers.image.description: \${{DESCRIPTION}} 73 org.opencontainers.image.licenses: \${{LICENSES}} 74 org.opencontainers.image.vendor: \${{VENDOR}} 75 EOF 76 cat > ${BATS_FILE_TMPDIR}/Dockerfile<<EOF 77 FROM public.ecr.aws/t0x7q1g8/centos:7 78 CMD ["/bin/sh", "-c", "echo 'It works!'"] 79 EOF 80 zot_serve ${ZOT_PATH} ${zot_config_file} 81 wait_zot_reachable ${zot_port} 82 } 83 84 function teardown() { 85 # conditionally printing on failure is possible from teardown but not from from teardown_file 86 cat ${BATS_FILE_TMPDIR}/zot.log 87 } 88 89 function teardown_file() { 90 zot_stop_all 91 run rm -rf ${HOME}/.config/notation 92 } 93 94 @test "build image with podman and specify annotations" { 95 zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port` 96 run podman build -f ${BATS_FILE_TMPDIR}/Dockerfile -t 127.0.0.1:${zot_port}/annotations:latest . --format oci --annotation org.opencontainers.image.vendor="CentOS" --annotation org.opencontainers.image.licenses="GPLv2" 97 [ "$status" -eq 0 ] 98 run podman push 127.0.0.1:${zot_port}/annotations:latest --tls-verify=false --format=oci 99 [ "$status" -eq 0 ] 100 run curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList(repo: \"annotations\") { Results { RepoName Tag Manifests {Digest ConfigDigest Size Layers { Size Digest }} Vendor Licenses }}}"}' http://localhost:${zot_port}/v2/_zot/ext/search 101 [ "$status" -eq 0 ] 102 103 [ $(echo "${lines[-1]}" | jq '.data.ImageList.Results[0].RepoName') = '"annotations"' ] 104 [ $(echo "${lines[-1]}" | jq '.data.ImageList.Results[0].Vendor') = '"CentOS"' ] 105 [ $(echo "${lines[-1]}" | jq '.data.ImageList.Results[0].Licenses') = '"GPLv2"' ] 106 } 107 108 @test "build image with stacker and specify annotations" { 109 zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port` 110 run stacker --oci-dir ${BATS_FILE_TMPDIR}/stackeroci --stacker-dir ${BATS_FILE_TMPDIR}/.stacker --roots-dir ${BATS_FILE_TMPDIR}/roots build -f ${BATS_FILE_TMPDIR}/stacker.yaml --substitute IMAGE_NAME="ghcr.io/project-zot/golang" --substitute IMAGE_TAG="1.20" --substitute DESCRIPTION="mydesc" --substitute VENDOR="CentOs" --substitute LICENSES="GPLv2" --substitute COMMIT= --substitute OS=$OS --substitute ARCH=$ARCH 111 [ "$status" -eq 0 ] 112 run stacker --oci-dir ${BATS_FILE_TMPDIR}/stackeroci --stacker-dir ${BATS_FILE_TMPDIR}/.stacker --roots-dir ${BATS_FILE_TMPDIR}/roots publish -f ${BATS_FILE_TMPDIR}/stacker.yaml --substitute IMAGE_NAME="ghcr.io/project-zot/golang" --substitute IMAGE_TAG="1.20" --substitute DESCRIPTION="mydesc" --substitute VENDOR="CentOs" --substitute LICENSES="GPLv2" --url docker://127.0.0.1:${zot_port} --tag 1.20 --skip-tls 113 [ "$status" -eq 0 ] 114 run curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList(repo: \"ghcr.io/project-zot/golang\") { Results { RepoName Tag Manifests {Digest ConfigDigest Size Layers { Size Digest }} Vendor Licenses Description }}}"}' http://localhost:${zot_port}/v2/_zot/ext/search 115 [ "$status" -eq 0 ] 116 [ $(echo "${lines[-1]}" | jq '.data.ImageList.Results[0].RepoName') = '"ghcr.io/project-zot/golang"' ] 117 [ $(echo "${lines[-1]}" | jq '.data.ImageList.Results[0].Description') = '"mydesc"' ] 118 [ $(echo "${lines[-1]}" | jq '.data.ImageList.Results[0].Vendor') = '"CentOs"' ] 119 [ $(echo "${lines[-1]}" | jq '.data.ImageList.Results[0].Licenses') = '"GPLv2"' ] 120 } 121 122 @test "sign/verify with cosign (only tag-based signatures)" { 123 zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port` 124 run curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList(repo: \"annotations\") { Results { RepoName Tag Manifests {Digest ConfigDigest Size Layers { Size Digest }} Vendor Licenses }}}"}' http://localhost:${zot_port}/v2/_zot/ext/search 125 [ "$status" -eq 0 ] 126 [ $(echo "${lines[-1]}" | jq '.data.ImageList.Results[0].RepoName') = '"annotations"' ] 127 local digest=$(echo "${lines[-1]}" | jq -r '.data.ImageList.Results[0].Manifests[0].Digest') 128 129 run cosign initialize 130 [ "$status" -eq 0 ] 131 run cosign generate-key-pair --output-key-prefix "${BATS_FILE_TMPDIR}/cosign-sign-test" 132 [ "$status" -eq 0 ] 133 run cosign sign --key ${BATS_FILE_TMPDIR}/cosign-sign-test.key localhost:${zot_port}/annotations:latest --yes 134 [ "$status" -eq 0 ] 135 run cosign verify --key ${BATS_FILE_TMPDIR}/cosign-sign-test.pub localhost:${zot_port}/annotations:latest 136 [ "$status" -eq 0 ] 137 local sigName=$(echo "${lines[-1]}" | jq '.[].critical.image."docker-manifest-digest"') 138 [[ "$sigName" == *"${digest}"* ]] 139 tags=( $(oras repo tags --plain-http localhost:${zot_port}/annotations) ) 140 [ "$status" -eq 0 ] 141 local sigdes=$(oras manifest fetch --descriptor localhost:${zot_port}/annotations:${tags[1]} | jq .digest | tr -d \") 142 [ "$status" -eq 0 ] 143 run oras manifest fetch --plain-http localhost:${zot_port}/annotations@${sigdes} 144 [ "$status" -eq 0 ] 145 } 146 147 @test "sign/verify with cosign (only referrers)" { 148 zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port` 149 run curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList(repo: \"annotations\") { Results { RepoName Tag Manifests {Digest ConfigDigest Size Layers { Size Digest }} Vendor Licenses }}}"}' http://localhost:${zot_port}/v2/_zot/ext/search 150 [ "$status" -eq 0 ] 151 [ $(echo "${lines[-1]}" | jq '.data.ImageList.Results[0].RepoName') = '"annotations"' ] 152 local digest=$(echo "${lines[-1]}" | jq -r '.data.ImageList.Results[0].Manifests[0].Digest') 153 154 export COSIGN_OCI_EXPERIMENTAL=1 155 export COSIGN_EXPERIMENTAL=1 156 run cosign initialize 157 [ "$status" -eq 0 ] 158 run cosign generate-key-pair --output-key-prefix "${BATS_FILE_TMPDIR}/cosign-sign-test-experimental" 159 [ "$status" -eq 0 ] 160 run cosign sign --registry-referrers-mode=oci-1-1 --key ${BATS_FILE_TMPDIR}/cosign-sign-test-experimental.key localhost:${zot_port}/annotations:latest --yes 161 [ "$status" -eq 0 ] 162 run cosign verify --key ${BATS_FILE_TMPDIR}/cosign-sign-test-experimental.pub localhost:${zot_port}/annotations:latest 163 [ "$status" -eq 0 ] 164 local sigName=$(echo "${lines[-1]}" | jq '.[].critical.image."docker-manifest-digest"') 165 [[ "$sigName" == *"${digest}"* ]] 166 unset COSIGN_OCI_EXPERIMENTAL 167 unset COSIGN_EXPERIMENTAL 168 } 169 170 @test "sign/verify with cosign (tag and referrers)" { 171 zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port` 172 run curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList(repo: \"annotations\") { Results { RepoName Tag Manifests {Digest ConfigDigest Size Layers { Size Digest }} Vendor Licenses }}}"}' http://localhost:${zot_port}/v2/_zot/ext/search 173 [ "$status" -eq 0 ] 174 [ $(echo "${lines[-1]}" | jq '.data.ImageList.Results[0].RepoName') = '"annotations"' ] 175 local digest=$(echo "${lines[-1]}" | jq -r '.data.ImageList.Results[0].Manifests[0].Digest') 176 177 export COSIGN_OCI_EXPERIMENTAL=1 178 export COSIGN_EXPERIMENTAL=1 179 run cosign initialize 180 [ "$status" -eq 0 ] 181 182 run cosign generate-key-pair --output-key-prefix "${BATS_FILE_TMPDIR}/cosign-sign-test-tag-1" 183 [ "$status" -eq 0 ] 184 run cosign sign --key ${BATS_FILE_TMPDIR}/cosign-sign-test-tag-1.key localhost:${zot_port}/annotations:latest --yes 185 [ "$status" -eq 0 ] 186 187 run cosign generate-key-pair --output-key-prefix "${BATS_FILE_TMPDIR}/cosign-sign-test-referrers-1" 188 [ "$status" -eq 0 ] 189 run cosign sign --registry-referrers-mode=oci-1-1 --key ${BATS_FILE_TMPDIR}/cosign-sign-test-referrers-1.key localhost:${zot_port}/annotations:latest --yes 190 [ "$status" -eq 0 ] 191 192 run cosign generate-key-pair --output-key-prefix "${BATS_FILE_TMPDIR}/cosign-sign-test-tag-2" 193 [ "$status" -eq 0 ] 194 run cosign sign --key ${BATS_FILE_TMPDIR}/cosign-sign-test-tag-2.key localhost:${zot_port}/annotations:latest --yes 195 [ "$status" -eq 0 ] 196 197 run cosign verify --key ${BATS_FILE_TMPDIR}/cosign-sign-test-tag-1.pub localhost:${zot_port}/annotations:latest 198 [ "$status" -eq 0 ] 199 local sigName=$(echo "${lines[-1]}" | jq '.[].critical.image."docker-manifest-digest"') 200 [[ "$sigName" == *"${digest}"* ]] 201 run cosign verify --key ${BATS_FILE_TMPDIR}/cosign-sign-test-tag-2.pub localhost:${zot_port}/annotations:latest 202 [ "$status" -eq 0 ] 203 local sigName=$(echo "${lines[-1]}" | jq '.[].critical.image."docker-manifest-digest"') 204 [[ "$sigName" == *"${digest}"* ]] 205 run cosign verify --key ${BATS_FILE_TMPDIR}/cosign-sign-test-referrers-1.pub localhost:${zot_port}/annotations:latest 206 [ "$status" -eq 0 ] 207 local sigName=$(echo "${lines[-1]}" | jq '.[].critical.image."docker-manifest-digest"') 208 [[ "$sigName" == *"${digest}"* ]] 209 210 run cosign generate-key-pair --output-key-prefix "${BATS_FILE_TMPDIR}/cosign-sign-test-referrers-2" 211 [ "$status" -eq 0 ] 212 run cosign sign --registry-referrers-mode=oci-1-1 --key ${BATS_FILE_TMPDIR}/cosign-sign-test-referrers-2.key localhost:${zot_port}/annotations:latest --yes 213 [ "$status" -eq 0 ] 214 run cosign verify --key ${BATS_FILE_TMPDIR}/cosign-sign-test-referrers-2.pub localhost:${zot_port}/annotations:latest 215 [ "$status" -eq 0 ] 216 local sigName=$(echo "${lines[-1]}" | jq '.[].critical.image."docker-manifest-digest"') 217 [[ "$sigName" == *"${digest}"* ]] 218 219 unset COSIGN_OCI_EXPERIMENTAL 220 unset COSIGN_EXPERIMENTAL 221 } 222 223 @test "sign/verify with notation" { 224 zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port` 225 run curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList(repo: \"annotations\") { Results { RepoName Tag Manifests {Digest ConfigDigest Size Layers { Size Digest }} Vendor Licenses }}}"}' http://localhost:${zot_port}/v2/_zot/ext/search 226 [ "$status" -eq 0 ] 227 [ $(echo "${lines[-1]}" | jq '.data.ImageList.Results[0].RepoName') = '"annotations"' ] 228 [ "$status" -eq 0 ] 229 230 run notation cert generate-test "notation-sign-test" 231 [ "$status" -eq 0 ] 232 233 local trust_policy_file=${HOME}/.config/notation/trustpolicy.json 234 235 cat >${trust_policy_file} <<EOF 236 { 237 "version": "1.0", 238 "trustPolicies": [ 239 { 240 "name": "notation-sign-test", 241 "registryScopes": [ "*" ], 242 "signatureVerification": { 243 "level" : "strict" 244 }, 245 "trustStores": [ "ca:notation-sign-test" ], 246 "trustedIdentities": [ 247 "*" 248 ] 249 } 250 ] 251 } 252 EOF 253 254 run notation sign --key "notation-sign-test" --insecure-registry localhost:${zot_port}/annotations:latest 255 [ "$status" -eq 0 ] 256 run notation verify --insecure-registry localhost:${zot_port}/annotations:latest 257 [ "$status" -eq 0 ] 258 run notation list --insecure-registry localhost:${zot_port}/annotations:latest 259 [ "$status" -eq 0 ] 260 } 261 262 @test "sign/verify with notation( NOTATION_EXPERIMENTAL=1 and --allow-referrers-api )" { 263 zot_port=`cat ${BATS_FILE_TMPDIR}/zot.port` 264 run curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ ImageList(repo: \"annotations\") { Results { RepoName Tag Manifests {Digest ConfigDigest Size Layers { Size Digest }} Vendor Licenses }}}"}' http://localhost:${zot_port}/v2/_zot/ext/search 265 [ "$status" -eq 0 ] 266 [ $(echo "${lines[-1]}" | jq '.data.ImageList.Results[0].RepoName') = '"annotations"' ] 267 [ "$status" -eq 0 ] 268 269 run notation cert generate-test "notation-sign-test-experimental" 270 [ "$status" -eq 0 ] 271 272 local trust_policy_file=${HOME}/.config/notation/trustpolicy.json 273 274 cat >${trust_policy_file} <<EOF 275 { 276 "version": "1.0", 277 "trustPolicies": [ 278 { 279 "name": "notation-sign-test-experimental", 280 "registryScopes": [ "*" ], 281 "signatureVerification": { 282 "level" : "strict" 283 }, 284 "trustStores": [ "ca:notation-sign-test-experimental" ], 285 "trustedIdentities": [ 286 "*" 287 ] 288 } 289 ] 290 } 291 EOF 292 293 export NOTATION_EXPERIMENTAL=1 294 run notation sign --allow-referrers-api --key "notation-sign-test-experimental" --insecure-registry localhost:${zot_port}/annotations:latest 295 [ "$status" -eq 0 ] 296 run notation verify --allow-referrers-api --insecure-registry localhost:${zot_port}/annotations:latest 297 [ "$status" -eq 0 ] 298 run notation list --allow-referrers-api --insecure-registry localhost:${zot_port}/annotations:latest 299 [ "$status" -eq 0 ] 300 unset NOTATION_EXPERIMENTAL 301 }