upleb.uk

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

summaryrefslogtreecommitdiff
path: root/grasp-audit
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2025-11-05 14:43:30 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2025-11-05 14:45:02 +0000
commitb22cb23928ef799b0a5d362003d3084d2ab267b4 (patch)
tree26ae31724472e7d5d2b2f61df47e728c25f8d908 /grasp-audit
parentebdf1779697e1b3d0fa0e1068af4340a16eabf2b (diff)
test: consolidate state announcement tests with GRASP-01 spec format
Refactor repository state announcement testing to better match GRASP-01 specification requirements: - Consolidate multiple refs testing into accept_valid_repo_state_announcement - Remove separate accept_state_announcement_multiple_refs test (redundant) - Update tag format to match spec: use git reference as tag kind Example: ["refs/heads/main", "<commit-sha>"] instead of ["r", "refs/heads/main", "<commit-sha>"] - Ensure repo announcement (kind 30617) is sent before state announcement - Test multiple branch refs (main, develop), tag refs (v1.0.0), and HEAD - Simplify test validation by removing redundant assertions This approach provides better spec compliance and reduces test redundancy while maintaining comprehensive coverage of multiple reference scenarios.
Diffstat (limited to 'grasp-audit')
-rw-r--r--grasp-audit/src/specs/grasp01_nostr_relay.rs134
1 files changed, 37 insertions, 97 deletions
diff --git a/grasp-audit/src/specs/grasp01_nostr_relay.rs b/grasp-audit/src/specs/grasp01_nostr_relay.rs
index 19322cb..247850b 100644
--- a/grasp-audit/src/specs/grasp01_nostr_relay.rs
+++ b/grasp-audit/src/specs/grasp01_nostr_relay.rs
@@ -25,8 +25,6 @@ impl Grasp01NostrRelayTests {
25 25
26 // Repository state announcement tests 26 // Repository state announcement tests
27 results.add(Self::test_accept_valid_repo_state_announcement(client).await); 27 results.add(Self::test_accept_valid_repo_state_announcement(client).await);
28 results.add(Self::test_accept_state_announcement_multiple_refs(client).await);
29 results.add(Self::test_accept_state_announcement_no_refs(client).await);
30 28
31 // Related event acceptance tests 29 // Related event acceptance tests
32 results.add(Self::test_accept_event_tagging_repo_announcement(client).await); 30 results.add(Self::test_accept_event_tagging_repo_announcement(client).await);
@@ -277,29 +275,53 @@ impl Grasp01NostrRelayTests {
277 TestResult::new( 275 TestResult::new(
278 "accept_valid_repo_state_announcement", 276 "accept_valid_repo_state_announcement",
279 "GRASP-01:nostr-relay:6-7", 277 "GRASP-01:nostr-relay:6-7",
280 "Accept valid repository state announcements with required tags", 278 "Accept valid state announcements after repo announcement accepted",
281 ) 279 )
282 .run(|| async { 280 .run(|| async {
283 // Create unique repository identifier 281 // First, create a repository announcement (kind 30617) by the same author
284 let timestamp = Timestamp::now().as_u64(); 282 let test_name = format!("test-repo-multi-refs-{}", Timestamp::now().as_u64());
285 let repo_id = format!("test-repo-state-{}", timestamp); 283 let repo_event = client.create_repo_announcement(&test_name).await
284 .map_err(|e| format!("Failed to create repository announcement: {}", e))?;
285
286 // Extract repo_id from the repository announcement
287 let repo_id = repo_event.tags.iter()
288 .find(|t| t.kind() == TagKind::d())
289 .and_then(|t| t.content())
290 .ok_or("Missing d tag in repository announcement")?
291 .to_string();
286 292
287 // Create kind 30618 repository state announcement with required tags 293 // Get maintainer npub
288 let npub = client.public_key().to_bech32() 294 let npub = client.public_key().to_bech32()
289 .map_err(|e| format!("Failed to convert public key to bech32: {}", e))?; 295 .map_err(|e| format!("Failed to convert public key to bech32: {}", e))?;
290 296
297 // Create kind 30618 repository state announcement with multiple refs
298 // Format: ["r", "refs/heads/main", "<commit-id>"]
291 let event = client.event_builder(Kind::Custom(30618), "") 299 let event = client.event_builder(Kind::Custom(30618), "")
292 .tag(Tag::identifier(&repo_id)) 300 .tag(Tag::identifier(&repo_id))
293 .tag(Tag::custom(TagKind::custom("maintainers"), vec![npub])) 301 .tag(Tag::custom(TagKind::custom("refs/heads/main"), vec![
294 .tag(Tag::custom(TagKind::custom("r"), vec!["refs/heads/main".to_string()])) 302 "abc123def456789012345678901234567890abcd"
303 ]))
304 .tag(Tag::custom(TagKind::custom("refs/heads/develop"), vec![
305 "def456789012345678901234567890abcdef123"
306 ]))
307 .tag(Tag::custom(TagKind::custom("refs/tags/v1.0.0"), vec![
308 "123456789012345678901234567890abcdef456"
309 ]))
310 .tag(Tag::custom(TagKind::custom("HEAD"), vec![
311 "ref: refs/heads/main"
312 ]))
295 .build(client.keys()) 313 .build(client.keys())
296 .map_err(|e| format!("Failed to build repository state announcement: {}", e))?; 314 .map_err(|e| format!("Failed to build state announcement: {}", e))?;
297 315
298 let event_id = event.id; 316 let event_id = event.id;
299 317
300 // Send the event 318 // Send the repo announcement event
319 client.send_event(repo_event.clone()).await
320 .map_err(|e| format!("Failed to send state announcement to relay: {}", e))?;
321
322 // Send the state event
301 client.send_event(event.clone()).await 323 client.send_event(event.clone()).await
302 .map_err(|e| format!("Failed to send repository state announcement to relay: {}", e))?; 324 .map_err(|e| format!("Failed to send state announcement to relay: {}", e))?;
303 325
304 // Query back to verify it was accepted and stored 326 // Query back to verify it was accepted and stored
305 let filter = Filter::new() 327 let filter = Filter::new()
@@ -317,95 +339,13 @@ impl Grasp01NostrRelayTests {
317 event_id, repo_id 339 event_id, repo_id
318 )); 340 ));
319 } 341 }
320 342
321 // Verify it's the same event
322 let stored_event = events.iter()
323 .find(|e| e.id == event_id)
324 .ok_or(format!(
325 "Stored event ID doesn't match sent event. Expected: {}, Got {} events",
326 event_id, events.len()
327 ))?;
328
329 // Verify required tags are present
330 let has_d_tag = stored_event.tags.iter()
331 .any(|t| t.kind() == TagKind::d() && t.content() == Some(&repo_id));
332
333 let has_maintainers_tag = stored_event.tags.iter()
334 .any(|t| t.kind() == TagKind::custom("maintainers"));
335
336 let has_r_tag = stored_event.tags.iter()
337 .any(|t| {
338 t.kind() == TagKind::custom("r") &&
339 t.content().map(|c| c.contains("refs/heads/main")).unwrap_or(false)
340 });
341
342 if !has_d_tag {
343 return Err(format!("Stored event missing d tag with repo identifier ({})", repo_id));
344 }
345
346 if !has_maintainers_tag {
347 return Err("Stored event missing maintainers tag".to_string());
348 }
349
350 if !has_r_tag {
351 return Err("Stored event missing r tag with git reference".to_string());
352 }
353
354 Ok(()) 343 Ok(())
355 }) 344 })
356 .await 345 .await
357 } 346 }
358 347
359 /// Test: Accept state announcement with multiple refs 348
360 ///
361 /// Spec: Line 3 of ../grasp/01.md
362 /// Requirement: MUST accept state announcements with multiple refs
363 async fn test_accept_state_announcement_multiple_refs(client: &AuditClient) -> TestResult {
364 TestResult::new(
365 "accept_state_announcement_multiple_refs",
366 "GRASP-01:nostr-relay:3",
367 "Accept state announcements with multiple branch and tag refs",
368 )
369 .run(|| async {
370 // TODO: Implementation
371 // 1. Send valid kind 30617 repo announcement
372 // 2. Create kind 30618 with multiple refs:
373 // - refs/heads/main: "{commit-sha-1}"
374 // - refs/heads/develop: "{commit-sha-2}"
375 // - refs/tags/v1.0.0: "{commit-sha-3}"
376 // - refs/tags/v2.0.0: "{commit-sha-4}"
377 // - HEAD: "ref: refs/heads/main"
378 // 3. Send and verify acceptance
379 // 4. Query back and verify all refs are stored
380
381 Err("Not implemented yet".to_string())
382 })
383 .await
384 }
385
386 /// Test: Accept state announcement with no refs (stop tracking)
387 ///
388 /// Spec: NIP-34 repository state announcements
389 /// Requirement: Support stopping state tracking by sending event with no refs
390 async fn test_accept_state_announcement_no_refs(client: &AuditClient) -> TestResult {
391 TestResult::new(
392 "accept_state_announcement_no_refs",
393 "GRASP-01:nostr-relay:3",
394 "Accept state announcements with no refs (stop tracking)",
395 )
396 .run(|| async {
397 // TODO: Implementation
398 // 1. Send valid kind 30617 repo announcement
399 // 2. Send kind 30618 with refs (establish state)
400 // 3. Send kind 30618 with ONLY d tag (no refs)
401 // 4. Verify acceptance (allows author to stop tracking)
402 // 5. Query to confirm latest state has no refs
403
404 Err("Not implemented yet".to_string())
405 })
406 .await
407 }
408
409 // ========================================================================= 349 // =========================================================================
410 // Related Event Acceptance Tests 350 // Related Event Acceptance Tests
411 // ========================================================================= 351 // =========================================================================