diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 4353aa1..d726472 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -11,6 +11,11 @@ on: required: false type: boolean default: true + build-docker: + description: 'Build Docker' + required: false + type: boolean + default: true draft-release: description: 'Draft Release' required: false @@ -79,6 +84,8 @@ jobs: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y - uses: actions/checkout@v4 # must install git before checkout and set safe.directory after checkout because of container + with: + fetch-depth: 0 - name: Prepare filename run: echo "OUTPUT_FILENAME=rbuilder-${VERSION}-${{ matrix.configs.target }}" >> $GITHUB_ENV @@ -87,7 +94,7 @@ jobs: run: | git config --global --add safe.directory "$(pwd)" . $HOME/.cargo/env - cargo build --release --target ${{ matrix.configs.target }} + make build-reproducible TARGET=${{ matrix.configs.target }} ./target/${{ matrix.configs.target }}/release/rbuilder version - name: Upload artifact @@ -96,6 +103,60 @@ jobs: name: ${{ env.OUTPUT_FILENAME }} path: target/${{ matrix.configs.target }}/release/rbuilder + build-docker: + name: Build and publish Docker image + if: ${{ github.event.inputs.build-docker == 'true' || github.event_name == 'push'}} + needs: extract-version + runs-on: warp-ubuntu-latest-x64-16x + env: + VERSION: ${{ needs.extract-version.outputs.VERSION }} + permissions: + contents: read + packages: write + + steps: + - name: Checkout sources + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Docker metadata + uses: docker/metadata-action@v5 + id: meta + with: + images: ghcr.io/${{ github.repository }} + labels: org.opencontainers.image.source=${{ github.repositoryUrl }} + tags: | + type=sha + type=semver,pattern={{version}},value=${{ env.VERSION }} + type=semver,pattern={{major}}.{{minor}},value=${{ env.VERSION }} + type=semver,pattern={{major}},value=${{ env.VERSION }} + type=raw,value=latest,enable=${{ !contains(env.VERSION, '-') }} + + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push Docker image + uses: docker/build-push-action@v5 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64 + provenance: false + cache-from: type=gha + cache-to: type=gha,mode=max + build-args: | + BUILD_PROFILE=release + draft-release: name: Draft release if: ${{ github.event.inputs.draft-release == 'true' || github.event_name == 'push'}} # when manually triggered or version tagged diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..4001657 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,21 @@ +FROM rust:1.82-bullseye@sha256:c42c8ca762560c182ba30edda0e0d71a8604040af2672370559d7e854653c66d AS builder + +ARG BUILD_PROFILE=release +ENV BUILD_PROFILE=$BUILD_PROFILE + +RUN apt-get update && apt-get install -y \ + libclang-dev=1:11.0-51+nmu5 \ + protobuf-compiler=3.12.4-1+deb11u1 + +# Clone the repository at the specific branch +WORKDIR /app +COPY ./ /app + +# Build the project with the reproducible settings +RUN make build-reproducible + +RUN mv /app/target/x86_64-unknown-linux-gnu/"${BUILD_PROFILE}"/rbuilder /rbuilder + +FROM gcr.io/distroless/cc-debian12:nonroot-6755e21ccd99ddead6edc8106ba03888cbeed41a +COPY --from=builder /rbuilder /rbuilder +ENTRYPOINT [ "/rbuilder" ] diff --git a/Makefile b/Makefile index 627e31e..6ee25cb 100644 --- a/Makefile +++ b/Makefile @@ -25,6 +25,41 @@ clean: ## Clean up build: ## Build static binary for x86_64 cargo build --release --target x86_64-unknown-linux-gnu +# Environment variables for reproducible builds +# Initialize RUSTFLAGS +RUST_BUILD_FLAGS = + +# Remove build ID from the binary to ensure reproducibility across builds +RUST_BUILD_FLAGS += -C link-arg=-Wl,--build-id=none + +# Remove metadata hash from symbol names to ensure reproducible builds +RUST_BUILD_FLAGS += -C metadata='' + +# Set timestamp from last git commit for reproducible builds +SOURCE_DATE ?= $(shell git log -1 --pretty=%ct) + +# Disable incremental compilation to avoid non-deterministic artifacts +CARGO_INCREMENTAL_VAL = 0 + +# Set C locale for consistent string handling and sorting +LOCALE_VAL = C + +# Set UTC timezone for consistent time handling across builds +TZ_VAL = UTC + +# Set the target for the build, default to x86_64 +TARGET ?= x86_64-unknown-linux-gnu + +.PHONY: build-reproducible +build-reproducible: ## Build reproducible static binary for x86_64 + # Set timestamp from last git commit for reproducible builds + SOURCE_DATE_EPOCH=$(SOURCE_DATE) \ + RUSTFLAGS="${RUST_BUILD_FLAGS} --remap-path-prefix $$(pwd)=." \ + CARGO_INCREMENTAL=${CARGO_INCREMENTAL_VAL} \ + LC_ALL=${LOCALE_VAL} \ + TZ=${TZ_VAL} \ + cargo build --release --locked --target $(TARGET) + .PHONY: docker-image docker-image: ## Build a rbuilder Docker image docker build --platform linux/amd64 . -t rbuilder