Rust
mkSecureArtifact detects a Rust project by a Cargo.toml at the root of
src. It builds the crate with rustPlatform.buildRustPackage from a vendored
Cargo.lock and hands the result to mkHardenedImage.
The marker
The primary marker is Cargo.toml. A rust-toolchain.toml alongside it is read
for the toolchain channel and recorded as the buildConfigFile.
Required and optional ecosystemArgs
cargoLock(required) — a vendored relative path toCargo.lock, written exactly as./Cargo.lock.outputHashes(optional) —cargoLock.outputHashesfor git dependencies. Git deps have no crates.io checksum, so they need an explicit"<crate>-<version>" -> sha256entry. Omit it entirely when the lock has no git dependencies.
The vendored Cargo.lock / no-IFD rule
This one bites people, so it’s worth stating plainly: cargoLock must be a
vendored relative path, never "${src}/Cargo.lock". Reading the lock out of
the fetched source is an import-from-derivation — nix flake check --no-build
can’t evaluate it, and the repo’s no-ifd-lockfile lint rejects it. The emitter
even asserts against a /nix/store/ string sneaking in and throws with a
pointer to this rule. Copy Cargo.lock into your repo and reference it
relatively.
hb.mkSecureArtifact {
name = "my-cli";
version = "0.9.0";
src = ./.;
ecosystemArgs = {
cargoLock = ./Cargo.lock; # vendored — NOT "${src}/Cargo.lock"
# outputHashes = { "some-git-crate-1.2.3" = "sha256-…"; };
};
image.cmd = [ "/bin/my-cli" ];
}
Derivation-first alternative
If your crate needs build inputs, features, or flags the emitter doesn’t take, build it yourself and image it directly:
let
myCli = pkgs.rustPlatform.buildRustPackage {
pname = "my-cli";
version = "0.9.0";
src = ./.;
cargoLock.lockFile = ./Cargo.lock; # still vendored, still relative
buildInputs = [ pkgs.openssl ];
nativeBuildInputs = [ pkgs.pkg-config ];
};
in
hb.mkHardenedImage {
name = "my-cli";
version = "0.9.0";
package = myCli;
cmd = [ "/bin/my-cli" ];
}
FIPS composition (aws-lc-rs, ADR-0028)
Rust’s FIPS path is aws-lc-rs in FIPS mode (ADR-0028), not a flag you flip on
an ordinary build. To ship a FIPS Rust artifact you build the crate under the
FIPS package set — which composes the aws-lc-rs FIPS module — and only then pass
fips = true so the image carries truthful FIPS labels. As everywhere,
fips = true is a truthfulness contract: it labels; it does not convert a
non-FIPS build. See FIPS.
SBOM
Rust crates are folded into the CycloneDX SBOM automatically — the SBOM builder
reads the Cargo.lock inside the vendored cargoDeps on the finished
derivation, so no extra configuration is needed. See SBOMs.