From 46f61aa7fc7bd522785cb9aa723d2b475448b3da Mon Sep 17 00:00:00 2001 From: adelayoub Date: Wed, 25 Feb 2026 07:36:00 +0100 Subject: [PATCH 1/7] refactor(rust): apply cargo fmt formatting --- rust/src/api/encryption/aes_gcm.rs | 12 +++------ rust/src/api/hashing/argon2.rs | 28 +++++++++++++------- rust/src/api/hashing/blake3.rs | 20 +++++++++------ rust/src/api/hashing/mod.rs | 30 ++++++++++++---------- rust/src/api/hashing/sha3.rs | 18 ++++++------- rust/src/api/kdf/hkdf.rs | 41 ++++++++++-------------------- rust/src/core/mod.rs | 2 +- rust/src/core/secret.rs | 2 +- 8 files changed, 76 insertions(+), 77 deletions(-) diff --git a/rust/src/api/encryption/aes_gcm.rs b/rust/src/api/encryption/aes_gcm.rs index 519d3f8..d401f4c 100644 --- a/rust/src/api/encryption/aes_gcm.rs +++ b/rust/src/api/encryption/aes_gcm.rs @@ -220,19 +220,15 @@ mod tests { fn nist_test_vector_decrypt() { let key = hex("feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308"); let nonce = hex("cafebabefacedbaddecaf888"); - let expected_pt = hex( - "d9313225f88406e5a55909c5aff5269a\ + let expected_pt = hex("d9313225f88406e5a55909c5aff5269a\ 86a7a9531534f7da2e4c303d8a318a72\ 1c3c0c95956809532fcf0e2449a6b525\ - b16aedf5aa0de657ba637b39", - ); + b16aedf5aa0de657ba637b39"); let aad = hex("feedfacedeadbeeffeedfacedeadbeefabaddad2"); - let ct = hex( - "522dc1f099567d07f47f37a32a84427d\ + let ct = hex("522dc1f099567d07f47f37a32a84427d\ 643a8cdcbfe5c0c97598a2bd2555d1aa\ 8cb08e48590dbb3da7b08b1056828838\ - c5f61e6393ba7a0abcc9f662", - ); + c5f61e6393ba7a0abcc9f662"); let tag = hex("76fc6ece0f4e1768cddf8853bb2d551b"); // Build wire format: nonce || ciphertext || tag diff --git a/rust/src/api/hashing/argon2.rs b/rust/src/api/hashing/argon2.rs index d45c487..ff248de 100644 --- a/rust/src/api/hashing/argon2.rs +++ b/rust/src/api/hashing/argon2.rs @@ -95,8 +95,8 @@ mod tests { #[test] fn test_hash_contains_preset_params() { - let hash = argon2id_hash("test".into(), Argon2Preset::Mobile) - .expect("hashing should succeed"); + let hash = + argon2id_hash("test".into(), Argon2Preset::Mobile).expect("hashing should succeed"); // Mobile: m=65536 (64*1024), t=3, p=4 assert!(hash.contains("m=65536"), "Missing memory param: {}", hash); @@ -106,8 +106,8 @@ mod tests { #[test] fn test_hash_desktop_preset_params() { - let hash = argon2id_hash("test".into(), Argon2Preset::Desktop) - .expect("hashing should succeed"); + let hash = + argon2id_hash("test".into(), Argon2Preset::Desktop).expect("hashing should succeed"); // Desktop: m=262144 (256*1024), t=4, p=8 assert!(hash.contains("m=262144"), "Missing memory param: {}", hash); @@ -147,7 +147,10 @@ mod tests { let hash2 = argon2id_hash_with_salt("password".into(), salt.into(), Argon2Preset::Mobile) .expect("hashing should succeed"); - assert_eq!(hash1, hash2, "Same password + salt should produce same hash"); + assert_eq!( + hash1, hash2, + "Same password + salt should produce same hash" + ); } #[test] @@ -159,7 +162,10 @@ mod tests { let hash2 = argon2id_hash_with_salt("password2".into(), salt.into(), Argon2Preset::Mobile) .expect("hashing should succeed"); - assert_ne!(hash1, hash2, "Different passwords should produce different hashes"); + assert_ne!( + hash1, hash2, + "Different passwords should produce different hashes" + ); } #[test] @@ -196,7 +202,11 @@ mod tests { #[test] fn test_invalid_salt() { - let result = argon2id_hash_with_salt("password".into(), "!!!invalid!!!".into(), Argon2Preset::Mobile); + let result = argon2id_hash_with_salt( + "password".into(), + "!!!invalid!!!".into(), + Argon2Preset::Mobile, + ); assert!(result.is_err()); match result { Err(CryptoError::InvalidParameter(_)) => {} // expected @@ -207,8 +217,8 @@ mod tests { #[test] fn test_empty_password_hashes() { // Empty password is valid — Argon2id should handle it - let hash = argon2id_hash(String::new(), Argon2Preset::Mobile) - .expect("empty password should hash"); + let hash = + argon2id_hash(String::new(), Argon2Preset::Mobile).expect("empty password should hash"); assert!(hash.starts_with("$argon2id$")); assert!(argon2id_verify(hash, String::new()).is_ok()); } diff --git a/rust/src/api/hashing/blake3.rs b/rust/src/api/hashing/blake3.rs index 49e81e2..223f9b2 100644 --- a/rust/src/api/hashing/blake3.rs +++ b/rust/src/api/hashing/blake3.rs @@ -56,9 +56,9 @@ mod tests { let digest = hasher.finalize().expect("finalize should succeed"); // BLAKE3 empty string hash (official test vector) - let expected = hex::decode( - "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262" - ).expect("valid hex"); + let expected = + hex::decode("af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262") + .expect("valid hex"); assert_eq!(digest, expected); } @@ -66,13 +66,15 @@ mod tests { #[test] fn test_hello_world() { let mut hasher = Blake3Hasher::new(); - hasher.update(b"hello world").expect("update should succeed"); + hasher + .update(b"hello world") + .expect("update should succeed"); let digest = hasher.finalize().expect("finalize should succeed"); // BLAKE3("hello world") - verified against reference implementation - let expected = hex::decode( - "d74981efa70a0c880b8d8c1985d075dbcbf679b99a5f9914e5aaf96b831a9e24" - ).expect("valid hex"); + let expected = + hex::decode("d74981efa70a0c880b8d8c1985d075dbcbf679b99a5f9914e5aaf96b831a9e24") + .expect("valid hex"); assert_eq!(digest, expected); } @@ -101,7 +103,9 @@ mod tests { // After reset, should produce empty hash let digest = hasher.finalize().expect("finalize should succeed"); - let empty_hash = Blake3Hasher::new().finalize().expect("finalize should succeed"); + let empty_hash = Blake3Hasher::new() + .finalize() + .expect("finalize should succeed"); assert_eq!(digest, empty_hash); } diff --git a/rust/src/api/hashing/mod.rs b/rust/src/api/hashing/mod.rs index da7cab4..9846b05 100644 --- a/rust/src/api/hashing/mod.rs +++ b/rust/src/api/hashing/mod.rs @@ -1,8 +1,8 @@ //! Hashing API module. +pub mod argon2; mod blake3; mod sha3; -pub mod argon2; use crate::core::error::CryptoError; use crate::core::traits::Hasher; @@ -37,33 +37,37 @@ pub fn create_sha3() -> HasherHandle { /// Feed data into the hasher. pub fn hasher_update(handle: &HasherHandle, data: Vec) -> Result<(), CryptoError> { - let mut guard = handle.inner.lock().map_err(|_| { - CryptoError::HashingFailed("Hasher lock poisoned".into()) - })?; + let mut guard = handle + .inner + .lock() + .map_err(|_| CryptoError::HashingFailed("Hasher lock poisoned".into()))?; guard.update(&data) } /// Reset the hasher to its initial state. pub fn hasher_reset(handle: &HasherHandle) -> Result<(), CryptoError> { - let mut guard = handle.inner.lock().map_err(|_| { - CryptoError::HashingFailed("Hasher lock poisoned".into()) - })?; + let mut guard = handle + .inner + .lock() + .map_err(|_| CryptoError::HashingFailed("Hasher lock poisoned".into()))?; guard.reset() } /// Finalize and return the digest. pub fn hasher_finalize(handle: &HasherHandle) -> Result, CryptoError> { - let guard = handle.inner.lock().map_err(|_| { - CryptoError::HashingFailed("Hasher lock poisoned".into()) - })?; + let guard = handle + .inner + .lock() + .map_err(|_| CryptoError::HashingFailed("Hasher lock poisoned".into()))?; guard.finalize() } /// Get the algorithm identifier for the hasher. pub fn hasher_algorithm_id(handle: &HasherHandle) -> Result { - let guard = handle.inner.lock().map_err(|_| { - CryptoError::HashingFailed("Hasher lock poisoned".into()) - })?; + let guard = handle + .inner + .lock() + .map_err(|_| CryptoError::HashingFailed("Hasher lock poisoned".into()))?; Ok(guard.algorithm_id().to_string()) } diff --git a/rust/src/api/hashing/sha3.rs b/rust/src/api/hashing/sha3.rs index 4a66805..3447c0b 100644 --- a/rust/src/api/hashing/sha3.rs +++ b/rust/src/api/hashing/sha3.rs @@ -57,10 +57,9 @@ mod tests { let digest = hasher.finalize().expect("finalize should succeed"); // NIST SHA-3 empty string test vector - let expected = hex::decode( - "a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a", - ) - .expect("valid hex"); + let expected = + hex::decode("a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a") + .expect("valid hex"); assert_eq!(digest, expected); } @@ -72,10 +71,9 @@ mod tests { let digest = hasher.finalize().expect("finalize should succeed"); // NIST SHA-3("abc") test vector - let expected = hex::decode( - "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", - ) - .expect("valid hex"); + let expected = + hex::decode("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532") + .expect("valid hex"); assert_eq!(digest, expected); } @@ -104,7 +102,9 @@ mod tests { // After reset, should produce empty hash let digest = hasher.finalize().expect("finalize should succeed"); - let empty_hash = Sha3Hasher::new().finalize().expect("finalize should succeed"); + let empty_hash = Sha3Hasher::new() + .finalize() + .expect("finalize should succeed"); assert_eq!(digest, empty_hash); } diff --git a/rust/src/api/kdf/hkdf.rs b/rust/src/api/kdf/hkdf.rs index eaebed3..f942e99 100644 --- a/rust/src/api/kdf/hkdf.rs +++ b/rust/src/api/kdf/hkdf.rs @@ -41,10 +41,7 @@ pub fn hkdf_derive( /// Input key material (`ikm`, `salt`) is zeroed before the function returns. /// The caller is responsible for zeroizing the returned PRK. #[frb(sync)] -pub fn hkdf_extract( - mut ikm: Vec, - mut salt: Option>, -) -> Result, CryptoError> { +pub fn hkdf_extract(mut ikm: Vec, mut salt: Option>) -> Result, CryptoError> { let salt_ref = salt.as_ref().map(Vec::as_slice); let (prk, _) = Hkdf::::extract(salt_ref, &ikm); ikm.zeroize(); @@ -151,11 +148,9 @@ mod tests { let ikm = hex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); let salt = Some(hex("000102030405060708090a0b0c")); let info = hex("f0f1f2f3f4f5f6f7f8f9"); - let expected = hex( - "3cb25f25faacd57a90434f64d0362f2a\ + let expected = hex("3cb25f25faacd57a90434f64d0362f2a\ 2d2d0a90cf1a5a4c5db02d56ecc4c5bf\ - 34007208d5b887185865", - ); + 34007208d5b887185865"); let result = hkdf_derive(ikm, salt, info, 42).unwrap(); assert_eq!(result, expected); } @@ -163,35 +158,27 @@ mod tests { // RFC 5869 Test Case 2 (long inputs) #[test] fn rfc5869_test_case_2() { - let ikm = hex( - "000102030405060708090a0b0c0d0e0f\ + let ikm = hex("000102030405060708090a0b0c0d0e0f\ 101112131415161718191a1b1c1d1e1f\ 202122232425262728292a2b2c2d2e2f\ 303132333435363738393a3b3c3d3e3f\ - 404142434445464748494a4b4c4d4e4f", - ); - let salt = Some(hex( - "606162636465666768696a6b6c6d6e6f\ + 404142434445464748494a4b4c4d4e4f"); + let salt = Some(hex("606162636465666768696a6b6c6d6e6f\ 707172737475767778797a7b7c7d7e7f\ 808182838485868788898a8b8c8d8e8f\ 909192939495969798999a9b9c9d9e9f\ - a0a1a2a3a4a5a6a7a8a9aaabacadaeaf", - )); - let info = hex( - "b0b1b2b3b4b5b6b7b8b9babbbcbdbebf\ + a0a1a2a3a4a5a6a7a8a9aaabacadaeaf")); + let info = hex("b0b1b2b3b4b5b6b7b8b9babbbcbdbebf\ c0c1c2c3c4c5c6c7c8c9cacbcccdcecf\ d0d1d2d3d4d5d6d7d8d9dadbdcdddedf\ e0e1e2e3e4e5e6e7e8e9eaebecedeeef\ - f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", - ); - let expected = hex( - "b11e398dc80327a1c8e7f78c596a4934\ + f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"); + let expected = hex("b11e398dc80327a1c8e7f78c596a4934\ 4f012eda2d4efad8a050cc4c19afa97c\ 59045a99cac7827271cb41c65e590e09\ da3275600c2f09b8367793a9aca3db71\ cc30c58179ec3e87c14c01d5c1f3434f\ - 1d87", - ); + 1d87"); let result = hkdf_derive(ikm, salt, info, 82).unwrap(); assert_eq!(result, expected); } @@ -201,11 +188,9 @@ mod tests { fn rfc5869_test_case_3() { let ikm = hex("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); let info = vec![]; - let expected = hex( - "8da4e775a563c18f715f802a063c5a31\ + let expected = hex("8da4e775a563c18f715f802a063c5a31\ b8a11f5c5ee1879ec3454e5f3c738d2d\ - 9d201395faa4b61a96c8", - ); + 9d201395faa4b61a96c8"); let result = hkdf_derive(ikm, None, info, 42).unwrap(); assert_eq!(result, expected); } diff --git a/rust/src/core/mod.rs b/rust/src/core/mod.rs index 050b202..a314d3b 100644 --- a/rust/src/core/mod.rs +++ b/rust/src/core/mod.rs @@ -7,4 +7,4 @@ pub mod error; pub mod format; pub mod rng; pub mod secret; -pub mod traits; \ No newline at end of file +pub mod traits; diff --git a/rust/src/core/secret.rs b/rust/src/core/secret.rs index 521d637..b907255 100644 --- a/rust/src/core/secret.rs +++ b/rust/src/core/secret.rs @@ -1,7 +1,7 @@ //! Secure memory wrapper that zeroes on drop. -use std::fmt; use flutter_rust_bridge::frb; +use std::fmt; use zeroize::{Zeroize, ZeroizeOnDrop}; /// A buffer that securely zeroes its contents when dropped. From 2c7b9d938d765a5b2b4965779cf58a3ad546569e Mon Sep 17 00:00:00 2001 From: adelayoub Date: Wed, 25 Feb 2026 07:44:19 +0100 Subject: [PATCH 2/7] build(ci): add GitHub Actions pipeline for rust, Dart, Android, and ios --- .github/workflows/ci.yml | 73 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..452fa83 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,73 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + rust: + name: Rust (lint + test) + runs-on: ubuntu-latest + defaults: + run: + working-directory: rust + steps: + - uses: actions/checkout@v4 + - uses: dtolnay/rust-toolchain@stable + with: + components: clippy + - uses: Swatinem/rust-cache@v2 + with: + workspaces: rust + - run: cargo clippy --all-targets -- -D warnings + - run: cargo test + + dart: + name: Dart (analyze) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + channel: stable + - run: flutter pub get + - run: dart analyze lib/ integration_test/ + + build-android: + name: Android build + needs: [rust, dart] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + channel: stable + - uses: dtolnay/rust-toolchain@stable + with: + targets: aarch64-linux-android,armv7-linux-androideabi + - uses: nttld/setup-ndk@v1 + with: + ndk-version: r27c + - run: flutter pub get + - run: cd example && flutter build apk --release + + build-ios: + name: iOS build + needs: [rust, dart] + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + channel: stable + - uses: dtolnay/rust-toolchain@stable + with: + targets: aarch64-apple-ios,aarch64-apple-ios-sim + - run: flutter pub get + - run: cd example && flutter build ios --release --no-codesign From 165653beb2cc078755a303b5c2a56968c4a9db91 Mon Sep 17 00:00:00 2001 From: adelayoub Date: Wed, 25 Feb 2026 07:48:03 +0100 Subject: [PATCH 3/7] build(ci): add GitHub Actions pipeline for all platforms --- .github/workflows/ci.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 452fa83..5347d63 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,3 +71,30 @@ jobs: targets: aarch64-apple-ios,aarch64-apple-ios-sim - run: flutter pub get - run: cd example && flutter build ios --release --no-codesign + + build-linux: + name: Linux build + needs: [rust, dart] + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + channel: stable + - uses: dtolnay/rust-toolchain@stable + - run: sudo apt-get update && sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev + - run: flutter pub get + - run: cd example && flutter build linux --release + + build-windows: + name: Windows build + needs: [rust, dart] + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2 + with: + channel: stable + - uses: dtolnay/rust-toolchain@stable + - run: flutter pub get + - run: cd example && flutter build windows --release From 9d006782c108db73b7d2f4c0a4e8975ea2181311 Mon Sep 17 00:00:00 2001 From: adelayoub Date: Wed, 25 Feb 2026 07:49:52 +0100 Subject: [PATCH 4/7] build(ci): update --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5347d63..019b51b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,7 +2,7 @@ name: CI on: push: - branches: [main] + branches: [main, ci/test-pipeline] pull_request: branches: [main] From 6bd78cc36b6bfae6fdc85d2605f990861d553930 Mon Sep 17 00:00:00 2001 From: adelayoub Date: Wed, 25 Feb 2026 07:54:36 +0100 Subject: [PATCH 5/7] build(ci): update --- .github/workflows/ci.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 019b51b..5f17683 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,14 +29,17 @@ jobs: - run: cargo test dart: - name: Dart (analyze) + name: Dart (codegen + analyze) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: subosito/flutter-action@v2 with: channel: stable + - uses: dtolnay/rust-toolchain@stable + - run: cargo install flutter_rust_bridge_codegen - run: flutter pub get + - run: flutter_rust_bridge_codegen generate - run: dart analyze lib/ integration_test/ build-android: From 7b2d7f96cb298ad4fe0b89bae40553651e6878c4 Mon Sep 17 00:00:00 2001 From: adelayoub Date: Wed, 25 Feb 2026 08:15:42 +0100 Subject: [PATCH 6/7] fix(ci): ios chnaged to flutter build ios simulator and added some fixes to the freezed generated --- .github/workflows/ci.yml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5f17683..0e3b538 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,6 +40,7 @@ jobs: - run: cargo install flutter_rust_bridge_codegen - run: flutter pub get - run: flutter_rust_bridge_codegen generate + - run: dart run build_runner build --delete-conflicting-outputs - run: dart analyze lib/ integration_test/ build-android: @@ -57,7 +58,10 @@ jobs: - uses: nttld/setup-ndk@v1 with: ndk-version: r27c + - run: cargo install flutter_rust_bridge_codegen - run: flutter pub get + - run: flutter_rust_bridge_codegen generate + - run: dart run build_runner build --delete-conflicting-outputs - run: cd example && flutter build apk --release build-ios: @@ -72,8 +76,11 @@ jobs: - uses: dtolnay/rust-toolchain@stable with: targets: aarch64-apple-ios,aarch64-apple-ios-sim + - run: cargo install flutter_rust_bridge_codegen - run: flutter pub get - - run: cd example && flutter build ios --release --no-codesign + - run: flutter_rust_bridge_codegen generate + - run: dart run build_runner build --delete-conflicting-outputs + - run: cd example && flutter build ios --simulator --debug build-linux: name: Linux build @@ -86,7 +93,10 @@ jobs: channel: stable - uses: dtolnay/rust-toolchain@stable - run: sudo apt-get update && sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev + - run: cargo install flutter_rust_bridge_codegen - run: flutter pub get + - run: flutter_rust_bridge_codegen generate + - run: dart run build_runner build --delete-conflicting-outputs - run: cd example && flutter build linux --release build-windows: @@ -99,5 +109,8 @@ jobs: with: channel: stable - uses: dtolnay/rust-toolchain@stable + - run: cargo install flutter_rust_bridge_codegen - run: flutter pub get + - run: flutter_rust_bridge_codegen generate + - run: dart run build_runner build --delete-conflicting-outputs - run: cd example && flutter build windows --release From 1bb072f05b5c040f67451d70552031cdefec4bfd Mon Sep 17 00:00:00 2001 From: adelayoub Date: Wed, 25 Feb 2026 08:48:54 +0100 Subject: [PATCH 7/7] fix(ci): removed windows --- .github/workflows/ci.yml | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0e3b538..4f69d6e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -98,19 +98,3 @@ jobs: - run: flutter_rust_bridge_codegen generate - run: dart run build_runner build --delete-conflicting-outputs - run: cd example && flutter build linux --release - - build-windows: - name: Windows build - needs: [rust, dart] - runs-on: windows-latest - steps: - - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v2 - with: - channel: stable - - uses: dtolnay/rust-toolchain@stable - - run: cargo install flutter_rust_bridge_codegen - - run: flutter pub get - - run: flutter_rust_bridge_codegen generate - - run: dart run build_runner build --delete-conflicting-outputs - - run: cd example && flutter build windows --release