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 21:38:10 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2025-12-01 21:38:10 +0000
commit3c398b5e528f79231fa55f91225f9e79be1d43f5 (patch)
tree188bfffbc6a6fae59b5f0d401047f0c77fb2244b /grasp-audit/src/specs
parentbfbdd1c2fe2a556af099d79ea25d1b9bd1d3fd2c (diff)
better fixtures: MaintainerStateDataPushed
Diffstat (limited to 'grasp-audit/src/specs')
-rw-r--r--grasp-audit/src/specs/grasp01/push_authorization.rs228
1 files changed, 19 insertions, 209 deletions
diff --git a/grasp-audit/src/specs/grasp01/push_authorization.rs b/grasp-audit/src/specs/grasp01/push_authorization.rs
index f6a2314..2e14953 100644
--- a/grasp-audit/src/specs/grasp01/push_authorization.rs
+++ b/grasp-audit/src/specs/grasp01/push_authorization.rs
@@ -35,7 +35,7 @@ use crate::{
35 clone_repo, create_commit, create_deterministic_commit, 35 clone_repo, create_commit, create_deterministic_commit,
36 create_deterministic_commit_with_variant, try_push, try_push_to_ref, AuditClient, 36 create_deterministic_commit_with_variant, try_push, try_push_to_ref, AuditClient,
37 CommitVariant, FixtureKind, TestContext, TestResult, DETERMINISTIC_COMMIT_HASH, 37 CommitVariant, FixtureKind, TestContext, TestResult, DETERMINISTIC_COMMIT_HASH,
38 MAINTAINER_DETERMINISTIC_COMMIT_HASH, RECURSIVE_MAINTAINER_DETERMINISTIC_COMMIT_HASH, 38 MAINTAINER_DETERMINISTIC_COMMIT_HASH,
39}; 39};
40use nostr_sdk::prelude::*; 40use nostr_sdk::prelude::*;
41use std::fs; 41use std::fs;
@@ -814,234 +814,44 @@ impl PushAuthorizationTests {
814 /// Test push authorized by recursive maintainer state event 814 /// Test push authorized by recursive maintainer state event
815 /// 815 ///
816 /// GRASP-01: "respecting the recursive maintainer set" 816 /// GRASP-01: "respecting the recursive maintainer set"
817 /// This tests recursive maintainer chains: Owner -> MaintainerA -> MaintainerB 817 /// This tests recursive maintainer chains: Owner -> Maintainer -> RecursiveMaintainer
818 /// 818 ///
819 /// ## Fixture-First Pattern 819 /// This test uses the RecursiveMaintainerStateDataPushed fixture which handles all 4 stages:
820 /// 820 /// 1. **Generated**: Creates MaintainerStateDataPushed (owner's + maintainer's data pushed)
821 /// 1. **Generate**: Create TestContext and get fixture chain: 821 /// + MaintainerAnnouncement (maintainer lists recursive maintainer)
822 /// - RepoState (owner's repo announcement + state event) 822 /// + RecursiveMaintainerState (recursive maintainer's state event)
823 /// - MaintainerAnnouncement (maintainer lists recursive-maintainer) 823 /// 2. **Sent**: Sends events to relay
824 /// - MaintainerState (maintainer's state event) 824 /// 3. **Verified**: Confirms events accepted by relay
825 /// - RecursiveMaintainerRepoAndState (recursive maintainer's announcement + state) 825 /// 4. **DataPushed**: Clones repo, creates recursive maintainer deterministic commit, pushes to relay
826 /// 2. **Send**: Clone repo, create recursive maintainer deterministic commit, push
827 /// 3. **Verify**: Push should succeed because recursive maintainer's state event authorizes it
828 /// 826 ///
829 /// The fixture chain establishes: Owner -> Maintainer -> RecursiveMaintainer 827 /// The test wraps the fixture result in pass/fail using the error message.
830 /// Each level publishes announcements that authorize the next level. 828 #[allow(unused_variables)] // relay_domain is now handled by fixture
831 pub async fn test_push_authorized_by_recursive_maintainer_state( 829 pub async fn test_push_authorized_by_recursive_maintainer_state(
832 client: &AuditClient, 830 client: &AuditClient,
833 relay_domain: &str, 831 relay_domain: &str,
834 ) -> TestResult { 832 ) -> TestResult {
835 use std::process::Command;
836
837 let test_name = "test_push_authorized_by_recursive_maintainer_state"; 833 let test_name = "test_push_authorized_by_recursive_maintainer_state";
838
839 // ============================================================
840 // Step 1: GENERATE - Create TestContext and get fixture chain
841 // ============================================================
842 let ctx = TestContext::new(client); 834 let ctx = TestContext::new(client);
843 835
844 // Get RepoState fixture (owner's repo announcement + state event) 836 // The RecursiveMaintainerStateDataPushed fixture handles all stages:
845 let state_event = match ctx.get_fixture(FixtureKind::RepoState).await { 837 // Generate → Send → Verify → DataPush
846 Ok(e) => e, 838 match ctx.get_fixture(FixtureKind::RecursiveMaintainerStateDataPushed).await {
847 Err(e) => { 839 Ok(_recursive_maintainer_state_event) => {
848 return TestResult::new( 840 TestResult::new(
849 test_name,
850 "GRASP-01",
851 "Push authorized by recursive maintainer state event",
852 )
853 .fail(format!("Failed to create RepoState fixture: {}", e));
854 }
855 };
856
857 // Get MaintainerAnnouncement fixture (maintainer's repo announcement listing recursive maintainer)
858 match ctx.get_fixture(FixtureKind::MaintainerAnnouncement).await {
859 Ok(_) => {}
860 Err(e) => {
861 return TestResult::new(
862 test_name,
863 "GRASP-01",
864 "Push authorized by recursive maintainer state event",
865 )
866 .fail(format!(
867 "Failed to create MaintainerAnnouncement fixture: {}",
868 e
869 ));
870 }
871 };
872
873 // Get MaintainerState fixture (maintainer's state event)
874 match ctx.get_fixture(FixtureKind::MaintainerState).await {
875 Ok(_) => {}
876 Err(e) => {
877 return TestResult::new(
878 test_name,
879 "GRASP-01",
880 "Push authorized by recursive maintainer state event",
881 )
882 .fail(format!("Failed to create MaintainerState fixture: {}", e));
883 }
884 };
885
886 // Get RecursiveMaintainerRepoAndState fixture (completes 3-level delegation chain)
887 match ctx
888 .get_fixture(FixtureKind::RecursiveMaintainerRepoAndState)
889 .await
890 {
891 Ok(_) => {}
892 Err(e) => {
893 return TestResult::new(
894 test_name,
895 "GRASP-01",
896 "Push authorized by recursive maintainer state event",
897 )
898 .fail(format!(
899 "Failed to create RecursiveMaintainerRepoAndState fixture: {}",
900 e
901 ));
902 }
903 };
904
905 tokio::time::sleep(std::time::Duration::from_millis(200)).await;
906
907 // Extract repo_id and npub from owner's state event
908 let repo_id = match state_event
909 .tags
910 .iter()
911 .find(|t| t.kind() == TagKind::d())
912 .and_then(|t| t.content())
913 {
914 Some(id) => id.to_string(),
915 None => {
916 return TestResult::new(
917 test_name,
918 "GRASP-01",
919 "Push authorized by recursive maintainer state event",
920 )
921 .fail("Missing repo_id in state event");
922 }
923 };
924
925 let npub = match state_event.pubkey.to_bech32() {
926 Ok(n) => n,
927 Err(e) => {
928 return TestResult::new(
929 test_name,
930 "GRASP-01",
931 "Push authorized by recursive maintainer state event",
932 )
933 .fail(format!("Failed to convert pubkey to bech32: {}", e));
934 }
935 };
936
937 // ============================================================
938 // Step 2: SEND - Clone, create recursive maintainer commit, push
939 // ============================================================
940 let clone_path = match clone_repo(relay_domain, &npub, &repo_id) {
941 Ok(p) => p,
942 Err(e) => {
943 return TestResult::new(
944 test_name, 841 test_name,
945 "GRASP-01", 842 "GRASP-01",
946 "Push authorized by recursive maintainer state event", 843 "Push authorized by recursive maintainer state event",
947 ) 844 )
948 .fail(&e); 845 .pass()
949 } 846 }
950 };
951 let cleanup = || {
952 let _ = fs::remove_dir_all(&clone_path);
953 };
954
955 // Reset to orphan state and create deterministic root commit
956 // Step 1: Create orphan branch (removes all history)
957 let _ = Command::new("git")
958 .args(["checkout", "--orphan", "main-new"])
959 .current_dir(&clone_path)
960 .output();
961
962 // Step 2: Clear staged files (orphan keeps files staged from previous branch)
963 let _ = Command::new("git")
964 .args(["rm", "-rf", "--cached", "."])
965 .current_dir(&clone_path)
966 .output();
967
968 // Step 3: Create recursive maintainer deterministic commit
969 let commit_hash = match create_deterministic_commit_with_variant(
970 &clone_path,
971 CommitVariant::RecursiveMaintainer,
972 ) {
973 Ok(h) => h,
974 Err(e) => { 847 Err(e) => {
975 cleanup(); 848 TestResult::new(
976 return TestResult::new(
977 test_name, 849 test_name,
978 "GRASP-01", 850 "GRASP-01",
979 "Push authorized by recursive maintainer state event", 851 "Push authorized by recursive maintainer state event",
980 ) 852 )
981 .fail(format!( 853 .fail(format!("{}", e))
982 "Failed to create recursive maintainer commit: {}",
983 e
984 ));
985 } 854 }
986 };
987
988 // Step 4: Replace main branch with our new orphan branch
989 let _ = Command::new("git")
990 .args(["branch", "-D", "main"])
991 .current_dir(&clone_path)
992 .output();
993
994 let _ = Command::new("git")
995 .args(["branch", "-m", "main"])
996 .current_dir(&clone_path)
997 .output();
998
999 // Verify commit hash matches expected
1000 if commit_hash != RECURSIVE_MAINTAINER_DETERMINISTIC_COMMIT_HASH {
1001 cleanup();
1002 return TestResult::new(
1003 test_name,
1004 "GRASP-01",
1005 "Push authorized by recursive maintainer state event",
1006 )
1007 .fail(format!(
1008 "Recursive maintainer commit hash mismatch: got {}, expected {}",
1009 commit_hash, RECURSIVE_MAINTAINER_DETERMINISTIC_COMMIT_HASH
1010 ));
1011 }
1012
1013 // ============================================================
1014 // Step 3: VERIFY - Push should succeed because recursive
1015 // maintainer's state event authorizes this commit
1016 // ============================================================
1017 let push_result = try_push(&clone_path);
1018 cleanup();
1019
1020 match push_result {
1021 Ok(true) => TestResult::new(
1022 test_name,
1023 "GRASP-01",
1024 "Push authorized by recursive maintainer state event",
1025 )
1026 .pass(),
1027 Ok(false) => TestResult::new(
1028 test_name,
1029 "GRASP-01",
1030 "Push authorized by recursive maintainer state event",
1031 )
1032 .fail(format!(
1033 "Push was rejected but should have been accepted. \
1034 The recursive maintainer published a state event with commit {}, \
1035 and the relay should authorize pushes matching this state event \
1036 through recursive maintainer traversal (Owner -> Maintainer -> RecursiveMaintainer).",
1037 RECURSIVE_MAINTAINER_DETERMINISTIC_COMMIT_HASH
1038 )),
1039 Err(e) => TestResult::new(
1040 test_name,
1041 "GRASP-01",
1042 "Push authorized by recursive maintainer state event",
1043 )
1044 .fail(format!("Push error: {}", e)),
1045 } 855 }
1046 } 856 }
1047 857