mirror of
https://github.com/jmcorgan/fips.git
synced 2026-10-05 19:18:25 +00:00
Embed the source revision in container-built binaries again
The build image had no git, so build.rs could not read the revision and every binary built through the container carried none: -V printed only the version. The image now installs git, and trusts the source mounted at /src, which is owned by the host user while the build runs as root; without that entry git refuses the repository and the revision is silently empty just the same. The image tag now includes a hash of Dockerfile.build. Before, the tag named only the floor image and the toolchain, so a host with the image cached kept using it after the Dockerfile changed, and this change would never have reached it. A build from a git worktree still has no revision, because the worktree's git directory is outside the mounted tree. That is documented, with the -V reference noting that the revision is omitted when it could not be read, rather than worked around; release and CI builds use full checkouts.
This commit is contained in:
@@ -245,6 +245,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
states a floor lower or higher than the one they need. A dependency the
|
states a floor lower or higher than the one they need. A dependency the
|
||||||
packaging tool drops, including one it drops after only a warning when it
|
packaging tool drops, including one it drops after only a warning when it
|
||||||
cannot resolve a binary, now fails the build instead of shipping.
|
cannot resolve a binary, now fails the build instead of shipping.
|
||||||
|
- `-V` on binaries built into the Linux packages now includes the source
|
||||||
|
revision, as `<version> (rev <git-hash>)`. The build image had no git, so
|
||||||
|
every container-built binary printed the version alone. A package built from
|
||||||
|
a git worktree still has no revision, because the worktree's git directory is
|
||||||
|
outside the tree the build sees. The build image's tag now includes a hash of
|
||||||
|
its Dockerfile, so a host with an older image cached builds a new one instead
|
||||||
|
of reusing it.
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ controlled through the standard service control manager.
|
|||||||
| Flag | Argument | Description |
|
| Flag | Argument | Description |
|
||||||
| ---- | -------- | ----------- |
|
| ---- | -------- | ----------- |
|
||||||
| `-c`, `--config` | `FILE` | Use `FILE` as the configuration. Skips the default search paths. |
|
| `-c`, `--config` | `FILE` | Use `FILE` as the configuration. Skips the default search paths. |
|
||||||
| `-V` | — | Print the short version, `<version> (rev <git-hash>)`. |
|
| `-V` | — | Print the short version, `<version> (rev <git-hash>)`. The `rev` part is omitted when the build could not read a git revision, as in a package built from a git worktree. |
|
||||||
| `--version` | — | Print the long version: short version plus build target triple. |
|
| `--version` | — | Print the long version: short version plus build target triple. |
|
||||||
| `-h`, `--help` | — | Print usage and exit. |
|
| `-h`, `--help` | — | Print usage and exit. |
|
||||||
| `--install-service` | — | (Windows only) Install `fips` as a Windows service. Requires Administrator. |
|
| `--install-service` | — | (Windows only) Install `fips` as a Windows service. Requires Administrator. |
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ that defines the socket location, see
|
|||||||
| Flag | Argument | Description |
|
| Flag | Argument | Description |
|
||||||
| ---- | -------- | ----------- |
|
| ---- | -------- | ----------- |
|
||||||
| `-s`, `--socket` | `PATH` | Override the control-socket path (Linux/macOS) or TCP port (Windows). |
|
| `-s`, `--socket` | `PATH` | Override the control-socket path (Linux/macOS) or TCP port (Windows). |
|
||||||
| `-V` | — | Print the short version, `<version> (rev <git-hash>)`. |
|
| `-V` | — | Print the short version, `<version> (rev <git-hash>)`. The `rev` part is omitted when the build could not read a git revision, as in a package built from a git worktree. |
|
||||||
| `--version` | — | Print the long version: short version plus build target triple. |
|
| `--version` | — | Print the long version: short version plus build target triple. |
|
||||||
| `-h`, `--help` | — | Print usage and exit. Per-subcommand help via `fipsctl <subcommand> --help`. |
|
| `-h`, `--help` | — | Print usage and exit. Per-subcommand help via `fipsctl <subcommand> --help`. |
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ a confirmation prompt — see [Keybindings](#keybindings)). For
|
|||||||
| `-s`, `--socket` | `PATH` | (auto) | Daemon control-socket path / port. Same default as `fipsctl`. |
|
| `-s`, `--socket` | `PATH` | (auto) | Daemon control-socket path / port. Same default as `fipsctl`. |
|
||||||
| `--gateway-socket` | `PATH` | (auto) | `fips-gateway` control-socket path / port. Default: `/run/fips/gateway.sock` (Unix), TCP port `21211` (Windows). |
|
| `--gateway-socket` | `PATH` | (auto) | `fips-gateway` control-socket path / port. Default: `/run/fips/gateway.sock` (Unix), TCP port `21211` (Windows). |
|
||||||
| `-r`, `--refresh` | `SECONDS` | `2` | Poll interval. |
|
| `-r`, `--refresh` | `SECONDS` | `2` | Poll interval. |
|
||||||
| `-V` | — | — | Print the short version, `<version> (rev <git-hash>)`. |
|
| `-V` | — | — | Print the short version, `<version> (rev <git-hash>)`. The `rev` part is omitted when the build could not read a git revision, as in a package built from a git worktree. |
|
||||||
| `--version` | — | — | Print the long version: short version plus build target triple. |
|
| `--version` | — | — | Print the long version: short version plus build target triple. |
|
||||||
| `-h`, `--help` | — | — | Print usage and exit. |
|
| `-h`, `--help` | — | — | Print usage and exit. |
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,10 @@
|
|||||||
# This image carries the toolchain and the build dependencies only. It never
|
# 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
|
# 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.
|
# not invalidate the image and a warm rebuild costs seconds rather than minutes.
|
||||||
|
#
|
||||||
|
# A build from a git worktree carries no source revision: the worktree's .git is
|
||||||
|
# a file pointing outside the mounted tree, so git cannot read it here. Release
|
||||||
|
# and CI builds use full checkouts and carry one.
|
||||||
ARG BASE=ubuntu:22.04
|
ARG BASE=ubuntu:22.04
|
||||||
FROM ${BASE}
|
FROM ${BASE}
|
||||||
|
|
||||||
@@ -24,10 +28,22 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
|||||||
clang \
|
clang \
|
||||||
binutils \
|
binutils \
|
||||||
dpkg-dev \
|
dpkg-dev \
|
||||||
|
git \
|
||||||
curl \
|
curl \
|
||||||
ca-certificates \
|
ca-certificates \
|
||||||
&& apt-get clean && rm -rf /var/lib/apt/lists/*
|
&& 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 dirty flag can be stale in a local container build. build.rs reruns only
|
||||||
|
# when .git/HEAD or .git/refs change, and the target directory is a persistent
|
||||||
|
# volume, so an uncommitted edit alone does not refresh it; git here also runs
|
||||||
|
# without the host user's global excludes, so a file only those ignore reads as
|
||||||
|
# dirty. Release and CI builds start from a committed, fresh tree.
|
||||||
|
RUN git config --system --add safe.directory /src
|
||||||
|
|
||||||
# The toolchain version is passed in, read from rust-toolchain.toml by the
|
# 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
|
# 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
|
# the compiler the rest of CI uses, and bumping the pin rebuilds the image. The
|
||||||
|
|||||||
@@ -12,9 +12,10 @@
|
|||||||
# Usage: build-deb-container.sh [--output-dir DIR] [--version V] [--features LIST]
|
# Usage: build-deb-container.sh [--output-dir DIR] [--version V] [--features LIST]
|
||||||
# [--rebuild-image]
|
# [--rebuild-image]
|
||||||
#
|
#
|
||||||
# Requires docker. The image is cached between runs and rebuilt only when the
|
# Requires docker. The image is cached between runs under a tag made of the
|
||||||
# Dockerfile or the floor changes; the source is mounted rather than copied, so
|
# floor image, the Rust toolchain and a hash of Dockerfile.build, so a change to
|
||||||
# editing code does not invalidate it.
|
# any of the three builds a new image; the source is mounted rather than copied,
|
||||||
|
# so editing code does not invalidate it.
|
||||||
|
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
@@ -35,7 +36,7 @@ while [[ $# -gt 0 ]]; do
|
|||||||
--version) VERSION="${2:?missing value for --version}"; shift 2 ;;
|
--version) VERSION="${2:?missing value for --version}"; shift 2 ;;
|
||||||
--features) FEATURES="${2:?missing value for --features}"; shift 2 ;;
|
--features) FEATURES="${2:?missing value for --features}"; shift 2 ;;
|
||||||
--rebuild-image) REBUILD_IMAGE=1; shift ;;
|
--rebuild-image) REBUILD_IMAGE=1; shift ;;
|
||||||
-h|--help) sed -n '2,17p' "$0"; exit 0 ;;
|
-h|--help) sed -n '2,18p' "$0"; exit 0 ;;
|
||||||
*) echo "Unknown option: $1" >&2; exit 2 ;;
|
*) echo "Unknown option: $1" >&2; exit 2 ;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
@@ -47,13 +48,21 @@ command -v docker >/dev/null 2>&1 || {
|
|||||||
|
|
||||||
# Read the toolchain from the pin rather than choosing one here, and put it in
|
# Read the toolchain from the pin rather than choosing one here, and put it in
|
||||||
# the tag so a bump rebuilds the image instead of silently reusing a stale one.
|
# the tag so a bump rebuilds the image instead of silently reusing a stale one.
|
||||||
|
# The Dockerfile's content goes in the tag for the same reason: without it a
|
||||||
|
# host that has the image cached keeps using it after the Dockerfile changes.
|
||||||
RUST_TOOLCHAIN=$(awk -F'"' '/^channel *=/{print $2; exit}' "$REPO_ROOT/rust-toolchain.toml")
|
RUST_TOOLCHAIN=$(awk -F'"' '/^channel *=/{print $2; exit}' "$REPO_ROOT/rust-toolchain.toml")
|
||||||
[ -n "$RUST_TOOLCHAIN" ] || {
|
[ -n "$RUST_TOOLCHAIN" ] || {
|
||||||
echo "build-deb-container: could not read channel from rust-toolchain.toml" >&2
|
echo "build-deb-container: could not read channel from rust-toolchain.toml" >&2
|
||||||
exit 2
|
exit 2
|
||||||
}
|
}
|
||||||
|
|
||||||
IMAGE_TAG="fips-deb-builder:${FIPS_BUILD_IMAGE//[:\/]/-}-rust${RUST_TOOLCHAIN}"
|
DOCKERFILE_HASH=$(sha256sum "$SCRIPT_DIR/Dockerfile.build" | cut -c1-12) || DOCKERFILE_HASH=""
|
||||||
|
[[ "$DOCKERFILE_HASH" =~ ^[0-9a-f]{12}$ ]] || {
|
||||||
|
echo "build-deb-container: could not hash $SCRIPT_DIR/Dockerfile.build" >&2
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
IMAGE_TAG="fips-deb-builder:${FIPS_BUILD_IMAGE//[:\/]/-}-rust${RUST_TOOLCHAIN}-${DOCKERFILE_HASH}"
|
||||||
|
|
||||||
if [ "$REBUILD_IMAGE" -eq 1 ] || ! docker image inspect "$IMAGE_TAG" >/dev/null 2>&1; then
|
if [ "$REBUILD_IMAGE" -eq 1 ] || ! docker image inspect "$IMAGE_TAG" >/dev/null 2>&1; then
|
||||||
echo "=== Building $IMAGE_TAG from $FIPS_BUILD_IMAGE with Rust $RUST_TOOLCHAIN ===" >&2
|
echo "=== Building $IMAGE_TAG from $FIPS_BUILD_IMAGE with Rust $RUST_TOOLCHAIN ===" >&2
|
||||||
@@ -67,10 +76,10 @@ else
|
|||||||
echo "=== Using cached $IMAGE_TAG ===" >&2
|
echo "=== Using cached $IMAGE_TAG ===" >&2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Derive the version and the timestamp on the host, where git works, and pass
|
# Derive the version and the timestamp on the host and pass both in, because a
|
||||||
# both in. The container then never runs git, which matters for two reasons: a
|
# worktree's .git is a file pointing outside the mount and does not resolve in
|
||||||
# worktree's .git is a file pointing outside the mount and would not resolve,
|
# the container. The image's git is there only for build.rs's revision, which is
|
||||||
# and a bind-mounted repository trips git's dubious-ownership check.
|
# empty for a worktree build for the same reason.
|
||||||
if [ -z "$VERSION" ]; then
|
if [ -z "$VERSION" ]; then
|
||||||
CRATE_VERSION=$(awk -F'"' '/^version = /{print $2; exit}' "$REPO_ROOT/Cargo.toml")
|
CRATE_VERSION=$(awk -F'"' '/^version = /{print $2; exit}' "$REPO_ROOT/Cargo.toml")
|
||||||
if [[ "$CRATE_VERSION" == *-dev ]]; then
|
if [[ "$CRATE_VERSION" == *-dev ]]; then
|
||||||
@@ -100,7 +109,8 @@ if [ -n "$FEATURES" ]; then
|
|||||||
# it is also what marks the version so a feature package is distinguishable
|
# it is also what marks the version so a feature package is distinguishable
|
||||||
# from the default build of the same commit. It refuses --features with
|
# from the default build of the same commit. It refuses --features with
|
||||||
# --no-build for that reason, so the two cases cannot share one command.
|
# --no-build for that reason, so the two cases cannot share one command.
|
||||||
# The version still comes from the host, because the image has no git.
|
# The version still comes from the host, because a worktree's .git does
|
||||||
|
# not resolve inside the mount.
|
||||||
BUILD_CMD="packaging/debian/build-deb.sh --features '$FEATURES' --version '$VERSION' --output-dir /out --name-file /name/deb"
|
BUILD_CMD="packaging/debian/build-deb.sh --features '$FEATURES' --version '$VERSION' --output-dir /out --name-file /name/deb"
|
||||||
else
|
else
|
||||||
BUILD_CMD="cargo build --release --locked
|
BUILD_CMD="cargo build --release --locked
|
||||||
|
|||||||
@@ -145,8 +145,8 @@ elif [[ -n "${FEATURES}" ]]; then
|
|||||||
# An explicit version needs the same marker for the same reason, and it is
|
# An explicit version needs the same marker for the same reason, and it is
|
||||||
# the only way a caller that cannot derive the version here can get one.
|
# the only way a caller that cannot derive the version here can get one.
|
||||||
# The container build is that caller: it derives the version on the host
|
# The container build is that caller: it derives the version on the host
|
||||||
# because the image has no git, and the source is mounted read-only from a
|
# because the source may be mounted read-only from a worktree whose .git is
|
||||||
# worktree whose .git is a file pointing outside the mount.
|
# a file pointing outside the mount, which git in the container cannot read.
|
||||||
if [[ "${VERSION_OVERRIDE}" == *"+$(printf '%s' "${FEATURES}" | tr -c 'a-zA-Z0-9.' '.')"* ]]; then
|
if [[ "${VERSION_OVERRIDE}" == *"+$(printf '%s' "${FEATURES}" | tr -c 'a-zA-Z0-9.' '.')"* ]]; then
|
||||||
: # already marked by the caller
|
: # already marked by the caller
|
||||||
elif [[ "${VERSION_OVERRIDE}" == *-* ]]; then
|
elif [[ "${VERSION_OVERRIDE}" == *-* ]]; then
|
||||||
|
|||||||
Reference in New Issue
Block a user