chain-module-sdk-rust/crates/fai-module-sdk/tests/wit_freeze.rs
flemming-it d3642853ec
All checks were successful
CI / Linux x86_64 (Forgejo) (push) Successful in 1m41s
feat: initial fai-module-sdk v0.1.0 with #[fai_module] macro
The SDK provides a stable, ergonomic Rust surface for writing
F∆I Platform modules. A module is now a single decorated
function:

    #[fai_module]
    fn invoke(_ctx: Context, inputs: Inputs)
        -> Result<Outputs, ModuleError>
    {
        let text = inputs.require_text("input")?;
        Ok(Outputs::new().with_text("output", format!("echo: {text}")))
    }

The macro absorbs every piece of WASM-module boilerplate that
previously lived per-repo: the wit_bindgen::generate! call, the
Guest trait impl, the WIT-to-SDK type conversions, the
wit_bindgen::export! glue, and the unsafe_op_in_unsafe_fn allow
attribute. Module repos depend only on fai-module-sdk and need
no wit/ directory of their own — the SDK ships a verified
mirror of the platform's frozen v1.0 WIT contract.

The SDK is the central lever for keeping the contract stable
without freezing module ergonomics. If the platform ever bumps
the WIT contract (additive minor or coordinated v2.0), the
change is absorbed inside the SDK; existing module source
keeps compiling against a new SDK release.

Components in this initial drop:

  crates/fai-module-sdk
      Public types — Context, Inputs, Outputs, Payload,
      ModuleError. Helpers like require_text / require_json /
      with_bytes / with_json. Pure Rust, no wit_bindgen
      dependency in user-facing code.

  crates/fai-module-sdk-macros
      The proc-macro crate that emits the wit_bindgen call,
      the Guest impl, the WIT<->SDK conversion code, and the
      export! invocation. Uses runtime_path to route the
      generated bindings through the SDK's re-export of
      wit_bindgen::rt so user crates need no direct dep.

  wit/world.wit
      Mirror of fai/platform :: wit/world.wit, frozen at v1.0.
      A snapshot test (crates/fai-module-sdk/tests/wit_freeze.rs)
      asserts the SHA-256 matches the platform constant; CI
      fails if the two ever drift.

  examples/echo
      Reference module that demonstrates the entire authoring
      surface. Compiles to wasm32-wasip2 with the correct
      v1.0 imports baked in (verified manually; CI runs the
      same build).

Tests: 7 unit tests + 1 snapshot test. Cargo fmt and clippy
clean across the workspace and the example.

Forgejo CI workflow mirrors the platform pattern (manual
external-URL checkout + libssl-dev system deps + wasm32-wasip2
target + workspace fmt/clippy/build/test + example wasm build).

Signed-off-by: flemming-it <sf@flemming.it>
2026-05-01 02:23:44 +02:00

53 lines
1.9 KiB
Rust

//! Snapshot test for the WIT mirror.
//!
//! The SDK ships its own copy of `wit/world.wit` so the proc-macro
//! can embed it via `include_str!` at compile time. The hash MUST
//! match the platform's frozen v1.0 hash. If this test fails, the
//! mirror has drifted and the SDK cannot guarantee binary
//! compatibility with the platform.
#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
use std::path::PathBuf;
use sha2::{Digest, Sha256};
/// Identical to FROZEN_WIT_SHA256 in
/// fai/platform :: crates/fai_runtime/tests/wit_freeze.rs.
/// Update both repos in lockstep, never one alone.
const PLATFORM_FROZEN_WIT_SHA256: &str =
"6f4e2266a4264832a16fe5a3704622cd978b290b90f3300c3ed236d98b689b5f";
fn world_wit_path() -> PathBuf {
PathBuf::from(env!("CARGO_MANIFEST_DIR"))
.parent()
.expect("crates parent")
.parent()
.expect("workspace root")
.join("wit")
.join("world.wit")
}
#[test]
fn wit_mirror_matches_platform_frozen_hash() {
let path = world_wit_path();
let bytes = std::fs::read(&path).unwrap_or_else(|e| panic!("read {}: {e}", path.display()));
let mut hasher = Sha256::new();
hasher.update(&bytes);
let actual = format!("{:x}", hasher.finalize());
assert_eq!(
actual, PLATFORM_FROZEN_WIT_SHA256,
"\n\nwit/world.wit in this repo has drifted from the platform's\n\
frozen v1.0 hash. The SDK MUST mirror the platform exactly\n\
or modules built with this SDK will not be wire-compatible.\n\n\
If the platform intentionally bumped to a new minor (e.g.\n\
v1.1 with additive changes), update BOTH:\n\
1. wit/world.wit here to match the platform copy\n\
2. PLATFORM_FROZEN_WIT_SHA256 in this test\n\n\
If the platform is still on the old hash, revert this WIT\n\
change.\n\n\
actual hash: {actual}\n"
);
}