RELAY v1.11 §10.3 Adapt(), full rust-FuSa lifecycle + TARA, CLI rename - #11
Merged
Conversation
… rename - Add a vendored `relay` module (src/relay.rs) implementing RELAY spec §18.3's Message/Protocol/Version/Context/SubscriberOptions/Error types and the async Node/Caller traits, since no published relay-rs crate exists yet. - Implement a real `Adapt()` (src/adapt.rs `adapt()`) per §10.3: wraps a `Controller` as an async `relay::Caller`/`Node`, dispatching the blocking Controller API via `spawn_blocking` and applying the SubscriberOptions back-pressure policy (§10.5) through a dedicated AdaptQueue. Backed by new `to_message()`/`from_message()`/`response_to_message()` conversions matching the §15.7.5 field mappings exactly. - `rcp capabilities` now legitimately reports `"adapt": true` (a real Adapt() exists) and `"optional_interfaces": ["LoaningController"]` (previously empty despite LoaningController being implemented). - Export `RELAY_SPEC_VERSION` from the crate root (§18.3) and derive `Serialize`/`Deserialize` on `Command`/`Response`/`Status` with the exact §15.5 JSON field names; `Zone`/`Priority`/`CommandType`/`ResponseStatus` get hand-written numeric serde (bare integers, matching Go's wire format) rather than derived, since they stay newtype structs — converting them to `#[repr(u8)] enum` per §18.3's illustrative Rust snippet would be a much larger breaking change across every module that uses `.0`/Ord/Hash on them, for no wire-format difference. - Bump SPEC_VERSION/RELAY_SPEC_VERSION to 1.11 (current RELAY spec) and fix README's self-contradictory v1.6/v1.10 claims plus other stale "1.10" mentions (SAFETY_PLAN.md, .fusa-dfmea.json, .fusa-reqs.json REQ-SPEC-001). - Rename the CLI binary `rcp` -> `rust-rcp` per §13.2 (lowercase `<lang>-<protocol>`); update CI/docs accordingly. Library crate name is unchanged (`rcp`), matching §13.3's `mod <protocol>` convention. - Bump Cargo.toml to 0.3.0 so the next tag matches the crate version again (the existing v0.2.0 tag was cut with Cargo.toml still at 0.1.0; that historical tag can't be fixed retroactively, but this keeps future releases in sync) — MINOR bump since this adds new spec-conformance capability, not just a patch. - Add a hand-authored ISO/SAE 21434 TARA (tara.json: assets, threat scenarios, cybersecurity goals) grounded in RCP's actual attack surface (wire framing, E2E CRC/replay, authz, rate limiting, TLS bridge) per §20.4, and a `rust-fusa` CI job running the full rsfusa lifecycle (check/ trace/tara/cyber/qualify/release, gating; lint/analyze/comp/fmea/boundary/ hara/safety-case/iso26262 best-effort) per §20.1 item 2 — rust-CAN's CI is the template. Migrated .fusa.json/.fusa-reqs.json to the schema the current rsfusa release actually expects (both were written against an older, incompatible schema and failed to parse at all). - Left issue #7 (fully-synchronous core Controller/Registry API) open: a full async rewrite of the ~11k-line core API is a much larger, riskier change than this pass's scope, and the crate's sync design is plausibly intentional for no_std/embedded targets rather than an oversight — see the issue comment for the detailed rationale. The RELAY-facing boundary (Adapt()) is genuinely async now, which is the surface RELAY interop actually depends on. Closes #4 Closes #5 Closes #6 Closes #8 Closes #9 Closes #10 Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes every open issue from the 2026-07-27 RELAY ecosystem audit of rust-RCP.
Issues fixed
#5 [P0] capabilities doc falsely declares
"adapt": trueImplemented a real
Adapt()(rcp::adapt(ctrl), src/adapt.rs) per RELAY spec §10.3: wraps aControlleras an asyncrelay::Caller/relay::Node, backed by newto_message()/from_message()/response_to_message()conversions matching §15.7.5 exactly."adapt": trueis now a true statement rather than a stale hardcoded claim. Also populated"optional_interfaces": ["LoaningController"](previously[]despiteLoaningControllerbeing implemented).#6 [P1] No RELAY Rust binding
Added a vendored
relaymodule (src/relay.rs —Message,Protocol,Version,Context,SubscriberOptions, the four error sentinels, asyncNode/Callertraits) per §18.3, since no publishedrelay-rscrate exists yet (matches therust-CANsibling's own vendoring approach). ExportedRELAY_SPEC_VERSIONfrom the crate root.Command/Response/Statusnow deriveSerialize/Deserializewith the exact §15.5 JSON field names (includingCommand'styperename and base64-encodedpayload).Zone/Priority/CommandType/ResponseStatusget hand-written numeric serde (bare integers, matching Go's wire format) rather than a full conversion to#[repr(u8)] enum— that representation change would ripple through every module using.0/Ord/Hashon them for no wire-format difference, so I kept the existing newtype-struct representation and just made it serialize correctly.#8 [P1] CLI binary name
rcpnotrust-rcpRenamed the
[[bin]]target andTOOLconst torust-rcpper §13.2. Library crate name staysrcp, matching §13.3'smod <protocol>convention (unaffected —rust-CAN's own lib crate name diverges from this pattern for unrelated reasons, so I left ours as-is since no issue flagged it). Updated CI workflow build/binary paths accordingly.#9 [P1] Cargo.toml version never bumped for v0.2.0 tag
Bumped Cargo.toml to
0.3.0(MINOR bump — this PR adds new spec-conformance capability) so the next tag matches the crate version again. The existingv0.2.0GitHub tag itself permanently carriesCargo.tomlversion0.1.0in its historical commit; I did not rewrite tag history to "fix" that, per the task's git-safety constraints — going forward the invariant holds again.#10 [P2] README self-contradicts on spec version
Bumped the whole crate to target RELAY spec v1.11 (current), fixing the v1.6/v1.10 contradiction and every other stale "1.10" mention I found (SAFETY_PLAN.md,
.fusa-dfmea.json,.fusa-reqs.json'sREQ-SPEC-001text, the CI job name).#4 Add a TARA and the full rust-FuSa CI lifecycle
Added a hand-authored ISO/SAE 21434 TARA (
tara.json: 6 assets, 8 threat scenarios, 5 cybersecurity goals) grounded in RCP's actual attack surface (wire framing, E2E CRC/replay, authz allowlist bypass, rate-limiter/priority-queue DoS, TLS downgrade, watchdog suppression) per §20.4. Added arust-fusaCI job that installsrsfusaand runs the full lifecycle —check/trace/tara/cyber/qualify/releasegating,lint/analyze/comp/fmea/boundary/hara/safety-case/iso26262best-effort — mirroringrust-CAN's own CI job. Along the way I discovered.fusa.jsonand.fusa-reqs.jsonwere written against an older, incompatiblersfusaconfig schema (the current releasedrsfusacouldn't even parse them —missing field 'standard'), so I migrated both to the schema the current tool actually expects, verified locally against the realrsfusabinary and againstrust-CAN's own known-good files.Issue left open
#7 [P1] Crate is fully synchronous, violating §18.3's async-primary model
Left open with an explanatory comment. This PR does deliver a genuinely async surface — the new
relay::Node/CallerAdapt()boundary (the surface RELAY interop actually depends on) isasync fnthroughout, dispatching the blockingController/Registrycalls viatokio::task::spawn_blocking. But converting the entire ~11k-line coreController/RegistryAPI (used by all ~40 sibling modules — bridges, safety controllers, etc.) toasync fnis a much larger and riskier rewrite than the rest of this pass, and the crate's synchronous design is plausibly intentional forno_std/embedded targets rather than an oversight (the README described it that way, even if the crate isn't literally#![no_std]today). I didn't want to force that architectural call under this fix pass; the issue's own suggested fix offers exactly this "raise as spec feedback" path as an alternative to a full rewrite.Verification
cargo fmt --all -- --check— cleancargo clippy --all-targets --all-features -- -D warnings— cleancargo test --all-targets(debug + release) — 385 tests, all passingcargo llvm-cov --all-targets --fail-under-lines 90— 90.91% lines, passescargo audit— clean, no known vulnerabilities in new deps (tokio, chrono, base64, async-trait)relay conform --strict target/release/rust-rcp— PASS (built and run locally against the realrelayv1.11.1 CLI)relay interop target/release/rust-rcp—rcp-statusvector EQUIVALENTrsfusa check/trace/tara/cyber/qualify/release— all run cleanly against this branch with the realrsfusav0.3.8 binary (built fromgithub.com/SoundMatt/rust-FuSa)scripts/fusa-gap-check.sh— 357/357 requirements (100%) tracedTest plan
relay conform --strict,relay interop, RELAY spec unit conformance, IEC 62443 cyber gap check, new rust-FuSa full lifecycle job, SBOM, security audit)