Skip to content

ci: build-reproducibility — clean cdylib wasm verification for all workspaces - #1

Closed
ELKorede wants to merge 1 commit into
masterfrom
feat/build-reproducibility-ci
Closed

ci: build-reproducibility — clean cdylib wasm verification for all workspaces#1
ELKorede wants to merge 1 commit into
masterfrom
feat/build-reproducibility-ci

Conversation

@ELKorede

Copy link
Copy Markdown
Collaborator

Summary

Adds a dedicated CI workflow that starts from a clean Cargo target directory and verifies every deployable cdylib wasm artifact across all workspaces. Fails the job if any expected .wasm file is absent, empty, or lacks the WebAssembly magic bytes.

Closes #[build-reproducibility issue].


Before / After

Before

Gap Description
Incomplete coverage contracts-ci.yml built only the bounty_escrow workspace; the other four contracts/ packages and the entire soroban/ workspace had no clean-build gate
Cached target wasm-size-budget.yml restored the Cargo target/ directory from cache before building, so a silently-deleted cdylib could pass if the cached artifact was still present
No explicit assertion Artifact absence was only caught by upload-artifact: if-no-files-found: error — no structured check for magic bytes or file size
No version record No workflow captured the resolved soroban-sdk version alongside each build

After

A new .github/workflows/build-reproducibility.yml runs on every push and PR that touches Rust or CI source. It:

  1. Runs cargo clean before every build — the Cargo registry cache (crate downloads) is retained but the compiled target/ tree is always empty.
  2. Builds all 8 deployable cdylibs across three independent workspace groups.
  3. Asserts each artifact via scripts/verify-wasm-artifacts.sh: file exists, size > 0, WebAssembly magic bytes (\x00asm) present.
  4. Records and uploads compiler + resolved SDK versions as a build artifact.

Authoritative cdylib target list

Workspace Package Expected artifact
contracts/bounty_escrow bounty-escrow bounty_escrow.wasm
contracts/bounty_escrow escrow (sub) escrow.wasm
contracts/grainlify-core grainlify-core grainlify_core.wasm
contracts/program-escrow program-escrow program_escrow.wasm
contracts/view-facade view-facade view_facade.wasm
contracts/escrow-view-facade escrow-view-facade escrow_view_facade.wasm
soroban/ escrow escrow.wasm
soroban/ program-escrow program_escrow.wasm

Excluded (not cdylib / host-only):

  • grainlify-stream — no crate-type in Cargo.toml, testutils-only, produces no deployable wasm
  • grainlify-contracts[[bin]] + rlib, not a cdylib

Evidence requested by the issue

Verification commands (from issue)

# These commands match the exact steps in the new workflow.
# They cannot run in this codespace (no Rust toolchain installed),
# but will execute in the ubuntu-latest GitHub Actions runner.
cargo clean --manifest-path contracts/bounty_escrow/Cargo.toml
cargo build --manifest-path contracts/bounty_escrow/Cargo.toml --workspace --target wasm32-unknown-unknown --release

Regression tests

scripts/tests/test_verify_wasm_artifacts.sh exercises verify-wasm-artifacts.sh with 8 synthetic-fixture test cases (no Rust toolchain needed):

Running verify-wasm-artifacts.sh regression tests

  ✅ PASS  single valid wasm passes
  ✅ PASS  multiple valid wasms pass
  ✅ PASS  missing wasm fails
  ✅ PASS  empty wasm fails
  ✅ PASS  bad magic bytes fails
  ✅ PASS  missing artifact dir fails
  ✅ PASS  partial miss fails (one valid, one missing)
  ✅ PASS  no args fails

Results: 8 passed, 0 failed

YAML syntax

YAML valid - top-level keys: ['name', True, 'env', 'jobs']
Jobs: ['record-versions', 'build-contracts-bounty-escrow', 'build-contracts-standalone', 'build-soroban', 'summarize']

(True is Python's rendering of the YAML on keyword — correct for GitHub Actions.)


Files changed

File Description
.github/workflows/build-reproducibility.yml New workflow (5 jobs, 371 lines)
scripts/verify-wasm-artifacts.sh Assertion script: exists, non-empty, magic bytes
scripts/tests/test_verify_wasm_artifacts.sh 8-case regression test suite

No existing tests were modified, weakened, or deleted.

Adds a CI job that starts from a clean Cargo target directory and
verifies every deployable wasm artifact is produced correctly.

Problem addressed:
- No existing CI job performed a clean build of all cdylib packages
- contracts-ci.yml only covered the bounty_escrow workspace
- wasm-size-budget.yml used a cached target (not clean) and relied on
  upload-artifact for failure detection rather than explicit assertions

Changes:
- .github/workflows/build-reproducibility.yml
  New workflow with 5 jobs:
  • record-versions: captures rustc, cargo, and resolved soroban-sdk
    versions as a build artifact
  • build-contracts-bounty-escrow: cargo clean + build for the
    bounty_escrow workspace (produces bounty_escrow.wasm + escrow.wasm)
  • build-contracts-standalone: matrix over grainlify-core,
    program-escrow, view-facade, escrow-view-facade (one clean build
    each, fail-fast: false so all packages are always attempted)
  • build-soroban: cargo clean + build for soroban/contracts/escrow
    and soroban/contracts/program-escrow; grainlify-stream excluded
    (no crate-type = cdylib, host-only testutils helper)
  • summarize: collects all artifacts and prints a final report

- scripts/verify-wasm-artifacts.sh
  Reusable assertion script that checks: file exists, size > 0,
  WebAssembly magic bytes (\x00asm) present. Called from the workflow
  and runnable locally. Exits 1 if any assertion fails.

- scripts/tests/test_verify_wasm_artifacts.sh
  8 regression tests for verify-wasm-artifacts.sh using synthetic
  wasm fixtures (no Rust toolchain required). All tests pass.

Authoritative cdylib target list (excludes host-only and non-cdylib):
  contracts/bounty_escrow workspace → bounty_escrow.wasm, escrow.wasm
  contracts/grainlify-core          → grainlify_core.wasm
  contracts/program-escrow          → program_escrow.wasm
  contracts/view-facade             → view_facade.wasm
  contracts/escrow-view-facade      → escrow_view_facade.wasm
  soroban/contracts/escrow          → escrow.wasm
  soroban/contracts/program-escrow  → program_escrow.wasm
@ELKorede ELKorede closed this Aug 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant