feat: Add reproducible builds release workflows and push images to DockerHub #12
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: reproducible-build | |
on: | |
workflow_dispatch: {} | |
schedule: | |
- cron: "0 1 */2 * *" # Every 2 days to catch issues early | |
pull_request: | |
types: [opened, synchronize, labeled] | |
paths: | |
- "Makefile" | |
- "Dockerfile.reproducible" | |
- ".github/workflows/reproducible-build.yml" | |
- "Cargo.toml" | |
- "Cargo.lock" | |
jobs: | |
build-x86_64: | |
name: test reproducible builds (x86_64) | |
runs-on: ubuntu-latest | |
# Run on schedule, workflow_dispatch, or PRs with the 'test-reproducible' label | |
if: > | |
github.event_name == 'schedule' || | |
github.event_name == 'workflow_dispatch' || | |
contains(github.event.pull_request.labels.*.name, 'test-reproducible') | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
with: | |
driver: docker # Use docker driver instead of docker-container for reproducibility | |
- name: Build first reproducible Docker image | |
run: | | |
echo "=== Building first Docker image (x86_64) ===" | |
docker build -f Dockerfile.reproducible \ | |
--build-arg RUST_TARGET="x86_64-unknown-linux-gnu" \ | |
--build-arg RUST_IMAGE="rust:1.86-bullseye@sha256:1110399f568f1dbe838e58f15b4162d899cb95f450f5f0ffa739614f3a4c32f1" \ | |
-t build-lighthouse-1 . | |
echo "=== Extracting binary from first build ===" | |
docker create --name extract-lighthouse-1 build-lighthouse-1 | |
docker cp extract-lighthouse-1:/lighthouse ./lighthouse-build-1 | |
docker rm extract-lighthouse-1 | |
echo "=== First build info ===" | |
ls -la lighthouse-build-1 | |
sha256sum lighthouse-build-1 | |
file lighthouse-build-1 | |
- name: Clean Docker state completely | |
run: | | |
echo "=== Cleaning Docker state ===" | |
# Remove the first image | |
docker rmi build-lighthouse-1 || true | |
# Remove all build cache (important for reproducibility testing) | |
docker buildx prune -f || true | |
docker system prune -f || true | |
# Clear any remaining containers | |
docker container prune -f || true | |
echo "=== Docker state cleaned ===" | |
docker images | |
docker ps -a | |
- name: Build second reproducible Docker image | |
run: | | |
echo "=== Building second Docker image (x86_64) ===" | |
docker build -f Dockerfile.reproducible \ | |
--build-arg RUST_TARGET="x86_64-unknown-linux-gnu" \ | |
--build-arg RUST_IMAGE="rust:1.86-bullseye@sha256:1110399f568f1dbe838e58f15b4162d899cb95f450f5f0ffa739614f3a4c32f1" \ | |
-t build-lighthouse-2 . | |
echo "=== Extracting binary from second build ===" | |
docker create --name extract-lighthouse-2 build-lighthouse-2 | |
docker cp extract-lighthouse-2:/lighthouse ./lighthouse-build-2 | |
docker rm extract-lighthouse-2 | |
echo "=== Second build info ===" | |
ls -la lighthouse-build-2 | |
sha256sum lighthouse-build-2 | |
file lighthouse-build-2 | |
- name: Compare Docker-built binaries | |
run: | | |
echo "=== Comparing Docker-built binaries (x86_64) ===" | |
echo "Build 1 info:" | |
ls -la lighthouse-build-1 | |
echo "Build 2 info:" | |
ls -la lighthouse-build-2 | |
echo "=== SHA256 checksums ===" | |
sha256sum lighthouse-build-* | |
echo "=== Binary comparison ===" | |
if cmp lighthouse-build-1 lighthouse-build-2; then | |
echo "✅ SUCCESS: Docker-built binaries are identical!" | |
echo "✅ Reproducible Docker build PASSED for x86_64" | |
else | |
echo "❌ FAILED: Docker-built binaries differ" | |
echo "First 10 differences:" | |
cmp -l lighthouse-build-1 lighthouse-build-2 | head -10 | |
exit 1 | |
fi | |
build-aarch64: | |
name: test reproducible builds (aarch64) | |
runs-on: ubuntu-24.04-arm | |
# Run on schedule, workflow_dispatch, or PRs with the 'test-reproducible' label | |
if: > | |
github.event_name == 'schedule' || | |
github.event_name == 'workflow_dispatch' || | |
contains(github.event.pull_request.labels.*.name, 'test-reproducible') | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
with: | |
driver: docker | |
- name: Build first reproducible Docker image | |
run: | | |
echo "=== Building first Docker image (aarch64) ===" | |
docker build -f Dockerfile.reproducible \ | |
--platform linux/arm64 \ | |
--build-arg RUST_TARGET="aarch64-unknown-linux-gnu" \ | |
--build-arg RUST_IMAGE="rust:1.86-bullseye@sha256:36053eabadeb701e3e0406610a2ce72ccfa10b7828963cd08cffdcf660518b27" \ | |
-t build-lighthouse-1-arm64 . | |
echo "=== Extracting binary from first build ===" | |
docker create --name extract-lighthouse-1-arm64 build-lighthouse-1-arm64 | |
docker cp extract-lighthouse-1-arm64:/lighthouse ./lighthouse-build-1-arm64 | |
docker rm extract-lighthouse-1-arm64 | |
echo "=== First build info ===" | |
ls -la lighthouse-build-1-arm64 | |
sha256sum lighthouse-build-1-arm64 | |
file lighthouse-build-1-arm64 | |
- name: Clean Docker state completely | |
run: | | |
echo "=== Cleaning Docker state ===" | |
docker rmi build-lighthouse-1-arm64 || true | |
docker buildx prune -f || true | |
docker system prune -f || true | |
docker container prune -f || true | |
echo "=== Docker state cleaned ===" | |
docker images | |
docker ps -a | |
- name: Build second reproducible Docker image | |
run: | | |
echo "=== Building second Docker image (aarch64) ===" | |
docker build -f Dockerfile.reproducible \ | |
--platform linux/arm64 \ | |
--build-arg RUST_TARGET="aarch64-unknown-linux-gnu" \ | |
--build-arg RUST_IMAGE="rust:1.86-bullseye@sha256:36053eabadeb701e3e0406610a2ce72ccfa10b7828963cd08cffdcf660518b27" \ | |
-t build-lighthouse-2-arm64 . | |
echo "=== Extracting binary from second build ===" | |
docker create --name extract-lighthouse-2-arm64 build-lighthouse-2-arm64 | |
docker cp extract-lighthouse-2-arm64:/lighthouse ./lighthouse-build-2-arm64 | |
docker rm extract-lighthouse-2-arm64 | |
echo "=== Second build info ===" | |
ls -la lighthouse-build-2-arm64 | |
sha256sum lighthouse-build-2-arm64 | |
file lighthouse-build-2-arm64 | |
- name: Compare Docker-built binaries | |
run: | | |
echo "=== Comparing Docker-built binaries (aarch64) ===" | |
echo "Build 1 info:" | |
ls -la lighthouse-build-1-arm64 | |
echo "Build 2 info:" | |
ls -la lighthouse-build-2-arm64 | |
echo "=== SHA256 checksums ===" | |
sha256sum lighthouse-build-*-arm64 | |
echo "=== Binary comparison ===" | |
if cmp lighthouse-build-1-arm64 lighthouse-build-2-arm64; then | |
echo "✅ SUCCESS: Docker-built binaries are identical!" | |
echo "✅ Reproducible Docker build PASSED for aarch64" | |
else | |
echo "❌ FAILED: Docker-built binaries differ" | |
echo "First 10 differences:" | |
cmp -l lighthouse-build-1-arm64 lighthouse-build-2-arm64 | head -10 | |
exit 1 | |
fi | |
summary: | |
name: reproducible build summary | |
runs-on: ubuntu-latest | |
needs: [build-x86_64, build-aarch64] | |
if: always() | |
steps: | |
- name: Report results | |
run: | | |
echo "## 🔄 Reproducible Build Test Results" | |
echo "" | |
# Show trigger reason | |
if [[ "${{ github.event_name }}" == "schedule" ]]; then | |
echo "**Trigger**: Scheduled check (every 2 days)" | |
elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then | |
echo "**Trigger**: Manual run" | |
elif [[ "${{ github.event_name }}" == "pull_request" ]]; then | |
echo "**Trigger**: PR with 'test-reproducible' label" | |
fi | |
echo "" | |
if [[ "${{ needs.build-x86_64.result }}" == "success" ]]; then | |
echo "✅ **x86_64**: Reproducible builds PASSED" | |
elif [[ "${{ needs.build-x86_64.result }}" == "skipped" ]]; then | |
echo "⏭️ **x86_64**: Skipped (no label or wrong trigger)" | |
else | |
echo "❌ **x86_64**: Reproducible builds FAILED" | |
fi | |
if [[ "${{ needs.build-aarch64.result }}" == "success" ]]; then | |
echo "✅ **aarch64**: Reproducible builds PASSED" | |
elif [[ "${{ needs.build-aarch64.result }}" == "skipped" ]]; then | |
echo "⏭️ **aarch64**: Skipped (no label or wrong trigger)" | |
else | |
echo "❌ **aarch64**: Reproducible builds FAILED" | |
fi | |
echo "" | |
if [[ "${{ needs.build-x86_64.result }}" == "success" ]] \ | |
&& [[ "${{ needs.build-aarch64.result }}" == "success" ]]; then | |
echo "🎉 **Overall**: All reproducible builds are working correctly!" | |
echo "Docker containers are reproducible." | |
elif [[ "${{ needs.build-x86_64.result }}" == "skipped" ]] \ | |
&& [[ "${{ needs.build-aarch64.result }}" == "skipped" ]]; then | |
echo "⏭️ **Overall**: Tests were skipped (add 'test-reproducible' label to run on PRs)" | |
else | |
echo "⚠️ **Overall**: Some reproducible builds failed" | |
echo "Check the logs above for details" | |
exit 1 | |
fi |