commit 93027d0e0885a2234fbc244559f82b70b5f93010
parent 0455d7211ac01f0e8a6d15908285a90202bebc17
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:
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 { .. }));