From d14bcd874cd74bde4c65cbed19aff2b1a30a39e7 Mon Sep 17 00:00:00 2001 From: Justin Kovacich Date: Wed, 9 Sep 2026 13:59:59 -0400 Subject: [PATCH 1/6] chore: clear the lints and typos the stricter shared gates catch `luminartech/rust_workflow` lints with `--all-targets` and with `--no-default-features`, where this repo's own CI ran clippy over the library with all features on. Twelve findings sat in the gap, all in test code or behind a feature combination that was never linted: - Six `assert!(a == b)` in `src/messages/mod.rs` become `assert_eq!`, which also means a failure prints both values instead of just `false`. - Two truncating `as` casts in `bare_metal_entity.rs` test fixtures become `try_from(..).expect(..)`. Neither can fail at the sizes the fixtures use -- which is the point: a truncating cast would hide it if that changed. - `LogicalAddress::is_valid_client_address` gains `#[must_use]`. Only the no-default-features lint reached it, so this repo never saw it. - A `Duration` subtraction in the interleaving test becomes `saturating_sub`. The instants are recorded in order so it cannot underflow, but an underflow would panic the test rather than fail its assertion, which reads as a hang. - Two doc comments get backticks on `DoIP`, which rustdoc otherwise reads as an unlinked item. `typos` found two real ones, both now fixed. `diagnotics` was in a **user-visible warning string** in `logical_address.rs`, so it would have shipped to anyone using the crate; `recieve` was in a doc comment. The three it flagged that are deliberate -- `pendings` (a run of DoIP "response pending" messages), `catch-alls`, `mis-mapped` -- are allowed in `.typos.toml`. One test doc comment named an internal MicroVision application as its example of a tester holding the `TCP_DATA` slot. This repository is public, so it now says "a diagnostic tool already polling the same ECU" -- which is also what the test actually exercises. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/ci.yml | 93 -------------------------------------- .github/workflows/main.yml | 72 +++++++++++++++++++++++++++++ .pre-commit-config.yaml | 71 +++++++++++++++++++++++++++++ .typos.toml | 8 ++++ .vscode/launch.json | 2 +- deny.toml | 19 ++++++++ src/bare_metal_entity.rs | 7 ++- src/client_inner.rs | 2 +- src/logical_address.rs | 3 +- src/messages/mod.rs | 24 +++++++--- tests/integration_test.rs | 10 ++-- 11 files changed, 203 insertions(+), 108 deletions(-) delete mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/main.yml create mode 100644 .pre-commit-config.yaml create mode 100644 .typos.toml create mode 100644 deny.toml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 69e0a1e..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,93 +0,0 @@ -name: CI - -on: - push: - branches: [main] - pull_request: - -env: - CARGO_TERM_COLOR: always - -permissions: - contents: read - -jobs: - test: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 - - run: cargo build --all-features - - run: cargo test --all-features - - clippy: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - uses: dtolnay/rust-toolchain@stable - with: - components: clippy - - uses: Swatinem/rust-cache@v2 - - run: cargo clippy --all-features -- -D warnings -Dclippy::pedantic - - fmt: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - uses: dtolnay/rust-toolchain@stable - with: - components: rustfmt - - run: cargo fmt -- --check - - feature-matrix: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - uses: dtolnay/rust-toolchain@stable - with: - components: clippy - - uses: Swatinem/rust-cache@v2 - - run: rustup target add thumbv7em-none-eabihf - - run: cargo check --no-default-features - - run: cargo check --no-default-features --features alloc - - run: cargo check --no-default-features --features std - - run: cargo check --no-default-features --features server - - run: cargo check --no-default-features --features client - - run: cargo check --no-default-features --features codec - - run: cargo check --features client,server - - run: cargo check --no-default-features --target thumbv7em-none-eabihf - - run: cargo clippy --all-targets --features client,server -- -D warnings - - run: cargo test --no-default-features - - run: cargo test --features client,server - - run: cargo build --example bare_metal_codec --no-default-features - - run: cargo run --example bare_metal_codec --no-default-features - - docs: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 - - run: cargo doc --no-deps --all-features - env: - RUSTDOCFLAGS: -D warnings - - msrv: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - uses: dtolnay/rust-toolchain@master - with: - toolchain: "1.88" - - uses: Swatinem/rust-cache@v2 - - run: cargo check --all-features - - run: cargo check --no-default-features - - package: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v6 - - uses: dtolnay/rust-toolchain@stable - - uses: Swatinem/rust-cache@v2 - - run: cargo publish --dry-run diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml new file mode 100644 index 0000000..184bfaf --- /dev/null +++ b/.github/workflows/main.yml @@ -0,0 +1,72 @@ +# Thin caller for the org-wide reusable Rust CI workflow, matching the sibling +# protocol repos (`uds_protocol`, `automotive_wire_codec`). This file owns the +# triggers and repo-specific configuration; `luminartech/rust_workflow` owns the +# jobs: pre-commit, lint, build, no_std canary, unit tests with coverage, miri, +# MSRV, semver-checks, security audit, docs, and a publish dry run. +# +# Publishing is NOT here. `release.yml` publishes on a `v*` tag through +# crates.io trusted publishing, which needs no stored registry token, so +# `publish-crate` is off below. +name: CI + +on: + pull_request: + merge_group: + push: + branches: [main] + workflow_dispatch: + inputs: + enable-comprehensive-tests: + description: 'Run comprehensive test suites (longer miri)' + required: false + default: false + type: boolean + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + ci: + uses: luminartech/rust_workflow/.github/workflows/rust-ci.yml@v1 + with: + # `release.yml` owns publishing, through trusted publishing rather than a + # registry token. The dry run stays on: it is the check that the crate + # still packages, and it needs no credentials. + publish-crate: false + run-publish-dry-run: true + + # OFF until the first version is on crates.io. `cargo-semver-checks` + # diffs against the published baseline, and there is none yet -- turn + # this on in the same change that enables publishing. + run-semver-checks: false + + # OFF until the crate has cargo-fuzz targets. `cargo fuzz build` fails + # without a `fuzz/` directory; simple_doip#1 adds four targets, and this + # flips when that lands. + run-fuzz-tests: false + + # OFF because this crate has no `prop_` tests. The filter would select + # nothing, and `cargo nextest` exits 4 on an empty selection -- so the + # job would fail rather than skip. Unit tests therefore run everything. + run-property-tests: false + unit-test-filter: 'all()' + + # `thumbv7em-none-eabihf` rather than the workflow's `thumbv6m` default: + # it is the target this crate's bare-metal support is written and + # documented against, and `examples/bare_metal_codec` is built for it. + no-std-target: thumbv7em-none-eabihf + + # `--lib` only: `tests/golden_vectors.rs` reads its `.hex` fixtures off + # disk, and miri's isolation refuses `open`. The lib tests are where the + # zero-copy decode paths worth checking for UB live -- 21 of them pass + # under miri today. + miri-args: '--lib' + + # MSRV comes from `rust-version` in Cargo.toml, so it cannot drift from + # what the manifest promises. + + comprehensive-tests: ${{ inputs.enable-comprehensive-tests || false }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..dac4536 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,71 @@ +# Mirrors the checks `luminartech/rust_workflow` runs, so a failure shows up +# before the push rather than in CI. Install with `pre-commit install`. +# +# mdformat is deliberately absent, unlike the sibling protocol repos: it +# escapes `[` and `]`, and this crate's README and ARCHITECTURE.md are full of +# intra-doc-style references and tables that the escaping mangles. +default_language_version: + python: python3.12 +default_stages: [pre-commit] +default_install_hook_types: [pre-commit, prepare-commit-msg, commit-msg] +repos: + # Squash-merge uses the PR title as the commit message, so the same grammar + # is checked on the commit locally. + - repo: https://github.com/compilerla/conventional-pre-commit + rev: v4.4.0 + hooks: + - id: conventional-pre-commit + stages: [commit-msg] + args: + - --strict + - feat + - fix + - perf + - docs + - refactor + - revert + - style + - test + - chore + - ci + - build + - repo: meta + hooks: + - id: check-hooks-apply + - id: check-useless-excludes + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v6.0.0 + hooks: + - id: trailing-whitespace + exclude_types: + - markdown + - id: end-of-file-fixer + exclude_types: + - rust + - id: check-yaml + args: [--allow-multiple-documents] + - id: check-json + # VS Code's launch.json is JSONC -- comments are expected there and + # strict JSON parsing rejects them. + exclude: ^\.vscode/ + - id: check-added-large-files + args: [--maxkb=1024] + - id: check-merge-conflict + - id: mixed-line-ending + args: [--fix=lf] + exclude_types: + - batch + - repo: https://github.com/crate-ci/typos + rev: v1.39.1 + hooks: + - id: typos + args: ["--config", ".typos.toml"] + - repo: https://github.com/gitleaks/gitleaks + rev: v8.29.0 + hooks: + - id: gitleaks + - repo: https://github.com/FeryET/pre-commit-rust + rev: v1.2.1 + hooks: + - id: fmt + - id: cargo-check diff --git a/.typos.toml b/.typos.toml new file mode 100644 index 0000000..2ff8b37 --- /dev/null +++ b/.typos.toml @@ -0,0 +1,8 @@ +# Words this crate uses deliberately that `typos` reads as misspellings. +[default.extend-words] +# "response pending" is a DoIP/UDS message; a sequence of them is "pendings". +pendings = "pendings" +# From "catch-alls" -- the enum variants that absorb unknown wire values. +alls = "alls" +# From "mis-mapped". +mis = "mis" diff --git a/.vscode/launch.json b/.vscode/launch.json index 7f5506b..783ce5a 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -117,4 +117,4 @@ "cwd": "${workspaceFolder}" } ] -} \ No newline at end of file +} diff --git a/deny.toml b/deny.toml new file mode 100644 index 0000000..4de13db --- /dev/null +++ b/deny.toml @@ -0,0 +1,19 @@ +[licenses] +version = 2 +confidence-threshold = 0.8 +allow = [ + "MIT", + "Apache-2.0", + "Unicode-3.0", +] + +[bans] +multiple-versions = "warn" +wildcards = "allow" + +[advisories] +yanked = "warn" + +[sources] +unknown-registry = "deny" +unknown-git = "deny" diff --git a/src/bare_metal_entity.rs b/src/bare_metal_entity.rs index d19225a..20820e6 100644 --- a/src/bare_metal_entity.rs +++ b/src/bare_metal_entity.rs @@ -534,7 +534,10 @@ mod tests { capture().uds_requests.push(request.to_vec()); response_out[0] = 0x55; response_out[1..=request.len()].copy_from_slice(request); - (request.len() + 1) as i32 + // The echo fixture is handed requests of a few bytes, so the + // conversion cannot fail; a truncating `as` would hide it if + // that ever stopped being true. + i32::try_from(request.len() + 1).expect("echo response length fits in i32") }, } } @@ -711,7 +714,7 @@ mod tests { let msg = Header::new( PROTOCOL_VERSION, PayloadType::DiagnosticMessage, - (MAX_RX_PAYLOAD + 1) as u32, + u32::try_from(MAX_RX_PAYLOAD + 1).expect("test payload length fits in u32"), ); let mut writer: &mut [u8] = &mut header; msg.encode(&mut writer).unwrap(); diff --git a/src/client_inner.rs b/src/client_inner.rs index 0f04509..dbb556a 100644 --- a/src/client_inner.rs +++ b/src/client_inner.rs @@ -129,7 +129,7 @@ impl Inner where Conn: crate::connection::Connector + 'static + Send + Sync, { - /// Spawns the inner client to run in the background and returns the send and recieve channels + /// Spawns the inner client to run in the background and returns the send and receive channels pub fn spawn(client_options: ClientOptions) -> (ControlSender, UpdateReceiver) { trace!("Spawning inner client"); let (control_sender, control_receiver) = mpsc::channel(16); diff --git a/src/logical_address.rs b/src/logical_address.rs index bf6ce30..0f36e24 100644 --- a/src/logical_address.rs +++ b/src/logical_address.rs @@ -36,6 +36,7 @@ impl LogicalAddress { /// Verify if the logical address is within the valid range for a client address /// of 0x0E00 - 0x0FFF + #[must_use] pub fn is_valid_client_address(&self) -> bool { if *self >= Self::MIN_CLIENT_ADDRESS && *self <= Self::MAX_CLIENT_ADDRESS { // Check if the logical address is in the OBD range @@ -46,7 +47,7 @@ impl LogicalAddress { #[cfg(feature = "std")] info!( "Logical addresses in the 0x0F00-0x0F7F range are intended for internal \ - data collection/on-board diagnotics only. Ensure that this is the intended use case." + data collection/on-board diagnostics only. Ensure that this is the intended use case." ); } true diff --git a/src/messages/mod.rs b/src/messages/mod.rs index c53404b..d8994ba 100644 --- a/src/messages/mod.rs +++ b/src/messages/mod.rs @@ -541,19 +541,29 @@ mod tests { fn test_valid_messages() { let buf: [u8; 9] = [0x02, 0xFD, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03]; let deserialized_message: Message<'_> = Message::decode(&buf).unwrap().0; - assert!(deserialized_message.header.protocol_version == ProtocolVersion::V2012); - assert!(deserialized_message.header.payload_type == PayloadType::NegativeAcknowledge); - assert!(deserialized_message.header.payload_length == 1); + assert_eq!( + deserialized_message.header.protocol_version, + ProtocolVersion::V2012 + ); + assert_eq!( + deserialized_message.header.payload_type, + PayloadType::NegativeAcknowledge + ); + assert_eq!(deserialized_message.header.payload_length, 1); let buf: [u8; 15] = [ 0x01, 0xFE, 0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; let deserialized_message: Message<'_> = Message::decode(&buf).unwrap().0; - assert!(deserialized_message.header.protocol_version == ProtocolVersion::V2010); - assert!( - deserialized_message.header.payload_type == PayloadType::VehicleIdentificationRequest + assert_eq!( + deserialized_message.header.protocol_version, + ProtocolVersion::V2010 + ); + assert_eq!( + deserialized_message.header.payload_type, + PayloadType::VehicleIdentificationRequest ); - assert!(deserialized_message.header.payload_length == 7); + assert_eq!(deserialized_message.header.payload_length, 7); } #[test] fn test_invalid_inverse() { diff --git a/tests/integration_test.rs b/tests/integration_test.rs index 6aedaae..7654b06 100644 --- a/tests/integration_test.rs +++ b/tests/integration_test.rs @@ -618,7 +618,7 @@ async fn wrong_routing_activation_response_type_errors_without_panicking() { /// A [`ServerConnectionHandler`] that *denies* routing activation, mimicking a /// `DoIP` entity whose single `TCP_DATA` slot is already held by another tester -/// (for example EnVision polling the same sensor). +/// (a diagnostic tool already polling the same ECU, say). struct DenyingRoutingHandler; #[async_trait] @@ -1481,7 +1481,10 @@ async fn handler_holds_pending_wait_open_between_sends() { // Bound 2: the two pendings are separated by the handler's 50ms sleep. Batched, they // arrive in the same flush and the gap collapses to microseconds. - let pending_gap = pending_at[1] - pending_at[0]; + // `saturating_sub`, not `-`: the two instants are recorded in order, so the + // difference cannot be negative -- but an underflow here would panic the + // test rather than fail the assertion below, which reads as a hang. + let pending_gap = pending_at[1].saturating_sub(pending_at[0]); assert!( pending_gap >= INTERLEAVING_MARGIN, "the two pending responses arrived {pending_gap:?} apart (at {:?} and {:?}); the \ @@ -1505,7 +1508,8 @@ async fn handler_holds_pending_wait_open_between_sends() { let _ = accept_loop.await; } -/// A raw DoIP entity that answers exactly one diagnostic request and then hangs up: +/// A raw `DoIP` entity that answers exactly one diagnostic request and then hangs +/// up: /// routing activation response, positive ack, the response itself, then close. /// /// Written against raw halves rather than [`Server`] because the point of the fixture From f402824b319cf92d7e288125a8969bdc81a3ed9c Mon Sep 17 00:00:00 2001 From: Justin Kovacich Date: Wed, 9 Sep 2026 13:59:59 -0400 Subject: [PATCH 2/6] ci: adopt the org-wide reusable Rust workflow Replaces this repo's seven hand-rolled jobs with a thin caller for `luminartech/rust_workflow/.github/workflows/rust-ci.yml@v1`, the same shape `uds_protocol` and `automotive_wire_codec` use. What the crate gains over the old `ci.yml`: pre-commit, a security audit (`cargo audit` + `cargo deny`), coverage, miri, and `cargo-semver-checks` -- the last being the gate that stops an accidental breaking release once the crate is published. Four inputs are deliberately off or overridden, each for a reason that will expire: - `publish-crate: false`. `release.yml` owns publishing, through trusted publishing rather than the registry token this workflow expects. The publish *dry run* stays on -- it needs no credentials and checks the crate still packages. - `run-semver-checks: false`. It diffs against the published baseline, and there is none until the first release. Flip it in the change that enables publishing. - `run-fuzz-tests: false`. `cargo fuzz build` needs a `fuzz/` directory. #1 adds four targets; this flips when that lands. - `run-property-tests: false` with `unit-test-filter: 'all()'`. There are no `prop_` tests, the filter would select nothing, and `cargo nextest` exits 4 on an empty selection -- so the job would fail rather than skip. And two overrides that are not temporary: `no-std-target: thumbv7em-none-eabihf`, the target this crate's bare-metal support is written against and `examples/bare_metal_codec` is built for, rather than the workflow's `thumbv6m` default; and `miri-args: '--lib'`, because `tests/golden_vectors.rs` reads its fixtures off disk and miri's isolation refuses `open`. The library tests are where the zero-copy decode paths worth checking for UB live, and 21 of them pass under miri. MSRV is left unset so the job reads `rust-version` from Cargo.toml and cannot drift from what the manifest promises. Scaffolding the shared workflow expects: `.pre-commit-config.yaml`, `.typos.toml`, and `deny.toml` copied from `uds_protocol`. Two hooks the siblings run are deliberately absent, with the reasons in the config -- mdformat would mangle this crate's markdown tables and reference-style links, and check-json has no strict JSON to check here. Every enabled gate was verified locally, including miri and pre-commit; `cargo deny` and `cargo audit` are not installed on this machine, so this PR's own run is their first check. This overlaps #1, which proposed its own 297-line `main.yml` before `rust_workflow` was tagged. The scaffolding that PR adds -- fuzz targets especially -- is still wanted; its workflow file is superseded by this caller. Co-Authored-By: Claude Opus 5 (1M context) --- .pre-commit-config.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index dac4536..c8ea9df 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -4,6 +4,10 @@ # mdformat is deliberately absent, unlike the sibling protocol repos: it # escapes `[` and `]`, and this crate's README and ARCHITECTURE.md are full of # intra-doc-style references and tables that the escaping mangles. +# +# check-json is absent too: the only JSON here is `.vscode/launch.json`, which +# is JSONC. Excluding it instead would leave the hook matching nothing, and +# `check-hooks-apply` fails a hook that matches nothing. default_language_version: python: python3.12 default_stages: [pre-commit] @@ -44,10 +48,6 @@ repos: - rust - id: check-yaml args: [--allow-multiple-documents] - - id: check-json - # VS Code's launch.json is JSONC -- comments are expected there and - # strict JSON parsing rejects them. - exclude: ^\.vscode/ - id: check-added-large-files args: [--maxkb=1024] - id: check-merge-conflict From 475939121d3a5dccd5bb6cf6567f40d62e9654a4 Mon Sep 17 00:00:00 2001 From: Justin Kovacich Date: Wed, 9 Sep 2026 14:04:47 -0400 Subject: [PATCH 3/6] chore(deps): refresh the lockfile off three vulnerable versions `cargo audit` fails on the committed lockfile with three vulnerabilities, all from versions that had drifted years behind what the manifest allows: - `bytes 1.4.0` -- RUSTSEC-2026-0007 (patched in >= 1.11.1) - `mio 0.8.8` -- RUSTSEC-2024-0019 (patched in >= 0.8.11) - `tracing-subscriber 0.3.19` -- RUSTSEC-2025-0055 (patched in >= 0.3.20) `cargo update` takes them to 1.12.1, 1.2.3 and 0.3.23, and moves 53 other packages -- `tokio 1.30.0` to 1.53.1 and `anyhow 1.0.75` to 1.0.104 among them, which clears three `unsound` advisories that were only warnings. No manifest requirement changes; every one of these was already permitted. The risk in a 56-package update is the MSRV, which this repo has never actually verified (see the next commit). `cargo +1.88` builds the refreshed graph with `--all-features` and with `--no-default-features`, so 1.88 still holds. Co-Authored-By: Claude Opus 5 (1M context) --- Cargo.lock | 321 ++++++++++---------------------------------- rust-toolchain.toml | 4 - 2 files changed, 72 insertions(+), 253 deletions(-) delete mode 100644 rust-toolchain.toml diff --git a/Cargo.lock b/Cargo.lock index fb7441a..c0fd8fe 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,44 +2,23 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "addr2line" -version = "0.20.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - [[package]] name = "anyhow" -version = "1.0.75" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "async-trait" -version = "0.1.73" +version = "0.1.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" +checksum = "82f6aeea286b8eb4dd3431a1be1b59d290ace00f5bfd8e2a159bc2a05e2c1667" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.5", ] -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - [[package]] name = "automotive-wire-codec" version = "0.3.0" @@ -49,41 +28,17 @@ dependencies = [ "embedded-io", ] -[[package]] -name = "backtrace" -version = "0.3.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - [[package]] name = "bytes" -version = "1.4.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" - -[[package]] -name = "cc" -version = "1.0.82" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01" -dependencies = [ - "libc", -] +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "embedded-io" @@ -93,9 +48,9 @@ checksum = "9eb1aa714776b75c7e67e1da744b81a129b3ff919c8712b5e1b32252c1f07cc7" [[package]] name = "futures" -version = "0.3.28" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "9a31d2a3fbaaeb2af2368bbdd904aa8e812d3c04a1ee10d3171f52d556e5d0a3" dependencies = [ "futures-channel", "futures-core", @@ -124,9 +79,9 @@ checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "031b47cf1a3c6cc8bc2fc76cd437f521619387907d469316e7c0bc278f1f5432" dependencies = [ "futures-core", "futures-task", @@ -179,24 +134,12 @@ dependencies = [ "slab", ] -[[package]] -name = "gimli" -version = "0.27.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" - [[package]] name = "heck" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" -[[package]] -name = "hermit-abi" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b" - [[package]] name = "lazy_static" version = "1.5.0" @@ -205,36 +148,27 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" [[package]] name = "log" -version = "0.4.29" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" [[package]] name = "memchr" -version = "2.5.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "miniz_oxide" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" -dependencies = [ - "adler", -] +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "mio" -version = "0.8.8" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" +checksum = "4b18443e9c262bfe8fa82f51666e2642c53393f7e5c27b3e1aeab922cff5b9d8" dependencies = [ "libc", "wasi", @@ -243,75 +177,43 @@ dependencies = [ [[package]] name = "nu-ansi-term" -version = "0.46.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" -dependencies = [ - "overload", - "winapi", -] - -[[package]] -name = "num_cpus" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "object" -version = "0.31.1" +version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "memchr", + "windows-sys", ] [[package]] name = "once_cell" -version = "1.18.0" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" - -[[package]] -name = "overload" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "pin-project-lite" -version = "0.2.12" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.46" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - [[package]] name = "sharded-slab" version = "0.1.7" @@ -341,24 +243,21 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.15.1" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "b9be42f50aa861c555654aa3a37f52f4b1074bacf4e48fe0ef7fa584e80f1f0f" [[package]] name = "socket2" -version = "0.5.3" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877" +checksum = "c3d1e2c7f27f8d4cb10542a02c49005dbd6e93095799d6f3be745fae9f8fedd4" dependencies = [ "libc", "windows-sys", @@ -382,14 +281,14 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] name = "syn" -version = "2.0.118" +version = "2.0.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" dependencies = [ "proc-macro2", "quote", @@ -409,44 +308,42 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.18" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "2.0.18" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.5", ] [[package]] name = "thread_local" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070" dependencies = [ "cfg-if", ] [[package]] name = "tokio" -version = "1.30.0" +version = "1.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d3ce25f50619af8b0aec2eb23deebe84249e19e2ddd393a6e16e3300a6dadfd" +checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed" dependencies = [ - "backtrace", "bytes", "libc", "mio", - "num_cpus", "pin-project-lite", "socket2", "tokio-macros", @@ -455,45 +352,44 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.1.0" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +checksum = "78773a2a397f451582ce068015985c33193cf6dea8b74d2a639fe457b2f07b0e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.5", ] [[package]] name = "tokio-util" -version = "0.7.8" +version = "0.7.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +checksum = "494815d09bf52b5548659851081238f0ca39ff638363907596da739561c62c52" dependencies = [ "bytes", "futures-core", "futures-sink", + "libc", "pin-project-lite", "tokio", - "tracing", ] [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ - "cfg-if", "pin-project-lite", "tracing-core", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", "valuable", @@ -512,9 +408,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.19" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ "nu-ansi-term", "sharded-slab", @@ -526,9 +422,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "valuable" @@ -538,94 +434,21 @@ checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "winapi" -version = "0.3.9" +name = "windows-link" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-targets", + "windows-link", ] - -[[package]] -name = "windows-targets" -version = "0.48.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" diff --git a/rust-toolchain.toml b/rust-toolchain.toml deleted file mode 100644 index 2328719..0000000 --- a/rust-toolchain.toml +++ /dev/null @@ -1,4 +0,0 @@ -[toolchain] -channel = "stable" -components = ["clippy", "rustfmt"] -targets = ["thumbv7em-none-eabihf"] From d78ea6d3abd5776c8da80485c4f93ed8d1d64358 Mon Sep 17 00:00:00 2001 From: Justin Kovacich Date: Wed, 9 Sep 2026 14:05:30 -0400 Subject: [PATCH 4/6] docs: record the dependency refresh and why there is no toolchain file Two things the previous commit changed without saying so. Its message describes only the lockfile refresh, but the `rust-toolchain.toml` deletion was already staged when I wrote it, so both landed together and the reason for the removal went unrecorded. Rather than rewrite the commit, the reason goes where someone will look for it. `CONTRIBUTING.md` now states that the absence of a toolchain file is deliberate: a directory-local `rust-toolchain.toml` overrides whatever toolchain CI installs, which turned the miri job into a failure and the MSRV job into a no-op that built with stable. It also says to name a toolchain explicitly when checking the floor, which is the trap I fell into -- `cargo +nightly` and `cargo +1.88` beat the file, so every local check passed while CI could not. The lockfile refresh gets a `Security` entry in the changelog, because three of the versions it moved off had RUSTSEC advisories against them and a consumer reading the changelog to decide whether to upgrade should see that. Co-Authored-By: Claude Opus 5 (1M context) --- CHANGELOG.md | 7 +++++++ CONTRIBUTING.md | 9 +++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25481e2..494a9bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,13 @@ changed rather than what was announced at the time. right source address. It stays `0x0000` before activation and after an activation the handler denied. +### Security + +- The committed lockfile pinned three versions with RUSTSEC advisories against + them — `bytes 1.4.0`, `mio 0.8.8` and `tracing-subscriber 0.3.19`. All three + are refreshed past their patched versions. No manifest requirement changed; + every one was already permitted. + ### Changed - docs.rs now builds with all features, so the `client`, `server` and `codec` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bf2e4bb..42efd0a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,8 +10,13 @@ preserve when changing the crate. ## Building and testing -The minimum supported Rust version is **1.88**. `default = []`, so a bare -`cargo test` exercises only the `no_std` core: +The minimum supported Rust version is **1.88**, declared as `rust-version` in +`Cargo.toml`. There is deliberately no `rust-toolchain.toml`: a directory-local +toolchain file overrides the toolchain CI installs, which silently turns the +MSRV and miri jobs into no-ops. Use whatever stable you have, and name a +toolchain explicitly (`cargo +1.88 build`) when you want to check the floor. + +`default = []`, so a bare `cargo test` exercises only the `no_std` core: ```sh cargo test --all-features # everything From 276d91f64cb24a422746e518e26366f3bb0829a3 Mon Sep 17 00:00:00 2001 From: Justin Kovacich Date: Wed, 9 Sep 2026 14:56:56 -0400 Subject: [PATCH 5/6] ci: lint the PR title, because squash-merge makes it the commit message The repository merges by squash with `squash_merge_commit_title: PR_TITLE`, so the PR title is the commit subject that lands on `main` -- the individual commits in a branch never appear there. The commit history is the changelog, so an unconventional PR title becomes a permanent unconventional changelog entry, and nothing was checking it. Both `uds_protocol` and `automotive_wire_codec` have carried this workflow; this repo did not. Only the title job is ported. The sibling repos pair it with a description lint that requires `## Issue URL` and `## Testing` sections from a pull-request template, and a `No Issue` label as the escape hatch. This repo has neither, so that job would fail every open PR. simple_doip#1 adds the templates -- the description lint belongs with them. The action is pinned by commit SHA rather than tag, matching how the shared workflow pins third-party actions. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/pr-lint.yml | 54 +++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 .github/workflows/pr-lint.yml diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml new file mode 100644 index 0000000..7ae5405 --- /dev/null +++ b/.github/workflows/pr-lint.yml @@ -0,0 +1,54 @@ +# PR title linting lives in its own workflow so a title edit re-runs only this +# check, not the whole verification suite. +# +# This matters more here than it looks: the repository merges by squash with +# `squash_merge_commit_title: PR_TITLE`, so the PR title -- not the commits in +# the branch -- is the commit subject that lands on `main`. The commit history +# is the changelog, and this is what keeps its entries conventional. +name: PR Lint + +on: + pull_request: + types: [opened, edited, reopened, synchronize] + +permissions: + pull-requests: read + +concurrency: + group: pr-lint-${{ github.head_ref }} + cancel-in-progress: true + +jobs: + pr-title-lint: + name: PR Title Lint + runs-on: ubuntu-latest + steps: + - uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + # The action matches types case-sensitively, so both the lowercase + # (conventional-commit spec) and capitalized forms are listed. + types: | + feat + Feat + fix + Fix + perf + Perf + docs + Docs + refactor + Refactor + revert + Revert + style + Style + test + Test + chore + Chore + ci + CI + build + Build From 27d590335c56d836b112b740ac202b10044ffb27 Mon Sep 17 00:00:00 2001 From: Justin Kovacich Date: Thu, 10 Sep 2026 09:52:40 -0400 Subject: [PATCH 6/6] ci: release with release-plz, like the sibling protocol repos Turns on `use-release-plz`, which activates the reusable workflow's release-plz PR and release jobs and disables its tag-gated `Release & Publish` job, so only one release path can fire. Wiring matches `automotive_wire_codec` exactly: `contents: write` + `pull-requests: write` on the called workflow (the test jobs downscope themselves back to read), the registry token and the release-plz GitHub App credentials passed as secrets, and `publish-repository` pinned so a fork cannot publish under this name. Repo configuration this needs before it can actually release, none of which is in this diff: `CARGO_REGISTRY_TOKEN`, `RELEASE_PLZ_APP_ID` and `RELEASE_PLZ_APP_PRIVATE_KEY` as secrets, and a `crates-io` environment -- the reusable workflow gates both release jobs on one, and this repo has no environments at all today while both siblings do. Until then the release-plz jobs run and no-op rather than publishing. `run-semver-checks` stays off, but the comment now says what it will and will not do once the first publish gives it a baseline: it diffs the public API surface, so a changed signature is caught and a changed behavior is not. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/main.yml | 39 ++++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 8 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 184bfaf..43b5f1f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,11 +2,12 @@ # protocol repos (`uds_protocol`, `automotive_wire_codec`). This file owns the # triggers and repo-specific configuration; `luminartech/rust_workflow` owns the # jobs: pre-commit, lint, build, no_std canary, unit tests with coverage, miri, -# MSRV, semver-checks, security audit, docs, and a publish dry run. +# MSRV, semver-checks, security audit, docs, a publish dry run, and the +# release-plz automation. # -# Publishing is NOT here. `release.yml` publishes on a `v*` tag through -# crates.io trusted publishing, which needs no stored registry token, so -# `publish-crate` is off below. +# Releasing is not a separate workflow: `use-release-plz` below turns on the +# two release-plz jobs in the reusable workflow, which maintain a release PR +# on every `main` push and publish when it merges. name: CI on: @@ -32,16 +33,38 @@ concurrency: jobs: ci: uses: luminartech/rust_workflow/.github/workflows/rust-ci.yml@v1 + # The test jobs downscope themselves to `contents: read`; this grant + # exists for the release-plz jobs, which push the release-PR branch and + # the release tag. + permissions: + contents: write + pull-requests: write + secrets: + cargo-registry-token: ${{ secrets.CARGO_REGISTRY_TOKEN }} + release-plz-app-id: ${{ secrets.RELEASE_PLZ_APP_ID }} + release-plz-app-private-key: ${{ secrets.RELEASE_PLZ_APP_PRIVATE_KEY }} with: - # `release.yml` owns publishing, through trusted publishing rather than a - # registry token. The dry run stays on: it is the check that the crate + # release-plz owns versioning, the changelog, tags, GitHub releases and + # the publish -- matching `uds_protocol` and `automotive_wire_codec`. + # It also disables the workflow's tag-gated `Release & Publish` job, so + # the two paths cannot both fire. + use-release-plz: true + # Restrict publishing to the canonical repo so a fork never publishes + # under this crate's name. + publish-repository: luminartech/simple_doip + + # The dry run stays on for pull requests: it is the check that the crate # still packages, and it needs no credentials. - publish-crate: false run-publish-dry-run: true # OFF until the first version is on crates.io. `cargo-semver-checks` # diffs against the published baseline, and there is none yet -- turn - # this on in the same change that enables publishing. + # this on once the first release-plz publish has happened. + # + # Worth knowing when it is on: it reads the public API surface, so it + # catches a changed signature and not a changed behavior. A function + # that starts emitting different bytes passes it. Breaking changes of + # that kind still have to be marked `!` on the PR title by hand. run-semver-checks: false # OFF until the crate has cargo-fuzz targets. `cargo fuzz build` fails