lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

commit 13e1d274f04fc464124bf9c7b8d02c51f224c6a2
parent 67e5089b435d89f763b73a60ed3b23e5a9f6a374
Author: triesap <tyson@radroots.org>
Date:   Tue,  7 Jul 2026 20:34:34 +0000

transport: consume shared Reticulum endpoint in target sets

- replace the SDK-local Reticulum endpoint literal with the shared transport constant
- reject raw Reticulum endpoint drift through shared target construction
- reject malformed typed Reticulum targets at SDK target-set ingress
- update SDK source-boundary and adapter tests for the shared endpoint contract

Diffstat:
Mcrates/sdk/src/transport.rs | 13++++++-------
Mcrates/sdk/tests/source_boundary.rs | 14++++++++++++++
Mcrates/sdk/tests/unit/adapters_radrootsd_tests.rs | 14+++++++-------
Mcrates/sdk/tests/unit/transport_tests.rs | 42+++++++++++++++++++++++++++++++++---------
4 files changed, 60 insertions(+), 23 deletions(-)

diff --git a/crates/sdk/src/transport.rs b/crates/sdk/src/transport.rs @@ -1,8 +1,8 @@ use crate::RadrootsSdkError; use radroots_transport::{ - RadrootsTransportDeliveryReceipt, RadrootsTransportKind, RadrootsTransportSatisfactionClass, - RadrootsTransportTarget, RadrootsTransportTargetFingerprint, RadrootsTransportTargetReceipt, - RadrootsTransportTargetSet, + RADROOTS_RETICULUM_PREVIEW_ENDPOINT_URI, RadrootsTransportDeliveryReceipt, + RadrootsTransportKind, RadrootsTransportSatisfactionClass, RadrootsTransportTarget, + RadrootsTransportTargetFingerprint, RadrootsTransportTargetReceipt, RadrootsTransportTargetSet, }; use radroots_transport_nostr::{RadrootsRelayUrl, RadrootsRelayUrlPolicy}; use serde::ser::{SerializeStruct, Serializer}; @@ -16,7 +16,6 @@ pub use radroots_transport::{ }; pub const SDK_TRANSPORT_TARGET_MAX_COUNT: usize = 20; -const RETICULUM_PREVIEW_ENDPOINT_URI: &str = "reticulum:preview-unavailable"; #[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize)] #[serde(rename_all = "snake_case")] @@ -237,11 +236,11 @@ impl TargetSet { } for target in &targets { if target.kind == RadrootsTransportKind::Reticulum - && target.uri.as_str() != RETICULUM_PREVIEW_ENDPOINT_URI + && target.uri.as_str() != RADROOTS_RETICULUM_PREVIEW_ENDPOINT_URI { return Err(RadrootsSdkError::InvalidRequest { message: format!( - "Reticulum preview endpoint must be {RETICULUM_PREVIEW_ENDPOINT_URI}" + "Reticulum preview endpoint must be {RADROOTS_RETICULUM_PREVIEW_ENDPOINT_URI}" ), }); } @@ -308,7 +307,7 @@ pub struct ReticulumPreviewProfile { impl ReticulumPreviewProfile { pub fn preview_unavailable() -> Self { Self { - endpoint_uri: RETICULUM_PREVIEW_ENDPOINT_URI.to_owned(), + endpoint_uri: RADROOTS_RETICULUM_PREVIEW_ENDPOINT_URI.to_owned(), behavior: ReticulumPreviewBehavior::RejectDeliveryAttempts, } } diff --git a/crates/sdk/tests/source_boundary.rs b/crates/sdk/tests/source_boundary.rs @@ -1397,6 +1397,20 @@ fn sdk_transport_sources_keep_reticulum_preview_push_boundary() { } } + let transport_source = read_source(manifest_dir.join("src/transport.rs").as_path()); + assert!( + transport_source.contains("RADROOTS_RETICULUM_PREVIEW_ENDPOINT_URI"), + "src/transport.rs must consume the shared Reticulum preview endpoint constant" + ); + assert!( + !transport_source.contains("const RETICULUM_PREVIEW_ENDPOINT_URI"), + "src/transport.rs must not duplicate the Reticulum preview endpoint constant" + ); + assert!( + !transport_source.contains("reticulum:preview-unavailable"), + "src/transport.rs must not duplicate the Reticulum preview endpoint literal" + ); + let sync_runtime = read_source(manifest_dir.join("src/sync_runtime.rs").as_path()); for required in [ "TransportProfile::ReticulumPreview { profile }", diff --git a/crates/sdk/tests/unit/adapters_radrootsd_tests.rs b/crates/sdk/tests/unit/adapters_radrootsd_tests.rs @@ -1,13 +1,13 @@ use super::*; +use radroots_transport::RADROOTS_RETICULUM_PREVIEW_ENDPOINT_URI; use radroots_transport_nostr::{ RadrootsRelayPublishRequest, RadrootsRelayTargetSet, RadrootsRelayUrlPolicy, }; use radroots_transport_publish_protocol::{ - NostrPublishTargetSourcePolicy, RETICULUM_PREVIEW_ENDPOINT_URI, TransportPublishDeliveryPolicy, - TransportPublishEventRequest, TransportPublishEventResponse, TransportPublishJobStatus, - TransportPublishJobView, TransportPublishOutcomeKind, TransportPublishPreviewBehavior, - TransportPublishTarget, TransportPublishTargetOutcome, TransportPublishTargetPolicy, - TransportPublishTargetSource, + NostrPublishTargetSourcePolicy, TransportPublishDeliveryPolicy, TransportPublishEventRequest, + TransportPublishEventResponse, TransportPublishJobStatus, TransportPublishJobView, + TransportPublishOutcomeKind, TransportPublishPreviewBehavior, TransportPublishTarget, + TransportPublishTargetOutcome, TransportPublishTargetPolicy, TransportPublishTargetSource, }; use std::io::{Read, Write}; use std::net::TcpListener; @@ -517,7 +517,7 @@ async fn publish_signed_event_preserves_typed_reticulum_preview_behavior() { ); assert_eq!( body["params"]["target_policy"]["targets"][0]["endpoint_uri"], - RETICULUM_PREVIEW_ENDPOINT_URI + RADROOTS_RETICULUM_PREVIEW_ENDPOINT_URI ); assert_eq!( body["params"]["target_policy"]["targets"][0]["preview_behavior"], @@ -646,7 +646,7 @@ async fn relay_publish_adapter_maps_proxy_errors_to_transport_errors() { fn relay_proxy_target_conversion_rejects_reticulum_targets_before_behavior_loss() { let target = radroots_transport::RadrootsTransportTarget::new( radroots_transport::RadrootsTransportKind::Reticulum, - RETICULUM_PREVIEW_ENDPOINT_URI, + RADROOTS_RETICULUM_PREVIEW_ENDPOINT_URI, ) .expect("Reticulum target"); diff --git a/crates/sdk/tests/unit/transport_tests.rs b/crates/sdk/tests/unit/transport_tests.rs @@ -3,7 +3,10 @@ use super::{ ReticulumPreviewProfile, SatisfactionPolicy, TargetPolicy, TargetSet, TransportProfile, }; use crate::{RadrootsSdkError, SDK_TRANSPORT_TARGET_MAX_COUNT}; -use radroots_transport::{RadrootsTransportKind, RadrootsTransportTarget}; +use radroots_transport::{ + RADROOTS_RETICULUM_PREVIEW_ENDPOINT_URI, RadrootsTransportError, RadrootsTransportKind, + RadrootsTransportTarget, RadrootsTransportTargetFingerprint, RadrootsTransportTargetUri, +}; #[path = "../support/serializer_failure.rs"] mod serializer_failure; @@ -175,7 +178,10 @@ fn target_set_accessors_and_configured_relays_cover_empty_and_dedupe_paths() { fn reticulum_preview_profile_uses_canonical_endpoint_and_behavior_names() { let profile = ReticulumPreviewProfile::preview_unavailable(); - assert_eq!(profile.endpoint_uri(), "reticulum:preview-unavailable"); + assert_eq!( + profile.endpoint_uri(), + RADROOTS_RETICULUM_PREVIEW_ENDPOINT_URI + ); assert_eq!( profile.behavior(), ReticulumPreviewBehavior::RejectDeliveryAttempts @@ -199,13 +205,31 @@ fn reticulum_preview_profile_uses_canonical_endpoint_and_behavior_names() { #[test] fn explicit_target_sets_reject_noncanonical_reticulum_preview_endpoints() { - let err = TargetSet::transport_targets(vec![ - RadrootsTransportTarget::new( - RadrootsTransportKind::Reticulum, - "reticulum:preview-unavailable-alt", - ) - .expect("target"), - ]) + for invalid in [ + " reticulum:preview-unavailable", + "reticulum:preview-unavailable ", + "RETICULUM:preview-unavailable", + "reticulum:Preview-Unavailable", + "reticulum:preview", + "reticulum:preview-unavailable-alt", + "reticulum:custom", + ] { + assert_eq!( + RadrootsTransportTarget::new(RadrootsTransportKind::Reticulum, invalid) + .expect_err("invalid Reticulum target"), + RadrootsTransportError::InvalidTargetUri + ); + } + + let uri = + RadrootsTransportTargetUri::parse("reticulum:preview-unavailable-alt").expect("target uri"); + let fingerprint = + RadrootsTransportTargetFingerprint::from_target(&RadrootsTransportKind::Reticulum, &uri); + let err = TargetSet::transport_targets(vec![RadrootsTransportTarget { + kind: RadrootsTransportKind::Reticulum, + uri, + fingerprint, + }]) .expect_err("noncanonical Reticulum endpoint"); assert!(matches!(err, RadrootsSdkError::InvalidRequest { .. }));