diff --git a/container.go b/container.go index 5f0684640a..ecf0186305 100644 --- a/container.go +++ b/container.go @@ -65,21 +65,23 @@ type Container interface { // ImageBuildInfo defines what is needed to build an image type ImageBuildInfo interface { - GetContext() (io.Reader, error) // the path to the build context - GetDockerfile() string // the relative path to the Dockerfile, including the fileitself - ShouldPrintBuildLog() bool // allow build log to be printed to stdout - ShouldBuildImage() bool // return true if the image needs to be built - GetBuildArgs() map[string]*string // return the environment args used to build the from Dockerfile + GetContext() (io.Reader, error) // the path to the build context + GetDockerfile() string // the relative path to the Dockerfile, including the fileitself + ShouldPrintBuildLog() bool // allow build log to be printed to stdout + ShouldBuildImage() bool // return true if the image needs to be built + GetBuildArgs() map[string]*string // return the environment args used to build the from Dockerfile + GetAuthConfigs() map[string]types.AuthConfig // return the auth configs to be able to pull from an authenticated docker registry } // FromDockerfile represents the parameters needed to build an image from a Dockerfile // rather than using a pre-built one type FromDockerfile struct { - Context string // the path to the context of of the docker build - ContextArchive io.Reader // the tar archive file to send to docker that contains the build context - Dockerfile string // the path from the context to the Dockerfile for the image, defaults to "Dockerfile" - BuildArgs map[string]*string // enable user to pass build args to docker daemon - PrintBuildLog bool // enable user to print build log + Context string // the path to the context of of the docker build + ContextArchive io.Reader // the tar archive file to send to docker that contains the build context + Dockerfile string // the path from the context to the Dockerfile for the image, defaults to "Dockerfile" + BuildArgs map[string]*string // enable user to pass build args to docker daemon + PrintBuildLog bool // enable user to print build log + AuthConfigs map[string]types.AuthConfig // enable auth configs to be able to pull from an authenticated docker registry } type ContainerFile struct { @@ -230,6 +232,11 @@ func (c *ContainerRequest) GetDockerfile() string { return f } +// GetAuthConfigs returns the auth configs to be able to pull from an authenticated docker registry +func (c *ContainerRequest) GetAuthConfigs() map[string]types.AuthConfig { + return c.FromDockerfile.AuthConfigs +} + func (c *ContainerRequest) ShouldBuildImage() bool { return c.FromDockerfile.Context != "" || c.FromDockerfile.ContextArchive != nil } diff --git a/container_test.go b/container_test.go index 88953d21bc..b8cc1329e8 100644 --- a/container_test.go +++ b/container_test.go @@ -12,6 +12,7 @@ import ( "testing" "time" + "github.com/docker/docker/api/types" "github.com/stretchr/testify/assert" "github.com/testcontainers/testcontainers-go/wait" @@ -127,6 +128,50 @@ func Test_GetDockerfile(t *testing.T) { } } +func Test_GetAuthConfigs(t *testing.T) { + type TestCase struct { + name string + ExpectedAuthConfigs map[string]types.AuthConfig + ContainerRequest ContainerRequest + } + + testTable := []TestCase{ + { + name: "defaults to no auth", + ExpectedAuthConfigs: nil, + ContainerRequest: ContainerRequest{ + FromDockerfile: FromDockerfile{}, + }, + }, + { + name: "will specify credentials", + ExpectedAuthConfigs: map[string]types.AuthConfig{ + "https://myregistry.com/": { + Username: "username", + Password: "password", + }, + }, + ContainerRequest: ContainerRequest{ + FromDockerfile: FromDockerfile{ + AuthConfigs: map[string]types.AuthConfig{ + "https://myregistry.com/": { + Username: "username", + Password: "password", + }, + }, + }, + }, + }, + } + + for _, testCase := range testTable { + t.Run(testCase.name, func(t *testing.T) { + cfgs := testCase.ContainerRequest.GetAuthConfigs() + assert.Equal(t, testCase.ExpectedAuthConfigs, cfgs) + }) + } +} + func Test_BuildImageWithContexts(t *testing.T) { type TestCase struct { Name string diff --git a/docker.go b/docker.go index 80c4e63c63..1e1e5ba697 100644 --- a/docker.go +++ b/docker.go @@ -879,6 +879,7 @@ func (p *DockerProvider) BuildImage(ctx context.Context, img ImageBuildInfo) (st buildOptions := types.ImageBuildOptions{ BuildArgs: img.GetBuildArgs(), Dockerfile: img.GetDockerfile(), + AuthConfigs: img.GetAuthConfigs(), Context: buildContext, Tags: []string{repoTag}, Remove: true, diff --git a/docker_test.go b/docker_test.go index 9714cf4f49..c8f5e58fe1 100644 --- a/docker_test.go +++ b/docker_test.go @@ -43,6 +43,7 @@ const ( nginxAlpineImage = "docker.io/nginx:alpine" nginxDefaultPort = "80/tcp" nginxHighPort = "8080/tcp" + daemonMaxVersion = "1.41" ) var providerType = ProviderDocker @@ -1033,8 +1034,129 @@ func Test_BuildContainerFromDockerfile(t *testing.T) { WaitingFor: wait.ForLog("Ready to accept connections"), } - t.Log("creating generic container request from container request") + redisC, err := prepareRedisImage(ctx, req, t) + require.NoError(t, err) + terminateContainerOnEnd(t, ctx, redisC) + + checkSuccessfulRedisImage(ctx, redisC, t) +} + +func Test_BuildContainerFromDockerfileWithAuthConfig_ShouldSucceedWithAuthConfigs(t *testing.T) { + prepareLocalRegistryWithAuth(t) + defer func() { + ctx := context.Background() + testcontainersClient, err := client.NewClientWithOpts(client.WithVersion(daemonMaxVersion)) + if err != nil { + t.Log("could not create client to cleanup registry: ", err) + } + + _, err = testcontainersClient.ImageRemove(ctx, "localhost:5000/redis:5.0-alpine", types.ImageRemoveOptions{ + Force: true, + PruneChildren: true, + }) + if err != nil { + t.Log("could not remove image: ", err) + } + + }() + + t.Log("getting context") + ctx := context.Background() + t.Log("got context, creating container request") + req := ContainerRequest{ + FromDockerfile: FromDockerfile{ + Context: "./testresources", + Dockerfile: "auth.Dockerfile", + AuthConfigs: map[string]types.AuthConfig{ + "localhost:5000": { + Username: "testuser", + Password: "testpassword", + }, + }, + }, + + ExposedPorts: []string{"6379/tcp"}, + WaitingFor: wait.ForLog("Ready to accept connections"), + } + + redisC, err := prepareRedisImage(ctx, req, t) + require.NoError(t, err) + terminateContainerOnEnd(t, ctx, redisC) + + checkSuccessfulRedisImage(ctx, redisC, t) +} + +func Test_BuildContainerFromDockerfileWithAuthConfig_ShouldFailWithoutAuthConfigs(t *testing.T) { + prepareLocalRegistryWithAuth(t) + + t.Log("getting context") + ctx := context.Background() + t.Log("got context, creating container request") + req := ContainerRequest{ + FromDockerfile: FromDockerfile{ + Context: "./testresources", + Dockerfile: "auth.Dockerfile", + }, + ExposedPorts: []string{"6379/tcp"}, + WaitingFor: wait.ForLog("Ready to accept connections"), + } + + redisC, err := prepareRedisImage(ctx, req, t) + require.Error(t, err) + terminateContainerOnEnd(t, ctx, redisC) +} + +func prepareLocalRegistryWithAuth(t *testing.T) { + ctx := context.Background() + wd, err := os.Getwd() + assert.NoError(t, err) + req := ContainerRequest{ + Image: "registry:2", + ExposedPorts: []string{"5000:5000/tcp"}, + Env: map[string]string{ + "REGISTRY_AUTH": "htpasswd", + "REGISTRY_AUTH_HTPASSWD_REALM": "Registry", + "REGISTRY_AUTH_HTPASSWD_PATH": "/auth/htpasswd", + "REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY": "/data", + }, + Mounts: ContainerMounts{ + ContainerMount{ + Source: GenericBindMountSource{ + HostPath: fmt.Sprintf("%s/testresources/auth", wd), + }, + Target: "/auth", + }, + ContainerMount{ + Source: GenericBindMountSource{ + HostPath: fmt.Sprintf("%s/testresources/data", wd), + }, + Target: "/data", + }, + }, + WaitingFor: wait.ForExposedPort(), + } + + genContainerReq := GenericContainerRequest{ + ProviderType: providerType, + ContainerRequest: req, + Started: true, + } + + t.Log("creating registry container") + + registryC, err := GenericContainer(ctx, genContainerReq) + assert.NoError(t, err) + + t.Cleanup(func() { + assert.NoError(t, registryC.Terminate(context.Background())) + }) + + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) +} + +func prepareRedisImage(ctx context.Context, req ContainerRequest, t *testing.T) (Container, error) { genContainerReq := GenericContainerRequest{ ProviderType: providerType, ContainerRequest: req, @@ -1044,11 +1166,15 @@ func Test_BuildContainerFromDockerfile(t *testing.T) { t.Log("creating redis container") redisC, err := GenericContainer(ctx, genContainerReq) - require.NoError(t, err) - terminateContainerOnEnd(t, ctx, redisC) t.Log("created redis container") + return redisC, err +} + +func checkSuccessfulRedisImage(ctx context.Context, redisC Container, t *testing.T) { + t.Log("created redis container") + t.Log("getting redis container endpoint") endpoint, err := redisC.Endpoint(ctx, "") if err != nil { @@ -1057,12 +1183,12 @@ func Test_BuildContainerFromDockerfile(t *testing.T) { t.Log("retrieved redis container endpoint") - client := redis.NewClient(&redis.Options{ + redisClient := redis.NewClient(&redis.Options{ Addr: endpoint, }) t.Log("pinging redis") - pong, err := client.Ping(ctx).Result() + pong, err := redisClient.Ping(ctx).Result() require.NoError(t, err) t.Log("received response from redis") @@ -2437,6 +2563,9 @@ func assertExtractedFiles(t *testing.T, ctx context.Context, container Container require.NoError(t, err) for _, srcFile := range srcFiles { + if srcFile.IsDir() { + continue + } srcBytes, err := ioutil.ReadFile(filepath.Join(hostFilePath, srcFile.Name())) if err != nil { require.NoError(t, err) diff --git a/docs/features/build_from_dockerfile.md b/docs/features/build_from_dockerfile.md index 85068f62c1..5e13c1fd56 100644 --- a/docs/features/build_from_dockerfile.md +++ b/docs/features/build_from_dockerfile.md @@ -60,3 +60,24 @@ fromDockerfile := testcontainers.FromDockerfile{ **Please Note** if you specify a `ContextArchive` this will cause Testcontainers-go to ignore the path passed in to `Context`. + +## Images requiring auth + +If you are building a local Docker image that is fetched from a Docker image in a registry requiring authentication +(e.g., assuming you are fetching from a custom registry such as `myregistry.com`), you will need to specify the +credentials to succeed, as follows: + +```go +req := ContainerRequest{ + FromDockerfile: testcontainers.FromDockerfile{ + Context: "/path/to/build/context", + Dockerfile: "CustomDockerfile", + AuthConfigs: map[string]types.AuthConfig{ + "https://myregistry.com": { + Username: "myusername", + Password: "mypassword", + }, + }, + }, +} +``` \ No newline at end of file diff --git a/file_test.go b/file_test.go index 5b1c130d45..6c176c110a 100644 --- a/file_test.go +++ b/file_test.go @@ -73,6 +73,9 @@ func Test_TarDir(t *testing.T) { } for _, srcFile := range srcFiles { + if srcFile.IsDir() { + continue + } srcBytes, err := ioutil.ReadFile(filepath.Join(src, srcFile.Name())) if err != nil { t.Fatal(err) diff --git a/testresources/auth.Dockerfile b/testresources/auth.Dockerfile new file mode 100644 index 0000000000..270ae9d9e9 --- /dev/null +++ b/testresources/auth.Dockerfile @@ -0,0 +1 @@ +FROM localhost:5000/redis:5.0-alpine \ No newline at end of file diff --git a/testresources/auth/htpasswd b/testresources/auth/htpasswd new file mode 100644 index 0000000000..9a5d4aaff6 --- /dev/null +++ b/testresources/auth/htpasswd @@ -0,0 +1,2 @@ +testuser:$2y$05$tTymaYlWwJOqie.bcSUUN.I.kxmo1m5TLzYQ4/ejJ46UMXGtq78EO + diff --git a/testresources/data/docker/registry/v2/blobs/sha256/21/213ec9aee27d8be045c6a92b7eac22c9a64b44558193775a1a7f626352392b49/data b/testresources/data/docker/registry/v2/blobs/sha256/21/213ec9aee27d8be045c6a92b7eac22c9a64b44558193775a1a7f626352392b49/data new file mode 100644 index 0000000000..caac84b41c Binary files /dev/null and b/testresources/data/docker/registry/v2/blobs/sha256/21/213ec9aee27d8be045c6a92b7eac22c9a64b44558193775a1a7f626352392b49/data differ diff --git a/testresources/data/docker/registry/v2/blobs/sha256/25/2595acf2c0bea71c4135062d027e4cf088b1674b3bb008b2571796491aa662b1/data b/testresources/data/docker/registry/v2/blobs/sha256/25/2595acf2c0bea71c4135062d027e4cf088b1674b3bb008b2571796491aa662b1/data new file mode 100644 index 0000000000..81c85d096f Binary files /dev/null and b/testresources/data/docker/registry/v2/blobs/sha256/25/2595acf2c0bea71c4135062d027e4cf088b1674b3bb008b2571796491aa662b1/data differ diff --git a/testresources/data/docker/registry/v2/blobs/sha256/64/64acd9e2f7c70ed5b56219f5b8949a8cbc67c03f8c51fdb6786bec66eec4476b/data b/testresources/data/docker/registry/v2/blobs/sha256/64/64acd9e2f7c70ed5b56219f5b8949a8cbc67c03f8c51fdb6786bec66eec4476b/data new file mode 100644 index 0000000000..7f2bf8fe86 Binary files /dev/null and b/testresources/data/docker/registry/v2/blobs/sha256/64/64acd9e2f7c70ed5b56219f5b8949a8cbc67c03f8c51fdb6786bec66eec4476b/data differ diff --git a/testresources/data/docker/registry/v2/blobs/sha256/66/662f040a4fc0e397e379a82a7d79663bb26698ae009d674e70b0224c4b155edb/data b/testresources/data/docker/registry/v2/blobs/sha256/66/662f040a4fc0e397e379a82a7d79663bb26698ae009d674e70b0224c4b155edb/data new file mode 100644 index 0000000000..8d34bd5df0 --- /dev/null +++ b/testresources/data/docker/registry/v2/blobs/sha256/66/662f040a4fc0e397e379a82a7d79663bb26698ae009d674e70b0224c4b155edb/data @@ -0,0 +1,41 @@ +{ + "schemaVersion": 2, + "mediaType": "application/vnd.docker.distribution.manifest.v2+json", + "config": { + "mediaType": "application/vnd.docker.container.image.v1+json", + "size": 6320, + "digest": "sha256:960343481690ac146b55e1b704b9685104f1710bd557c7a409c48fdc721929fa" + }, + "layers": [ + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 2806054, + "digest": "sha256:213ec9aee27d8be045c6a92b7eac22c9a64b44558193775a1a7f626352392b49" + }, + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 1271, + "digest": "sha256:fb541f77610a7550755893b11853752742e9b173e4e9967f4db6b02c2e51ce4a" + }, + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 398361, + "digest": "sha256:dc2e3041aaa57579fe87bf26fbb56fcf7aef49b3f5a0e0ee37eab519855dd37e" + }, + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 6444723, + "digest": "sha256:a59c682d8704ef96c5dec2f59481ac24993fb3c25a4a139e22e2db664a34b06a" + }, + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 135, + "digest": "sha256:64acd9e2f7c70ed5b56219f5b8949a8cbc67c03f8c51fdb6786bec66eec4476b" + }, + { + "mediaType": "application/vnd.docker.image.rootfs.diff.tar.gzip", + "size": 580, + "digest": "sha256:2595acf2c0bea71c4135062d027e4cf088b1674b3bb008b2571796491aa662b1" + } + ] +} \ No newline at end of file diff --git a/testresources/data/docker/registry/v2/blobs/sha256/96/960343481690ac146b55e1b704b9685104f1710bd557c7a409c48fdc721929fa/data b/testresources/data/docker/registry/v2/blobs/sha256/96/960343481690ac146b55e1b704b9685104f1710bd557c7a409c48fdc721929fa/data new file mode 100644 index 0000000000..4233a50f51 --- /dev/null +++ b/testresources/data/docker/registry/v2/blobs/sha256/96/960343481690ac146b55e1b704b9685104f1710bd557c7a409c48fdc721929fa/data @@ -0,0 +1 @@ +{"architecture":"amd64","config":{"Hostname":"","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"ExposedPorts":{"6379/tcp":{}},"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","REDIS_VERSION=5.0.14","REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-5.0.14.tar.gz","REDIS_DOWNLOAD_SHA=3ea5024766d983249e80d4aa9457c897a9f079957d0fb1f35682df233f997f32"],"Cmd":["redis-server"],"Image":"sha256:c6b61b4eb28dfbb356b1faf35269891803301551508b1604cf67492e23f58496","Volumes":{"/data":{}},"WorkingDir":"/data","Entrypoint":["docker-entrypoint.sh"],"OnBuild":null,"Labels":null},"container":"3f5209e45fd8d25352646faf4c9ed85bd0f55581859dac5c0b6f71a0f354d59f","container_config":{"Hostname":"3f5209e45fd8","Domainname":"","User":"","AttachStdin":false,"AttachStdout":false,"AttachStderr":false,"ExposedPorts":{"6379/tcp":{}},"Tty":false,"OpenStdin":false,"StdinOnce":false,"Env":["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin","REDIS_VERSION=5.0.14","REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-5.0.14.tar.gz","REDIS_DOWNLOAD_SHA=3ea5024766d983249e80d4aa9457c897a9f079957d0fb1f35682df233f997f32"],"Cmd":["/bin/sh","-c","#(nop) ","CMD [\"redis-server\"]"],"Image":"sha256:c6b61b4eb28dfbb356b1faf35269891803301551508b1604cf67492e23f58496","Volumes":{"/data":{}},"WorkingDir":"/data","Entrypoint":["docker-entrypoint.sh"],"OnBuild":null,"Labels":{}},"created":"2022-10-07T03:33:38.951799853Z","docker_version":"20.10.12","history":[{"created":"2022-08-09T17:19:53.274069586Z","created_by":"/bin/sh -c #(nop) ADD file:2a949686d9886ac7c10582a6c29116fd29d3077d02755e87e111870d63607725 in / "},{"created":"2022-08-09T17:19:53.47374331Z","created_by":"/bin/sh -c #(nop) CMD [\"/bin/sh\"]","empty_layer":true},{"created":"2022-10-07T03:30:17.540132626Z","created_by":"/bin/sh -c addgroup -S -g 1000 redis \u0026\u0026 adduser -S -G redis -u 999 redis"},{"created":"2022-10-07T03:30:18.701947002Z","created_by":"/bin/sh -c apk add --no-cache \t\t'su-exec\u003e=0.2' \t\ttzdata"},{"created":"2022-10-07T03:33:00.969689587Z","created_by":"/bin/sh -c #(nop) ENV REDIS_VERSION=5.0.14","empty_layer":true},{"created":"2022-10-07T03:33:01.061281294Z","created_by":"/bin/sh -c #(nop) ENV REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-5.0.14.tar.gz","empty_layer":true},{"created":"2022-10-07T03:33:01.154686334Z","created_by":"/bin/sh -c #(nop) ENV REDIS_DOWNLOAD_SHA=3ea5024766d983249e80d4aa9457c897a9f079957d0fb1f35682df233f997f32","empty_layer":true},{"created":"2022-10-07T03:33:37.807285887Z","created_by":"/bin/sh -c set -eux; \t\tapk add --no-cache --virtual .build-deps \t\tcoreutils \t\tdpkg-dev dpkg \t\tgcc \t\tlinux-headers \t\tmake \t\tmusl-dev \t\topenssl-dev \t\twget \t; \t\twget -O redis.tar.gz \"$REDIS_DOWNLOAD_URL\"; \techo \"$REDIS_DOWNLOAD_SHA *redis.tar.gz\" | sha256sum -c -; \tmkdir -p /usr/src/redis; \ttar -xzf redis.tar.gz -C /usr/src/redis --strip-components=1; \trm redis.tar.gz; \t\tgrep -q '^#define CONFIG_DEFAULT_PROTECTED_MODE 1$' /usr/src/redis/src/server.h; \tsed -ri 's!^(#define CONFIG_DEFAULT_PROTECTED_MODE) 1$!\\1 0!' /usr/src/redis/src/server.h; \tgrep -q '^#define CONFIG_DEFAULT_PROTECTED_MODE 0$' /usr/src/redis/src/server.h; \t\tgnuArch=\"$(dpkg-architecture --query DEB_BUILD_GNU_TYPE)\"; \textraJemallocConfigureFlags=\"--build=$gnuArch\"; \tdpkgArch=\"$(dpkg --print-architecture)\"; \tcase \"${dpkgArch##*-}\" in \t\tamd64 | i386 | x32) extraJemallocConfigureFlags=\"$extraJemallocConfigureFlags --with-lg-page=12\" ;; \t\t*) extraJemallocConfigureFlags=\"$extraJemallocConfigureFlags --with-lg-page=16\" ;; \tesac; \textraJemallocConfigureFlags=\"$extraJemallocConfigureFlags --with-lg-hugepage=21\"; \tgrep -F 'cd jemalloc \u0026\u0026 ./configure ' /usr/src/redis/deps/Makefile; \tsed -ri 's!cd jemalloc \u0026\u0026 ./configure !\u0026'\"$extraJemallocConfigureFlags\"' !' /usr/src/redis/deps/Makefile; \tgrep -F \"cd jemalloc \u0026\u0026 ./configure $extraJemallocConfigureFlags \" /usr/src/redis/deps/Makefile; \t\tmake -C /usr/src/redis -j \"$(nproc)\" all; \tmake -C /usr/src/redis install; \t\tserverMd5=\"$(md5sum /usr/local/bin/redis-server | cut -d' ' -f1)\"; export serverMd5; \tfind /usr/local/bin/redis* -maxdepth 0 \t\t-type f -not -name redis-server \t\t-exec sh -eux -c ' \t\t\tmd5=\"$(md5sum \"$1\" | cut -d\" \" -f1)\"; \t\t\ttest \"$md5\" = \"$serverMd5\"; \t\t' -- '{}' ';' \t\t-exec ln -svfT 'redis-server' '{}' ';' \t; \t\trm -r /usr/src/redis; \t\trunDeps=\"$( \t\tscanelf --needed --nobanner --format '%n#p' --recursive /usr/local \t\t\t| tr ',' '\\n' \t\t\t| sort -u \t\t\t| awk 'system(\"[ -e /usr/local/lib/\" $1 \" ]\") == 0 { next } { print \"so:\" $1 }' \t)\"; \tapk add --no-network --virtual .redis-rundeps $runDeps; \tapk del --no-network .build-deps; \t\tredis-cli --version; \tredis-server --version"},{"created":"2022-10-07T03:33:38.347225861Z","created_by":"/bin/sh -c mkdir /data \u0026\u0026 chown redis:redis /data"},{"created":"2022-10-07T03:33:38.444090076Z","created_by":"/bin/sh -c #(nop) VOLUME [/data]","empty_layer":true},{"created":"2022-10-07T03:33:38.545951015Z","created_by":"/bin/sh -c #(nop) WORKDIR /data","empty_layer":true},{"created":"2022-10-07T03:33:38.658945137Z","created_by":"/bin/sh -c #(nop) COPY file:a9e7249f657e2eec627bb4be492ad18aae3e5e1f0e47d22644eaf1ef2138c0ce in /usr/local/bin/ "},{"created":"2022-10-07T03:33:38.754618391Z","created_by":"/bin/sh -c #(nop) ENTRYPOINT [\"docker-entrypoint.sh\"]","empty_layer":true},{"created":"2022-10-07T03:33:38.850313099Z","created_by":"/bin/sh -c #(nop) EXPOSE 6379","empty_layer":true},{"created":"2022-10-07T03:33:38.951799853Z","created_by":"/bin/sh -c #(nop) CMD [\"redis-server\"]","empty_layer":true}],"os":"linux","rootfs":{"type":"layers","diff_ids":["sha256:994393dc58e7931862558d06e46aa2bb17487044f670f310dffe1d24e4d1eec7","sha256:6dbd9594c43d4115a12f2e203dfd586ba420dbd75a00d2d6c3feecdeb0048371","sha256:5669106330164180bda406cb49aa2126735bc29065b55354736d2656dffdbb96","sha256:ae23d15ebd31905b77598e96646e2cf46463bf8bd50e3b65c32ded7502402a9e","sha256:82566308f0b016b3848e916f16363ef5329f1fac362347fcb8cb99b1ba9461d7","sha256:beeee888b45e7cbe9e51c618ffe059806875e5570cb5607da75bd9e0b2649a43"]}} \ No newline at end of file diff --git a/testresources/data/docker/registry/v2/blobs/sha256/a5/a59c682d8704ef96c5dec2f59481ac24993fb3c25a4a139e22e2db664a34b06a/data b/testresources/data/docker/registry/v2/blobs/sha256/a5/a59c682d8704ef96c5dec2f59481ac24993fb3c25a4a139e22e2db664a34b06a/data new file mode 100644 index 0000000000..1ac50ad3c7 Binary files /dev/null and b/testresources/data/docker/registry/v2/blobs/sha256/a5/a59c682d8704ef96c5dec2f59481ac24993fb3c25a4a139e22e2db664a34b06a/data differ diff --git a/testresources/data/docker/registry/v2/blobs/sha256/dc/dc2e3041aaa57579fe87bf26fbb56fcf7aef49b3f5a0e0ee37eab519855dd37e/data b/testresources/data/docker/registry/v2/blobs/sha256/dc/dc2e3041aaa57579fe87bf26fbb56fcf7aef49b3f5a0e0ee37eab519855dd37e/data new file mode 100644 index 0000000000..f6708738a6 Binary files /dev/null and b/testresources/data/docker/registry/v2/blobs/sha256/dc/dc2e3041aaa57579fe87bf26fbb56fcf7aef49b3f5a0e0ee37eab519855dd37e/data differ diff --git a/testresources/data/docker/registry/v2/blobs/sha256/fb/fb541f77610a7550755893b11853752742e9b173e4e9967f4db6b02c2e51ce4a/data b/testresources/data/docker/registry/v2/blobs/sha256/fb/fb541f77610a7550755893b11853752742e9b173e4e9967f4db6b02c2e51ce4a/data new file mode 100644 index 0000000000..eca594a3ac Binary files /dev/null and b/testresources/data/docker/registry/v2/blobs/sha256/fb/fb541f77610a7550755893b11853752742e9b173e4e9967f4db6b02c2e51ce4a/data differ diff --git a/testresources/data/docker/registry/v2/repositories/redis/_layers/sha256/213ec9aee27d8be045c6a92b7eac22c9a64b44558193775a1a7f626352392b49/link b/testresources/data/docker/registry/v2/repositories/redis/_layers/sha256/213ec9aee27d8be045c6a92b7eac22c9a64b44558193775a1a7f626352392b49/link new file mode 100644 index 0000000000..a36da7dcd8 --- /dev/null +++ b/testresources/data/docker/registry/v2/repositories/redis/_layers/sha256/213ec9aee27d8be045c6a92b7eac22c9a64b44558193775a1a7f626352392b49/link @@ -0,0 +1 @@ +sha256:213ec9aee27d8be045c6a92b7eac22c9a64b44558193775a1a7f626352392b49 \ No newline at end of file diff --git a/testresources/data/docker/registry/v2/repositories/redis/_layers/sha256/2595acf2c0bea71c4135062d027e4cf088b1674b3bb008b2571796491aa662b1/link b/testresources/data/docker/registry/v2/repositories/redis/_layers/sha256/2595acf2c0bea71c4135062d027e4cf088b1674b3bb008b2571796491aa662b1/link new file mode 100644 index 0000000000..0e19e655c1 --- /dev/null +++ b/testresources/data/docker/registry/v2/repositories/redis/_layers/sha256/2595acf2c0bea71c4135062d027e4cf088b1674b3bb008b2571796491aa662b1/link @@ -0,0 +1 @@ +sha256:2595acf2c0bea71c4135062d027e4cf088b1674b3bb008b2571796491aa662b1 \ No newline at end of file diff --git a/testresources/data/docker/registry/v2/repositories/redis/_layers/sha256/64acd9e2f7c70ed5b56219f5b8949a8cbc67c03f8c51fdb6786bec66eec4476b/link b/testresources/data/docker/registry/v2/repositories/redis/_layers/sha256/64acd9e2f7c70ed5b56219f5b8949a8cbc67c03f8c51fdb6786bec66eec4476b/link new file mode 100644 index 0000000000..8fb2ca14b5 --- /dev/null +++ b/testresources/data/docker/registry/v2/repositories/redis/_layers/sha256/64acd9e2f7c70ed5b56219f5b8949a8cbc67c03f8c51fdb6786bec66eec4476b/link @@ -0,0 +1 @@ +sha256:64acd9e2f7c70ed5b56219f5b8949a8cbc67c03f8c51fdb6786bec66eec4476b \ No newline at end of file diff --git a/testresources/data/docker/registry/v2/repositories/redis/_layers/sha256/960343481690ac146b55e1b704b9685104f1710bd557c7a409c48fdc721929fa/link b/testresources/data/docker/registry/v2/repositories/redis/_layers/sha256/960343481690ac146b55e1b704b9685104f1710bd557c7a409c48fdc721929fa/link new file mode 100644 index 0000000000..ff0826dc7f --- /dev/null +++ b/testresources/data/docker/registry/v2/repositories/redis/_layers/sha256/960343481690ac146b55e1b704b9685104f1710bd557c7a409c48fdc721929fa/link @@ -0,0 +1 @@ +sha256:960343481690ac146b55e1b704b9685104f1710bd557c7a409c48fdc721929fa \ No newline at end of file diff --git a/testresources/data/docker/registry/v2/repositories/redis/_layers/sha256/a59c682d8704ef96c5dec2f59481ac24993fb3c25a4a139e22e2db664a34b06a/link b/testresources/data/docker/registry/v2/repositories/redis/_layers/sha256/a59c682d8704ef96c5dec2f59481ac24993fb3c25a4a139e22e2db664a34b06a/link new file mode 100644 index 0000000000..719dc0acdb --- /dev/null +++ b/testresources/data/docker/registry/v2/repositories/redis/_layers/sha256/a59c682d8704ef96c5dec2f59481ac24993fb3c25a4a139e22e2db664a34b06a/link @@ -0,0 +1 @@ +sha256:a59c682d8704ef96c5dec2f59481ac24993fb3c25a4a139e22e2db664a34b06a \ No newline at end of file diff --git a/testresources/data/docker/registry/v2/repositories/redis/_layers/sha256/dc2e3041aaa57579fe87bf26fbb56fcf7aef49b3f5a0e0ee37eab519855dd37e/link b/testresources/data/docker/registry/v2/repositories/redis/_layers/sha256/dc2e3041aaa57579fe87bf26fbb56fcf7aef49b3f5a0e0ee37eab519855dd37e/link new file mode 100644 index 0000000000..34fb3fb32a --- /dev/null +++ b/testresources/data/docker/registry/v2/repositories/redis/_layers/sha256/dc2e3041aaa57579fe87bf26fbb56fcf7aef49b3f5a0e0ee37eab519855dd37e/link @@ -0,0 +1 @@ +sha256:dc2e3041aaa57579fe87bf26fbb56fcf7aef49b3f5a0e0ee37eab519855dd37e \ No newline at end of file diff --git a/testresources/data/docker/registry/v2/repositories/redis/_layers/sha256/fb541f77610a7550755893b11853752742e9b173e4e9967f4db6b02c2e51ce4a/link b/testresources/data/docker/registry/v2/repositories/redis/_layers/sha256/fb541f77610a7550755893b11853752742e9b173e4e9967f4db6b02c2e51ce4a/link new file mode 100644 index 0000000000..b2cd2f62e0 --- /dev/null +++ b/testresources/data/docker/registry/v2/repositories/redis/_layers/sha256/fb541f77610a7550755893b11853752742e9b173e4e9967f4db6b02c2e51ce4a/link @@ -0,0 +1 @@ +sha256:fb541f77610a7550755893b11853752742e9b173e4e9967f4db6b02c2e51ce4a \ No newline at end of file diff --git a/testresources/data/docker/registry/v2/repositories/redis/_manifests/revisions/sha256/662f040a4fc0e397e379a82a7d79663bb26698ae009d674e70b0224c4b155edb/link b/testresources/data/docker/registry/v2/repositories/redis/_manifests/revisions/sha256/662f040a4fc0e397e379a82a7d79663bb26698ae009d674e70b0224c4b155edb/link new file mode 100644 index 0000000000..58e62086c4 --- /dev/null +++ b/testresources/data/docker/registry/v2/repositories/redis/_manifests/revisions/sha256/662f040a4fc0e397e379a82a7d79663bb26698ae009d674e70b0224c4b155edb/link @@ -0,0 +1 @@ +sha256:662f040a4fc0e397e379a82a7d79663bb26698ae009d674e70b0224c4b155edb \ No newline at end of file diff --git a/testresources/data/docker/registry/v2/repositories/redis/_manifests/tags/5.0-alpine/current/link b/testresources/data/docker/registry/v2/repositories/redis/_manifests/tags/5.0-alpine/current/link new file mode 100644 index 0000000000..58e62086c4 --- /dev/null +++ b/testresources/data/docker/registry/v2/repositories/redis/_manifests/tags/5.0-alpine/current/link @@ -0,0 +1 @@ +sha256:662f040a4fc0e397e379a82a7d79663bb26698ae009d674e70b0224c4b155edb \ No newline at end of file diff --git a/testresources/data/docker/registry/v2/repositories/redis/_manifests/tags/5.0-alpine/index/sha256/662f040a4fc0e397e379a82a7d79663bb26698ae009d674e70b0224c4b155edb/link b/testresources/data/docker/registry/v2/repositories/redis/_manifests/tags/5.0-alpine/index/sha256/662f040a4fc0e397e379a82a7d79663bb26698ae009d674e70b0224c4b155edb/link new file mode 100644 index 0000000000..58e62086c4 --- /dev/null +++ b/testresources/data/docker/registry/v2/repositories/redis/_manifests/tags/5.0-alpine/index/sha256/662f040a4fc0e397e379a82a7d79663bb26698ae009d674e70b0224c4b155edb/link @@ -0,0 +1 @@ +sha256:662f040a4fc0e397e379a82a7d79663bb26698ae009d674e70b0224c4b155edb \ No newline at end of file