mirror of
https://gitlab.archlinux.org/archlinux/archlinux-docker.git
synced 2026-05-14 10:16:15 +02:00
Merge branch 'repro' into 'master'
Add a new `repro` image version / tag providing a bit for bit reproducible image Closes #44 See merge request archlinux/archlinux-docker!96
This commit is contained in:
commit
09a5aed161
@ -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]=<output/Dockerfile.multilib-devel"
|
||||
--form "actions[][action]=update"
|
||||
--form "actions[][file_path]=Dockerfile.repro"
|
||||
--form "actions[][content]=<output/Dockerfile.repro"
|
||||
--form "actions[][action]=update"
|
||||
--form "actions[][file_path]=.gitlab-ci.yml"
|
||||
--form "actions[][content]=<.gitlab-ci.yml"
|
||||
--form "actions[][action]=update"
|
||||
@ -313,6 +391,10 @@ release:
|
||||
url: '${PACKAGE_REGISTRY_URL}/multilib-devel-${BUILD_VERSION}.tar.zst'
|
||||
- name: 'multilib-devel-${BUILD_VERSION}.tar.zst.SHA256'
|
||||
url: '${PACKAGE_REGISTRY_URL}/multilib-devel-${BUILD_VERSION}.tar.zst.SHA256'
|
||||
- name: 'repro-${BUILD_VERSION}.tar.zst'
|
||||
url: '${PACKAGE_REGISTRY_URL}/repro-${BUILD_VERSION}.tar.zst'
|
||||
- name: 'repro-${BUILD_VERSION}.tar.zst.SHA256'
|
||||
url: '${PACKAGE_REGISTRY_URL}/repro-${BUILD_VERSION}.tar.zst.SHA256'
|
||||
|
||||
# Publish to the official Docker namespace: https://hub.docker.com/_/archlinux
|
||||
# Note: The description is maintained here: https://github.com/docker-library/docs/tree/master/archlinux
|
||||
@ -347,7 +429,7 @@ publish-dockerhub:
|
||||
- git checkout -b "$head"
|
||||
- cp ../docker-library.template library/archlinux
|
||||
- |
|
||||
for group in base base-devel multilib-devel; do
|
||||
for group in base base-devel multilib-devel repro; do
|
||||
test "${group}" = "base" && extra="latest, " || extra=""
|
||||
echo "Tags: ${extra}${group}, ${group}-${BUILD_VERSION}" >> library/archlinux
|
||||
echo "GitCommit: ${BUILD_COMMIT}" >> library/archlinux
|
||||
|
||||
@ -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"]
|
||||
|
||||
8
Makefile
8
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)
|
||||
|
||||
24
README.md
24
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
|
||||
[access-tokens]: https://gitlab.archlinux.org/archlinux/archlinux-docker/-/settings/access_tokens
|
||||
|
||||
207
REPRO.md
Normal file
207
REPRO.md
Normal file
@ -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).
|
||||
@ -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"
|
||||
|
||||
@ -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 . \
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user