diff --git a/.commitlintrc.yml b/.commitlintrc.yml new file mode 100644 index 0000000..a37c14c --- /dev/null +++ b/.commitlintrc.yml @@ -0,0 +1,45 @@ +# If updating this file, please also review `docs/release-process.md` +# (in the contentauth/c2pa-rs repo) and +# `.github/workflows/pr_title.yml` and update the summary of these rules +# in those files accordingly. + +rules: + # Body may be empty + body-empty: + level: ignore + + # Description must not be empty + description-empty: + level: error + + # Description should be <70 chars + description-max-length: + level: warning + length: 70 + + # Scope is not allowed + scope: + level: error + optional: false + options: [] + + # Subject line should exist + subject-empty: + level: error + + # Type must be one of these options + type: + level: error + options: + - build + - chore + - ci + - docs + - feat + - fix + - perf + - refactor + - revert + - style + - test + - update diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..823a017 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,7 @@ +## Changes in this pull request +_Give a narrative description of what has been changed._ + +## Checklist +- [ ] This PR represents a single feature, fix, or change. +- [ ] All applicable changes have been documented. +- [ ] Any `TO DO` items (or similar) have been entered as GitHub issues and the link to that issue has been included in a comment. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..c94ea14 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,19 @@ +version: 2 +updates: + - package-ecosystem: "cargo" + directory: "/" + schedule: + interval: "daily" + commit-message: + prefix: "update" + cooldown: + default-days: 7 + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + commit-message: + prefix: "chore" + cooldown: + default-days: 7 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..58ec3ae --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,508 @@ +name: CI + +on: + workflow_dispatch: + pull_request: + branches: + - main + types: + - opened + - reopened + - synchronize + - labeled + push: + branches: + - main + +jobs: + tests: + name: Unit tests + + if: | + github.event_name != 'pull_request' || + github.event.pull_request.author_association == 'COLLABORATOR' || + github.event.pull_request.author_association == 'MEMBER' || + github.event.pull_request.user.login == 'dependabot[bot]' || + contains(github.event.pull_request.labels.*.name, 'safe to test') + + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + os: [windows-latest, macos-latest, ubuntu-latest] + rust_version: [stable, 1.87.0] + + steps: + - name: Checkout repository + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de # master + with: + toolchain: ${{ matrix.rust_version }} + components: llvm-tools-preview + + - name: Cache Rust dependencies + uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 + + - name: Install cargo-llvm-cov + uses: taiki-e/install-action@72f835688cb6c15903b796f704b01e652a2b8835 # cargo-llvm-cov + + - name: Generate code coverage + run: cargo llvm-cov --lib --all-features --lcov --output-path lcov.info + + - name: Filter out tests + uses: scouten/uncover-tests@f3bbdfb953b5989f48d8dfad0a88a83c4d914389 # v1.1.1 + with: + input-file: lcov.info + output-file: lcov.filtered.info + + # Tokens aren't available for PRs originating from forks, + # so we don't attempt to upload code coverage in that case. + - name: Upload code coverage results + if: | + github.event_name != 'pull_request' || + github.event.pull_request.author_association == 'COLLABORATOR' || + github.event.pull_request.author_association == 'MEMBER' || + github.event.pull_request.user.login == 'dependabot[bot]' + uses: codecov/codecov-action@0fb7174895f61a3b6b78fc075e0cd60383518dac # v5.5.5 + with: + token: ${{ secrets.CODECOV_ORG_TOKEN }} + fail_ci_if_error: true + verbose: true + files: ./lcov.filtered.info + + doc-tests: + name: Doc tests (requires nightly Rust) + # TODO: Remove this once cargo-llvm-cov can run doc tests and generate + # coverage. (This requires a bug fix that is only available in nightly Rust.) + # Watch https://github.com/taiki-e/cargo-llvm-cov/issues/2 + # for progress. + + if: | + github.event_name != 'pull_request' || + github.event.pull_request.author_association == 'COLLABORATOR' || + github.event.pull_request.author_association == 'MEMBER' || + github.event.pull_request.user.login == 'dependabot[bot]' || + contains(github.event.pull_request.labels.*.name, 'safe to test') + + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@6bed0761d98439e5a578e2877258200ad565ba87 # stable + + - name: Cache Rust dependencies + uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 + + - name: Install cargo-llvm-cov + uses: taiki-e/install-action@72f835688cb6c15903b796f704b01e652a2b8835 # cargo-llvm-cov + + # Disabling code coverage for doc tests due to a new bug in Rust nightly + # as of 2025-01-08. Will investigate later to see if there's a repro case. + # Meanwhile, simply run the tests so we know if there are any failing + # doc tests. + + - name: Run doc tests (COVERAGE DISABLED) + run: | + cargo test --workspace --all-features --doc + + # - name: Generate code coverage + # env: + # RUST_BACKTRACE: "1" + # run: | + # cargo llvm-cov --workspace --all-features --lcov --doctests --output-path lcov.info + + # Tokens aren't available for PRs originating from forks, + # so we don't attempt to upload code coverage in that case. + # - name: Upload code coverage results + # if: | + # github.event_name != 'pull_request' || + # github.event.pull_request.author_association == 'COLLABORATOR' || + # github.event.pull_request.author_association == 'MEMBER' || + # github.event.pull_request.user.login == 'dependabot[bot]' + # uses: codecov/codecov-action@0fb7174895f61a3b6b78fc075e0cd60383518dac # v5.5.5 + # with: + # token: ${{ secrets.CODECOV_TOKEN }} + # fail_ci_if_error: true + # verbose: true + + tests-cross: + name: Unit tests (cross) + + if: | + github.event_name != 'pull_request' || + github.event.pull_request.author_association == 'COLLABORATOR' || + github.event.pull_request.author_association == 'MEMBER' || + github.event.pull_request.user.login == 'dependabot[bot]' || + contains(github.event.pull_request.labels.*.name, 'safe to test') + + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + target: [aarch64-unknown-linux-gnu] + rust_version: [stable, 1.87.0] + + steps: + - name: Checkout repository + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de # master + with: + toolchain: ${{ matrix.rust_version }} + targets: ${{ matrix.target }} + + - name: Install cross-compilation toolset + run: cargo install cross + + - name: Cache Rust dependencies + uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 + + # Note that we do not run code coverage because + # it isn't readily accessible from cross-compilation + # environment. (A PR to fix this would be welcomed!) + + - name: Run unit tests (cross build) + run: cross test --lib --all-features --target ${{ matrix.target }} + + tests-ios: + name: Unit tests (iOS simulator) + + if: | + github.event_name != 'pull_request' || + github.event.pull_request.author_association == 'COLLABORATOR' || + github.event.pull_request.author_association == 'MEMBER' || + github.event.pull_request.user.login == 'dependabot[bot]' || + contains(github.event.pull_request.labels.*.name, 'safe to test') + + runs-on: macos-14 + + steps: + - name: Checkout repository + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de # master + with: + toolchain: 1.87.0 + targets: aarch64-apple-ios-sim + + - name: Install cargo-dinghy + run: | + VERSION=0.8.1 + URL="https://github.com/sonos/dinghy/releases/download/${VERSION}/cargo-dinghy-macos-${VERSION}.tgz" + wget -O - $URL | tar -xz --strip-components=1 -C ~/.cargo/bin + + - name: Check cargo-dinghy version. + run: cargo dinghy --version + + - name: Setup iOS Simulator + # Use the first installed iOS runtime and the first (i.e. oldest) supported iPhone device. + run: | + RUNTIME=$(xcrun simctl list runtimes --json | jq '.runtimes | map(select(.name | contains("iOS"))) | .[0]') + RUNTIME_ID=$(echo $RUNTIME | jq -r '.identifier') + echo "Using runtime:" $RUNTIME_ID + DEVICE_ID=$(echo $RUNTIME | jq -r '.supportedDeviceTypes | map(select(.productFamily == "iPhone")) | .[0].identifier') + echo "Using device:" $DEVICE_ID + SIM_ID=$(xcrun simctl create Test-iPhone $DEVICE_ID $RUNTIME_ID) + echo "Created simulator:" $SIM_ID + xcrun simctl boot $SIM_ID + echo "device=$SIM_ID" >> $GITHUB_ENV + + - name: Cache Rust dependencies + uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 + + - name: Run unit tests (cross build) + run: cargo dinghy -p auto-ios-aarch64-sim -d ${{ env.device }} test --all-targets --all-features + + tests-wasm: + name: Unit tests (Wasm) + + if: | + github.event_name != 'pull_request' || + github.event.pull_request.author_association == 'COLLABORATOR' || + github.event.pull_request.author_association == 'MEMBER' || + github.event.pull_request.user.login == 'dependabot[bot]' || + contains(github.event.pull_request.labels.*.name, 'safe to test') || + contains(github.event.pull_request.labels.*.name, 'check-release') + + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@6bed0761d98439e5a578e2877258200ad565ba87 # stable + + - name: Set up Chrome + uses: browser-actions/setup-chrome@48ad923757ca74d66703209fe939badbdf80f2f4 # v2.2.0 + with: + chrome-version: 142 + install-chromedriver: true + + - name: Add Wasm web target + run: rustup target add wasm32-unknown-unknown + + - name: Install cargo-binstall + uses: cargo-bins/cargo-binstall@f8162f41a8ea5ec653c5cba967cc1b2d89c867c5 # main + + - name: Install wasm-bindgen-cli + run: cargo binstall -y wasm-bindgen-cli --version 0.2.106 + + - name: Run Wasm tests + run: cargo test --all-features --target wasm32-unknown-unknown + env: + CARGO_TARGET_WASM32_UNKNOWN_UNKNOWN_RUNNER: wasm-bindgen-test-runner + WASM_BINDGEN_TEST_TIMEOUT: 60 + + tests-wasi: + name: Unit tests (WASI) + + if: | + github.event_name != 'pull_request' || + github.event.pull_request.author_association == 'COLLABORATOR' || + github.event.pull_request.author_association == 'MEMBER' || + github.event.pull_request.user.login == 'dependabot[bot]' || + contains(github.event.pull_request.labels.*.name, 'safe to test') || + contains(github.event.pull_request.labels.*.name, 'check-release') + + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + + # Nightly required for testing until this issue is resolved: + # wasip2 target should not conditionally feature gate stdlib APIs rust-lang/rust#130323 https://github.com/rust-lang/rust/issues/130323 + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de # master + with: + toolchain: nightly-2026-01-16 + + - name: Install wasmtime + run: | + curl https://wasmtime.dev/install.sh -sSf | bash + echo "$HOME/.wasmtime/bin" >> $GITHUB_PATH + + - name: Install clang + run: | + sudo apt-get update + sudo apt-get install -y clang + + - name: Add wasm32-wasip2 target + run: rustup target add --toolchain nightly-2026-01-16 wasm32-wasip2 + + - name: Cache Rust dependencies + uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 + + - name: Run WASI tests + env: + CARGO_TARGET_WASM32_WASIP2_RUNNER: "wasmtime -S cli -S http --dir . --env GITHUB_ACTIONS=${GITHUB_ACTIONS}" + CC: clang + RUST_MIN_STACK: 16777216 + run: | + cargo +nightly-2026-01-16 test --target wasm32-wasip2 --all-features -- --no-capture + + test-direct-minimal-versions: + name: Unit tests with minimum versions of direct dependencies + + if: | + github.event_name != 'pull_request' || + github.event.pull_request.author_association == 'COLLABORATOR' || + github.event.pull_request.author_association == 'MEMBER' || + github.event.pull_request.user.login == 'dependabot[bot]' || + contains(github.event.pull_request.labels.*.name, 'safe to test') + + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + os: [windows-latest, macos-latest, ubuntu-latest] + + steps: + - name: Checkout repository + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de # master + with: + toolchain: nightly-2025-12-06 + + - name: Cache Rust dependencies + uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 + + - name: Run tests + run: | + cargo +nightly-2025-12-06 test -Z direct-minimal-versions --all-targets --all-features + + publish-preflight: + name: Preflight crate publish + + if: | + github.event_name != 'pull_request' || + github.event.pull_request.author_association == 'COLLABORATOR' || + github.event.pull_request.author_association == 'MEMBER' || + github.event.pull_request.user.login == 'dependabot[bot]' || + contains(github.event.pull_request.labels.*.name, 'safe to test') + + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@6bed0761d98439e5a578e2877258200ad565ba87 # stable + + - name: Cache Rust dependencies + uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 + + - name: Dry-run of crate publish + run: cargo publish --dry-run + + clippy_check: + name: Clippy + + if: | + github.event_name != 'pull_request' || + github.event.pull_request.author_association == 'COLLABORATOR' || + github.event.pull_request.author_association == 'MEMBER' || + github.event.pull_request.user.login == 'dependabot[bot]' || + contains(github.event.pull_request.labels.*.name, 'safe to test') + + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@6bed0761d98439e5a578e2877258200ad565ba87 # stable + with: + components: clippy + + - name: Cache Rust dependencies + uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 + + - name: Run Clippy + run: | + cargo clippy --all-features --all-targets -- -Dwarnings + + cargo_fmt: + name: Enforce Rust code format + + if: | + github.event_name != 'pull_request' || + github.event.pull_request.author_association == 'COLLABORATOR' || + github.event.pull_request.author_association == 'MEMBER' || + github.event.pull_request.user.login == 'dependabot[bot]' || + contains(github.event.pull_request.labels.*.name, 'safe to test') + + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + + - name: Install nightly toolchain + uses: dtolnay/rust-toolchain@02cb101ec7c40f2c49e1d9714d64511d8e1b74de # master + with: + toolchain: nightly-2026-01-16 + components: rustfmt + + - name: Check format + run: cargo +nightly-2026-01-16 fmt --all -- --check + + taplo_fmt: + name: Enforce TOML format + if: | + github.event_name != 'pull_request' || + github.event.pull_request.author_association == 'COLLABORATOR' || + github.event.pull_request.author_association == 'MEMBER' || + github.event.pull_request.user.login == 'dependabot[bot]' || + contains(github.event.pull_request.labels.*.name, 'safe to test') + + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + + - name: Install Taplo CLI + run: cargo install taplo-cli --locked + + - name: Check TOML format + run: taplo fmt --check + + docs_rs: + name: Preflight docs.rs build + + if: | + github.event_name != 'pull_request' || + github.event.pull_request.author_association == 'COLLABORATOR' || + github.event.pull_request.author_association == 'MEMBER' || + github.event.pull_request.user.login == 'dependabot[bot]' || + contains(github.event.pull_request.labels.*.name, 'safe to test') + + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + + - name: Install Rust toolchain + # Nightly is used here because the docs.rs build + # uses nightly and we use doc_cfg features that are + # not in stable Rust as of this writing (Rust 1.88). + uses: dtolnay/rust-toolchain@be39649afda95dbf70f87cce95f68b8d5797b296 # nightly + + - name: Cache Rust dependencies + uses: Swatinem/rust-cache@6323deb102c322ba6fcbdcafc7e3dddab59af2b6 # v2.9.2 + + - name: Install cargo-docs-rs + uses: dtolnay/install@982daea0f5d846abc3c83e01a6a1d73c040047c1 # cargo-docs-rs + + - name: Preflight docs.rs + env: + RUSTDOCFLAGS: -Dwarnings + run: cargo docs-rs + + cargo-deny: + name: License / vulnerability audit + + if: | + github.event_name != 'pull_request' || + github.event.pull_request.author_association == 'COLLABORATOR' || + github.event.pull_request.author_association == 'MEMBER' || + github.event.pull_request.user.login == 'dependabot[bot]' || + contains(github.event.pull_request.labels.*.name, 'safe to test') + + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + checks: + - advisories + - bans licenses sources + + # Prevent sudden announcement of a new advisory from failing CI: + continue-on-error: ${{ matrix.checks == 'advisories' }} + + steps: + - name: Checkout repository + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + + - name: Audit crate dependencies + uses: EmbarkStudios/cargo-deny-action@3c6349835b2b7b196a839186cb8b78e02f7b5f25 # v2.1.1 + with: + command: check ${{ matrix.checks }} diff --git a/.github/workflows/pr_title.yml b/.github/workflows/pr_title.yml new file mode 100644 index 0000000..4ddb573 --- /dev/null +++ b/.github/workflows/pr_title.yml @@ -0,0 +1,104 @@ +name: PR title + +on: + pull_request: + types: [opened, synchronize, reopened, edited] + +jobs: + title_cc_validation: + name: Conventional commits validation + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + + # If changing this, please also see `.commitlintrc` and + # `docs/release-process.md` (in contentauth/c2pa-rs repo). + + - name: Check PR title + env: + PR_TITLE: ${{ github.event.pull_request.title }} + run: | + # If this step fails, please expand this step for more information. + # + # You will need to revise this pull request's title to + # match the "summary" (first) line of a Conventional Commit message. + # This enables us to automatically generate a meaningful changelog. + # + # The summary line (and thus the PR title) must have this exact format + # (including punctuation): + # + # type: description + # + # `type` describes the nature of changes you are making. This project + # requires the type to be one of these exact names: + # + # * fix + # * feat (will cause a minor version bump) + # * chore (will be omitted from changelog) + # * update + # * doc + # + # NOTE: Conventional Commits also defines a `(scope)` parameter + # which can define a sub-area within the project where the change was + # made. This project is configured to disallow the use of `scope`. + # + # `description` is a short human-readable summary of the changes being made. + # It is required. + # + # This project does not currently enforce the following items, but + # we ask that you observe the following preferences in `description`: + # + # * The entire description should be written and capitalized as + # an English-language sentence, except that the trailing period + # should be omitted. + # * Any acronyms such as JSON or YAML should be capitalized as per + # common usage in English-language sentences. + # + # After you edit the PR title, this task will run again and the + # warning should go away if you have made acceptable changes. + # + # For more information on Conventional Commits, please see: + # + # https://www.conventionalcommits.org/en/v1.0.0/ + # + # ------------ (end of message) ------------ + + if echo "$PR_TITLE" | grep -E '^chore(\(.*\))?: release '; then + echo "Exception / OK: chore release pattern" + exit 0; + fi + + if echo "$PR_TITLE" | grep -E '^chore: release'; then + echo "Exception / OK: chore release pattern" + exit 0; + fi + + if echo "$PR_TITLE" | grep -E '^chore(\(deps\))?: bump '; then + echo "Exception / OK: Dependabot update pattern" + exit 0; + fi + + if echo "$PR_TITLE" | grep -E '^update: update '; then + echo "Exception / OK: Dependabot update pattern" + exit 0; + fi + + if echo "$PR_TITLE" | grep -E '^update: bump '; then + echo "Exception / OK: Dependabot update pattern" + exit 0; + fi + + echo "Installing commitlint-rs. Please wait 30-40 seconds ..." + cargo install --quiet commitlint-rs + set -e + + echo   + echo   + echo --- commitlint results for PR title \"$PR_TITLE\" --- + echo   + + echo "$PR_TITLE" | commitlint -g .commitlintrc.yml + + echo "✅ PR title matches all enforced rules." diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..9e92516 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,40 @@ +name: Release-plz + +permissions: + pull-requests: write + contents: write + +on: + push: + branches: + - main + +jobs: + release-plz: + name: Release-plz + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0 + with: + fetch-depth: 0 + token: ${{ secrets.RELEASE_PLZ_ORG_TOKEN }} + + - name: Install Rust toolchain + uses: dtolnay/rust-toolchain@6bed0761d98439e5a578e2877258200ad565ba87 # stable + + - name: Run release-plz + uses: MarcoIeni/release-plz-action@487eb7b5c085a664d5c5ca05f4159bd9b591182a # v0.5.120 + env: + GITHUB_TOKEN: ${{ secrets.RELEASE_PLZ_ORG_TOKEN }} + CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_ORG_TOKEN }} + + - name: Clean up stale release-plz branches + run: | + git --no-pager branch --remote |\ + grep 'origin/release-plz-' |\ + sort -r |\ + tail -n +2 |\ + sed 's/origin\///' |\ + xargs -I {} git push origin --delete {} diff --git a/.taplo.toml b/.taplo.toml new file mode 100644 index 0000000..77bde4e --- /dev/null +++ b/.taplo.toml @@ -0,0 +1,12 @@ +# Taplo TOML formatter configuration. +# Used for Cargo.toml files within this project. + +[formatting] +# Enforce alphabetical ordering of dependencies. +reorder_keys = true + +# Spaces inside inline tables (hash maps). +inline_table_padding = 1 + +# No spaces inside arrays. +array_padding = 0 diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d4ad7c..17db8bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,8 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.4.0] - 2026-09-14 +## [0.4.0] +_14 September 2026_ Syncs cimpl with the pointer-registry rewrite done for the embedded copy in c2pa-rs, replacing simple pointer validation with borrow-checked handle @@ -55,7 +56,8 @@ tracking. - `MAX_CSTRING_LEN` / `MAX_STRING_ARRAY_LEN` public constants from `macros.rs` -## [0.3.1] - 2026-02-16 +## [0.3.1] +_16 February 2026_ ### Documentation @@ -69,7 +71,8 @@ tracking. - Removed unused `paste` dependency (now zero dependencies) -## [0.3.0] - 2026-02-16 +## [0.3.0] +_16 February 2026_ ### Note diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..0bd1f75 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Adobe code of conduct + +## Our pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language. +* Being respectful of differing viewpoints and experiences. +* Gracefully accepting constructive criticism. +* Focusing on what is best for the community. +* Showing empathy towards other community members. + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances. +* Trolling, insulting/derogatory comments, and personal or political attacks. +* Public or private harassment. +* Publishing others' private information, such as a physical or electronic + address, without explicit permission. +* Other conduct which could reasonably be considered inappropriate in a + professional setting. + +## Our responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at Grp-opensourceoffice@adobe.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the code of conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This code of conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [https://contributor-covenant.org/version/1/4][version]. + +[homepage]: https://contributor-covenant.org +[version]: https://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..32902f8 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,78 @@ +# Contributing + +We welcome contributions to this project! + +Before you start, we ask that you understand the following guidelines. + +## Code of conduct + +This project adheres to the Adobe [code of conduct](CODE_OF_CONDUCT.md). By participating, +you are expected to uphold this code. Please report unacceptable behavior to +[Grp-opensourceoffice@adobe.com](mailto:Grp-opensourceoffice@adobe.com). + +## Have a question? + +Start by filing an issue. The existing committers on this project work to reach +consensus around project direction and issue solutions within issue threads +(when appropriate). + +## Contributor license agreement + +All third-party contributions to this project must be accompanied by a signed contributor +license agreement. This gives Adobe permission to redistribute your contributions +as part of the project. [Sign our CLA](https://opensource.adobe.com/cla.html). You +only need to submit an Adobe CLA one time, so if you have submitted one previously, +you are good to go! + +Please note that the Adobe CLA is tied to each _individual_ contributor. We do not currently +have a mechanism to allow the CLA to be signed on behalf of an entire organization. + +### Code reviews + +All submissions should come in the form of pull requests and need to be reviewed +by project committers. Read [GitHub's pull request documentation](https://help.github.com/articles/about-pull-requests/) +for more information on sending pull requests. + +Code submissions will need to pass all automated tests in place at the time of submission. +These include such things as Rust code format, Clippy/lint checks, and unit test coverage. + +We encourage you to raise an issue in GitHub before starting work on a major addition to the crate. +This will give us an opportunity to discuss API design and avoid duplicate efforts. + +### Pull request titles + +Titles of pull requests that target a long-lived branch such as _main_ or a release-specific branch should follow [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/#specification). The repository's [commit lint rules](https://github.com/contentauth/c2pa-rs/blob/main/.commitlintrc.yml) require that the first word of the pull request title must be one of the following: + +- `fix` +- `feat` +- `chore` +- `update` +- `doc` + +If more detail is warranted, add a blank line and then continue with sentences (these sentences should be punctuated as such) and paragraphs as needed to provide that detail. There is no need to word-wrap this message. + +For example: + +```text +feat: Introduce a new API to validate 1.0 claims + +Repurpose existing v2 API for 0.8 compatibility (read: no validation) mode. +``` + +The conventional commit message requirement does not apply to individual commits within a pull request, provided that those commits will be squashed when the PR is merged and the resulting squash commit does follow the conventional commit requirement. This may require the person merging the PR to verify the commit message syntax when performing the squash merge. + +TIP: For single-commit PRs, ensure the commit message conforms to the conventional commit requirement, since by default that will also be the title of the PR. + +## From contributor to committer + +We love contributions from our community! If you'd like to go a step beyond contributor +and become a committer with full write access and a say in the project, you must +be invited to the project. The existing committers employ an internal nomination +process that must reach lazy consensus (silence is approval) before invitations +are issued. If you feel you are qualified and want to get more deeply involved, +feel free to reach out to existing committers to have a conversation about that. + +## Security issues + +Do not create a public GitHub issue for any suspected security vulnerabilities. Instead, please file an issue through [Adobe's HackerOne page](https://hackerone.com/adobe?type=team). +For more information on reporting security issues, see [SECURITY.md](SECURITY.md). diff --git a/Cargo.toml b/Cargo.toml index 3ed6c43..76aab62 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,17 +1,20 @@ [package] -name = "cimpl" -version = "0.4.0" +authors = [ + "Gavin Peacock ", + "Tania Mathern ", +] +categories = ["api-bindings", "development-tools::ffi"] description = "Simple C implementations from Rust - FFI utilities and macros for creating safe, ergonomic C bindings" +documentation = "https://docs.rs/cimpl" edition = "2021" -authors = ["Gavin Peacock ", "Tania Mathern "] +homepage = "https://github.com/contentauth/cimpl" +keywords = ["ffi", "bindings", "c", "utilities", "macros"] license = "MIT OR Apache-2.0" +name = "cimpl" readme = "README.md" -homepage = "https://github.com/contentauth/cimpl" repository = "https://github.com/contentauth/cimpl" -documentation = "https://docs.rs/cimpl" -keywords = ["ffi", "bindings", "c", "utilities", "macros"] -categories = ["api-bindings", "development-tools::ffi"] rust-version = "1.87" +version = "0.4.0" [package.metadata.docs.rs] all-features = true diff --git a/LICENSE-APACHE b/LICENSE-APACHE index 758d439..aee26b9 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2020 Adobe + Copyright 2026 Adobe Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/LICENSE-MIT b/LICENSE-MIT index e1e3bd7..efee322 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,6 +1,6 @@ MIT License -© Copyright 2020 Adobe. All rights reserved. +© Copyright 2026 Adobe. All rights reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 0000000..b77a718 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,12 @@ +codecov: + notify: + # Update this depending on how many independent jobs upload coverage results. + # https://docs.codecov.com/docs/notifications#section-preventing-notifications-until-after-n-builds + after_n_builds: 3 + +coverage: + status: + project: + default: + target: auto + threshold: 1% diff --git a/deny.toml b/deny.toml new file mode 100644 index 0000000..70ddc3f --- /dev/null +++ b/deny.toml @@ -0,0 +1,43 @@ +# Configuration used for dependency checking with cargo-deny. +# +# For further details on all configuration options see: +# https://embarkstudios.github.io/cargo-deny/checks/cfg.html + +[graph] +targets = [ + { triple = "x86_64-unknown-linux-gnu" }, + { triple = "x86_64-apple-darwin" }, + { triple = "x86_64-pc-windows-msvc" }, + { triple = "aarch64-apple-darwin" }, + { triple = "wasm32-unknown-unknown" }, +] + +[advisories] +ignore = [] +yanked = "deny" + +[bans] +multiple-versions = "allow" # "deny" # TODO: Re-enable when possible. + +[licenses] +allow = [ + "Apache-2.0", + "BSD-2-Clause", + "BSD-3-Clause", + # "CC0-1.0", + "ISC", + # "LicenseRef-ring", + "MIT", + "MPL-2.0", + "Unicode-3.0", + # "Unicode-DFS-2016", + "Zlib", + "CDLA-Permissive-2.0", +] +confidence-threshold = 0.9 + +[sources] +allow-git = [] +allow-registry = ["https://github.com/rust-lang/crates.io-index"] +unknown-git = "deny" +unknown-registry = "deny" diff --git a/examples/reference/Cargo.toml b/examples/reference/Cargo.toml index 47c1b30..b776616 100644 --- a/examples/reference/Cargo.toml +++ b/examples/reference/Cargo.toml @@ -1,11 +1,11 @@ [package] +edition = "2021" name = "cimpl-reference" version = "0.3.2" -edition = "2021" [lib] -name = "value_converter" crate-type = ["cdylib", "staticlib", "rlib"] +name = "value_converter" [features] default = ["ffi"] diff --git a/examples/reference/cbindgen.toml b/examples/reference/cbindgen.toml index 2d44d77..ab5a5dd 100644 --- a/examples/reference/cbindgen.toml +++ b/examples/reference/cbindgen.toml @@ -1,11 +1,11 @@ -language = "C" -include_guard = "CIMPL_VALUE_CONVERTER_H" autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */" +cpp_compat = true documentation = true documentation_style = "doxy" +include_guard = "CIMPL_VALUE_CONVERTER_H" +language = "C" line_length = 100 tab_width = 4 -cpp_compat = true header = """ /* Generated by cbindgen - DO NOT EDIT MANUALLY */ @@ -38,18 +38,27 @@ header = """ # Add prefix to all exported functions prefix = "vc_" # Generate opaque pointer declaration -item_types = ["globals", "enums", "structs", "unions", "typedefs", "opaque", "functions", "constants"] +item_types = [ + "globals", + "enums", + "structs", + "unions", + "typedefs", + "opaque", + "functions", + "constants", +] [export.rename] "ValueConverter" = "ValueConverter" [enum] -rename_variants = "ScreamingSnakeCase" prefix_with_name = true +rename_variants = "ScreamingSnakeCase" [fn] rename_args = "CamelCase" [parse] -parse_deps = false include = ["cimpl"] +parse_deps = false diff --git a/examples/uuid/Cargo.toml b/examples/uuid/Cargo.toml index 339cd5f..f6e5e27 100644 --- a/examples/uuid/Cargo.toml +++ b/examples/uuid/Cargo.toml @@ -1,11 +1,11 @@ [package] +edition = "2021" name = "uuid_ffi" version = "0.1.0" -edition = "2021" [lib] -name = "uuid_ffi" crate-type = ["cdylib", "rlib"] +name = "uuid_ffi" [features] default = ["ffi"] @@ -13,8 +13,8 @@ ffi = [] [dependencies] cimpl = { path = "../.." } -uuid = { version = "1.11", features = ["v4"] } thiserror = "2.0" +uuid = { version = "1.11", features = ["v4"] } [build-dependencies] cbindgen = "0.27" diff --git a/examples/uuid/cbindgen.toml b/examples/uuid/cbindgen.toml index 16e7ac8..e92d7af 100644 --- a/examples/uuid/cbindgen.toml +++ b/examples/uuid/cbindgen.toml @@ -1,9 +1,9 @@ -language = "C" -include_guard = "CIMPL_UUID_H" autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */" +cpp_compat = true +include_guard = "CIMPL_UUID_H" include_version = true +language = "C" namespace = "uuid" -cpp_compat = true style = "both" header = """ @@ -24,7 +24,16 @@ header = """ """ [export] -item_types = ["globals", "enums", "structs", "unions", "typedefs", "opaque", "functions", "constants"] +item_types = [ + "globals", + "enums", + "structs", + "unions", + "typedefs", + "opaque", + "functions", + "constants", +] [export.rename] "Uuid" = "Uuid" diff --git a/release-plz.toml b/release-plz.toml new file mode 100644 index 0000000..1949919 --- /dev/null +++ b/release-plz.toml @@ -0,0 +1,47 @@ +[changelog] +body = """ + +## [{{ version | trim_start_matches(pat="v") }}]{%- if release_link -%}({{ release_link }}){% endif %} +_{{ timestamp | date(format="%d %B %Y") }}_ +{% for group, commits in commits | group_by(attribute="group") -%} +{%- if group != "chore" %} +### {{ group | upper_first }} + +{% for commit in commits -%} +{%- if commit.scope and commit.scope != package -%} +* *({{commit.scope}})* {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }}{%- if commit.links %} ({% for link in commit.links %}[{{link.text}}]({{link.href}}) {% endfor -%}){% endif %} +{% else -%} +* {% if commit.breaking %}[**breaking**] {% endif %}{{ commit.message | upper_first }} +{% endif -%} +{%- endfor %} + +{%- endif %} + +{%- endfor -%} +""" +header = """# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +""" + +commit_parsers = [ + { message = "^feat", group = "added" }, + { message = "^changed", group = "changed" }, + { message = "^deprecated", group = "deprecated" }, + { message = "^fix", group = "fixed" }, + { message = "^security", group = "security" }, + { message = "^chore", group = "chore" }, + { message = "^update", group = "updated dependencies" }, + { message = "^doc", group = "documented" }, + { message = "^.*", group = "other" }, +] + +[workspace] +dependencies_update = true +features_always_increment_minor = false +pr_labels = ["release"] +release_always = false +release_commits = "^(feat|fix|docs|perf|refactor|revert|test|update)[(:]" diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..4e4836d --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,16 @@ +# IMPORTANT: PR validation uses nightly version of +# rustfmt. + +# Invoke by using: +# +# rustup toolchain add nightly +# cargo +nightly fmt + +blank_lines_upper_bound = 1 +edition = "2021" +format_code_in_doc_comments = true +group_imports = "StdExternalCrate" +hex_literal_case = "Lower" +imports_granularity = "Crate" +reorder_impl_items = true +unstable_features = true diff --git a/src/error.rs b/src/error.rs index fcc40b1..7e3c2ff 100644 --- a/src/error.rs +++ b/src/error.rs @@ -72,7 +72,6 @@ thread_local! { /// } /// } /// ``` -/// #[derive(Debug, Clone)] pub struct Error { message: String, @@ -441,6 +440,7 @@ mod tests { } #[test] + #[cfg(not(target_os = "wasi"))] // WASI does not support threads fn test_thread_local_isolation() { use std::thread; diff --git a/src/lib.rs b/src/lib.rs index 3f1792a..f5f16a2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -140,12 +140,12 @@ //! //! - [`cstr_or_return!`] - C string to Rust with UTF-8 validation and bounds checking //! - [`to_c_string()`] - Rust String to tracked C string -//! - [`option_to_c_string!`] - Option to C string (NULL if None) +//! - [`option_to_c_string!`] - `Option` to C string (NULL if None) //! //! ### Byte Array Handling //! //! - [`bytes_or_return!`] - Validate and convert C byte arrays -//! - [`to_c_bytes()`] - Rust Vec to tracked C byte array +//! - [`to_c_bytes()`] - Rust `Vec` to tracked C byte array //! //! ### Result Handling //! @@ -228,9 +228,8 @@ pub mod utils; pub mod macros; // Re-export main types and functions for convenience -pub use error::{Error, Result}; // Convenience alias to avoid name conflicts -pub use error::Error as CimplError; +pub use error::{Error as CimplError, Error, Result}; pub use utils::{ checkout_exclusive, checkout_shared, cimpl_free, ensure_trackable, is_safe_buffer_size, safe_slice_from_raw_parts, to_c_bytes, to_c_string, track_arc, track_arc_mutex, track_box, diff --git a/src/macros.rs b/src/macros.rs index 6c16478..c282e74 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -1021,11 +1021,11 @@ macro_rules! cstr_array_or_return_int { /// Free a pointer that was allocated by cimpl. /// -/// This is a convenience macro wrapper around `cimpl_free` (see [`crate::cimpl_free`]). +/// This is a convenience macro wrapper around `cimpl_free` (see [`crate::cimpl_free()`]). /// /// # Returns /// - `0` on success -/// - `-1` on error (see [`crate::cimpl_free`] for details) +/// - `-1` on error (see [`crate::cimpl_free()`] for details) /// /// # Error Handling /// diff --git a/src/utils.rs b/src/utils.rs index 24ca8a3..ca9e7fc 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1721,6 +1721,7 @@ mod tests { } #[test] + #[cfg(not(target_os = "wasi"))] // WASI does not support threads fn test_concurrent_shared_checkouts_succeed() { let ptr = track_box(Box::into_raw(Box::new(42i32))); let addr = ptr as usize; @@ -1755,6 +1756,7 @@ mod tests { } #[test] + #[cfg(not(target_os = "wasi"))] // WASI does not support threads fn test_guard_cleans_up_once() { static CLEANUPS: AtomicUsize = AtomicUsize::new(0); struct Counted; @@ -1781,6 +1783,7 @@ mod tests { } #[test] + #[cfg(panic = "unwind")] fn test_panicking_cleanup_is_handled() { struct Panics; impl Drop for Panics { @@ -1851,6 +1854,7 @@ mod tests { } #[test] + #[cfg(not(target_os = "wasi"))] // WASI does not support threads fn test_registry_stays_usable_after_the_lock_is_poisoned() { use std::sync::atomic::AtomicBool;