diff options
Diffstat (limited to 'grasp-audit')
| -rw-r--r-- | grasp-audit/src/bin/grasp-audit.rs | 13 | ||||
| -rw-r--r-- | grasp-audit/src/fixtures.rs | 16 | ||||
| -rw-r--r-- | grasp-audit/src/probe.rs | 190 | ||||
| -rw-r--r-- | grasp-audit/src/specs/grasp01/purgatory.rs | 4 |
4 files changed, 143 insertions, 80 deletions
diff --git a/grasp-audit/src/bin/grasp-audit.rs b/grasp-audit/src/bin/grasp-audit.rs index 305e5eb..ab835e7 100644 --- a/grasp-audit/src/bin/grasp-audit.rs +++ b/grasp-audit/src/bin/grasp-audit.rs | |||
| @@ -132,7 +132,11 @@ async fn main() -> Result<()> { | |||
| 132 | println!("\n[Run {}]", run); | 132 | println!("\n[Run {}]", run); |
| 133 | } | 133 | } |
| 134 | let report = grasp_audit::probe::run_probe( | 134 | let report = grasp_audit::probe::run_probe( |
| 135 | &relay, keys.clone(), read_only, timeout, overall_secs, | 135 | &relay, |
| 136 | keys.clone(), | ||
| 137 | read_only, | ||
| 138 | timeout, | ||
| 139 | overall_secs, | ||
| 136 | ) | 140 | ) |
| 137 | .await; | 141 | .await; |
| 138 | if json { | 142 | if json { |
| @@ -144,10 +148,9 @@ async fn main() -> Result<()> { | |||
| 144 | tokio::time::sleep(Duration::from_secs(interval)).await; | 148 | tokio::time::sleep(Duration::from_secs(interval)).await; |
| 145 | } | 149 | } |
| 146 | } else { | 150 | } else { |
| 147 | let report = grasp_audit::probe::run_probe( | 151 | let report = |
| 148 | &relay, keys, read_only, timeout, overall_secs, | 152 | grasp_audit::probe::run_probe(&relay, keys, read_only, timeout, overall_secs) |
| 149 | ) | 153 | .await; |
| 150 | .await; | ||
| 151 | if json { | 154 | if json { |
| 152 | report.print_json(); | 155 | report.print_json(); |
| 153 | } else { | 156 | } else { |
diff --git a/grasp-audit/src/fixtures.rs b/grasp-audit/src/fixtures.rs index 4678790..d09c36b 100644 --- a/grasp-audit/src/fixtures.rs +++ b/grasp-audit/src/fixtures.rs | |||
| @@ -967,7 +967,9 @@ impl<'a> TestContext<'a> { | |||
| 967 | FixtureKind::PREvent2Served => self.build_pr_event_2_served().await, | 967 | FixtureKind::PREvent2Served => self.build_pr_event_2_served().await, |
| 968 | 968 | ||
| 969 | FixtureKind::PurgatoryValidRepoSent => self.build_purgatory_valid_repo_sent().await, | 969 | FixtureKind::PurgatoryValidRepoSent => self.build_purgatory_valid_repo_sent().await, |
| 970 | FixtureKind::PurgatoryOwnerStateDataPushed => self.build_purgatory_owner_state_data_pushed().await, | 970 | FixtureKind::PurgatoryOwnerStateDataPushed => { |
| 971 | self.build_purgatory_owner_state_data_pushed().await | ||
| 972 | } | ||
| 971 | 973 | ||
| 972 | FixtureKind::OwnerStateDataPushed => self.build_owner_state_data_pushed().await, | 974 | FixtureKind::OwnerStateDataPushed => self.build_owner_state_data_pushed().await, |
| 973 | 975 | ||
| @@ -1147,7 +1149,10 @@ impl<'a> TestContext<'a> { | |||
| 1147 | Ok(h) => h, | 1149 | Ok(h) => h, |
| 1148 | Err(e) => { | 1150 | Err(e) => { |
| 1149 | cleanup(&clone_path); | 1151 | cleanup(&clone_path); |
| 1150 | return Err(anyhow::anyhow!("Failed to create deterministic commit: {}", e)); | 1152 | return Err(anyhow::anyhow!( |
| 1153 | "Failed to create deterministic commit: {}", | ||
| 1154 | e | ||
| 1155 | )); | ||
| 1151 | } | 1156 | } |
| 1152 | }; | 1157 | }; |
| 1153 | 1158 | ||
| @@ -1186,7 +1191,12 @@ impl<'a> TestContext<'a> { | |||
| 1186 | DETERMINISTIC_COMMIT_HASH | 1191 | DETERMINISTIC_COMMIT_HASH |
| 1187 | )); | 1192 | )); |
| 1188 | } | 1193 | } |
| 1189 | Err(e) => return Err(anyhow::anyhow!("PurgatoryOwnerStateDataPushed push error: {}", e)), | 1194 | Err(e) => { |
| 1195 | return Err(anyhow::anyhow!( | ||
| 1196 | "PurgatoryOwnerStateDataPushed push error: {}", | ||
| 1197 | e | ||
| 1198 | )) | ||
| 1199 | } | ||
| 1190 | } | 1200 | } |
| 1191 | 1201 | ||
| 1192 | // ============================================================ | 1202 | // ============================================================ |
diff --git a/grasp-audit/src/probe.rs b/grasp-audit/src/probe.rs index ecbbcc9..8dad1d4 100644 --- a/grasp-audit/src/probe.rs +++ b/grasp-audit/src/probe.rs | |||
| @@ -167,10 +167,7 @@ fn now_iso8601() -> String { | |||
| 167 | let mo = if mp < 10 { mp + 3 } else { mp - 9 }; // month [1, 12] | 167 | let mo = if mp < 10 { mp + 3 } else { mp - 9 }; // month [1, 12] |
| 168 | let yr = if mo <= 2 { y + 1 } else { y }; | 168 | let yr = if mo <= 2 { y + 1 } else { y }; |
| 169 | 169 | ||
| 170 | format!( | 170 | format!("{:04}-{:02}-{:02}T{:02}:{:02}:{:02}Z", yr, mo, d, h, m, s) |
| 171 | "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}Z", | ||
| 172 | yr, mo, d, h, m, s | ||
| 173 | ) | ||
| 174 | } | 171 | } |
| 175 | 172 | ||
| 176 | // ============================================================ | 173 | // ============================================================ |
| @@ -246,8 +243,7 @@ pub async fn run_probe( | |||
| 246 | error: Some(error_msg), | 243 | error: Some(error_msg), |
| 247 | }); | 244 | }); |
| 248 | // Skip all subsequent checks | 245 | // Skip all subsequent checks |
| 249 | let already: std::collections::HashSet<&str> = | 246 | let already: std::collections::HashSet<&str> = $checks.iter().map(|c| c.name).collect(); |
| 250 | $checks.iter().map(|c| c.name).collect(); | ||
| 251 | for name in ALL_CHECK_NAMES { | 247 | for name in ALL_CHECK_NAMES { |
| 252 | if !already.contains(name) { | 248 | if !already.contains(name) { |
| 253 | $checks.push(skipped(name, "overall timeout")); | 249 | $checks.push(skipped(name, "overall timeout")); |
| @@ -303,8 +299,8 @@ pub async fn run_probe( | |||
| 303 | let clone_url = format!("{}/{}/{}.git", http_base, npub, repo_id); | 299 | let clone_url = format!("{}/{}/{}.git", http_base, npub, repo_id); |
| 304 | 300 | ||
| 305 | // Create temp dir for local repo | 301 | // Create temp dir for local repo |
| 306 | let local_repo_path = std::env::temp_dir() | 302 | let local_repo_path = |
| 307 | .join(format!("grasp-probe-{}", uuid::Uuid::new_v4())); | 303 | std::env::temp_dir().join(format!("grasp-probe-{}", uuid::Uuid::new_v4())); |
| 308 | 304 | ||
| 309 | // Initialise local repo (offline) | 305 | // Initialise local repo (offline) |
| 310 | let init_result = init_local_repo(&local_repo_path, &clone_url); | 306 | let init_result = init_local_repo(&local_repo_path, &clone_url); |
| @@ -368,7 +364,14 @@ pub async fn run_probe( | |||
| 368 | // Step 1: connect_websocket | 364 | // Step 1: connect_websocket |
| 369 | // ============================================================ | 365 | // ============================================================ |
| 370 | if Instant::now() >= deadline { | 366 | if Instant::now() >= deadline { |
| 371 | deadline_return!(relay_url, timestamp, total_start, overall_secs, checks, "connect_websocket"); | 367 | deadline_return!( |
| 368 | relay_url, | ||
| 369 | timestamp, | ||
| 370 | total_start, | ||
| 371 | overall_secs, | ||
| 372 | checks, | ||
| 373 | "connect_websocket" | ||
| 374 | ); | ||
| 372 | } | 375 | } |
| 373 | let step1_start = Instant::now(); | 376 | let step1_start = Instant::now(); |
| 374 | let client_result = tokio::time::timeout( | 377 | let client_result = tokio::time::timeout( |
| @@ -426,12 +429,21 @@ pub async fn run_probe( | |||
| 426 | // ============================================================ | 429 | // ============================================================ |
| 427 | { | 430 | { |
| 428 | if Instant::now() >= deadline { | 431 | if Instant::now() >= deadline { |
| 429 | deadline_return!(relay_url, timestamp, total_start, overall_secs, checks, "nip11_fetch"); | 432 | deadline_return!( |
| 433 | relay_url, | ||
| 434 | timestamp, | ||
| 435 | total_start, | ||
| 436 | overall_secs, | ||
| 437 | checks, | ||
| 438 | "nip11_fetch" | ||
| 439 | ); | ||
| 430 | } | 440 | } |
| 431 | let step2_start = Instant::now(); | 441 | let step2_start = Instant::now(); |
| 432 | let http_client = reqwest::Client::new(); | 442 | let http_client = reqwest::Client::new(); |
| 433 | let nip11_result = tokio::time::timeout( | 443 | let nip11_result = tokio::time::timeout( |
| 434 | deadline.saturating_duration_since(Instant::now()).min(Duration::from_secs(timeout_secs)), | 444 | deadline |
| 445 | .saturating_duration_since(Instant::now()) | ||
| 446 | .min(Duration::from_secs(timeout_secs)), | ||
| 435 | http_client | 447 | http_client |
| 436 | .get(&http_base) | 448 | .get(&http_base) |
| 437 | .header("Accept", "application/nostr+json") | 449 | .header("Accept", "application/nostr+json") |
| @@ -443,24 +455,20 @@ pub async fn run_probe( | |||
| 443 | 455 | ||
| 444 | match nip11_result { | 456 | match nip11_result { |
| 445 | Ok(Ok(resp)) if resp.status().is_success() => { | 457 | Ok(Ok(resp)) if resp.status().is_success() => { |
| 446 | let detail = resp | 458 | let detail = resp.json::<serde_json::Value>().await.ok().map(|v| { |
| 447 | .json::<serde_json::Value>() | 459 | let name = v.get("name").and_then(|n| n.as_str()).unwrap_or("unknown"); |
| 448 | .await | 460 | // software is typically a repo URL; take the last path segment |
| 449 | .ok() | 461 | let software = v |
| 450 | .map(|v| { | 462 | .get("software") |
| 451 | let name = v.get("name").and_then(|n| n.as_str()).unwrap_or("unknown"); | 463 | .and_then(|s| s.as_str()) |
| 452 | // software is typically a repo URL; take the last path segment | 464 | .map(|s| s.trim_end_matches('/').rsplit('/').next().unwrap_or(s)) |
| 453 | let software = v | 465 | .unwrap_or("unknown"); |
| 454 | .get("software") | 466 | let version = v |
| 455 | .and_then(|s| s.as_str()) | 467 | .get("version") |
| 456 | .map(|s| s.trim_end_matches('/').rsplit('/').next().unwrap_or(s)) | 468 | .and_then(|ver| ver.as_str()) |
| 457 | .unwrap_or("unknown"); | 469 | .unwrap_or("unknown"); |
| 458 | let version = v | 470 | format!("{} ({} v{})", name, software, version) |
| 459 | .get("version") | 471 | }); |
| 460 | .and_then(|ver| ver.as_str()) | ||
| 461 | .unwrap_or("unknown"); | ||
| 462 | format!("{} ({} v{})", name, software, version) | ||
| 463 | }); | ||
| 464 | checks.push(ProbeCheck { | 472 | checks.push(ProbeCheck { |
| 465 | name: "nip11_fetch", | 473 | name: "nip11_fetch", |
| 466 | passed: true, | 474 | passed: true, |
| @@ -509,7 +517,14 @@ pub async fn run_probe( | |||
| 509 | let mut write_succeeded = false; | 517 | let mut write_succeeded = false; |
| 510 | 518 | ||
| 511 | if Instant::now() >= deadline { | 519 | if Instant::now() >= deadline { |
| 512 | deadline_return!(relay_url, timestamp, total_start, overall_secs, checks, "publish_events"); | 520 | deadline_return!( |
| 521 | relay_url, | ||
| 522 | timestamp, | ||
| 523 | total_start, | ||
| 524 | overall_secs, | ||
| 525 | checks, | ||
| 526 | "publish_events" | ||
| 527 | ); | ||
| 513 | } | 528 | } |
| 514 | 529 | ||
| 515 | if read_only { | 530 | if read_only { |
| @@ -558,10 +573,7 @@ pub async fn run_probe( | |||
| 558 | error: Some(e.to_string()), | 573 | error: Some(e.to_string()), |
| 559 | }); | 574 | }); |
| 560 | // Skip steps 4 and 5; step 6 will use fallback | 575 | // Skip steps 4 and 5; step 6 will use fallback |
| 561 | checks.push(skipped( | 576 | checks.push(skipped("git_repo_initialised", "publish_events failed")); |
| 562 | "git_repo_initialised", | ||
| 563 | "publish_events failed", | ||
| 564 | )); | ||
| 565 | checks.push(skipped("git_push", "publish_events failed")); | 577 | checks.push(skipped("git_push", "publish_events failed")); |
| 566 | } | 578 | } |
| 567 | } | 579 | } |
| @@ -571,7 +583,14 @@ pub async fn run_probe( | |||
| 571 | // ============================================================ | 583 | // ============================================================ |
| 572 | if write_succeeded { | 584 | if write_succeeded { |
| 573 | if Instant::now() >= deadline { | 585 | if Instant::now() >= deadline { |
| 574 | deadline_return!(relay_url, timestamp, total_start, overall_secs, checks, "git_repo_initialised"); | 586 | deadline_return!( |
| 587 | relay_url, | ||
| 588 | timestamp, | ||
| 589 | total_start, | ||
| 590 | overall_secs, | ||
| 591 | checks, | ||
| 592 | "git_repo_initialised" | ||
| 593 | ); | ||
| 575 | } | 594 | } |
| 576 | let step4_start = Instant::now(); | 595 | let step4_start = Instant::now(); |
| 577 | let poll_url = format!("{}/info/refs?service=git-upload-pack", clone_url); | 596 | let poll_url = format!("{}/info/refs?service=git-upload-pack", clone_url); |
| @@ -624,7 +643,14 @@ pub async fn run_probe( | |||
| 624 | // ============================================================ | 643 | // ============================================================ |
| 625 | if write_succeeded { | 644 | if write_succeeded { |
| 626 | if Instant::now() >= deadline { | 645 | if Instant::now() >= deadline { |
| 627 | deadline_return!(relay_url, timestamp, total_start, overall_secs, checks, "git_push"); | 646 | deadline_return!( |
| 647 | relay_url, | ||
| 648 | timestamp, | ||
| 649 | total_start, | ||
| 650 | overall_secs, | ||
| 651 | checks, | ||
| 652 | "git_push" | ||
| 653 | ); | ||
| 628 | } | 654 | } |
| 629 | let step5_start = Instant::now(); | 655 | let step5_start = Instant::now(); |
| 630 | let push_result = try_push(&local_repo_path); | 656 | let push_result = try_push(&local_repo_path); |
| @@ -690,8 +716,14 @@ pub async fn run_probe( | |||
| 690 | continue; | 716 | continue; |
| 691 | } | 717 | } |
| 692 | let mut parts = content.splitn(2, ' '); | 718 | let mut parts = content.splitn(2, ' '); |
| 693 | let hash = match parts.next() { Some(h) if h.len() == 40 => h, _ => continue }; | 719 | let hash = match parts.next() { |
| 694 | let refname = match parts.next() { Some(r) => r.trim(), None => continue }; | 720 | Some(h) if h.len() == 40 => h, |
| 721 | _ => continue, | ||
| 722 | }; | ||
| 723 | let refname = match parts.next() { | ||
| 724 | Some(r) => r.trim(), | ||
| 725 | None => continue, | ||
| 726 | }; | ||
| 695 | // Skip refs/nostr/* — only branches (refs/heads/*) and tags (refs/tags/*) | 727 | // Skip refs/nostr/* — only branches (refs/heads/*) and tags (refs/tags/*) |
| 696 | if refname.starts_with("refs/nostr/") { | 728 | if refname.starts_with("refs/nostr/") { |
| 697 | continue; | 729 | continue; |
| @@ -705,14 +737,23 @@ pub async fn run_probe( | |||
| 705 | // ---- Write path ---- | 737 | // ---- Write path ---- |
| 706 | // Step 6a: git_fetch_refs — just verify the endpoint returns 200 | 738 | // Step 6a: git_fetch_refs — just verify the endpoint returns 200 |
| 707 | if Instant::now() >= deadline { | 739 | if Instant::now() >= deadline { |
| 708 | deadline_return!(relay_url, timestamp, total_start, overall_secs, checks, "git_fetch_refs"); | 740 | deadline_return!( |
| 741 | relay_url, | ||
| 742 | timestamp, | ||
| 743 | total_start, | ||
| 744 | overall_secs, | ||
| 745 | checks, | ||
| 746 | "git_fetch_refs" | ||
| 747 | ); | ||
| 709 | } | 748 | } |
| 710 | let refs_url = format!("{}/info/refs?service=git-upload-pack", clone_url); | 749 | let refs_url = format!("{}/info/refs?service=git-upload-pack", clone_url); |
| 711 | let http_client = reqwest::Client::new(); | 750 | let http_client = reqwest::Client::new(); |
| 712 | 751 | ||
| 713 | let step6_start = Instant::now(); | 752 | let step6_start = Instant::now(); |
| 714 | let refs_result = tokio::time::timeout( | 753 | let refs_result = tokio::time::timeout( |
| 715 | deadline.saturating_duration_since(Instant::now()).min(Duration::from_secs(timeout_secs)), | 754 | deadline |
| 755 | .saturating_duration_since(Instant::now()) | ||
| 756 | .min(Duration::from_secs(timeout_secs)), | ||
| 716 | http_client.get(&refs_url).send(), | 757 | http_client.get(&refs_url).send(), |
| 717 | ) | 758 | ) |
| 718 | .await; | 759 | .await; |
| @@ -833,14 +874,23 @@ pub async fn run_probe( | |||
| 833 | 874 | ||
| 834 | // In read-only mode: first check that at least one announcement exists | 875 | // In read-only mode: first check that at least one announcement exists |
| 835 | if Instant::now() >= deadline { | 876 | if Instant::now() >= deadline { |
| 836 | deadline_return!(relay_url, timestamp, total_start, overall_secs, checks, "serves_latest_announcement"); | 877 | deadline_return!( |
| 878 | relay_url, | ||
| 879 | timestamp, | ||
| 880 | total_start, | ||
| 881 | overall_secs, | ||
| 882 | checks, | ||
| 883 | "serves_latest_announcement" | ||
| 884 | ); | ||
| 837 | } | 885 | } |
| 838 | let filter = Filter::new().kind(Kind::GitRepoAnnouncement).limit(1); | 886 | let filter = Filter::new().kind(Kind::GitRepoAnnouncement).limit(1); |
| 839 | let existing = client | 887 | let existing = client |
| 840 | .client() | 888 | .client() |
| 841 | .fetch_events( | 889 | .fetch_events( |
| 842 | filter, | 890 | filter, |
| 843 | deadline.saturating_duration_since(Instant::now()).min(Duration::from_secs(5)), | 891 | deadline |
| 892 | .saturating_duration_since(Instant::now()) | ||
| 893 | .min(Duration::from_secs(5)), | ||
| 844 | ) | 894 | ) |
| 845 | .await | 895 | .await |
| 846 | .unwrap_or_default(); | 896 | .unwrap_or_default(); |
| @@ -909,18 +959,25 @@ pub async fn run_probe( | |||
| 909 | .find(|t| t.kind() == TagKind::custom("clone")) | 959 | .find(|t| t.kind() == TagKind::custom("clone")) |
| 910 | .and_then(|t| t.content()) | 960 | .and_then(|t| t.content()) |
| 911 | .map(|s| s.to_string()) | 961 | .map(|s| s.to_string()) |
| 912 | .unwrap_or_else(|| { | 962 | .unwrap_or_else(|| format!("{}/{}/{}.git", http_base, ann_npub, ann_id)); |
| 913 | format!("{}/{}/{}.git", http_base, ann_npub, ann_id) | ||
| 914 | }); | ||
| 915 | 963 | ||
| 916 | if Instant::now() >= deadline { | 964 | if Instant::now() >= deadline { |
| 917 | deadline_return!(relay_url, timestamp, total_start, overall_secs, checks, "git_fetch_refs"); | 965 | deadline_return!( |
| 966 | relay_url, | ||
| 967 | timestamp, | ||
| 968 | total_start, | ||
| 969 | overall_secs, | ||
| 970 | checks, | ||
| 971 | "git_fetch_refs" | ||
| 972 | ); | ||
| 918 | } | 973 | } |
| 919 | let step6_start = Instant::now(); | 974 | let step6_start = Instant::now(); |
| 920 | let refs_url = format!("{}/info/refs?service=git-upload-pack", fetch_url); | 975 | let refs_url = format!("{}/info/refs?service=git-upload-pack", fetch_url); |
| 921 | let http_client = reqwest::Client::new(); | 976 | let http_client = reqwest::Client::new(); |
| 922 | let refs_result = tokio::time::timeout( | 977 | let refs_result = tokio::time::timeout( |
| 923 | deadline.saturating_duration_since(Instant::now()).min(Duration::from_secs(timeout_secs)), | 978 | deadline |
| 979 | .saturating_duration_since(Instant::now()) | ||
| 980 | .min(Duration::from_secs(timeout_secs)), | ||
| 924 | http_client.get(&refs_url).send(), | 981 | http_client.get(&refs_url).send(), |
| 925 | ) | 982 | ) |
| 926 | .await; | 983 | .await; |
| @@ -935,7 +992,7 @@ pub async fn run_probe( | |||
| 935 | passed: true, | 992 | passed: true, |
| 936 | skipped: false, | 993 | skipped: false, |
| 937 | duration_ms: step6_ms, | 994 | duration_ms: step6_ms, |
| 938 | detail: None, | 995 | detail: None, |
| 939 | error: None, | 996 | error: None, |
| 940 | }); | 997 | }); |
| 941 | Some(body) | 998 | Some(body) |
| @@ -946,7 +1003,7 @@ pub async fn run_probe( | |||
| 946 | passed: false, | 1003 | passed: false, |
| 947 | skipped: false, | 1004 | skipped: false, |
| 948 | duration_ms: step6_ms, | 1005 | duration_ms: step6_ms, |
| 949 | detail: None, | 1006 | detail: None, |
| 950 | error: Some(format!("HTTP {}", resp.status())), | 1007 | error: Some(format!("HTTP {}", resp.status())), |
| 951 | }); | 1008 | }); |
| 952 | None | 1009 | None |
| @@ -957,7 +1014,7 @@ pub async fn run_probe( | |||
| 957 | passed: false, | 1014 | passed: false, |
| 958 | skipped: false, | 1015 | skipped: false, |
| 959 | duration_ms: step6_ms, | 1016 | duration_ms: step6_ms, |
| 960 | detail: None, | 1017 | detail: None, |
| 961 | error: Some(e.to_string()), | 1018 | error: Some(e.to_string()), |
| 962 | }); | 1019 | }); |
| 963 | None | 1020 | None |
| @@ -968,7 +1025,7 @@ pub async fn run_probe( | |||
| 968 | passed: false, | 1025 | passed: false, |
| 969 | skipped: false, | 1026 | skipped: false, |
| 970 | duration_ms: step6_ms, | 1027 | duration_ms: step6_ms, |
| 971 | detail: None, | 1028 | detail: None, |
| 972 | error: Some("timeout".to_string()), | 1029 | error: Some("timeout".to_string()), |
| 973 | }); | 1030 | }); |
| 974 | None | 1031 | None |
| @@ -981,10 +1038,7 @@ pub async fn run_probe( | |||
| 981 | // including recursive maintainer chains), then compare against git refs. | 1038 | // including recursive maintainer chains), then compare against git refs. |
| 982 | match refs_body_fallback { | 1039 | match refs_body_fallback { |
| 983 | None => { | 1040 | None => { |
| 984 | checks.push(skipped( | 1041 | checks.push(skipped("git_refs_match_state", "git_fetch_refs failed")); |
| 985 | "git_refs_match_state", | ||
| 986 | "git_fetch_refs failed", | ||
| 987 | )); | ||
| 988 | } | 1042 | } |
| 989 | Some(body) => { | 1043 | Some(body) => { |
| 990 | let fetched_refs = parse_refs(&body); | 1044 | let fetched_refs = parse_refs(&body); |
| @@ -992,19 +1046,19 @@ pub async fn run_probe( | |||
| 992 | // Fetch all state events for this repo_id from the relay. | 1046 | // Fetch all state events for this repo_id from the relay. |
| 993 | // The relay only serves authorized state events (owner + full | 1047 | // The relay only serves authorized state events (owner + full |
| 994 | // recursive maintainer chain already resolved by the relay). | 1048 | // recursive maintainer chain already resolved by the relay). |
| 995 | let state_filter = Filter::new() | 1049 | let state_filter = Filter::new().kind(Kind::RepoState).custom_tag( |
| 996 | .kind(Kind::RepoState) | 1050 | nostr_sdk::prelude::SingleLetterTag::lowercase( |
| 997 | .custom_tag( | 1051 | nostr_sdk::prelude::Alphabet::D, |
| 998 | nostr_sdk::prelude::SingleLetterTag::lowercase( | 1052 | ), |
| 999 | nostr_sdk::prelude::Alphabet::D, | 1053 | ann_id.clone(), |
| 1000 | ), | 1054 | ); |
| 1001 | ann_id.clone(), | ||
| 1002 | ); | ||
| 1003 | let state_events = client | 1055 | let state_events = client |
| 1004 | .client() | 1056 | .client() |
| 1005 | .fetch_events( | 1057 | .fetch_events( |
| 1006 | state_filter, | 1058 | state_filter, |
| 1007 | deadline.saturating_duration_since(Instant::now()).min(Duration::from_secs(5)), | 1059 | deadline |
| 1060 | .saturating_duration_since(Instant::now()) | ||
| 1061 | .min(Duration::from_secs(5)), | ||
| 1008 | ) | 1062 | ) |
| 1009 | .await | 1063 | .await |
| 1010 | .unwrap_or_default(); | 1064 | .unwrap_or_default(); |
| @@ -1046,7 +1100,8 @@ pub async fn run_probe( | |||
| 1046 | Some(h) => h.to_string(), | 1100 | Some(h) => h.to_string(), |
| 1047 | None => continue, | 1101 | None => continue, |
| 1048 | }; | 1102 | }; |
| 1049 | let prev_ts = latest_ts.get(kind_str.as_ref()).copied().unwrap_or(0); | 1103 | let prev_ts = |
| 1104 | latest_ts.get(kind_str.as_ref()).copied().unwrap_or(0); | ||
| 1050 | if ts >= prev_ts { | 1105 | if ts >= prev_ts { |
| 1051 | expected.insert(kind_str.to_string(), hash); | 1106 | expected.insert(kind_str.to_string(), hash); |
| 1052 | latest_ts.insert(kind_str.to_string(), ts); | 1107 | latest_ts.insert(kind_str.to_string(), ts); |
| @@ -1103,10 +1158,7 @@ pub async fn run_probe( | |||
| 1103 | detail: None, | 1158 | detail: None, |
| 1104 | error: Some("no repositories found on relay".to_string()), | 1159 | error: Some("no repositories found on relay".to_string()), |
| 1105 | }); | 1160 | }); |
| 1106 | checks.push(skipped( | 1161 | checks.push(skipped("git_refs_match_state", "no announcement found")); |
| 1107 | "git_refs_match_state", | ||
| 1108 | "no announcement found", | ||
| 1109 | )); | ||
| 1110 | } | 1162 | } |
| 1111 | } | 1163 | } |
| 1112 | } | 1164 | } |
diff --git a/grasp-audit/src/specs/grasp01/purgatory.rs b/grasp-audit/src/specs/grasp01/purgatory.rs index 0686da8..fdc1e32 100644 --- a/grasp-audit/src/specs/grasp01/purgatory.rs +++ b/grasp-audit/src/specs/grasp01/purgatory.rs | |||
| @@ -54,9 +54,7 @@ impl PurgatoryTests { | |||
| 54 | 54 | ||
| 55 | // Deletion event tests (NIP-09) | 55 | // Deletion event tests (NIP-09) |
| 56 | results.add(Self::test_deletion_by_event_id_removes_purgatory_state_event(client).await); | 56 | results.add(Self::test_deletion_by_event_id_removes_purgatory_state_event(client).await); |
| 57 | results.add( | 57 | results.add(Self::test_deletion_by_coordinate_removes_purgatory_state_event(client).await); |
| 58 | Self::test_deletion_by_coordinate_removes_purgatory_state_event(client).await, | ||
| 59 | ); | ||
| 60 | 58 | ||
| 61 | // PR purgatory tests | 59 | // PR purgatory tests |
| 62 | results.add(Self::test_pr_event_accepted_into_purgatory_and_isnt_served(client).await); | 60 | results.add(Self::test_pr_event_accepted_into_purgatory_and_isnt_served(client).await); |