upleb.uk

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

summaryrefslogtreecommitdiff
path: root/grasp-audit/src
diff options
context:
space:
mode:
Diffstat (limited to 'grasp-audit/src')
-rw-r--r--grasp-audit/src/fixtures.rs110
1 files changed, 67 insertions, 43 deletions
diff --git a/grasp-audit/src/fixtures.rs b/grasp-audit/src/fixtures.rs
index 9a00aef..fc6e8cb 100644
--- a/grasp-audit/src/fixtures.rs
+++ b/grasp-audit/src/fixtures.rs
@@ -154,6 +154,22 @@ pub enum FixtureKind {
154 /// - Timestamp: 10 seconds in the past 154 /// - Timestamp: 10 seconds in the past
155 RepoState, 155 RepoState,
156 156
157 /// Owner's repository state announcement (kind 30618) sent to relay and accepted into purgatory
158 ///
159 /// This is the "sent" stage: the state event has been published to the relay and
160 /// accepted (OK response), but no git data has been pushed yet so it remains in
161 /// purgatory and is not served to clients.
162 ///
163 /// Use this when you need the state event to exist on the relay but do not need
164 /// the full push/serve cycle. For the complete cycle (git pushed + verified served),
165 /// use `OwnerStateDataPushed`.
166 ///
167 /// - Requires ValidRepoSent (uses same repo_id)
168 /// - Signed by owner keys (`client.keys()`)
169 /// - Points to DETERMINISTIC_COMMIT_HASH
170 /// - Timestamp: 10 seconds in the past
171 OwnerRepoStateSent,
172
157 /// PR (Pull Request) event for the SAME repo_id as ValidRepoServed 173 /// PR (Pull Request) event for the SAME repo_id as ValidRepoServed
158 /// - Requires ValidRepoServed (uses same repo_id, needs queryable repo) 174 /// - Requires ValidRepoServed (uses same repo_id, needs queryable repo)
159 /// - Signed by `client.pr_author_keys()` 175 /// - Signed by `client.pr_author_keys()`
@@ -343,6 +359,8 @@ impl FixtureKind {
343 // Fixtures that depend on ValidRepoServed (need queryable announcement) 359 // Fixtures that depend on ValidRepoServed (need queryable announcement)
344 Self::RepoWithIssue => vec![Self::ValidRepoServed], 360 Self::RepoWithIssue => vec![Self::ValidRepoServed],
345 Self::RepoState => vec![Self::ValidRepoSent], 361 Self::RepoState => vec![Self::ValidRepoSent],
362 // OwnerRepoStateSent depends on ValidRepoSent: state event sent, sitting in purgatory
363 Self::OwnerRepoStateSent => vec![Self::ValidRepoSent],
346 Self::PREvent => vec![Self::ValidRepoServed], 364 Self::PREvent => vec![Self::ValidRepoServed],
347 Self::PREventGenerated => vec![Self::ValidRepoServed], 365 Self::PREventGenerated => vec![Self::ValidRepoServed],
348 Self::PRWrongCommitPushedBeforeEvent => vec![Self::PREventGenerated], 366 Self::PRWrongCommitPushedBeforeEvent => vec![Self::PREventGenerated],
@@ -354,7 +372,8 @@ impl FixtureKind {
354 Self::PREvent2GitDataPushed => vec![Self::PREvent2Sent], 372 Self::PREvent2GitDataPushed => vec![Self::PREvent2Sent],
355 Self::PREvent2Served => vec![Self::PREvent2GitDataPushed], 373 Self::PREvent2Served => vec![Self::PREvent2GitDataPushed],
356 374
357 Self::OwnerStateDataPushed => vec![Self::ValidRepoSent], 375 // OwnerStateDataPushed depends on OwnerRepoStateSent (git push + purgatory release)
376 Self::OwnerStateDataPushed => vec![Self::OwnerRepoStateSent],
358 377
359 // Fixtures that depend on RepoWithIssue 378 // Fixtures that depend on RepoWithIssue
360 Self::RepoWithComment => vec![Self::RepoWithIssue], 379 Self::RepoWithComment => vec![Self::RepoWithIssue],
@@ -399,6 +418,8 @@ impl FixtureKind {
399 Self::HeadSetToDevelopBranch => true, 418 Self::HeadSetToDevelopBranch => true,
400 // ValidRepoServed doesn't send anything itself, just returns cached event 419 // ValidRepoServed doesn't send anything itself, just returns cached event
401 Self::ValidRepoServed => true, 420 Self::ValidRepoServed => true,
421 // OwnerRepoStateSent sends its state event and notes purgatory internally
422 Self::OwnerRepoStateSent => true,
402 // All other fixtures return a single event for the caller to send 423 // All other fixtures return a single event for the caller to send
403 _ => false, 424 _ => false,
404 } 425 }
@@ -774,6 +795,40 @@ impl<'a> TestContext<'a> {
774 .map_err(|e| anyhow::anyhow!("Failed to build state announcement: {}", e)) 795 .map_err(|e| anyhow::anyhow!("Failed to build state announcement: {}", e))
775 } 796 }
776 797
798 FixtureKind::OwnerRepoStateSent => {
799 use nostr_sdk::prelude::*;
800
801 // ValidRepoSent is ensured by ensure_fixture before this is called
802 let repo = self.get_cached_dependency(FixtureKind::ValidRepoSent)?;
803 let repo_id = self.extract_repo_id(&repo)?;
804
805 let base_time = Timestamp::now().as_secs();
806 let older_timestamp = Timestamp::from(base_time - 10);
807
808 let state_event = self
809 .client
810 .event_builder(Kind::RepoState, "")
811 .tag(Tag::identifier(&repo_id))
812 .tag(Tag::custom(
813 TagKind::custom("refs/heads/main"),
814 vec![DETERMINISTIC_COMMIT_HASH.to_string()],
815 ))
816 .tag(Tag::custom(
817 TagKind::custom("HEAD"),
818 vec!["ref: refs/heads/main".to_string()],
819 ))
820 .custom_time(older_timestamp)
821 .build(self.client.keys())
822 .map_err(|e| anyhow::anyhow!("Failed to build state announcement: {}", e))?;
823
824 // Send to relay - event will be accepted but held in purgatory (no git data yet)
825 self.client
826 .send_event_and_note_purgatory(state_event.clone())
827 .await?;
828
829 Ok(state_event)
830 }
831
777 FixtureKind::PREvent => { 832 FixtureKind::PREvent => {
778 use nostr_sdk::prelude::*; 833 use nostr_sdk::prelude::*;
779 834
@@ -945,57 +1000,26 @@ impl<'a> TestContext<'a> {
945 .ok_or_else(|| anyhow::anyhow!("Missing d tag in repo announcement")) 1000 .ok_or_else(|| anyhow::anyhow!("Missing d tag in repo announcement"))
946 } 1001 }
947 1002
948 /// Build OwnerStateDataPushed fixture: full 4-stage fixture for push authorization 1003 /// Build OwnerStateDataPushed fixture: git push + purgatory release for owner's state event
949 /// 1004 ///
950 /// This handles all stages of the fixture: 1005 /// `OwnerRepoStateSent` is ensured as a dependency before this is called — the state event
951 /// 1. **Generated**: Creates RepoState (repo announcement + state event) 1006 /// is already on the relay in purgatory. This fixture completes the cycle:
952 /// 2. **Sent**: Sends events to relay (returns OK, accepted but 'purgatory:...' message) 1007 /// 1. **DataPushed**: Clones repo, creates deterministic commit, pushes to relay
953 /// 3. **Verify Not Served**: Confirms event is not served by relays 1008 /// 2. **Verified**: Confirms state event is released from purgatory and served
954 /// 4. **DataPushed**: Clones repo, creates deterministic commit, pushes to relay
955 /// 5. **Verified**: Confirms event is served by relay
956 /// 1009 ///
957 /// # Returns 1010 /// # Returns
958 /// The state event (kind 30618) after all stages complete successfully 1011 /// The state event (kind 30618) after git data is pushed and purgatory is released
959 async fn build_owner_state_data_pushed(&self) -> Result<Event> { 1012 async fn build_owner_state_data_pushed(&self) -> Result<Event> {
960 use nostr_sdk::prelude::*; 1013 use nostr_sdk::prelude::*;
961 1014
962 // ============================================================ 1015 // OwnerRepoStateSent is ensured by ensure_fixture before this is called.
963 // Stage 1: ValidRepoSent is ensured by ensure_fixture before this is called 1016 // The state event is already on the relay in purgatory - retrieve it from cache.
964 // ============================================================ 1017 let state_event = self.get_cached_dependency(FixtureKind::OwnerRepoStateSent)?;
965 let repo = self.get_cached_dependency(FixtureKind::ValidRepoSent)?; 1018 let repo = self.get_cached_dependency(FixtureKind::ValidRepoSent)?;
966 let repo_id = self.extract_repo_id(&repo)?; 1019 let repo_id = self.extract_repo_id(&repo)?;
967 1020
968 // Build state event
969 let base_time = Timestamp::now().as_secs();
970 let older_timestamp = Timestamp::from(base_time - 10); // 10 seconds ago
971
972 let state_event = self
973 .client
974 .event_builder(Kind::RepoState, "")
975 .tag(Tag::identifier(&repo_id))
976 .tag(Tag::custom(
977 TagKind::custom("refs/heads/main"),
978 vec![DETERMINISTIC_COMMIT_HASH.to_string()],
979 ))
980 .tag(Tag::custom(
981 TagKind::custom("HEAD"),
982 vec!["ref: refs/heads/main".to_string()],
983 ))
984 .custom_time(older_timestamp)
985 .build(self.client.keys())
986 .map_err(|e| anyhow::anyhow!("Failed to build state announcement: {}", e))?;
987
988 // ============================================================ 1021 // ============================================================
989 // Stage 2 & 3: Send to Relay, get Accepted response and Verify its Not Served 1022 // Stage 1: DataPushed - Clone repo, create commit, push
990 // ============================================================
991 let (_, _in_purgatory) = self
992 .client
993 .send_event_and_note_purgatory(state_event.clone())
994 .await?;
995 // Note: We don't fail if purgatory wasn't observed - the fixture proceeds regardless
996
997 // ============================================================
998 // Stage 4: DataPushed - Clone repo, create commit, push
999 // ============================================================ 1023 // ============================================================
1000 1024
1001 // Get relay domain from connected relay 1025 // Get relay domain from connected relay
@@ -1097,7 +1121,7 @@ impl<'a> TestContext<'a> {
1097 } 1121 }
1098 1122
1099 // ============================================================ 1123 // ============================================================
1100 // Stage 5: Verify state event is on relay 1124 // Stage 2: Verify state event is released from purgatory
1101 // ============================================================ 1125 // ============================================================
1102 1126
1103 tokio::time::sleep(Duration::from_millis(200)).await; 1127 tokio::time::sleep(Duration::from_millis(200)).await;