SIGN IN SIGN UP

feat: crates.io OIDC trusted publishing for the Rust crates (LEO-326) (#20)

* feat: crates.io OIDC trusted publishing for the Rust crates (LEO-326)

Make sensorwatch-sys self-contained and add tokenless OIDC publishing so the
two Rust crates can ship to crates.io from a reviewed GitHub Release.

- Vendor the C core (src/*.c + internal/public headers) into
  rust/sensorwatch-sys/vendor/ and redirect build.rs + regen-bindings.sh at
  it. cargo publish only packages files under the crate dir, so the sources
  must travel with the crate or a consumer build fails.
- Add a CI `vendor-sync` job that re-copies the canonical core and fails on
  any drift (mirrors the bindgen-drift guard); pin the vendored tree to LF so
  the diff is deterministic across runners.
- Packaging: tight `include` on both crates, per-crate README + LICENSE and
  readme metadata; pin the wrapper dep sensorwatch-sys = "=0.1.0".
- Add publish-crates.yml: fires on `rust-v*` Releases, gates on
  fmt/clippy/test, authenticates via rust-lang/crates-io-auth-action (OIDC,
  no stored CARGO_REGISTRY_TOKEN), publishes sensorwatch-sys then sensorwatch.
- Guard publish.yml (PyPI) to ignore `rust-v*` tags so the PyPI and crates.io
  release streams don't collide.
- Docs: CONTRIBUTING "Releasing the Rust crates" (recipe, one-time
  trusted-publisher setup, vendor re-sync), README install note, SECURITY.md
  §6.3 supply-chain note.

Verified locally: cargo fmt/clippy/test --workspace clean; cargo package
--list -p sensorwatch-sys ships the vendored C sources; cargo publish
--dry-run -p sensorwatch-sys builds from the extracted tarball.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* review: address round-1 feedback (comment fix, concurrency, package-check CI)

- build.rs: the module comment referenced src/sw_session.c; point it at
  vendor/src/sw_session.c so it reads correctly when the -sys crate is viewed
  in isolation on crates.io (Copilot).
- publish-crates.yml: add a `concurrency` group so two rust-v* releases firing
  close together serialize instead of racing; never cancel an in-flight publish
  (kimi #3).
- ci.yml: new `crates-package-check` job that asserts the wrapper's =x.y.z pin
  matches the workspace version (turns a release-day half-publish into a
  PR-time failure — lcj-claude) and dry-run-publishes sensorwatch-sys so the
  packaging + verify build stay green before release day (kimi #1).

Declined (non-blocking): distinguishing indexing delays from real errors in the
wrapper publish retry loop — brittle error-string parsing for little gain; the
5x30s loop is sufficient.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* review: point sensorwatch-sys docs at the vendored header path (round 2)

The -sys README and Cargo.toml description referenced
`include/sensorwatch/sensorwatch.h`, which doesn't exist in the published
crate — the header ships vendored at `vendor/include/sensorwatch/sensorwatch.h`.
Point both at the vendored path (noting the repo-canonical mirror) so the
references resolve when the crate is read in isolation on crates.io (Copilot).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Leonard Janke <lcjanke2020@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A
Agent for Leonard Janke committed
e47b529299e124b62e02032f0e32b726db8b6eeb
Parent: 774cfcf
Committed by GitHub <noreply@github.com> on 7/1/2026, 8:00:24 PM