From 64a86de9fc5ded51a1b5405223fc5dce16839fef Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Wed, 5 Nov 2025 12:50:03 +0000 Subject: Refactor: abstract announcement event creation into AuditClient helper - Add create_repo_announcement() method to AuditClient - Remove duplicate code from nip01_smoke.rs - Update grasp01_nostr_relay.rs to use centralized helper - All tests passing (GRASP-01: 4/18, NIP-01: 6/6) --- grasp-audit/src/client.rs | 43 ++++++++++++++++++++++++++++ grasp-audit/src/specs/grasp01_nostr_relay.rs | 31 ++++++++------------ grasp-audit/src/specs/nip01_smoke.rs | 43 +++------------------------- 3 files changed, 59 insertions(+), 58 deletions(-) (limited to 'grasp-audit/src') diff --git a/grasp-audit/src/client.rs b/grasp-audit/src/client.rs index b80b59f..7706ee3 100644 --- a/grasp-audit/src/client.rs +++ b/grasp-audit/src/client.rs @@ -158,6 +158,49 @@ impl AuditClient { pub fn keys(&self) -> &Keys { &self.keys } + + /// Create a NIP-34 repository announcement event + /// + /// This helper creates a properly formatted NIP-34 announcement that will be + /// accepted by GRASP relays (which require events to list the relay in clone/relays tags). + /// + /// # Arguments + /// * `test_name` - Name of the test (used to create unique repo identifier) + /// + /// # Returns + /// A built and signed Event ready to be sent to the relay + pub async fn create_repo_announcement(&self, test_name: &str) -> Result { + // Get relay URL from client + let relay_url = self.client.relays().await + .keys() + .next() + .ok_or_else(|| anyhow!("No relay connected"))? + .to_string(); + + // Convert WebSocket URL to HTTP URL for clone tag + let http_url = relay_url + .replace("ws://", "http://") + .replace("wss://", "https://"); + + // Create unique repository identifier using UUID for consistency + let repo_id = format!("{}-{}", test_name, uuid::Uuid::new_v4()); + + // Get npub for clone URL + let npub = self.public_key().to_bech32() + .map_err(|e| anyhow!("Failed to convert public key to bech32 npub format: {}", e))?; + + // Build kind 30617 repository announcement + let event = self.event_builder(Kind::GitRepoAnnouncement, format!("Test repository for {}", test_name)) + .tag(Tag::identifier(&repo_id)) + .tag(Tag::custom(TagKind::custom("name"), vec![format!("{} Test Repository", test_name)])) + .tag(Tag::custom(TagKind::custom("description"), vec![format!("Repository for {} testing", test_name)])) + .tag(Tag::custom(TagKind::custom("clone"), vec![format!("{}/{}/{}.git", http_url, npub, repo_id)])) + .tag(Tag::custom(TagKind::custom("relays"), vec![relay_url.clone()])) + .build(self.keys()) + .map_err(|e| anyhow!("Failed to build repository announcement event: {}", e))?; + + Ok(event) + } } #[cfg(test)] diff --git a/grasp-audit/src/specs/grasp01_nostr_relay.rs b/grasp-audit/src/specs/grasp01_nostr_relay.rs index 5a93672..837434b 100644 --- a/grasp-audit/src/specs/grasp01_nostr_relay.rs +++ b/grasp-audit/src/specs/grasp01_nostr_relay.rs @@ -64,35 +64,28 @@ impl Grasp01NostrRelayTests { "Accept valid repository announcements with service in clone and relays tags", ) .run(|| async { - // Get relay URL from client + // Create a NIP-34 repository announcement event + let event = client.create_repo_announcement("accept_valid_repo_announcement").await + .map_err(|e| format!("Failed to create repository announcement: {}", e))?; + + // Get relay URL for validation let relay_url = client.client().relays().await .keys() .next() .ok_or("No relay connected")? .to_string(); - // Convert WebSocket URL to HTTP URL for clone tag + // Convert WebSocket URL to HTTP URL for validation let http_url = relay_url .replace("ws://", "http://") .replace("wss://", "https://"); - // Create unique repository identifier - let timestamp = Timestamp::now().as_u64(); - let repo_id = format!("test-repo-{}", timestamp); - - // Get npub for clone URL - let npub = client.public_key().to_bech32() - .map_err(|e| format!("Failed to convert public key to bech32 npub format: {}", e))?; - - // Build kind 30617 repository announcement - let event = client.event_builder(Kind::GitRepoAnnouncement, "") - .tag(Tag::identifier(&repo_id)) - .tag(Tag::custom(TagKind::Custom("name".into()), vec!["GRASP-01 Test Repository"])) - .tag(Tag::custom(TagKind::Custom("description".into()), vec!["Test repository for GRASP-01 compliance testing"])) - .tag(Tag::custom(TagKind::Custom("clone".into()), vec![format!("{}/{}/{}.git", http_url, npub, repo_id)])) - .tag(Tag::custom(TagKind::Custom("relays".into()), vec![relay_url.clone()])) - .build(client.keys()) - .map_err(|e| format!("Failed to build repository announcement event (kind 30617): {}", e))?; + // Extract repo_id from the event's d tag + let repo_id = event.tags.iter() + .find(|t| t.kind() == TagKind::d()) + .and_then(|t| t.content()) + .ok_or("Missing d tag in announcement")? + .to_string(); // Send the event let event_id = client.send_event(event.clone()).await diff --git a/grasp-audit/src/specs/nip01_smoke.rs b/grasp-audit/src/specs/nip01_smoke.rs index cb256c5..9ed0f56 100644 --- a/grasp-audit/src/specs/nip01_smoke.rs +++ b/grasp-audit/src/specs/nip01_smoke.rs @@ -10,43 +10,6 @@ use nostr_sdk::prelude::*; pub struct Nip01SmokeTests; impl Nip01SmokeTests { - /// Create a NIP-34 repository announcement event - /// - /// This helper creates a properly formatted NIP-34 announcement that will be - /// accepted by GRASP relays (which require events to list the relay in clone/relays tags). - async fn create_announcement_event(client: &AuditClient, test_name: &str) -> Result { - // Get relay URL from client - let relay_url = client.client().relays().await - .keys() - .next() - .ok_or("No relay URL found")? - .to_string(); - - // Convert ws:// to http:// for clone URL - let http_url = relay_url - .replace("ws://", "http://") - .replace("wss://", "https://"); - - // Create unique repository identifier - let repo_id = format!("{}-{}", test_name, uuid::Uuid::new_v4()); - let npub = client.public_key().to_bech32() - .map_err(|e| format!("Failed to encode npub: {}", e))?; - - // Create NIP-34 repository announcement (kind 30617) - // This event lists the GRASP server, so it should be accepted - let event = client - .event_builder(Kind::Custom(30617), format!("NIP-01 smoke test repository: {}", test_name)) - .tag(Tag::identifier(&repo_id)) // d tag - .tag(Tag::custom(TagKind::Custom("name".into()), vec![format!("{} Test Repo", test_name)])) - .tag(Tag::custom(TagKind::Custom("description".into()), vec![format!("Repository for {} smoke testing", test_name)])) - .tag(Tag::custom(TagKind::Custom("clone".into()), vec![format!("{}/{}/{}.git", http_url, npub, repo_id)])) - .tag(Tag::custom(TagKind::Custom("relays".into()), vec![relay_url.clone()])) - .build(client.keys()) - .map_err(|e| format!("Failed to build event: {}", e))?; - - Ok(event) - } - /// Run all NIP-01 smoke tests pub async fn run_all(client: &AuditClient) -> AuditResult { let mut results = AuditResult::new("NIP-01 Smoke Tests"); @@ -97,7 +60,8 @@ impl Nip01SmokeTests { ) .run(|| async { // Create a NIP-34 announcement event - let event = Self::create_announcement_event(client, "send_receive_event").await?; + let event = client.create_repo_announcement("send_receive_event").await + .map_err(|e| format!("Failed to create announcement: {}", e))?; // Send event let event_id = client @@ -161,7 +125,8 @@ impl Nip01SmokeTests { ) .run(|| async { // Create a NIP-34 announcement event (accepted by GRASP relays) - let event = Self::create_announcement_event(client, "create_subscription").await?; + let event = client.create_repo_announcement("create_subscription").await + .map_err(|e| format!("Failed to create announcement: {}", e))?; let event_id = client .send_event(event.clone()) -- cgit v1.2.3