make cpio reproducible - #199
Conversation
There was a problem hiding this comment.
Pull request overview
This PR aims to make initramfs cpio outputs reproducible by normalizing filesystem mtimes in the staged initramfs tree before the archive is created.
Changes:
- Add a build-script step that normalizes mtimes under
$INITRAMFS_WORKtoSOURCE_DATE_EPOCH(defaulting to 0). - Add unit tests that assert the mtime-normalization step is emitted and ordered correctly relative to release-file injection and
cpiocreation.
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
6fb3bc3 to
75ca11f
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 1 changed files in this pull request and generated no new comments.
Suppressed comments (1)
src/commands/initramfs/image.rs:129
- You pin
LC_ALL=Cfor the cpio entry sort to avoid locale-driven archive drift, but the initramfs build ID is also derived from a locale-sensitive sort of RPM NEVRAs earlier in this generated script (rpm -qa ... | sort). If the SDK/container ever gains additional locales or forwardsLC_*from the host, the same package set could produce a differentINITRAMFS_BUILD_ID. Consider pinning that earlier sort toLC_ALL=Cas well.
# Reproducibility notes for the pipeline below:
# * `LC_ALL=C sort` — entry order is archive order (and, with
# --renumber-inodes, decides the inode numbers), so collation must not
# drift. Today's SDK ships only the C/POSIX locales, which makes this a
# no-op, but it stops the archive from changing if the image ever gains
# real locales or the CLI starts forwarding the host's LC_* vars.
Signed-off-by: Beniamin Sandu <b.sandu@peridio.com>
75ca11f to
9cd0f95
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated no new comments.
Suppressed comments (1)
src/commands/initramfs/image.rs:126
xargspasses arbitrary filenames from the staged tree intotouch. If any path begins with-,touchcan interpret it as an option. Add--after thetouchoptions so all subsequent arguments are treated as paths.
| xargs -0r touch -h -d "@${{SOURCE_DATE_EPOCH:-0}}"
|
One note on The normalization pass reads That also means the Worth a follow-up to plumb Unrelated FYI while in here: the pass zeroes |
mobileoverlord
left a comment
There was a problem hiding this comment.
Approving to land the LC_ALL=C pins, which are the load-bearing part — rootfs/install.rs (collation decides which kernel binary Image points at) and sdk/install.rs (preset first-match-wins decides which units end up enabled) were real latent bugs, not cosmetics.
Two follow-ups tracked separately rather than held against this PR:
- #203 purges the ~14MB of dnf/rpm state that
cp -acarries into the staged tree. The cpio is not byte-reproducible without it — the rpmdb stamps INSTALLTIME/INSTALLTID per package andvar/cache/dnfholds generated repodata, so mtime normalization alone doesn't get there. That PR needs to rebase so its purge sits above the touch pass here. SOURCE_DATE_EPOCHwiring, per my comment above.
Nit for whenever you're next in this file, not worth a round trip: the case block emits all four branches regardless of the initramfs_filesystem argument, so the format loops in test_cpio_entry_order_is_locale_independent, test_all_cpio_formats_get_normalized_tree and test_gzip_omits_timestamp assert on text that's present for every input. They read as per-format coverage but aren't — one call would do.
The purge missed var/log. rootfs/install.rs omits $DNF_SDK_HOST_OPTS,
which is what redirects logdir/cachedir/persistdir at the SDK prefix --
so the same omission that puts var/cache/dnf and var/lib/dnf in the
sysroot puts dnf.log, dnf.rpm.log and hawkey.log in var/log, every line
wall-clock stamped. Both images now remove them, and both tests assert
all six paths; deleting the new `rm -f` fails them.
Dropped the `!contains("$ROOTFS_SYSROOT/var/lib/rpm")` guard from both
tests. That string has no occurrences to begin with, so the assertion
could not fail, and the build-ID query it claimed to protect is spelled
`--root "$ROOTFS_SYSROOT"` with `--dbpath`. A test that cannot fail is
worse than no test: it reads as coverage.
Scoped the reproducibility claim to what it earns. Removing this state
is necessary but not sufficient -- `cpio --reproducible` is
--device-independent on GNU cpio 2.15 and does not normalize mtime, and
the removal itself restamps the directories it empties. That half is
#199's. The comments say so rather than implying the image lands
reproducible here.
Adds the CHANGELOG entry, including the one consumer this can surprise:
anything running `rpm -qa` against a built image rather than the sysroot.
No description provided.