#!/usr/bin/env bash # # Download an OCI image with both docker-pull and oci-unpack, and compare the # tarball from docker-export with the unpacked image. set -euo pipefail if [ $# -ne 1 ] then echo "Usage: $0 " exit 1 fi REFERENCE=$1 CONTAINER_ID="" WORKDIR=$(mktemp -d) run() { ( set -x ; "$@" ) } cleanup() { rm -fr "$WORKDIR" if [ -n "$CONTAINER_ID" ] then docker rm --force "$CONTAINER_ID" > /dev/null fi } trap cleanup EXIT # Dependencies. for dep in docker jq mtree unpack do if ! type -P $dep > /dev/null then printf '%s: not found.\n' "$dep" exit 1 fi done # Pull the image to the local Docker. run docker pull --quiet "$REFERENCE" # Unpack it. run unpack "$REFERENCE" "$WORKDIR/unpack" # Create a container that just delete `/dev`. Some (very old) images # includes block/character devices, but oci-unpack does not support it. CONTAINER_ID=$(run docker create "$REFERENCE") # Extract container contents. mkdir "$WORKDIR/docker" run docker export "$CONTAINER_ID" \ | tar -C "$WORKDIR/docker" --numeric-owner -x # Create a directory specification from the tarball. keywords=( uid gid mode size type link nlink sha256 ) cd "$WORKDIR/docker" # Force the mtime for directories touched by docker-create. for path in . etc do unpack_path="$WORKDIR/unpack/rootfs/$path" if [ -d "$unpack_path" ] then touch -r "$path" "$unpack_path" fi done # Exclude files modified by docker-create. # # Ref: https://github.com/moby/moby/blob/v27.3.1/daemon/initlayer/setup_unix.go#L23-L33 exclude=( ./.dockerenv ./dev ./etc/hostname ./etc/hosts ./etc/mtab ./etc/resolv.conf ./proc ./sys ) run mtree \ -c > "$WORKDIR/mtree" \ -X <(printf '%s\n' "${exclude[@]}") \ -K "$(printf %s, "${keywords[@]}")" # Validate the specification. run mtree \ -p "$WORKDIR/unpack/rootfs" \ -X <(printf '%s\n' "${exclude[@]}") \ -f "$WORKDIR/mtree"