Generally this is a sane default and it's especially
important after the recent decoupling of the images
where different debian bases are used for each image.
Piping get.volta.sh into bash installs whatever version volta.sh
currently advertises as the latest. Download a fixed volta release
instead and verify its SHA-256 before extracting it, so the image
build is more reproducible and a tampered download fails the build.
Node and npm are still fetched by volta without any integrity check,
since volta does not verify its downloads.
Piping sh.rustup.rs into sh runs whatever script the server currently
serves. Download a fixed rustup-init version instead and verify its
SHA-256 before running it, so the image build is more reproducible and
a tampered download fails the build.
The variable is only meaningful together with the /cargo-target volume
that container-run.sh mounts, but the image exported it to every user,
including CI jobs that run the image through `container:` and mount no
such volume. Those builds wrote to a path nothing else knew about, which
defeated Rust caching and forced workarounds.
Release builds and local containerized builds go through
container-run.sh and are unaffected, on both Linux and Android.
Cargo removed the default "object" scope from the release profile in
rust-lang/cargo#17424, so enabling the feature in .cargo/config.toml no
longer trims anything, silently. The scope has to be set per profile,
and that key cannot be committed to .cargo/config.toml because stable
cargo rejects it rather than ignoring it.
The image reference files, and the Dockerfiles that build on our own
images, named only a tag. Tags are mutable: whoever can push to the
registry can point one at a different image, and then everybody
silently builds in something else. We never reuse a tag, since it is
the commit the image was built from, but that is a promise the files
themselves do not make and nobody downstream can check.
Name the images by digest instead, everywhere they are referenced. The
build environment is an input to a reproducible build just as much as
the source is, so it has to be named as precisely.
test/scripts/Dockerfile loses its `latest` default rather than gaining
a digest. Its container-run.sh always passes the image in, read from
building/linux-container-image.txt, so the default only existed to be
silently wrong.
Which commit an image was built from is still in git: the signed commit
adding its signatures names the tag in its message and the digest in
the directory it adds under building/sigstore/.
build-and-publish-container-image.sh now also prints the line to put in
the reference file, so the digest never has to be looked up by hand.
The build script previously read the Rust version out of
rust-toolchain.toml and passed it to the image build. This coupled the
container image to the toolchain file: the two pin the same version and,
since Rust is preinstalled in the image, they must match exactly. A
mismatch is not a hard error either -- rustup silently auto-installs the
toolchain named in rust-toolchain.toml on first use, but only the bare
toolchain, without the clippy component or the targets baked into the
image, so clippy and cross-compilation jobs fail with 'missing
component/target' errors.
That coupling forced a Rust bump to rebuild and republish the image in
the same PR as the rust-toolchain.toml change. Because the image is
tagged with the git commit it was built from, rebasing that PR onto a
moved main rewrote the commit hash and left the published tag pointing
at a dangling commit.
Setting the version directly in the Dockerfile makes the image build
self-contained: it no longer needs the PR's rust-toolchain.toml. The
image can now be built, signed and pushed straight to main from a
permanent commit, and rust-toolchain.toml and the image pin bumped to
match in a later, rebase-safe change.