diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3fa63c041..f5b829fef 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -59,9 +59,77 @@ jobs: path: ./crates/contracts/build retention-days: 1 + reproducibility-check: + name: reproducibility-check (linux-amd64) + needs: [prepare, build-contracts] + runs-on: ubuntu-latest-8-cores + env: + TARGET: x86_64-unknown-linux-gnu + steps: + - uses: actions/checkout@v4 + + - name: Set SOURCE_DATE_EPOCH + shell: bash + run: | + echo "SOURCE_DATE_EPOCH=$(git log -1 --format=%ct)" >> $GITHUB_ENV + + - name: Download contract artifacts + uses: actions/download-artifact@v4 + with: + name: contract-artifacts + path: ./crates/contracts/build + + - uses: actions-rust-lang/setup-rust-toolchain@v1 + name: Rust Toolchain Setup + with: + toolchain: ${{ env.RUST_VERSION }} + target: ${{ env.TARGET }} + cache-on-failure: true + cache-key: reproducibility-${{ env.TARGET }} + + - name: Verify vendored dependency archive + shell: bash + run: | + ./scripts/release/verify-vendor-archive.sh --extract-check + + - name: Build (pass 1) + shell: bash + run: | + ./scripts/release/build-katana-vendored.sh --target "$TARGET" + SHA_ONE=$(sha256sum "./target/$TARGET/performance/katana" | awk '{ print $1 }') + echo "sha_one=$SHA_ONE" >> $GITHUB_ENV + + - name: Build (pass 2) + shell: bash + run: | + rm -rf ./target + ./scripts/release/build-katana-vendored.sh --target "$TARGET" + SHA_TWO=$(sha256sum "./target/$TARGET/performance/katana" | awk '{ print $1 }') + echo "sha_two=$SHA_TWO" >> $GITHUB_ENV + + - name: Compare hashes + shell: bash + run: | + echo "Build #1 SHA256: $sha_one" + echo "Build #2 SHA256: $sha_two" + if [[ "$sha_one" != "$sha_two" ]]; then + echo "Reproducibility check failed: hashes differ." + exit 1 + fi + + - name: Summary + shell: bash + run: | + echo "## Reproducibility Check" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- target: \`$TARGET\`" >> $GITHUB_STEP_SUMMARY + echo "- SOURCE_DATE_EPOCH: \`$SOURCE_DATE_EPOCH\`" >> $GITHUB_STEP_SUMMARY + echo "- sha256(build #1): \`$sha_one\`" >> $GITHUB_STEP_SUMMARY + echo "- sha256(build #2): \`$sha_two\`" >> $GITHUB_STEP_SUMMARY + release: name: ${{ matrix.job.target }} (${{ matrix.job.os }}${{ matrix.job.native_build == true && ', native' || '' }}) - needs: [prepare, build-contracts] + needs: [prepare, build-contracts, reproducibility-check] runs-on: ${{ matrix.job.os }} env: PLATFORM_NAME: ${{ matrix.job.platform }} @@ -118,6 +186,11 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Set SOURCE_DATE_EPOCH + shell: bash + run: | + echo "SOURCE_DATE_EPOCH=$(git log -1 --format=%ct)" >> $GITHUB_ENV + - name: Download contract artifacts uses: actions/download-artifact@v4 with: @@ -204,17 +277,22 @@ jobs: # See: https://github.com/jemalloc/jemalloc/issues/467 echo "JEMALLOC_SYS_WITH_LG_PAGE=16" >> $GITHUB_ENV + - name: Verify vendored dependency archive + shell: bash + run: | + ./scripts/release/verify-vendor-archive.sh --extract-check + - name: Build binary if: ${{ matrix.job.native_build == false }} shell: bash run: | - cargo build -p katana --bin katana --profile performance --target ${{ matrix.job.target }} + ./scripts/release/build-katana-vendored.sh --target "${{ matrix.job.target }}" - name: Build binary ( w/ cairo-native ) if: ${{ matrix.job.native_build == true }} shell: bash run: | - cargo build -p katana --bin katana --profile performance --features native --target ${{ matrix.job.target }} + ./scripts/release/build-katana-vendored.sh --target "${{ matrix.job.target }}" --native - name: Archive binaries id: artifacts diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 4999bdd9a..1b025949a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,20 +7,26 @@ on: - "release/**" paths: - "Cargo.toml" + - "Cargo.lock" - "bin/**/*.rs" - "bin/**/Cargo.toml" - "crates/**/*.rs" - "crates/**/Cargo.toml" + - "scripts/release/*.sh" + - "third_party/cargo/**" - ".github/workflows/test.yml" pull_request: types: [opened, synchronize, ready_for_review] paths: - "Cargo.toml" + - "Cargo.lock" - "bin/**/*.rs" - "bin/**/Cargo.toml" - "crates/**/*.rs" - "crates/**/Cargo.toml" + - "scripts/release/*.sh" + - "third_party/cargo/**" - ".github/workflows/test.yml" # Cancel in progress workflow when a new one is triggered by running in a concurrency group @@ -42,8 +48,38 @@ jobs: - uses: actions/checkout@v3 - run: scripts/rust_fmt.sh --check + vendor-consistency: + runs-on: ubuntu-latest + if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.draft == false) + container: + image: ghcr.io/dojoengine/katana-dev:latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 + # Workaround for https://github.com/actions/runner-images/issues/6775 + - run: git config --global --add safe.directory "*" + + - name: Verify vendored archive and manifest + run: make vendor-verify + + - name: Enforce vendor refresh when Cargo.lock changes + if: github.event_name == 'pull_request' + run: | + BASE_SHA="${{ github.event.pull_request.base.sha }}" + HEAD_SHA="${{ github.event.pull_request.head.sha }}" + CHANGED_FILES="$(git diff --name-only "$BASE_SHA" "$HEAD_SHA")" + + if echo "$CHANGED_FILES" | grep -q "^Cargo.lock$"; then + if ! echo "$CHANGED_FILES" | grep -Eq "^third_party/cargo/(vendor\.tar\.gz\.part-[0-9]+|vendor\.tar\.gz\.sha256|VENDOR_MANIFEST\.lock)$"; then + echo "Cargo.lock changed but vendored dependency artifacts were not refreshed." + echo "Run: make vendor-refresh" + exit 1 + fi + fi + generate-test-artifacts: - needs: [fmt] + needs: [fmt, vendor-consistency] runs-on: ubuntu-latest if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.pull_request.draft == false) container: diff --git a/Makefile b/Makefile index a2de99b1b..87ad6143b 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ SCARB_REQUIRED_VERSIONS := $(sort $(SCARB_VERSION) $(AVNU_SCARB_VERSION) $(VRF_S .DEFAULT_GOAL := usage .SILENT: clean -.PHONY: usage help check-llvm native-deps native-deps-macos native-deps-linux native-deps-windows build-explorer contracts tee-sev-snp clean deps install-scarb fixtures snos-artifacts db-compat-artifacts generate-db-fixtures install-pyenv +.PHONY: usage help check-llvm native-deps native-deps-macos native-deps-linux native-deps-windows build-explorer contracts tee-sev-snp clean deps install-scarb fixtures snos-artifacts db-compat-artifacts generate-db-fixtures install-pyenv vendor-refresh vendor-verify usage help: @echo "Usage:" @@ -55,6 +55,8 @@ usage help: @echo " snos-artifacts: Prepare SNOS tests artifacts." @echo " db-compat-artifacts: Prepare database compatibility test artifacts." @echo " generate-db-fixtures: Generate spawn-and-move and simple DB fixtures (requires scarb + sozo)." + @echo " vendor-refresh: Refresh the vendored Cargo dependency archive and manifest." + @echo " vendor-verify: Verify vendored Cargo archive and Cargo.lock consistency." @echo " native-deps-macos: Install cairo-native dependencies for macOS." @echo " native-deps-linux: Install cairo-native dependencies for Linux." @echo " native-deps-windows: Install cairo-native dependencies for Windows." @@ -96,6 +98,12 @@ build-explorer: contracts: install-scarb $(CONTRACTS_BUILD_DIR) +vendor-refresh: + @./scripts/release/update-vendor-archive.sh + +vendor-verify: + @./scripts/release/verify-vendor-archive.sh --extract-check + tee-sev-snp: @echo "Building AMD SEV-SNP TEE VM components..." @if [ -n "$(KATANA_BINARY)" ]; then \ diff --git a/README.md b/README.md index 4d29c6051..feabf8212 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ - [Cairo Native](#cairo-native) - [Explorer](#explorer) - [Testing](#testing) +- [Release Reproducibility](#release-reproducibility) ## Development Setup @@ -102,3 +103,25 @@ Once setup is complete, you can run the tests using: ```bash cargo nextest run ``` + +## Release Reproducibility + +Katana release binaries are built from a vendored Cargo dependency archive committed in this repository: + +- `third_party/cargo/vendor.tar.gz.part-*` +- `third_party/cargo/vendor.tar.gz.sha256` +- `third_party/cargo/VENDOR_MANIFEST.lock` + +The archive is committed as split parts to stay under GitHub's per-file size limit. + +When dependencies change, refresh these artifacts in the same PR: + +```bash +make vendor-refresh +``` + +You can verify integrity and lockfile consistency locally with: + +```bash +make vendor-verify +``` diff --git a/docs/release-reproducibility.md b/docs/release-reproducibility.md new file mode 100644 index 000000000..c5be55e08 --- /dev/null +++ b/docs/release-reproducibility.md @@ -0,0 +1,57 @@ +# Release Reproducibility + +Katana release binaries use a vendored Cargo dependency archive to reduce non-determinism from network/package source drift. + +## Vendored Artifacts + +- `third_party/cargo/vendor.tar.gz.part-*` +- `third_party/cargo/vendor.tar.gz.sha256` +- `third_party/cargo/VENDOR_MANIFEST.lock` + +The archive is stored as split parts to remain below GitHub's per-file blob limit. + +The manifest records: + +- SHA-256 of `Cargo.lock` +- SHA-256 of the dependency archive +- archive path metadata used by CI/release validation + +## Updating Vendored Dependencies + +After any dependency update (`cargo add`, `cargo update`, manifest edits), refresh vendored artifacts: + +```bash +make vendor-refresh +``` + +Commit all of the following in the same PR: + +- `Cargo.lock` +- `third_party/cargo/vendor.tar.gz.part-*` +- `third_party/cargo/vendor.tar.gz.sha256` +- `third_party/cargo/VENDOR_MANIFEST.lock` + +## Validation + +Run local verification: + +```bash +make vendor-verify +``` + +Verification checks: + +- archive checksum matches `vendor.tar.gz.sha256` +- manifest archive hash matches the archive +- manifest lock hash matches `Cargo.lock` +- archive extract sanity checks (`cargo-home` layout) + +CI enforces this for pull requests and blocks drift. + +## Release Workflow Behavior + +`release.yml` now: + +- validates vendored artifacts before building +- builds Katana with `--locked --offline --frozen` via `scripts/release/build-katana-vendored.sh` +- runs a reproducibility gate (two clean Linux amd64 builds with matching SHA-256) diff --git a/scripts/release/build-katana-vendored.sh b/scripts/release/build-katana-vendored.sh new file mode 100755 index 000000000..3fc306596 --- /dev/null +++ b/scripts/release/build-katana-vendored.sh @@ -0,0 +1,115 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" + +TARGET="" +PROFILE="${PROFILE:-performance}" +NATIVE_BUILD=0 + +VENDOR_DIR="${VENDOR_DIR:-$PROJECT_ROOT/third_party/cargo}" +VENDOR_ARCHIVE_NAME="${VENDOR_ARCHIVE_NAME:-vendor.tar.gz}" +VERIFY_SCRIPT="$SCRIPT_DIR/verify-vendor-archive.sh" + +error() { + echo "ERROR: $*" >&2 + exit 1 +} + +require_cmd() { + command -v "$1" >/dev/null 2>&1 || error "Missing required command: $1" +} + +collect_vendor_parts() { + VENDOR_PARTS=() + while IFS= read -r part; do + VENDOR_PARTS+=("$part") + done < <(find "$VENDOR_DIR" -maxdepth 1 -type f -name "${VENDOR_ARCHIVE_NAME}.part-*" | LC_ALL=C sort) + [[ ${#VENDOR_PARTS[@]} -gt 0 ]] || error "No vendor archive parts found in $VENDOR_DIR" +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --target) + [[ -n "${2:-}" ]] || error "Missing value for --target" + TARGET="$2" + shift 2 + ;; + --profile) + [[ -n "${2:-}" ]] || error "Missing value for --profile" + PROFILE="$2" + shift 2 + ;; + --native) + NATIVE_BUILD=1 + shift + ;; + -h|--help) + cat < [--profile ] [--native] + +Builds katana with: + - vendored dependencies only + - --locked --offline --frozen cargo mode +EOF + exit 0 + ;; + *) + error "Unknown option: $1" + ;; + esac +done + +[[ -n "$TARGET" ]] || error "target is required (use --target)" + +require_cmd cargo +require_cmd tar +[[ -x "$VERIFY_SCRIPT" ]] || error "Verification script is not executable: $VERIFY_SCRIPT" +collect_vendor_parts + +if [[ -z "${SOURCE_DATE_EPOCH:-}" ]]; then + error "SOURCE_DATE_EPOCH must be set" +fi +if ! [[ "$SOURCE_DATE_EPOCH" =~ ^[0-9]+$ ]]; then + error "SOURCE_DATE_EPOCH must be an integer unix timestamp" +fi + +"$VERIFY_SCRIPT" + +TMP_DIR="$(mktemp -d)" +trap 'rm -rf "$TMP_DIR"' EXIT + +EXTRACT_DIR="$TMP_DIR/extracted" +mkdir -p "$EXTRACT_DIR" +TMP_ARCHIVE="$TMP_DIR/$VENDOR_ARCHIVE_NAME" +cat "${VENDOR_PARTS[@]}" > "$TMP_ARCHIVE" + +tar -xzf "$TMP_ARCHIVE" -C "$EXTRACT_DIR" +[[ -d "$EXTRACT_DIR/cargo-home" ]] || error "Vendor archive missing top-level cargo-home/ directory" +CARGO_HOME_DIR="$EXTRACT_DIR/cargo-home" + +FEATURE_ARGS=() +if [[ $NATIVE_BUILD -eq 1 ]]; then + FEATURE_ARGS=(--features native) +fi + +echo "Building katana (target=$TARGET, profile=$PROFILE, native=$NATIVE_BUILD)" +CARGO_HOME="$CARGO_HOME_DIR" cargo build \ + --locked \ + --offline \ + --frozen \ + -p katana \ + --bin katana \ + --profile "$PROFILE" \ + --target "$TARGET" \ + "${FEATURE_ARGS[@]}" + +BINARY_PATH="$PROJECT_ROOT/target/$TARGET/$PROFILE/katana" +if [[ "$TARGET" == *"windows"* ]]; then + BINARY_PATH="$PROJECT_ROOT/target/$TARGET/$PROFILE/katana.exe" +fi + +[[ -f "$BINARY_PATH" ]] || error "Expected binary not found at $BINARY_PATH" +echo "Build succeeded: $BINARY_PATH" diff --git a/scripts/release/update-vendor-archive.sh b/scripts/release/update-vendor-archive.sh new file mode 100755 index 000000000..32def83eb --- /dev/null +++ b/scripts/release/update-vendor-archive.sh @@ -0,0 +1,168 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" + +VENDOR_DIR="$PROJECT_ROOT/third_party/cargo" +VENDOR_ARCHIVE_NAME="${VENDOR_ARCHIVE_NAME:-vendor.tar.gz}" +VENDOR_PART_PREFIX="${VENDOR_PART_PREFIX:-$VENDOR_DIR/${VENDOR_ARCHIVE_NAME}.part-}" +VENDOR_PART_SIZE="${VENDOR_PART_SIZE:-95m}" +VENDOR_ARCHIVE_SHA256_FILE="${VENDOR_ARCHIVE_SHA256_FILE:-$VENDOR_DIR/vendor.tar.gz.sha256}" +VENDOR_MANIFEST_FILE="${VENDOR_MANIFEST_FILE:-$VENDOR_DIR/VENDOR_MANIFEST.lock}" +CARGO_LOCK_FILE="${CARGO_LOCK_FILE:-$PROJECT_ROOT/Cargo.lock}" +CARGO_HOME_LAYOUT_DIR="cargo-home" +FETCH_TARGETS=( + "x86_64-unknown-linux-gnu" + "aarch64-unknown-linux-gnu" + "aarch64-apple-darwin" + "x86_64-pc-windows-msvc" +) + +# Use a stable default to avoid archive churn across unrelated commits. +SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-0}" + +error() { + echo "ERROR: $*" >&2 + exit 1 +} + +require_cmd() { + command -v "$1" >/dev/null 2>&1 || error "Missing required command: $1" +} + +hash_file() { + local file="$1" + if command -v sha256sum >/dev/null 2>&1; then + sha256sum "$file" | awk '{ print $1 }' + elif command -v shasum >/dev/null 2>&1; then + shasum -a 256 "$file" | awk '{ print $1 }' + else + error "Neither sha256sum nor shasum is available" + fi +} + +resolve_tar_impl() { + if command -v gtar >/dev/null 2>&1; then + echo "gnu:gtar" + return + fi + + if command -v tar >/dev/null 2>&1; then + if tar --version 2>/dev/null | grep -q "GNU tar"; then + echo "gnu:tar" + return + fi + echo "bsd:tar" + return + fi + + error "tar is required" +} + +create_archive() { + local impl="$1" + local tar_cmd="$2" + local output_archive="$3" + + if [[ "$impl" == "gnu" ]]; then + "$tar_cmd" \ + --sort=name \ + --mtime="@$SOURCE_DATE_EPOCH" \ + --owner=0 \ + --group=0 \ + --numeric-owner \ + --format=gnu \ + -C "$TMP_DIR" \ + -czf "$output_archive" \ + "$CARGO_HOME_LAYOUT_DIR" + return + fi + + local file_list="$TMP_DIR/vendor-files.txt" + (cd "$TMP_DIR" && find "$CARGO_HOME_LAYOUT_DIR" -print | LC_ALL=C sort > "$file_list") + (cd "$TMP_DIR" && "$tar_cmd" --uid 0 --gid 0 --numeric-owner --format pax -cf - -T "$file_list" | gzip -n > "$output_archive") +} + +epoch_to_touch_timestamp() { + if date -u -r 0 "+%Y%m%d%H%M.%S" >/dev/null 2>&1; then + date -u -r "$SOURCE_DATE_EPOCH" "+%Y%m%d%H%M.%S" + else + date -u -d "@$SOURCE_DATE_EPOCH" "+%Y%m%d%H%M.%S" + fi +} + +normalize_timestamps() { + local dir="$1" + local timestamp + timestamp="$(epoch_to_touch_timestamp)" + find "$dir" -exec touch -h -t "$timestamp" {} + +} + +if ! [[ "$SOURCE_DATE_EPOCH" =~ ^[0-9]+$ ]]; then + error "SOURCE_DATE_EPOCH must be an integer unix timestamp" +fi + +require_cmd cargo +require_cmd gzip +require_cmd split +TAR_IMPL_WITH_CMD="$(resolve_tar_impl)" +TAR_IMPL="${TAR_IMPL_WITH_CMD%%:*}" +TAR_CMD="${TAR_IMPL_WITH_CMD##*:}" + +[[ -f "$CARGO_LOCK_FILE" ]] || error "Cargo.lock not found at $CARGO_LOCK_FILE" + +TMP_DIR="$(mktemp -d)" +trap 'rm -rf "$TMP_DIR"' EXIT +TMP_CARGO_HOME_DIR="$TMP_DIR/$CARGO_HOME_LAYOUT_DIR" +TMP_ARCHIVE="$TMP_DIR/$VENDOR_ARCHIVE_NAME" + +echo "Fetching dependencies into isolated CARGO_HOME..." +mkdir -p "$TMP_CARGO_HOME_DIR" +for target in "${FETCH_TARGETS[@]}"; do + echo " - target: $target" + CARGO_HOME="$TMP_CARGO_HOME_DIR" cargo fetch --locked --target "$target" --config net.git-fetch-with-cli=false +done + +mkdir -p "$VENDOR_DIR" + +echo "Pruning non-essential caches..." +rm -rf "$TMP_CARGO_HOME_DIR/registry/src" "$TMP_CARGO_HOME_DIR/git/checkouts" + +echo "Normalizing cached dependency timestamps..." +normalize_timestamps "$TMP_CARGO_HOME_DIR" + +echo "Creating deterministic archive: $TMP_ARCHIVE" +create_archive "$TAR_IMPL" "$TAR_CMD" "$TMP_ARCHIVE" + +VENDOR_ARCHIVE_SHA256="$(hash_file "$TMP_ARCHIVE")" +printf "%s %s\n" "$VENDOR_ARCHIVE_SHA256" "$VENDOR_ARCHIVE_NAME" > "$VENDOR_ARCHIVE_SHA256_FILE" + +echo "Splitting archive into git-safe parts (size=$VENDOR_PART_SIZE)..." +find "$VENDOR_DIR" -maxdepth 1 -type f -name "${VENDOR_ARCHIVE_NAME}.part-*" -delete +split -b "$VENDOR_PART_SIZE" -d -a 3 "$TMP_ARCHIVE" "$VENDOR_PART_PREFIX" +rm -f "$VENDOR_DIR/$VENDOR_ARCHIVE_NAME" + +PART_COUNT="$(find "$VENDOR_DIR" -maxdepth 1 -type f -name "${VENDOR_ARCHIVE_NAME}.part-*" | wc -l | tr -d ' ')" +[[ "$PART_COUNT" -gt 0 ]] || error "No archive parts were generated" + +CARGO_LOCK_SHA256="$(hash_file "$CARGO_LOCK_FILE")" + +cat > "$VENDOR_MANIFEST_FILE" <&2 + exit 1 +} + +require_cmd() { + command -v "$1" >/dev/null 2>&1 || error "Missing required command: $1" +} + +hash_file() { + local file="$1" + if command -v sha256sum >/dev/null 2>&1; then + sha256sum "$file" | awk '{ print $1 }' + elif command -v shasum >/dev/null 2>&1; then + shasum -a 256 "$file" | awk '{ print $1 }' + else + error "Neither sha256sum nor shasum is available" + fi +} + +parse_manifest_value() { + local key="$1" + awk -F'=' -v k="$key" '$1 == k { print substr($0, index($0, "=") + 1) }' "$VENDOR_MANIFEST_FILE" | tail -n 1 +} + +collect_vendor_parts() { + VENDOR_PARTS=() + while IFS= read -r part; do + VENDOR_PARTS+=("$part") + done < <(find "$VENDOR_DIR" -maxdepth 1 -type f -name "${VENDOR_ARCHIVE_NAME}.part-*" | LC_ALL=C sort) + [[ ${#VENDOR_PARTS[@]} -gt 0 ]] || error "No vendor archive parts found for pattern: $VENDOR_PART_GLOB" +} + +while [[ $# -gt 0 ]]; do + case "$1" in + --extract-check) + EXTRACT_CHECK=1 + shift + ;; + -h|--help) + cat < "$TMP_ARCHIVE" + +EXPECTED_ARCHIVE_SHA="$(awk '{ print $1 }' "$VENDOR_ARCHIVE_SHA256_FILE" | head -n 1)" +[[ -n "$EXPECTED_ARCHIVE_SHA" ]] || error "Vendor archive sha file is empty: $VENDOR_ARCHIVE_SHA256_FILE" + +ACTUAL_ARCHIVE_SHA="$(hash_file "$TMP_ARCHIVE")" +if [[ "$EXPECTED_ARCHIVE_SHA" != "$ACTUAL_ARCHIVE_SHA" ]]; then + error "Vendor archive checksum mismatch. expected=$EXPECTED_ARCHIVE_SHA actual=$ACTUAL_ARCHIVE_SHA" +fi + +MANIFEST_ARCHIVE_SHA="$(parse_manifest_value vendor_archive_sha256)" +[[ -n "$MANIFEST_ARCHIVE_SHA" ]] || error "Missing vendor_archive_sha256 in $VENDOR_MANIFEST_FILE" +if [[ "$MANIFEST_ARCHIVE_SHA" != "$ACTUAL_ARCHIVE_SHA" ]]; then + error "Manifest vendor archive sha mismatch. expected=$MANIFEST_ARCHIVE_SHA actual=$ACTUAL_ARCHIVE_SHA" +fi + +MANIFEST_LOCK_SHA="$(parse_manifest_value cargo_lock_sha256)" +[[ -n "$MANIFEST_LOCK_SHA" ]] || error "Missing cargo_lock_sha256 in $VENDOR_MANIFEST_FILE" + +ACTUAL_LOCK_SHA="$(hash_file "$CARGO_LOCK_FILE")" +if [[ "$MANIFEST_LOCK_SHA" != "$ACTUAL_LOCK_SHA" ]]; then + error "Cargo.lock checksum mismatch. expected=$MANIFEST_LOCK_SHA actual=$ACTUAL_LOCK_SHA" +fi + +if [[ $EXTRACT_CHECK -eq 1 ]]; then + EXTRACT_DIR="$TMP_DIR/extracted" + mkdir -p "$EXTRACT_DIR" + tar -xzf "$TMP_ARCHIVE" -C "$EXTRACT_DIR" + [[ -d "$EXTRACT_DIR/cargo-home" ]] || error "Vendor archive extract check failed: missing cargo-home directory" + [[ -d "$EXTRACT_DIR/cargo-home/registry/cache" ]] || error "Vendor archive extract check failed: missing registry/cache" + [[ -d "$EXTRACT_DIR/cargo-home/git/db" ]] || error "Vendor archive extract check failed: missing git/db" + + if [[ -z "$(find "$EXTRACT_DIR/cargo-home/registry/cache" -type f -print -quit)" ]]; then + error "Vendor archive extract check failed: no cached registry crates found" + fi +fi + +echo "Vendor archive verification succeeded." diff --git a/third_party/cargo/VENDOR_MANIFEST.lock b/third_party/cargo/VENDOR_MANIFEST.lock new file mode 100644 index 000000000..237a1a473 --- /dev/null +++ b/third_party/cargo/VENDOR_MANIFEST.lock @@ -0,0 +1,9 @@ +manifest_version=1 +cargo_lock_path=Cargo.lock +cargo_lock_sha256=d68486924d65e41aa0f4d342db8fd39ab4a5d3d519e0e79ae7939a15674b5bac +vendor_archive_path=third_party/cargo/vendor.tar.gz +vendor_archive_sha256=7f54d37e1cd5c1c7d0ea8f0eacd167ce36199cd2bc8def36762f6314eab86ee8 +vendor_archive_sha256_file=third_party/cargo/vendor.tar.gz.sha256 +vendor_archive_part_prefix=third_party/cargo/vendor.tar.gz.part- +source_date_epoch=0 +generated_by=scripts/release/update-vendor-archive.sh diff --git a/third_party/cargo/vendor.tar.gz.part-000 b/third_party/cargo/vendor.tar.gz.part-000 new file mode 100644 index 000000000..85468fdcc Binary files /dev/null and b/third_party/cargo/vendor.tar.gz.part-000 differ diff --git a/third_party/cargo/vendor.tar.gz.part-001 b/third_party/cargo/vendor.tar.gz.part-001 new file mode 100644 index 000000000..0b23cf3dc Binary files /dev/null and b/third_party/cargo/vendor.tar.gz.part-001 differ diff --git a/third_party/cargo/vendor.tar.gz.part-002 b/third_party/cargo/vendor.tar.gz.part-002 new file mode 100644 index 000000000..a6fb52e8f Binary files /dev/null and b/third_party/cargo/vendor.tar.gz.part-002 differ diff --git a/third_party/cargo/vendor.tar.gz.part-003 b/third_party/cargo/vendor.tar.gz.part-003 new file mode 100644 index 000000000..6d75918af Binary files /dev/null and b/third_party/cargo/vendor.tar.gz.part-003 differ diff --git a/third_party/cargo/vendor.tar.gz.part-004 b/third_party/cargo/vendor.tar.gz.part-004 new file mode 100644 index 000000000..71c6d257b Binary files /dev/null and b/third_party/cargo/vendor.tar.gz.part-004 differ diff --git a/third_party/cargo/vendor.tar.gz.part-005 b/third_party/cargo/vendor.tar.gz.part-005 new file mode 100644 index 000000000..0d73e62b0 Binary files /dev/null and b/third_party/cargo/vendor.tar.gz.part-005 differ diff --git a/third_party/cargo/vendor.tar.gz.part-006 b/third_party/cargo/vendor.tar.gz.part-006 new file mode 100644 index 000000000..68807ea14 Binary files /dev/null and b/third_party/cargo/vendor.tar.gz.part-006 differ diff --git a/third_party/cargo/vendor.tar.gz.part-007 b/third_party/cargo/vendor.tar.gz.part-007 new file mode 100644 index 000000000..b1724fe20 Binary files /dev/null and b/third_party/cargo/vendor.tar.gz.part-007 differ diff --git a/third_party/cargo/vendor.tar.gz.part-008 b/third_party/cargo/vendor.tar.gz.part-008 new file mode 100644 index 000000000..bcb1bf364 Binary files /dev/null and b/third_party/cargo/vendor.tar.gz.part-008 differ diff --git a/third_party/cargo/vendor.tar.gz.part-009 b/third_party/cargo/vendor.tar.gz.part-009 new file mode 100644 index 000000000..601949d7a Binary files /dev/null and b/third_party/cargo/vendor.tar.gz.part-009 differ diff --git a/third_party/cargo/vendor.tar.gz.part-010 b/third_party/cargo/vendor.tar.gz.part-010 new file mode 100644 index 000000000..1e4019253 Binary files /dev/null and b/third_party/cargo/vendor.tar.gz.part-010 differ diff --git a/third_party/cargo/vendor.tar.gz.part-011 b/third_party/cargo/vendor.tar.gz.part-011 new file mode 100644 index 000000000..f684dcd38 Binary files /dev/null and b/third_party/cargo/vendor.tar.gz.part-011 differ diff --git a/third_party/cargo/vendor.tar.gz.part-012 b/third_party/cargo/vendor.tar.gz.part-012 new file mode 100644 index 000000000..8520c1253 Binary files /dev/null and b/third_party/cargo/vendor.tar.gz.part-012 differ diff --git a/third_party/cargo/vendor.tar.gz.part-013 b/third_party/cargo/vendor.tar.gz.part-013 new file mode 100644 index 000000000..3f915bed0 Binary files /dev/null and b/third_party/cargo/vendor.tar.gz.part-013 differ diff --git a/third_party/cargo/vendor.tar.gz.part-014 b/third_party/cargo/vendor.tar.gz.part-014 new file mode 100644 index 000000000..c3feb03c5 Binary files /dev/null and b/third_party/cargo/vendor.tar.gz.part-014 differ diff --git a/third_party/cargo/vendor.tar.gz.part-015 b/third_party/cargo/vendor.tar.gz.part-015 new file mode 100644 index 000000000..d65d62e54 Binary files /dev/null and b/third_party/cargo/vendor.tar.gz.part-015 differ diff --git a/third_party/cargo/vendor.tar.gz.sha256 b/third_party/cargo/vendor.tar.gz.sha256 new file mode 100644 index 000000000..3c3f95dad --- /dev/null +++ b/third_party/cargo/vendor.tar.gz.sha256 @@ -0,0 +1 @@ +7f54d37e1cd5c1c7d0ea8f0eacd167ce36199cd2bc8def36762f6314eab86ee8 vendor.tar.gz