diff --git a/.github/workflows/main-push-nuget-publish.yml b/.github/workflows/main-push-nuget-publish.yml index 5fc3e03..e32d482 100644 --- a/.github/workflows/main-push-nuget-publish.yml +++ b/.github/workflows/main-push-nuget-publish.yml @@ -7,6 +7,9 @@ on: push: branches: [ "main" ] +permissions: + contents: read + jobs: native-windows: runs-on: windows-latest @@ -54,9 +57,55 @@ jobs: name: native-linux path: cas-dotnet-sdk/artifacts/native/linux-x64 + native-macos-arm64: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - uses: dtolnay/rust-toolchain@stable + + - name: Build Rust (macOS arm64) + working-directory: cas-core-lib + run: cargo build --release + + - name: Stage native + run: | + mkdir -p cas-dotnet-sdk/artifacts/native/osx-arm64 + cp cas-core-lib/target/release/libcas_core_lib.dylib cas-dotnet-sdk/artifacts/native/osx-arm64/ + + - uses: actions/upload-artifact@v4 + with: + name: native-osx-arm64 + path: cas-dotnet-sdk/artifacts/native/osx-arm64 + + native-macos-x64: + runs-on: macos-13 + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - uses: dtolnay/rust-toolchain@stable + + - name: Build Rust (macOS x64) + working-directory: cas-core-lib + run: cargo build --release + + - name: Stage native + run: | + mkdir -p cas-dotnet-sdk/artifacts/native/osx-x64 + cp cas-core-lib/target/release/libcas_core_lib.dylib cas-dotnet-sdk/artifacts/native/osx-x64/ + + - uses: actions/upload-artifact@v4 + with: + name: native-osx-x64 + path: cas-dotnet-sdk/artifacts/native/osx-x64 + pack-and-publish: runs-on: ubuntu-latest - needs: [native-windows, native-linux] + needs: [native-windows, native-linux, native-macos-arm64, native-macos-x64] steps: - uses: actions/checkout@v4 @@ -71,11 +120,23 @@ jobs: name: native-linux path: cas-dotnet-sdk/artifacts/native/linux-x64 + - uses: actions/download-artifact@v4 + with: + name: native-osx-arm64 + path: cas-dotnet-sdk/artifacts/native/osx-arm64 + + - uses: actions/download-artifact@v4 + with: + name: native-osx-x64 + path: cas-dotnet-sdk/artifacts/native/osx-x64 + - name: Verify staged natives run: | ls -R cas-dotnet-sdk/artifacts/native test -f cas-dotnet-sdk/artifacts/native/linux-x64/libcas_core_lib.so test -f cas-dotnet-sdk/artifacts/native/win-x64/cas_core_lib.dll + test -f cas-dotnet-sdk/artifacts/native/osx-arm64/libcas_core_lib.dylib + test -f cas-dotnet-sdk/artifacts/native/osx-x64/libcas_core_lib.dylib - uses: actions/setup-dotnet@v4 with: diff --git a/.github/workflows/pr-tests-linux.yml b/.github/workflows/pr-tests-linux.yml index 040a089..a1d8c22 100644 --- a/.github/workflows/pr-tests-linux.yml +++ b/.github/workflows/pr-tests-linux.yml @@ -5,6 +5,9 @@ on: branches: [ main ] workflow_dispatch: +permissions: + contents: read + concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true diff --git a/.github/workflows/pr-tests-macos-arm64.yml b/.github/workflows/pr-tests-macos-arm64.yml new file mode 100644 index 0000000..c0a6166 --- /dev/null +++ b/.github/workflows/pr-tests-macos-arm64.yml @@ -0,0 +1,57 @@ +name: PR Tests - macOS arm64 + +on: + pull_request: + branches: [ main ] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + build: + # macos-latest is Apple Silicon (osx-arm64). + runs-on: macos-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 6.0.x + 7.0.x + 8.0.x + 9.0.x + 10.0.x + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - name: Build Rust native (macOS arm64) + working-directory: cas-core-lib + run: cargo build --release + + - name: Stage native lib for tests + shell: bash + run: | + set -euo pipefail + for tfm in net6.0 net7.0 net8.0 net9.0 net10.0; do + OUTDIR="cas-dotnet-sdk-tests/bin/Release/${tfm}" + mkdir -p "$OUTDIR" + cp "cas-core-lib/target/release/libcas_core_lib.dylib" "$OUTDIR/" + done + ls -la cas-dotnet-sdk-tests/bin/Release + + - name: Run tests (all target frameworks) + run: | + echo "Running tests for all target frameworks on macos-latest (arm64)" + dotnet test ./cas-dotnet-sdk-tests/cas-dotnet-sdk-tests.csproj -c Release --logger "trx" diff --git a/.github/workflows/pr-tests-macos-x64.yml b/.github/workflows/pr-tests-macos-x64.yml new file mode 100644 index 0000000..2cce1c3 --- /dev/null +++ b/.github/workflows/pr-tests-macos-x64.yml @@ -0,0 +1,57 @@ +name: PR Tests - macOS x64 + +on: + pull_request: + branches: [ main ] + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + build: + # macos-13 is Intel (osx-x64). + runs-on: macos-13 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: | + 6.0.x + 7.0.x + 8.0.x + 9.0.x + 10.0.x + + - name: Setup Rust + uses: dtolnay/rust-toolchain@stable + + - name: Build Rust native (macOS x64) + working-directory: cas-core-lib + run: cargo build --release + + - name: Stage native lib for tests + shell: bash + run: | + set -euo pipefail + for tfm in net6.0 net7.0 net8.0 net9.0 net10.0; do + OUTDIR="cas-dotnet-sdk-tests/bin/Release/${tfm}" + mkdir -p "$OUTDIR" + cp "cas-core-lib/target/release/libcas_core_lib.dylib" "$OUTDIR/" + done + ls -la cas-dotnet-sdk-tests/bin/Release + + - name: Run tests (all target frameworks) + run: | + echo "Running tests for all target frameworks on macos-13 (x64)" + dotnet test ./cas-dotnet-sdk-tests/cas-dotnet-sdk-tests.csproj -c Release --logger "trx" diff --git a/.github/workflows/pr-tests-windows.yml b/.github/workflows/pr-tests-windows.yml index a9d8ffc..f1b7738 100644 --- a/.github/workflows/pr-tests-windows.yml +++ b/.github/workflows/pr-tests-windows.yml @@ -4,6 +4,9 @@ on: pull_request: branches: [ main ] workflow_dispatch: + +permissions: + contents: read concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} diff --git a/CLAUDE.md b/CLAUDE.md index f239c06..6d5de83 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -10,7 +10,7 @@ CAS .NET SDK is a managed cryptographic toolkit published as the [`cas-dotnet-sd - `cas-dotnet-sdk/` — the SDK class library (NuGet package source). Multi-targets `net6.0`–`net10.0`. - `cas-dotnet-sdk-tests/` — xUnit test project, references the SDK directly. -- `cas-core-lib/` — **git submodule** containing the Rust source compiled to `cas_core_lib.dll` (Windows) / `libcas_core_lib.so` (Linux). Clone with `--recursive` or run `git submodule update --init --recursive`. +- `cas-core-lib/` — **git submodule** containing the Rust source compiled to `cas_core_lib.dll` (Windows) / `libcas_core_lib.so` (Linux) / `libcas_core_lib.dylib` (macOS). Clone with `--recursive` or run `git submodule update --init --recursive`. - `docs/EXAMPLES.md` — usage samples. ## Build & Test @@ -35,6 +35,8 @@ dotnet test ./cas-dotnet-sdk-tests/cas-dotnet-sdk-tests.csproj -f net8.0 --filte dotnet test ./cas-dotnet-sdk-tests/cas-dotnet-sdk-tests.csproj -f net8.0 --filter "DisplayName~Hash512" ``` +The same commands work for local development on macOS: a Rust toolchain on PATH builds `libcas_core_lib.dylib`, and the `StageRustArtifacts` MSBuild target detects the host (Apple Silicon vs Intel) and stages it into `artifacts/native/osx-arm64/` or `artifacts/native/osx-x64/` automatically — no extra flags needed. + Note: CI (`.github/workflows/pr-tests-*.yml`) builds `cargo build --release` separately, then copies the native lib into the test `bin/Release/` directory before running `dotnet test`. If you build the Rust lib by hand and the MSBuild target is skipped, the native artifact must end up next to the test assembly the same way. ## Architecture: the three-layer wrapper pattern @@ -67,4 +69,6 @@ Categories with interchangeable algorithms expose a `*Factory` (e.g. `HasherFact ## Cross-platform constraint -Only **Windows x64** and **Linux x64** are supported (no macOS). All wrappers must keep Windows and Linux paths in sync — a function added to one platform wrapper without the other will throw `DllNotFoundException` / `EntryPointNotFoundException` on the missing platform. Tests run against .NET 6–10 on both OSes in CI on every PR. +Supported targets: **Windows x64**, **Linux x64**, and **macOS** (both `osx-arm64` Apple Silicon and `osx-x64` Intel). Since the csbindgen migration (#191), P/Invoke goes through the generated `generated/NativeMethods.g.cs` using the bare library name `cas_core_lib`; the .NET runtime resolves it per-OS to `cas_core_lib.dll` / `libcas_core_lib.so` / `libcas_core_lib.dylib`, so there are no per-platform `[DllImport]` files to keep in sync. The native lib is built (`cargo build --release`), staged into `artifacts/native//`, and packed into `runtimes//native` for each RID. Tests run against .NET 6–10 on all three OSes in CI on every PR: `pr-tests-windows` and `pr-tests-linux` fan out one job per TFM, while macOS is split by architecture into two separate workflows — `pr-tests-macos-arm64` (`macos-latest`, Apple Silicon) and `pr-tests-macos-x64` (`macos-13`, Intel) — each running all five target frameworks in a single `dotnet test` invocation (no `-f`). The `OperatingSystemDeterminator` resolves Windows, Linux, and OSX and throws on anything else. + +Note: this is desktop **macOS / Darwin**, not iOS. Real iOS (`aarch64-apple-ios`) would need a cross-compiled native lib and a simulator/device to run tests, neither of which the current CI provides. diff --git a/README.md b/README.md index aefd669..e3b7af6 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ CAS .NET SDK is a comprehensive cryptographic toolkit for .NET, designed to prov - Seamless integration with [cas-lib](https://github.com/Cryptographic-API-Services/cas-lib) Rust FFI layer for optimal performance - Unified interface: no need to manage multiple cryptography packages or surf disparate documentation - Built on trusted, open-source cryptography libraries -- Cross-platform support: Windows x64, Linux x64 +- Cross-platform support: Windows x64, Linux x64, macOS (Apple Silicon arm64 & Intel x64) - Multi-framework support: .NET 6, 7, 8, 9, 10 ## Documentation & References @@ -26,7 +26,7 @@ We build on the work of leading cryptography projects. For in-depth algorithm de See practical usage and code samples in our [Examples](./docs/EXAMPLES.md). ## Supported Frameworks / Operating Systems -We aim to provide cross-compatibility wherever possible. Test cases are run on .NET 6-9 for Windows and Linux (Ubuntu) on each pull request and release to NuGet through GitHub Actions. +We aim to provide cross-compatibility wherever possible. Test cases are run on .NET 6-10 for Windows, Linux (Ubuntu), and macOS on each pull request and release to NuGet through GitHub Actions. - [X] .NET 6 - [X] .NET 7 - [X] .NET 8 @@ -34,6 +34,8 @@ We aim to provide cross-compatibility wherever possible. Test cases are run on . - [X] .NET 10 - [X] Windows x64 - [X] Linux x64 +- [X] macOS arm64 (Apple Silicon) +- [X] macOS x64 (Intel) ## Disclaimer This SDK leverages several cryptographic crates via our core FFI [layer](https://github.com/Cryptographic-API-Services/cas-core-lib). Please note that many of these crates have not undergone formal security audits. Use this library at your own risk and always review the underlying cryptographic implementations for your security requirements. diff --git a/cas-dotnet-sdk/README.md b/cas-dotnet-sdk/README.md index 7325155..e3b7af6 100644 --- a/cas-dotnet-sdk/README.md +++ b/cas-dotnet-sdk/README.md @@ -13,8 +13,8 @@ CAS .NET SDK is a comprehensive cryptographic toolkit for .NET, designed to prov - Seamless integration with [cas-lib](https://github.com/Cryptographic-API-Services/cas-lib) Rust FFI layer for optimal performance - Unified interface: no need to manage multiple cryptography packages or surf disparate documentation - Built on trusted, open-source cryptography libraries -- Cross-platform support: Windows x64, Linux x64 -- Multi-framework support: .NET 6, 7, 8, 9 +- Cross-platform support: Windows x64, Linux x64, macOS (Apple Silicon arm64 & Intel x64) +- Multi-framework support: .NET 6, 7, 8, 9, 10 ## Documentation & References We build on the work of leading cryptography projects. For in-depth algorithm details and implementation notes, please refer to: @@ -26,7 +26,7 @@ We build on the work of leading cryptography projects. For in-depth algorithm de See practical usage and code samples in our [Examples](./docs/EXAMPLES.md). ## Supported Frameworks / Operating Systems -We aim to provide cross-compatibility wherever possible. Test cases are run on .NET 6-9 for Windows and Linux (Ubuntu) on each pull request and release to NuGet through GitHub Actions. +We aim to provide cross-compatibility wherever possible. Test cases are run on .NET 6-10 for Windows, Linux (Ubuntu), and macOS on each pull request and release to NuGet through GitHub Actions. - [X] .NET 6 - [X] .NET 7 - [X] .NET 8 @@ -34,6 +34,8 @@ We aim to provide cross-compatibility wherever possible. Test cases are run on . - [X] .NET 10 - [X] Windows x64 - [X] Linux x64 +- [X] macOS arm64 (Apple Silicon) +- [X] macOS x64 (Intel) ## Disclaimer This SDK leverages several cryptographic crates via our core FFI [layer](https://github.com/Cryptographic-API-Services/cas-core-lib). Please note that many of these crates have not undergone formal security audits. Use this library at your own risk and always review the underlying cryptographic implementations for your security requirements. diff --git a/cas-dotnet-sdk/cas-dotnet-sdk.csproj b/cas-dotnet-sdk/cas-dotnet-sdk.csproj index 0b22173..7b5628c 100644 --- a/cas-dotnet-sdk/cas-dotnet-sdk.csproj +++ b/cas-dotnet-sdk/cas-dotnet-sdk.csproj @@ -9,7 +9,7 @@ true cas-dotnet-sdk icon.jpeg - 1.9.75 + 1.9.76 Mike Mulchrone A Nuget package that provides a implementation of the RustCrypto suite of cryptographic algorithms. https://github.com/Cryptographic-API-Services/cas-dotnet-sdk @@ -40,12 +40,25 @@ + + + <_IsOSX>$([MSBuild]::IsOSPlatform('OSX')) + + <_HostArch>$([System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture.ToString().ToLowerInvariant()) + + <_RustOut Include="$(RustProjectDir)\target\release\cas_core_lib.dll" /> <_DestDir Include="$(NativeArtifactsDir)/win-x64/" /> - + + <_RustOut Include="$(RustProjectDir)/target/release/libcas_core_lib.dylib" /> + <_DestDir Include="$(NativeArtifactsDir)/osx-$(_HostArch)/" /> + + + <_RustOut Include="$(RustProjectDir)/target/release/libcas_core_lib.so" /> <_DestDir Include="$(NativeArtifactsDir)/linux-x64/" /> @@ -71,6 +84,22 @@ libcas_core_lib.so PreserveNewest + + + true + runtimes\osx-arm64\native + libcas_core_lib.dylib + PreserveNewest + + + + true + runtimes\osx-x64\native + libcas_core_lib.dylib + PreserveNewest +