From 034c05ce404b2b6d16fd12e896fcc66acaf3ec9f Mon Sep 17 00:00:00 2001 From: Coredevjay Date: Mon, 31 Aug 2026 09:05:13 +0000 Subject: [PATCH] fix(ci): reproducible builds and release version validation - Add --frozen to all cargo build/test/clippy commands in the Makefile, contract-ci.yml, and release.yml so CI/local builds fail if Cargo.lock is out of date instead of silently regenerating it. - Replace npm install with npm ci in Makefile frontend targets for lockfile-exact dependency installs. - Add make fmt, make typecheck-frontend, and make setup targets. - Add a verify-version job to the release workflow that fails the release if the pushed tag doesn't match Cargo.toml (CLI/contract) or frontend/package.json versions. Closes #316 Closes #317 Closes #318 Closes #320 --- .github/workflows/contract-ci.yml | 8 +++---- .github/workflows/release.yml | 35 ++++++++++++++++++++++++++- Makefile | 39 ++++++++++++++++++++++--------- 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/.github/workflows/contract-ci.yml b/.github/workflows/contract-ci.yml index 28b108e..d9988cb 100644 --- a/.github/workflows/contract-ci.yml +++ b/.github/workflows/contract-ci.yml @@ -110,16 +110,16 @@ jobs: run: cargo fmt --all -- --check - name: Clippy - run: cargo clippy --workspace --all-targets -- -D warnings + run: cargo clippy --frozen --workspace --all-targets -- -D warnings - name: Build (native) - run: cargo build --workspace + run: cargo build --frozen --workspace - name: Build contract (wasm32) - run: cargo build --package trellis_core --target wasm32-unknown-unknown --release + run: cargo build --frozen --package trellis_core --target wasm32-unknown-unknown --release - name: Test - run: cargo test --workspace + run: cargo test --frozen --workspace - name: Validate test snapshots are up to date run: | diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ad4ce7d..4bffcae 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -43,8 +43,39 @@ jobs: name: changelog path: CHANGELOG.md + verify-version: + name: Verify tag matches Cargo.toml/package.json versions + runs-on: ubuntu-latest + steps: + - name: Check out repository + uses: actions/checkout@v7 + + - name: Compare tag version with Cargo.toml/package.json + run: | + set -euo pipefail + TAG_VERSION="${GITHUB_REF_NAME#v}" + CLI_VERSION=$(grep -m1 '^version' cli/trellis_cli/Cargo.toml | sed -E 's/version = "(.*)"/\1/') + CONTRACT_VERSION=$(grep -m1 '^version' contracts/trellis_core/Cargo.toml | sed -E 's/version = "(.*)"/\1/') + FRONTEND_VERSION=$(node -p "require('./frontend/package.json').version") + + echo "Tag version: $TAG_VERSION" + echo "CLI version: $CLI_VERSION" + echo "Contract version: $CONTRACT_VERSION" + echo "Frontend version: $FRONTEND_VERSION" + + MISMATCH=0 + [ "$TAG_VERSION" = "$CLI_VERSION" ] || { echo "::error::Tag version ($TAG_VERSION) does not match cli/trellis_cli/Cargo.toml version ($CLI_VERSION)"; MISMATCH=1; } + [ "$TAG_VERSION" = "$CONTRACT_VERSION" ] || { echo "::error::Tag version ($TAG_VERSION) does not match contracts/trellis_core/Cargo.toml version ($CONTRACT_VERSION)"; MISMATCH=1; } + [ "$TAG_VERSION" = "$FRONTEND_VERSION" ] || { echo "::error::Tag version ($TAG_VERSION) does not match frontend/package.json version ($FRONTEND_VERSION)"; MISMATCH=1; } + + if [ "$MISMATCH" -eq 1 ]; then + echo "::error::Version mismatch between git tag and Cargo.toml/package.json. Bump the versions before tagging." + exit 1 + fi + build-contract: name: Build contract WASM + needs: verify-version runs-on: ubuntu-latest steps: - name: Check out repository @@ -60,6 +91,7 @@ jobs: # build` (wasm32v1-none) — see DEPLOYMENT.md for why. run: | cargo rustc \ + --frozen \ --manifest-path=contracts/trellis_core/Cargo.toml \ --crate-type=cdylib \ --target=wasm32-unknown-unknown \ @@ -73,6 +105,7 @@ jobs: build-cli: name: Build CLI (${{ matrix.target }}) + needs: verify-version runs-on: ${{ matrix.os }} strategy: fail-fast: false @@ -97,7 +130,7 @@ jobs: targets: ${{ matrix.target }} - name: Build trellis CLI - run: cargo build --release --manifest-path=cli/trellis_cli/Cargo.toml --target=${{ matrix.target }} + run: cargo build --frozen --release --manifest-path=cli/trellis_cli/Cargo.toml --target=${{ matrix.target }} - name: Package binary shell: bash diff --git a/Makefile b/Makefile index e1404f7..f8810f2 100644 --- a/Makefile +++ b/Makefile @@ -5,6 +5,9 @@ # make build — build everything (contract WASM + frontend) # make test — run all tests (contract + frontend) # make lint — run all linters (clippy + oxlint) +# make fmt — run cargo fmt on the workspace +# make typecheck-frontend — run tsc typecheck on the frontend +# make setup — install prerequisites (rustup target + npm deps) # make deploy — deploy contract to testnet (see DEPLOYMENT.md) # make clean — remove all build artifacts # make build-contract — build only the contract WASM @@ -16,10 +19,10 @@ # make lint-contract — run only clippy on contract and CLI # make lint-frontend — run only oxlint on frontend -.PHONY: help build test lint deploy clean +.PHONY: help build test lint fmt deploy clean setup .PHONY: build-contract build-cli build-frontend .PHONY: test-contract test-snapshots-update test-frontend -.PHONY: lint-contract lint-frontend +.PHONY: lint-contract lint-frontend typecheck-frontend help: @echo "Trellis Protocol — Build Targets" @@ -34,38 +37,46 @@ help: build: build-contract build-cli build-frontend build-contract: - cargo build --manifest-path contracts/trellis_core/Cargo.toml --target wasm32-unknown-unknown --release + cargo build --frozen --manifest-path contracts/trellis_core/Cargo.toml --target wasm32-unknown-unknown --release build-cli: - cargo build --manifest-path cli/trellis_cli/Cargo.toml --release + cargo build --frozen --manifest-path cli/trellis_cli/Cargo.toml --release build-frontend: - cd frontend && npm install && npm run build + # npm ci (not npm install) installs exact versions from package-lock.json + # for reproducible builds. + cd frontend && npm ci && npm run build # ── Test ─────────────────────────────────────────────────────────────────── test: test-contract test-frontend test-contract: - cargo test --manifest-path contracts/trellis_core/Cargo.toml + cargo test --frozen --manifest-path contracts/trellis_core/Cargo.toml test-snapshots-update: SOROBAN_TEST_SNAPSHOT_FILE=overwrite cargo test --manifest-path contracts/trellis_core/Cargo.toml @echo "Snapshots regenerated. Review the diff with: git diff contracts/trellis_core/test_snapshots/" test-frontend: - cd frontend && npm install && npm test + cd frontend && npm ci && npm test # ── Lint ─────────────────────────────────────────────────────────────────── lint: lint-contract lint-frontend lint-contract: - cargo clippy --manifest-path contracts/trellis_core/Cargo.toml -- -D warnings - cargo clippy --manifest-path cli/trellis_cli/Cargo.toml -- -D warnings + cargo clippy --frozen --manifest-path contracts/trellis_core/Cargo.toml -- -D warnings + cargo clippy --frozen --manifest-path cli/trellis_cli/Cargo.toml -- -D warnings lint-frontend: - cd frontend && npm install && npm run lint + cd frontend && npm ci && npm run lint + +fmt: + cargo fmt --all + +typecheck-frontend: + cd frontend && npm run typecheck # ── Deploy ───────────────────────────────────────────────────────────────── @@ -86,4 +97,10 @@ deploy: clean: cargo clean cd frontend && rm -rf dist node_modules - rm -rf target \ No newline at end of file + rm -rf target + +# ── Setup ────────────────────────────────────────────────────────────────── + +setup: + rustup target add wasm32-unknown-unknown + cd frontend && npm ci \ No newline at end of file