Files
fips/packaging/debian/Dockerfile.build
Johnathan Corgan 3d3eb5f3a8 Check that a package's binaries carry the tree's revision
Git in the build container could not read a worktree's repository, whose
.git names a directory outside the mounted tree, or the objects a
--shared clone borrows from another repository. Worktree packages
carried no revision, and a --shared clone's package claimed a clean tree
when it was dirty.

The container build now mounts, read-only at their own paths, the git
directories outside the tree that the checkout refers to: the common git
directory and every alternate object store, followed as deep as git
follows them. A relative alternates entry that would climb above / where
the container sees it is refused, with a request to write it as an
absolute path. The container compares the HEAD it reads with the host's
before it waits for the lock, so a gap in those mounts fails at once.

A tree that is not the top of its own work tree, such as a release
tarball unpacked inside a packaging repository, is built as no checkout
and its binaries carry no revision: the outer repository's HEAD is not
the tree's revision.

After packaging, testing/check-deb-revision.sh runs each packaged binary
and checks that it carries the tree's commit and dirty flag. It fails
when HEAD moved during the build, and when git can read HEAD but not the
tree's state. When the state changed during the build it checks the
commit only.
2026-10-13 03:05:21 +00:00

73 lines
3.4 KiB
INI

# Build image for the Linux release artifacts.
#
# Pinned to the oldest distribution FIPS supports, because the glibc a binary is
# linked against decides the glibc it will run on. See packaging/build-floor.env
# for the floor and the reasoning; BASE is passed from there, not written here,
# so there is one place to change it.
#
# This image carries the toolchain and the build dependencies only. It never
# carries the source: the source is mounted at run time, so editing a file does
# not invalidate the image and a warm rebuild costs seconds rather than minutes.
#
# build-deb-container.sh also mounts, read-only, the git directories a worktree
# or a --shared clone refers to outside the tree, so a build of any tree that is
# the top of its own git checkout, worktrees and shared clones included, carries
# the tree's revision and dirty flag. A tree with no git checkout of its own,
# such as one nested inside another repository, carries none.
ARG BASE=ubuntu:22.04
FROM ${BASE}
ENV DEBIAN_FRONTEND=noninteractive
# dpkg-dev is not in a bare ubuntu:22.04 and is what provides dpkg-shlibdeps,
# which cargo-deb's "$auto" dependency resolution shells out to. Without it the
# declared dependencies would silently lose their versions again.
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
pkg-config \
libdbus-1-dev \
libclang-dev \
clang \
binutils \
dpkg-dev \
git \
curl \
ca-certificates \
&& apt-get clean && rm -rf /var/lib/apt/lists/*
# build.rs asks git for the revision it embeds in the binaries. The source is
# mounted at /src owned by the host user, while the build runs as root, and git
# refuses a repository owned by someone else: without this entry the revision is
# silently empty, exactly as it was when the image had no git at all.
# The workspace crates are cleaned before every package build, so build.rs
# reruns and reads the tree's current dirty flag. Git here runs without the host
# user's global excludes, so a file only those ignore reads as dirty.
RUN git config --system --add safe.directory /src
# The toolchain version is passed in, read from rust-toolchain.toml by the
# calling script, and the image tag carries it -- so the image cannot drift from
# the compiler the rest of CI uses, and bumping the pin rebuilds the image. The
# builder this replaces installed `stable` and never copied rust-toolchain.toml,
# so it compiled with a different compiler from the release and nothing said so.
#
# CARGO_NET_RETRY raises cargo's own retry count for crate downloads, both for
# cargo install below and for the package build that runs in this image; the
# registry is fetched cold on every CI runner and has failed mid-download.
# CARGO_HTTP_MULTIPLEXING is left at its default: turn it off only if HTTP/2
# framing errors from the registry still occur with the higher retry count.
ARG RUST_TOOLCHAIN
ENV RUSTUP_HOME=/usr/local/rustup \
CARGO_HOME=/usr/local/cargo \
CARGO_NET_RETRY=10 \
PATH=/usr/local/cargo/bin:$PATH
RUN test -n "${RUST_TOOLCHAIN}" \
&& curl --retry 3 --retry-connrefused --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs \
| sh -s -- -y --profile minimal --default-toolchain "${RUST_TOOLCHAIN}" \
&& chmod -R a+w "$RUSTUP_HOME" "$CARGO_HOME"
ARG CARGO_DEB_VERSION=3.6.3
RUN cargo install cargo-deb --version "${CARGO_DEB_VERSION}" --locked \
&& chmod -R a+w "$CARGO_HOME"
WORKDIR /src