Skip to content

Merge pull request #721 from soma-enyi/feature/issues-663-664-665-666 #191

Merge pull request #721 from soma-enyi/feature/issues-663-664-665-666

Merge pull request #721 from soma-enyi/feature/issues-663-664-665-666 #191

Workflow file for this run

name: CI
on:
push:
branches: ["main", "feature/**", "fix/**", "docs/**"]
pull_request:
branches: ["main"]
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
# ── Type-check all contracts ──────────────────────────────────────────────
check:
name: cargo check
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: "1.75"
targets: wasm32-unknown-unknown
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.toml') }}
restore-keys: ${{ runner.os }}-cargo-
- name: cargo check (native)
run: cargo check --workspace
- name: cargo check (wasm32)
run: cargo check --workspace --target wasm32-unknown-unknown --exclude kora-tests
# ── Lint ──────────────────────────────────────────────────────────────────
clippy:
name: clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: "1.75"
components: clippy
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-clippy-${{ hashFiles('**/Cargo.toml') }}
restore-keys: ${{ runner.os }}-clippy-
- name: cargo clippy (warnings as errors)
run: cargo clippy --workspace -- -D warnings
# ── Formatting ────────────────────────────────────────────────────────────
fmt:
name: rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: "1.75"
components: rustfmt
- name: cargo fmt --check
run: cargo fmt --all -- --check
# ── Unbounded loop guard ──────────────────────────────────────────────────
#
# Flags loops over ledger-sourced collections (Map/Vec loaded from
# persistent/instance storage) that make a cross-contract call per
# iteration with no visible bound — cost scales with on-chain state size
# and can exceed Soroban's CPU instruction limit at scale.
# financing_pool::distribute_yield is a known, baselined instance; new
# occurrences fail this check. See scripts/check_unbounded_loops.py.
unbounded-loop-guard:
name: unbounded loop guard
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Check for unbounded loops with cross-contract calls
run: python3 scripts/check_unbounded_loops.py
# ── Dependency cycle guard (issue #275) ──────────────────────────────────
#
# Runs `cargo tree` and fails if any cycle is detected.
# Cargo itself rejects cyclic Cargo.toml graphs, so this step
# catches the error and surfaces it clearly in the CI log.
#
# If a cycle is ever introduced, cargo tree will exit non-zero and
# print the cycle path. Fix by removing the circular dependency.
cycle-guard:
name: dependency cycle guard
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: "1.75"
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-tree-${{ hashFiles('**/Cargo.toml') }}
restore-keys: ${{ runner.os }}-tree-
- name: Install cargo-tree (bundled with cargo, verify it works)
run: cargo tree --version
- name: Check for dependency cycles
run: |
echo "=== Kora workspace dependency graph ==="
cargo tree --workspace --depth 3
echo ""
echo "=== Cycle check ==="
# cargo tree exits non-zero if it encounters a cycle.
# An explicit check with --no-dedupe surfaces all paths.
if cargo tree --workspace --no-dedupe 2>&1 | grep -i "cycle detected"; then
echo "ERROR: Circular dependency detected in workspace."
echo "Fix: remove the cycle shown above before merging."
exit 1
fi
echo "No dependency cycles detected."
# ── KoraError variant consistency guard (issue #421) ─────────────────────
#
# Fails the build if any contract crate references a `KoraError::Variant`
# that isn't actually declared on the `KoraError` enum in
# contracts/shared/src/errors.rs — the recurring bug class behind issues
# #188, #244, #245, #346, #347. Runs independently of `cargo check` so it
# still gives a signal even when the workspace itself fails to compile.
error-variant-guard:
name: KoraError variant consistency
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: "1.75"
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-xtask-${{ hashFiles('**/Cargo.toml') }}
restore-keys: ${{ runner.os }}-xtask-
- name: cargo run -p kora-xtask --bin check-error-variants
run: cargo run -p kora-xtask --bin check-error-variants
# ── Unit & integration tests ──────────────────────────────────────────────
test:
name: cargo test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: "1.75"
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-test-${{ hashFiles('**/Cargo.toml') }}
restore-keys: ${{ runner.os }}-test-
- name: cargo test
run: cargo test --workspace
# ── Code coverage gate (issue #643) ──────────────────────────────────────
#
# Measures code coverage using cargo-tarpaulin with a minimum threshold
# to ensure adequate test coverage across the workspace.
coverage:
name: code coverage
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: "1.75"
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-coverage-${{ hashFiles('**/Cargo.toml') }}
restore-keys: ${{ runner.os }}-coverage-
- name: Install cargo-tarpaulin
run: cargo install cargo-tarpaulin --locked --version 0.21.0
- name: Run coverage analysis
run: make coverage COVERAGE_MIN=95
# ── TTL Keeper validation (issue #644) ───────────────────────────────────
#
# Validates that the TTL keeper script is properly configured for
# scheduled execution with proper error handling and network validation.
ttl-keeper-validation:
name: TTL Keeper validation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate TTL keeper script
run: ./scripts/test-ttl-keeper.sh
# ── Reproducible build verification (issue #645) ─────────────────────────
#
# Validates that WASM binaries are built reproducibly. This ensures that
# the compiled output is deterministic, which is critical for proving that
# deployed contracts match their source code.
reproducible-build-check:
name: Reproducible build verification
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate reproducible build structure
run: ./scripts/test-reproducible-build.sh
# ── WASM size regression gate test (issue #646) ──────────────────────────
#
# Validates that the WASM size regression gate is properly configured to:
# - Track all contract sizes
# - Compare against baseline
# - Fail on regressions exceeding threshold
# - Report results clearly
wasm-size-gate-test:
name: WASM size regression gate validation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate WASM size gate configuration
run: ./scripts/test-wasm-size-gate.sh
# ── Supply-chain audit gate (issue #609) ─────────────────────────────────
#
# Runs cargo-deny (license / banned-crate / source checks against deny.toml)
# and cargo-audit (vulnerability advisories against RustSec database) as a
# blocking CI gate. Both tools are installed at pinned versions so results
# are reproducible.
#
# Exception process:
# - For a known advisory that is accepted-risk: add an `[advisories.ignore]`
# entry in deny.toml with a comment explaining the rationale and a
# tracking issue.
# - For a disallowed license or source: add an explicit `[licenses.allow]`
# or `[sources.allow-git]` entry in deny.toml.
#
# Retry policy: the step retries once on non-zero exit to absorb transient
# registry/network failures (GitHub Actions native retry via a shell loop).
supply-chain-audit:
name: supply-chain audit (cargo-deny + cargo-audit)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
toolchain: "1.75"
- name: Cache cargo registry
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
key: ${{ runner.os }}-audit-${{ hashFiles('**/Cargo.toml', 'deny.toml') }}
restore-keys: ${{ runner.os }}-audit-
- name: Install cargo-deny (pinned)
run: |
# Retry once on transient network failure
cargo install cargo-deny --locked --version 0.14.24 \
|| cargo install cargo-deny --locked --version 0.14.24
- name: Install cargo-audit (pinned)
run: |
cargo install cargo-audit --locked --version 0.21.0 \
|| cargo install cargo-audit --locked --version 0.21.0
- name: cargo deny check
# Fail on vulnerabilities, disallowed licenses, banned crates, and
# disallowed registries/sources. Retry once on transient registry
# network failures (exit code 1 can also mean a real deny failure,
# but a second attempt distinguishes the two in most cases).
run: |
cargo deny check \
|| cargo deny check
- name: cargo audit
# Fetch the advisory database and check for known CVEs.
# --deny warnings escalates unmaintained/unsound to a failure.
# Retry once for network resilience.
run: |
cargo audit --deny warnings \
|| cargo audit --deny warnings