diff --git a/Dockerfile b/Dockerfile index 152940030..ae34a91f6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -126,7 +126,8 @@ ARG CGO_ENABLED ENV CGO_ENABLED ${CGO_ENABLED} ENV GOCACHE /.cache/go-build ENV GOMODCACHE /.cache/mod -ENV SOURCE_DATE_EPOCH=0 +ARG SOURCE_DATE_EPOCH +ENV SOURCE_DATE_EPOCH ${SOURCE_DATE_EPOCH} WORKDIR /src # The build-go target creates a container to build Go code with Go modules downloaded and verified. diff --git a/Makefile b/Makefile index 24d14391b..c77c00277 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,7 @@ REGISTRY ?= ghcr.io USERNAME ?= talos-systems SHA ?= $(shell git describe --match=none --always --abbrev=8 --dirty) TAG ?= $(shell git describe --tag --always --dirty --match v[0-9]*) +SOURCE_DATE_EPOCH ?= $(shell git log -1 --pretty=%ct) IMAGE_REGISTRY ?= $(REGISTRY) IMAGE_TAG ?= $(TAG) BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD) @@ -11,7 +12,7 @@ NAME = Talos ARTIFACTS := _out TOOLS ?= ghcr.io/talos-systems/tools:v0.7.0-alpha.0-2-g7172a5d -PKGS ?= v0.7.0-alpha.0-13-g12856ce +PKGS ?= v0.7.0-alpha.0-14-g875c7ec EXTRAS ?= v0.5.0-alpha.0-1-g4957f3c GO_VERSION ?= 1.16 GOFUMPT_VERSION ?= v0.1.0 @@ -84,6 +85,7 @@ COMMON_ARGS += --build-arg=STRINGER_VERSION=$(STRINGER_VERSION) COMMON_ARGS += --build-arg=DEEPCOPY_GEN_VERSION=$(DEEPCOPY_GEN_VERSION) COMMON_ARGS += --build-arg=VTPROTOBUF_VERSION=$(VTPROTOBUF_VERSION) COMMON_ARGS += --build-arg=TAG=$(TAG) +COMMON_ARGS += --build-arg=SOURCE_DATE_EPOCH=$(SOURCE_DATE_EPOCH) COMMON_ARGS += --build-arg=ARTIFACTS=$(ARTIFACTS) COMMON_ARGS += --build-arg=IMPORTVET=$(IMPORTVET) COMMON_ARGS += --build-arg=TESTPKGS=$(TESTPKGS) @@ -230,7 +232,7 @@ iso: ## Builds the ISO and outputs it to the artifact directory. @docker pull $(REGISTRY_AND_USERNAME)/installer:$(TAG) @for platform in $(subst $(,),$(space),$(PLATFORM)); do \ arch=`basename "$${platform}"` ; \ - docker run --rm -i $(REGISTRY_AND_USERNAME)/installer:$(TAG) iso --arch $$arch --tar-to-stdout | tar xz -C $(ARTIFACTS) ; \ + docker run --rm -e SOURCE_DATE_EPOCH=$(SOURCE_DATE_EPOCH) -i $(REGISTRY_AND_USERNAME)/installer:$(TAG) iso --arch $$arch --tar-to-stdout | tar xz -C $(ARTIFACTS) ; \ done .PHONY: boot diff --git a/cmd/installer/cmd/iso.go b/cmd/installer/cmd/iso.go index 0597bdbfa..915913fe4 100644 --- a/cmd/installer/cmd/iso.go +++ b/cmd/installer/cmd/iso.go @@ -100,6 +100,10 @@ func runISOCmd() error { return err } + if err := pkg.TouchFiles("/mnt"); err != nil { + return err + } + log.Println("creating ISO") out := fmt.Sprintf("/tmp/talos-%s.iso", options.Arch) diff --git a/cmd/installer/pkg/epoch.go b/cmd/installer/pkg/epoch.go new file mode 100644 index 000000000..6a4c1caa6 --- /dev/null +++ b/cmd/installer/pkg/epoch.go @@ -0,0 +1,25 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package pkg + +import ( + "os" + "strconv" +) + +// SourceDateEpoch returns parsed value of SOURCE_DATE_EPOCH. +func SourceDateEpoch() (int64, bool, error) { + epoch, ok := os.LookupEnv("SOURCE_DATE_EPOCH") + if !ok { + return 0, false, nil + } + + epochInt, err := strconv.ParseInt(epoch, 10, 64) + if err != nil { + return 0, false, err + } + + return epochInt, true, nil +} diff --git a/cmd/installer/pkg/iso.go b/cmd/installer/pkg/iso.go index 145f4fb78..fbc80daca 100644 --- a/cmd/installer/pkg/iso.go +++ b/cmd/installer/pkg/iso.go @@ -6,19 +6,36 @@ package pkg import ( "fmt" + "os" + "time" "github.com/talos-systems/go-cmd/pkg/cmd" ) // CreateISO creates an iso by invoking the `grub-mkrescue` command. -func CreateISO(iso, dir string) (err error) { - _, err = cmd.Run( - "grub-mkrescue", +func CreateISO(iso, dir string) error { + args := []string{ "--compress=xz", - "--output="+iso, + "--output=" + iso, dir, - ) + } + if epoch, ok, err := SourceDateEpoch(); err != nil { + return err + } else if ok { + // set EFI FAT image serial number + if err := os.Setenv("GRUB_FAT_SERIAL_NUMBER", fmt.Sprintf("%x", uint32(epoch))); err != nil { + return err + } + + args = append(args, + "--", + "-volume_date", "all_file_dates", fmt.Sprintf("=%d", epoch), + "-volume_date", "uuid", time.Unix(epoch, 0).Format("2006010215040500"), + ) + } + + _, err := cmd.Run("grub-mkrescue", args...) if err != nil { return fmt.Errorf("failed to create ISO: %w", err) } diff --git a/cmd/installer/pkg/touch.go b/cmd/installer/pkg/touch.go new file mode 100644 index 000000000..28dd759d1 --- /dev/null +++ b/cmd/installer/pkg/touch.go @@ -0,0 +1,37 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +package pkg + +import ( + "io/fs" + "log" + "os" + "path/filepath" + "time" +) + +// TouchFiles updates mtime for all the files under root if SOURCE_DATE_EPOCH is set. +func TouchFiles(root string) error { + epochInt, ok, err := SourceDateEpoch() + if err != nil { + return err + } + + if !ok { + return nil + } + + timestamp := time.Unix(epochInt, 0) + + log.Printf("changing timestamps under %q to %s", root, timestamp) + + return filepath.WalkDir(root, func(path string, d fs.DirEntry, err error) error { + if err != nil { + return err + } + + return os.Chtimes(path, timestamp, timestamp) + }) +}