lib

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

commit 639cdae2fc15cab732ff507bb6640d1302d577ae
parent e008273835fdadfeacce80727bbc01f360e718cd
Author: triesap <tyson@radroots.org>
Date:   Fri, 31 Jul 2026 13:02:16 +0000

nostr: complete package conformance coverage

- exercise canonical protocol conversions through the public adapter surface
- prove exact authorized local signing through the generic signer contract
- reject forbidden production dependencies traits and host runtime ownership
- qualify every supported feature target documentation and workspace gate

Diffstat:
Acrates/nostr/tests/conformance.rs | 88+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mcrates/nostr/tests/package_boundary.rs | 86++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 173 insertions(+), 1 deletion(-)

diff --git a/crates/nostr/tests/conformance.rs b/crates/nostr/tests/conformance.rs @@ -0,0 +1,88 @@ +use radroots_event::id::Nip01Coordinate; +use radroots_identity::PublicKey; +use radroots_nostr::{ + Error, + event::{coordinate_from_nostr, coordinate_to_nostr}, + key::{public_key_from_npub, public_key_to_npub}, + tag::{from_parts, to_parts}, +}; + +const PUBLIC_KEY: &str = "79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"; + +#[test] +fn public_protocol_conversions_are_canonical_and_typed() { + let public_key = PublicKey::from_hex(PUBLIC_KEY).expect("canonical public key"); + let npub = public_key_to_npub(public_key).expect("NIP-19 public key"); + assert!(npub.starts_with("npub1")); + assert_eq!( + public_key_from_npub(&npub).expect("canonical public key"), + public_key + ); + + let coordinate = Nip01Coordinate::parse(format!("30402:{PUBLIC_KEY}:listing-1")) + .expect("canonical coordinate"); + let nostr_coordinate = coordinate_to_nostr(&coordinate).expect("Nostr coordinate"); + assert_eq!( + coordinate_from_nostr(&nostr_coordinate).expect("canonical coordinate"), + coordinate + ); + + let parts = vec!["t".to_owned(), "soil".to_owned()]; + let tag = from_parts(parts.clone()).expect("Nostr tag"); + assert_eq!(to_parts(&tag), parts); + assert!(matches!(from_parts(Vec::new()), Err(Error::TagConversion))); +} + +#[cfg(feature = "signing")] +#[tokio::test] +async fn public_local_signer_signs_only_the_exact_authorized_draft() { + use radroots_event::{EventDraft, contract::AuthorRole, envelope::kind::KIND_GEOCHAT}; + use radroots_nostr::{key::SecretKey, signing::LocalSigner}; + use radroots_protocol::runtime::v1::OperationId; + use radroots_signing::{ + Actor, SignRequest, Signer, + actor::ActorSource, + request::{CancellationPolicy, SignPolicy}, + }; + + let secret_key = + SecretKey::parse("0000000000000000000000000000000000000000000000000000000000000001") + .expect("fixture secret"); + let public_key = secret_key.public_key().expect("public key"); + assert_eq!(public_key.to_hex(), PUBLIC_KEY); + + let draft = EventDraft::new( + "radroots.social.geochat.v1", + KIND_GEOCHAT, + 1_700_000_000, + Vec::new(), + "package-conformance-message", + PUBLIC_KEY, + ) + .expect("frozen event draft"); + let expected_id = draft.expected_event_id_hex(); + let actor = Actor::new( + public_key, + ActorSource::ExplicitPublicKey, + [AuthorRole::Any], + ) + .expect("authorized actor"); + let request = SignRequest::new( + OperationId::SyncPush, + actor, + draft, + SignPolicy::new(u64::MAX, CancellationPolicy::LocalCooperative) + .expect("bounded signing policy"), + ) + .expect("signing request"); + + let signer = LocalSigner::new(secret_key).expect("local signer"); + let receipt = signer.sign(request).await.expect("signed receipt"); + + assert_eq!(receipt.signed_event().id_str(), expected_id); + assert_eq!(*receipt.signed_event().pubkey(), public_key); + assert_eq!( + receipt.signed_event().content(), + "package-conformance-message" + ); +} diff --git a/crates/nostr/tests/package_boundary.rs b/crates/nostr/tests/package_boundary.rs @@ -71,7 +71,8 @@ fn manifest_has_final_identity_features_and_radroots_dependencies() { } assert_eq!( dependencies - .into_iter() + .iter() + .copied() .filter(|dependency| dependency.starts_with("radroots_")) .collect::<BTreeSet<_>>(), BTreeSet::from([ @@ -82,6 +83,49 @@ fn manifest_has_final_identity_features_and_radroots_dependencies() { "radroots_signing", ]) ); + + for forbidden in [ + "keyring", + "nostr-sdk", + "nostr_sdk", + "radroots_outbox", + "radroots_storage", + "radroots_transport", + "reqwest", + "sqlx", + "tokio", + ] { + assert!( + !dependencies.contains(forbidden), + "portable Nostr adapter must not depend on `{forbidden}`" + ); + } + + let features = table_keys(MANIFEST, "[features]"); + for required in ["default", "std", "events", "signing", "nip17", "blossom"] { + assert!( + features.contains(required), + "manifest is missing supported feature `{required}`" + ); + } + for feature in features { + let declaration = table_value(MANIFEST, "[features]", feature) + .unwrap_or_else(|| panic!("missing feature declaration `{feature}`")); + for forbidden in [ + "client", + "http", + "network", + "relay", + "reqwest", + "runtime", + "transport", + ] { + assert!( + !declaration.contains(forbidden), + "feature `{feature}` activates forbidden live-I/O authority `{forbidden}`" + ); + } + } } #[test] @@ -396,6 +440,46 @@ fn focused_nip_and_blossom_features_own_no_network_operations() { } } +#[test] +fn production_api_declares_no_traits_or_host_runtime_implementations() { + let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + let mut public_traits = BTreeSet::new(); + + for source_path in rust_sources(&manifest_dir.join("src")) { + let source = fs::read_to_string(&source_path) + .unwrap_or_else(|error| panic!("failed to read {}: {error}", source_path.display())); + let production = source.split("\n#[cfg(test)]").next().unwrap_or(&source); + for line in production.lines() { + let trimmed = line.trim_start(); + if let Some(name) = trimmed + .strip_prefix("pub trait ") + .and_then(|rest| rest.split([':', '<', ' ']).next()) + { + public_traits.insert(name.to_owned()); + } + for forbidden in [ + "nostr_sdk::", + "reqwest::", + "sqlx::", + "tokio::spawn", + "std::net::", + "std::thread::spawn", + ] { + assert!( + !trimmed.contains(forbidden), + "{} owns forbidden host/runtime implementation `{forbidden}`: {trimmed}", + source_path.display() + ); + } + } + } + + assert!( + public_traits.is_empty(), + "concrete protocol adapter must not publish an SPI trait: {public_traits:?}" + ); +} + fn rust_sources(root: &Path) -> Vec<PathBuf> { let mut pending = vec![root.to_path_buf()]; let mut sources = Vec::new();