Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
126 changes: 126 additions & 0 deletions .github/workflows/rust-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
name: Rust CI

on:
push:
branches: [main]
paths:
- 'rust/**'
- '.github/workflows/rust-ci.yml'
pull_request:
paths:
- 'rust/**'
- '.github/workflows/rust-ci.yml'
workflow_dispatch:

concurrency:
group: rust-ci-${{ github.ref }}
cancel-in-progress: true

env:
CARGO_TERM_COLOR: always
RUSTFLAGS: -D warnings

defaults:
run:
working-directory: rust

jobs:
test:
name: Test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
# Kept in sync with the platforms `ort` supports; see rust/README.md.
os: [ubuntu-latest, macos-latest, windows-latest]
steps:
- uses: actions/checkout@v4

- uses: dtolnay/rust-toolchain@stable

- uses: Swatinem/rust-cache@v2
with:
workspaces: rust

# The ONNX model files are not in the repository; the tests load them
# from `rust/models`. Cache them so we don't re-download ~230 MB per run.
- name: Cache models
id: cache-models
uses: actions/cache@v4
with:
path: rust/models
key: trustmark-models-${{ hashFiles('rust/crates/xtask/src/main.rs') }}

- name: Fetch models
if: steps.cache-models.outputs.cache-hit != 'true'
run: cargo xtask fetch-models

- name: Build
run: cargo build --workspace --all-targets

- name: Test
run: cargo test --workspace

- name: Doc tests
run: cargo test --doc

lint:
name: Format and clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy

- uses: Swatinem/rust-cache@v2
with:
workspaces: rust

- name: cargo fmt
run: cargo fmt --all -- --check

- name: cargo clippy
run: cargo clippy --workspace --all-targets --all-features

msrv:
name: Minimum supported Rust version
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Read rust-version from Cargo.toml
id: msrv
run: |
msrv=$(grep -m1 '^rust-version' Cargo.toml | cut -d'"' -f2)
echo "Detected MSRV: $msrv"
echo "version=$msrv" >> "$GITHUB_OUTPUT"

- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ steps.msrv.outputs.version }}

- uses: Swatinem/rust-cache@v2
with:
workspaces: rust

- name: Check against MSRV
run: cargo check --workspace --all-targets

package:
name: Verify publishable package
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: dtolnay/rust-toolchain@stable

- uses: Swatinem/rust-cache@v2
with:
workspaces: rust

# Catches problems that only show up in the packaged crate, such as files
# excluded by .gitignore that the build actually needs.
- name: cargo publish --dry-run
run: cargo publish --dry-run --locked
122 changes: 122 additions & 0 deletions .github/workflows/rust-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
name: Rust release

# Publishes the `trustmark` crate to crates.io.
#
# Trigger by pushing a tag of the form `rust-v<version>` (for example
# `rust-v0.3.0`), where `<version>` matches the `version` field in
# `rust/Cargo.toml`. The tag prefix keeps Rust releases distinct from the
# Python package releases that share this repository.
#
# You can also run it manually from the Actions tab; use `dry_run: true` to
# rehearse everything except the actual `cargo publish`.
#
# Authentication uses crates.io Trusted Publishing (OIDC) — no API token is
# stored in this repository. See rust/RELEASING.md for the one-time setup.

on:
push:
tags:
- 'rust-v*'
workflow_dispatch:
inputs:
dry_run:
description: 'Run every step but skip the actual publish'
type: boolean
default: true

concurrency:
group: rust-release
cancel-in-progress: false

env:
CARGO_TERM_COLOR: always

defaults:
run:
working-directory: rust

jobs:
release:
name: Publish to crates.io
runs-on: ubuntu-latest
environment: crates-io
permissions:
contents: write
id-token: write
steps:
- uses: actions/checkout@v4

- uses: dtolnay/rust-toolchain@stable

- uses: Swatinem/rust-cache@v2
with:
workspaces: rust

- name: Determine version
id: version
run: |
set -euo pipefail
manifest_version=$(cargo metadata --no-deps --format-version 1 \
| python3 -c 'import json,sys; print(next(p["version"] for p in json.load(sys.stdin)["packages"] if p["name"] == "trustmark"))')
echo "Manifest version: $manifest_version"

if [ "${GITHUB_REF_TYPE:-}" = "tag" ]; then
tag_version="${GITHUB_REF_NAME#rust-v}"
if [ "$tag_version" != "$manifest_version" ]; then
echo "::error::Tag $GITHUB_REF_NAME implies version $tag_version but rust/Cargo.toml says $manifest_version."
exit 1
fi
fi

echo "version=$manifest_version" >> "$GITHUB_OUTPUT"

- name: Check version is not already published
run: |
set -euo pipefail
version="${{ steps.version.outputs.version }}"
published=$(curl -sSf -H 'User-Agent: adobe/trustmark release workflow' \
"https://crates.io/api/v1/crates/trustmark" \
| python3 -c 'import json,sys; print("\n".join(v["num"] for v in json.load(sys.stdin)["versions"]))')
if echo "$published" | grep -qx "$version"; then
echo "::error::trustmark $version is already published on crates.io. Bump the version in rust/Cargo.toml."
exit 1
fi
echo "trustmark $version is not yet published."

- name: Cache models
id: cache-models
uses: actions/cache@v4
with:
path: rust/models
key: trustmark-models-${{ hashFiles('rust/crates/xtask/src/main.rs') }}

- name: Fetch models
if: steps.cache-models.outputs.cache-hit != 'true'
run: cargo xtask fetch-models

- name: Test
run: cargo test --workspace --locked

- name: Package
run: cargo publish --dry-run --locked

- name: Authenticate to crates.io
if: inputs.dry_run != true
uses: rust-lang/crates-io-auth-action@v1
id: auth

- name: Publish
if: inputs.dry_run != true
run: cargo publish --locked
env:
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}

- name: Create GitHub release
if: github.ref_type == 'tag' && inputs.dry_run != true
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release create "$GITHUB_REF_NAME" \
--repo "$GITHUB_REPOSITORY" \
--title "Rust crate ${{ steps.version.outputs.version }}" \
--notes "The \`trustmark\` crate ${{ steps.version.outputs.version }} is published at https://crates.io/crates/trustmark/${{ steps.version.outputs.version }}."
43 changes: 43 additions & 0 deletions rust/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Changelog

All notable changes to the `trustmark` Rust crate are documented here. This
crate is versioned independently of the Python package in this repository.

Entries for releases before 0.3.0 were reconstructed from the commit history,
since those versions were published manually and without tags.

## 0.3.0

- Upgrade `ort` to 2.0.0-rc.12. This is the fix for 0.2.2 no longer being
buildable: the prebuilt ONNX Runtime binaries that `ort-sys` 2.0.0-rc.8
downloads at build time are no longer hosted.
- Upgrade `ndarray` to 0.17.
- `encode` and `decode` now take `&self`, so a loaded model can be shared
between callers. Encoding and decoding use separate sessions and can run
concurrently; inference on a single session is serialized.
- Raise the minimum supported Rust version to 1.88.
- Add release automation and this changelog; see [`RELEASING.md`](RELEASING.md).

## 0.2.2

- Update the model download URL used by `cargo xtask fetch-models`.
- Document platform support.

## 0.2.1

- Fix an integer truncation bug.
- Fix the documentation build.

## 0.2.0

- Switch image resizing from `image` to `fast_image_resize` for better
performance.
- Support a user-specified JPEG output quality.
- Save JPEG output as RGB instead of RGBA.
- Fix resizing when the target is larger than the source image.

## 0.1.0

- Initial release: encoding and decoding of TrustMark watermarks in binary mode
for all variants, with the same error correction levels as the Python
implementation.
11 changes: 11 additions & 0 deletions rust/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,14 @@ To run the Python benchmarks, run the following from the workspace root:
```
benches/load.sh && benches/encode.sh
```

## Releasing

Changes to this crate are validated by the [Rust CI](../.github/workflows/rust-ci.yml)
workflow, and releases to crates.io are performed by the
[Rust release](../.github/workflows/rust-release.yml) workflow when a
`rust-v*` tag is pushed.

See [RELEASING.md](RELEASING.md) for the full process, including the manual
fallback and the setup required on crates.io. Notable changes are recorded in
[CHANGELOG.md](CHANGELOG.md).
Loading
Loading