diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..43b68c9 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,151 @@ +name: Release + +on: + push: + tags: + - "v*" + workflow_dispatch: + inputs: + draft-release: + default: false + description: "Draft Release" + required: false + type: boolean + build-docker: + default: false + description: "Build Docker" + required: false + type: boolean + build-binary: + default: true + description: "Build Binary" + required: false + type: boolean + features: + default: '' + description: "Binary Compilation Features" + options: + - '' + - 'redact-sensitive' + required: false + type: choice + +jobs: + extract-version: + name: Extract version + runs-on: warp-ubuntu-2404-x64-2x + outputs: + VERSION: ${{ steps.extract_version.outputs.VERSION }} + steps: + - name: Extract version + id: extract_version + run: | + if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then + VERSION="${GITHUB_REF#refs/tags/}" + else + VERSION="$(echo ${GITHUB_SHA} | cut -c1-7)" + fi + echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT + echo "${VERSION}" + + echo "### Version: \`${VERSION}\`" >> $GITHUB_STEP_SUMMARY + echo "| | |" >> $GITHUB_STEP_SUMMARY + echo "| ------------------- | ---------------------- |" >> $GITHUB_STEP_SUMMARY + echo "| \`GITHUB_REF_TYPE\` | \`${GITHUB_REF_TYPE}\` |" >> $GITHUB_STEP_SUMMARY + echo "| \`GITHUB_REF_NAME\` | \`${GITHUB_REF_NAME}\` |" >> $GITHUB_STEP_SUMMARY + echo "| \`GITHUB_REF\` | \`${GITHUB_REF}\` |" >> $GITHUB_STEP_SUMMARY + echo "| \`GITHUB_SHA\` | \`${GITHUB_SHA}\` |" >> $GITHUB_STEP_SUMMARY + echo "| \`VERSION\` | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY + echo "| \`FEATURES\` | \`${{ github.event.inputs.features || 'none' }}\` |" >> $GITHUB_STEP_SUMMARY + + build-binary: + name: Build binary + needs: extract-version + if: ${{ github.event.inputs.build-binary == 'true' || github.event_name == 'push'}} # when manually triggered or version tagged + runs-on: ${{ matrix.configs.runner }} + permissions: + contents: write + packages: write + strategy: + matrix: + configs: + - target: x86_64-unknown-linux-gnu + runner: warp-ubuntu-latest-x64-32x + profile: reproducible + features: + - ${{ github.event.inputs.features || '' }} + + steps: + - uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Install rust + run: | + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y + + - name: Build reproducible binary with Docker + run: | + RUST_TOOLCHAIN=$(rustc --version | cut -d' ' -f2) + docker build \ + --build-arg "RUST_TOOLCHAIN=${RUST_TOOLCHAIN}" \ + --build-arg "FEATURES=${{ matrix.features }}" \ + --build-arg "VERSION=${{ needs.extract-version.outputs.VERSION }}" \ + -f Dockerfile.build-deb -t atp:release \ + --output type=local,dest=./target . + + - name: Upload attested-tls-proxy artifact + uses: actions/upload-artifact@v4 + with: + name: attested-tls-proxy-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.configs.target }}${{ matrix.features && '-' }}${{ matrix.features }} + path: target/${{ matrix.configs.profile }}/attested-tls-proxy + + - name: Upload *.deb package + uses: actions/upload-artifact@v4 + with: + name: deb-${{ needs.extract-version.outputs.VERSION }}-${{ matrix.configs.target }}${{ matrix.features && '-' }}${{ matrix.features }} + path: target/debian/*.deb + + + draft-release: + name: Draft release + if: ${{ github.event.inputs.draft-release == 'true' || github.event_name == 'push'}} # when manually triggered or version tagged + needs: [extract-version, build-binary] + runs-on: warp-ubuntu-2404-x64-16x + env: + VERSION: ${{ needs.extract-version.outputs.VERSION }} + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + merge-multiple: true + path: artifacts + + - name: Record artifacts checksums + working-directory: artifacts + run: | + find ./ || true + for file in *; do sha256sum "$file" >> sha256sums.txt; done; + cat sha256sums.txt + + - name: Create release draft + uses: softprops/action-gh-release@v2.0.5 + id: create-release-draft + with: + draft: true + files: artifacts/* + generate_release_notes: true + name: ${{ env.VERSION }} + tag_name: ${{ env.VERSION }} + + - name: Write Github Step Summary + run: | + echo "---" + echo "### Release Draft: ${{ env.VERSION }}" >> $GITHUB_STEP_SUMMARY + echo "${{ steps.create-release-draft.outputs.url }}" >> $GITHUB_STEP_SUMMARY diff --git a/Cargo.toml b/Cargo.toml index 3233bdc..7509be7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,9 +3,11 @@ members = [".", "dummy-attestation-server"] [package] name = "attested-tls-proxy" +description = "An HTTP attested TLS proxy server and client for secure communication with CVM services" version = "0.1.0" edition = "2024" license = "MIT" +repository = "https://github.com/flashbots/attested-tls-proxy" [dependencies] tokio = { version = "1.48.0", features = ["full"] } @@ -56,3 +58,29 @@ tdx-quote = { version = "0.0.4", features = ["mock"] } [features] default = ["azure"] azure = ["tss-esapi", "az-tdx-vtpm"] + +[package.metadata.deb] +maintainer = "Flashbots Team " +depends = "$auto" +section = "network" +priority = "optional" +maintainer-scripts = "pkg/debian" +assets = [ + [ + "target/reproducible/attested-tls-proxy", + "usr/bin/", + "755", + ], + [ + "LICENSE", + "usr/share/doc/attested-tls-proxy/", + "644", + ], +] +systemd-units = { enable = false, start = false, unit-name = "attested-tls-proxy" } + +[profile.reproducible] +inherits = "release" +lto = "thin" +panic = "abort" +incremental = false diff --git a/Dockerfile.build-deb b/Dockerfile.build-deb new file mode 100644 index 0000000..dc2ff1d --- /dev/null +++ b/Dockerfile.build-deb @@ -0,0 +1,18 @@ +ARG RUST_TOOLCHAIN=1.89.0 +FROM docker.io/rust:$RUST_TOOLCHAIN-trixie AS builder + +ARG FEATURES VERSION +# Switch to snapshot repository +RUN sed -i '/^# http/{N;s|^# \(http[^ ]*\)\nURIs: .*|# \1\nURIs: \1|}' /etc/apt/sources.list.d/debian.sources +RUN apt-get -o Acquire::Check-Valid-Until=false update && \ + apt-get install -y \ + pkg-config clang libclang-dev \ + openssl libssl-dev libtss2-dev \ + cmake + +WORKDIR /build +COPY . . +RUN make build && make build-deb + +FROM scratch AS artifacts +COPY --from=builder /build/target/x86_64-unknown-linux-gnu/ / diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2a1b849 --- /dev/null +++ b/Makefile @@ -0,0 +1,112 @@ +# Heavily inspired by rbuilder: https://github.com/flashbots/rbuilder/blob/develop/Makefile +.DEFAULT_GOAL := help + +GIT_VER ?= $(shell git describe --tags --always --dirty="-dev") +GIT_TAG ?= $(shell git describe --tags --abbrev=0) + +FEATURES ?= + +##@ Help + +.PHONY: help +help: ## Display this help. + @awk 'BEGIN {FS = ":.*##"; printf "Usage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST) + +.PHONY: v +v: ## Show the current version + @echo "Version: ${GIT_VER}" + +##@ Build + +.PHONY: clean +clean: ## Clean up + cargo clean + +# Detect the current architecture +ARCH := $(shell uname -m) + +# Determine if we're on x86_64 +ifeq ($(ARCH),x86_64) + IS_X86_64 = 1 +else + IS_X86_64 = 0 +endif + +# Set build profile and flags based on architecture +ifeq ($(IS_X86_64),1) + # x86_64: Use reproducible profile with reproducible build flags + BUILD_PROFILE = reproducible + BUILD_TARGET = x86_64-unknown-linux-gnu + + # Environment variables for reproducible builds + # Initialize RUSTFLAGS + RUST_BUILD_FLAGS = + # Optimize for modern CPUs + RUST_BUILD_FLAGS += -C target-cpu=x86-64-v3 + # 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='' + # Remap paths to ensure reproducible builds + RUST_BUILD_FLAGS += --remap-path-prefix $(shell pwd)=. + # Set timestamp from last git commit for reproducible builds + SOURCE_DATE ?= $(shell git log -1 --pretty=%ct) + # Set C locale for consistent string handling and sorting + LOCALE_VAL = C + # Set UTC timezone for consistent time handling across builds + TZ_VAL = UTC + + # Environment setup for reproducible builds + BUILD_ENV = SOURCE_DATE_EPOCH=$(SOURCE_DATE) \ + RUSTFLAGS="${RUST_BUILD_FLAGS}" \ + LC_ALL=${LOCALE_VAL} \ + TZ=${TZ_VAL} \ + JEMALLOC_OVERRIDE=/usr/lib/x86_64-linux-gnu/libjemalloc.a +else + # Non-x86_64: Use release profile without reproducible build flags + BUILD_PROFILE = release + BUILD_TARGET = + RUST_BUILD_FLAGS = + BUILD_ENV = +endif + +.PHONY: build +build: ## Build (release version) + $(BUILD_ENV) cargo build --features "$(FEATURES)" --locked $(if $(BUILD_TARGET),--target $(BUILD_TARGET)) --profile $(BUILD_PROFILE) + +.PHONY: build-dev +build-dev: ## Build (debug version) + cargo build --features "$(FEATURES)" + +##@ Debian Packages + +.PHONY: install-cargo-deb +install-cargo-deb: + @command -v cargo-deb >/dev/null 2>&1 || cargo install cargo-deb@3.6.0 --locked + +.PHONY: build-deb +build-deb: install-cargo-deb ## Build Debian package + cargo deb --profile $(BUILD_PROFILE) --no-build --no-dbgsym --no-strip \ + -p attested-tls-proxy \ + $(if $(BUILD_TARGET),--target $(BUILD_TARGET)) \ + $(if $(VERSION),--deb-version "1~$(VERSION)") + +##@ Dev + +.PHONY: lint +lint: ## Run the linters + cargo fmt -- --check + cargo clippy --workspace --features "$(FEATURES)" -- -D warnings + +.PHONY: test +test: + cargo test --verbose --features "$(FEATURES)" + +.PHONY: lt +lt: lint test ## Run "lint" and "test" + +.PHONY: fmt +fmt: ## Format the code + cargo fmt + cargo fix --allow-staged + cargo clippy --features "$(FEATURES)" --fix --allow-staged diff --git a/scripts/check-reproducibility.sh b/scripts/check-reproducibility.sh new file mode 100755 index 0000000..1b9e6ae --- /dev/null +++ b/scripts/check-reproducibility.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +# Checks reproducibility by running a package build twice and printing hashes of .deb package + +set -euo pipefail + +rm -rf /tmp/repro1 /tmp/repro2 +mkdir -p /tmp/repro1 /tmp/repro2 + +docker build -f Dockerfile.build-deb --no-cache --output type=local,dest=/tmp/repro1 . +docker build -f Dockerfile.build-deb --no-cache --output type=local,dest=/tmp/repro2 . + +sha256sum /tmp/repro1/debian/*.deb +sha256sum /tmp/repro2/debian/*.deb