app

Local-first trade for farms and co-ops
git clone https://radroots.dev/git/app.git
Log | Files | Refs | README | LICENSE

commit 47ef6f21ed8a157d0cac900ea18e75f9f0377157
parent c3f8b0d732d12def73289caa15e0f9704b896ff2
Author: triesap <tyson@radroots.org>
Date:   Fri, 19 Jun 2026 03:56:15 -0700

runtime: remove listing direct publish guard exceptions

- rename the app sync transport away from legacy direct publish identity
- remove obsolete listing publish SDK boundary allowlist entries
- keep remaining deferred account and local outbox guard exceptions explicit
- update source guard injection coverage for runtime SDK client rejection

Diffstat:
Mcrates/desktop/src/runtime.rs | 42+++++++++++++++++++++---------------------
Mcrates/desktop/src/source_guards.rs | 73++++++++-----------------------------------------------------------------
2 files changed, 29 insertions(+), 86 deletions(-)

diff --git a/crates/desktop/src/runtime.rs b/crates/desktop/src/runtime.rs @@ -304,11 +304,11 @@ enum AppDirectRelayIngestError { } #[derive(Clone)] -struct SdkDirectRelayAppSyncTransport { +struct ConfiguredRelayAppSyncTransport { relay_urls: Vec<String>, } -impl SdkDirectRelayAppSyncTransport { +impl ConfiguredRelayAppSyncTransport { fn new(_accounts_manager: RadrootsNostrAccountsManager, nostr_relay_urls: Vec<String>) -> Self { Self { relay_urls: nostr_relay_urls, @@ -401,7 +401,7 @@ fn publish_payload_context(publish_payload: &AppPublishPayload) -> &AppPublishCo } } -impl AppSyncTransport for SdkDirectRelayAppSyncTransport { +impl AppSyncTransport for ConfiguredRelayAppSyncTransport { fn sync(&mut self, request: AppSyncRequest) -> Result<AppSyncResult, AppSyncTransportError> { self.sync_with_sdk(request) } @@ -1694,7 +1694,7 @@ impl DesktopAppRuntimeState { )); let sync_transport: Box<dyn AppSyncTransport + Send> = match accounts_bootstrap.accounts_manager.as_ref() { - Some(accounts_manager) => Box::new(SdkDirectRelayAppSyncTransport::new( + Some(accounts_manager) => Box::new(ConfiguredRelayAppSyncTransport::new( accounts_manager.clone(), nostr_relay_urls.clone(), )), @@ -10714,11 +10714,11 @@ mod tests { "585591529da0bab31b3b1b1f986611cf5f435dca84f978c89ee8a40cca7103df"; use super::{ - APP_DATABASE_FILE_NAME, APP_SYNC_PUBLISH_USES_SDK_RUNTIME_MESSAGE, DesktopAppRuntime, - DesktopAppRuntimeActivityContextError, DesktopAppRuntimeCommandError, - DesktopAppRuntimeMetadataSummary, DesktopAppRuntimeState, DesktopAppSdkDiagnosticsState, - DesktopAppSyncStatusSummary, DesktopRemoteSignerPaths, SYNC_TRANSPORT_UNAVAILABLE_MESSAGE, - SdkDirectRelayAppSyncTransport, TokioRuntimeBuilder, default_sync_transport, + APP_DATABASE_FILE_NAME, APP_SYNC_PUBLISH_USES_SDK_RUNTIME_MESSAGE, + ConfiguredRelayAppSyncTransport, DesktopAppRuntime, DesktopAppRuntimeActivityContextError, + DesktopAppRuntimeCommandError, DesktopAppRuntimeMetadataSummary, DesktopAppRuntimeState, + DesktopAppSdkDiagnosticsState, DesktopAppSyncStatusSummary, DesktopRemoteSignerPaths, + SYNC_TRANSPORT_UNAVAILABLE_MESSAGE, TokioRuntimeBuilder, default_sync_transport, direct_relay_event_source_runtime, farm_sync_payload, is_hex_64, order_decision_publish_payload_to_sdk_decision, pending_sync_upsert, signed_event_from_local_record, @@ -11084,7 +11084,7 @@ mod tests { .clone(); runtime.lock_state_mut().nostr_relay_urls = vec![relay.url().to_owned()]; runtime.lock_state_mut().sync_transport = - Box::new(SdkDirectRelayAppSyncTransport::with_relay_urls( + Box::new(ConfiguredRelayAppSyncTransport::with_relay_urls( accounts_manager, vec![relay.url().to_owned()], )); @@ -11112,7 +11112,7 @@ mod tests { }); let operation = PendingSyncOperation::from_publish_payload(payload, "2026-05-24T12:00:00Z") .expect("typed farm publish work should serialize"); - let mut transport = SdkDirectRelayAppSyncTransport::with_relay_urls( + let mut transport = ConfiguredRelayAppSyncTransport::with_relay_urls( manager, vec![relay_a.url().to_owned(), relay_b.url().to_owned()], ); @@ -11150,7 +11150,7 @@ mod tests { let operation = PendingSyncOperation::from_publish_payload(payload, "2026-05-24T12:00:00Z") .expect("typed listing publish work should serialize"); let mut transport = - SdkDirectRelayAppSyncTransport::with_relay_urls(manager, vec![relay.url().to_owned()]); + ConfiguredRelayAppSyncTransport::with_relay_urls(manager, vec![relay.url().to_owned()]); let error = transport .sync(AppSyncRequest { @@ -11242,7 +11242,7 @@ mod tests { let operation = PendingSyncOperation::from_publish_payload(payload, "2026-05-24T12:00:00Z") .expect("typed order request publish work should serialize"); let mut transport = - SdkDirectRelayAppSyncTransport::with_relay_urls(manager, vec![relay.url().to_owned()]); + ConfiguredRelayAppSyncTransport::with_relay_urls(manager, vec![relay.url().to_owned()]); let error = transport .sync(AppSyncRequest { @@ -11289,7 +11289,7 @@ mod tests { let operation = PendingSyncOperation::from_publish_payload(payload, "2026-05-24T12:00:00Z") .expect("typed order decision publish work should serialize"); let mut transport = - SdkDirectRelayAppSyncTransport::with_relay_urls(manager, vec![relay.url().to_owned()]); + ConfiguredRelayAppSyncTransport::with_relay_urls(manager, vec![relay.url().to_owned()]); let error = transport .sync(AppSyncRequest { @@ -11459,7 +11459,7 @@ mod tests { }) .collect::<Vec<_>>(); let mut transport = - SdkDirectRelayAppSyncTransport::with_relay_urls(manager, vec![relay.url().to_owned()]); + ConfiguredRelayAppSyncTransport::with_relay_urls(manager, vec![relay.url().to_owned()]); let error = transport .sync(AppSyncRequest { @@ -11891,7 +11891,7 @@ mod tests { "2026-05-24T12:01:00Z", ); let mut transport = - SdkDirectRelayAppSyncTransport::with_relay_urls(manager, vec![relay.url().to_owned()]); + ConfiguredRelayAppSyncTransport::with_relay_urls(manager, vec![relay.url().to_owned()]); let error = transport .sync(AppSyncRequest { @@ -12001,7 +12001,7 @@ mod tests { let operation = PendingSyncOperation::from_publish_payload(payload, "2026-05-25T07:00:00Z") .expect("order publish payload should serialize"); let mut transport = - SdkDirectRelayAppSyncTransport::with_relay_urls(manager, vec![relay.url().to_owned()]); + ConfiguredRelayAppSyncTransport::with_relay_urls(manager, vec![relay.url().to_owned()]); let error = transport .sync(AppSyncRequest { @@ -12035,7 +12035,7 @@ mod tests { let operation = PendingSyncOperation::from_publish_payload(payload, "2026-05-24T12:00:00Z") .expect("typed listing publish work should serialize"); let mut transport = - SdkDirectRelayAppSyncTransport::with_relay_urls(manager, vec![relay.url().to_owned()]); + ConfiguredRelayAppSyncTransport::with_relay_urls(manager, vec![relay.url().to_owned()]); let error = transport .sync(AppSyncRequest { @@ -12065,7 +12065,7 @@ mod tests { let operation = PendingSyncOperation::from_publish_payload(payload, "2026-05-24T12:00:00Z") .expect("typed farm publish work should serialize"); let mut transport = - SdkDirectRelayAppSyncTransport::with_relay_urls(manager, vec![relay.url().to_owned()]); + ConfiguredRelayAppSyncTransport::with_relay_urls(manager, vec![relay.url().to_owned()]); let error = transport .sync(AppSyncRequest { @@ -12097,7 +12097,7 @@ mod tests { let operation = PendingSyncOperation::from_publish_payload(payload, "2026-05-24T12:00:00Z") .expect("typed farm publish work should serialize"); let mut transport = - SdkDirectRelayAppSyncTransport::with_relay_urls(manager, vec![relay.url().to_owned()]); + ConfiguredRelayAppSyncTransport::with_relay_urls(manager, vec![relay.url().to_owned()]); let error = transport .sync(AppSyncRequest { @@ -12143,7 +12143,7 @@ mod tests { let operation = PendingSyncOperation::from_publish_payload(payload, "2026-05-24T12:00:00Z") .expect("typed farm publish work should serialize"); let mut transport = - SdkDirectRelayAppSyncTransport::with_relay_urls(manager, vec![relay.url().to_owned()]); + ConfiguredRelayAppSyncTransport::with_relay_urls(manager, vec![relay.url().to_owned()]); let error = transport .sync(AppSyncRequest { diff --git a/crates/desktop/src/source_guards.rs b/crates/desktop/src/source_guards.rs @@ -1308,55 +1308,6 @@ const STRICT_SDK_BOUNDARY_FORBIDDEN_PATTERNS: &[SdkBoundaryForbiddenPattern] = & const LEGACY_SDK_BOUNDARY_ALLOWLIST: &[LegacySdkBoundaryAllowlistEntry] = &[ LegacySdkBoundaryAllowlistEntry { - path: "crates/desktop/src/runtime.rs", - pattern: "SdkDirectRelayAppSyncTransport", - owner: "rpv1-app-sdk-refactor.07", - reason: "desktop runtime still owns deferred direct relay publish transport for listing publish", - removal_condition: "remove when listing publish workflow enqueues through AppSdkRuntime", - }, - LegacySdkBoundaryAllowlistEntry { - path: "crates/desktop/src/runtime.rs", - pattern: "RadrootsSdkClient", - owner: "rpv1-app-sdk-refactor.07", - reason: "desktop runtime still constructs the legacy direct publish client for listing publish", - removal_condition: "remove when direct publish workflows no longer construct SDK clients outside AppSdkRuntime", - }, - LegacySdkBoundaryAllowlistEntry { - path: "crates/desktop/src/runtime.rs", - pattern: "RadrootsSdkConfig", - owner: "rpv1-app-sdk-refactor.07", - reason: "desktop runtime still configures the legacy direct publish client for listing publish", - removal_condition: "remove when direct publish workflows no longer configure SDK clients outside AppSdkRuntime", - }, - LegacySdkBoundaryAllowlistEntry { - path: "crates/desktop/src/runtime.rs", - pattern: "SdkTransportMode::RelayDirect", - owner: "rpv1-app-sdk-refactor.07", - reason: "desktop runtime still uses relay direct publish transport for listing publish", - removal_condition: "remove when listing publish workflow routes through SDK canonical outbox and sync APIs", - }, - LegacySdkBoundaryAllowlistEntry { - path: "crates/desktop/src/runtime.rs", - pattern: "SignerConfig::LocalIdentity", - owner: "rpv1-app-sdk-refactor.07", - reason: "desktop runtime still configures direct local signing for listing publish", - removal_condition: "remove when publish signing is mediated by AppSdkRuntime and SDK signer adapters", - }, - LegacySdkBoundaryAllowlistEntry { - path: "crates/desktop/src/runtime.rs", - pattern: "PendingSyncOperation::from_publish_payload", - owner: "rpv1-app-sdk-refactor.07", - reason: "desktop runtime still creates legacy local outbox publish work for listing publish", - removal_condition: "remove when listing publish writes SDK canonical outbox requests instead of app local_outbox operations", - }, - LegacySdkBoundaryAllowlistEntry { - path: "crates/desktop/src/runtime.rs", - pattern: "publish_with_identity", - owner: "rpv1-app-sdk-refactor.07", - reason: "desktop runtime still calls legacy direct SDK listing publish APIs", - removal_condition: "remove when listing publish workflow enqueues through AppSdkRuntime", - }, - LegacySdkBoundaryAllowlistEntry { path: "crates/desktop/src/accounts.rs", pattern: "RadrootsIdentity::from_secret_key_str", owner: "rpv1-app-sdk-hardening.04", @@ -1385,20 +1336,6 @@ const LEGACY_SDK_BOUNDARY_ALLOWLIST: &[LegacySdkBoundaryAllowlistEntry] = &[ removal_condition: "remove when remote signer protocol sessions are mediated by SDK signer adapters and protected store APIs", }, LegacySdkBoundaryAllowlistEntry { - path: "crates/sync/src/publish.rs", - pattern: "SdkTransportMode::RelayDirect", - owner: "rpv1-app-sdk-refactor.07", - reason: "sync payload metadata still marks legacy listing local outbox publish work as relay direct", - removal_condition: "remove when listing publish payload metadata is replaced by SDK canonical outbox requests", - }, - LegacySdkBoundaryAllowlistEntry { - path: "crates/sync/src/publish.rs", - pattern: "publish_draft_with_identity", - owner: "rpv1-app-sdk-refactor.07", - reason: "sync payload metadata still names legacy listing SDK publish operations", - removal_condition: "remove when listing publish payload metadata is replaced by SDK canonical outbox requests", - }, - LegacySdkBoundaryAllowlistEntry { path: "crates/store/src/lib.rs", pattern: ".enqueue_pending_operation(", owner: "rpv1-app-sdk-refactor.07", @@ -1616,10 +1553,16 @@ fn strict_sdk_boundary_scanner_rejects_unallowlisted_new_production_paths() { assert_eq!(findings.len(), 1); assert_eq!(findings[0].pattern, "RadrootsSdkClient"); + let runtime_findings = unallowlisted_sdk_boundary_patterns( + "crates/desktop/src/runtime.rs", + "fn publish() { let _ = RadrootsSdkClient::from_config(config); }", + ); + assert_eq!(runtime_findings.len(), 1); + assert_eq!(runtime_findings[0].pattern, "RadrootsSdkClient"); assert!( unallowlisted_sdk_boundary_patterns( - "crates/desktop/src/runtime.rs", - "fn publish() { let _ = RadrootsSdkClient::from_config(config); }", + "crates/desktop/src/accounts.rs", + "fn import() { let _ = RawSecretKey; }", ) .is_empty() );