commit bb53bc2b0fd18edc98ed3778d69c682a040396c9
parent 24e27e9e1ba9eb6946431d28e8c48f15064a1f94
Author: triesap <tyson@radroots.org>
Date: Tue, 7 Jul 2026 22:26:51 +0000
transport: reject proxy targets before jobs
- Add daemon coverage for canonical proxy explicit target rejection.
- Prove invalid proxy requests do not record publish jobs.
- Guard source boundaries for shared proxy target validation.
- Preserve Reticulum preview request validation behavior.
Diffstat:
2 files changed, 59 insertions(+), 0 deletions(-)
diff --git a/src/core/transport_publish.rs b/src/core/transport_publish.rs
@@ -3061,6 +3061,39 @@ mod tests {
);
}
+ #[tokio::test]
+ async fn publish_event_rejects_proxy_target_before_recording_job() {
+ let identity = RadrootsIdentity::generate();
+ let (proxy, adapter) = transport_publish(TransportPublishConfig::default());
+ let principal =
+ explicit_target_principal(&proxy, identity.public_key_hex(), PublishJobVisibility::Own);
+ let mut request = reticulum_publish_request(
+ signed_event(&identity, "{}"),
+ TransportPublishPreviewBehavior::RejectDeliveryAttempts,
+ );
+ request.target_policy =
+ TransportPublishTargetPolicy::explicit_targets(vec![TransportPublishTarget {
+ transport_kind: "proxy".to_owned(),
+ endpoint_uri: "radrootsd-proxy:publish".to_owned(),
+ preview_behavior: None,
+ }]);
+
+ let err = proxy
+ .publish_event(&principal, request)
+ .await
+ .expect_err("proxy target");
+
+ assert!(matches!(err, TransportPublishError::InvalidSignedEvent(_)));
+ assert!(adapter.captured_raw_events().is_empty());
+ assert!(
+ proxy
+ .store
+ .list_jobs_for_principal(&principal, 10)
+ .expect("jobs")
+ .is_empty()
+ );
+ }
+
fn removed_proxy_kind_string() -> String {
["radrootsd", "_proxy"].concat()
}
diff --git a/tests/source_boundary.rs b/tests/source_boundary.rs
@@ -85,6 +85,32 @@ fn transport_publish_sources_reject_removed_protocol_identifiers() {
}
#[test]
+fn transport_publish_sources_reject_proxy_explicit_targets() {
+ let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR"));
+ let protocol_source = read_source(
+ manifest_dir
+ .join("../lib/crates/transport_publish_protocol/src/lib.rs")
+ .as_path(),
+ );
+ for required in [
+ "ExplicitProxyTarget",
+ "transport_kind == RadrootsTransportKind::Proxy",
+ "cannot be used as a daemon explicit target",
+ ] {
+ assert!(
+ protocol_source.contains(required),
+ "transport publish protocol must retain proxy explicit-target rejection witness `{required}`"
+ );
+ }
+
+ let daemon_source = read_source(manifest_dir.join("src/core/transport_publish.rs").as_path());
+ assert!(
+ daemon_source.contains("publish_event_rejects_proxy_target_before_recording_job"),
+ "daemon transport publish tests must prove proxy explicit targets are rejected before job recording"
+ );
+}
+
+#[test]
fn transport_publish_capabilities_expose_per_transport_readiness() {
let methods_source = read_source(
Path::new(env!("CARGO_MANIFEST_DIR"))