diff --git a/.cargo-auditable-version b/.cargo-auditable-version new file mode 100644 index 000000000..8bd6ba8c5 --- /dev/null +++ b/.cargo-auditable-version @@ -0,0 +1 @@ +0.7.5 diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index f4a152475..71cde3ae3 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -146,6 +146,13 @@ jobs: if: steps.platform-check.outputs.skip != 'true' && matrix.platform == 'mac' uses: dtolnay/rust-toolchain@stable + - name: Install cargo-auditable (Mac) + if: steps.platform-check.outputs.skip != 'true' && matrix.platform == 'mac' + run: | + v="$(cat .cargo-auditable-version)" + [ -n "$v" ] || { echo "ERROR: could not read cargo-auditable version from .cargo-auditable-version"; exit 1; } + cargo install cargo-auditable@"$v" --locked + - name: Build binaries (Mac) if: steps.platform-check.outputs.skip != 'true' && matrix.platform == 'mac' env: @@ -157,7 +164,7 @@ jobs: if [[ -n "$FEATURES" ]]; then FEATURE_FLAG="--features $FEATURES" fi - cargo build --profile ${{ matrix.profile }} $FEATURE_FLAG \ + cargo auditable build --locked --profile ${{ matrix.profile }} $FEATURE_FLAG \ --bin rbuilder \ --bin rbuilder-operator \ --bin tbv-bidding-service \ diff --git a/Makefile b/Makefile index 1df6805a6..626202a79 100644 --- a/Makefile +++ b/Makefile @@ -71,21 +71,32 @@ else BUILD_ENV = endif +# The cargo-auditable embedded data is sorted and timestamp-free +CARGO_AUDITABLE_VERSION := $(shell cat $(dir $(firstword $(MAKEFILE_LIST)))/.cargo-auditable-version 2>/dev/null) +ifeq ($(strip $(CARGO_AUDITABLE_VERSION)),) +$(error could not read cargo-auditable version from .cargo-auditable-version) +endif + +.PHONY: install-cargo-auditable +install-cargo-auditable: + @cargo install --list | grep -qxF 'cargo-auditable v$(CARGO_AUDITABLE_VERSION):' \ + || cargo install cargo-auditable@$(CARGO_AUDITABLE_VERSION) --locked + .PHONY: build -build: ## Build (release version) - $(BUILD_ENV) cargo build --features "$(FEATURES) jemalloc-unprefixed" --locked $(if $(BUILD_TARGET),--target $(BUILD_TARGET)) --profile $(BUILD_PROFILE) --workspace +build: install-cargo-auditable ## Build (release version) + $(BUILD_ENV) cargo auditable build --features "$(FEATURES) jemalloc-unprefixed" --locked $(if $(BUILD_TARGET),--target $(BUILD_TARGET)) --profile $(BUILD_PROFILE) --workspace .PHONY: build-bid-scraper -build-bid-scraper: ## Build the bid-scraper binary (release version) - $(BUILD_ENV) cargo build --features "$(FEATURES)" --locked $(if $(BUILD_TARGET),--target $(BUILD_TARGET)) --bin bid-scraper --profile $(BUILD_PROFILE) +build-bid-scraper: install-cargo-auditable ## Build the bid-scraper binary (release version) + $(BUILD_ENV) cargo auditable build --features "$(FEATURES)" --locked $(if $(BUILD_TARGET),--target $(BUILD_TARGET)) --bin bid-scraper --profile $(BUILD_PROFILE) .PHONY: build-rbuilder-operator -build-rbuilder-operator: ## Build the rbuilder-operator binary (release version) - $(BUILD_ENV) cargo build --features "$(FEATURES) jemalloc-unprefixed" --locked $(if $(BUILD_TARGET),--target $(BUILD_TARGET)) --bin rbuilder-operator --profile $(BUILD_PROFILE) +build-rbuilder-operator: install-cargo-auditable ## Build the rbuilder-operator binary (release version) + $(BUILD_ENV) cargo auditable build --features "$(FEATURES) jemalloc-unprefixed" --locked $(if $(BUILD_TARGET),--target $(BUILD_TARGET)) --bin rbuilder-operator --profile $(BUILD_PROFILE) .PHONY: build-rbuilder-rebalancer -build-rbuilder-rebalancer: ## Build the rbuilder-rebalancer binary (release version) - $(BUILD_ENV) cargo build --features "$(FEATURES) jemalloc-unprefixed" --locked $(if $(BUILD_TARGET),--target $(BUILD_TARGET)) --bin rbuilder-rebalancer --profile $(BUILD_PROFILE) +build-rbuilder-rebalancer: install-cargo-auditable ## Build the rbuilder-rebalancer binary (release version) + $(BUILD_ENV) cargo auditable build --features "$(FEATURES) jemalloc-unprefixed" --locked $(if $(BUILD_TARGET),--target $(BUILD_TARGET)) --bin rbuilder-rebalancer --profile $(BUILD_PROFILE) .PHONY: build-dev build-dev: ## Build (debug version) @@ -106,9 +117,10 @@ docker-image-test-relay: ## Build a test relay Docker image ##@ Debian Packages # Define binary paths for smart dependencies -BID_SCRAPER_BIN := target/$(if $(BUILD_TARGET),$(BUILD_TARGET)/)$(BUILD_PROFILE)/bid-scraper -RBUILDER_OPERATOR_BIN := target/$(if $(BUILD_TARGET),$(BUILD_TARGET)/)$(BUILD_PROFILE)/rbuilder-operator -RBUILDER_REBALANCER_BIN := target/$(if $(BUILD_TARGET),$(BUILD_TARGET)/)$(BUILD_PROFILE)/rbuilder-rebalancer +BUILD_OUTPUT_DIR := target/$(if $(BUILD_TARGET),$(BUILD_TARGET)/)$(BUILD_PROFILE) +BID_SCRAPER_BIN := $(BUILD_OUTPUT_DIR)/bid-scraper +RBUILDER_OPERATOR_BIN := $(BUILD_OUTPUT_DIR)/rbuilder-operator +RBUILDER_REBALANCER_BIN := $(BUILD_OUTPUT_DIR)/rbuilder-rebalancer .PHONY: install-cargo-deb install-cargo-deb: diff --git a/README.md b/README.md index 0291fcc88..7778de613 100644 --- a/README.md +++ b/README.md @@ -156,25 +156,36 @@ curl http://localhost:5555/relay/v1/data/bidtraces/proposer_payload_delivered ### Reproducible builds -You only need to set the `SOURCE_DATE_EPOCH` environment variable to ensure that the build is reproducible: +`make build` produces reproducible binaries on x86_64: it sets the `SOURCE_DATE_EPOCH` +environment variable (last commit timestamp) and the required compiler flags automatically: ```bash -# Use last commit timestamp as the build date -$ export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) - # build #1 $ rm -rf target/ -$ cargo build --release -$ sha256sum target/release/rbuilder -d92ac33b94e16ed4a035b9dd52108fe78bd9bb160a91fced8e439f59b84c3207 target/release/rbuilder +$ make build +$ sha256sum target/x86_64-unknown-linux-gnu/reproducible/rbuilder + target/x86_64-unknown-linux-gnu/reproducible/rbuilder # build #2 $ rm -rf target/ -$ cargo build --release -$ sha256sum target/release/rbuilder -d92ac33b94e16ed4a035b9dd52108fe78bd9bb160a91fced8e439f59b84c3207 target/release/rbuilder +$ make build +$ sha256sum target/x86_64-unknown-linux-gnu/reproducible/rbuilder + target/x86_64-unknown-linux-gnu/reproducible/rbuilder + +# the two hashes are identical ``` +### Auditable builds + +Release builds (`make build`, the Docker images, and the released binaries) go through +[`cargo auditable`](https://github.com/rust-secure-code/cargo-auditable), which embeds the full +dependency list into each binary. The embedded data can be read by scanners such as +`cargo audit bin`, `trivy`, `grype`, and `syft`, so both the binaries and the container images +built from them can be scanned for Rust dependencies. + +The pinned `cargo-auditable` version used by all build paths lives in +[`.cargo-auditable-version`](./.cargo-auditable-version). + --- ## Release Stability and Development Process diff --git a/crates/bid-scraper/src/best_bid_ws_connector.rs b/crates/bid-scraper/src/best_bid_ws_connector.rs index 24ae1830e..325ac9450 100644 --- a/crates/bid-scraper/src/best_bid_ws_connector.rs +++ b/crates/bid-scraper/src/best_bid_ws_connector.rs @@ -85,6 +85,7 @@ impl BestBidWSConnector(request: R) -> Result where R: IntoClientRequest + Unpin, diff --git a/crates/eth-sparse-mpt/src/utils.rs b/crates/eth-sparse-mpt/src/utils.rs index 42a31abfa..4c5f19e8b 100644 --- a/crates/eth-sparse-mpt/src/utils.rs +++ b/crates/eth-sparse-mpt/src/utils.rs @@ -126,7 +126,7 @@ pub fn mismatch(xs: &[u8], ys: &[u8]) -> usize { #[inline] fn mismatch_chunks(xs: &[u8], ys: &[u8]) -> usize { - let off = std::iter::zip(xs.chunks_exact(N), ys.chunks_exact(N)) + let off = std::iter::zip(xs.as_chunks::().0, ys.as_chunks::().0) .take_while(|(x, y)| x == y) .count() * N; diff --git a/crates/rbuilder-operator/src/bidding_service_wrapper/mod.rs b/crates/rbuilder-operator/src/bidding_service_wrapper/mod.rs index 40a2bf40f..b05d93c7f 100644 --- a/crates/rbuilder-operator/src/bidding_service_wrapper/mod.rs +++ b/crates/rbuilder-operator/src/bidding_service_wrapper/mod.rs @@ -1,5 +1,7 @@ #[rustfmt::skip] +#[allow(clippy::result_large_err)] pub mod bidding_service; +#[allow(clippy::result_large_err)] pub mod client; pub mod conversion; pub mod fast_streams; diff --git a/crates/rbuilder/src/mev_boost/bloxroute_grpc.rs b/crates/rbuilder/src/mev_boost/bloxroute_grpc.rs index a1a238ede..75267e5fc 100644 --- a/crates/rbuilder/src/mev_boost/bloxroute_grpc.rs +++ b/crates/rbuilder/src/mev_boost/bloxroute_grpc.rs @@ -14,6 +14,7 @@ use rbuilder_primitives::mev_boost::SubmitBlockRequest; use std::sync::Arc; /// Bloxroute gRPC types. +#[allow(clippy::result_large_err)] pub mod types { tonic::include_proto!("bloxroute"); } diff --git a/docker/Dockerfile.rbuilder b/docker/Dockerfile.rbuilder index 81dde36ae..d74882ecc 100644 --- a/docker/Dockerfile.rbuilder +++ b/docker/Dockerfile.rbuilder @@ -36,6 +36,10 @@ RUN set -eux; \ rm -rf /tmp/sccache.tar.gz /tmp/sccache-v0.8.2-${ARCH_TAG} RUN cargo install cargo-chef --version ^0.1 +COPY .cargo-auditable-version /tmp/cargo-auditable-version +RUN v="$(cat /tmp/cargo-auditable-version)"; \ + [ -n "$v" ] || { echo "ERROR: could not read cargo-auditable version from .cargo-auditable-version"; exit 1; }; \ + cargo install cargo-auditable@"$v" --locked ENV CARGO_HOME=/usr/local/cargo @@ -72,14 +76,18 @@ ARG FEATURES RUN --mount=type=cache,target=/usr/local/cargo/registry \ --mount=type=cache,target=/usr/local/cargo/git \ --mount=type=cache,target=$SCCACHE_DIR,sharing=locked \ - cargo build --release --features="$FEATURES" --package=${RBUILDER_BIN} + cargo auditable build --release --features="$FEATURES" --package=${RBUILDER_BIN} +RUN readelf -S /app/target/release/${RBUILDER_BIN} | grep -q '\.dep-v0' \ + || { echo "ERROR: .dep-v0 audit section missing from ${RBUILDER_BIN}"; exit 1; } FROM builder AS test-relay ARG FEATURES RUN --mount=type=cache,target=/usr/local/cargo/registry \ --mount=type=cache,target=/usr/local/cargo/git \ --mount=type=cache,target=$SCCACHE_DIR,sharing=locked \ - cargo build --release --features="$FEATURES" --package=test-relay + cargo auditable build --release --features="$FEATURES" --package=test-relay +RUN readelf -S /app/target/release/test-relay | grep -q '\.dep-v0' \ + || { echo "ERROR: .dep-v0 audit section missing from test-relay"; exit 1; } # Runtime container for test-relay diff --git a/docker/Dockerfile.reproducible b/docker/Dockerfile.reproducible index c54eeafe4..1b965813b 100644 --- a/docker/Dockerfile.reproducible +++ b/docker/Dockerfile.reproducible @@ -10,9 +10,17 @@ RUN apt-get -o Acquire::Check-Valid-Until=false update && \ libclang-dev \ protobuf-compiler \ cmake +COPY .cargo-auditable-version /tmp/cargo-auditable-version +RUN v="$(cat /tmp/cargo-auditable-version)"; \ + [ -n "$v" ] || { echo "ERROR: could not read cargo-auditable version from .cargo-auditable-version"; exit 1; }; \ + cargo install cargo-auditable@"$v" --locked WORKDIR /build COPY . . RUN SOURCE_DATE=1730000000 make build && make build-deb +RUN set -e; for bin in rbuilder rbuilder-operator tbv-bidding-service reth-rbuilder bid-scraper rbuilder-rebalancer; do \ + readelf -S "/build/target/x86_64-unknown-linux-gnu/reproducible/${bin}" | grep -q '\.dep-v0' \ + || { echo "ERROR: .dep-v0 audit section missing from ${bin}"; exit 1; }; \ + done FROM scratch AS artifacts COPY --from=builder /build/target/x86_64-unknown-linux-gnu/ /