diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2025-12-01 22:13:37 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2025-12-01 22:13:37 +0000 |
| commit | 11870a0f810accf0431d82a74b6fd3adec9d23df (patch) | |
| tree | 82a61995b1a18b4a618544b159e886d5c2e95015 /grasp-audit/src/specs | |
| parent | 883774c7785c57bded21ba3be63d0fdac8a51dcf (diff) | |
better fixtures: refs/nostr tests
Diffstat (limited to 'grasp-audit/src/specs')
| -rw-r--r-- | grasp-audit/src/specs/grasp01/push_authorization.rs | 331 |
1 files changed, 148 insertions, 183 deletions
diff --git a/grasp-audit/src/specs/grasp01/push_authorization.rs b/grasp-audit/src/specs/grasp01/push_authorization.rs index 36abd30..0119ab3 100644 --- a/grasp-audit/src/specs/grasp01/push_authorization.rs +++ b/grasp-audit/src/specs/grasp01/push_authorization.rs | |||
| @@ -32,9 +32,8 @@ | |||
| 32 | const PR_TEST_COMMIT_HASH: &str = "5d40fb1555a0c28bf4d650515a73aaa54d4d9bfb"; | 32 | const PR_TEST_COMMIT_HASH: &str = "5d40fb1555a0c28bf4d650515a73aaa54d4d9bfb"; |
| 33 | 33 | ||
| 34 | use crate::{ | 34 | use crate::{ |
| 35 | clone_repo, create_commit, create_deterministic_commit, | 35 | clone_repo, create_commit, create_deterministic_commit_with_variant, try_push, try_push_to_ref, |
| 36 | create_deterministic_commit_with_variant, try_push, try_push_to_ref, AuditClient, | 36 | AuditClient, CommitVariant, FixtureKind, TestContext, TestResult, |
| 37 | CommitVariant, FixtureKind, TestContext, TestResult, DETERMINISTIC_COMMIT_HASH, | ||
| 38 | MAINTAINER_DETERMINISTIC_COMMIT_HASH, | 37 | MAINTAINER_DETERMINISTIC_COMMIT_HASH, |
| 39 | }; | 38 | }; |
| 40 | use nostr_sdk::prelude::*; | 39 | use nostr_sdk::prelude::*; |
| @@ -238,132 +237,9 @@ async fn setup_pr_test_repo( | |||
| 238 | } | 237 | } |
| 239 | 238 | ||
| 240 | // ============================================================ | 239 | // ============================================================ |
| 241 | // PR Ref Push Test Setup Helpers - Minimize Test Duplication | 240 | // PR Ref Push Test Helpers |
| 242 | // ============================================================ | 241 | // ============================================================ |
| 243 | 242 | ||
| 244 | /// Result of setting up a repo with a wrong commit pushed before PR event exists. | ||
| 245 | /// Used as shared setup for tests 3, 4, 5 which all depend on this scenario. | ||
| 246 | #[allow(dead_code)] | ||
| 247 | struct PrRefTestSetup { | ||
| 248 | clone_path: PathBuf, | ||
| 249 | pr_event_id: String, | ||
| 250 | repo_id: String, | ||
| 251 | owner_npub: String, | ||
| 252 | wrong_commit_hash: String, | ||
| 253 | /// The unpublished PR event - store it so we can publish the SAME event later | ||
| 254 | pr_event: Event, | ||
| 255 | } | ||
| 256 | |||
| 257 | impl PrRefTestSetup { | ||
| 258 | fn cleanup(&self) { | ||
| 259 | let _ = std::fs::remove_dir_all(&self.clone_path); | ||
| 260 | } | ||
| 261 | } | ||
| 262 | |||
| 263 | /// Sets up a repo and pushes a WRONG commit to refs/nostr/<pr-event-id> BEFORE PR event exists. | ||
| 264 | /// | ||
| 265 | /// This is the shared setup for PR ref lifecycle tests: | ||
| 266 | /// - Creates repo (gets PREvent fixture for event-id but doesn't publish yet) | ||
| 267 | /// - Clones repo | ||
| 268 | /// - Creates a commit that does NOT match PR_TEST_COMMIT_HASH | ||
| 269 | /// - Pushes to refs/nostr/<pr-event-id> (should succeed - no event to validate against) | ||
| 270 | /// | ||
| 271 | /// Tests using this setup: | ||
| 272 | /// - test_pr_push_to_nostr_ref_with_wrong_commit_accepted_before_event_received: verify initial push accepted | ||
| 273 | /// - test_pr_event_published_removes_nostr_ref_at_incorrect_commit: publish event, verify cleanup | ||
| 274 | /// - test_push_to_nostr_ref_with_wrong_commit_after_event_received_rejected: publish event, try push wrong commit | ||
| 275 | /// - test_push_to_nostr_ref_with_correct_commit_after_event_received_accepted: publish event, push correct commit | ||
| 276 | #[allow(dead_code)] | ||
| 277 | async fn setup_repo_with_wrong_commit_pushed( | ||
| 278 | ctx: &TestContext<'_>, | ||
| 279 | relay_domain: &str, | ||
| 280 | ) -> Result<PrRefTestSetup, String> { | ||
| 281 | // Get ValidRepo fixture (publishes repo announcement to relay) | ||
| 282 | let repo_event = ctx | ||
| 283 | .get_fixture(FixtureKind::ValidRepo) | ||
| 284 | .await | ||
| 285 | .map_err(|e| format!("Failed to get repo announcement: {}", e))?; | ||
| 286 | |||
| 287 | // Build PR event WITHOUT publishing - we need its ID before the event exists on relay | ||
| 288 | // This allows testing refs/nostr/<event-id> push behavior before the event is received | ||
| 289 | let pr_event = ctx | ||
| 290 | .build_fixture_only(FixtureKind::PREvent) | ||
| 291 | .await | ||
| 292 | .map_err(|e| format!("Failed to build PR event fixture: {}", e))?; | ||
| 293 | |||
| 294 | let repo_id = repo_event | ||
| 295 | .tags | ||
| 296 | .iter() | ||
| 297 | .find(|t| t.kind() == TagKind::d()) | ||
| 298 | .and_then(|t| t.content()) | ||
| 299 | .ok_or("No repo identifier in announcement")? | ||
| 300 | .to_string(); | ||
| 301 | |||
| 302 | let owner_npub = repo_event.pubkey.to_bech32().map_err(|e| e.to_string())?; | ||
| 303 | let pr_event_id = pr_event.id.to_hex(); | ||
| 304 | |||
| 305 | // Clone the repository | ||
| 306 | let clone_path = clone_repo(relay_domain, &owner_npub, &repo_id)?; | ||
| 307 | |||
| 308 | // Create a WRONG commit (not the one expected by PR event) | ||
| 309 | let wrong_commit_hash = | ||
| 310 | create_deterministic_commit_with_variant(&clone_path, CommitVariant::Owner)?; | ||
| 311 | |||
| 312 | // Verify it's actually different from expected | ||
| 313 | if wrong_commit_hash == PR_TEST_COMMIT_HASH { | ||
| 314 | let _ = std::fs::remove_dir_all(&clone_path); | ||
| 315 | return Err("Test setup error: wrong_commit_hash equals PR_TEST_COMMIT_HASH".to_string()); | ||
| 316 | } | ||
| 317 | |||
| 318 | // Push to refs/nostr/<pr-event-id> (no event published yet, should succeed) | ||
| 319 | let push_output = Command::new("git") | ||
| 320 | .args([ | ||
| 321 | "push", | ||
| 322 | "origin", | ||
| 323 | &format!("master:refs/nostr/{}", pr_event_id), | ||
| 324 | ]) | ||
| 325 | .current_dir(&clone_path) | ||
| 326 | .output() | ||
| 327 | .map_err(|e| format!("Failed to execute git push: {}", e))?; | ||
| 328 | |||
| 329 | if !push_output.status.success() { | ||
| 330 | let stderr = String::from_utf8_lossy(&push_output.stderr); | ||
| 331 | let _ = std::fs::remove_dir_all(&clone_path); | ||
| 332 | return Err(format!( | ||
| 333 | "Initial push failed (expected success before PR event): {}", | ||
| 334 | stderr | ||
| 335 | )); | ||
| 336 | } | ||
| 337 | |||
| 338 | Ok(PrRefTestSetup { | ||
| 339 | clone_path, | ||
| 340 | pr_event_id, | ||
| 341 | repo_id, | ||
| 342 | owner_npub, | ||
| 343 | wrong_commit_hash, | ||
| 344 | pr_event, | ||
| 345 | }) | ||
| 346 | } | ||
| 347 | |||
| 348 | /// Publishes the SAME PR event that was built during setup. | ||
| 349 | /// Call this after setup_repo_with_wrong_commit_pushed to test post-event behavior. | ||
| 350 | /// | ||
| 351 | /// IMPORTANT: We must publish the EXACT same event that was used during setup, | ||
| 352 | /// otherwise the event ID won't match the refs/nostr/<event-id> ref that was pushed. | ||
| 353 | #[allow(dead_code)] | ||
| 354 | async fn publish_pr_event_and_wait(ctx: &TestContext<'_>, pr_event: &Event) -> Result<(), String> { | ||
| 355 | // Publish the exact same PR event that was created during setup | ||
| 356 | ctx.client() | ||
| 357 | .send_event(pr_event.clone()) | ||
| 358 | .await | ||
| 359 | .map_err(|e| format!("Failed to publish PR event: {}", e))?; | ||
| 360 | |||
| 361 | // Wait for relay to process | ||
| 362 | tokio::time::sleep(tokio::time::Duration::from_millis(500)).await; | ||
| 363 | |||
| 364 | Ok(()) | ||
| 365 | } | ||
| 366 | |||
| 367 | /// Creates the correct PR test commit (matching PR_TEST_COMMIT_HASH) in an existing clone. | 243 | /// Creates the correct PR test commit (matching PR_TEST_COMMIT_HASH) in an existing clone. |
| 368 | /// Used after wrong commit was pushed to test pushing the correct commit. | 244 | /// Used after wrong commit was pushed to test pushing the correct commit. |
| 369 | #[allow(dead_code)] | 245 | #[allow(dead_code)] |
| @@ -1139,7 +1015,9 @@ impl PushAuthorizationTests { | |||
| 1139 | /// when no corresponding event exists yet. This is expected behavior because | 1015 | /// when no corresponding event exists yet. This is expected behavior because |
| 1140 | /// there's no validation event to check against. | 1016 | /// there's no validation event to check against. |
| 1141 | /// | 1017 | /// |
| 1142 | /// Uses `setup_repo_with_wrong_commit_pushed` helper which handles all setup. | 1018 | /// Uses `PRWrongCommitPushedBeforeEvent` fixture which handles all setup |
| 1019 | /// and verifies the push succeeded. | ||
| 1020 | #[allow(unused_variables)] // relay_domain is now handled by fixture | ||
| 1143 | pub async fn test_pr_push_to_nostr_ref_with_wrong_commit_accepted_before_event_received( | 1021 | pub async fn test_pr_push_to_nostr_ref_with_wrong_commit_accepted_before_event_received( |
| 1144 | client: &AuditClient, | 1022 | client: &AuditClient, |
| 1145 | relay_domain: &str, | 1023 | relay_domain: &str, |
| @@ -1149,19 +1027,15 @@ impl PushAuthorizationTests { | |||
| 1149 | let desc = "Push wrong commit to refs/nostr/<pr-event-id> before PR event (should accept)"; | 1027 | let desc = "Push wrong commit to refs/nostr/<pr-event-id> before PR event (should accept)"; |
| 1150 | let ctx = TestContext::new(client); | 1028 | let ctx = TestContext::new(client); |
| 1151 | 1029 | ||
| 1152 | // Setup includes: create repo, clone, create wrong commit, push to refs/nostr/<event-id> | 1030 | // The PRWrongCommitPushedBeforeEvent fixture handles: |
| 1153 | // The push happens BEFORE PR event is published, so should succeed | 1031 | // 1. Create repo announcement |
| 1154 | let setup = match setup_repo_with_wrong_commit_pushed(&ctx, relay_domain).await { | 1032 | // 2. Build PR event (but don't send it) |
| 1155 | Ok(s) => s, | 1033 | // 3. Clone repo, create wrong commit, push to refs/nostr/<event-id> |
| 1156 | Err(e) => { | 1034 | // If the push fails, the fixture will return an error |
| 1157 | return TestResult::new(test_name, "GRASP-01", desc).fail(&e); | 1035 | match ctx.get_fixture(FixtureKind::PRWrongCommitPushedBeforeEvent).await { |
| 1158 | } | 1036 | Ok(_pr_event) => TestResult::new(test_name, "GRASP-01", desc).pass(), |
| 1159 | }; | 1037 | Err(e) => TestResult::new(test_name, "GRASP-01", desc).fail(format!("{}", e)), |
| 1160 | 1038 | } | |
| 1161 | // Setup already pushed and verified success - just cleanup and report pass | ||
| 1162 | setup.cleanup(); | ||
| 1163 | |||
| 1164 | TestResult::new(test_name, "GRASP-01", desc).pass() | ||
| 1165 | } | 1039 | } |
| 1166 | 1040 | ||
| 1167 | /// Test 2: After publishing PR event, verify that incorrect refs get cleaned up | 1041 | /// Test 2: After publishing PR event, verify that incorrect refs get cleaned up |
| @@ -1170,7 +1044,7 @@ impl PushAuthorizationTests { | |||
| 1170 | /// the relay should validate any existing refs/nostr/<event-id> refs and | 1044 | /// the relay should validate any existing refs/nostr/<event-id> refs and |
| 1171 | /// delete those that don't match the commit in the PR event's `c` tag. | 1045 | /// delete those that don't match the commit in the PR event's `c` tag. |
| 1172 | /// | 1046 | /// |
| 1173 | /// Depends on: `setup_repo_with_wrong_commit_pushed` (wrong commit already pushed) | 1047 | /// Uses `PREventSentAfterWrongPush` fixture which builds on the wrong push fixture. |
| 1174 | pub async fn test_pr_event_published_removes_nostr_ref_at_incorrect_commit( | 1048 | pub async fn test_pr_event_published_removes_nostr_ref_at_incorrect_commit( |
| 1175 | client: &AuditClient, | 1049 | client: &AuditClient, |
| 1176 | relay_domain: &str, | 1050 | relay_domain: &str, |
| @@ -1179,38 +1053,66 @@ impl PushAuthorizationTests { | |||
| 1179 | let desc = "Publishing PR event should trigger cleanup of incorrect refs"; | 1053 | let desc = "Publishing PR event should trigger cleanup of incorrect refs"; |
| 1180 | let ctx = TestContext::new(client); | 1054 | let ctx = TestContext::new(client); |
| 1181 | 1055 | ||
| 1182 | // Setup: wrong commit already pushed to refs/nostr/<pr-event-id> | 1056 | // Get fixture: wrong commit was pushed, then PR event was sent |
| 1183 | let setup = match setup_repo_with_wrong_commit_pushed(&ctx, relay_domain).await { | 1057 | let pr_event = match ctx.get_fixture(FixtureKind::PREventSentAfterWrongPush).await { |
| 1184 | Ok(s) => s, | 1058 | Ok(e) => e, |
| 1185 | Err(e) => { | 1059 | Err(e) => { |
| 1186 | return TestResult::new(test_name, "GRASP-01", desc).fail(&e); | 1060 | return TestResult::new(test_name, "GRASP-01", desc).fail(format!("{}", e)); |
| 1187 | } | 1061 | } |
| 1188 | }; | 1062 | }; |
| 1189 | 1063 | ||
| 1190 | // NOW publish the PR event - this should trigger cleanup validation | 1064 | let pr_event_id = pr_event.id.to_hex(); |
| 1191 | if let Err(e) = publish_pr_event_and_wait(&ctx, &setup.pr_event).await { | 1065 | |
| 1192 | setup.cleanup(); | 1066 | // Get repo info for cloning (fresh clone for verification) |
| 1193 | return TestResult::new(test_name, "GRASP-01", desc).fail(&e); | 1067 | let repo = match ctx.get_fixture(FixtureKind::ValidRepo).await { |
| 1194 | } | 1068 | Ok(r) => r, |
| 1069 | Err(e) => { | ||
| 1070 | return TestResult::new(test_name, "GRASP-01", desc).fail(format!("{}", e)); | ||
| 1071 | } | ||
| 1072 | }; | ||
| 1073 | |||
| 1074 | let repo_id = repo | ||
| 1075 | .tags | ||
| 1076 | .iter() | ||
| 1077 | .find(|t| t.kind() == TagKind::d()) | ||
| 1078 | .and_then(|t| t.content()) | ||
| 1079 | .unwrap_or("unknown") | ||
| 1080 | .to_string(); | ||
| 1081 | |||
| 1082 | let owner_npub = match repo.pubkey.to_bech32() { | ||
| 1083 | Ok(n) => n, | ||
| 1084 | Err(e) => { | ||
| 1085 | return TestResult::new(test_name, "GRASP-01", desc) | ||
| 1086 | .fail(format!("Failed to get owner npub: {}", e)); | ||
| 1087 | } | ||
| 1088 | }; | ||
| 1089 | |||
| 1090 | // Clone fresh for verification | ||
| 1091 | let clone_path = match clone_repo(relay_domain, &owner_npub, &repo_id) { | ||
| 1092 | Ok(p) => p, | ||
| 1093 | Err(e) => { | ||
| 1094 | return TestResult::new(test_name, "GRASP-01", desc).fail(&e); | ||
| 1095 | } | ||
| 1096 | }; | ||
| 1195 | 1097 | ||
| 1196 | // Check if the incorrect ref was deleted | 1098 | // Check if the incorrect ref was deleted |
| 1197 | let ref_name = format!("refs/nostr/{}", setup.pr_event_id); | 1099 | let ref_name = format!("refs/nostr/{}", pr_event_id); |
| 1198 | let refs_exist = match ref_exists_on_remote(&setup.clone_path, &ref_name) { | 1100 | let refs_exist = match ref_exists_on_remote(&clone_path, &ref_name) { |
| 1199 | Ok(exists) => exists, | 1101 | Ok(exists) => exists, |
| 1200 | Err(e) => { | 1102 | Err(e) => { |
| 1201 | setup.cleanup(); | 1103 | let _ = fs::remove_dir_all(&clone_path); |
| 1202 | return TestResult::new(test_name, "GRASP-01", desc).fail(&e); | 1104 | return TestResult::new(test_name, "GRASP-01", desc).fail(&e); |
| 1203 | } | 1105 | } |
| 1204 | }; | 1106 | }; |
| 1205 | 1107 | ||
| 1206 | setup.cleanup(); | 1108 | let _ = fs::remove_dir_all(&clone_path); |
| 1207 | 1109 | ||
| 1208 | // Ref should be deleted since the pushed commit doesn't match the PR event's `c` tag | 1110 | // Ref should be deleted since the pushed commit doesn't match the PR event's `c` tag |
| 1209 | if refs_exist { | 1111 | if refs_exist { |
| 1210 | TestResult::new(test_name, "GRASP-01", desc).fail(format!( | 1112 | TestResult::new(test_name, "GRASP-01", desc).fail(format!( |
| 1211 | "Expected refs/nostr/{} to be deleted when PR event published with non-matching commit, \ | 1113 | "Expected refs/nostr/{} to be deleted when PR event published with non-matching commit, \ |
| 1212 | but the ref still exists. The relay should delete refs that don't match the event's `c` tag.", | 1114 | but the ref still exists. The relay should delete refs that don't match the event's `c` tag.", |
| 1213 | setup.pr_event_id | 1115 | pr_event_id |
| 1214 | )) | 1116 | )) |
| 1215 | } else { | 1117 | } else { |
| 1216 | TestResult::new(test_name, "GRASP-01", desc).pass() | 1118 | TestResult::new(test_name, "GRASP-01", desc).pass() |
| @@ -1223,7 +1125,7 @@ impl PushAuthorizationTests { | |||
| 1223 | /// when a corresponding event exists but the pushed commit doesn't match | 1125 | /// when a corresponding event exists but the pushed commit doesn't match |
| 1224 | /// the commit in the PR event's `c` tag. | 1126 | /// the commit in the PR event's `c` tag. |
| 1225 | /// | 1127 | /// |
| 1226 | /// Depends on: `setup_repo_with_wrong_commit_pushed` for repo/clone setup, then publishes PR event | 1128 | /// Uses `PREventSentAfterWrongPush` fixture, then attempts to push wrong commit again. |
| 1227 | pub async fn test_push_to_nostr_ref_with_wrong_commit_after_event_received_rejected( | 1129 | pub async fn test_push_to_nostr_ref_with_wrong_commit_after_event_received_rejected( |
| 1228 | client: &AuditClient, | 1130 | client: &AuditClient, |
| 1229 | relay_domain: &str, | 1131 | relay_domain: &str, |
| @@ -1232,30 +1134,65 @@ impl PushAuthorizationTests { | |||
| 1232 | let desc = "Push wrong commit to refs/nostr/<pr-event-id> after PR event (should reject)"; | 1134 | let desc = "Push wrong commit to refs/nostr/<pr-event-id> after PR event (should reject)"; |
| 1233 | let ctx = TestContext::new(client); | 1135 | let ctx = TestContext::new(client); |
| 1234 | 1136 | ||
| 1235 | // Setup: wrong commit already pushed (we'll use the same setup, but publish PR first) | 1137 | // Get fixture: PR event exists on relay (wrong commit was previously pushed but may have been cleaned up) |
| 1236 | let setup = match setup_repo_with_wrong_commit_pushed(&ctx, relay_domain).await { | 1138 | let pr_event = match ctx.get_fixture(FixtureKind::PREventSentAfterWrongPush).await { |
| 1237 | Ok(s) => s, | 1139 | Ok(e) => e, |
| 1140 | Err(e) => { | ||
| 1141 | return TestResult::new(test_name, "GRASP-01", desc).fail(format!("{}", e)); | ||
| 1142 | } | ||
| 1143 | }; | ||
| 1144 | |||
| 1145 | let pr_event_id = pr_event.id.to_hex(); | ||
| 1146 | |||
| 1147 | // Get repo info for cloning (fresh clone for this test) | ||
| 1148 | let repo = match ctx.get_fixture(FixtureKind::ValidRepo).await { | ||
| 1149 | Ok(r) => r, | ||
| 1150 | Err(e) => { | ||
| 1151 | return TestResult::new(test_name, "GRASP-01", desc).fail(format!("{}", e)); | ||
| 1152 | } | ||
| 1153 | }; | ||
| 1154 | |||
| 1155 | let repo_id = repo | ||
| 1156 | .tags | ||
| 1157 | .iter() | ||
| 1158 | .find(|t| t.kind() == TagKind::d()) | ||
| 1159 | .and_then(|t| t.content()) | ||
| 1160 | .unwrap_or("unknown") | ||
| 1161 | .to_string(); | ||
| 1162 | |||
| 1163 | let owner_npub = match repo.pubkey.to_bech32() { | ||
| 1164 | Ok(n) => n, | ||
| 1165 | Err(e) => { | ||
| 1166 | return TestResult::new(test_name, "GRASP-01", desc) | ||
| 1167 | .fail(format!("Failed to get owner npub: {}", e)); | ||
| 1168 | } | ||
| 1169 | }; | ||
| 1170 | |||
| 1171 | // Clone fresh for this test | ||
| 1172 | let clone_path = match clone_repo(relay_domain, &owner_npub, &repo_id) { | ||
| 1173 | Ok(p) => p, | ||
| 1238 | Err(e) => { | 1174 | Err(e) => { |
| 1239 | return TestResult::new(test_name, "GRASP-01", desc).fail(&e); | 1175 | return TestResult::new(test_name, "GRASP-01", desc).fail(&e); |
| 1240 | } | 1176 | } |
| 1241 | }; | 1177 | }; |
| 1242 | 1178 | ||
| 1243 | // Publish PR event FIRST (before our test push) | 1179 | // Create a wrong commit (Owner variant, not PRTestCommit) |
| 1244 | if let Err(e) = publish_pr_event_and_wait(&ctx, &setup.pr_event).await { | 1180 | if let Err(e) = create_deterministic_commit_with_variant(&clone_path, CommitVariant::Owner) |
| 1245 | setup.cleanup(); | 1181 | { |
| 1182 | let _ = fs::remove_dir_all(&clone_path); | ||
| 1246 | return TestResult::new(test_name, "GRASP-01", desc).fail(&e); | 1183 | return TestResult::new(test_name, "GRASP-01", desc).fail(&e); |
| 1247 | } | 1184 | } |
| 1248 | 1185 | ||
| 1249 | // Try to push again with wrong commit (should be rejected now that PR event exists) | 1186 | // Try to push with wrong commit (should be rejected since PR event exists) |
| 1250 | let push_succeeded = match push_to_pr_ref(&setup.clone_path, &setup.pr_event_id) { | 1187 | let push_succeeded = match push_to_pr_ref(&clone_path, &pr_event_id) { |
| 1251 | Ok(success) => success, | 1188 | Ok(success) => success, |
| 1252 | Err(e) => { | 1189 | Err(e) => { |
| 1253 | setup.cleanup(); | 1190 | let _ = fs::remove_dir_all(&clone_path); |
| 1254 | return TestResult::new(test_name, "GRASP-01", desc).fail(&e); | 1191 | return TestResult::new(test_name, "GRASP-01", desc).fail(&e); |
| 1255 | } | 1192 | } |
| 1256 | }; | 1193 | }; |
| 1257 | 1194 | ||
| 1258 | setup.cleanup(); | 1195 | let _ = fs::remove_dir_all(&clone_path); |
| 1259 | 1196 | ||
| 1260 | // Should REJECT - PR event exists with different commit hash | 1197 | // Should REJECT - PR event exists with different commit hash |
| 1261 | if push_succeeded { | 1198 | if push_succeeded { |
| @@ -1272,7 +1209,7 @@ impl PushAuthorizationTests { | |||
| 1272 | /// when a corresponding event exists AND the pushed commit matches | 1209 | /// when a corresponding event exists AND the pushed commit matches |
| 1273 | /// the commit in the PR event's `c` tag. | 1210 | /// the commit in the PR event's `c` tag. |
| 1274 | /// | 1211 | /// |
| 1275 | /// Depends on: `setup_repo_with_wrong_commit_pushed` for setup, then resets to correct commit | 1212 | /// Uses `PREventSentAfterWrongPush` fixture, then creates correct commit and pushes. |
| 1276 | pub async fn test_push_to_nostr_ref_with_correct_commit_after_event_received_accepted( | 1213 | pub async fn test_push_to_nostr_ref_with_correct_commit_after_event_received_accepted( |
| 1277 | client: &AuditClient, | 1214 | client: &AuditClient, |
| 1278 | relay_domain: &str, | 1215 | relay_domain: &str, |
| @@ -1281,36 +1218,64 @@ impl PushAuthorizationTests { | |||
| 1281 | let desc = "Push correct commit to refs/nostr/<pr-event-id> after PR event (should accept)"; | 1218 | let desc = "Push correct commit to refs/nostr/<pr-event-id> after PR event (should accept)"; |
| 1282 | let ctx = TestContext::new(client); | 1219 | let ctx = TestContext::new(client); |
| 1283 | 1220 | ||
| 1284 | // Setup: wrong commit already pushed | 1221 | // Get fixture: PR event exists on relay |
| 1285 | let setup = match setup_repo_with_wrong_commit_pushed(&ctx, relay_domain).await { | 1222 | let pr_event = match ctx.get_fixture(FixtureKind::PREventSentAfterWrongPush).await { |
| 1286 | Ok(s) => s, | 1223 | Ok(e) => e, |
| 1287 | Err(e) => { | 1224 | Err(e) => { |
| 1288 | return TestResult::new(test_name, "GRASP-01", desc).fail(&e); | 1225 | return TestResult::new(test_name, "GRASP-01", desc).fail(format!("{}", e)); |
| 1289 | } | 1226 | } |
| 1290 | }; | 1227 | }; |
| 1291 | 1228 | ||
| 1292 | // Publish PR event FIRST | 1229 | let pr_event_id = pr_event.id.to_hex(); |
| 1293 | if let Err(e) = publish_pr_event_and_wait(&ctx, &setup.pr_event).await { | 1230 | |
| 1294 | setup.cleanup(); | 1231 | // Get repo info for cloning (fresh clone for this test) |
| 1295 | return TestResult::new(test_name, "GRASP-01", desc).fail(&e); | 1232 | let repo = match ctx.get_fixture(FixtureKind::ValidRepo).await { |
| 1296 | } | 1233 | Ok(r) => r, |
| 1234 | Err(e) => { | ||
| 1235 | return TestResult::new(test_name, "GRASP-01", desc).fail(format!("{}", e)); | ||
| 1236 | } | ||
| 1237 | }; | ||
| 1238 | |||
| 1239 | let repo_id = repo | ||
| 1240 | .tags | ||
| 1241 | .iter() | ||
| 1242 | .find(|t| t.kind() == TagKind::d()) | ||
| 1243 | .and_then(|t| t.content()) | ||
| 1244 | .unwrap_or("unknown") | ||
| 1245 | .to_string(); | ||
| 1297 | 1246 | ||
| 1298 | // Reset to CORRECT commit (the one expected by PR event) | 1247 | let owner_npub = match repo.pubkey.to_bech32() { |
| 1299 | if let Err(e) = reset_to_correct_pr_commit(&setup.clone_path) { | 1248 | Ok(n) => n, |
| 1300 | setup.cleanup(); | 1249 | Err(e) => { |
| 1250 | return TestResult::new(test_name, "GRASP-01", desc) | ||
| 1251 | .fail(format!("Failed to get owner npub: {}", e)); | ||
| 1252 | } | ||
| 1253 | }; | ||
| 1254 | |||
| 1255 | // Clone fresh for this test | ||
| 1256 | let clone_path = match clone_repo(relay_domain, &owner_npub, &repo_id) { | ||
| 1257 | Ok(p) => p, | ||
| 1258 | Err(e) => { | ||
| 1259 | return TestResult::new(test_name, "GRASP-01", desc).fail(&e); | ||
| 1260 | } | ||
| 1261 | }; | ||
| 1262 | |||
| 1263 | // Create the CORRECT PR test commit (the one expected by PR event) | ||
| 1264 | if let Err(e) = reset_to_correct_pr_commit(&clone_path) { | ||
| 1265 | let _ = fs::remove_dir_all(&clone_path); | ||
| 1301 | return TestResult::new(test_name, "GRASP-01", desc).fail(&e); | 1266 | return TestResult::new(test_name, "GRASP-01", desc).fail(&e); |
| 1302 | } | 1267 | } |
| 1303 | 1268 | ||
| 1304 | // Push correct commit (should succeed) | 1269 | // Push correct commit (should succeed) |
| 1305 | let push_succeeded = match push_to_pr_ref(&setup.clone_path, &setup.pr_event_id) { | 1270 | let push_succeeded = match push_to_pr_ref(&clone_path, &pr_event_id) { |
| 1306 | Ok(success) => success, | 1271 | Ok(success) => success, |
| 1307 | Err(e) => { | 1272 | Err(e) => { |
| 1308 | setup.cleanup(); | 1273 | let _ = fs::remove_dir_all(&clone_path); |
| 1309 | return TestResult::new(test_name, "GRASP-01", desc).fail(&e); | 1274 | return TestResult::new(test_name, "GRASP-01", desc).fail(&e); |
| 1310 | } | 1275 | } |
| 1311 | }; | 1276 | }; |
| 1312 | 1277 | ||
| 1313 | setup.cleanup(); | 1278 | let _ = fs::remove_dir_all(&clone_path); |
| 1314 | 1279 | ||
| 1315 | // Should ACCEPT - commit matches PR event's c tag | 1280 | // Should ACCEPT - commit matches PR event's c tag |
| 1316 | if !push_succeeded { | 1281 | if !push_succeeded { |