diff --git a/pkg/util/tar_util.go b/pkg/util/tar_util.go index 7703ff5050..fc114fee17 100644 --- a/pkg/util/tar_util.go +++ b/pkg/util/tar_util.go @@ -97,6 +97,8 @@ func (t *Tar) AddFileToTar(p string) error { // this makes this layer unnecessarily differ from a cached layer which does contain this information hdr.Uname = "" hdr.Gname = "" + // use PAX format to preserve accurate mtime (match Docker behavior) + hdr.Format = tar.FormatPAX hardlink, linkDst := t.checkHardlink(p, i) if hardlink { diff --git a/pkg/util/tar_util_test.go b/pkg/util/tar_util_test.go index e0c1becac6..16dd055f92 100644 --- a/pkg/util/tar_util_test.go +++ b/pkg/util/tar_util_test.go @@ -17,12 +17,15 @@ limitations under the License. package util import ( + "archive/tar" + "bytes" "compress/gzip" "io" "io/ioutil" "os" "path/filepath" "testing" + "time" "github.com/GoogleContainerTools/kaniko/testutil" ) @@ -57,6 +60,39 @@ func Test_IsLocalTarArchive(t *testing.T) { } } +func Test_AddFileToTar(t *testing.T) { + testDir, err := ioutil.TempDir("", "") + if err != nil { + t.Fatalf("err setting up temp dir: %v", err) + } + defer os.RemoveAll(testDir) + + path := filepath.Join(testDir, regularFiles[0]) + if err := ioutil.WriteFile(path, []byte("hello"), os.ModePerm); err != nil { + t.Fatal(err) + } + // use a pre-determined time with non-zero microseconds to avoid flakiness + mtime := time.UnixMicro(1635533172891395) + if err := os.Chtimes(path, mtime, mtime); err != nil { + t.Fatal(err) + } + + buf := new(bytes.Buffer) + tarw := NewTar(buf) + if err := tarw.AddFileToTar(path); err != nil { + t.Fatal(err) + } + tarw.Close() + + // Check that the mtime is correct (#1808) + tarReader := tar.NewReader(buf) + hdr, err := tarReader.Next() + if err != nil { + t.Fatal(err) + } + testutil.CheckDeepEqual(t, mtime, hdr.ModTime) +} + func setUpFilesAndTars(testDir string) error { regularFilesAndContents := map[string]string{ regularFiles[0]: "",