macula-rust 0.8.0

Rust SDK for the macula 12 mesh: ML-DSA-87 and LAMPS composite node keys, a post-quantum QUIC transport — mobile first, not mobile-only.
Documentation
name: Release to crates.io

on:
  push:
    tags: ["v*"]

jobs:
  publish:
    name: publish to crates.io
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: dtolnay/rust-toolchain@stable

      - name: Extract version from tag
        id: version
        run: echo "VERSION=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT"

      - name: Validate version matches Cargo.toml
        run: |
          PACKAGE_VERSION=$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -1)
          if [ "$PACKAGE_VERSION" != "${{ steps.version.outputs.VERSION }}" ]; then
            echo "::error::Tag version (${{ steps.version.outputs.VERSION }}) doesn't match Cargo.toml version ($PACKAGE_VERSION)"
            exit 1
          fi

      # Rebuilds and re-runs the suite here rather than trusting an artifact
      # from ci.yml's run: a tag push is a separate event from the branch
      # push ci.yml validated, so there is no prior run to reuse. --locked:
      # the committed Cargo.lock is what was tested.
      # The integration tests dial macula-go's in-process stations
      # (tests/teststation), built to target/teststation first.
      - uses: actions/setup-go@v5
        with:
          go-version-file: tests/teststation/go.mod
          cache-dependency-path: tests/teststation/go.sum
      - run: ./scripts/build-teststation.sh
      - run: cargo build --workspace --all-targets --locked
      - run: cargo test --workspace --all-features --locked
      - run: cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
      - run: cargo fmt --all -- --check

      # Dry-run needs no registry auth -- it only verifies metadata,
      # compresses the package, and checks the result, never uploads.
      - name: Dry-run publish (catches packaging issues before the real one)
        run: cargo publish --dry-run

      # CRATES_IO_TOKEN (a plain crates.io API token, cargo login-style) --
      # NOT OIDC Trusted Publishing, unlike this org's npm (macula-mcp)
      # and NuGet (macula-dotnet) release workflows. crates.io does
      # support Trusted Publishing (rust-lang/crates-io-auth-action, same
      # shape as those two), but it has no PyPI-style "pending publisher"
      # for a crate that doesn't exist yet -- a Trusted Publisher can only
      # be configured on crates.io AFTER a crate's first release already
      # exists there. A static token is the only mechanism that can
      # actually perform that first release from CI at all.
      #
      # macula-rust v0.2.3 published this way 2026-09-05 -- the migration
      # path once someone wants to spend the time on it: add a Trusted
      # Publisher for macula-io/macula-rust + this workflow file in the
      # crate's crates.io settings, replace this step with
      # `rust-lang/crates-io-auth-action@v1` (permissions:
      # id-token: write) feeding its `token` output to
      # CARGO_REGISTRY_TOKEN the same way, then delete the CRATES_IO_TOKEN
      # repo secret -- no code reason to keep a long-lived token around
      # once the OIDC path is available.
      - name: Publish to crates.io
        run: cargo publish
        env:
          CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}