cli

Command-line interface for Radroots
git clone https://radroots.dev/git/cli.git
Log | Files | Refs | README | LICENSE

commit 77a641133b5545c59afad193775275376fd825aa
parent 73cefddc6d9a7d2bde47a9b3341c5c0419889c02
Author: triesap <tyson@radroots.org>
Date:   Thu,  7 May 2026 03:29:23 +0000

cli: gate listing update publish mode

Diffstat:
Msrc/operation_listing.rs | 2+-
Msrc/operation_registry.rs | 2++
Mtests/target_cli.rs | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 85 insertions(+), 1 deletion(-)

diff --git a/src/operation_listing.rs b/src/operation_listing.rs @@ -119,7 +119,7 @@ impl OperationService<ListingUpdateRequest> for ListingOperationService<'_> { request.operation_id(), crate::runtime::listing::update(&config, &args), )?; - serialized_operation_result::<ListingUpdateResult, _>(&view) + mutation_result::<ListingUpdateResult>(request.operation_id(), &view) } } diff --git a/src/operation_registry.rs b/src/operation_registry.rs @@ -1155,6 +1155,7 @@ pub fn requires_nostr_relay_publish_mode(operation_id: &str) -> bool { operation_id, "farm.publish" | "listing.publish" + | "listing.update" | "listing.archive" | "order.submit" | "order.accept" @@ -1513,6 +1514,7 @@ mod tests { let expected = [ "farm.publish", "listing.publish", + "listing.update", "listing.archive", "order.submit", "order.accept", diff --git a/tests/target_cli.rs b/tests/target_cli.rs @@ -175,6 +175,88 @@ fn radrootsd_publish_mode_fails_closed_for_direct_relay_publish_paths() { } #[test] +fn radrootsd_publish_mode_fails_closed_for_listing_update() { + let sandbox = RadrootsCliSandbox::new(); + let missing_listing = sandbox.root().join("missing-listing.toml"); + + let (output, value) = sandbox.json_output(&[ + "--format", + "json", + "--publish-mode", + "radrootsd", + "listing", + "update", + missing_listing.to_string_lossy().as_ref(), + ]); + + assert!(!output.status.success()); + assert_eq!(output.status.code(), Some(3)); + assert_eq!(value["operation_id"], "listing.update"); + assert_eq!(value["result"], Value::Null); + assert_eq!(value["errors"][0]["code"], "operation_unavailable"); + assert_eq!(value["errors"][0]["detail"]["publish"]["mode"], "radrootsd"); + assert_eq!( + value["errors"][0]["detail"]["publish"]["provider"]["provider_runtime_id"], + "radrootsd" + ); + assert_eq!( + value["errors"][0]["detail"]["publish"]["provider"]["state"], + "unavailable" + ); +} + +#[test] +fn listing_update_unavailable_support_exits_nonzero() { + let sandbox = RadrootsCliSandbox::new(); + sandbox.json_success(&["--format", "json", "account", "create"]); + let farm = sandbox.json_success(&[ + "--format", + "json", + "farm", + "create", + "--name", + "Update Farm", + "--location", + "farmstand", + "--country", + "US", + "--delivery-method", + "pickup", + ]); + let listing_file = create_listing_draft(&sandbox, "update-unavailable"); + make_listing_publishable( + &listing_file, + farm["result"]["config"]["farm_d_tag"] + .as_str() + .expect("farm d tag"), + ); + + let (output, value) = sandbox.json_output(&[ + "--format", + "json", + "--relay", + "ws://127.0.0.1:9", + "listing", + "update", + listing_file.to_string_lossy().as_ref(), + ]); + + assert!(!output.status.success()); + assert_eq!(output.status.code(), Some(3)); + assert_eq!(value["operation_id"], "listing.update"); + assert_eq!(value["result"], Value::Null); + assert_eq!(value["errors"][0]["code"], "operation_unavailable"); + assert!( + value["errors"][0]["message"] + .as_str() + .expect("error message") + .contains("direct Nostr relay publishing is not implemented for listing update") + ); + assert_no_removed_command_reference(&value, &["listing", "update"]); + assert_no_daemon_runtime_reference(&value, &["listing", "update"]); +} + +#[test] fn removed_order_submit_watch_flag_is_rejected_publicly() { let output = radroots() .args(["order", "submit", "--watch"])