upleb.uk

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

summaryrefslogtreecommitdiff
path: root/grasp-audit/src/specs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2025-12-01 22:34:17 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2025-12-01 22:34:17 +0000
commit29ac0975a6a2f9e1cc585bd56a28b93205d0a2ac (patch)
tree1ba0124839a3bff36f56780d67fdead2ecdd1f01 /grasp-audit/src/specs
parent504eaf4f5aba93a3e935bbee76042dd35cada666 (diff)
test: test_head_set_after_git_push_with_required_oids
Diffstat (limited to 'grasp-audit/src/specs')
-rw-r--r--grasp-audit/src/specs/grasp01/push_authorization.rs236
1 files changed, 204 insertions, 32 deletions
diff --git a/grasp-audit/src/specs/grasp01/push_authorization.rs b/grasp-audit/src/specs/grasp01/push_authorization.rs
index 9e8597b..00b8ae9 100644
--- a/grasp-audit/src/specs/grasp01/push_authorization.rs
+++ b/grasp-audit/src/specs/grasp01/push_authorization.rs
@@ -1031,7 +1031,10 @@ impl PushAuthorizationTests {
1031 // 2. Build PR event (but don't send it) 1031 // 2. Build PR event (but don't send it)
1032 // 3. Clone repo, create wrong commit, push to refs/nostr/<event-id> 1032 // 3. Clone repo, create wrong commit, push to refs/nostr/<event-id>
1033 // If the push fails, the fixture will return an error 1033 // If the push fails, the fixture will return an error
1034 match ctx.get_fixture(FixtureKind::PRWrongCommitPushedBeforeEvent).await { 1034 match ctx
1035 .get_fixture(FixtureKind::PRWrongCommitPushedBeforeEvent)
1036 .await
1037 {
1035 Ok(_pr_event) => TestResult::new(test_name, "GRASP-01", desc).pass(), 1038 Ok(_pr_event) => TestResult::new(test_name, "GRASP-01", desc).pass(),
1036 Err(e) => TestResult::new(test_name, "GRASP-01", desc).fail(format!("{}", e)), 1039 Err(e) => TestResult::new(test_name, "GRASP-01", desc).fail(format!("{}", e)),
1037 } 1040 }
@@ -1053,7 +1056,10 @@ impl PushAuthorizationTests {
1053 let ctx = TestContext::new(client); 1056 let ctx = TestContext::new(client);
1054 1057
1055 // Get fixture: wrong commit was pushed, then PR event was sent 1058 // Get fixture: wrong commit was pushed, then PR event was sent
1056 let pr_event = match ctx.get_fixture(FixtureKind::PREventSentAfterWrongPush).await { 1059 let pr_event = match ctx
1060 .get_fixture(FixtureKind::PREventSentAfterWrongPush)
1061 .await
1062 {
1057 Ok(e) => e, 1063 Ok(e) => e,
1058 Err(e) => { 1064 Err(e) => {
1059 return TestResult::new(test_name, "GRASP-01", desc).fail(format!("{}", e)); 1065 return TestResult::new(test_name, "GRASP-01", desc).fail(format!("{}", e));
@@ -1134,7 +1140,10 @@ impl PushAuthorizationTests {
1134 let ctx = TestContext::new(client); 1140 let ctx = TestContext::new(client);
1135 1141
1136 // Get fixture: PR event exists on relay (wrong commit was previously pushed but may have been cleaned up) 1142 // Get fixture: PR event exists on relay (wrong commit was previously pushed but may have been cleaned up)
1137 let pr_event = match ctx.get_fixture(FixtureKind::PREventSentAfterWrongPush).await { 1143 let pr_event = match ctx
1144 .get_fixture(FixtureKind::PREventSentAfterWrongPush)
1145 .await
1146 {
1138 Ok(e) => e, 1147 Ok(e) => e,
1139 Err(e) => { 1148 Err(e) => {
1140 return TestResult::new(test_name, "GRASP-01", desc).fail(format!("{}", e)); 1149 return TestResult::new(test_name, "GRASP-01", desc).fail(format!("{}", e));
@@ -1218,7 +1227,10 @@ impl PushAuthorizationTests {
1218 let ctx = TestContext::new(client); 1227 let ctx = TestContext::new(client);
1219 1228
1220 // Get fixture: PR event exists on relay 1229 // Get fixture: PR event exists on relay
1221 let pr_event = match ctx.get_fixture(FixtureKind::PREventSentAfterWrongPush).await { 1230 let pr_event = match ctx
1231 .get_fixture(FixtureKind::PREventSentAfterWrongPush)
1232 .await
1233 {
1222 Ok(e) => e, 1234 Ok(e) => e,
1223 Err(e) => { 1235 Err(e) => {
1224 return TestResult::new(test_name, "GRASP-01", desc).fail(format!("{}", e)); 1236 return TestResult::new(test_name, "GRASP-01", desc).fail(format!("{}", e));
@@ -1315,11 +1327,14 @@ impl PushAuthorizationTests {
1315 // ============================================================ 1327 // ============================================================
1316 let ctx = TestContext::new(client); 1328 let ctx = TestContext::new(client);
1317 1329
1318 let _develop_state_event = match ctx.get_fixture(FixtureKind::HeadSetToDevelopBranch).await { 1330 let _develop_state_event = match ctx.get_fixture(FixtureKind::HeadSetToDevelopBranch).await
1331 {
1319 Ok(e) => e, 1332 Ok(e) => e,
1320 Err(e) => { 1333 Err(e) => {
1321 return TestResult::new(test_name, "GRASP-01", desc) 1334 return TestResult::new(test_name, "GRASP-01", desc).fail(format!(
1322 .fail(format!("Failed to create HeadSetToDevelopBranch fixture: {}", e)); 1335 "Failed to create HeadSetToDevelopBranch fixture: {}",
1336 e
1337 ));
1323 } 1338 }
1324 }; 1339 };
1325 1340
@@ -1381,36 +1396,193 @@ impl PushAuthorizationTests {
1381 } 1396 }
1382 1397
1383 /// Test that HEAD is set after git push with oids 1398 /// Test that HEAD is set after git push with oids
1399 ///
1400 /// GRASP-01: "MUST set repository HEAD per repository state announcement
1401 /// as soon as the git data related to that branch has been received."
1402 ///
1403 /// This test verifies the HEAD-setting behavior when:
1404 /// 1. A new state event is published with HEAD="refs/heads/develop1" pointing to a new commit
1405 /// 2. The git data (the new commit) has NOT yet been pushed
1406 /// 3. The relay receives the git push with the required oids
1407 /// 4. Only AFTER the push completes should HEAD be updated to "develop1"
1408 ///
1409 /// This differs from test_head_set_after_state_event_with_existing_commit in that
1410 /// the git data doesn't exist yet when the state event is published.
1411 ///
1412 /// ## Fixture-First Pattern
1413 ///
1414 /// Uses HeadSetToDevelopBranch fixture as base, then:
1415 /// 1. **Depends on**: HeadSetToDevelopBranch (HEAD already set to develop)
1416 /// 2. **Clone**: Clone repo to create new local branch develop1
1417 /// 3. **Create unique commit**: New commit on develop1 that doesn't exist on relay
1418 /// 4. **Build state event**: HEAD=refs/heads/develop1 pointing to new commit
1419 /// 5. **Send state event**: Before git push (git data not yet on relay)
1420 /// 6. **Git push**: Push develop1 branch - sends required oids
1421 /// 7. **Verify**: HEAD should now point to refs/heads/develop1
1384 pub async fn test_head_set_after_git_push_with_required_oids( 1422 pub async fn test_head_set_after_git_push_with_required_oids(
1385 _client: &AuditClient, 1423 client: &AuditClient,
1386 _relay_domain: &str, 1424 relay_domain: &str,
1387 ) -> TestResult { 1425 ) -> TestResult {
1388 let test_name = "test_head_set_after_git_push_with_required_oids"; 1426 let test_name = "test_head_set_after_git_push_with_required_oids";
1389 let desc = "HEAD is set to match state event when git push sends required oids to formulate branch"; 1427 let desc = "HEAD is set to match state event when git push sends required oids to formulate branch";
1390 1428
1391 // DO the above as prep. then create a unique commit, create state event with HEAD=develop1 branch at unqiue commit 1429 // ============================================================
1392 // git push the new develop1 branch. then check HEAD with this: 1430 // Step 1: Get HeadSetToDevelopBranch fixture as baseline
1393 // let default_branch = 1431 // This establishes: repo, maintainer chain, git data, HEAD=develop
1394 // match get_default_branch_from_info_refs(relay_domain, &npub, &repo_id).await { 1432 // ============================================================
1395 // Ok(branch) => branch, 1433 let ctx = TestContext::new(client);
1396 // Err(e) => { 1434
1397 // return TestResult::new(test_name, "GRASP-01", desc) 1435 let _develop_state = match ctx.get_fixture(FixtureKind::HeadSetToDevelopBranch).await {
1398 // .fail(format!("Failed to get default branch: {}", e)); 1436 Ok(e) => e,
1399 // } 1437 Err(e) => {
1400 // }; 1438 return TestResult::new(test_name, "GRASP-01", desc).fail(format!(
1401 1439 "Failed to create HeadSetToDevelopBranch fixture: {}",
1402 // // Verify HEAD points to refs/heads/develop1 1440 e
1403 // if default_branch == "refs/heads/develop1" { 1441 ));
1404 // TestResult::new(test_name, "GRASP-01", desc).pass() 1442 }
1405 // } else { 1443 };
1406 // TestResult::new(test_name, "GRASP-01", desc).fail(format!( 1444
1407 // "Expected HEAD to point to 'refs/heads/develop' but got '{}'. \ 1445 // ============================================================
1408 // GRASP-01 requires: 'MUST set repository HEAD per repository state announcement \ 1446 // Step 2: Extract repo_id and owner npub from ValidRepo (cached by fixture)
1409 // as soon as the git data related to that branch has been received.'", 1447 // ============================================================
1410 // default_branch 1448 let valid_repo = match ctx.get_fixture(FixtureKind::ValidRepo).await {
1411 // )) 1449 Ok(e) => e,
1412 // } 1450 Err(e) => {
1413 TestResult::new(test_name, "GRASP-01", desc).fail("test not implemented") 1451 return TestResult::new(test_name, "GRASP-01", desc)
1452 .fail(format!("Failed to get ValidRepo fixture: {}", e));
1453 }
1454 };
1455
1456 let repo_id = match valid_repo
1457 .tags
1458 .iter()
1459 .find(|t| t.kind() == TagKind::d())
1460 .and_then(|t| t.content())
1461 {
1462 Some(id) => id.to_string(),
1463 None => {
1464 return TestResult::new(test_name, "GRASP-01", desc)
1465 .fail("Missing repo_id in ValidRepo");
1466 }
1467 };
1468
1469 let npub = match valid_repo.pubkey.to_bech32() {
1470 Ok(n) => n,
1471 Err(e) => {
1472 return TestResult::new(test_name, "GRASP-01", desc)
1473 .fail(format!("Failed to convert pubkey to bech32: {}", e));
1474 }
1475 };
1476
1477 // ============================================================
1478 // Step 3: Clone the repo to create a new local branch
1479 // ============================================================
1480 let clone_path = match clone_repo(relay_domain, &npub, &repo_id) {
1481 Ok(path) => path,
1482 Err(e) => {
1483 return TestResult::new(test_name, "GRASP-01", desc)
1484 .fail(format!("Failed to clone repo: {}", e));
1485 }
1486 };
1487
1488 // ============================================================
1489 // Step 4: Create and checkout develop1 branch, then create unique commit
1490 // ============================================================
1491 let output = Command::new("git")
1492 .args(["checkout", "-b", "develop1"])
1493 .current_dir(&clone_path)
1494 .output();
1495
1496 if let Err(e) = output {
1497 let _ = fs::remove_dir_all(&clone_path);
1498 return TestResult::new(test_name, "GRASP-01", desc)
1499 .fail(format!("Failed to create develop1 branch: {}", e));
1500 }
1501
1502 // Create a unique commit on develop1
1503 let commit_hash = match create_commit(&clone_path, "Unique develop1 commit") {
1504 Ok(hash) => hash,
1505 Err(e) => {
1506 let _ = fs::remove_dir_all(&clone_path);
1507 return TestResult::new(test_name, "GRASP-01", desc)
1508 .fail(format!("Failed to create commit: {}", e));
1509 }
1510 };
1511
1512 // ============================================================
1513 // Step 5: Build and send state event with HEAD=refs/heads/develop1
1514 // This references a commit that doesn't yet exist on the relay
1515 // ============================================================
1516 let state_event = match client
1517 .event_builder(Kind::Custom(30618), "")
1518 .tag(Tag::identifier(&repo_id))
1519 .tag(Tag::custom(
1520 TagKind::custom("HEAD"),
1521 vec!["refs/heads/develop1".to_string()],
1522 ))
1523 .tag(Tag::custom(
1524 TagKind::custom("refs/heads/develop1"),
1525 vec![commit_hash.clone()],
1526 ))
1527 .build(client.keys())
1528 {
1529 Ok(e) => e,
1530 Err(e) => {
1531 let _ = fs::remove_dir_all(&clone_path);
1532 return TestResult::new(test_name, "GRASP-01", desc)
1533 .fail(format!("Failed to build state event: {}", e));
1534 }
1535 };
1536
1537 // Send the state event (commit doesn't exist on relay yet)
1538 if let Err(e) = client.send_event(state_event).await {
1539 let _ = fs::remove_dir_all(&clone_path);
1540 return TestResult::new(test_name, "GRASP-01", desc)
1541 .fail(format!("Failed to send state event: {}", e));
1542 }
1543
1544 // ============================================================
1545 // Step 6: Push the develop1 branch - this sends the required oids
1546 // ============================================================
1547 let push_result = try_push_to_ref(&clone_path, "refs/heads/develop1");
1548 let _ = fs::remove_dir_all(&clone_path); // Cleanup clone
1549
1550 match push_result {
1551 Ok(true) => { /* Push succeeded, continue to verify */ }
1552 Ok(false) => {
1553 return TestResult::new(test_name, "GRASP-01", desc)
1554 .fail("Push to refs/heads/develop1 was rejected");
1555 }
1556 Err(e) => {
1557 return TestResult::new(test_name, "GRASP-01", desc)
1558 .fail(format!("Failed to push develop1 branch: {}", e));
1559 }
1560 }
1561
1562 // ============================================================
1563 // Step 7: VERIFY - Query info/refs to check the default branch
1564 // HEAD should now point to refs/heads/develop1 as git data is available
1565 // ============================================================
1566 let default_branch =
1567 match get_default_branch_from_info_refs(relay_domain, &npub, &repo_id).await {
1568 Ok(branch) => branch,
1569 Err(e) => {
1570 return TestResult::new(test_name, "GRASP-01", desc)
1571 .fail(format!("Failed to get default branch: {}", e));
1572 }
1573 };
1574
1575 // Verify HEAD points to refs/heads/develop1
1576 if default_branch == "refs/heads/develop1" {
1577 TestResult::new(test_name, "GRASP-01", desc).pass()
1578 } else {
1579 TestResult::new(test_name, "GRASP-01", desc).fail(format!(
1580 "Expected HEAD to point to 'refs/heads/develop1' but got '{}'. \
1581 GRASP-01 requires: 'MUST set repository HEAD per repository state announcement \
1582 as soon as the git data related to that branch has been received.'",
1583 default_branch
1584 ))
1585 }
1414 } 1586 }
1415} 1587}
1416 1588