diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 20e75e7..09dfd3b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -6,6 +6,7 @@ stages: - lint - rootfs - image + - repro - test - pre-release - release @@ -61,7 +62,7 @@ get_version: stage: rootfs parallel: matrix: - - GROUP: [base, base-devel, multilib-devel] + - GROUP: [base, base-devel, multilib-devel, repro] before_script: - pacman -Syu --noconfirm git make fakechroot fakeroot - pacman -Sdd --noconfirm devtools @@ -98,16 +99,25 @@ rootfs:secure: stage: image parallel: matrix: - - GROUP: [base, base-devel, multilib-devel] + - GROUP: [base, base-devel, multilib-devel, repro] tags: - vm id_tokens: SIGSTORE_ID_TOKEN: aud: sigstore script: - - podman build - -f "$CI_PROJECT_DIR/output/Dockerfile.$GROUP" - -t "$CI_REGISTRY_IMAGE:$GROUP-$CI_COMMIT_REF_SLUG" + - | + if [[ "$GROUP" == "repro" ]]; then + SOURCE_DATE_EPOCH=$(date -u -d "today 00:00:00" +%s) + REPRO_ARGS=( + --source-date-epoch=${SOURCE_DATE_EPOCH} + --rewrite-timestamp + ) + fi + podman build \ + "${REPRO_ARGS[@]}" \ + -f "$CI_PROJECT_DIR/output/Dockerfile.$GROUP" \ + -t "$CI_REGISTRY_IMAGE:$GROUP-$CI_COMMIT_REF_SLUG" \ "$CI_PROJECT_DIR/output" - podman push --sign-by-sigstore=<(sed "s/TEMPLATE_OIDC_ID_TOKEN/${SIGSTORE_ID_TOKEN}/" sigstore-param-file.yaml) "$CI_REGISTRY_IMAGE:$GROUP-$CI_COMMIT_REF_SLUG" @@ -138,6 +148,61 @@ image:build:secure: - podman login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY" - 'echo -e "default-docker:\n use-sigstore-attachments: true" > /etc/containers/registries.d/sigstore.yaml' +.test_repro: + stage: repro + before_script: + - pacman -Syu --noconfirm git make fakechroot fakeroot podman diffoscope diffoci + - pacman -Sdd --noconfirm devtools + script: + - make BUILDDIR="$PWD/repro-build" OUTPUTDIR="$PWD/repro-output" $PWD/repro-output/Dockerfile.repro + - echo "The sha256 hash of the original rootFS is:" + - cat output/repro.tar.zst.SHA256 + - echo "The sha256 hash of the rebuilt rootFS is:" + - cat repro-output/repro.tar.zst.SHA256 + - diffoscope output/repro.tar.zst repro-output/repro.tar.zst + - echo "RootFS is reproducible!" + - | + SOURCE_DATE_EPOCH=$(date -u -d "today 00:00:00" +%s) + podman build \ + --no-cache \ + --source-date-epoch=${SOURCE_DATE_EPOCH} \ + --rewrite-timestamp \ + -f "$CI_PROJECT_DIR/repro-output/Dockerfile.repro" \ + -t "archlinux-docker:repro-$CI_COMMIT_REF_SLUG" \ + "$CI_PROJECT_DIR/repro-output" + - podman pull $CI_REGISTRY_IMAGE:repro-$CI_COMMIT_REF_SLUG + - echo "Digest of the original image is:" + - podman inspect --format '{{.Digest}}' "$CI_REGISTRY_IMAGE:repro-$CI_COMMIT_REF_SLUG" + - echo "Digest of the rebuilt image is:" + - podman inspect --format '{{.Digest}}' "localhost/archlinux-docker:repro-$CI_COMMIT_REF_SLUG" + - diffoci diff --semantic --verbose podman://$CI_REGISTRY_IMAGE:repro-$CI_COMMIT_REF_SLUG podman://localhost/archlinux-docker:repro-$CI_COMMIT_REF_SLUG + - echo "Image is reproducible!" + artifacts: + paths: + - repro-output/* + exclude: + - repro-output/*.tar + expire_in: 2h + +test-repro: + extends: .test_repro + tags: + - vm + except: + - master@archlinux/archlinux-docker + - releases@archlinux/archlinux-docker + - schedules@archlinux/archlinux-docker + - tags@archlinux/archlinux-docker + +test-repro:secure: + extends: .test_repro + tags: + - secure + - vm + only: + - master@archlinux/archlinux-docker + - schedules@archlinux/archlinux-docker + # Build and publish to the Arch Linux group namespaces: # https://hub.docker.com/r/archlinux/archlinux # https://quay.io/repository/archlinux/archlinux @@ -209,6 +274,16 @@ test:base-devel: - test -u /usr/bin/sudo # issue 70 - test -u /usr/bin/passwd +test:repro: + extends: .test + image: $CI_REGISTRY_IMAGE:repro-$CI_COMMIT_REF_SLUG + script: + - pacman-key --init + - pacman-key --populate archlinux + - pacman -Syu --noconfirm arch-repro-status + - arch-repro-status + - *test-script + pre-release: stage: pre-release image: registry.gitlab.com/gitlab-org/release-cli:latest @@ -234,7 +309,7 @@ pre-release: -d "{\"full_description\": $(cat README.md | jq -sR .)}" # Upload rootfs to the Generic Packages Repository - for group in base base-devel multilib-devel; do + for group in base base-devel multilib-devel repro; do rootfs_file="${group}-${BUILD_VERSION}.tar.zst" mv "output/${group}.tar.zst" "output/${rootfs_file}" mv "output/${group}.tar.zst.SHA256" "output/${rootfs_file}.SHA256" @@ -246,7 +321,7 @@ pre-release: done # Create the Dockerfiles, commit to the release branch - for group in base base-devel multilib-devel; do + for group in base base-devel multilib-devel repro; do rootfs_file="${group}-${BUILD_VERSION}.tar.zst" ./scripts/make-dockerfile.sh "${rootfs_file}" "${group}" "output" "curl -sOJL \"${PACKAGE_REGISTRY_URL}/${rootfs_file}\"" "${group}" sed -i "/^COPY ${rootfs_file} \/$/d" output/Dockerfile.${group} @@ -267,6 +342,9 @@ pre-release: --form "actions[][file_path]=Dockerfile.multilib-devel" --form "actions[][content]=> library/archlinux echo "GitCommit: ${BUILD_COMMIT}" >> library/archlinux diff --git a/Dockerfile.template b/Dockerfile.template index 6ecfc3d..4bb2c65 100644 --- a/Dockerfile.template +++ b/Dockerfile.template @@ -37,7 +37,8 @@ LABEL org.opencontainers.image.created="TEMPLATE_CREATED" COPY --from=verify /rootfs/ / RUN ldconfig && \ - sed -i '/BUILD_ID/a VERSION_ID=TEMPLATE_VERSION_ID' /etc/os-release + sed -i '/BUILD_ID/a VERSION_ID=TEMPLATE_VERSION_ID' /etc/os-release && \ + LDCONFIG_AUX_CACHE ENV LANG=C.UTF-8 CMD ["/usr/bin/bash"] diff --git a/Makefile b/Makefile index 86d9c72..45c90a8 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,8 @@ OCITOOL=podman # or docker BUILDDIR=$(shell pwd)/build OUTPUTDIR=$(shell pwd)/output +ARCHIVE_SNAPSHOT=$(shell date -d "-1 day" +"%Y/%m/%d") +SOURCE_DATE_EPOCH=$(shell date -u -d "today 00:00:00" +"%s") .PHONY: clean clean: @@ -8,14 +10,14 @@ clean: .PRECIOUS: $(OUTPUTDIR)/%.tar.zst $(OUTPUTDIR)/%.tar.zst: - scripts/make-rootfs.sh $(*) $(BUILDDIR) $(OUTPUTDIR) + scripts/make-rootfs.sh $(*) $(BUILDDIR) $(OUTPUTDIR) $(ARCHIVE_SNAPSHOT) $(SOURCE_DATE_EPOCH) .PRECIOUS: $(OUTPUTDIR)/Dockerfile.% $(OUTPUTDIR)/Dockerfile.%: $(OUTPUTDIR)/%.tar.zst - scripts/make-dockerfile.sh "$(*).tar.zst" $(*) $(OUTPUTDIR) "true" "Dev" + scripts/make-dockerfile.sh "$(*).tar.zst" $(*) $(OUTPUTDIR) "true" "Dev" $(SOURCE_DATE_EPOCH) # The following is for local builds only, it is not used by the CI/CD pipeline -all: image-base image-base-devel image-multilib-devel +all: image-base image-base-devel image-multilib-devel image-repro image-%: $(OUTPUTDIR)/Dockerfile.% ${OCITOOL} build -f $(OUTPUTDIR)/Dockerfile.$(*) -t archlinux/archlinux:$(*) $(OUTPUTDIR) diff --git a/README.md b/README.md index 928a6b9..6e0ab47 100644 --- a/README.md +++ b/README.md @@ -12,11 +12,16 @@ Arch Linux provides OCI-Compliant container images in multiple repositories: * [Daily in our ghcr.io repository][ghcr-containers]: `podman pull ghcr.io/archlinux/archlinux:latest` or `docker pull ghcr.io/archlinux/archlinux:latest` -Three versions of the image are provided: `base` (approx. 150 MiB), `base-devel` +Four versions of the image are provided: `base` (approx. 150 MiB), `base-devel` (approx. 260 MiB) and `multilib-devel` (approx. 300MiB) containing the -respective meta package. All of them are available as -tags with `latest` pointing to `base`. Additionally, images are tagged with their -date and build job number, f.e. `base-devel-20201118.0.9436`. +respective meta package; and `repro` which is a bit for bit reproducible version +of the `base` image (note that, to ensure reproducibility, the pacman keys +are stripped from this image so you're expected to run +`pacman-key --init && pacman-key --populate archlinux` before being able to update +the system and install packages via `pacman`). +All of them are available as tags with `latest` pointing to `base`. +Additionally, images are tagged with their date and build job number, +f.e. `base-devel-20201118.0.9436`. While the images are regularly kept up to date it is strongly recommended running `pacman -Syu` right after starting a container due to the rolling @@ -35,7 +40,7 @@ $ cosign verify ghcr.io/archlinux/archlinux:latest --certificate-identity-regexp * Provide the Arch experience in a Docker image * Provide the simplest but complete image to `base`, `base-devel` and `multilib-devel` on a regular basis -* `pacman` needs to work out of the box +* `pacman` needs to work out of the box (with the exception of the `repro` image, while we are working on technical contstrains) * All installed packages have to be kept unmodified >>> @@ -67,7 +72,12 @@ Make sure your user can directly interact with Podman (i.e. `podman info` works) ### Usage There are multiple `make image-XXX` targets, where each creates the respective `archlinux:XXX` image based on the corresponding meta package. -Currently those include `base`, `base-devel` and `multilib-devel`. +Currently those include `base`, `base-devel`, `multilib-devel` and `repro`. + +### Reproducing a `repro` image + +To reproduce a `repro` image locally, follow the instructions +in [REPRO.md](https://gitlab.archlinux.org/archlinux/archlinux-docker/-/blob/master/REPRO.md). ## Pipeline @@ -118,4 +128,4 @@ Every year in June the content of the protected `GITLAB_PROJECT_TOKEN` variable [self-container-registry]: https://gitlab.archlinux.org/archlinux/archlinux-docker/container_registry -[access-tokens]: https://gitlab.archlinux.org/archlinux/archlinux-docker/-/settings/access_tokens \ No newline at end of file +[access-tokens]: https://gitlab.archlinux.org/archlinux/archlinux-docker/-/settings/access_tokens diff --git a/REPRO.md b/REPRO.md new file mode 100644 index 0000000..dc009ae --- /dev/null +++ b/REPRO.md @@ -0,0 +1,207 @@ +# Reproducing a `repro` image locally + +The `repro` image provides a bit for bit [reproducible build](https://reproducible-builds.org) +of the `base` image. + +Note that, to ensure reproducibility, the pacman keys are stripped from this +image, so you're expected to run `pacman-key --init && pacman-key --populate archlinux` +before being able to update the system and install packages via `pacman` when using this image. + +To reproduce the `repro` image locally, follow the below instructions. + +## Disclaimer + +Reproducible builds [expect the same build environment across builds](https://reproducible-builds.org/docs/definition/). + +While it *should* be fine in most cases, this means we cannot guarantee that you will always be able +to successfully reproduce a specific image locally over time. + +Technically speaking, the older the image you're trying to reproduce is, the more chance there is +to have more or less significant differences between your build environment +and the one used to build the original image (for instance in terms of packages versions). +Such differences can affect the build (and the resulting artifacts). Please note that failing to +reproduce an image locally does not necessarily mean that it isn't reproducible per se, but can +just be the result of significant enough differences between your build environment and the one +used to build the original image. + +You can avoid (or mitigate) eventual issues due to such differences by restoring all packages +of your build environment to the build date of the original image (see the [related instructions +from the Arch Wiki](https://wiki.archlinux.org/title/Arch_Linux_Archive#Restore_all_packages_to_a_specific_date)). + +## Dependencies + +Install the following Arch Linux packages: + +* make +* devtools +* git +* podman +* fakechroot +* fakeroot +* diffoscope (to optionally check the reproducibility of the rootFS) +* diffoci + +## Prepare the build environment + +Prepare the build environment by setting the following environment variables: + +* `BUILD_VERSION`: The build version of the `repro` image you want to reproduce. +For instance, if you're aiming to reproduce the `repro-20260331.0.508794` image: + +```bash +export BUILD_VERSION="20260331.0.508794" +``` + +* `ARCHIVE_SNAPSHOT`: The date of the Arch Linux repository archive snaphot to build +the image against. This is based on the date included in the image's `BUILD_VERSION`: + +```bash +export ARCHIVE_SNAPSHOT=$(date -d "${BUILD_VERSION%%.*} -1 day" +"%Y/%m/%d") +``` + +* `SOURCE_DATE_EPOCH`: The value to normalize timestamps with during the build. +This is based on the date included in the image's `BUILD_VERSION`: + +```bash +export SOURCE_DATE_EPOCH=$(date -u -d "${BUILD_VERSION%%.*} 00:00:00" +"%s") +``` + +Then clone the [archlinux-docker](https://gitlab.archlinux.org/archlinux/archlinux-docker) +repository and move into it: + +```bash +git clone https://gitlab.archlinux.org/archlinux/archlinux-docker.git +cd archlinux-docker +``` + +Note that all the following instructions assume that you are at the root of the +archlinux-docker repository cloned above. + +## Build the rootFS and generate the Dockerfile + +Build the rootFS with the required parameters: + +```bash +make \ + ARCHIVE_SNAPSHOT="$ARCHIVE_SNAPSHOT" \ + SOURCE_DATE_EPOCH="$SOURCE_DATE_EPOCH" \ + $PWD/output/Dockerfile.repro +``` + +The following resulting artifacts will be located in `$PWD/output`: + +* repro.tar.zst (the rootFS) +* repro.tar.zst.SHA256 (sha256 hash of the rootFS) +* Dockerfile.repro (the generated Dockerfile) + +## Optional - Check the rootFS reproducibility + +At that point, if the artifacts built for the image you're aiming to reproduce +are still available for download from the rootfs stage of the corresponding +[archlinux-docker pipeline](https://gitlab.archlinux.org/archlinux/archlinux-docker/-/pipelines) +, you can optionally compare the content of the `repro.tar.zst.SHA256` +file from the pipeline to the one generated during your local build (which +should be the same, indicating that the rootFS has been successfully reproduced). + +Additionally, you can check differences between the `repro.tar.zst` tarball from +the pipeline and the one built during your local build with `diffoscope` +*(where `/tmp/repro.tar.zst` is the rootFS tarball downloaded from the pipeline and +`$PWD/output/repro.tar.zst` is the rootFS tarball built during your local build in the following example)*: + +```bash +diffoscope /tmp/repro.tar.zst $PWD/output/repro.tar.zst +``` + +This should return no difference, acting as additional indicator that the rootFS has been +successfully reproduced. + +## Build the image + +You can now (re)build the image against the rootFS and the Dockerfile generated in the previous step. +To do so, build the image with the required parameters: + +```bash +podman build \ + --no-cache \ + --source-date-epoch=$SOURCE_DATE_EPOCH \ + --rewrite-timestamp \ + -f "$PWD/output/Dockerfile.repro" \ + -t "archlinux:repro-$BUILD_VERSION" \ + "$PWD/output" +``` + +The built image will be accessible in your local podman container storage under the name: +`localhost/archlinux:repro-$BUILD_VERSION`. + +## Check the image reproducibility + +Pull the image you're aiming to reproduce from Docker Hub: + +```bash +podman pull docker.io/archlinux/archlinux:repro-$BUILD_VERSION +``` + +Compare the digest of the image pulled from Docker Hub to the digest of the image you built +locally: + +```bash +podman inspect --format '{{.Digest}}' docker.io/archlinux/archlinux:repro-$BUILD_VERSION +podman inspect --format '{{.Digest}}' localhost/archlinux:repro-$BUILD_VERSION +``` + +Both digests should be identical, indicating that the image has been successfully reproduced. + +Additionally, you can check difference between the image pulled from Docker Hub and +the image you built locally with `diffoci`: + +```bash +diffoci diff --semantic --verbose podman://docker.io/archlinux/archlinux:repro-$BUILD_VERSION podman://localhost/archlinux:repro-$BUILD_VERSION +``` + +This should show no difference, acting as additional indicator that the image has been +successfully reproduced *(see the following section about the `--semantic` flag requirement)*. + +### Note about `diffoci` requiring the `--semantic` flag (a.k.a "non-strict" mode) + +Docker / Podman does not allow to have two images with the same name & tag combination stored +locally, [making it impossible to compare two images with the same name with +`diffoci`](https://github.com/reproducible-containers/diffoci/issues/74). +To work around this limitation, one of the two image has to be named differently, whether by +setting a different name / tag combination at build time (as done in this guide) or by renaming +it post-build with e.g. `podman tag`. + +However, the image name & tag combination is automatically reported (and updated in the case +of a renaming) in the image annotations / metadata and it's apparently not possible to fully overwrite +it during build or update it post-build in a straightforward way. +This introduces unavoidable differences +in the image annotations / metadata that `diffoci` will therefore systematically report by default. +See for instance the following `diffoci` output reporting a difference in the image name annotation: + +``` +Event: "DescriptorMismatch" (field "Annotations") + map[string]string{ + "io.containerd.image.name": strings.Join({ +- "docker.io/archlinux/archlinux:repro-20260331.0.508794", ++ "localhost/archlinux:repro-20260331.0.508794", + }, ""), +``` + +Given that it's currently not possible to have two images with the same name & tag +combination stored locally and that it's also not possible to "normalize" the related +annotations / metadata during (or after) the build, we are not aware of a way to get a +fully successful `diffoci` output in default / strict mode (i.e., with *absolutely* no +reported differences, see the [related upstream report](https://github.com/reproducible-containers/diffoci/issues/266)). +This is why we are "forced" to run `diffoci` with the `--semantic` flag +([a.k.a "non-strict" mode](https://github.com/reproducible-containers/diffoci?tab=readme-ov-file#non-strict-aka-semantic-mode)), +which ignores some attributes, including image name annotations. + +While having to run `diffoci` with the `--semantic` flag (for the lack of another option) +just to workaround this technical constraint is unfortunate, we can attest that: + +* This limitation is specific to metadata handling in container tooling and does not +affect the actual filesystem contents or runtime behavior of the image. +* The reported difference in the image name annotation when running `diffoci` in default / strict mode +is (or is supposed to be, at least) the **only** difference being reported when comparing the two images. +* This image name annotation is not part of the hashed object when generating the image digest, +meaning that this difference does not prevent digest equality between the two images (allowing +us to claim bit for bit reproducibility regardless). diff --git a/scripts/make-dockerfile.sh b/scripts/make-dockerfile.sh index 878d18d..4def246 100755 --- a/scripts/make-dockerfile.sh +++ b/scripts/make-dockerfile.sh @@ -7,16 +7,27 @@ declare -r GROUP="$2" declare -r OUTPUTDIR="$3" declare -r DOWNLOAD="$4" declare -r TITLE="$5" +declare -rx SOURCE_DATE_EPOCH="$6" # Do not use these directly in the sed below - it will mask git failures BUILD_VERSION="${BUILD_VERSION:-dev}" CI_COMMIT_SHA="${CI_COMMIT_SHA:-$(git rev-parse HEAD)}" +# Honor SOURCE_DATE_EPOCH and delete non-determistic ldconfig auxiliary cache file for the repro GROUP +if [[ "$GROUP" == "repro" ]]; then + CREATED_TIMESTAMP=$(date -u -d "@$SOURCE_DATE_EPOCH" +%Y-%m-%dT%H:%M:%SZ) + LDCONFIG_AUX_CACHE="rm -f /var/cache/ldconfig/aux-cache" +else + CREATED_TIMESTAMP=$(date -Is) + LDCONFIG_AUX_CACHE="true" +fi + sed -e "s|TEMPLATE_ROOTFS_FILE|$ROOTFS_FILE|" \ -e "s|TEMPLATE_ROOTFS_DOWNLOAD|$DOWNLOAD|" \ -e "s|TEMPLATE_ROOTFS_HASH|$(cat $OUTPUTDIR/$ROOTFS_FILE.SHA256)|" \ -e "s|TEMPLATE_TITLE|Arch Linux $TITLE Image|" \ -e "s|TEMPLATE_VERSION_ID|$BUILD_VERSION|" \ -e "s|TEMPLATE_REVISION|$CI_COMMIT_SHA|" \ - -e "s|TEMPLATE_CREATED|$(date -Is)|" \ + -e "s|TEMPLATE_CREATED|$CREATED_TIMESTAMP|" \ + -e "s|LDCONFIG_AUX_CACHE|$LDCONFIG_AUX_CACHE|" \ Dockerfile.template > "$OUTPUTDIR/Dockerfile.$GROUP" diff --git a/scripts/make-rootfs.sh b/scripts/make-rootfs.sh index a55f718..6359de5 100755 --- a/scripts/make-rootfs.sh +++ b/scripts/make-rootfs.sh @@ -7,6 +7,8 @@ declare -r WRAPPER="fakechroot -- fakeroot" declare -r GROUP="$1" declare -r BUILDDIR="$2" declare -r OUTPUTDIR="$3" +declare -r ARCHIVE_SNAPSHOT="$4" +declare -rx SOURCE_DATE_EPOCH="$5" mkdir -vp "$BUILDDIR/alpm-hooks/usr/share/libalpm/hooks" find /usr/share/libalpm/hooks -exec ln -sf /dev/null "$BUILDDIR/alpm-hooks"{} \; @@ -33,24 +35,51 @@ fi cp --recursive --preserve=timestamps rootfs/* "$BUILDDIR/" ln -fs /usr/lib/os-release "$BUILDDIR/etc/os-release" +# Use archived repo snapshot from archive.archlinux.org for reproducible builds +if [[ "$GROUP" == "repro" ]]; then + sed -i "1iServer = https://archive.archlinux.org/repos/$ARCHIVE_SNAPSHOT/\\\$repo/os/\\\$arch" "$BUILDDIR/etc/pacman.d/mirrorlist" + repro_pacman_options=( + --logfile /dev/null + ) +fi + $WRAPPER -- \ pacman -Sy -r "$BUILDDIR" \ --disable-sandbox-filesystem \ --noconfirm --dbpath "$BUILDDIR/var/lib/pacman" \ --config pacman.conf \ --noscriptlet \ - --hookdir "$BUILDDIR/alpm-hooks/usr/share/libalpm/hooks/" base "$GROUP" + "${repro_pacman_options[@]}" \ + --hookdir "$BUILDDIR/alpm-hooks/usr/share/libalpm/hooks/" base ${GROUP:+${GROUP/repro/}} # repro is not a package $WRAPPER -- chroot "$BUILDDIR" update-ca-trust $WRAPPER -- chroot "$BUILDDIR" pacman-key --init $WRAPPER -- chroot "$BUILDDIR" pacman-key --populate +if [[ "$GROUP" == "repro" ]]; then + # Remove archived repo snapshot from the mirrorlist + sed -i '1d' "$BUILDDIR/etc/pacman.d/mirrorlist" + # Clear pacman keyring for reproducible builds + rm -rf "$BUILDDIR"/etc/pacman.d/gnupg/* + # Normalize mtimes + find "$BUILDDIR" -exec touch --no-dereference --date="@$SOURCE_DATE_EPOCH" {} + +fi + # add system users $WRAPPER -- chroot "$BUILDDIR" /usr/bin/systemd-sysusers --root "/" # remove passwordless login for root (see CVE-2019-5021 for reference) sed -i -e 's/^root::/root:!:/' "$BUILDDIR/etc/shadow" +if [[ "$GROUP" == "repro" ]]; then + repro_tar_options=( + --mtime="@$SOURCE_DATE_EPOCH" + --clamp-mtime + --sort=name + --pax-option=delete=atime,delete=ctime + ) +fi + # fakeroot to map the gid/uid of the builder process to root # fixes #22 fakeroot -- \ @@ -58,6 +87,7 @@ fakeroot -- \ --numeric-owner \ --xattrs \ --acls \ + "${repro_tar_options[@]}" \ --exclude-from=exclude \ -C "$BUILDDIR" \ -c . \