Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions tools/buildsys/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ pub(crate) struct BuildKitArgs {
#[arg(long, env = "BUILDSYS_VERSION_BUILD")]
pub(crate) version_build: String,

/// Unix seconds of the latest project commit. Forwarded to the buildkit
/// sandbox as `BUILD_ID_TIMESTAMP` for reproducible artifact timestamps.
#[arg(long, env = "BUILDSYS_VERSION_BUILD_TIMESTAMP")]
pub(crate) version_build_timestamp: String,

/// Version number for the workspace
#[arg(long, env = "BUILDSYS_VERSION_IMAGE")]
pub(crate) version_image: String,
Expand Down
5 changes: 5 additions & 0 deletions tools/buildsys/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ impl KitBuildArgs {
args.build_arg("KIT", &self.kit);
args.build_arg("PACKAGE_DEPENDENCIES", self.package_dependencies.join(" "));
args.build_arg("BUILD_ID", &self.version_build);
args.build_arg("BUILD_ID_TIMESTAMP", &self.version_build_timestamp);
args.build_arg("VERSION_ID", &self.version_id);
args.build_arg("EXTERNAL_KIT_METADATA", &self.external_kit_metadata);
args.build_arg("VENDOR", &self.vendor);
Expand All @@ -195,6 +196,9 @@ struct KitBuildArgs {
local_kits: Vec<String>,
vendor: String,
version_build: String,
/// Unix seconds of the latest project commit. Forwarded as
/// `BUILD_ID_TIMESTAMP` for reproducible kit OCI timestamps.
version_build_timestamp: String,
version_id: String,
}

Expand Down Expand Up @@ -503,6 +507,7 @@ impl DockerBuild {
external_kit_metadata: EXTERNAL_KIT_METADATA.into(),
package_dependencies: manifest.package_dependencies().context(error::GraphSnafu)?,
version_build: args.version_build,
version_build_timestamp: args.version_build_timestamp,
version_id: args.version_image,
}),
secrets_args: Vec::new(),
Expand Down
6 changes: 4 additions & 2 deletions twoliter/embedded/Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ BUILDSYS_METADATA_DIR = "${BUILDSYS_BUILD_DIR}/metadata"
BUILDSYS_CARGO_METADATA_PATH = "${BUILDSYS_METADATA_DIR}/cargo_metadata.json"
BUILDSYS_SBKEYS_PROFILE = { script = ['echo "${BUILDSYS_SBKEYS_PROFILE:-local}"'] }
BUILDSYS_VERSION_BUILD = { script = ["git describe --always --dirty --exclude '*' --abbrev=8 || echo 00000000"] }
# The unix timestamp in ms of the latest commit of the project.
# This is an input for setting the Release value of a package.
# Unix seconds of the latest project commit. Threaded through buildsys and the
# Dockerfile as `BUILD_ID_TIMESTAMP`; used as the source of truth for the RPM
# `Release` and `BUILDTIME`, `SOURCE_DATE_EPOCH`, kit OCI `.created`, and
# variant `InstalledTime` fields to keep build artifacts reproducible.
BUILDSYS_VERSION_BUILD_TIMESTAMP = { script = ["git show -s --format=%ct HEAD || echo 0000000000"] }
# For now, release config path can't be overridden with -e, because it's used
# later in this section. You have to edit the path here in Makefile.toml to
Expand Down
32 changes: 31 additions & 1 deletion twoliter/embedded/build.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ ARG BUILD_ID
ARG BUILD_ID_TIMESTAMP
ENV BUILD_ID=${BUILD_ID}
ENV BUILD_ID_TIMESTAMP=${BUILD_ID_TIMESTAMP}
# Mirror BUILD_ID_TIMESTAMP into SOURCE_DATE_EPOCH so rpm clamps payload/gzip
# mtimes. `BUILDTIME` is not derived from it here; the rpmbuild calls below
# also pass `--define '_buildtime ...'` to force a reproducible header.
ENV SOURCE_DATE_EPOCH=${BUILD_ID_TIMESTAMP}
WORKDIR /home/builder

USER builder
Expand Down Expand Up @@ -133,6 +137,13 @@ RUN --mount=source=.cargo/twoliter_cargo_config.toml,target=/home/builder/rpmbui
--mount=type=cache,target=/home/builder/.cache,from=cache,source=/cache \
--mount=source=sources,target=/home/builder/rpmbuild/BUILD/sources \
--mount=target=/host \
# Require a numeric BUILD_ID_TIMESTAMP; an empty value silently disables
# rpm's mtime clamp and buildtime override.
if [[ -z "${BUILD_ID_TIMESTAMP:-}" ]] || \
! [[ "${BUILD_ID_TIMESTAMP}" =~ ^[0-9]+$ ]]; then \
echo "BUILD_ID_TIMESTAMP must be a Unix seconds value for reproducible RPMs, got '${BUILD_ID_TIMESTAMP:-}'" >&2; \
exit 1; \
fi && \
# The dist tag is set as the `Release` field in Bottlerocket RPMs. Define it to be
# in the form <timestamp of latest commit>.<latest commit short sha>.br1
# Remove '-dirty' from the commit sha: '-' is an illegal character for the Release field
Expand All @@ -141,6 +152,7 @@ RUN --mount=source=.cargo/twoliter_cargo_config.toml,target=/home/builder/rpmbui
rpmbuild -bb --clean \
--undefine _auto_set_build_flags \
--define "_target_cpu ${ARCH}" \
--define "_buildtime ${BUILD_ID_TIMESTAMP}" \
--define "dist .${BUILD_ID_TIMESTAMP}.${BUILD_ID//-dirty/}.br1" \
rpmbuild/SPECS/${PACKAGE}.spec

Expand Down Expand Up @@ -178,13 +190,16 @@ ARG PACKAGE_DEPENDENCIES
ARG ARCH
ARG NOCACHE
ARG BUILD_ID
# Consumed by rpm2kit for the kit's OCI `.created` timestamp.
ARG BUILD_ID_TIMESTAMP
ARG VERSION_ID
ARG EXTERNAL_KIT_METADATA
ARG VENDOR
ARG LOCAL_KIT_DEPENDENCIES
ARG BYPASS_SOCKET
ARG OUTPUT_SOCKET
ARG BUILDER_UID
ENV BUILD_ID_TIMESTAMP=${BUILD_ID_TIMESTAMP}

WORKDIR /home/builder
USER root
Expand Down Expand Up @@ -273,17 +288,29 @@ ARG KIT_DEPENDENCIES
ARG EXTERNAL_KIT_DEPENDENCIES
ARG ARCH
ARG NOCACHE
# Forwarded to rpmbuild as SOURCE_DATE_EPOCH for mtime clamping and as
# `_buildtime` for the RPM BUILDTIME header.
ARG BUILD_ID_TIMESTAMP
ENV BUILD_ID_TIMESTAMP=${BUILD_ID_TIMESTAMP}
ENV SOURCE_DATE_EPOCH=${BUILD_ID_TIMESTAMP}

WORKDIR /home/builder
USER builder

# Build the metadata RPM for the variant.
RUN --mount=target=/host \
cat "/usr/lib/rpm/platform/${ARCH}-bottlerocket/macros" generated.rpmmacros > .rpmmacros \
# Require a numeric BUILD_ID_TIMESTAMP so SOURCE_DATE_EPOCH reaches rpm.
if [[ -z "${BUILD_ID_TIMESTAMP:-}" ]] || \
! [[ "${BUILD_ID_TIMESTAMP}" =~ ^[0-9]+$ ]]; then \
echo "BUILD_ID_TIMESTAMP must be a Unix seconds value for reproducible RPMs, got '${BUILD_ID_TIMESTAMP:-}'" >&2; \
exit 1; \
fi \
&& cat "/usr/lib/rpm/platform/${ARCH}-bottlerocket/macros" generated.rpmmacros > .rpmmacros \
&& cat generated.bconds /host/build/tools/metadata.spec >> rpmbuild/SPECS/metadata.spec \
&& rpmbuild -ba --clean \
--undefine _auto_set_build_flags \
--define "_target_cpu ${ARCH}" \
--define "_buildtime ${BUILD_ID_TIMESTAMP}" \
rpmbuild/SPECS/metadata.spec \
&& rpm -qp --provides rpmbuild/RPMS/${ARCH}/bottlerocket-metadata-*.${ARCH}.rpm \
&& echo ${NOCACHE}
Expand Down Expand Up @@ -526,6 +553,9 @@ ARG NOCACHE
ARG VARIANT
ARG VARIANT_NAME=${VARIANT}
ENV VARIANT=${VARIANT_NAME} VERSION_ID=${VERSION_ID} BUILD_ID=${BUILD_ID}
# Forwarded for consistency; rpm2kmodkit emits no timestamped artifacts today.
ARG BUILD_ID_TIMESTAMP
ENV BUILD_ID_TIMESTAMP=${BUILD_ID_TIMESTAMP}
ARG BYPASS_SOCKET
ARG OUTPUT_SOCKET
ARG BUILDER_UID
Expand Down
7 changes: 6 additions & 1 deletion twoliter/embedded/rpm2eif
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,12 @@ cleanup() {
trap cleanup EXIT

echo "=== Installing RPMs ==="
INSTALL_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
# Written to `InstalledTime` in application-inventory.json. Derived from
# BUILD_ID_TIMESTAMP to keep the inventory reproducible.
: "${BUILD_ID_TIMESTAMP:?BUILD_ID_TIMESTAMP required for reproducible inventory}"
[[ "${BUILD_ID_TIMESTAMP}" =~ ^[0-9]+$ ]] || \
{ echo "BUILD_ID_TIMESTAMP must be numeric, got '${BUILD_ID_TIMESTAMP}'" >&2; exit 1; }
INSTALL_TIME="$(date -u -d "@${BUILD_ID_TIMESTAMP}" +%Y-%m-%dT%H:%M:%SZ)"
rpm -iv --ignorearch --root "${INSTALL_ROOT}" \
"${PACKAGE_DIR}"/*.rpm

Expand Down
7 changes: 6 additions & 1 deletion twoliter/embedded/rpm2img
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,12 @@ if [[ "${STANDALONE_IMAGE}" == "no" && "${PARTITION_PLAN}" == "split" ]]; then
--sort --print "${DATA_IMAGE}"
fi

INSTALL_TIME="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
# Written to `InstalledTime` in application-inventory.json. Derived from
# BUILD_ID_TIMESTAMP to keep the inventory reproducible.
: "${BUILD_ID_TIMESTAMP:?BUILD_ID_TIMESTAMP required for reproducible inventory}"
[[ "${BUILD_ID_TIMESTAMP}" =~ ^[0-9]+$ ]] || \
{ echo "BUILD_ID_TIMESTAMP must be numeric, got '${BUILD_ID_TIMESTAMP}'" >&2; exit 1; }
INSTALL_TIME="$(date -u -d "@${BUILD_ID_TIMESTAMP}" +%Y-%m-%dT%H:%M:%SZ)"
rpm -iv --ignorearch --root "${ROOT_MOUNT}" "${PACKAGE_DIR}"/*.rpm

# Embed any declared guest variant images into the host rootfs. Each entry has the form
Expand Down
8 changes: 7 additions & 1 deletion twoliter/embedded/rpm2kit
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,13 @@ cleanup() {
}
trap 'cleanup' EXIT

TIMESTAMP="$(date +"%FT%T.%NZ")"
# Written to the kit's OCI `.created` field and index
# `org.opencontainers.image.created` annotation. Derived from
# BUILD_ID_TIMESTAMP to keep kit metadata reproducible.
: "${BUILD_ID_TIMESTAMP:?BUILD_ID_TIMESTAMP required for reproducible kit metadata}"
[[ "${BUILD_ID_TIMESTAMP}" =~ ^[0-9]+$ ]] || \
{ echo "BUILD_ID_TIMESTAMP must be numeric, got '${BUILD_ID_TIMESTAMP}'" >&2; exit 1; }
TIMESTAMP="$(date -u -d "@${BUILD_ID_TIMESTAMP}" +%Y-%m-%dT%H:%M:%SZ)"
FILENAME_PREFIX="${KIT:?}-v${VERSION_ID:?}-${BUILD_ID:?}-${ARCH:?}"
# Translate ARCH into the proper docker arch
case "${ARCH}" in
Expand Down
3 changes: 3 additions & 0 deletions twoliter/src/tool-crates/embedded-bundle/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ fn main() {
let mut buf_writer = Vec::new().writer();
let enc = ZlibEncoder::new(&mut buf_writer, Compression::default());
let mut tar = tar::Builder::new(enc);
// Zero mtimes/uids/gids and mask modes so the embedded tarball is
// byte-identical across builds of the same source tree.
tar.mode(tar::HeaderMode::Deterministic);
tar.append_dir_all("", &paths.prep_dir).unwrap();

// Drop tar object to ensure any finalizing steps are done.
Expand Down