github.com/opensuse/umoci@v0.4.2/test/unpack.bats (about) 1 #!/usr/bin/env bats -t 2 # umoci: Umoci Modifies Open Containers' Images 3 # Copyright (C) 2016, 2017, 2018 SUSE LLC. 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 load helpers 18 19 function setup() { 20 setup_image 21 } 22 23 function teardown() { 24 teardown_tmpdirs 25 teardown_image 26 } 27 28 @test "umoci unpack" { 29 # Unpack the image. 30 new_bundle_rootfs 31 umoci unpack --image "${IMAGE}:${TAG}" "$BUNDLE" 32 [ "$status" -eq 0 ] 33 bundle-verify "$BUNDLE" 34 35 # We need to make sure these files properly exist. 36 [ -f "$BUNDLE/config.json" ] 37 [ -d "$ROOTFS" ] 38 39 # Check that the image appears about right. 40 # NOTE: Since we could be using different images, this will be fairly 41 # generic. 42 [ -e "$ROOTFS/bin/sh" ] 43 [ -e "$ROOTFS/etc/passwd" ] 44 [ -e "$ROOTFS/etc/group" ] 45 46 # Ensure that gomtree suceeds on the unpacked bundle. 47 gomtree -p "$ROOTFS" -f "$BUNDLE"/sha256_*.mtree 48 [ "$status" -eq 0 ] 49 [ -z "$output" ] 50 51 # Make sure that unpack fails without a bundle path. 52 umoci unpack --image "${IMAGE}:${TAG}" 53 [ "$status" -ne 0 ] 54 # ... or with too many 55 umoci unpack --image "${IMAGE}:${TAG}" too many arguments 56 [ "$status" -ne 0 ] 57 ! [ -d too ] 58 ! [ -d many ] 59 ! [ -d arguments ] 60 61 image-verify "${IMAGE}" 62 } 63 64 @test "umoci unpack [missing args]" { 65 umoci unpack --image="${IMAGE}:${TAG}" 66 [ "$status" -ne 0 ] 67 68 new_bundle_rootfs 69 umoci unpack "$BUNDLE" 70 [ "$status" -ne 0 ] 71 } 72 73 @test "umoci unpack [config.json contains mount namespace]" { 74 # Unpack the image. 75 new_bundle_rootfs 76 umoci unpack --image "${IMAGE}:${TAG}" "$BUNDLE" 77 [ "$status" -eq 0 ] 78 bundle-verify "$BUNDLE" 79 80 # Ensure that we have a mount namespace enabled. 81 sane_run jq -SM 'any(.linux.namespaces[] | .type; . == "mount")' "$BUNDLE/config.json" 82 [ "$status" -eq 0 ] 83 [[ "$output" == "true" ]] 84 85 image-verify "${IMAGE}" 86 } 87 88 @test "umoci unpack [consistent results]" { 89 # Unpack the image. 90 new_bundle_rootfs && BUNDLE_A="$BUNDLE" ROOTFS_A="$ROOTFS" 91 umoci unpack --image "${IMAGE}:${TAG}" "$BUNDLE" 92 [ "$status" -eq 0 ] 93 bundle-verify "$BUNDLE" 94 95 # Wait a beat. 96 sleep 5s 97 98 # Unpack it again. 99 new_bundle_rootfs && BUNDLE_B="$BUNDLE" ROOTFS_B="$ROOTFS" 100 umoci unpack --image "${IMAGE}:${TAG}" "$BUNDLE" 101 [ "$status" -eq 0 ] 102 bundle-verify "$BUNDLE" 103 104 # Ensure that gomtree cross-succeeds. 105 gomtree -p "$ROOTFS_A" -f "$BUNDLE_B"/sha256_*.mtree 106 [ "$status" -eq 0 ] 107 [ -z "$output" ] 108 gomtree -p "$ROOTFS_B" -f "$BUNDLE_A"/sha256_*.mtree 109 [ "$status" -eq 0 ] 110 [ -z "$output" ] 111 112 image-verify "${IMAGE}" 113 } 114 115 @test "umoci unpack [setuid]" { 116 # Unpack the image. 117 new_bundle_rootfs 118 umoci unpack --image "${IMAGE}:${TAG}" "$BUNDLE" 119 [ "$status" -eq 0 ] 120 bundle-verify "$BUNDLE" 121 122 # Make some files setuid and setgid. 123 touch "$ROOTFS/setuid" && chmod u+xs "$ROOTFS/setuid" 124 touch "$ROOTFS/setgid" && chmod g+xs "$ROOTFS/setgid" 125 touch "$ROOTFS/setugid" && chmod ug+xs "$ROOTFS/setugid" 126 127 # Repack the image. 128 umoci repack --image "${IMAGE}:${TAG}" "$BUNDLE" 129 [ "$status" -eq 0 ] 130 image-verify "${IMAGE}" 131 132 # Unpack the image. 133 new_bundle_rootfs 134 umoci unpack --image "${IMAGE}:${TAG}" "$BUNDLE" 135 [ "$status" -eq 0 ] 136 bundle-verify "$BUNDLE" 137 138 # Check that the set{uid,gid} bits were preserved. 139 [ -u "$ROOTFS/setuid" ] 140 [ -g "$ROOTFS/setgid" ] 141 [ -u "$ROOTFS/setugid" ] && [ -g "$ROOTFS/setugid" ] 142 143 image-verify "${IMAGE}" 144 } 145 146 @test "umoci unpack [setcap]" { 147 # We need to setcap which requires root on quite a few kernels -- and we 148 # don't support v3 capabilities yet (which allow us as an unprivileged user 149 # to write capabilities). 150 requires root 151 152 # Unpack the image. 153 new_bundle_rootfs 154 umoci unpack --image "${IMAGE}:${TAG}" "$BUNDLE" 155 [ "$status" -eq 0 ] 156 bundle-verify "$BUNDLE" 157 158 # Make some files setuid and setgid. 159 touch "$ROOTFS/setcap1" && setcap "cap_net_raw+eip" "$ROOTFS/setcap1" 160 touch "$ROOTFS/setcap2" && setcap "cap_sys_admin,cap_setfcap+eip" "$ROOTFS/setcap2" 161 162 # Repack the image. 163 umoci repack --image "${IMAGE}:${TAG}" "$BUNDLE" 164 [ "$status" -eq 0 ] 165 image-verify "${IMAGE}" 166 167 # Unpack the image (as root). 168 new_bundle_rootfs 169 umoci unpack --image "${IMAGE}:${TAG}" "$BUNDLE" 170 [ "$status" -eq 0 ] 171 bundle-verify "$BUNDLE" 172 173 # Ensure that the capability bits were preserved. 174 sane_run getcap "$ROOTFS/setcap1" 175 [ "$status" -eq 0 ] 176 [[ "$output" == *" = cap_net_raw+eip"* ]] 177 sane_run getcap "$ROOTFS/setcap2" 178 [ "$status" -eq 0 ] 179 [[ "$output" == *" = cap_sys_admin,cap_setfcap"* ]] 180 181 # Unpack the image (as rootless). 182 new_bundle_rootfs 183 umoci unpack --rootless --image "${IMAGE}:${TAG}" "$BUNDLE" 184 [ "$status" -eq 0 ] 185 bundle-verify "$BUNDLE" 186 187 # TODO: Actually set capabilities as an unprivileged user and then test 188 # that the correct v3 capabilities were set. 189 190 image-verify "${IMAGE}" 191 } 192 193 @test "umoci unpack [mknod]" { 194 # We need to mknod which requires root on most kernels. Since Linux 4.18 it's 195 # been possible for unprivileged users to mknod(2) but we can't use that here 196 # (it requires owning the filesystem's superblock). 197 requires root 198 199 # Unpack the image. 200 new_bundle_rootfs 201 umoci unpack --image "${IMAGE}:${TAG}" "$BUNDLE" 202 [ "$status" -eq 0 ] 203 bundle-verify "$BUNDLE" 204 205 # Make some mknod. 206 mknod "$ROOTFS/block1" b 128 42 # 80:2a 61a4 207 mknod "$ROOTFS/block2" b 255 128 # ff:80 61a4 208 mknod "$ROOTFS/char1" c 133 37 # 85:25 21a4 209 mknod "$ROOTFS/char2" c 253 97 # fd:61 21a4 210 mkfifo "$ROOTFS/fifo" 211 212 # Repack the image. 213 umoci repack --image "${IMAGE}:${TAG}" "$BUNDLE" 214 [ "$status" -eq 0 ] 215 image-verify "${IMAGE}" 216 217 # Unpack the image (as root). 218 new_bundle_rootfs 219 umoci unpack --image "${IMAGE}:${TAG}" "$BUNDLE" 220 [ "$status" -eq 0 ] 221 bundle-verify "$BUNDLE" 222 223 # Check that all of the bits were preserved. 224 [ -b "$ROOTFS/block1" ] 225 [[ "$(stat -c '%t:%T' "$ROOTFS/block1")" == *"80:2a"* ]] 226 [ -b "$ROOTFS/block2" ] 227 [[ "$(stat -c '%t:%T' "$ROOTFS/block2")" == *"ff:80"* ]] 228 [ -c "$ROOTFS/char1" ] 229 [[ "$(stat -c '%t:%T' "$ROOTFS/char1")" == *"85:25"* ]] 230 [ -c "$ROOTFS/char2" ] 231 [[ "$(stat -c '%t:%T' "$ROOTFS/char2")" == *"fd:61"* ]] 232 [ -p "$ROOTFS/fifo" ] 233 234 # Unpack the image (as rootless). 235 new_bundle_rootfs 236 umoci unpack --rootless --image "${IMAGE}:${TAG}" "$BUNDLE" 237 [ "$status" -eq 0 ] 238 bundle-verify "$BUNDLE" 239 240 # At the least, check that the files exist. 241 [ -e "$ROOTFS/block1" ] 242 [ -e "$ROOTFS/block2" ] 243 [ -e "$ROOTFS/char1" ] 244 [ -e "$ROOTFS/char2" ] 245 # But the FIFOs should be preserved. 246 [ -p "$ROOTFS/fifo" ] 247 248 image-verify "${IMAGE}" 249 } 250 251 @test "umoci unpack --keep-dirlinks" { 252 # Unpack the image. 253 new_bundle_rootfs 254 umoci unpack --image "${IMAGE}:${TAG}" "$BUNDLE" 255 [ "$status" -eq 0 ] 256 bundle-verify "$BUNDLE" 257 258 # Create some links for us to play with in the next layer. 259 mkdir "$ROOTFS/dir" 260 touch "$ROOTFS/dir/a" 261 ln -s dir "$ROOTFS/link" 262 ln -s link "$ROOTFS/link2" 263 ln -s loop2 "$ROOTFS/loop1" 264 ln -s loop3 "$ROOTFS/loop2" 265 ln -s link2/loop4 "$ROOTFS/loop3" 266 ln -s ../loop1 "$ROOTFS/dir/loop4" 267 chmod 000 "$ROOTFS/dir" 268 269 # Repack the image. 270 umoci repack --refresh-bundle --image "${IMAGE}:${TAG}" "$BUNDLE" 271 [ "$status" -eq 0 ] 272 image-verify "$IMAGE" 273 274 # Create a fake rootfs which contains entries inside symlinks. 275 ROOTFS="$(setup_tmpdir)" 276 mkdir "$ROOTFS/link" # == /dir 277 touch "$ROOTFS/link/b" 278 mkdir "$ROOTFS/link2" # == /link == /dir 279 touch "$ROOTFS/link2/c" 280 mkdir "$ROOTFS/loop1" # == /loop{1..4} ... (symlink loop) 281 touch "$ROOTFS/loop1/broken" 282 sane_run tar cvfC "$BATS_TMPDIR/layer1.tar" "$ROOTFS" . 283 [ "$status" -eq 0 ] 284 285 # Insert our fake layer manually. 286 umoci raw add-layer --image "${IMAGE}:${TAG}" "$BATS_TMPDIR/layer1.tar" 287 [ "$status" -eq 0 ] 288 image-verify "${IMAGE}" 289 290 # Unpack our weird image. 291 new_bundle_rootfs 292 umoci unpack --keep-dirlinks --image "${IMAGE}:${TAG}" "$BUNDLE" 293 [ "$status" -eq 0 ] 294 bundle-verify "$BUNDLE" 295 296 # Resolution of links without destroying the links themselves. 297 chmod 755 "$ROOTFS/dir" 298 [ -f "$ROOTFS/dir/a" ] 299 [ -f "$ROOTFS/dir/b" ] 300 [ -f "$ROOTFS/dir/c" ] 301 [ -L "$ROOTFS/link" ] 302 [ -L "$ROOTFS/link2" ] 303 [ "$(readlink "$ROOTFS/link")" = "dir" ] 304 [ "$(readlink "$ROOTFS/link2")" = "link" ] 305 # ... but symlink loops have to be broken. 306 [ -d "$ROOTFS/loop1" ] 307 [ -f "$ROOTFS/loop1/broken" ] 308 [ -L "$ROOTFS/loop2" ] 309 [ -L "$ROOTFS/loop3" ] 310 [ -L "$ROOTFS/dir/loop4" ] 311 [ "$(readlink "$ROOTFS/loop2")" = "loop3" ] 312 [ "$(readlink "$ROOTFS/loop3")" = "link2/loop4" ] 313 [ "$(readlink "$ROOTFS/dir/loop4")" = "../loop1" ] 314 }