upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2025-11-05 08:31:24 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2025-11-05 08:31:24 +0000
commitc2183f156a767c1443c7ae62954fe8192e349ceb (patch)
treecbbcbd41113a1d96898106b43ea11c9bf65399ca
parent64e607dd67f3777aa596596d74ee16e1bf9f4f27 (diff)
feat(grasp-audit): implement test_accept_valid_repo_announcement
- Fix Tags iteration error (use .iter() method) - Test validates GRASP-01 requirement: accept repo announcements listing service - Verifies clone and relays tags contain service URL - Tested against ngit-relay on port 18081 - Test passes successfully
-rw-r--r--grasp-audit/src/specs/grasp01_nostr_relay.rs89
-rw-r--r--grasp-audit/src/specs/mod.rs2
2 files changed, 77 insertions, 14 deletions
diff --git a/grasp-audit/src/specs/grasp01_nostr_relay.rs b/grasp-audit/src/specs/grasp01_nostr_relay.rs
index 1d1de79..a81132d 100644
--- a/grasp-audit/src/specs/grasp01_nostr_relay.rs
+++ b/grasp-audit/src/specs/grasp01_nostr_relay.rs
@@ -64,20 +64,81 @@ impl Grasp01NostrRelayTests {
64 "Accept valid repository announcements with service in clone and relays tags", 64 "Accept valid repository announcements with service in clone and relays tags",
65 ) 65 )
66 .run(|| async { 66 .run(|| async {
67 // TODO: Implementation 67 // Get relay URL from client
68 // 1. Get service URL from client config 68 let relay_url = client.client().relays().await
69 // 2. Create kind 30617 event with: 69 .keys()
70 // - d tag: "test-repo-{timestamp}" 70 .next()
71 // - name tag: "Test Repository" 71 .ok_or("No relay connected")?
72 // - description tag: "Test repository for GRASP-01 compliance" 72 .to_string();
73 // - clone tag: "{service_url}/{npub}/test-repo.git"
74 // - relays tag: "{service_ws_url}"
75 // 3. Send event to relay
76 // 4. Verify OK response (not rejected)
77 // 5. Query back with filter on kind 30617, author, d tag
78 // 6. Verify event is stored and matches what we sent
79 73
80 Err("Not implemented yet".to_string()) 74 // Convert WebSocket URL to HTTP URL for clone tag
75 let http_url = relay_url
76 .replace("ws://", "http://")
77 .replace("wss://", "https://");
78
79 // Create unique repository identifier
80 let timestamp = Timestamp::now().as_u64();
81 let repo_id = format!("test-repo-{}", timestamp);
82
83 // Get npub for clone URL
84 let npub = client.public_key().to_bech32()
85 .map_err(|e| format!("Failed to convert pubkey to npub: {}", e))?;
86
87 // Build kind 30617 repository announcement
88 let event = client.event_builder(Kind::GitRepoAnnouncement, "")
89 .tag(Tag::identifier(&repo_id))
90 .tag(Tag::custom(TagKind::Custom("name".into()), vec!["GRASP-01 Test Repository"]))
91 .tag(Tag::custom(TagKind::Custom("description".into()), vec!["Test repository for GRASP-01 compliance testing"]))
92 .tag(Tag::custom(TagKind::Custom("clone".into()), vec![format!("{}/{}/{}.git", http_url, npub, repo_id)]))
93 .tag(Tag::custom(TagKind::Custom("relays".into()), vec![relay_url.clone()]))
94 .build(client.keys())
95 .map_err(|e| format!("Failed to build event: {}", e))?;
96
97 // Send the event
98 let event_id = client.send_event(event.clone()).await
99 .map_err(|e| format!("Failed to send event: {}", e))?;
100
101 // Query back to verify it was accepted and stored
102 let filter = Filter::new()
103 .kind(Kind::GitRepoAnnouncement)
104 .author(client.public_key())
105 .identifier(&repo_id);
106
107 let events = client.query(filter).await
108 .map_err(|e| format!("Failed to query events: {}", e))?;
109
110 // Verify we got the event back
111 if events.is_empty() {
112 return Err("Event was not stored in relay (possibly rejected)".to_string());
113 }
114
115 // Verify it's the same event
116 let stored_event = events.iter()
117 .find(|e| e.id == event_id)
118 .ok_or("Stored event ID doesn't match sent event")?;
119
120 // Verify key tags are present
121 let has_clone_tag = stored_event.tags.iter()
122 .any(|t| {
123 t.kind() == TagKind::Custom("clone".into()) &&
124 t.content().map(|c| c.contains(&http_url)).unwrap_or(false)
125 });
126
127 let has_relays_tag = stored_event.tags.iter()
128 .any(|t| {
129 t.kind() == TagKind::Custom("relays".into()) &&
130 t.content() == Some(&relay_url)
131 });
132
133 if !has_clone_tag {
134 return Err(format!("Stored event missing clone tag with service URL ({})", http_url));
135 }
136
137 if !has_relays_tag {
138 return Err(format!("Stored event missing relays tag with service URL ({})", relay_url));
139 }
140
141 Ok(())
81 }) 142 })
82 .await 143 .await
83 } 144 }
@@ -564,7 +625,7 @@ mod tests {
564 #[ignore] // Requires running relay 625 #[ignore] // Requires running relay
565 async fn test_grasp01_nostr_relay_against_relay() { 626 async fn test_grasp01_nostr_relay_against_relay() {
566 let config = AuditConfig::ci(); 627 let config = AuditConfig::ci();
567 let client = AuditClient::new("ws://localhost:8081", config) 628 let client = AuditClient::new("ws://localhost:18081", config)
568 .await 629 .await
569 .expect("Failed to connect to relay"); 630 .expect("Failed to connect to relay");
570 631
diff --git a/grasp-audit/src/specs/mod.rs b/grasp-audit/src/specs/mod.rs
index 451ea1f..834bf9e 100644
--- a/grasp-audit/src/specs/mod.rs
+++ b/grasp-audit/src/specs/mod.rs
@@ -1,5 +1,7 @@
1//! Test specifications 1//! Test specifications
2 2
3pub mod grasp01_nostr_relay;
3pub mod nip01_smoke; 4pub mod nip01_smoke;
4 5
6pub use grasp01_nostr_relay::Grasp01NostrRelayTests;
5pub use nip01_smoke::Nip01SmokeTests; 7pub use nip01_smoke::Nip01SmokeTests;