Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 5 additions & 0 deletions Creditra-Contracts/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[target.x86_64-pc-windows-msvc]
#linker = "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.44.35207\\bin\\Hostx64\\x64\\link.exe"

[env]
#LIB = "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.44.35207\\lib\\x64;C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.26100.0\\um\\x64;C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.26100.0\\ucrt\\x64"
231 changes: 231 additions & 0 deletions Creditra-Contracts/.github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
name: CI

on:
push:
branches: [main, master, develop]
pull_request:
branches: [main, master, develop]

concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
CARGO_TERM_COLOR: always
# Reproducible builds: resolve dependencies strictly from the committed
# Cargo.lock. Any drift (manifest edit without lock refresh) fails the build
# instead of silently picking new dependency versions.
CARGOFLAGS: --locked
# Pinned cargo-llvm-cov version. Bump deliberately in the same commit as any
# toolchain bump: a different reporter can move the measured line percentage
# and therefore trip the floor below.
CARGO_LLVM_COV_VERSION: "0.9.1"
# Enforced line-coverage floor, in percent, for contracts/creditra-credit.
#
# This is the single source of truth for the floor. `docs/COVERAGE.md` and
# `README.md` describe it in prose; this value is what CI actually enforces.
#
# 92 is a ratchet on the measured 92.93% (3777 lines, 3510 covered), leaving
# ~0.93pp of headroom so unrelated PRs are not blocked by fractional drift.
# The floor is raised as tests land — never lowered to unblock a PR.
#
# Note: the 95% figure previously advertised in README.md was measured over
# the root Soroban workspace, which does not compile on main and therefore
# cannot be measured by any tool. See docs/COVERAGE.md.
MIN_LINE_COVERAGE: "92"

jobs:
contract:
name: Creditra credit contract
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

# Single source of truth: the exact channel pinned in
# rust-toolchain.toml. Do not hardcode versions here and do not use
# floating channel refs for the toolchain action — both are rejected
# by scripts/check-toolchain.sh so local and CI builds cannot diverge.
- name: Read pinned toolchain channel
id: toolchain
run: |
set -euo pipefail
channel="$(sed -n 's/^[[:space:]]*channel[[:space:]]*=[[:space:]]*"\([^"]*\)".*/\1/p' rust-toolchain.toml | head -n1)"
if [[ -z "$channel" ]]; then
echo "::error::Could not read the pinned channel from rust-toolchain.toml"
exit 1
fi
echo "channel=$channel" >> "$GITHUB_OUTPUT"
echo "Pinned toolchain channel: $channel"

- name: Install pinned Rust toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ steps.toolchain.outputs.channel }}
targets: wasm32-unknown-unknown
components: rustfmt, clippy

# Fail fast — before any compile — if the runner's active toolchain,
# lock files, or the workflow itself drift from the reproducible-build
# policy (e.g. a stray rustup override or an uncommitted Cargo.lock).
- name: Verify reproducible-build policy
run: scripts/check-toolchain.sh --verify-active --lock contracts/creditra-credit/Cargo.lock

- name: Validate generated contract interfaces
run: scripts/validate_schemas.sh

# The reproducible-build guard scripts are the enforcement layer for the
# pinned-toolchain policy. Run their own test suites so a regression in
# the guards themselves fails CI, not just a regression in the contracts.
# (Bash-only, no Rust toolchain required.)
- name: Test reproducible-build guard scripts
run: |
set -euo pipefail
scripts/test_check_toolchain.sh
scripts/test_check_wasm_size.sh

- name: Print toolchain versions
run: |
rustc --version
cargo --version
rustup target list --installed

- name: Check formatting
working-directory: contracts/creditra-credit
run: cargo fmt -- --check

- name: Run clippy
working-directory: contracts/creditra-credit
run: cargo clippy $CARGOFLAGS --all-targets -- -D warnings

- name: Run tests
working-directory: contracts/creditra-credit
run: cargo test $CARGOFLAGS --no-fail-fast

- name: Build native release
working-directory: contracts/creditra-credit
run: cargo build $CARGOFLAGS --release

- name: Build WASM release
working-directory: contracts/creditra-credit
env:
RUSTFLAGS: -C link-arg=--allow-undefined
# Build only the library for the wasm target so host-side binaries
# (e.g. the `schema` generator) are not compiled for wasm. This
# prevents host-only macros and traits from being evaluated for the
# wasm build and avoids CI failures when building the artifact.
run: cargo build $CARGOFLAGS --release --lib --target wasm32-unknown-unknown

# Enforce the artifact size budget with the same scanner the guard tests
# exercise (scripts/check-wasm-size.sh), so CI and local policy checks
# share one implementation. Threshold is unchanged at 614,400 bytes.
- name: Verify WASM artifact
env:
THRESHOLD_BYTES: "614400"
WASM_DIR: contracts/creditra-credit/target/wasm32-unknown-unknown/release
run: scripts/check-wasm-size.sh --check-only

- name: Upload WASM artifact
uses: actions/upload-artifact@v4
with:
name: creditra-credit-wasm
path: contracts/creditra-credit/target/wasm32-unknown-unknown/release/creditra_credit.wasm
if-no-files-found: error

# Line-coverage floor. Kept as its own job so it is a distinct, independently
# gateable required check: a coverage regression reads as a coverage failure
# instead of hiding inside the contract job.
coverage:
name: Line coverage floor
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

# Same pin-reading step as the contract job. rust-toolchain.toml is the
# single source of truth, so coverage is measured by the exact compiler
# that produces the shipped WASM.
- name: Read pinned toolchain channel
id: toolchain
run: |
set -euo pipefail
channel="$(sed -n 's/^[[:space:]]*channel[[:space:]]*=[[:space:]]*"\([^"]*\)".*/\1/p' rust-toolchain.toml | head -n1)"
if [[ -z "$channel" ]]; then
echo "::error::Could not read the pinned channel from rust-toolchain.toml"
exit 1
fi
echo "channel=$channel" >> "$GITHUB_OUTPUT"
echo "Pinned toolchain channel: $channel"

# `llvm-tools` is required by cargo-llvm-cov; it is declared in
# rust-toolchain.toml so it is installed here rather than fetched ad hoc.
- name: Install pinned Rust toolchain
uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ steps.toolchain.outputs.channel }}
targets: wasm32-unknown-unknown
components: rustfmt, clippy, llvm-tools

- name: Install cargo-llvm-cov
run: cargo install cargo-llvm-cov --version "$CARGO_LLVM_COV_VERSION" --locked

# The coverage job gates on numbers, so it must also enforce the same
# reproducible-build policy the contract job does. A drifted toolchain or
# an uncommitted lock file would otherwise produce a floor verdict from a
# build CI would never ship.
- name: Verify reproducible-build policy
run: scripts/check-toolchain.sh --verify-active --lock contracts/creditra-credit/Cargo.lock

# This step is the floor. `cargo llvm-cov` writes the HTML report first and
# then exits non-zero when measured line coverage is below
# MIN_LINE_COVERAGE, so the job fails the workflow while the report below
# is still produced for inspection.
- name: Measure line coverage
working-directory: contracts/creditra-credit
run: cargo llvm-cov --all-targets --html --fail-under-lines "$MIN_LINE_COVERAGE"

# `if: always()` is deliberate: the report is most valuable when the floor
# was breached, and a failing step would otherwise skip the upload and the
# summary, leaving the failure unexplained.
- name: Publish coverage summary
if: always()
working-directory: contracts/creditra-credit
env:
REPORT_JSON: target/llvm-cov/coverage.json
run: |
set -euo pipefail
if [[ ! -d target/llvm-cov/html ]]; then
echo "::error::No coverage report was produced; the measurement step failed before writing one."
exit 1
fi
cargo llvm-cov report --json > "$REPORT_JSON"
pct="$(jq -r '.data[0].totals.lines.percent' "$REPORT_JSON")"
covered="$(jq -r '.data[0].totals.lines.covered' "$REPORT_JSON")"
total="$(jq -r '.data[0].totals.lines.count' "$REPORT_JSON")"
{
echo "## Line coverage"
echo
echo "| Metric | Value |"
echo "| --- | --- |"
echo "| Measured line coverage | ${pct}% |"
echo "| Enforced floor (MIN_LINE_COVERAGE) | ${MIN_LINE_COVERAGE}% |"
echo "| Covered / total lines | ${covered} / ${total} |"
echo
echo "Uncovered lines per file:"
echo
echo '```'
cargo llvm-cov report --show-missing-lines --summary-only | sed -n '/^Uncovered Lines:/,$p'
echo '```'
} >> "$GITHUB_STEP_SUMMARY"

# Replaces the coverage/ HTML tree that used to be committed to git. The
# directory is already ignored via `/coverage` in .gitignore; the report is
# now attached to each run so it can never go stale again.
- name: Upload coverage report
if: always()
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: contracts/creditra-credit/target/llvm-cov/html
if-no-files-found: error
retention-days: 14
24 changes: 24 additions & 0 deletions Creditra-Contracts/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/target
# Root workspace lock is committed (reproducible builds); the anchored pattern
# keeps sub-workspace lock files (e.g. contracts/creditra-credit/Cargo.lock)
# committable too.
/Cargo.lock
**/*.rs.bk
.env
/coverage
test_snapshots/
*.proptest-regressions
*.profraw
**/*.profraw
/docs/superpowers/
/.remember/
.vscode/
.idea/
*.swp
*.swo
.DS_Store
rustup-init.exe
verify_preservation_baseline.exe
verify_preservation_baseline.pdb
*.wasm
.aider*
55 changes: 55 additions & 0 deletions Creditra-Contracts/.idx/dev.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# To learn more about how to use Nix to configure your environment
# see: https://firebase.google.com/docs/studio/customize-workspace
{ pkgs, ... }: {
# Which nixpkgs channel to use.
channel = "stable-24.05"; # or "unstable"

# Use https://search.nixos.org/packages to find packages
packages = [
# pkgs.go
# pkgs.python311
# pkgs.python311Packages.pip
# pkgs.nodejs_20
# pkgs.nodePackages.nodemon
];

# Sets environment variables in the workspace
env = {};
idx = {
# Search for the extensions you want on https://open-vsx.org/ and use "publisher.id"
extensions = [
# "vscodevim.vim"
];

# Enable previews
previews = {
enable = true;
previews = {
# web = {
# # Example: run "npm run dev" with PORT set to IDX's defined port for previews,
# # and show it in IDX's web preview panel
# command = ["npm" "run" "dev"];
# manager = "web";
# env = {
# # Environment variables to set for your server
# PORT = "$PORT";
# };
# };
};
};

# Workspace lifecycle hooks
workspace = {
# Runs when a workspace is first created
onCreate = {
# Example: install JS dependencies from NPM
# npm-install = "npm install";
};
# Runs when the workspace is (re)started
onStart = {
# Example: start a background task to watch and re-build backend code
# watch-backend = "npm run watch-backend";
};
};
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"specId": "9e1eb760-12f1-4b16-a002-3091ca4682b8", "workflowType": "requirements-first", "specType": "feature"}
Loading
Loading