upleb.uk

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

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--grasp-audit/src/fixtures.rs138
-rw-r--r--grasp-audit/src/specs/grasp01/push_authorization.rs24
2 files changed, 96 insertions, 66 deletions
diff --git a/grasp-audit/src/fixtures.rs b/grasp-audit/src/fixtures.rs
index c5eb5f8..dca204b 100644
--- a/grasp-audit/src/fixtures.rs
+++ b/grasp-audit/src/fixtures.rs
@@ -227,20 +227,17 @@ pub enum FixtureKind {
227 /// - Git push verified to succeed (state matches pushed commit) 227 /// - Git push verified to succeed (state matches pushed commit)
228 OwnerStateDataPushed, 228 OwnerStateDataPushed,
229 229
230 /// Maintainer's state event with git data successfully pushed (full 4-stage fixture) 230 /// Maintainer's state event with git data successfully pushed (full 5-stage fixture)
231 /// 231 ///
232 /// This fixture tests that a maintainer can authorize pushes with ONLY a state event, 232 /// This fixture tests that a maintainer can authorize pushes with ONLY a state event,
233 /// without publishing their own repo announcement. The maintainer is still listed in 233 /// without publishing their own repo announcement.
234 /// the owner's announcement, so they're a valid maintainer.
235 ///
236 /// GRASP-01: "respecting the recursive maintainer set"
237 /// 234 ///
238 /// Stages: 235 /// This fixture represents the complete flow for testing maintainer push authorization:
239 /// 1. **Generated**: Creates ValidRepo (owner's announcement with maintainer in maintainers tag) 236 /// 1. **OwnerStateDataPushed dependency**: Owner's repo and state event already on relay, git data pushed
240 /// + MaintainerState (maintainer's state event ONLY - no announcement) 237 /// 2. **Sent**: Sends maintainer state event to relay (returns OK, accepted but 'purgatory:...' message)
241 /// 2. **Sent**: Sends events to relay 238 /// 3. **Verify Not Served**: Confirms event is not served by relays
242 /// 3. **Verified**: Confirms events accepted by relay 239 /// 4. **DataPushed**: Clones repo, creates maintainer deterministic commit, force-pushes to relay
243 /// 4. **DataPushed**: Clones repo, creates maintainer deterministic commit, pushes to relay 240 /// 5. **Verified**: Confirms event is served by relay
244 /// 241 ///
245 /// - Requires OwnerStateDataPushed (owner's data already pushed to git) 242 /// - Requires OwnerStateDataPushed (owner's data already pushed to git)
246 /// - State event signed by maintainer keys (`client.maintainer_keys()`) 243 /// - State event signed by maintainer keys (`client.maintainer_keys()`)
@@ -248,26 +245,23 @@ pub enum FixtureKind {
248 /// - Git push verified to succeed (force push with maintainer's state event authorizes the commit) 245 /// - Git push verified to succeed (force push with maintainer's state event authorizes the commit)
249 MaintainerStateDataPushed, 246 MaintainerStateDataPushed,
250 247
251 /// Recursive maintainer's state event with git data successfully pushed (full 4-stage fixture) 248 /// Recursive maintainer's state event with git data successfully pushed (full 5-stage fixture)
252 /// 249 ///
253 /// This fixture tests that a recursive maintainer (authorized via maintainer chain) can 250 /// This fixture tests that a recursive maintainer (authorized via maintainer chain) can
254 /// authorize pushes. The recursive maintainer is listed in the maintainer's announcement, 251 /// authorize pushes. The recursive maintainer is listed in the maintainer's announcement,
255 /// not the owner's announcement, so this tests the recursive maintainer traversal. 252 /// not the owner's announcement, so this tests the recursive maintainer traversal.
256 /// 253 ///
257 /// GRASP-01: "respecting the recursive maintainer set" 254 /// This fixture represents the complete flow for testing recursive maintainer push authorization:
255 /// 1. **Generated**: (MaintainerStateDataPushed dependency includes ValidRepo + OwnerStateDataPushed)
256 /// Creates MaintainerAnnouncement + RecursiveMaintainerState
257 /// 2. **Sent**: Sends events to relay (returns OK, accepted but 'purgatory:...' message)
258 /// 3. **Verify Not Served**: Confirms event is not served by relays
259 /// 4. **DataPushed**: Clones repo, creates recursive maintainer deterministic commit, pushes to relay
260 /// 5. **Verified**: Confirms event is served by relay
258 /// 261 ///
259 /// Chain: Owner -> Maintainer -> RecursiveMaintainer 262 /// Chain: Owner -> Maintainer -> RecursiveMaintainer
260 /// 263 ///
261 /// Stages:
262 /// 1. **Generated**: Creates MaintainerStateDataPushed (includes ValidRepo + OwnerStateDataPushed)
263 /// + MaintainerAnnouncement (maintainer's announcement listing recursive maintainer)
264 /// + RecursiveMaintainerState (recursive maintainer's state event)
265 /// 2. **Sent**: Sends events to relay
266 /// 3. **Verified**: Confirms events accepted by relay
267 /// 4. **DataPushed**: Clones repo, creates recursive maintainer deterministic commit, pushes to relay
268 ///
269 /// - Requires MaintainerStateDataPushed (establishes Owner -> Maintainer chain with git data) 264 /// - Requires MaintainerStateDataPushed (establishes Owner -> Maintainer chain with git data)
270 /// - Sends MaintainerAnnouncement (establishes Maintainer -> RecursiveMaintainer connection)
271 /// - State event signed by recursive maintainer keys (`client.recursive_maintainer_keys()`) 265 /// - State event signed by recursive maintainer keys (`client.recursive_maintainer_keys()`)
272 /// - Points to RECURSIVE_MAINTAINER_DETERMINISTIC_COMMIT_HASH 266 /// - Points to RECURSIVE_MAINTAINER_DETERMINISTIC_COMMIT_HASH
273 /// - Git push verified to succeed (recursive maintainer's state event authorizes the commit) 267 /// - Git push verified to succeed (recursive maintainer's state event authorizes the commit)
@@ -1026,7 +1020,7 @@ impl<'a> TestContext<'a> {
1026 Ok(state_event) 1020 Ok(state_event)
1027 } 1021 }
1028 1022
1029 /// Build MaintainerStateDataPushed fixture: full 4-stage fixture for maintainer push authorization 1023 /// Build MaintainerStateDataPushed fixture: full 5-stage fixture for maintainer push authorization
1030 /// 1024 ///
1031 /// This tests that a maintainer can authorize pushes with ONLY a state event, 1025 /// This tests that a maintainer can authorize pushes with ONLY a state event,
1032 /// without publishing their own repo announcement. 1026 /// without publishing their own repo announcement.
@@ -1034,6 +1028,13 @@ impl<'a> TestContext<'a> {
1034 /// Depends on OwnerStateDataPushed - the owner's data has already been pushed. 1028 /// Depends on OwnerStateDataPushed - the owner's data has already been pushed.
1035 /// The maintainer force-pushes their commit on top. 1029 /// The maintainer force-pushes their commit on top.
1036 /// 1030 ///
1031 /// This handles all stages of the fixture:
1032 /// 1. **OwnerStateDataPushed dependency**: Owner's repo and state event already on relay, git data pushed
1033 /// 2. **Sent**: Sends maintainer state event to relay (returns OK, accepted but 'purgatory:...' message)
1034 /// 3. **Verify Not Served**: Confirms event is not served by relays
1035 /// 4. **DataPushed**: Clones repo, creates maintainer deterministic commit, force-pushes to relay
1036 /// 5. **Verified**: Confirms event is served by relay
1037 ///
1037 /// # Returns 1038 /// # Returns
1038 /// The maintainer's state event (kind 30618) after all stages complete successfully 1039 /// The maintainer's state event (kind 30618) after all stages complete successfully
1039 async fn build_maintainer_state_data_pushed(&self) -> Result<Event> { 1040 async fn build_maintainer_state_data_pushed(&self) -> Result<Event> {
@@ -1041,7 +1042,6 @@ impl<'a> TestContext<'a> {
1041 1042
1042 // ============================================================ 1043 // ============================================================
1043 // Stage 1: OwnerStateDataPushed is ensured by ensure_fixture before this is called 1044 // Stage 1: OwnerStateDataPushed is ensured by ensure_fixture before this is called
1044 // The owner's repo and state event are already on the relay, and git data is pushed
1045 // ============================================================ 1045 // ============================================================
1046 let owner_state = self.get_cached_dependency(FixtureKind::OwnerStateDataPushed)?; 1046 let owner_state = self.get_cached_dependency(FixtureKind::OwnerStateDataPushed)?;
1047 1047
@@ -1071,15 +1071,12 @@ impl<'a> TestContext<'a> {
1071 .build(self.client.maintainer_keys()) 1071 .build(self.client.maintainer_keys())
1072 .map_err(|e| anyhow::anyhow!("Failed to build maintainer state event: {}", e))?; 1072 .map_err(|e| anyhow::anyhow!("Failed to build maintainer state event: {}", e))?;
1073 1073
1074 // Send maintainer state event to relay
1075 self.client
1076 .send_event(maintainer_state_event.clone())
1077 .await?;
1078
1079 // ============================================================ 1074 // ============================================================
1080 // Stage 3: Verify state event was accepted 1075 // Stage 2 & 3: Send to Relay, get Accepted response and Verify its Not Served
1081 // ============================================================ 1076 // ============================================================
1082 tokio::time::sleep(std::time::Duration::from_millis(200)).await; 1077 self.client
1078 .send_event_expect_purgatory_not_served(maintainer_state_event.clone())
1079 .await?;
1083 1080
1084 // ============================================================ 1081 // ============================================================
1085 // Stage 4: DataPushed - Clone repo, create maintainer commit, push 1082 // Stage 4: DataPushed - Clone repo, create maintainer commit, push
@@ -1154,20 +1151,35 @@ impl<'a> TestContext<'a> {
1154 cleanup(&clone_path); 1151 cleanup(&clone_path);
1155 1152
1156 match push_result { 1153 match push_result {
1157 Ok(true) => Ok(maintainer_state_event), 1154 Ok(res) => {
1158 Ok(false) => Err(anyhow::anyhow!( 1155 if !res {
1159 "Push was rejected but should have been accepted. \ 1156 return Err(anyhow::anyhow!(
1157 "Push was rejected but should have been accepted. \
1160 The maintainer published a state event with commit {}, \ 1158 The maintainer published a state event with commit {}, \
1161 and even without a separate announcement, the relay should \ 1159 and even without a separate announcement, the relay should \
1162 authorize pushes matching this state event since the maintainer \ 1160 authorize pushes matching this state event since the maintainer \
1163 is listed in the owner's announcement.", 1161 is listed in the owner's announcement.",
1164 MAINTAINER_DETERMINISTIC_COMMIT_HASH 1162 MAINTAINER_DETERMINISTIC_COMMIT_HASH
1165 )), 1163 ));
1166 Err(e) => Err(anyhow::anyhow!("Push error: {}", e)), 1164 }
1165 }
1166 Err(e) => return Err(anyhow::anyhow!("Push error: {}", e)),
1167 }
1168
1169 // ============================================================
1170 // Stage 5: Verify state event is on relay
1171 // ============================================================
1172
1173 tokio::time::sleep(Duration::from_millis(200)).await;
1174
1175 if !self.client.is_event_on_relay(maintainer_state_event.id).await? {
1176 return Err(anyhow::anyhow!("state event not released from purgatory"));
1167 } 1177 }
1178
1179 Ok(maintainer_state_event)
1168 } 1180 }
1169 1181
1170 /// Build RecursiveMaintainerStateDataPushed fixture: full 4-stage fixture for recursive maintainer push authorization 1182 /// Build RecursiveMaintainerStateDataPushed fixture: full 5-stage fixture for recursive maintainer push authorization
1171 /// 1183 ///
1172 /// This tests that a recursive maintainer (authorized via maintainer chain) can authorize pushes. 1184 /// This tests that a recursive maintainer (authorized via maintainer chain) can authorize pushes.
1173 /// The recursive maintainer is listed in the maintainer's announcement, not the owner's announcement, 1185 /// The recursive maintainer is listed in the maintainer's announcement, not the owner's announcement,
@@ -1177,6 +1189,14 @@ impl<'a> TestContext<'a> {
1177 /// We then send the MaintainerAnnouncement (which lists the recursive maintainer), and the 1189 /// We then send the MaintainerAnnouncement (which lists the recursive maintainer), and the
1178 /// recursive maintainer force-pushes their commit on top. 1190 /// recursive maintainer force-pushes their commit on top.
1179 /// 1191 ///
1192 /// This handles all stages of the fixture:
1193 /// 1. **Generated**: (MaintainerStateDataPushed dependency includes ValidRepo + OwnerStateDataPushed)
1194 /// Creates MaintainerAnnouncement + RecursiveMaintainerState
1195 /// 2. **Sent**: Sends events to relay (returns OK, accepted but 'purgatory:...' message)
1196 /// 3. **Verify Not Served**: Confirms event is not served by relays
1197 /// 4. **DataPushed**: Clones repo, creates recursive maintainer deterministic commit, pushes to relay
1198 /// 5. **Verified**: Confirms event is served by relay
1199 ///
1180 /// # Returns 1200 /// # Returns
1181 /// The recursive maintainer's state event (kind 30618) after all stages complete successfully 1201 /// The recursive maintainer's state event (kind 30618) after all stages complete successfully
1182 async fn build_recursive_maintainer_state_data_pushed(&self) -> Result<Event> { 1202 async fn build_recursive_maintainer_state_data_pushed(&self) -> Result<Event> {
@@ -1184,8 +1204,6 @@ impl<'a> TestContext<'a> {
1184 1204
1185 // ============================================================ 1205 // ============================================================
1186 // Stage 1: MaintainerStateDataPushed is ensured by ensure_fixture before this is called 1206 // Stage 1: MaintainerStateDataPushed is ensured by ensure_fixture before this is called
1187 // The owner's repo, owner's state event, and maintainer's state event are already on the relay,
1188 // and maintainer's git data is pushed
1189 // ============================================================ 1207 // ============================================================
1190 let maintainer_state = 1208 let maintainer_state =
1191 self.get_cached_dependency(FixtureKind::MaintainerStateDataPushed)?; 1209 self.get_cached_dependency(FixtureKind::MaintainerStateDataPushed)?;
@@ -1197,7 +1215,7 @@ impl<'a> TestContext<'a> {
1197 let repo = self.get_cached_dependency(FixtureKind::ValidRepo)?; 1215 let repo = self.get_cached_dependency(FixtureKind::ValidRepo)?;
1198 1216
1199 // ============================================================ 1217 // ============================================================
1200 // Stage 2: Send MaintainerAnnouncement (establishes Maintainer -> RecursiveMaintainer chain) 1218 // Stage 1 (continued): Generate MaintainerAnnouncement and RecursiveMaintainerState
1201 // ============================================================ 1219 // ============================================================
1202 let maintainer_announcement = self.build_maintainer_announcement(&repo_id).await?; 1220 let maintainer_announcement = self.build_maintainer_announcement(&repo_id).await?;
1203 self.client.send_event(maintainer_announcement).await?; 1221 self.client.send_event(maintainer_announcement).await?;
@@ -1224,15 +1242,12 @@ impl<'a> TestContext<'a> {
1224 anyhow::anyhow!("Failed to build recursive maintainer state event: {}", e) 1242 anyhow::anyhow!("Failed to build recursive maintainer state event: {}", e)
1225 })?; 1243 })?;
1226 1244
1227 // Send recursive maintainer state event to relay
1228 self.client
1229 .send_event(recursive_maintainer_state_event.clone())
1230 .await?;
1231
1232 // ============================================================ 1245 // ============================================================
1233 // Stage 3: Verify state event was accepted 1246 // Stage 2 & 3: Send to Relay, get Accepted response and Verify its Not Served
1234 // ============================================================ 1247 // ============================================================
1235 tokio::time::sleep(std::time::Duration::from_millis(200)).await; 1248 self.client
1249 .send_event_expect_purgatory_not_served(recursive_maintainer_state_event.clone())
1250 .await?;
1236 1251
1237 // ============================================================ 1252 // ============================================================
1238 // Stage 4: DataPushed - Clone repo, create recursive maintainer commit, push 1253 // Stage 4: DataPushed - Clone repo, create recursive maintainer commit, push
@@ -1310,16 +1325,31 @@ impl<'a> TestContext<'a> {
1310 cleanup(&clone_path); 1325 cleanup(&clone_path);
1311 1326
1312 match push_result { 1327 match push_result {
1313 Ok(true) => Ok(recursive_maintainer_state_event), 1328 Ok(res) => {
1314 Ok(false) => Err(anyhow::anyhow!( 1329 if !res {
1315 "Push was rejected but should have been accepted. \ 1330 return Err(anyhow::anyhow!(
1331 "Push was rejected but should have been accepted. \
1316 The recursive maintainer published a state event with commit {}, \ 1332 The recursive maintainer published a state event with commit {}, \
1317 and the relay should authorize pushes matching this state event \ 1333 and the relay should authorize pushes matching this state event \
1318 through recursive maintainer traversal (Owner -> Maintainer -> RecursiveMaintainer).", 1334 through recursive maintainer traversal (Owner -> Maintainer -> RecursiveMaintainer).",
1319 RECURSIVE_MAINTAINER_DETERMINISTIC_COMMIT_HASH 1335 RECURSIVE_MAINTAINER_DETERMINISTIC_COMMIT_HASH
1320 )), 1336 ));
1321 Err(e) => Err(anyhow::anyhow!("Push error: {}", e)), 1337 }
1338 }
1339 Err(e) => return Err(anyhow::anyhow!("Push error: {}", e)),
1340 }
1341
1342 // ============================================================
1343 // Stage 5: Verify state event is on relay
1344 // ============================================================
1345
1346 tokio::time::sleep(Duration::from_millis(200)).await;
1347
1348 if !self.client.is_event_on_relay(recursive_maintainer_state_event.id).await? {
1349 return Err(anyhow::anyhow!("state event not released from purgatory"));
1322 } 1350 }
1351
1352 Ok(recursive_maintainer_state_event)
1323 } 1353 }
1324 1354
1325 /// Build HeadSetToDevelopBranch fixture: creates state event with HEAD=develop 1355 /// Build HeadSetToDevelopBranch fixture: creates state event with HEAD=develop
diff --git a/grasp-audit/src/specs/grasp01/push_authorization.rs b/grasp-audit/src/specs/grasp01/push_authorization.rs
index 6726fe5..64ce8f9 100644
--- a/grasp-audit/src/specs/grasp01/push_authorization.rs
+++ b/grasp-audit/src/specs/grasp01/push_authorization.rs
@@ -678,12 +678,12 @@ impl PushAuthorizationTests {
678 /// without publishing their own repo announcement. The maintainer is still 678 /// without publishing their own repo announcement. The maintainer is still
679 /// listed in the owner's announcement, so they're a valid maintainer. 679 /// listed in the owner's announcement, so they're a valid maintainer.
680 /// 680 ///
681 /// This test uses the MaintainerStateDataPushed fixture which handles all 4 stages: 681 /// This test uses the MaintainerStateDataPushed fixture which handles all 5 stages:
682 /// 1. **Generated**: Creates ValidRepo (owner's announcement with maintainer in maintainers tag) 682 /// 1. **OwnerStateDataPushed dependency**: Owner's repo and state event already on relay, git data pushed
683 /// + MaintainerState (maintainer's state event ONLY - no announcement) 683 /// 2. **Sent**: Sends maintainer state event to relay (returns OK, accepted but 'purgatory:...' message)
684 /// 2. **Sent**: Sends events to relay 684 /// 3. **Verify Not Served**: Confirms event is not served by relays
685 /// 3. **Verified**: Confirms events accepted by relay 685 /// 4. **DataPushed**: Clones repo, creates maintainer deterministic commit, force-pushes to relay
686 /// 4. **DataPushed**: Clones repo, creates maintainer deterministic commit, pushes to relay 686 /// 5. **Verified**: Confirms event is served by relay
687 /// 687 ///
688 /// The test wraps the fixture result in pass/fail using the error message. 688 /// The test wraps the fixture result in pass/fail using the error message.
689 #[allow(unused_variables)] // relay_domain is now handled by fixture 689 #[allow(unused_variables)] // relay_domain is now handled by fixture
@@ -720,13 +720,13 @@ impl PushAuthorizationTests {
720 /// GRASP-01: "respecting the recursive maintainer set" 720 /// GRASP-01: "respecting the recursive maintainer set"
721 /// This tests recursive maintainer chains: Owner -> Maintainer -> RecursiveMaintainer 721 /// This tests recursive maintainer chains: Owner -> Maintainer -> RecursiveMaintainer
722 /// 722 ///
723 /// This test uses the RecursiveMaintainerStateDataPushed fixture which handles all 4 stages: 723 /// This test uses the RecursiveMaintainerStateDataPushed fixture which handles all 5 stages:
724 /// 1. **Generated**: Creates MaintainerStateDataPushed (owner's + maintainer's data pushed) 724 /// 1. **Generated**: (MaintainerStateDataPushed dependency includes ValidRepo + OwnerStateDataPushed)
725 /// + MaintainerAnnouncement (maintainer lists recursive maintainer) 725 /// Creates MaintainerAnnouncement + RecursiveMaintainerState
726 /// + RecursiveMaintainerState (recursive maintainer's state event) 726 /// 2. **Sent**: Sends events to relay (returns OK, accepted but 'purgatory:...' message)
727 /// 2. **Sent**: Sends events to relay 727 /// 3. **Verify Not Served**: Confirms event is not served by relays
728 /// 3. **Verified**: Confirms events accepted by relay
729 /// 4. **DataPushed**: Clones repo, creates recursive maintainer deterministic commit, pushes to relay 728 /// 4. **DataPushed**: Clones repo, creates recursive maintainer deterministic commit, pushes to relay
729 /// 5. **Verified**: Confirms event is served by relay
730 /// 730 ///
731 /// The test wraps the fixture result in pass/fail using the error message. 731 /// The test wraps the fixture result in pass/fail using the error message.
732 #[allow(unused_variables)] // relay_domain is now handled by fixture 732 #[allow(unused_variables)] // relay_domain is now handled by fixture