Skip to content

Layer invalidated due to directory inclusion within tar #1909

Description

@ZIRAKrezovic

Okay, this is hard to put into words, but I'll try my best

To define a directory inclusion I'll use GNU Tar examples

$ mkdir gnutar
$ cd gnutar
$ touch simple.txt
$ tar cf - . | tar -tvf -

drwxr-xr-x 0/0       0 2026-03-11 22:24 ./
-rw-r--r-- 0/0       0 2026-03-11 22:24 ./simple.txt

You will notice that there is a root directory within tar itself, aka the first entry. You must also notice that there is a timestamp attached with a directory.

Now lets try something else

$ tar cf - * | tar -tvf -
-rw-r--r-- 0/0       0 2026-03-11 22:24 simple.txt

In this example, there is no root directory, file is stored directly at the root of the archive.

For fun, we can examine another example - tar.gz of latest release as generated by github

$ curl -sLo - https://github.com/fabric8io/docker-maven-plugin/archive/refs/tags/v0.48.1.tar.gz | tar -tzvf - | head -n5
drwxrwxr-x root/root         0 2026-02-07 18:47 docker-maven-plugin-0.48.1/
-rw-rw-r-- root/root       195 2026-02-07 18:47 docker-maven-plugin-0.48.1/.codecov.yml
-rw-rw-r-- root/root        85 2026-02-07 18:47 docker-maven-plugin-0.48.1/.gitattributes
drwxrwxr-x root/root         0 2026-02-07 18:47 docker-maven-plugin-0.48.1/.github/
-rw-rw-r-- root/root       484 2026-02-07 18:47 docker-maven-plugin-0.48.1/.github/ISSUE_TEMPLATE.md

There's no "./" in here either.

This brings us to the problem in D-M-P

Consider I define an assembly on a directory that is created by copying file (in the example, I'll use simple resources copied by maven plugin)

In the example below, I have used tar mode to demonstrate changed sha256sum that causes the layer invalidation

<assembly>
    <name>src-asset2</name>
    <targetDir>/src/asset2</targetDir>
    <mode>tar</mode>
    <inline>
        <fileSets>
            <fileSet>
                <directory>${project.basedir}/src/main/resources/asset2/</directory>
                <outputDirectory>.</outputDirectory>
            </fileSet>
        </fileSets>
    </inline>
</assembly>
<assembly>
    <name>tgt-asset2</name>
    <targetDir>/tgt/asset2</targetDir>
    <mode>tar</mode>
    <inline>
        <fileSets>
            <fileSet>
                <directory>${project.build.outputDirectory}/asset2/</directory>
                <outputDirectory>.</outputDirectory>
            </fileSet>
        </fileSets>
    </inline>
</assembly>

Directory state is as follows, before copying

$ ls -la src/main/resources/asset2/
total 1
drwxr-xr-x 1 0 0  0 Mar 11 21:28 ./
drwxr-xr-x 1 0 0  0 Mar 11 22:08 ../
-rw-r--r-- 1 0 0 24 Mar 11 21:29 example2.txt

Copied files are as follows

$ ls -la target/classes/asset2/
total 1
drwxr-xr-x 1 0 0  0 Mar 11 22:17 ./
drwxr-xr-x 1 0 0  0 Mar 11 22:17 ../
-rw-r--r-- 1 0 0 24 Mar 11 21:29 example2.txt

Which is expected, since resources plugin has to create target directories before copying files.

Lets now run D-M-P and examine tars created.

$ tar -tvf target/docker/layer-test/latest/build/src-asset2.tar
drwxr-xr-x 0/0 0 2026-03-11 21:28 ./
-rw-r--r-- 0/0 24 2026-03-11 21:29 ./example2.txt
$ sha256sum target/docker/layer-test/latest/build/src-asset2.tar
984c444d3d2db5742a5f7127dc0e2fccc30f5b413e373ee92b0e44442ea41bbc *target/docker/layer-test/latest/build/src-asset2.tar
$ tar -tvf target/docker/layer-test/latest/build/tgt-asset2.tar
drwxr-xr-x 0/0 0 2026-03-11 22:32 ./
-rw-r--r-- 0/0 24 2026-03-11 21:29 ./example2.txt
$ sha256sum target/docker/layer-test/latest/build/tgt-asset2.tar
5e168f1ac3833cd9522bce7cf0c6bb9423a61cb8dc864a18608ba63a341c69d3 *target/docker/layer-test/latest/build/tgt-asset2.tar

Second run, asset within the src folder remains the same, however same is not true (obviously) for second asset

$ tar -tvf target/docker/layer-test/latest/build/tgt-asset2.tar
drwxr-xr-x 0/0 0 2026-03-11 22:36 ./
-rw-r--r-- 0/0 24 2026-03-11 21:29 ./example2.txt
$ sha256sum target/docker/layer-test/latest/build/tgt-asset2.tar
0c7828aa91c34866a4a845a5e1abc2239de762376565a2fcf4c218fdd0619ee1 *target/docker/layer-test/latest/build/tgt-asset2.tar

As you can see, the layer that was supposed to have same file copied over - the file that was not modified in any regard - has its sha256sum changed because it includes ./ whose timestamp changes on every run.

It is the same with the directory mode. It always creates a different layer since it uses COPY /directory and not COPY /directory/* to copy files, transferring the timestamp of the owning directories as well.

You can find the full example here https://github.com/ZIRAKrezovic/dmp-layers

I would appreciate any help on how to handle this scenario. We have an artifact that gets downloaded by another maven plugin and extracted into target/, and its parent directory is always "current". Using assembly with them always results in layer invalidation as demonstrated above.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions