mirror of
https://relay.ngit.dev/npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/ngit-grasp.git
synced 2026-10-05 15:08:24 +00:00
test: migrate tests and grasp-audit to rust-nostr 0.45.0-alpha.1
Complete the 0.45 migration for the integration tests (tests/) and the grasp-audit workspace member. - TagKind removed throughout: Tag::custom takes string literals; tag.kind() compared as &str; ref-name matches use the raw string. - EventBuilder finalize traits brought into scope where needed; Keys::sign_event is now sync (SignEvent trait). - Client API: new() is no-arg, NIP-42 auth via ClientBuilder::authenticator(SignerAuthenticator::new(keys)); fetch_events(filter).timeout(d); subscribe(filter); sync(filter).opts(); Output.val -> Output.value; Relay status via relay.status().is_connected(). - MemoryDatabase via nostr_memory (unbounded/bounded). - hashes imports moved from nostr_sdk::hashes to nostr::hashes. - SyncSummary.remote/received are now maps keyed by EventId. cargo build, cargo build --tests, cargo build -p grasp-audit --tests, cargo clippy --all-targets --workspace, and cargo fmt all clean. Lib unit tests (440) pass.
This commit is contained in:
@@ -131,19 +131,12 @@ impl AuditConfig {
|
||||
/// // ]
|
||||
/// ```
|
||||
pub fn audit_tags(&self) -> Vec<Tag> {
|
||||
use nostr_sdk::prelude::{Alphabet, SingleLetterTag};
|
||||
|
||||
// Use "t" tags for categorization (standard NIP-01 hashtag type)
|
||||
let t_tag = SingleLetterTag::lowercase(Alphabet::T);
|
||||
|
||||
vec![
|
||||
Tag::custom(TagKind::SingleLetter(t_tag), vec!["grasp-audit-test-event"]),
|
||||
Tag::custom("t", vec!["grasp-audit-test-event"]),
|
||||
Tag::custom("t", vec![format!("audit-{}", self.run_id)]),
|
||||
Tag::custom(
|
||||
TagKind::SingleLetter(t_tag),
|
||||
vec![format!("audit-{}", self.run_id)],
|
||||
),
|
||||
Tag::custom(
|
||||
TagKind::SingleLetter(t_tag),
|
||||
"t",
|
||||
vec![format!(
|
||||
"audit-cleanup-after-{}",
|
||||
self.cleanup_after.as_secs()
|
||||
@@ -228,7 +221,7 @@ impl AuditEventBuilder {
|
||||
builder
|
||||
};
|
||||
|
||||
let event = builder.sign_with_keys(keys)?;
|
||||
let event = builder.finalize(keys)?;
|
||||
|
||||
Ok(event)
|
||||
}
|
||||
@@ -256,22 +249,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_audit_tags() {
|
||||
use nostr_sdk::prelude::{Alphabet, SingleLetterTag};
|
||||
|
||||
let config = AuditConfig::isolated();
|
||||
let tags = config.audit_tags();
|
||||
|
||||
assert_eq!(tags.len(), 3);
|
||||
|
||||
let t_tag = SingleLetterTag::lowercase(Alphabet::T);
|
||||
|
||||
// All tags should be "t" tags (hashtags)
|
||||
for tag in &tags {
|
||||
if let TagKind::SingleLetter(letter) = tag.kind() {
|
||||
assert_eq!(letter, t_tag);
|
||||
} else {
|
||||
panic!("Expected SingleLetter tag");
|
||||
}
|
||||
assert_eq!(tag.kind(), "t", "Expected 't' (SingleLetter) tag");
|
||||
}
|
||||
|
||||
// Check for "t" tag with "grasp-audit-test-event"
|
||||
@@ -300,7 +285,7 @@ mod tests {
|
||||
let keys = Keys::generate();
|
||||
|
||||
let event = AuditEventBuilder::new(Kind::TextNote, "test", config.clone())
|
||||
.tag(Tag::custom(TagKind::Custom("test".into()), vec!["value"]))
|
||||
.tag(Tag::custom("test", vec!["value"]))
|
||||
.build(&keys)
|
||||
.unwrap();
|
||||
|
||||
|
||||
+37
-37
@@ -42,7 +42,9 @@ impl AuditClient {
|
||||
let maintainer_keys = Keys::generate();
|
||||
let recursive_maintainer_keys = Keys::generate();
|
||||
let pr_author_keys = Keys::generate();
|
||||
let client = Client::new(keys.clone());
|
||||
let client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(keys.clone()))
|
||||
.build();
|
||||
Self {
|
||||
client,
|
||||
config,
|
||||
@@ -61,7 +63,9 @@ impl AuditClient {
|
||||
let maintainer_keys = Keys::generate();
|
||||
let recursive_maintainer_keys = Keys::generate();
|
||||
let pr_author_keys = Keys::generate();
|
||||
let client = Client::new(keys.clone());
|
||||
let client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(keys.clone()))
|
||||
.build();
|
||||
|
||||
// Add relay and connect
|
||||
client.add_relay(relay_url).await?;
|
||||
@@ -74,7 +78,7 @@ impl AuditClient {
|
||||
tokio::time::sleep(Duration::from_millis(100)).await;
|
||||
|
||||
let relays = client.relays().await;
|
||||
connected = relays.values().any(|r| r.is_connected());
|
||||
connected = relays.values().any(|r| r.status().is_connected());
|
||||
|
||||
if connected {
|
||||
break;
|
||||
@@ -129,7 +133,9 @@ impl AuditClient {
|
||||
let maintainer_keys = Keys::generate();
|
||||
let recursive_maintainer_keys = Keys::generate();
|
||||
let pr_author_keys = Keys::generate();
|
||||
let client = Client::new(keys.clone());
|
||||
let client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(keys.clone()))
|
||||
.build();
|
||||
|
||||
// Add relay and connect
|
||||
client.add_relay(relay_url).await?;
|
||||
@@ -142,7 +148,7 @@ impl AuditClient {
|
||||
tokio::time::sleep(Duration::from_millis(100)).await;
|
||||
|
||||
let relays = client.relays().await;
|
||||
connected = relays.values().any(|r| r.is_connected());
|
||||
connected = relays.values().any(|r| r.status().is_connected());
|
||||
|
||||
if connected {
|
||||
break;
|
||||
@@ -235,7 +241,7 @@ impl AuditClient {
|
||||
// Check if we have any connected relays
|
||||
let relays = self.client.relays().await;
|
||||
for relay in relays.values() {
|
||||
if relay.is_connected() {
|
||||
if relay.status().is_connected() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -326,7 +332,8 @@ impl AuditClient {
|
||||
pub async fn is_event_on_relay(&self, id: EventId) -> Result<bool> {
|
||||
Ok(!self
|
||||
.client
|
||||
.fetch_events(vec![Filter::new().id(id)], Duration::from_secs(1))
|
||||
.fetch_events(vec![Filter::new().id(id)])
|
||||
.timeout(Duration::from_secs(1))
|
||||
.await
|
||||
.context("error trying to query relay for event")?
|
||||
.is_empty())
|
||||
@@ -355,7 +362,7 @@ impl AuditClient {
|
||||
///
|
||||
/// // Create event with automatic audit tags
|
||||
/// let event = client.event_builder(Kind::TextNote, "test content")
|
||||
/// .tag(Tag::custom(TagKind::custom("custom"), vec!["value"]))
|
||||
/// .tag(Tag::custom("custom", vec!["value"]))
|
||||
/// .build(client.keys())?;
|
||||
///
|
||||
/// // Event now has both your custom tag AND the 3 audit tags
|
||||
@@ -384,7 +391,8 @@ impl AuditClient {
|
||||
|
||||
let events = self
|
||||
.client
|
||||
.fetch_events(filter, Duration::from_secs(5))
|
||||
.fetch_events(filter)
|
||||
.timeout(Duration::from_secs(5))
|
||||
.await?;
|
||||
|
||||
Ok(events.into_iter().collect())
|
||||
@@ -400,7 +408,7 @@ impl AuditClient {
|
||||
let mut all_events = Vec::new();
|
||||
|
||||
for filter in filters {
|
||||
let events = self.client.fetch_events(filter, timeout).await?;
|
||||
let events = self.client.fetch_events(filter).timeout(timeout).await?;
|
||||
all_events.extend(events.into_iter());
|
||||
}
|
||||
|
||||
@@ -498,25 +506,19 @@ impl AuditClient {
|
||||
)
|
||||
.tag(Tag::identifier(&repo_id))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("name"),
|
||||
"name",
|
||||
vec![format!("{} Test Repository", test_name)],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("description"),
|
||||
"description",
|
||||
vec![format!("Repository for {} testing", test_name)],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
"clone",
|
||||
vec![format!("{}/{}/{}.git", http_url, npub, repo_id)],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("relays"),
|
||||
vec![relay_url.clone()],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("maintainers"),
|
||||
maintainer_pubkeys.to_vec(),
|
||||
))
|
||||
.tag(Tag::custom("relays", vec![relay_url.clone()]))
|
||||
.tag(Tag::custom("maintainers", maintainer_pubkeys.to_vec()))
|
||||
.build(signing_keys)
|
||||
.map_err(|e| anyhow!("Failed to build repository announcement event: {}", e))?;
|
||||
|
||||
@@ -589,7 +591,7 @@ impl AuditClient {
|
||||
let repo_id = repo_event
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.ok_or_else(|| anyhow!("Repository event must have a 'd' tag"))?
|
||||
.to_string();
|
||||
@@ -598,8 +600,8 @@ impl AuditClient {
|
||||
let a_tag_value = format!("30617:{}:{}", repo_pubkey, repo_id);
|
||||
|
||||
let mut tags = vec![
|
||||
Tag::custom(TagKind::custom("a"), vec![a_tag_value]),
|
||||
Tag::custom(TagKind::custom("subject"), vec![issue_title]),
|
||||
Tag::custom("a", vec![a_tag_value]),
|
||||
Tag::custom("subject", vec![issue_title]),
|
||||
];
|
||||
|
||||
// Add any additional tags
|
||||
@@ -632,11 +634,11 @@ impl AuditClient {
|
||||
|
||||
let mut tags = vec![
|
||||
Tag::custom(
|
||||
TagKind::custom("E"),
|
||||
"E",
|
||||
vec![event_id.to_hex(), "".to_string(), "root".to_string()],
|
||||
),
|
||||
Tag::event(event_id),
|
||||
Tag::custom(TagKind::custom("K"), vec![event_kind.as_u16().to_string()]),
|
||||
Tag::custom("K", vec![event_kind.as_u16().to_string()]),
|
||||
Tag::public_key(event_pubkey),
|
||||
];
|
||||
|
||||
@@ -677,7 +679,9 @@ mod tests {
|
||||
let recursive_maintainer_keys = Keys::generate();
|
||||
let pr_author_keys = Keys::generate();
|
||||
let client = AuditClient {
|
||||
client: Client::new(keys.clone()),
|
||||
client: Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(keys.clone()))
|
||||
.build(),
|
||||
config: config.clone(),
|
||||
keys: keys.clone(),
|
||||
maintainer_keys,
|
||||
@@ -701,7 +705,9 @@ mod tests {
|
||||
let recursive_maintainer_keys = Keys::generate();
|
||||
let pr_author_keys = Keys::generate();
|
||||
let client = AuditClient {
|
||||
client: Client::new(keys.clone()),
|
||||
client: Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(keys.clone()))
|
||||
.build(),
|
||||
config: config.clone(),
|
||||
keys: keys.clone(),
|
||||
maintainer_keys,
|
||||
@@ -714,7 +720,7 @@ mod tests {
|
||||
// Create an event with a custom tag
|
||||
let event = client
|
||||
.event_builder(Kind::TextNote, "test content")
|
||||
.tag(Tag::custom(TagKind::custom("custom"), vec!["value"]))
|
||||
.tag(Tag::custom("custom", vec!["value"]))
|
||||
.build(&keys)
|
||||
.unwrap();
|
||||
|
||||
@@ -776,18 +782,12 @@ mod tests {
|
||||
let event = client
|
||||
.event_builder(Kind::GitRepoAnnouncement, "Test repository")
|
||||
.tag(Tag::identifier("test-repo"))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("maintainers"),
|
||||
maintainer_pubkeys.clone(),
|
||||
))
|
||||
.tag(Tag::custom("maintainers", maintainer_pubkeys.clone()))
|
||||
.build(client.keys())
|
||||
.unwrap();
|
||||
|
||||
// Verify the maintainers tag is present and correctly formatted
|
||||
let maintainers_tag = event
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::custom("maintainers"));
|
||||
let maintainers_tag = event.tags.iter().find(|t| t.kind() == "maintainers");
|
||||
|
||||
assert!(
|
||||
maintainers_tag.is_some(),
|
||||
|
||||
+29
-42
@@ -962,7 +962,7 @@ impl<'a> TestContext<'a> {
|
||||
let repo_id = repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.ok_or_else(|| anyhow::anyhow!("Missing d tag in repo announcement"))?
|
||||
.to_string();
|
||||
@@ -977,11 +977,11 @@ impl<'a> TestContext<'a> {
|
||||
.event_builder(Kind::RepoState, "")
|
||||
.tag(Tag::identifier(&repo_id))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("refs/heads/main"),
|
||||
"refs/heads/main",
|
||||
vec![DETERMINISTIC_COMMIT_HASH.to_string()],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("HEAD"),
|
||||
"HEAD",
|
||||
vec!["ref: refs/heads/main".to_string()],
|
||||
))
|
||||
.custom_time(older_timestamp)
|
||||
@@ -1004,11 +1004,11 @@ impl<'a> TestContext<'a> {
|
||||
.event_builder(Kind::RepoState, "")
|
||||
.tag(Tag::identifier(&repo_id))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("refs/heads/main"),
|
||||
"refs/heads/main",
|
||||
vec![DETERMINISTIC_COMMIT_HASH.to_string()],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("HEAD"),
|
||||
"HEAD",
|
||||
vec!["ref: refs/heads/main".to_string()],
|
||||
))
|
||||
.custom_time(older_timestamp)
|
||||
@@ -1032,7 +1032,7 @@ impl<'a> TestContext<'a> {
|
||||
let repo_id = repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.ok_or_else(|| anyhow::anyhow!("Missing repo_id in ValidRepoServed fixture"))?
|
||||
.to_string();
|
||||
@@ -1048,17 +1048,14 @@ impl<'a> TestContext<'a> {
|
||||
"Test PR for GRASP validation",
|
||||
)
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("a"),
|
||||
"a",
|
||||
vec![format!(
|
||||
"30617:{}:{}",
|
||||
self.client.public_key().to_hex(), // Owner pubkey
|
||||
repo_id
|
||||
)],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("c"),
|
||||
vec![PR_TEST_COMMIT_HASH.to_string()],
|
||||
))
|
||||
.tag(Tag::custom("c", vec![PR_TEST_COMMIT_HASH.to_string()]))
|
||||
.custom_time(pr_timestamp)
|
||||
.build(self.client.pr_author_keys())
|
||||
.map_err(|e| anyhow::anyhow!("Failed to build PR event: {}", e))
|
||||
@@ -1075,7 +1072,7 @@ impl<'a> TestContext<'a> {
|
||||
let repo_id = repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.ok_or_else(|| anyhow::anyhow!("Missing repo_id in ValidRepoServed fixture"))?
|
||||
.to_string();
|
||||
@@ -1091,17 +1088,14 @@ impl<'a> TestContext<'a> {
|
||||
"Test PR for GRASP validation",
|
||||
)
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("a"),
|
||||
"a",
|
||||
vec![format!(
|
||||
"30617:{}:{}",
|
||||
self.client.public_key().to_hex(), // Owner pubkey
|
||||
repo_id
|
||||
)],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("c"),
|
||||
vec![PR_TEST_COMMIT_HASH.to_string()],
|
||||
))
|
||||
.tag(Tag::custom("c", vec![PR_TEST_COMMIT_HASH.to_string()]))
|
||||
.custom_time(pr_timestamp)
|
||||
.build(self.client.pr_author_keys())
|
||||
.map_err(|e| anyhow::anyhow!("Failed to build PR event: {}", e))
|
||||
@@ -1172,16 +1166,16 @@ impl<'a> TestContext<'a> {
|
||||
)
|
||||
.tag(Tag::identifier(repo_id))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("name"),
|
||||
"name",
|
||||
vec![format!("{} (maintainer)", repo_id)],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
"clone",
|
||||
vec![format!("{}/{}/{}.git", http_url, maintainer_npub, repo_id)],
|
||||
))
|
||||
.tag(Tag::custom(TagKind::custom("relays"), vec![relay_url]))
|
||||
.tag(Tag::custom("relays", vec![relay_url]))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("maintainers"),
|
||||
"maintainers",
|
||||
vec![self.client.recursive_maintainer_pubkey_hex()],
|
||||
))
|
||||
.build(self.client.maintainer_keys())
|
||||
@@ -1190,10 +1184,9 @@ impl<'a> TestContext<'a> {
|
||||
|
||||
/// Extract repo_id from a repo announcement event
|
||||
fn extract_repo_id(&self, repo: &Event) -> Result<String> {
|
||||
use nostr_sdk::prelude::*;
|
||||
repo.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.map(|s| s.to_string())
|
||||
.ok_or_else(|| anyhow::anyhow!("Missing d tag in repo announcement"))
|
||||
@@ -1225,12 +1218,12 @@ impl<'a> TestContext<'a> {
|
||||
.client
|
||||
.event_builder(Kind::GitRepoAnnouncement, "")
|
||||
.tag(Tag::identifier(&repo_id))
|
||||
.tag(Tag::custom(TagKind::custom("name"), vec![repo_id.clone()]))
|
||||
.tag(Tag::custom("name", vec![repo_id.clone()]))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
"clone",
|
||||
vec![format!("{}/{}/{}.git", http_url, npub, repo_id)],
|
||||
))
|
||||
.tag(Tag::custom(TagKind::custom("relays"), vec![relay_url]))
|
||||
.tag(Tag::custom("relays", vec![relay_url]))
|
||||
.build(self.client.keys())
|
||||
.map_err(|e| anyhow::anyhow!("Failed to build repo announcement: {}", e))?;
|
||||
|
||||
@@ -1274,11 +1267,11 @@ impl<'a> TestContext<'a> {
|
||||
.event_builder(Kind::RepoState, "")
|
||||
.tag(Tag::identifier(&repo_id))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("refs/heads/main"),
|
||||
"refs/heads/main",
|
||||
vec![DETERMINISTIC_COMMIT_HASH.to_string()],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("HEAD"),
|
||||
"HEAD",
|
||||
vec!["ref: refs/heads/main".to_string()],
|
||||
))
|
||||
.custom_time(older_timestamp)
|
||||
@@ -1540,11 +1533,11 @@ impl<'a> TestContext<'a> {
|
||||
.event_builder(Kind::RepoState, "")
|
||||
.tag(Tag::identifier(&repo_id))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("refs/heads/main"),
|
||||
"refs/heads/main",
|
||||
vec![MAINTAINER_DETERMINISTIC_COMMIT_HASH.to_string()],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("HEAD"),
|
||||
"HEAD",
|
||||
vec!["ref: refs/heads/main".to_string()],
|
||||
))
|
||||
.custom_time(maintainer_timestamp)
|
||||
@@ -1715,11 +1708,11 @@ impl<'a> TestContext<'a> {
|
||||
.event_builder(Kind::RepoState, "")
|
||||
.tag(Tag::identifier(&repo_id))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("refs/heads/main"),
|
||||
"refs/heads/main",
|
||||
vec![RECURSIVE_MAINTAINER_DETERMINISTIC_COMMIT_HASH.to_string()],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("HEAD"),
|
||||
"HEAD",
|
||||
vec!["ref: refs/heads/main".to_string()],
|
||||
))
|
||||
.custom_time(recursive_maintainer_timestamp)
|
||||
@@ -1883,12 +1876,9 @@ impl<'a> TestContext<'a> {
|
||||
.client
|
||||
.event_builder(Kind::RepoState, "")
|
||||
.tag(Tag::identifier(&repo_id))
|
||||
.tag(Tag::custom("HEAD", vec!["refs/heads/develop".to_string()]))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("HEAD"),
|
||||
vec!["refs/heads/develop".to_string()],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("refs/heads/develop"),
|
||||
"refs/heads/develop",
|
||||
vec![RECURSIVE_MAINTAINER_DETERMINISTIC_COMMIT_HASH.to_string()],
|
||||
))
|
||||
.custom_time(develop_timestamp)
|
||||
@@ -2043,17 +2033,14 @@ impl<'a> TestContext<'a> {
|
||||
self.client
|
||||
.event_builder(Kind::GitPullRequest, "Test PR 2 for GRASP validation")
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("a"),
|
||||
"a",
|
||||
vec![format!(
|
||||
"30617:{}:{}",
|
||||
self.client.public_key().to_hex(),
|
||||
repo_id
|
||||
)],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("c"),
|
||||
vec![PR_TEST_COMMIT_HASH_2.to_string()],
|
||||
))
|
||||
.tag(Tag::custom("c", vec![PR_TEST_COMMIT_HASH_2.to_string()]))
|
||||
.custom_time(pr_timestamp)
|
||||
.build(self.client.pr_author_keys())
|
||||
.map_err(|e| anyhow::anyhow!("Failed to build PR event 2: {}", e))
|
||||
|
||||
+15
-33
@@ -324,18 +324,9 @@ pub async fn run_probe(
|
||||
config.clone(),
|
||||
)
|
||||
.tag(Tag::identifier(&repo_id))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("name"),
|
||||
vec!["GRASP Probe Repository"],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
vec![clone_url.clone()],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("relays"),
|
||||
vec![relay_url.to_string()],
|
||||
))
|
||||
.tag(Tag::custom("name", vec!["GRASP Probe Repository"]))
|
||||
.tag(Tag::custom("clone", vec![clone_url.clone()]))
|
||||
.tag(Tag::custom("relays", vec![relay_url.to_string()]))
|
||||
.build(&keys);
|
||||
|
||||
announcement_event_opt = ann_result.ok();
|
||||
@@ -343,12 +334,9 @@ pub async fn run_probe(
|
||||
let state_result = if let Some(ref ch) = commit_hash {
|
||||
crate::audit::AuditEventBuilder::new(Kind::RepoState, "", config.clone())
|
||||
.tag(Tag::identifier(&repo_id))
|
||||
.tag(Tag::custom("refs/heads/main", vec![ch.clone()]))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("refs/heads/main"),
|
||||
vec![ch.clone()],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("HEAD"),
|
||||
"HEAD",
|
||||
vec!["ref: refs/heads/main".to_string()],
|
||||
))
|
||||
.build(&keys)
|
||||
@@ -819,10 +807,7 @@ pub async fn run_probe(
|
||||
|
||||
if let Some(ref state_ev) = state_event_opt {
|
||||
for tag in state_ev.tags.iter() {
|
||||
let kind_str = match tag.kind() {
|
||||
TagKind::Custom(ref s) => s.clone(),
|
||||
_ => continue,
|
||||
};
|
||||
let kind_str = tag.kind().to_string();
|
||||
// Only check refs/heads/* and refs/tags/*, skip HEAD and refs/nostr/*
|
||||
if !kind_str.starts_with("refs/heads/")
|
||||
&& !kind_str.starts_with("refs/tags/")
|
||||
@@ -886,8 +871,8 @@ pub async fn run_probe(
|
||||
let filter = Filter::new().kind(Kind::GitRepoAnnouncement).limit(1);
|
||||
let existing = client
|
||||
.client()
|
||||
.fetch_events(
|
||||
filter,
|
||||
.fetch_events(filter)
|
||||
.timeout(
|
||||
deadline
|
||||
.saturating_duration_since(Instant::now())
|
||||
.min(Duration::from_secs(5)),
|
||||
@@ -905,7 +890,7 @@ pub async fn run_probe(
|
||||
let ann_id = ev
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.unwrap_or("unknown")
|
||||
.to_string();
|
||||
@@ -947,7 +932,7 @@ pub async fn run_probe(
|
||||
let ann_id = ev
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.unwrap_or("unknown")
|
||||
.to_string();
|
||||
@@ -956,7 +941,7 @@ pub async fn run_probe(
|
||||
let fetch_url = ev
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::custom("clone"))
|
||||
.find(|t| t.kind() == "clone")
|
||||
.and_then(|t| t.content())
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or_else(|| format!("{}/{}/{}.git", http_base, ann_npub, ann_id));
|
||||
@@ -1054,8 +1039,8 @@ pub async fn run_probe(
|
||||
);
|
||||
let state_events = client
|
||||
.client()
|
||||
.fetch_events(
|
||||
state_filter,
|
||||
.fetch_events(state_filter)
|
||||
.timeout(
|
||||
deadline
|
||||
.saturating_duration_since(Instant::now())
|
||||
.min(Duration::from_secs(5)),
|
||||
@@ -1087,10 +1072,7 @@ pub async fn run_probe(
|
||||
for state_ev in state_events.iter() {
|
||||
let ts = state_ev.created_at.as_secs();
|
||||
for tag in state_ev.tags.iter() {
|
||||
let kind_str = match tag.kind() {
|
||||
TagKind::Custom(ref s) => s.clone(),
|
||||
_ => continue,
|
||||
};
|
||||
let kind_str = tag.kind().to_string();
|
||||
if !kind_str.starts_with("refs/heads/")
|
||||
&& !kind_str.starts_with("refs/tags/")
|
||||
{
|
||||
@@ -1101,7 +1083,7 @@ pub async fn run_probe(
|
||||
None => continue,
|
||||
};
|
||||
let prev_ts =
|
||||
latest_ts.get(kind_str.as_ref()).copied().unwrap_or(0);
|
||||
latest_ts.get(kind_str.as_str()).copied().unwrap_or(0);
|
||||
if ts >= prev_ts {
|
||||
expected.insert(kind_str.to_string(), hash);
|
||||
latest_ts.insert(kind_str.to_string(), ts);
|
||||
|
||||
@@ -265,7 +265,7 @@ impl CorsTests {
|
||||
let repo_id = match repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
{
|
||||
Some(id) => id.to_string(),
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
use crate::fixtures::{send_and_verify_accepted, send_and_verify_rejected};
|
||||
use crate::specs::grasp01::SpecRef;
|
||||
use crate::{AuditClient, AuditResult, FixtureKind, TestContext, TestResult};
|
||||
use nostr_sdk::{Event, Filter, Kind, Tag, TagKind, Timestamp, ToBech32};
|
||||
use nostr_sdk::prelude::{Event, Filter, Kind, Tag, Timestamp, ToBech32};
|
||||
use std::time::Duration;
|
||||
|
||||
/// Test suite for GRASP-01 event acceptance policy
|
||||
@@ -186,7 +186,7 @@ impl EventAcceptancePolicyTests {
|
||||
let repo_id = event
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.ok_or("Missing d tag in announcement")?
|
||||
.to_string();
|
||||
@@ -221,13 +221,13 @@ impl EventAcceptancePolicyTests {
|
||||
|
||||
// Verify key tags are present
|
||||
let has_clone_tag = stored_event.tags.iter().any(|t| {
|
||||
t.kind() == TagKind::Custom("clone".into())
|
||||
&& t.content().map(|c| c.contains(&http_url)).unwrap_or(false)
|
||||
t.kind() == "clone" && t.content().map(|c| c.contains(&http_url)).unwrap_or(false)
|
||||
});
|
||||
|
||||
let has_relays_tag = stored_event.tags.iter().any(|t| {
|
||||
t.kind() == TagKind::Custom("relays".into()) && t.content() == Some(&relay_url)
|
||||
});
|
||||
let has_relays_tag = stored_event
|
||||
.tags
|
||||
.iter()
|
||||
.any(|t| t.kind() == "relays" && t.content() == Some(&relay_url));
|
||||
|
||||
if !has_clone_tag {
|
||||
return Err(format!(
|
||||
@@ -279,18 +279,12 @@ impl EventAcceptancePolicyTests {
|
||||
let event = client
|
||||
.event_builder(Kind::GitRepoAnnouncement, "")
|
||||
.tag(Tag::identifier(&repo_id))
|
||||
.tag(Tag::custom("name", vec!["Test Repo No Clone"]))
|
||||
.tag(Tag::custom(
|
||||
TagKind::Custom("name".into()),
|
||||
vec!["Test Repo No Clone"],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::Custom("clone".into()),
|
||||
"clone",
|
||||
vec!["https://github.com/user/repo.git"],
|
||||
)) // NOT this service
|
||||
.tag(Tag::custom(
|
||||
TagKind::Custom("relays".into()),
|
||||
vec![relay_url.clone()],
|
||||
)) // Correct relay
|
||||
.tag(Tag::custom("relays", vec![relay_url.clone()])) // Correct relay
|
||||
.build(client.keys())
|
||||
.map_err(|e| format!("Failed to build event: {}", e))?;
|
||||
|
||||
@@ -360,22 +354,16 @@ impl EventAcceptancePolicyTests {
|
||||
let event = client
|
||||
.event_builder(Kind::GitRepoAnnouncement, "")
|
||||
.tag(Tag::identifier(&repo_id))
|
||||
.tag(Tag::custom("name", vec!["Test Repo No Relays"]))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("name"),
|
||||
vec!["Test Repo No Relays"],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
"clone",
|
||||
vec![format!(
|
||||
"{}/{}/test-repo.git",
|
||||
http_url,
|
||||
client.public_key()
|
||||
)],
|
||||
)) // Correct clone
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("relays"),
|
||||
vec!["wss://relay.damus.io"],
|
||||
)) // NOT this service
|
||||
.tag(Tag::custom("relays", vec!["wss://relay.damus.io"])) // NOT this service
|
||||
.build(client.keys())
|
||||
.map_err(|e| format!("Failed to build event: {}", e))?;
|
||||
|
||||
@@ -454,7 +442,7 @@ impl EventAcceptancePolicyTests {
|
||||
let repo_id = recursive_state
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.ok_or("Missing d tag in recursive maintainer state")?
|
||||
.to_string();
|
||||
@@ -479,12 +467,12 @@ impl EventAcceptancePolicyTests {
|
||||
)
|
||||
.tag(Tag::identifier(&repo_id))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("name"),
|
||||
"name",
|
||||
vec![format!("{} (recursive maintainer view)", repo_id)],
|
||||
))
|
||||
// Clone points to another server, NOT the GRASP server
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
"clone",
|
||||
vec![format!(
|
||||
"https://another-grasp-server.com/{}/{}.git",
|
||||
recursive_maintainer_npub, repo_id
|
||||
@@ -492,7 +480,7 @@ impl EventAcceptancePolicyTests {
|
||||
))
|
||||
// Relays also points elsewhere (not this server)
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("relays"),
|
||||
"relays",
|
||||
vec!["wss://relay.damus.io"],
|
||||
))
|
||||
.build(client.recursive_maintainer_keys())
|
||||
@@ -661,10 +649,10 @@ impl EventAcceptancePolicyTests {
|
||||
// Create comment with `A` tag (root reference to repo)
|
||||
let tags = vec![
|
||||
Tag::custom(
|
||||
TagKind::custom("A"),
|
||||
"A",
|
||||
vec![a_tag_value.clone(), "".to_string(), "root".to_string()],
|
||||
),
|
||||
Tag::custom(TagKind::custom("K"), vec!["30617".to_string()]),
|
||||
Tag::custom("K", vec!["30617".to_string()]),
|
||||
Tag::public_key(repo.pubkey),
|
||||
];
|
||||
|
||||
@@ -715,7 +703,7 @@ impl EventAcceptancePolicyTests {
|
||||
let a_tag_value = format!("30617:{}:{}", repo.pubkey, repo_id);
|
||||
|
||||
// Create kind 1 note with `q` tag (quote reference to repo)
|
||||
let tags = vec![Tag::custom(TagKind::custom("q"), vec![a_tag_value])];
|
||||
let tags = vec![Tag::custom("q", vec![a_tag_value])];
|
||||
|
||||
let note = client
|
||||
.event_builder(Kind::TextNote, "Mentioning this repo")
|
||||
@@ -766,8 +754,7 @@ impl EventAcceptancePolicyTests {
|
||||
let repo_b = Self::create_test_repo(client, "repo-b").await?;
|
||||
|
||||
// Create Issue B that quotes accepted Issue A via 'q' tag (should make it accepted)
|
||||
let additional_tags =
|
||||
vec![Tag::custom(TagKind::custom("q"), vec![issue_a.id.to_hex()])];
|
||||
let additional_tags = vec![Tag::custom("q", vec![issue_a.id.to_hex()])];
|
||||
|
||||
let issue_b = client
|
||||
.create_issue(&repo_b, "Issue B", "issue content", additional_tags)
|
||||
@@ -853,7 +840,7 @@ impl EventAcceptancePolicyTests {
|
||||
|
||||
let kind1_a = client
|
||||
.event_builder(Kind::TextNote, "Note A about repo")
|
||||
.tags(vec![Tag::custom(TagKind::custom("q"), vec![a_tag_value])])
|
||||
.tags(vec![Tag::custom("q", vec![a_tag_value])])
|
||||
.build(client.keys())
|
||||
.map_err(|e| format!("Failed to build kind1 A: {}", e))?;
|
||||
|
||||
@@ -938,19 +925,16 @@ impl EventAcceptancePolicyTests {
|
||||
let issue_tags = vec![
|
||||
// Reference to accepted repo
|
||||
Tag::custom(
|
||||
TagKind::custom("a"),
|
||||
"a",
|
||||
vec![format!(
|
||||
"30617:{}:{}",
|
||||
repo.pubkey,
|
||||
Self::extract_d_tag(&repo).unwrap()
|
||||
)],
|
||||
),
|
||||
Tag::custom(
|
||||
TagKind::custom("subject"),
|
||||
vec!["Issue referencing kind1".to_string()],
|
||||
),
|
||||
Tag::custom("subject", vec!["Issue referencing kind1".to_string()]),
|
||||
// Quote the Kind 1 that hasn't been sent yet
|
||||
Tag::custom(TagKind::custom("q"), vec![kind1_note.id.to_hex()]),
|
||||
Tag::custom("q", vec![kind1_note.id.to_hex()]),
|
||||
];
|
||||
|
||||
let issue = client
|
||||
@@ -1003,14 +987,14 @@ impl EventAcceptancePolicyTests {
|
||||
let comment_b_tags = vec![
|
||||
// NIP-22 tags for the original issue
|
||||
Tag::custom(
|
||||
TagKind::custom("E"),
|
||||
"E",
|
||||
vec![issue.id.to_hex(), "".to_string(), "root".to_string()],
|
||||
),
|
||||
Tag::event(issue.id),
|
||||
Tag::custom(TagKind::custom("K"), vec![issue.kind.as_u16().to_string()]),
|
||||
Tag::custom("K", vec![issue.kind.as_u16().to_string()]),
|
||||
Tag::public_key(issue.pubkey),
|
||||
// Quote Comment A which hasn't been sent yet
|
||||
Tag::custom(TagKind::custom("q"), vec![comment_a.id.to_hex()]),
|
||||
Tag::custom("q", vec![comment_a.id.to_hex()]),
|
||||
];
|
||||
|
||||
let comment_b = client
|
||||
@@ -1077,8 +1061,8 @@ impl EventAcceptancePolicyTests {
|
||||
let kind1_b = client
|
||||
.event_builder(Kind::TextNote, "Note B mentioning Note A")
|
||||
.tags(vec![
|
||||
Tag::custom(TagKind::custom("q"), vec![a_tag_value]), // Quote repo (accepted)
|
||||
Tag::event(kind1_a.id), // Mention unsent Kind 1 A
|
||||
Tag::custom("q", vec![a_tag_value]), // Quote repo (accepted)
|
||||
Tag::event(kind1_a.id), // Mention unsent Kind 1 A
|
||||
])
|
||||
.build(client.keys())
|
||||
.map_err(|e| format!("Failed to build kind1 B: {}", e))?;
|
||||
@@ -1188,11 +1172,8 @@ impl EventAcceptancePolicyTests {
|
||||
|
||||
// Create comment that references ONLY repo B (unaccepted)
|
||||
let tags = vec![
|
||||
Tag::custom(
|
||||
TagKind::custom("A"),
|
||||
vec![repo_b_a_tag, "".to_string(), "root".to_string()],
|
||||
),
|
||||
Tag::custom(TagKind::custom("K"), vec!["30617".to_string()]),
|
||||
Tag::custom("A", vec![repo_b_a_tag, "".to_string(), "root".to_string()]),
|
||||
Tag::custom("K", vec!["30617".to_string()]),
|
||||
Tag::public_key(repo_b.pubkey),
|
||||
];
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ impl GitCloneTests {
|
||||
let repo_id = match repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
{
|
||||
Some(id) => id.to_string(),
|
||||
@@ -189,7 +189,7 @@ impl GitCloneTests {
|
||||
let repo_id = repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.ok_or("Missing d tag")
|
||||
.unwrap()
|
||||
@@ -293,7 +293,7 @@ impl GitCloneTests {
|
||||
let repo_id = match repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
{
|
||||
Some(id) => id.to_string(),
|
||||
|
||||
@@ -81,7 +81,7 @@ impl GitFilterTests {
|
||||
let repo_id = match repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
{
|
||||
Some(id) => id.to_string(),
|
||||
@@ -203,7 +203,7 @@ impl GitFilterTests {
|
||||
let repo_id = repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.ok_or("Missing d tag")
|
||||
.unwrap()
|
||||
@@ -314,7 +314,7 @@ impl GitFilterTests {
|
||||
let repo_id = repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.ok_or("Missing d tag")
|
||||
.unwrap()
|
||||
|
||||
@@ -92,7 +92,8 @@ impl Nip01SmokeTests {
|
||||
let direct_filter = Filter::new().kind(Kind::GitRepoAnnouncement).id(event_id);
|
||||
let direct_events = client
|
||||
.client()
|
||||
.fetch_events(direct_filter, std::time::Duration::from_secs(5))
|
||||
.fetch_events(direct_filter)
|
||||
.timeout(std::time::Duration::from_secs(5))
|
||||
.await
|
||||
.map_err(|e| format!("Direct query failed: {}", e))?;
|
||||
let direct_vec: Vec<Event> = direct_events.into_iter().collect();
|
||||
@@ -209,7 +210,7 @@ impl Nip01SmokeTests {
|
||||
let wrong_keys = Keys::generate();
|
||||
let wrong_event = EventBuilder::new(event.kind, event.content.clone())
|
||||
.tags(event.tags.clone())
|
||||
.sign_with_keys(&wrong_keys)
|
||||
.finalize(&wrong_keys)
|
||||
.map_err(|e| format!("Failed to build wrong event: {}", e))?;
|
||||
|
||||
// Create event JSON with mismatched pubkey and signature
|
||||
|
||||
@@ -102,7 +102,7 @@ impl PurgatoryTests {
|
||||
let repo_id = repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.ok_or("Missing d tag in repo announcement")?
|
||||
.to_string();
|
||||
@@ -168,7 +168,7 @@ impl PurgatoryTests {
|
||||
let repo_id = state_event
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.ok_or("Missing d tag in state event")?
|
||||
.to_string();
|
||||
@@ -242,7 +242,7 @@ impl PurgatoryTests {
|
||||
let repo_id = repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.ok_or("Missing d tag in repo announcement")?
|
||||
.to_string();
|
||||
@@ -323,7 +323,7 @@ impl PurgatoryTests {
|
||||
let repo_id = repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.ok_or("Missing d tag in repo announcement")?
|
||||
.to_string();
|
||||
@@ -332,11 +332,11 @@ impl PurgatoryTests {
|
||||
.event_builder(Kind::RepoState, "")
|
||||
.tag(Tag::identifier(&repo_id))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("refs/heads/main"),
|
||||
"refs/heads/main",
|
||||
vec!["abc123".to_string()],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("HEAD"),
|
||||
"HEAD",
|
||||
vec!["ref: refs/heads/main".to_string()],
|
||||
))
|
||||
.build(client.keys())
|
||||
@@ -417,7 +417,7 @@ impl PurgatoryTests {
|
||||
let repo_id = existing_state
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.ok_or("Missing d tag in state event")?
|
||||
.to_string();
|
||||
@@ -428,11 +428,11 @@ impl PurgatoryTests {
|
||||
.event_builder(Kind::RepoState, "")
|
||||
.tag(Tag::identifier(&repo_id))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("refs/heads/main"),
|
||||
"refs/heads/main",
|
||||
vec!["deadbeefdeadbeefdeadbeefdeadbeefdeadbeef".to_string()],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("HEAD"),
|
||||
"HEAD",
|
||||
vec!["ref: refs/heads/main".to_string()],
|
||||
))
|
||||
.build(client.keys())
|
||||
@@ -682,7 +682,7 @@ impl PurgatoryTests {
|
||||
let repo_id = existing_state
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.ok_or("Missing d tag in state event")?
|
||||
.to_string();
|
||||
@@ -716,11 +716,11 @@ impl PurgatoryTests {
|
||||
.event_builder(Kind::RepoState, "")
|
||||
.tag(Tag::identifier(&repo_id))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("refs/heads/main"),
|
||||
"refs/heads/main",
|
||||
vec![unique_commit.clone()],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("HEAD"),
|
||||
"HEAD",
|
||||
vec!["ref: refs/heads/main".to_string()],
|
||||
))
|
||||
.build(client.keys())
|
||||
@@ -744,7 +744,7 @@ impl PurgatoryTests {
|
||||
let deletion = client
|
||||
.event_builder(Kind::EventDeletion, "")
|
||||
.tag(Tag::event(state_event.id))
|
||||
.tag(Tag::custom(TagKind::custom("k"), vec!["30618"]))
|
||||
.tag(Tag::custom("k", vec!["30618"]))
|
||||
.build(client.keys())
|
||||
.map_err(|e| { cleanup(); format!("Failed to build deletion event: {}", e) })?;
|
||||
|
||||
@@ -811,7 +811,7 @@ impl PurgatoryTests {
|
||||
let repo_id = existing_state
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.ok_or("Missing d tag in state event")?
|
||||
.to_string();
|
||||
@@ -839,15 +839,15 @@ impl PurgatoryTests {
|
||||
.event_builder(Kind::GitRepoAnnouncement, "")
|
||||
.tag(Tag::identifier(&repo_id))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
"clone",
|
||||
vec![format!("{}/{}/{}.git", http_url, npub, repo_id)],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("relays"),
|
||||
"relays",
|
||||
vec![relay_url.clone()],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("maintainers"),
|
||||
"maintainers",
|
||||
vec![new_maintainer_hex.clone()],
|
||||
))
|
||||
.build(client.keys())
|
||||
@@ -883,11 +883,11 @@ impl PurgatoryTests {
|
||||
.event_builder(Kind::RepoState, "")
|
||||
.tag(Tag::identifier(&repo_id))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("refs/heads/main"),
|
||||
"refs/heads/main",
|
||||
vec![unique_commit.clone()],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("HEAD"),
|
||||
"HEAD",
|
||||
vec!["ref: refs/heads/main".to_string()],
|
||||
))
|
||||
.build(&new_maintainer_keys)
|
||||
@@ -913,8 +913,8 @@ impl PurgatoryTests {
|
||||
|
||||
let deletion = client
|
||||
.event_builder(Kind::EventDeletion, "")
|
||||
.tag(Tag::custom(TagKind::custom("a"), vec![coord]))
|
||||
.tag(Tag::custom(TagKind::custom("k"), vec!["30618"]))
|
||||
.tag(Tag::custom("a", vec![coord]))
|
||||
.tag(Tag::custom("k", vec!["30618"]))
|
||||
.build(&new_maintainer_keys)
|
||||
.map_err(|e| { cleanup(); format!("Failed to build deletion event: {}", e) })?;
|
||||
|
||||
|
||||
@@ -221,7 +221,7 @@ async fn setup_pr_test_repo(
|
||||
let repo_id = repo_event
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.ok_or("No repo identifier in announcement")?
|
||||
.to_string();
|
||||
@@ -424,7 +424,7 @@ impl PushAuthorizationTests {
|
||||
let repo_id = repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.unwrap()
|
||||
.to_string();
|
||||
@@ -569,7 +569,7 @@ impl PushAuthorizationTests {
|
||||
let repo_id = match state_event
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
{
|
||||
Some(id) => id.to_string(),
|
||||
@@ -809,7 +809,7 @@ impl PushAuthorizationTests {
|
||||
let repo_id = match state_event
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
{
|
||||
Some(id) => id.to_string(),
|
||||
@@ -880,10 +880,7 @@ impl PushAuthorizationTests {
|
||||
let rogue_state = match client
|
||||
.event_builder(Kind::RepoState, "")
|
||||
.tag(Tag::identifier(&repo_id))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("refs/heads/main"),
|
||||
vec![new_commit.clone()],
|
||||
))
|
||||
.tag(Tag::custom("refs/heads/main", vec![new_commit.clone()]))
|
||||
.build(&rogue_keys)
|
||||
{
|
||||
Ok(e) => e,
|
||||
@@ -973,7 +970,7 @@ impl PushAuthorizationTests {
|
||||
let repo_id = repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.unwrap()
|
||||
.to_string();
|
||||
@@ -1121,7 +1118,7 @@ impl PushAuthorizationTests {
|
||||
let repo_id = repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.unwrap_or("unknown")
|
||||
.to_string();
|
||||
@@ -1209,7 +1206,7 @@ impl PushAuthorizationTests {
|
||||
let repo_id = repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.unwrap_or("unknown")
|
||||
.to_string();
|
||||
@@ -1300,7 +1297,7 @@ impl PushAuthorizationTests {
|
||||
let repo_id = repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.unwrap_or("unknown")
|
||||
.to_string();
|
||||
@@ -1436,7 +1433,7 @@ impl PushAuthorizationTests {
|
||||
let repo_id = match valid_repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
{
|
||||
Some(id) => id.to_string(),
|
||||
@@ -1539,7 +1536,7 @@ impl PushAuthorizationTests {
|
||||
let repo_id = match valid_repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
{
|
||||
Some(id) => id.to_string(),
|
||||
@@ -1599,16 +1596,13 @@ impl PushAuthorizationTests {
|
||||
let state_event = match client
|
||||
.event_builder(Kind::RepoState, "")
|
||||
.tag(Tag::identifier(&repo_id))
|
||||
.tag(Tag::custom("HEAD", vec!["refs/heads/develop1".to_string()]))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("HEAD"),
|
||||
vec!["refs/heads/develop1".to_string()],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("refs/heads/develop1"),
|
||||
"refs/heads/develop1",
|
||||
vec![commit_hash.clone()],
|
||||
))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("refs/heads/develop"),
|
||||
"refs/heads/develop",
|
||||
vec![RECURSIVE_MAINTAINER_DETERMINISTIC_COMMIT_HASH.to_string()],
|
||||
))
|
||||
.build(client.keys())
|
||||
|
||||
@@ -70,7 +70,7 @@ impl RepositoryCreationTests {
|
||||
let repo_id = match repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
{
|
||||
Some(id) => id.to_string(),
|
||||
@@ -150,7 +150,7 @@ impl RepositoryCreationTests {
|
||||
let repo_id = match repo
|
||||
.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
{
|
||||
Some(id) => id.to_string(),
|
||||
|
||||
@@ -108,9 +108,9 @@ impl EventAcceptanceTests {
|
||||
Kind::GitPullRequest,
|
||||
"grasp-06 audit: PR for un-announced coord, clone tag on /prs/",
|
||||
)
|
||||
.tag(Tag::custom(TagKind::custom("a"), vec![a_tag_value]))
|
||||
.tag(Tag::custom(TagKind::custom("c"), vec![commit_hex]))
|
||||
.tag(Tag::custom(TagKind::custom("clone"), vec![clone_url]))
|
||||
.tag(Tag::custom("a", vec![a_tag_value]))
|
||||
.tag(Tag::custom("c", vec![commit_hex]))
|
||||
.tag(Tag::custom("clone", vec![clone_url]))
|
||||
.build(client.pr_author_keys())
|
||||
.map_err(|e| format!("Failed to build PR event: {}", e))?;
|
||||
|
||||
@@ -209,9 +209,9 @@ impl EventAcceptanceTests {
|
||||
Kind::GitPullRequest,
|
||||
"grasp-06 audit: orphan PR must land in purgatory, not be served",
|
||||
)
|
||||
.tag(Tag::custom(TagKind::custom("a"), vec![a_tag_value]))
|
||||
.tag(Tag::custom(TagKind::custom("c"), vec![commit_hex]))
|
||||
.tag(Tag::custom(TagKind::custom("clone"), vec![clone_url]))
|
||||
.tag(Tag::custom("a", vec![a_tag_value]))
|
||||
.tag(Tag::custom("c", vec![commit_hex]))
|
||||
.tag(Tag::custom("clone", vec![clone_url]))
|
||||
.build(client.pr_author_keys())
|
||||
.map_err(|e| format!("Failed to build PR event: {}", e))?;
|
||||
let event_id = event.id;
|
||||
@@ -313,12 +313,9 @@ impl EventAcceptanceTests {
|
||||
Kind::GitPullRequest,
|
||||
"grasp-06 audit: PR for un-announced coord, clone tag on foreign host",
|
||||
)
|
||||
.tag(Tag::custom(TagKind::custom("a"), vec![a_tag_value]))
|
||||
.tag(Tag::custom(TagKind::custom("c"), vec![commit_hex]))
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
vec![foreign_clone_url],
|
||||
))
|
||||
.tag(Tag::custom("a", vec![a_tag_value]))
|
||||
.tag(Tag::custom("c", vec![commit_hex]))
|
||||
.tag(Tag::custom("clone", vec![foreign_clone_url]))
|
||||
.build(client.pr_author_keys())
|
||||
.map_err(|e| format!("Failed to build PR event: {}", e))?;
|
||||
|
||||
|
||||
@@ -175,11 +175,11 @@ impl MirroringTests {
|
||||
"grasp-06 audit: PR via /prs/ should mirror to announced repo",
|
||||
)
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("a"),
|
||||
"a",
|
||||
vec![format!("30617:{}:{}", owner_pubkey_hex, repo_id)],
|
||||
))
|
||||
.tag(Tag::custom(TagKind::custom("c"), vec![commit_hash.clone()]))
|
||||
.tag(Tag::custom(TagKind::custom("clone"), vec![prs_url.clone()]))
|
||||
.tag(Tag::custom("c", vec![commit_hash.clone()]))
|
||||
.tag(Tag::custom("clone", vec![prs_url.clone()]))
|
||||
.build(client.pr_author_keys())
|
||||
.map_err(|e| format!("Failed to build PR event: {}", e))?;
|
||||
let pr_event_id_typed = pr_event.id;
|
||||
@@ -409,11 +409,11 @@ impl MirroringTests {
|
||||
"grasp-06 audit: git-first PR via /prs/ should still promote + mirror",
|
||||
)
|
||||
.tag(Tag::custom(
|
||||
TagKind::custom("a"),
|
||||
"a",
|
||||
vec![format!("30617:{}:{}", owner_pubkey_hex, repo_id)],
|
||||
))
|
||||
.tag(Tag::custom(TagKind::custom("c"), vec![commit_hash.clone()]))
|
||||
.tag(Tag::custom(TagKind::custom("clone"), vec![prs_url.clone()]))
|
||||
.tag(Tag::custom("c", vec![commit_hash.clone()]))
|
||||
.tag(Tag::custom("clone", vec![prs_url.clone()]))
|
||||
.build(client.pr_author_keys())
|
||||
.map_err(|e| format!("Failed to build PR event: {}", e))?;
|
||||
let pr_event_id_typed = pr_event.id;
|
||||
@@ -678,7 +678,7 @@ impl MirroringTests {
|
||||
fn extract_repo_id(repo: &Event) -> Result<String, String> {
|
||||
repo.tags
|
||||
.iter()
|
||||
.find(|t| t.kind() == TagKind::d())
|
||||
.find(|t| t.kind() == "d")
|
||||
.and_then(|t| t.content())
|
||||
.map(str::to_string)
|
||||
.ok_or_else(|| "Missing `d` tag in repo announcement".to_string())
|
||||
|
||||
@@ -64,7 +64,7 @@ impl PrsEndpointTests {
|
||||
// 3. Build a /prs/<valid-npub>/<id>.git/info/refs URL with a known-valid
|
||||
// npub. Using a fresh random npub guarantees no implementation could
|
||||
// have a repo there by accident.
|
||||
let probe_keys = nostr_sdk::Keys::generate();
|
||||
let probe_keys = nostr_sdk::prelude::Keys::generate();
|
||||
let probe_npub = probe_keys
|
||||
.public_key()
|
||||
.to_bech32()
|
||||
@@ -139,7 +139,7 @@ impl PrsEndpointTests {
|
||||
// 2. Build a /prs/<valid-npub>/<random-id>.git URL. Using fresh
|
||||
// random keys and a UUID identifier guarantees no implementation
|
||||
// could have prior state for this path.
|
||||
let probe_keys = nostr_sdk::Keys::generate();
|
||||
let probe_keys = nostr_sdk::prelude::Keys::generate();
|
||||
let probe_npub = probe_keys
|
||||
.public_key()
|
||||
.to_bech32()
|
||||
@@ -268,7 +268,7 @@ impl PrsEndpointTests {
|
||||
// 64-hex without pulling in a `rand` dep. No matching event
|
||||
// will ever exist; that's fine — the spec's contract here is
|
||||
// push acceptance, not purgatory release.
|
||||
let event_id_hex = nostr_sdk::Keys::generate().public_key().to_hex();
|
||||
let event_id_hex = nostr_sdk::prelude::Keys::generate().public_key().to_hex();
|
||||
let refname = format!("refs/nostr/{}", event_id_hex);
|
||||
|
||||
// 5. Push. Success means: relay routes /prs/, accepts our ref
|
||||
@@ -473,9 +473,9 @@ impl PushValidationTests {
|
||||
Kind::GitPullRequest,
|
||||
"grasp-06 audit: PR with c tag pointing at commit B (not the pushed commit A)",
|
||||
)
|
||||
.tag(Tag::custom(TagKind::custom("a"), vec![a_tag_value]))
|
||||
.tag(Tag::custom(TagKind::custom("c"), vec![commit_b.clone()]))
|
||||
.tag(Tag::custom(TagKind::custom("clone"), vec![prs_url.clone()]))
|
||||
.tag(Tag::custom("a", vec![a_tag_value]))
|
||||
.tag(Tag::custom("c", vec![commit_b.clone()]))
|
||||
.tag(Tag::custom("clone", vec![prs_url.clone()]))
|
||||
.build(client.pr_author_keys())
|
||||
.map_err(|e| format!("Failed to build PR event: {}", e))?;
|
||||
let pr_event_id_typed = pr_event.id;
|
||||
@@ -586,7 +586,7 @@ impl PushValidationTests {
|
||||
/// Fresh random keys + UUID ensure the path has no prior state and no
|
||||
/// implementation could have a repo there by accident.
|
||||
fn build_fresh_prs_url(http_url: &str) -> Result<String, String> {
|
||||
let probe_keys = nostr_sdk::Keys::generate();
|
||||
let probe_keys = nostr_sdk::prelude::Keys::generate();
|
||||
let probe_npub = probe_keys
|
||||
.public_key()
|
||||
.to_bech32()
|
||||
|
||||
@@ -1403,7 +1403,7 @@ fn describe_known_event_mismatch(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use nostr_sdk::prelude::{EventBuilder, Keys, Tag};
|
||||
use nostr_sdk::prelude::{EventBuilder, FinalizeEvent, Keys, Tag};
|
||||
|
||||
fn create_test_keys() -> Keys {
|
||||
Keys::generate()
|
||||
@@ -1419,10 +1419,7 @@ mod tests {
|
||||
.iter()
|
||||
.map(|k| k.public_key().to_hex())
|
||||
.collect();
|
||||
tags.push(Tag::custom(
|
||||
"maintainers",
|
||||
maintainer_pubkeys,
|
||||
));
|
||||
tags.push(Tag::custom("maintainers", maintainer_pubkeys));
|
||||
}
|
||||
|
||||
// Add clone and relay tags for validity
|
||||
@@ -1430,10 +1427,7 @@ mod tests {
|
||||
"clone",
|
||||
vec!["https://example.com/test.git".to_string()],
|
||||
));
|
||||
tags.push(Tag::custom(
|
||||
"relays",
|
||||
vec!["wss://example.com".to_string()],
|
||||
));
|
||||
tags.push(Tag::custom("relays", vec!["wss://example.com".to_string()]));
|
||||
|
||||
EventBuilder::new(Kind::GitRepoAnnouncement, "Test repo")
|
||||
.tags(tags)
|
||||
|
||||
+14
-35
@@ -1849,7 +1849,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_extract_identifier_from_pr_event_valid() {
|
||||
use nostr_sdk::prelude::{EventBuilder, Keys, Kind, Tag};
|
||||
use nostr_sdk::prelude::{EventBuilder, FinalizeEvent, Keys, Kind, Tag};
|
||||
|
||||
let keys = Keys::generate();
|
||||
let tags = vec![Tag::custom(
|
||||
@@ -1868,13 +1868,10 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_extract_identifier_from_pr_event_missing_tag() {
|
||||
use nostr_sdk::prelude::{EventBuilder, Keys, Kind, Tag};
|
||||
use nostr_sdk::prelude::{EventBuilder, FinalizeEvent, Keys, Kind, Tag};
|
||||
|
||||
let keys = Keys::generate();
|
||||
let tags = vec![Tag::custom(
|
||||
"c",
|
||||
vec!["commit123".to_string()],
|
||||
)];
|
||||
let tags = vec![Tag::custom("c", vec!["commit123".to_string()])];
|
||||
|
||||
let event = EventBuilder::new(Kind::from(1618), "PR content")
|
||||
.tags(tags)
|
||||
@@ -1887,7 +1884,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_extract_identifier_from_pr_event_wrong_kind_a_tag() {
|
||||
use nostr_sdk::prelude::{EventBuilder, Keys, Kind, Tag};
|
||||
use nostr_sdk::prelude::{EventBuilder, FinalizeEvent, Keys, Kind, Tag};
|
||||
|
||||
let keys = Keys::generate();
|
||||
let tags = vec![Tag::custom(
|
||||
@@ -1941,20 +1938,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_extract_tagged_owners_from_pr_events_with_a_tags() {
|
||||
use nostr_sdk::prelude::{EventBuilder, Keys, Kind, Tag};
|
||||
use nostr_sdk::prelude::{EventBuilder, FinalizeEvent, Keys, Kind, Tag};
|
||||
|
||||
let keys = Keys::generate();
|
||||
|
||||
// Create a PR event with `a` tags referencing repos
|
||||
let tags = vec![
|
||||
Tag::custom(
|
||||
"a",
|
||||
vec!["30617:abc123def456:test-repo".to_string()],
|
||||
),
|
||||
Tag::custom(
|
||||
"a",
|
||||
vec!["30617:789xyz000111:another-repo".to_string()],
|
||||
),
|
||||
Tag::custom("a", vec!["30617:abc123def456:test-repo".to_string()]),
|
||||
Tag::custom("a", vec!["30617:789xyz000111:another-repo".to_string()]),
|
||||
Tag::custom("c", vec!["commit123".to_string()]),
|
||||
];
|
||||
|
||||
@@ -1971,20 +1962,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_extract_tagged_owners_from_pr_events_deduplicates() {
|
||||
use nostr_sdk::prelude::{EventBuilder, Keys, Kind, Tag};
|
||||
use nostr_sdk::prelude::{EventBuilder, FinalizeEvent, Keys, Kind, Tag};
|
||||
|
||||
let keys = Keys::generate();
|
||||
|
||||
// Create two events with overlapping owners
|
||||
let tags1 = vec![Tag::custom(
|
||||
"a",
|
||||
vec!["30617:same_owner:repo1".to_string()],
|
||||
)];
|
||||
let tags1 = vec![Tag::custom("a", vec!["30617:same_owner:repo1".to_string()])];
|
||||
|
||||
let tags2 = vec![Tag::custom(
|
||||
"a",
|
||||
vec!["30617:same_owner:repo2".to_string()],
|
||||
)];
|
||||
let tags2 = vec![Tag::custom("a", vec!["30617:same_owner:repo2".to_string()])];
|
||||
|
||||
let event1 = EventBuilder::new(Kind::from(1618), "PR 1")
|
||||
.tags(tags1)
|
||||
@@ -2003,16 +1988,13 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_extract_tagged_owners_ignores_non_30617_a_tags() {
|
||||
use nostr_sdk::prelude::{EventBuilder, Keys, Kind, Tag};
|
||||
use nostr_sdk::prelude::{EventBuilder, FinalizeEvent, Keys, Kind, Tag};
|
||||
|
||||
let keys = Keys::generate();
|
||||
|
||||
// Create a PR event with a non-30617 `a` tag
|
||||
let tags = vec![
|
||||
Tag::custom(
|
||||
"a",
|
||||
vec!["30617:valid_owner:test-repo".to_string()],
|
||||
),
|
||||
Tag::custom("a", vec!["30617:valid_owner:test-repo".to_string()]),
|
||||
Tag::custom(
|
||||
"a",
|
||||
vec!["30618:state_event:test-repo".to_string()], // Not 30617
|
||||
@@ -2037,14 +2019,11 @@ mod tests {
|
||||
created_at: u64,
|
||||
nonce: &str,
|
||||
) -> RepositoryState {
|
||||
use nostr_sdk::prelude::{EventBuilder, Kind, Tag, Timestamp};
|
||||
use nostr_sdk::prelude::{EventBuilder, FinalizeEvent, Kind, Tag, Timestamp};
|
||||
|
||||
let tags = vec![
|
||||
Tag::custom("d", vec![identifier.to_string()]),
|
||||
Tag::custom(
|
||||
"refs/heads/main",
|
||||
vec![format!("abc123{}", nonce)],
|
||||
),
|
||||
Tag::custom("refs/heads/main", vec![format!("abc123{}", nonce)]),
|
||||
];
|
||||
|
||||
let event = EventBuilder::new(Kind::from(30618), nonce)
|
||||
|
||||
+1
-1
@@ -17,9 +17,9 @@ use hyper::server::conn::http1;
|
||||
use hyper::service::Service;
|
||||
use hyper::{Method, Request, Response};
|
||||
use hyper_util::rt::TokioIo;
|
||||
use nostr_relay_builder::LocalRelay;
|
||||
use nostr::hashes::sha1::Hash as Sha1Hash;
|
||||
use nostr::hashes::{Hash, HashEngine};
|
||||
use nostr_relay_builder::LocalRelay;
|
||||
use nostr_sdk::prelude::PublicKey;
|
||||
use tokio::net::TcpListener;
|
||||
|
||||
|
||||
@@ -61,7 +61,6 @@ fn duplicate(message: impl Into<std::borrow::Cow<'static, str>>) -> WritePolicyR
|
||||
WritePolicyResult::ok_msg(MachineReadablePrefix::Duplicate, message)
|
||||
}
|
||||
|
||||
|
||||
/// NIP-34 Write Policy with Full GRASP-01 Event Validation
|
||||
///
|
||||
/// Validates all events according to GRASP-01 specification using modular sub-policies:
|
||||
|
||||
+15
-58
@@ -77,11 +77,7 @@ impl RepositoryAnnouncement {
|
||||
.collect();
|
||||
|
||||
// return error if mutliple clone tags (incorrect formatting)
|
||||
let clone_tag_count = event
|
||||
.tags
|
||||
.iter()
|
||||
.filter(|t| t.kind() == "clone")
|
||||
.count();
|
||||
let clone_tag_count = event.tags.iter().filter(|t| t.kind() == "clone").count();
|
||||
|
||||
if clone_tag_count > 1 {
|
||||
return Err(anyhow::anyhow!("multiple clone tags found. correct format is single clone tag with multiple values"));
|
||||
@@ -514,7 +510,7 @@ pub fn validate_state(event: &Event) -> Result<()> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use nostr_sdk::{EventBuilder, Keys};
|
||||
use nostr_sdk::prelude::{EventBuilder, FinalizeEvent, Keys};
|
||||
|
||||
fn create_test_keys() -> Keys {
|
||||
Keys::generate()
|
||||
@@ -528,10 +524,7 @@ mod tests {
|
||||
) -> Event {
|
||||
use nostr_sdk::prelude::Tag;
|
||||
|
||||
let mut tags = vec![Tag::custom(
|
||||
"d",
|
||||
vec![identifier.to_string()],
|
||||
)];
|
||||
let mut tags = vec![Tag::custom("d", vec![identifier.to_string()])];
|
||||
|
||||
// NIP-34: Single clone tag with multiple values
|
||||
if !clone_urls.is_empty() {
|
||||
@@ -543,10 +536,7 @@ mod tests {
|
||||
|
||||
// NIP-34: Single relays tag with multiple values
|
||||
if !relays.is_empty() {
|
||||
tags.push(Tag::custom(
|
||||
"relays",
|
||||
relays.iter().map(|s| s.to_string()),
|
||||
));
|
||||
tags.push(Tag::custom("relays", relays.iter().map(|s| s.to_string())));
|
||||
}
|
||||
|
||||
EventBuilder::new(Kind::GitRepoAnnouncement, "Test repository")
|
||||
@@ -558,10 +548,7 @@ mod tests {
|
||||
fn create_state_event(keys: &Keys, identifier: &str, branches: Vec<(&str, &str)>) -> Event {
|
||||
use nostr_sdk::prelude::Tag;
|
||||
|
||||
let mut tags = vec![Tag::custom(
|
||||
"d",
|
||||
vec![identifier.to_string()],
|
||||
)];
|
||||
let mut tags = vec![Tag::custom("d", vec![identifier.to_string()])];
|
||||
|
||||
for (branch, commit) in branches {
|
||||
tags.push(Tag::custom(
|
||||
@@ -751,10 +738,7 @@ mod tests {
|
||||
"clone",
|
||||
vec!["https://gitnostr.com/alice/test-repo.git".to_string()],
|
||||
),
|
||||
Tag::custom(
|
||||
"relays",
|
||||
vec!["wss://gitnostr.com".to_string()],
|
||||
),
|
||||
Tag::custom("relays", vec!["wss://gitnostr.com".to_string()]),
|
||||
];
|
||||
|
||||
// Add maintainer using NIP-34 "maintainers" tag format
|
||||
@@ -782,16 +766,10 @@ mod tests {
|
||||
use nostr_sdk::prelude::Tag;
|
||||
|
||||
let keys = create_test_keys();
|
||||
let mut tags = vec![Tag::custom(
|
||||
"d",
|
||||
vec!["test-repo".to_string()],
|
||||
)];
|
||||
let mut tags = vec![Tag::custom("d", vec!["test-repo".to_string()])];
|
||||
|
||||
// Add branch
|
||||
tags.push(Tag::custom(
|
||||
"refs/heads/main",
|
||||
vec!["a1b2c3d4".to_string()],
|
||||
));
|
||||
tags.push(Tag::custom("refs/heads/main", vec!["a1b2c3d4".to_string()]));
|
||||
|
||||
// Add tag
|
||||
tags.push(Tag::custom(
|
||||
@@ -816,10 +794,7 @@ mod tests {
|
||||
use nostr_sdk::prelude::Tag;
|
||||
|
||||
let keys = create_test_keys();
|
||||
let mut tags = vec![Tag::custom(
|
||||
"d",
|
||||
vec!["test-repo".to_string()],
|
||||
)];
|
||||
let mut tags = vec![Tag::custom("d", vec!["test-repo".to_string()])];
|
||||
|
||||
// Add branch
|
||||
tags.push(Tag::custom(
|
||||
@@ -849,10 +824,7 @@ mod tests {
|
||||
use nostr_sdk::prelude::Tag;
|
||||
|
||||
let keys = create_test_keys();
|
||||
let mut tags = vec![Tag::custom(
|
||||
"d",
|
||||
vec!["test-repo".to_string()],
|
||||
)];
|
||||
let mut tags = vec![Tag::custom("d", vec!["test-repo".to_string()])];
|
||||
|
||||
// Add branch
|
||||
tags.push(Tag::custom(
|
||||
@@ -861,10 +833,7 @@ mod tests {
|
||||
));
|
||||
|
||||
// Add HEAD without "ref: " prefix (also valid)
|
||||
tags.push(Tag::custom(
|
||||
"HEAD",
|
||||
vec!["refs/heads/develop".to_string()],
|
||||
));
|
||||
tags.push(Tag::custom("HEAD", vec!["refs/heads/develop".to_string()]));
|
||||
|
||||
let event = EventBuilder::new(Kind::RepoState, "")
|
||||
.tags(tags)
|
||||
@@ -884,10 +853,7 @@ mod tests {
|
||||
let keys = create_test_keys();
|
||||
let tags = vec![
|
||||
Tag::custom("d", vec!["test-repo".to_string()]),
|
||||
Tag::custom(
|
||||
"refs/heads/main",
|
||||
vec!["a1b2c3d4".to_string()],
|
||||
),
|
||||
Tag::custom("refs/heads/main", vec!["a1b2c3d4".to_string()]),
|
||||
];
|
||||
|
||||
let event = EventBuilder::new(Kind::RepoState, "")
|
||||
@@ -906,22 +872,13 @@ mod tests {
|
||||
use nostr_sdk::prelude::Tag;
|
||||
|
||||
let keys = create_test_keys();
|
||||
let mut tags = vec![Tag::custom(
|
||||
"d",
|
||||
vec!["test-repo".to_string()],
|
||||
)];
|
||||
let mut tags = vec![Tag::custom("d", vec!["test-repo".to_string()])];
|
||||
|
||||
// Add branch for "main"
|
||||
tags.push(Tag::custom(
|
||||
"refs/heads/main",
|
||||
vec!["a1b2c3d4".to_string()],
|
||||
));
|
||||
tags.push(Tag::custom("refs/heads/main", vec!["a1b2c3d4".to_string()]));
|
||||
|
||||
// HEAD points to "develop" which doesn't exist in branches
|
||||
tags.push(Tag::custom(
|
||||
"HEAD",
|
||||
vec!["refs/heads/develop".to_string()],
|
||||
));
|
||||
tags.push(Tag::custom("HEAD", vec!["refs/heads/develop".to_string()]));
|
||||
|
||||
let event = EventBuilder::new(Kind::RepoState, "")
|
||||
.tags(tags)
|
||||
|
||||
@@ -297,10 +297,7 @@ mod tests {
|
||||
use std::sync::Arc;
|
||||
|
||||
fn make_context() -> PolicyContext {
|
||||
let db = Arc::new(MemoryDatabase::with_opts(MemoryDatabaseOptions {
|
||||
events: true,
|
||||
max_events: None,
|
||||
}));
|
||||
let db = Arc::new(nostr_memory::MemoryDatabase::unbounded());
|
||||
let purgatory = Arc::new(Purgatory::new(PathBuf::new()));
|
||||
let config = crate::config::Config::for_testing();
|
||||
PolicyContext::new_for_test("test.example.com", db, PathBuf::new(), purgatory, config)
|
||||
@@ -310,10 +307,7 @@ mod tests {
|
||||
EventBuilder::new(Kind::GitRepoAnnouncement, "")
|
||||
.tags(vec![
|
||||
Tag::identifier(identifier),
|
||||
Tag::custom(
|
||||
"clone",
|
||||
vec!["https://example.com/repo.git"],
|
||||
),
|
||||
Tag::custom("clone", vec!["https://example.com/repo.git"]),
|
||||
])
|
||||
.finalize(keys)
|
||||
.unwrap()
|
||||
|
||||
@@ -3,12 +3,12 @@ use std::path::{Path, PathBuf};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use nostr_relay_builder::builder::WritePolicyResult;
|
||||
use nostr_relay_builder::prelude::MachineReadablePrefix;
|
||||
/// State Policy - State event validation + ref alignment
|
||||
///
|
||||
/// Handles validation of NIP-34 repository state events (kind 30618)
|
||||
/// and aligns git refs with authorized state according to GRASP-01.
|
||||
use nostr_relay_builder::prelude::Event;
|
||||
use nostr_relay_builder::prelude::MachineReadablePrefix;
|
||||
|
||||
use super::PolicyContext;
|
||||
use crate::git;
|
||||
|
||||
@@ -347,7 +347,7 @@ pub fn diagnose_state_mismatch(
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use nostr_sdk::prelude::{EventBuilder, Keys, Tag};
|
||||
use nostr_sdk::prelude::{EventBuilder, FinalizeEvent, Keys, Tag};
|
||||
|
||||
fn create_test_state_event(identifier: &str, refs: Vec<(&str, &str)>) -> Event {
|
||||
let keys = Keys::generate();
|
||||
|
||||
+26
-79
@@ -26,8 +26,8 @@ pub use types::{
|
||||
};
|
||||
|
||||
use dashmap::DashMap;
|
||||
use nostr_sdk::prelude::*;
|
||||
use nostr_sdk::prelude::ToBech32;
|
||||
use nostr_sdk::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
@@ -1774,9 +1774,7 @@ mod tests {
|
||||
|
||||
// Add some test data
|
||||
let keys = Keys::generate();
|
||||
let event = EventBuilder::text_note("test")
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
let event = EventBuilder::text_note("test").finalize(&keys).unwrap();
|
||||
|
||||
purgatory.add_state(
|
||||
event.clone(),
|
||||
@@ -1838,9 +1836,7 @@ mod tests {
|
||||
assert!(!purgatory.has_pending_events("test-repo"));
|
||||
|
||||
// Add a state event
|
||||
let event = EventBuilder::text_note("state")
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
let event = EventBuilder::text_note("state").finalize(&keys).unwrap();
|
||||
purgatory.add_state(event, "test-repo".to_string(), keys.public_key(), false);
|
||||
|
||||
// Now should have pending events
|
||||
@@ -1932,9 +1928,7 @@ mod tests {
|
||||
fn test_pr_event_vs_placeholder() {
|
||||
let purgatory = Purgatory::new(PathBuf::new());
|
||||
let keys = Keys::generate();
|
||||
let event = EventBuilder::text_note("test PR")
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
let event = EventBuilder::text_note("test PR").finalize(&keys).unwrap();
|
||||
|
||||
// Add a PR event with actual event
|
||||
purgatory.add_pr(
|
||||
@@ -1989,9 +1983,7 @@ fn test_cleanup_removes_expired_entries() {
|
||||
let state_event = EventBuilder::text_note("state event")
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
let pr_event = EventBuilder::text_note("pr event")
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
let pr_event = EventBuilder::text_note("pr event").finalize(&keys).unwrap();
|
||||
|
||||
// Add entries to purgatory
|
||||
purgatory.add_state(
|
||||
@@ -2047,9 +2039,7 @@ fn test_cleanup_preserves_non_expired_entries() {
|
||||
let state_event = EventBuilder::text_note("state event")
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
let pr_event = EventBuilder::text_note("pr event")
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
let pr_event = EventBuilder::text_note("pr event").finalize(&keys).unwrap();
|
||||
|
||||
// Add fresh entries
|
||||
purgatory.add_state(
|
||||
@@ -2086,12 +2076,8 @@ fn test_cleanup_mixed_expired_and_fresh() {
|
||||
let keys = Keys::generate();
|
||||
|
||||
// Add multiple state events for same repo
|
||||
let event1 = EventBuilder::text_note("event1")
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
let event2 = EventBuilder::text_note("event2")
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
let event1 = EventBuilder::text_note("event1").finalize(&keys).unwrap();
|
||||
let event2 = EventBuilder::text_note("event2").finalize(&keys).unwrap();
|
||||
|
||||
purgatory.add_state(event1, "test-repo".to_string(), keys.public_key(), false);
|
||||
purgatory.add_state(event2, "test-repo".to_string(), keys.public_key(), false);
|
||||
@@ -2104,12 +2090,8 @@ fn test_cleanup_mixed_expired_and_fresh() {
|
||||
}
|
||||
|
||||
// Add PR events
|
||||
let pr1 = EventBuilder::text_note("pr1")
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
let pr2 = EventBuilder::text_note("pr2")
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
let pr1 = EventBuilder::text_note("pr1").finalize(&keys).unwrap();
|
||||
let pr2 = EventBuilder::text_note("pr2").finalize(&keys).unwrap();
|
||||
|
||||
purgatory.add_pr(pr1, "pr-1".to_string(), "commit-1".to_string(), false);
|
||||
purgatory.add_pr(pr2, "pr-2".to_string(), "commit-2".to_string(), false);
|
||||
@@ -2139,9 +2121,7 @@ fn test_remove_expired_legacy_method() {
|
||||
let purgatory = Purgatory::new(PathBuf::new());
|
||||
let keys = Keys::generate();
|
||||
|
||||
let state_event = EventBuilder::text_note("state")
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
let state_event = EventBuilder::text_note("state").finalize(&keys).unwrap();
|
||||
let pr_event = EventBuilder::text_note("pr").finalize(&keys).unwrap();
|
||||
|
||||
purgatory.add_state(state_event, "repo".to_string(), keys.public_key(), false);
|
||||
@@ -2170,9 +2150,7 @@ fn test_expired_event_tracking() {
|
||||
let purgatory = Purgatory::new(PathBuf::new());
|
||||
let keys = Keys::generate();
|
||||
|
||||
let state_event = EventBuilder::text_note("state")
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
let state_event = EventBuilder::text_note("state").finalize(&keys).unwrap();
|
||||
let pr_event = EventBuilder::text_note("pr").finalize(&keys).unwrap();
|
||||
|
||||
let state_event_id = state_event.id;
|
||||
@@ -2221,12 +2199,8 @@ fn test_cleanup_expired_events() {
|
||||
let purgatory = Purgatory::new(PathBuf::new());
|
||||
let keys = Keys::generate();
|
||||
|
||||
let event1 = EventBuilder::text_note("event1")
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
let event2 = EventBuilder::text_note("event2")
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
let event1 = EventBuilder::text_note("event1").finalize(&keys).unwrap();
|
||||
let event2 = EventBuilder::text_note("event2").finalize(&keys).unwrap();
|
||||
|
||||
let event1_id = event1.id;
|
||||
let event2_id = event2.id;
|
||||
@@ -2277,9 +2251,7 @@ fn test_expired_events_prevent_readdition() {
|
||||
let purgatory = Purgatory::new(PathBuf::new());
|
||||
let keys = Keys::generate();
|
||||
|
||||
let event = EventBuilder::text_note("test")
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
let event = EventBuilder::text_note("test").finalize(&keys).unwrap();
|
||||
let event_id = event.id;
|
||||
|
||||
// Add event to purgatory
|
||||
@@ -2340,9 +2312,7 @@ fn test_user_can_resubmit_expired_event() {
|
||||
let purgatory = Purgatory::new(PathBuf::new());
|
||||
let keys = Keys::generate();
|
||||
|
||||
let event = EventBuilder::text_note("test")
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
let event = EventBuilder::text_note("test").finalize(&keys).unwrap();
|
||||
let event_id = event.id;
|
||||
|
||||
// Add event to purgatory
|
||||
@@ -2452,10 +2422,7 @@ async fn test_save_and_restore_pr_events() {
|
||||
let keys = Keys::generate();
|
||||
|
||||
// Add PR event with actual event
|
||||
let tags = vec![Tag::custom(
|
||||
"a",
|
||||
vec!["30617:abc123:test-repo".to_string()],
|
||||
)];
|
||||
let tags = vec![Tag::custom("a", vec!["30617:abc123:test-repo".to_string()])];
|
||||
|
||||
let pr_event = EventBuilder::new(Kind::from(1618), "PR content")
|
||||
.tags(tags)
|
||||
@@ -2532,9 +2499,7 @@ async fn test_save_and_restore_expired_events() {
|
||||
let purgatory = Purgatory::new(PathBuf::new());
|
||||
let keys = Keys::generate();
|
||||
|
||||
let event = EventBuilder::text_note("test")
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
let event = EventBuilder::text_note("test").finalize(&keys).unwrap();
|
||||
let event_id = event.id;
|
||||
|
||||
// Add and expire event
|
||||
@@ -2673,9 +2638,7 @@ async fn test_downtime_calculation() {
|
||||
let keys = Keys::generate();
|
||||
|
||||
// Add state event
|
||||
let event = EventBuilder::text_note("test")
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
let event = EventBuilder::text_note("test").finalize(&keys).unwrap();
|
||||
|
||||
purgatory.add_state(event.clone(), "repo".to_string(), keys.public_key(), false);
|
||||
|
||||
@@ -2729,9 +2692,7 @@ async fn test_expiry_times_preserved() {
|
||||
let keys = Keys::generate();
|
||||
|
||||
// Add state event
|
||||
let event = EventBuilder::text_note("test")
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
let event = EventBuilder::text_note("test").finalize(&keys).unwrap();
|
||||
|
||||
purgatory.add_state(event.clone(), "repo".to_string(), keys.public_key(), false);
|
||||
|
||||
@@ -2837,10 +2798,7 @@ async fn test_mixed_pr_events_and_placeholders() {
|
||||
let keys = Keys::generate();
|
||||
|
||||
// Add PR event with actual event
|
||||
let tags = vec![Tag::custom(
|
||||
"a",
|
||||
vec!["30617:abc123:test-repo".to_string()],
|
||||
)];
|
||||
let tags = vec![Tag::custom("a", vec!["30617:abc123:test-repo".to_string()])];
|
||||
|
||||
let pr_event = EventBuilder::new(Kind::from(1618), "PR content")
|
||||
.tags(tags)
|
||||
@@ -2894,9 +2852,7 @@ async fn test_file_cleanup_after_successful_restore() {
|
||||
let keys = Keys::generate();
|
||||
|
||||
// Add some data
|
||||
let event = EventBuilder::text_note("test")
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
let event = EventBuilder::text_note("test").finalize(&keys).unwrap();
|
||||
purgatory.add_state(event, "repo".to_string(), keys.public_key(), false);
|
||||
|
||||
// Save to disk
|
||||
@@ -3076,12 +3032,8 @@ async fn test_comprehensive_roundtrip() {
|
||||
);
|
||||
|
||||
// Add multiple state events
|
||||
let state1 = EventBuilder::text_note("state 1")
|
||||
.finalize(&keys1)
|
||||
.unwrap();
|
||||
let state2 = EventBuilder::text_note("state 2")
|
||||
.finalize(&keys2)
|
||||
.unwrap();
|
||||
let state1 = EventBuilder::text_note("state 1").finalize(&keys1).unwrap();
|
||||
let state2 = EventBuilder::text_note("state 2").finalize(&keys2).unwrap();
|
||||
|
||||
purgatory.add_state(
|
||||
state1.clone(),
|
||||
@@ -3097,10 +3049,7 @@ async fn test_comprehensive_roundtrip() {
|
||||
);
|
||||
|
||||
// Add PR event
|
||||
let tags = vec![Tag::custom(
|
||||
"a",
|
||||
vec!["30617:abc123:repo1".to_string()],
|
||||
)];
|
||||
let tags = vec![Tag::custom("a", vec!["30617:abc123:repo1".to_string()])];
|
||||
let pr_event = EventBuilder::new(Kind::from(1618), "PR")
|
||||
.tags(tags)
|
||||
.finalize(&keys1)
|
||||
@@ -3116,9 +3065,7 @@ async fn test_comprehensive_roundtrip() {
|
||||
purgatory.add_pr_placeholder("pr-2".to_string(), "commit-2".to_string());
|
||||
|
||||
// Add and expire an event
|
||||
let expired_event = EventBuilder::text_note("expired")
|
||||
.finalize(&keys1)
|
||||
.unwrap();
|
||||
let expired_event = EventBuilder::text_note("expired").finalize(&keys1).unwrap();
|
||||
let expired_id = expired_event.id;
|
||||
purgatory.add_state(
|
||||
expired_event,
|
||||
|
||||
@@ -753,7 +753,7 @@ pub mod mock {
|
||||
// Create minimal repo data with just clone URLs
|
||||
// In real tests, you'd set up proper announcements
|
||||
use crate::nostr::events::RepositoryAnnouncement;
|
||||
use nostr_sdk::{EventBuilder, Keys, Kind};
|
||||
use nostr_sdk::prelude::{EventBuilder, FinalizeEvent, Keys, Kind};
|
||||
|
||||
let keys = Keys::generate();
|
||||
let mut announcements = Vec::new();
|
||||
|
||||
+44
-33
@@ -56,7 +56,7 @@
|
||||
//!
|
||||
//! ```rust,ignore
|
||||
//! use ngit_grasp::sync::rejected_index::{RejectedEventsIndex, RejectionReason, EventType};
|
||||
//! use nostr_sdk::{Event, PublicKey};
|
||||
//! use nostr_sdk::prelude::{Event, PublicKey};
|
||||
//! use std::time::Duration;
|
||||
//!
|
||||
//! let index = RejectedEventsIndex::new(
|
||||
@@ -829,12 +829,13 @@ impl RejectedEventsIndex {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use nostr_sdk::{Keys, NostrSigner};
|
||||
use nostr_sdk::prelude::{FinalizeUnsignedEvent, Keys, SignEvent};
|
||||
|
||||
async fn create_test_event() -> Event {
|
||||
let keys = Keys::generate();
|
||||
let unsigned = nostr_sdk::prelude::EventBuilder::text_note("test").finalize_unsigned(keys.public_key());
|
||||
keys.sign_event(unsigned).await.unwrap()
|
||||
let unsigned = nostr_sdk::prelude::EventBuilder::text_note("test")
|
||||
.finalize_unsigned(keys.public_key());
|
||||
keys.sign_event(unsigned).unwrap()
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -1032,11 +1033,13 @@ mod tests {
|
||||
let keys1 = Keys::generate();
|
||||
let keys2 = Keys::generate();
|
||||
|
||||
let unsigned1 = nostr_sdk::prelude::EventBuilder::text_note("test1").finalize_unsigned(keys1.public_key());
|
||||
let event1 = keys1.sign_event(unsigned1).await.unwrap();
|
||||
let unsigned1 = nostr_sdk::prelude::EventBuilder::text_note("test1")
|
||||
.finalize_unsigned(keys1.public_key());
|
||||
let event1 = keys1.sign_event(unsigned1).unwrap();
|
||||
|
||||
let unsigned2 = nostr_sdk::prelude::EventBuilder::text_note("test2").finalize_unsigned(keys2.public_key());
|
||||
let event2 = keys2.sign_event(unsigned2).await.unwrap();
|
||||
let unsigned2 = nostr_sdk::prelude::EventBuilder::text_note("test2")
|
||||
.finalize_unsigned(keys2.public_key());
|
||||
let event2 = keys2.sign_event(unsigned2).unwrap();
|
||||
|
||||
// Add two different maintainer repos
|
||||
index.add_announcement(
|
||||
@@ -1075,13 +1078,14 @@ mod tests {
|
||||
let keys = Keys::generate();
|
||||
|
||||
// Create an announcement event
|
||||
let unsigned_ann =
|
||||
nostr_sdk::prelude::EventBuilder::text_note("announcement").finalize_unsigned(keys.public_key());
|
||||
let event_ann = keys.sign_event(unsigned_ann).await.unwrap();
|
||||
let unsigned_ann = nostr_sdk::prelude::EventBuilder::text_note("announcement")
|
||||
.finalize_unsigned(keys.public_key());
|
||||
let event_ann = keys.sign_event(unsigned_ann).unwrap();
|
||||
|
||||
// Create a state event
|
||||
let unsigned_state = nostr_sdk::prelude::EventBuilder::text_note("state").finalize_unsigned(keys.public_key());
|
||||
let event_state = keys.sign_event(unsigned_state).await.unwrap();
|
||||
let unsigned_state = nostr_sdk::prelude::EventBuilder::text_note("state")
|
||||
.finalize_unsigned(keys.public_key());
|
||||
let event_state = keys.sign_event(unsigned_state).unwrap();
|
||||
|
||||
let pubkey = event_ann.pubkey;
|
||||
let identifier = "test-repo".to_string();
|
||||
@@ -1134,13 +1138,14 @@ mod tests {
|
||||
let keys = Keys::generate();
|
||||
|
||||
// Create an announcement event
|
||||
let unsigned_ann =
|
||||
nostr_sdk::prelude::EventBuilder::text_note("announcement").finalize_unsigned(keys.public_key());
|
||||
let event_ann = keys.sign_event(unsigned_ann).await.unwrap();
|
||||
let unsigned_ann = nostr_sdk::prelude::EventBuilder::text_note("announcement")
|
||||
.finalize_unsigned(keys.public_key());
|
||||
let event_ann = keys.sign_event(unsigned_ann).unwrap();
|
||||
|
||||
// Create a state event
|
||||
let unsigned_state = nostr_sdk::prelude::EventBuilder::text_note("state").finalize_unsigned(keys.public_key());
|
||||
let event_state = keys.sign_event(unsigned_state).await.unwrap();
|
||||
let unsigned_state = nostr_sdk::prelude::EventBuilder::text_note("state")
|
||||
.finalize_unsigned(keys.public_key());
|
||||
let event_state = keys.sign_event(unsigned_state).unwrap();
|
||||
|
||||
let pubkey = event_ann.pubkey;
|
||||
let identifier = "test-repo".to_string();
|
||||
@@ -1280,11 +1285,13 @@ mod tests {
|
||||
let keys = Keys::generate();
|
||||
|
||||
// Create two events
|
||||
let unsigned1 = nostr_sdk::prelude::EventBuilder::text_note("event1").finalize_unsigned(keys.public_key());
|
||||
let event1 = keys.sign_event(unsigned1).await.unwrap();
|
||||
let unsigned1 = nostr_sdk::prelude::EventBuilder::text_note("event1")
|
||||
.finalize_unsigned(keys.public_key());
|
||||
let event1 = keys.sign_event(unsigned1).unwrap();
|
||||
|
||||
let unsigned2 = nostr_sdk::prelude::EventBuilder::text_note("event2").finalize_unsigned(keys.public_key());
|
||||
let event2 = keys.sign_event(unsigned2).await.unwrap();
|
||||
let unsigned2 = nostr_sdk::prelude::EventBuilder::text_note("event2")
|
||||
.finalize_unsigned(keys.public_key());
|
||||
let event2 = keys.sign_event(unsigned2).unwrap();
|
||||
|
||||
// Add both events
|
||||
index.add_announcement(
|
||||
@@ -1491,13 +1498,14 @@ mod tests {
|
||||
let keys = Keys::generate();
|
||||
|
||||
// Create announcement event
|
||||
let unsigned_ann =
|
||||
nostr_sdk::prelude::EventBuilder::text_note("announcement").finalize_unsigned(keys.public_key());
|
||||
let event_ann = keys.sign_event(unsigned_ann).await.unwrap();
|
||||
let unsigned_ann = nostr_sdk::prelude::EventBuilder::text_note("announcement")
|
||||
.finalize_unsigned(keys.public_key());
|
||||
let event_ann = keys.sign_event(unsigned_ann).unwrap();
|
||||
|
||||
// Create state event
|
||||
let unsigned_state = nostr_sdk::prelude::EventBuilder::text_note("state").finalize_unsigned(keys.public_key());
|
||||
let event_state = keys.sign_event(unsigned_state).await.unwrap();
|
||||
let unsigned_state = nostr_sdk::prelude::EventBuilder::text_note("state")
|
||||
.finalize_unsigned(keys.public_key());
|
||||
let event_state = keys.sign_event(unsigned_state).unwrap();
|
||||
|
||||
// Add both types
|
||||
index.add_announcement(
|
||||
@@ -1545,14 +1553,17 @@ mod tests {
|
||||
let keys = Keys::generate();
|
||||
|
||||
// Create events with different rejection reasons
|
||||
let unsigned1 = nostr_sdk::prelude::EventBuilder::text_note("event1").finalize_unsigned(keys.public_key());
|
||||
let event1 = keys.sign_event(unsigned1).await.unwrap();
|
||||
let unsigned1 = nostr_sdk::prelude::EventBuilder::text_note("event1")
|
||||
.finalize_unsigned(keys.public_key());
|
||||
let event1 = keys.sign_event(unsigned1).unwrap();
|
||||
|
||||
let unsigned2 = nostr_sdk::prelude::EventBuilder::text_note("event2").finalize_unsigned(keys.public_key());
|
||||
let event2 = keys.sign_event(unsigned2).await.unwrap();
|
||||
let unsigned2 = nostr_sdk::prelude::EventBuilder::text_note("event2")
|
||||
.finalize_unsigned(keys.public_key());
|
||||
let event2 = keys.sign_event(unsigned2).unwrap();
|
||||
|
||||
let unsigned3 = nostr_sdk::prelude::EventBuilder::text_note("event3").finalize_unsigned(keys.public_key());
|
||||
let event3 = keys.sign_event(unsigned3).await.unwrap();
|
||||
let unsigned3 = nostr_sdk::prelude::EventBuilder::text_note("event3")
|
||||
.finalize_unsigned(keys.public_key());
|
||||
let event3 = keys.sign_event(unsigned3).unwrap();
|
||||
|
||||
// Add with different rejection reasons
|
||||
index.add_announcement(
|
||||
|
||||
@@ -67,7 +67,7 @@ async fn start_relay_with_grasp_services(services: &str) -> (Child, String, Path
|
||||
.join("ngit-grasp");
|
||||
|
||||
// Generate a test owner npub
|
||||
let test_keys = nostr_sdk::Keys::generate();
|
||||
let test_keys = nostr_sdk::prelude::Keys::generate();
|
||||
let test_npub = test_keys
|
||||
.public_key()
|
||||
.to_bech32()
|
||||
@@ -145,22 +145,21 @@ async fn test_archive_accepts_matching_grasp_service() {
|
||||
let tags = vec![
|
||||
Tag::identifier(identifier),
|
||||
Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
"clone",
|
||||
vec![format!("https://git.example.com/user/{}.git", identifier)],
|
||||
),
|
||||
Tag::custom(
|
||||
TagKind::custom("relays"),
|
||||
vec!["wss://relay.example.com".to_string()],
|
||||
),
|
||||
Tag::custom("relays", vec!["wss://relay.example.com".to_string()]),
|
||||
];
|
||||
|
||||
let announcement = EventBuilder::new(Kind::GitRepoAnnouncement, "Repository state")
|
||||
.tags(tags)
|
||||
.sign_with_keys(&keys)
|
||||
.finalize(&keys)
|
||||
.expect("Failed to sign announcement");
|
||||
|
||||
// Send announcement to relay
|
||||
let client = Client::new(keys.clone());
|
||||
let client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(keys.clone()))
|
||||
.build();
|
||||
client.add_relay(&url).await.expect("Failed to add relay");
|
||||
client.connect().await;
|
||||
|
||||
@@ -205,22 +204,21 @@ async fn test_archive_rejects_non_matching_grasp_service() {
|
||||
let tags = vec![
|
||||
Tag::identifier(identifier),
|
||||
Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
"clone",
|
||||
vec![format!("https://github.com/user/{}.git", identifier)],
|
||||
),
|
||||
Tag::custom(
|
||||
TagKind::custom("relays"),
|
||||
vec!["wss://relay.example.com".to_string()],
|
||||
),
|
||||
Tag::custom("relays", vec!["wss://relay.example.com".to_string()]),
|
||||
];
|
||||
|
||||
let announcement = EventBuilder::new(Kind::GitRepoAnnouncement, "Repository state")
|
||||
.tags(tags)
|
||||
.sign_with_keys(&keys)
|
||||
.finalize(&keys)
|
||||
.expect("Failed to sign announcement");
|
||||
|
||||
// Send announcement to relay
|
||||
let client = Client::new(keys.clone());
|
||||
let client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(keys.clone()))
|
||||
.build();
|
||||
client.add_relay(&url).await.expect("Failed to add relay");
|
||||
client.connect().await;
|
||||
|
||||
@@ -268,21 +266,20 @@ async fn test_archive_multiple_grasp_services() {
|
||||
let tags1 = vec![
|
||||
Tag::identifier(identifier1),
|
||||
Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
"clone",
|
||||
vec![format!("https://git.example.com/user/{}.git", identifier1)],
|
||||
),
|
||||
Tag::custom(
|
||||
TagKind::custom("relays"),
|
||||
vec!["wss://relay.example.com".to_string()],
|
||||
),
|
||||
Tag::custom("relays", vec!["wss://relay.example.com".to_string()]),
|
||||
];
|
||||
|
||||
let announcement1 = EventBuilder::new(Kind::GitRepoAnnouncement, "Repository state")
|
||||
.tags(tags1)
|
||||
.sign_with_keys(&keys1)
|
||||
.finalize(&keys1)
|
||||
.expect("Failed to sign announcement");
|
||||
|
||||
let client1 = Client::new(keys1.clone());
|
||||
let client1 = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(keys1.clone()))
|
||||
.build();
|
||||
client1.add_relay(&url).await.expect("Failed to add relay");
|
||||
client1.connect().await;
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
@@ -301,24 +298,23 @@ async fn test_archive_multiple_grasp_services() {
|
||||
let tags2 = vec![
|
||||
Tag::identifier(identifier2),
|
||||
Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
"clone",
|
||||
vec![format!(
|
||||
"https://gitlab.example.org/user/{}.git",
|
||||
identifier2
|
||||
)],
|
||||
),
|
||||
Tag::custom(
|
||||
TagKind::custom("relays"),
|
||||
vec!["wss://relay.example.com".to_string()],
|
||||
),
|
||||
Tag::custom("relays", vec!["wss://relay.example.com".to_string()]),
|
||||
];
|
||||
|
||||
let announcement2 = EventBuilder::new(Kind::GitRepoAnnouncement, "Repository state")
|
||||
.tags(tags2)
|
||||
.sign_with_keys(&keys2)
|
||||
.finalize(&keys2)
|
||||
.expect("Failed to sign announcement");
|
||||
|
||||
let client2 = Client::new(keys2.clone());
|
||||
let client2 = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(keys2.clone()))
|
||||
.build();
|
||||
client2.add_relay(&url).await.expect("Failed to add relay");
|
||||
client2.connect().await;
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
@@ -337,21 +333,20 @@ async fn test_archive_multiple_grasp_services() {
|
||||
let tags3 = vec![
|
||||
Tag::identifier(identifier3),
|
||||
Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
"clone",
|
||||
vec![format!("https://github.com/user/{}.git", identifier3)],
|
||||
),
|
||||
Tag::custom(
|
||||
TagKind::custom("relays"),
|
||||
vec!["wss://relay.example.com".to_string()],
|
||||
),
|
||||
Tag::custom("relays", vec!["wss://relay.example.com".to_string()]),
|
||||
];
|
||||
|
||||
let announcement3 = EventBuilder::new(Kind::GitRepoAnnouncement, "Repository state")
|
||||
.tags(tags3)
|
||||
.sign_with_keys(&keys3)
|
||||
.finalize(&keys3)
|
||||
.expect("Failed to sign announcement");
|
||||
|
||||
let client3 = Client::new(keys3.clone());
|
||||
let client3 = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(keys3.clone()))
|
||||
.build();
|
||||
client3.add_relay(&url).await.expect("Failed to add relay");
|
||||
client3.connect().await;
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
@@ -429,7 +424,9 @@ async fn test_archive_read_only_creates_bare_repo() {
|
||||
identifier,
|
||||
);
|
||||
|
||||
let source_client = Client::new(keys.clone());
|
||||
let source_client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(keys.clone()))
|
||||
.build();
|
||||
source_client
|
||||
.add_relay(source_relay.url())
|
||||
.await
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
//! let mock = MockRelay::start().await;
|
||||
//!
|
||||
//! // Use mock.url() for WebSocket connections
|
||||
//! let client = Client::new(keys);
|
||||
//! let client = Client::builder().authenticator(SignerAuthenticator::new(keys)).build();
|
||||
//! client.add_relay(mock.url()).await.unwrap();
|
||||
//!
|
||||
//! // All events are accepted without validation
|
||||
@@ -249,8 +249,8 @@ async fn handle_request(
|
||||
|
||||
/// Derive the Sec-WebSocket-Accept key from the request key.
|
||||
fn derive_accept_key(request_key: &[u8]) -> String {
|
||||
use nostr_sdk::hashes::sha1::Hash as Sha1Hash;
|
||||
use nostr_sdk::hashes::{Hash, HashEngine};
|
||||
use nostr::hashes::sha1::Hash as Sha1Hash;
|
||||
use nostr::hashes::{Hash, HashEngine};
|
||||
|
||||
const WS_GUID: &[u8] = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
|
||||
|
||||
@@ -308,7 +308,9 @@ mod tests {
|
||||
|
||||
// Create a client and connect
|
||||
let keys = Keys::generate();
|
||||
let client = Client::new(keys.clone());
|
||||
let client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(keys.clone()))
|
||||
.build();
|
||||
client
|
||||
.add_relay(mock.url())
|
||||
.await
|
||||
@@ -320,7 +322,7 @@ mod tests {
|
||||
|
||||
// Create and send a simple event
|
||||
let event = EventBuilder::text_note("Test note from MockRelay test")
|
||||
.sign_with_keys(&keys)
|
||||
.finalize(&keys)
|
||||
.expect("Failed to sign event");
|
||||
|
||||
let result = client.send_event(&event).await;
|
||||
@@ -329,7 +331,8 @@ mod tests {
|
||||
// Verify event was stored by fetching it back
|
||||
let filter = Filter::new().id(event.id);
|
||||
let events = client
|
||||
.fetch_events(filter, Duration::from_secs(2))
|
||||
.fetch_events(filter)
|
||||
.timeout(Duration::from_secs(2))
|
||||
.await
|
||||
.expect("Failed to fetch events");
|
||||
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ pub mod sync_helpers;
|
||||
|
||||
pub use git_server::{SimpleGitServer, SmartGitServer};
|
||||
pub use mock_relay::MockRelay;
|
||||
pub use port::{PortReservation, reserve_port};
|
||||
pub use port::{reserve_port, PortReservation};
|
||||
pub use purgatory_helpers::*;
|
||||
pub use relay::TestRelay;
|
||||
pub use sync_helpers::*;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
//!
|
||||
//! # nostr-sdk 0.43 API Notes
|
||||
//! - Use field access: `event.id`, `event.tags`, `event.tags.iter()`
|
||||
//! - Use `Tag::custom(TagKind::custom("name"), vec![...])` syntax
|
||||
//! - Use `Tag::custom("name", vec![...])` syntax
|
||||
//! - Use `EventBuilder::new(kind, content).tags(tags)` syntax
|
||||
|
||||
use nostr_sdk::prelude::*;
|
||||
@@ -193,50 +193,41 @@ pub fn create_state_event(
|
||||
) -> Result<Event, String> {
|
||||
let mut event_tags = vec![
|
||||
// d-tag (identifier)
|
||||
Tag::custom(TagKind::d(), vec![identifier.to_string()]),
|
||||
Tag::custom("d", vec![identifier.to_string()]),
|
||||
];
|
||||
|
||||
// Add clone URLs
|
||||
if !clone_urls.is_empty() {
|
||||
let urls: Vec<String> = clone_urls.iter().map(|s| s.to_string()).collect();
|
||||
event_tags.push(Tag::custom(TagKind::Clone, urls));
|
||||
event_tags.push(Tag::custom("clone", urls));
|
||||
}
|
||||
|
||||
// Add relay URLs
|
||||
if !relay_urls.is_empty() {
|
||||
let urls: Vec<String> = relay_urls.iter().map(|s| s.to_string()).collect();
|
||||
event_tags.push(Tag::custom(TagKind::Relays, urls));
|
||||
event_tags.push(Tag::custom("relays", urls));
|
||||
}
|
||||
|
||||
// Add branch refs (refs/heads/*)
|
||||
for (name, commit) in branches {
|
||||
let ref_name = format!("refs/heads/{}", name);
|
||||
event_tags.push(Tag::custom(
|
||||
TagKind::Custom(ref_name.into()),
|
||||
vec![commit.to_string()],
|
||||
));
|
||||
event_tags.push(Tag::custom(ref_name, vec![commit.to_string()]));
|
||||
}
|
||||
|
||||
// Add tag refs (refs/tags/*)
|
||||
for (name, commit) in tags {
|
||||
let ref_name = format!("refs/tags/{}", name);
|
||||
event_tags.push(Tag::custom(
|
||||
TagKind::Custom(ref_name.into()),
|
||||
vec![commit.to_string()],
|
||||
));
|
||||
event_tags.push(Tag::custom(ref_name, vec![commit.to_string()]));
|
||||
}
|
||||
|
||||
// Add HEAD pointing to main (if main exists)
|
||||
if branches.iter().any(|(name, _)| *name == "main") {
|
||||
event_tags.push(Tag::custom(
|
||||
TagKind::Custom("HEAD".into()),
|
||||
vec!["refs/heads/main".to_string()],
|
||||
));
|
||||
event_tags.push(Tag::custom("HEAD", vec!["refs/heads/main".to_string()]));
|
||||
}
|
||||
|
||||
EventBuilder::new(Kind::RepoState, "")
|
||||
.tags(event_tags)
|
||||
.sign_with_keys(keys)
|
||||
.finalize(keys)
|
||||
.map_err(|e| format!("Failed to sign state event: {}", e))
|
||||
}
|
||||
|
||||
@@ -262,14 +253,14 @@ pub fn create_pr_event(
|
||||
) -> Result<Event, String> {
|
||||
let tags = vec![
|
||||
// a-tag referencing the repository
|
||||
Tag::custom(TagKind::custom("a"), vec![repo_coord.to_string()]),
|
||||
Tag::custom("a", vec![repo_coord.to_string()]),
|
||||
// c-tag with the commit hash
|
||||
Tag::custom(TagKind::custom("c"), vec![commit_hash.to_string()]),
|
||||
Tag::custom("c", vec![commit_hash.to_string()]),
|
||||
];
|
||||
|
||||
EventBuilder::new(Kind::GitPullRequest, title)
|
||||
.tags(tags)
|
||||
.sign_with_keys(keys)
|
||||
.finalize(keys)
|
||||
.map_err(|e| format!("Failed to sign PR event: {}", e))
|
||||
}
|
||||
|
||||
@@ -310,20 +301,20 @@ pub fn create_pr_event_with_clone(
|
||||
) -> Result<Event, String> {
|
||||
let mut tags = vec![
|
||||
// a-tag referencing the repository
|
||||
Tag::custom(TagKind::custom("a"), vec![repo_coord.to_string()]),
|
||||
Tag::custom("a", vec![repo_coord.to_string()]),
|
||||
// c-tag with the commit hash
|
||||
Tag::custom(TagKind::custom("c"), vec![commit_hash.to_string()]),
|
||||
Tag::custom("c", vec![commit_hash.to_string()]),
|
||||
];
|
||||
|
||||
// Add clone URLs if provided
|
||||
if !clone_urls.is_empty() {
|
||||
let urls: Vec<String> = clone_urls.iter().map(|s| s.to_string()).collect();
|
||||
tags.push(Tag::custom(TagKind::Clone, urls));
|
||||
tags.push(Tag::custom("clone", urls));
|
||||
}
|
||||
|
||||
EventBuilder::new(Kind::GitPullRequest, title)
|
||||
.tags(tags)
|
||||
.sign_with_keys(keys)
|
||||
.finalize(keys)
|
||||
.map_err(|e| format!("Failed to sign PR event: {}", e))
|
||||
}
|
||||
|
||||
@@ -362,17 +353,17 @@ pub fn create_announcement_event(
|
||||
|
||||
if !clone_urls.is_empty() {
|
||||
let urls: Vec<String> = clone_urls.iter().map(|s| s.to_string()).collect();
|
||||
tags.push(Tag::custom(TagKind::custom("clone"), urls));
|
||||
tags.push(Tag::custom("clone", urls));
|
||||
}
|
||||
|
||||
if !relay_urls.is_empty() {
|
||||
let urls: Vec<String> = relay_urls.iter().map(|s| s.to_string()).collect();
|
||||
tags.push(Tag::custom(TagKind::custom("relays"), urls));
|
||||
tags.push(Tag::custom("relays", urls));
|
||||
}
|
||||
|
||||
EventBuilder::new(Kind::GitRepoAnnouncement, "")
|
||||
.tags(tags)
|
||||
.sign_with_keys(keys)
|
||||
.finalize(keys)
|
||||
.map_err(|e| format!("Failed to sign announcement event: {}", e))
|
||||
}
|
||||
|
||||
@@ -395,7 +386,9 @@ pub async fn wait_for_event_served(
|
||||
timeout: Duration,
|
||||
) -> Result<Event, String> {
|
||||
let temp_keys = Keys::generate();
|
||||
let client = Client::new(temp_keys);
|
||||
let client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(temp_keys))
|
||||
.build();
|
||||
|
||||
client
|
||||
.add_relay(relay_url)
|
||||
@@ -409,7 +402,7 @@ pub async fn wait_for_event_served(
|
||||
for _ in 0..20 {
|
||||
tokio::time::sleep(Duration::from_millis(100)).await;
|
||||
let relays = client.relays().await;
|
||||
if relays.values().any(|r| r.is_connected()) {
|
||||
if relays.values().any(|r| r.status().is_connected()) {
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
@@ -428,7 +421,11 @@ pub async fn wait_for_event_served(
|
||||
while start.elapsed() < timeout {
|
||||
let filter = Filter::new().id(*event_id);
|
||||
|
||||
match client.fetch_events(filter, Duration::from_secs(2)).await {
|
||||
match client
|
||||
.fetch_events(filter)
|
||||
.timeout(Duration::from_secs(2))
|
||||
.await
|
||||
{
|
||||
Ok(events) => {
|
||||
if let Some(event) = events.into_iter().next() {
|
||||
client.disconnect().await;
|
||||
@@ -470,7 +467,9 @@ pub async fn verify_event_not_served(
|
||||
check_duration: Duration,
|
||||
) -> Result<(), String> {
|
||||
let temp_keys = Keys::generate();
|
||||
let client = Client::new(temp_keys);
|
||||
let client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(temp_keys))
|
||||
.build();
|
||||
|
||||
client
|
||||
.add_relay(relay_url)
|
||||
@@ -484,7 +483,7 @@ pub async fn verify_event_not_served(
|
||||
for _ in 0..20 {
|
||||
tokio::time::sleep(Duration::from_millis(100)).await;
|
||||
let relays = client.relays().await;
|
||||
if relays.values().any(|r| r.is_connected()) {
|
||||
if relays.values().any(|r| r.status().is_connected()) {
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
@@ -498,7 +497,7 @@ pub async fn verify_event_not_served(
|
||||
// Check that event is NOT served
|
||||
let filter = Filter::new().id(*event_id);
|
||||
|
||||
match client.fetch_events(filter, check_duration).await {
|
||||
match client.fetch_events(filter).timeout(check_duration).await {
|
||||
Ok(events) => {
|
||||
client.disconnect().await;
|
||||
if events.is_empty() {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
//! `start_on_reservation_*` constructors — the listener stays bound for
|
||||
//! the duration of the reservation, eliminating the same-process race.
|
||||
|
||||
use nostr_sdk::ToBech32;
|
||||
use nostr_sdk::prelude::ToBech32;
|
||||
use std::path::PathBuf;
|
||||
use std::process::{Child, Command, Stdio};
|
||||
use std::time::{Duration, Instant};
|
||||
@@ -306,7 +306,7 @@ impl TestRelay {
|
||||
.join("ngit-grasp");
|
||||
|
||||
// Generate a test owner npub (using a random keypair)
|
||||
let test_keys = nostr_sdk::Keys::generate();
|
||||
let test_keys = nostr_sdk::prelude::Keys::generate();
|
||||
let test_npub = test_keys
|
||||
.public_key()
|
||||
.to_bech32()
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
//!
|
||||
//! # nostr-sdk 0.43 API Notes
|
||||
//! - Use field access: `event.id`, `event.tags`, `event.tags.iter()`
|
||||
//! - Use `Tag::custom(TagKind::custom("name"), vec![...])` syntax
|
||||
//! - Use `Tag::custom("name", vec![...])` syntax
|
||||
//! - Use `EventBuilder::new(kind, content).tags(tags)` syntax
|
||||
|
||||
use std::collections::HashMap;
|
||||
@@ -46,7 +46,9 @@ impl TestClient {
|
||||
/// * `Ok(TestClient)` on successful connection
|
||||
/// * `Err(String)` if connection fails after all retries
|
||||
pub async fn new(relay_url: &str, keys: Keys) -> Result<Self, String> {
|
||||
let client = Client::new(keys.clone());
|
||||
let client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(keys.clone()))
|
||||
.build();
|
||||
|
||||
client
|
||||
.add_relay(relay_url)
|
||||
@@ -74,7 +76,7 @@ impl TestClient {
|
||||
for attempt in 0..30 {
|
||||
tokio::time::sleep(Duration::from_millis(100)).await;
|
||||
let relays = self.client.relays().await;
|
||||
if relays.values().any(|r| r.is_connected()) {
|
||||
if relays.values().any(|r| r.status().is_connected()) {
|
||||
return Ok(());
|
||||
}
|
||||
if attempt == 29 {
|
||||
@@ -112,7 +114,7 @@ impl TestClient {
|
||||
match self.client.send_event(event).await {
|
||||
Ok(output) => {
|
||||
if !output.success.is_empty() {
|
||||
return Ok(output.val);
|
||||
return Ok(output.value);
|
||||
}
|
||||
// Log failures for debugging
|
||||
if !output.failed.is_empty() {
|
||||
@@ -215,16 +217,16 @@ fn build_layer2_issue_with_tag(
|
||||
tag_variant: TagVariant,
|
||||
) -> Result<Event, String> {
|
||||
let tag = match tag_variant {
|
||||
TagVariant::LowercaseA => Tag::custom(TagKind::custom("a"), vec![repo_coord.to_string()]),
|
||||
TagVariant::UppercaseA => Tag::custom(TagKind::custom("A"), vec![repo_coord.to_string()]),
|
||||
TagVariant::QuoteQ => Tag::custom(TagKind::custom("q"), vec![repo_coord.to_string()]),
|
||||
TagVariant::LowercaseA => Tag::custom("a", vec![repo_coord.to_string()]),
|
||||
TagVariant::UppercaseA => Tag::custom("A", vec![repo_coord.to_string()]),
|
||||
TagVariant::QuoteQ => Tag::custom("q", vec![repo_coord.to_string()]),
|
||||
};
|
||||
|
||||
let tags = vec![tag];
|
||||
|
||||
EventBuilder::new(Kind::GitIssue, title)
|
||||
.tags(tags)
|
||||
.sign_with_keys(keys)
|
||||
.finalize(keys)
|
||||
.map_err(|e| format!("Failed to sign Layer 2 issue event: {}", e))
|
||||
}
|
||||
|
||||
@@ -257,11 +259,11 @@ pub fn build_layer3_comment_event(
|
||||
// Choose tag based on kind (NIP-22 uses E, NIP-10 style uses e)
|
||||
let tag = if kind_num == Kind::Comment.as_u16() {
|
||||
// NIP-22 comment: uppercase 'E' tag
|
||||
Tag::custom(TagKind::custom("E"), vec![parent_event_id.to_hex()])
|
||||
Tag::custom("E", vec![parent_event_id.to_hex()])
|
||||
} else {
|
||||
// Kind 1 reply: lowercase 'e' tag with root marker (NIP-10)
|
||||
Tag::custom(
|
||||
TagKind::custom("e"),
|
||||
"e",
|
||||
vec![parent_event_id.to_hex(), "".to_string(), "root".to_string()],
|
||||
)
|
||||
};
|
||||
@@ -270,7 +272,7 @@ pub fn build_layer3_comment_event(
|
||||
|
||||
EventBuilder::new(kind, content)
|
||||
.tags(tags)
|
||||
.sign_with_keys(keys)
|
||||
.finalize(keys)
|
||||
.map_err(|e| format!("Failed to sign Layer 3 comment event: {}", e))
|
||||
}
|
||||
|
||||
@@ -281,13 +283,13 @@ pub fn build_layer3_reply_with_e_tag(
|
||||
content: &str,
|
||||
) -> Result<Event, String> {
|
||||
let tag = Tag::custom(
|
||||
TagKind::custom("e"),
|
||||
"e",
|
||||
vec![parent_event_id.to_hex(), "".to_string(), "root".to_string()],
|
||||
);
|
||||
|
||||
EventBuilder::new(Kind::Custom(1), content)
|
||||
.tags(vec![tag])
|
||||
.sign_with_keys(keys)
|
||||
.finalize(keys)
|
||||
.map_err(|e| format!("Failed to sign Layer 3 reply event: {}", e))
|
||||
}
|
||||
|
||||
@@ -297,11 +299,11 @@ pub fn build_layer3_comment_with_uppercase_e_tag(
|
||||
parent_event_id: &EventId,
|
||||
content: &str,
|
||||
) -> Result<Event, String> {
|
||||
let tag = Tag::custom(TagKind::custom("E"), vec![parent_event_id.to_hex()]);
|
||||
let tag = Tag::custom("E", vec![parent_event_id.to_hex()]);
|
||||
|
||||
EventBuilder::new(Kind::Comment, content)
|
||||
.tags(vec![tag])
|
||||
.sign_with_keys(keys)
|
||||
.finalize(keys)
|
||||
.map_err(|e| format!("Failed to sign Layer 3 comment event: {}", e))
|
||||
}
|
||||
|
||||
@@ -311,11 +313,11 @@ pub fn build_layer3_quote_with_q_tag(
|
||||
parent_event_id: &EventId,
|
||||
content: &str,
|
||||
) -> Result<Event, String> {
|
||||
let tag = Tag::custom(TagKind::custom("q"), vec![parent_event_id.to_hex()]);
|
||||
let tag = Tag::custom("q", vec![parent_event_id.to_hex()]);
|
||||
|
||||
EventBuilder::new(Kind::Custom(1), content)
|
||||
.tags(vec![tag])
|
||||
.sign_with_keys(keys)
|
||||
.finalize(keys)
|
||||
.map_err(|e| format!("Failed to sign Layer 3 quote event: {}", e))
|
||||
}
|
||||
|
||||
@@ -355,13 +357,13 @@ pub fn create_repo_announcement(keys: &Keys, domains: &[&str], identifier: &str)
|
||||
// Build tags for repository announcement
|
||||
let tags = vec![
|
||||
Tag::identifier(identifier),
|
||||
Tag::custom(TagKind::custom("clone"), clone_urls),
|
||||
Tag::custom(TagKind::custom("relays"), relay_urls),
|
||||
Tag::custom("clone", clone_urls),
|
||||
Tag::custom("relays", relay_urls),
|
||||
];
|
||||
|
||||
EventBuilder::new(Kind::GitRepoAnnouncement, "Repository state")
|
||||
.tags(tags)
|
||||
.sign_with_keys(keys)
|
||||
.finalize(keys)
|
||||
.expect("Failed to sign repo announcement")
|
||||
}
|
||||
|
||||
@@ -514,7 +516,9 @@ pub async fn wait_for_event_on_relay(relay_url: &str, filter: Filter, timeout: D
|
||||
loop {
|
||||
// Create a fresh client for each poll attempt (avoids stale connection state)
|
||||
let temp_keys = Keys::generate();
|
||||
let client = Client::new(temp_keys);
|
||||
let client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(temp_keys))
|
||||
.build();
|
||||
|
||||
if client.add_relay(relay_url).await.is_err() {
|
||||
if tokio::time::Instant::now() >= deadline {
|
||||
@@ -531,7 +535,7 @@ pub async fn wait_for_event_on_relay(relay_url: &str, filter: Filter, timeout: D
|
||||
for _ in 0..10 {
|
||||
tokio::time::sleep(Duration::from_millis(100)).await;
|
||||
let relays = client.relays().await;
|
||||
if relays.values().any(|r| r.is_connected()) {
|
||||
if relays.values().any(|r| r.status().is_connected()) {
|
||||
connected = true;
|
||||
break;
|
||||
}
|
||||
@@ -540,7 +544,10 @@ pub async fn wait_for_event_on_relay(relay_url: &str, filter: Filter, timeout: D
|
||||
if connected {
|
||||
// Use a short fetch window — if the event is there, EOSE comes back quickly
|
||||
let fetch_timeout = Duration::from_millis(500);
|
||||
let result = client.fetch_events(filter.clone(), fetch_timeout).await;
|
||||
let result = client
|
||||
.fetch_events(filter.clone())
|
||||
.timeout(fetch_timeout)
|
||||
.await;
|
||||
client.disconnect().await;
|
||||
|
||||
match result {
|
||||
@@ -1349,10 +1356,10 @@ pub async fn setup_announcement_on_relay(
|
||||
let announcement = EventBuilder::new(Kind::GitRepoAnnouncement, "Repository state")
|
||||
.tags(vec![
|
||||
Tag::identifier(identifier),
|
||||
Tag::custom(TagKind::custom("clone"), clone_urls.clone()),
|
||||
Tag::custom(TagKind::custom("relays"), relay_urls.clone()),
|
||||
Tag::custom("clone", clone_urls.clone()),
|
||||
Tag::custom("relays", relay_urls.clone()),
|
||||
])
|
||||
.sign_with_keys(keys)
|
||||
.finalize(keys)
|
||||
.expect("Failed to sign repo announcement");
|
||||
|
||||
// Build state event with all domains' clone URLs
|
||||
@@ -1471,10 +1478,10 @@ pub async fn run_sync_test(historic_events: &[Event], live_events: &[Event]) ->
|
||||
let announcement = EventBuilder::new(Kind::GitRepoAnnouncement, "Repository state")
|
||||
.tags(vec![
|
||||
Tag::identifier("test-repo"),
|
||||
Tag::custom(TagKind::custom("clone"), clone_urls.clone()),
|
||||
Tag::custom(TagKind::custom("relays"), relay_urls.clone()),
|
||||
Tag::custom("clone", clone_urls.clone()),
|
||||
Tag::custom("relays", relay_urls.clone()),
|
||||
])
|
||||
.sign_with_keys(&keys)
|
||||
.finalize(&keys)
|
||||
.expect("Failed to sign repo announcement");
|
||||
|
||||
// 5. Create state event referencing the commit
|
||||
|
||||
@@ -56,7 +56,7 @@ async fn test_nip77_negentropy_sync_finds_events() {
|
||||
// Build kind 10317 events (replaceable per pubkey, so two keys = two stored events)
|
||||
let event1 = EventBuilder::new(Kind::GitUserGraspList, "")
|
||||
.tags(vec![Tag::identifier("grasp-list-nip77-a")])
|
||||
.sign_with_keys(&keys1)
|
||||
.finalize(&keys1)
|
||||
.expect("Failed to sign event 1");
|
||||
let event1_id = event1.id;
|
||||
println!(
|
||||
@@ -67,7 +67,7 @@ async fn test_nip77_negentropy_sync_finds_events() {
|
||||
|
||||
let event2 = EventBuilder::new(Kind::GitUserGraspList, "")
|
||||
.tags(vec![Tag::identifier("grasp-list-nip77-b")])
|
||||
.sign_with_keys(&keys2)
|
||||
.finalize(&keys2)
|
||||
.expect("Failed to sign event 2");
|
||||
let event2_id = event2.id;
|
||||
println!(
|
||||
@@ -102,7 +102,9 @@ async fn test_nip77_negentropy_sync_finds_events() {
|
||||
|
||||
// 5. Create a fresh client to perform sync (different instance, no local events)
|
||||
let sync_keys = Keys::generate(); // Different keys, doesn't matter for sync
|
||||
let sync_client = Client::new(sync_keys);
|
||||
let sync_client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(sync_keys))
|
||||
.build();
|
||||
|
||||
sync_client
|
||||
.add_relay(relay.url())
|
||||
@@ -122,7 +124,7 @@ async fn test_nip77_negentropy_sync_finds_events() {
|
||||
|
||||
let sync_opts = SyncOptions::default();
|
||||
|
||||
let result = sync_client.sync(filter, &sync_opts).await;
|
||||
let result = sync_client.sync(filter).opts(sync_opts).await;
|
||||
|
||||
// 7. Cleanup
|
||||
sync_client.disconnect().await;
|
||||
@@ -131,7 +133,7 @@ async fn test_nip77_negentropy_sync_finds_events() {
|
||||
// 8. Verify results
|
||||
match result {
|
||||
Ok(output) => {
|
||||
let reconciliation = output.val;
|
||||
let reconciliation = output.value;
|
||||
println!("Negentropy sync completed!");
|
||||
println!(" Local: {:?}", reconciliation.local);
|
||||
println!(" Remote: {:?}", reconciliation.remote);
|
||||
@@ -180,7 +182,9 @@ async fn test_nip77_negentropy_sync_empty_result() {
|
||||
|
||||
// 2. Create client
|
||||
let keys = Keys::generate();
|
||||
let client = Client::new(keys.clone());
|
||||
let client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(keys.clone()))
|
||||
.build();
|
||||
|
||||
client
|
||||
.add_relay(relay.url())
|
||||
@@ -199,7 +203,7 @@ async fn test_nip77_negentropy_sync_empty_result() {
|
||||
|
||||
let sync_opts = SyncOptions::default();
|
||||
|
||||
let result = client.sync(filter, &sync_opts).await;
|
||||
let result = client.sync(filter).opts(sync_opts).await;
|
||||
|
||||
// 4. Cleanup
|
||||
client.disconnect().await;
|
||||
@@ -208,7 +212,7 @@ async fn test_nip77_negentropy_sync_empty_result() {
|
||||
// 5. Verify - should succeed but find nothing
|
||||
match result {
|
||||
Ok(output) => {
|
||||
let reconciliation = output.val;
|
||||
let reconciliation = output.value;
|
||||
println!("Empty sync completed!");
|
||||
println!(" Received: {:?}", reconciliation.received);
|
||||
println!(" Remote: {:?}", reconciliation.remote);
|
||||
|
||||
@@ -40,9 +40,7 @@ use std::time::Duration;
|
||||
|
||||
/// Helper to create a test event
|
||||
async fn create_test_event(keys: &Keys, content: &str) -> Event {
|
||||
EventBuilder::text_note(content)
|
||||
.sign_with_keys(keys)
|
||||
.unwrap()
|
||||
EventBuilder::text_note(content).finalize(keys).unwrap()
|
||||
}
|
||||
|
||||
/// Helper to create a state event with specific refs
|
||||
@@ -56,14 +54,14 @@ fn create_state_event_with_refs(
|
||||
// Add ref tags
|
||||
for (ref_name, commit_hash) in refs {
|
||||
tags.push(Tag::custom(
|
||||
TagKind::custom("ref"),
|
||||
"ref",
|
||||
vec![ref_name.to_string(), commit_hash.to_string()],
|
||||
));
|
||||
}
|
||||
|
||||
let event = EventBuilder::new(Kind::from(30618), "")
|
||||
.tags(tags)
|
||||
.sign_with_keys(keys)?;
|
||||
.finalize(keys)?;
|
||||
|
||||
Ok(event)
|
||||
}
|
||||
|
||||
+34
-16
@@ -62,7 +62,9 @@ async fn test_push_triggers_unified_processing() {
|
||||
// 3. Create and send announcement
|
||||
let announcement = create_repo_announcement(&keys, &[&relay.domain()], identifier);
|
||||
|
||||
let client = Client::new(keys.clone());
|
||||
let client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(keys.clone()))
|
||||
.build();
|
||||
client
|
||||
.add_relay(relay.url())
|
||||
.await
|
||||
@@ -163,7 +165,9 @@ async fn test_state_event_syncs_from_remote() {
|
||||
identifier,
|
||||
);
|
||||
|
||||
let source_client = Client::new(keys.clone());
|
||||
let source_client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(keys.clone()))
|
||||
.build();
|
||||
source_client
|
||||
.add_relay(source_relay.url())
|
||||
.await
|
||||
@@ -327,7 +331,9 @@ async fn test_pr_event_syncs_from_remote() {
|
||||
identifier,
|
||||
);
|
||||
|
||||
let source_client = Client::new(owner_keys.clone());
|
||||
let source_client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(owner_keys.clone()))
|
||||
.build();
|
||||
source_client
|
||||
.add_relay(source_relay.url())
|
||||
.await
|
||||
@@ -404,7 +410,9 @@ async fn test_pr_event_syncs_from_remote() {
|
||||
let pr_event_id = pr_event.id;
|
||||
|
||||
// Send PR event to source relay using PR author's client
|
||||
let pr_client = Client::new(pr_author_keys.clone());
|
||||
let pr_client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(pr_author_keys.clone()))
|
||||
.build();
|
||||
pr_client
|
||||
.add_relay(source_relay.url())
|
||||
.await
|
||||
@@ -540,7 +548,9 @@ async fn test_concurrent_state_and_pr_sync() {
|
||||
identifier,
|
||||
);
|
||||
|
||||
let source_client = Client::new(owner_keys.clone());
|
||||
let source_client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(owner_keys.clone()))
|
||||
.build();
|
||||
source_client
|
||||
.add_relay(source_relay.url())
|
||||
.await
|
||||
@@ -620,7 +630,9 @@ async fn test_concurrent_state_and_pr_sync() {
|
||||
let pr_event_id = pr_event.id;
|
||||
|
||||
// Send PR event to source relay using PR author's client
|
||||
let pr_client = Client::new(pr_author_keys.clone());
|
||||
let pr_client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(pr_author_keys.clone()))
|
||||
.build();
|
||||
pr_client
|
||||
.add_relay(source_relay.url())
|
||||
.await
|
||||
@@ -852,18 +864,18 @@ async fn test_pr_event_clone_tag_sync_with_partial_oid_aggregation_from_multiple
|
||||
// Create announcement with custom clone/relay URLs
|
||||
// Clone URLs: source_grasp + syncing (NOT git_server - PR commit only via PR's clone tag)
|
||||
// Relay URLs: source_grasp + mock_relay + syncing
|
||||
let announcement = nostr_sdk::EventBuilder::new(
|
||||
let announcement = nostr_sdk::prelude::EventBuilder::new(
|
||||
Kind::GitRepoAnnouncement,
|
||||
"Repository for PR clone tag + partial OID test",
|
||||
)
|
||||
.tags(vec![
|
||||
nostr_sdk::Tag::identifier(identifier),
|
||||
nostr_sdk::Tag::custom(
|
||||
nostr_sdk::TagKind::custom("clone"),
|
||||
nostr_sdk::prelude::Tag::identifier(identifier),
|
||||
nostr_sdk::prelude::Tag::custom(
|
||||
"clone",
|
||||
vec![clone_url_source.clone(), clone_url_syncing.clone()],
|
||||
),
|
||||
nostr_sdk::Tag::custom(
|
||||
nostr_sdk::TagKind::custom("relays"),
|
||||
nostr_sdk::prelude::Tag::custom(
|
||||
"relays",
|
||||
vec![
|
||||
source_grasp.url().to_string(),
|
||||
mock_relay.url().to_string(),
|
||||
@@ -871,11 +883,13 @@ async fn test_pr_event_clone_tag_sync_with_partial_oid_aggregation_from_multiple
|
||||
],
|
||||
),
|
||||
])
|
||||
.sign_with_keys(&owner_keys)
|
||||
.finalize(&owner_keys)
|
||||
.expect("Failed to sign announcement");
|
||||
|
||||
// Connect to source_grasp and send announcement
|
||||
let source_client = Client::new(owner_keys.clone());
|
||||
let source_client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(owner_keys.clone()))
|
||||
.build();
|
||||
source_client
|
||||
.add_relay(source_grasp.url())
|
||||
.await
|
||||
@@ -929,7 +943,9 @@ async fn test_pr_event_clone_tag_sync_with_partial_oid_aggregation_from_multiple
|
||||
// First, send announcement to mock_relay so it has the repo context
|
||||
// This is needed because the sync system filters events based on whether
|
||||
// they reference repos that list our relay
|
||||
let mock_client = Client::new(owner_keys.clone());
|
||||
let mock_client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(owner_keys.clone()))
|
||||
.build();
|
||||
mock_client
|
||||
.add_relay(mock_relay.url())
|
||||
.await
|
||||
@@ -960,7 +976,9 @@ async fn test_pr_event_clone_tag_sync_with_partial_oid_aggregation_from_multiple
|
||||
|
||||
// Send PR event to mock_relay
|
||||
// MockRelay accepts all events without validation (no purgatory)
|
||||
let pr_client = Client::new(pr_author_keys.clone());
|
||||
let pr_client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(pr_author_keys.clone()))
|
||||
.build();
|
||||
pr_client
|
||||
.add_relay(mock_relay.url())
|
||||
.await
|
||||
|
||||
@@ -20,10 +20,10 @@ async fn test_reject_state_without_announcement() {
|
||||
// Create a state event without any announcement
|
||||
let state_event = EventBuilder::new(Kind::RepoState, "")
|
||||
.tags([
|
||||
Tag::custom(TagKind::custom("d"), ["test-repo"]),
|
||||
Tag::custom(TagKind::custom("refs/heads/main"), ["abc123"]),
|
||||
Tag::custom("d", ["test-repo"]),
|
||||
Tag::custom("refs/heads/main", ["abc123"]),
|
||||
])
|
||||
.sign_with_keys(&keys)
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
|
||||
// Connect to relay
|
||||
@@ -77,14 +77,11 @@ async fn test_reject_state_from_unauthorized_author() {
|
||||
// Create announcement
|
||||
let announcement = EventBuilder::new(Kind::GitRepoAnnouncement, "")
|
||||
.tags([
|
||||
Tag::custom(TagKind::custom("d"), ["test-repo"]),
|
||||
Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
[format!("https://{}/test.git", relay.domain())],
|
||||
),
|
||||
Tag::custom(TagKind::custom("relays"), [relay.url()]),
|
||||
Tag::custom("d", ["test-repo"]),
|
||||
Tag::custom("clone", [format!("https://{}/test.git", relay.domain())]),
|
||||
Tag::custom("relays", [relay.url()]),
|
||||
])
|
||||
.sign_with_keys(&announcement_keys)
|
||||
.finalize(&announcement_keys)
|
||||
.unwrap();
|
||||
|
||||
// Connect to relay
|
||||
@@ -101,10 +98,10 @@ async fn test_reject_state_from_unauthorized_author() {
|
||||
// Try to send state event from unauthorized author
|
||||
let state_event = EventBuilder::new(Kind::RepoState, "")
|
||||
.tags([
|
||||
Tag::custom(TagKind::custom("d"), ["test-repo"]),
|
||||
Tag::custom(TagKind::custom("refs/heads/main"), ["abc123"]),
|
||||
Tag::custom("d", ["test-repo"]),
|
||||
Tag::custom("refs/heads/main", ["abc123"]),
|
||||
])
|
||||
.sign_with_keys(&unauthorized_keys)
|
||||
.finalize(&unauthorized_keys)
|
||||
.unwrap();
|
||||
|
||||
let result = client.send_event(&state_event).await;
|
||||
@@ -144,14 +141,11 @@ async fn test_accept_state_from_announcement_author() {
|
||||
// Create announcement
|
||||
let announcement = EventBuilder::new(Kind::GitRepoAnnouncement, "")
|
||||
.tags([
|
||||
Tag::custom(TagKind::custom("d"), ["test-repo"]),
|
||||
Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
[format!("https://{}/test.git", relay.domain())],
|
||||
),
|
||||
Tag::custom(TagKind::custom("relays"), [relay.url()]),
|
||||
Tag::custom("d", ["test-repo"]),
|
||||
Tag::custom("clone", [format!("https://{}/test.git", relay.domain())]),
|
||||
Tag::custom("relays", [relay.url()]),
|
||||
])
|
||||
.sign_with_keys(&keys)
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
|
||||
// Connect to relay
|
||||
@@ -168,10 +162,10 @@ async fn test_accept_state_from_announcement_author() {
|
||||
// Send state event from same author (should be accepted or go to purgatory)
|
||||
let state_event = EventBuilder::new(Kind::RepoState, "")
|
||||
.tags([
|
||||
Tag::custom(TagKind::custom("d"), ["test-repo"]),
|
||||
Tag::custom(TagKind::custom("refs/heads/main"), ["abc123"]),
|
||||
Tag::custom("d", ["test-repo"]),
|
||||
Tag::custom("refs/heads/main", ["abc123"]),
|
||||
])
|
||||
.sign_with_keys(&keys)
|
||||
.finalize(&keys)
|
||||
.unwrap();
|
||||
|
||||
let result = client.send_event(&state_event).await;
|
||||
@@ -214,18 +208,12 @@ async fn test_accept_state_from_maintainer() {
|
||||
// Create announcement with maintainer
|
||||
let announcement = EventBuilder::new(Kind::GitRepoAnnouncement, "")
|
||||
.tags([
|
||||
Tag::custom(TagKind::custom("d"), ["test-repo"]),
|
||||
Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
[format!("https://{}/test.git", relay.domain())],
|
||||
),
|
||||
Tag::custom(TagKind::custom("relays"), [relay.url()]),
|
||||
Tag::custom(
|
||||
TagKind::custom("maintainers"),
|
||||
[maintainer_keys.public_key().to_hex()],
|
||||
),
|
||||
Tag::custom("d", ["test-repo"]),
|
||||
Tag::custom("clone", [format!("https://{}/test.git", relay.domain())]),
|
||||
Tag::custom("relays", [relay.url()]),
|
||||
Tag::custom("maintainers", [maintainer_keys.public_key().to_hex()]),
|
||||
])
|
||||
.sign_with_keys(&owner_keys)
|
||||
.finalize(&owner_keys)
|
||||
.unwrap();
|
||||
|
||||
// Connect to relay
|
||||
@@ -242,10 +230,10 @@ async fn test_accept_state_from_maintainer() {
|
||||
// Send state event from maintainer
|
||||
let state_event = EventBuilder::new(Kind::RepoState, "")
|
||||
.tags([
|
||||
Tag::custom(TagKind::custom("d"), ["test-repo"]),
|
||||
Tag::custom(TagKind::custom("refs/heads/main"), ["abc123"]),
|
||||
Tag::custom("d", ["test-repo"]),
|
||||
Tag::custom("refs/heads/main", ["abc123"]),
|
||||
])
|
||||
.sign_with_keys(&maintainer_keys)
|
||||
.finalize(&maintainer_keys)
|
||||
.unwrap();
|
||||
|
||||
let result = client.send_event(&state_event).await;
|
||||
|
||||
@@ -17,14 +17,11 @@ use crate::common::{sync_helpers::*, TestRelay};
|
||||
///
|
||||
/// Used to create Layer 2 events like patches that reference a repository.
|
||||
fn create_event_referencing_repo(keys: &Keys, repo_coord: &str, kind: u16, content: &str) -> Event {
|
||||
let tags = vec![Tag::custom(
|
||||
TagKind::custom("a"),
|
||||
vec![repo_coord.to_string()],
|
||||
)];
|
||||
let tags = vec![Tag::custom("a", vec![repo_coord.to_string()])];
|
||||
|
||||
EventBuilder::new(Kind::from_u16(kind), content)
|
||||
.tags(tags)
|
||||
.sign_with_keys(keys)
|
||||
.finalize(keys)
|
||||
.expect("Failed to sign event")
|
||||
}
|
||||
|
||||
|
||||
@@ -425,7 +425,9 @@ async fn test_pagination_for_large_historic_sync() {
|
||||
|
||||
// Query for all issues
|
||||
let temp_keys = Keys::generate();
|
||||
let client = Client::new(temp_keys);
|
||||
let client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(temp_keys))
|
||||
.build();
|
||||
client
|
||||
.add_relay(syncing.url())
|
||||
.await
|
||||
@@ -436,7 +438,8 @@ async fn test_pagination_for_large_historic_sync() {
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
|
||||
let synced_issues = client
|
||||
.fetch_events(issues_filter, Duration::from_secs(5))
|
||||
.fetch_events(issues_filter)
|
||||
.timeout(Duration::from_secs(5))
|
||||
.await
|
||||
.expect("Failed to fetch issues from syncing relay");
|
||||
|
||||
|
||||
+13
-4
@@ -238,7 +238,9 @@ async fn test_live_sync_layer3_events() {
|
||||
let mut has_correct_ref = false;
|
||||
if comment_synced {
|
||||
let temp_keys = Keys::generate();
|
||||
let client = Client::new(temp_keys);
|
||||
let client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(temp_keys))
|
||||
.build();
|
||||
if client.add_relay(relay_b.url()).await.is_ok() {
|
||||
client.connect().await;
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
@@ -246,7 +248,8 @@ async fn test_live_sync_layer3_events() {
|
||||
let fetch_filter = Filter::new().kind(Kind::Comment).id(comment_id);
|
||||
|
||||
if let Ok(events) = client
|
||||
.fetch_events(fetch_filter, Duration::from_secs(2))
|
||||
.fetch_events(fetch_filter)
|
||||
.timeout(Duration::from_secs(2))
|
||||
.await
|
||||
{
|
||||
if let Some(event) = events.first() {
|
||||
@@ -376,7 +379,9 @@ async fn test_live_sync_event_ordering() {
|
||||
|
||||
// 6. Fetch all events from relay_b
|
||||
let temp_keys = Keys::generate();
|
||||
let client = Client::new(temp_keys);
|
||||
let client = Client::builder()
|
||||
.authenticator(SignerAuthenticator::new(temp_keys))
|
||||
.build();
|
||||
|
||||
let events_found: Vec<Event>;
|
||||
if client.add_relay(relay_b.url()).await.is_ok() {
|
||||
@@ -385,7 +390,11 @@ async fn test_live_sync_event_ordering() {
|
||||
|
||||
let filter = Filter::new().kind(Kind::GitIssue).author(keys.public_key());
|
||||
|
||||
match client.fetch_events(filter, Duration::from_secs(3)).await {
|
||||
match client
|
||||
.fetch_events(filter)
|
||||
.timeout(Duration::from_secs(3))
|
||||
.await
|
||||
{
|
||||
Ok(events) => {
|
||||
events_found = events.into_iter().collect();
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ async fn test_maintainer_announcement_reprocessed_immediately() {
|
||||
.tags(vec![
|
||||
Tag::identifier(identifier),
|
||||
Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
"clone",
|
||||
vec![format!(
|
||||
"http://{}/{}/{}.git",
|
||||
relay_a.domain(),
|
||||
@@ -70,9 +70,9 @@ async fn test_maintainer_announcement_reprocessed_immediately() {
|
||||
identifier
|
||||
)],
|
||||
),
|
||||
Tag::custom(TagKind::custom("relays"), vec![relay_a.url().to_string()]),
|
||||
Tag::custom("relays", vec![relay_a.url().to_string()]),
|
||||
])
|
||||
.sign_with_keys(&maintainer_keys)
|
||||
.finalize(&maintainer_keys)
|
||||
.unwrap();
|
||||
send_to_relay(&relay_a, &maintainer_announcement)
|
||||
.await
|
||||
@@ -104,7 +104,7 @@ async fn test_maintainer_announcement_reprocessed_immediately() {
|
||||
.tags(vec![
|
||||
Tag::identifier(identifier),
|
||||
Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
"clone",
|
||||
vec![format!(
|
||||
"http://{}/{}/{}.git",
|
||||
relay_b.domain(),
|
||||
@@ -113,15 +113,12 @@ async fn test_maintainer_announcement_reprocessed_immediately() {
|
||||
)],
|
||||
),
|
||||
Tag::custom(
|
||||
TagKind::custom("relays"),
|
||||
"relays",
|
||||
vec![relay_a.url().to_string(), relay_b.url().to_string()],
|
||||
),
|
||||
Tag::custom(
|
||||
TagKind::custom("maintainers"),
|
||||
vec![maintainer_keys.public_key().to_hex()],
|
||||
),
|
||||
Tag::custom("maintainers", vec![maintainer_keys.public_key().to_hex()]),
|
||||
])
|
||||
.sign_with_keys(&owner_keys)
|
||||
.finalize(&owner_keys)
|
||||
.unwrap();
|
||||
|
||||
send_to_relay(&relay_b, &owner_announcement).await.unwrap();
|
||||
@@ -208,15 +205,12 @@ async fn test_maintainer_announcement_cold_index_prevents_refetch() {
|
||||
.tags(vec![
|
||||
Tag::identifier(identifier),
|
||||
Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
"clone",
|
||||
vec![format!("https://example.com/{}.git", identifier)],
|
||||
),
|
||||
Tag::custom(
|
||||
TagKind::custom("relays"),
|
||||
vec!["wss://example.com".to_string()],
|
||||
),
|
||||
Tag::custom("relays", vec!["wss://example.com".to_string()]),
|
||||
])
|
||||
.sign_with_keys(&maintainer_keys)
|
||||
.finalize(&maintainer_keys)
|
||||
.unwrap();
|
||||
|
||||
// Send maintainer announcement - expect it to be rejected
|
||||
@@ -232,16 +226,13 @@ async fn test_maintainer_announcement_cold_index_prevents_refetch() {
|
||||
.tags(vec![
|
||||
Tag::identifier(identifier),
|
||||
Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
"clone",
|
||||
vec![format!("https://{}/{}.git", relay.domain(), identifier)],
|
||||
),
|
||||
Tag::custom(TagKind::custom("relays"), vec![relay.url().to_string()]),
|
||||
Tag::custom(
|
||||
TagKind::custom("maintainers"),
|
||||
vec![maintainer_keys.public_key().to_hex()],
|
||||
),
|
||||
Tag::custom("relays", vec![relay.url().to_string()]),
|
||||
Tag::custom("maintainers", vec![maintainer_keys.public_key().to_hex()]),
|
||||
])
|
||||
.sign_with_keys(&owner_keys)
|
||||
.finalize(&owner_keys)
|
||||
.unwrap();
|
||||
|
||||
client.send_event(&owner_announcement).await.unwrap();
|
||||
@@ -324,7 +315,7 @@ async fn test_multiple_maintainers_all_reprocessed() {
|
||||
.tags(vec![
|
||||
Tag::identifier(identifier.as_str()),
|
||||
Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
"clone",
|
||||
vec![format!(
|
||||
"http://{}/{}/{}.git",
|
||||
relay_a.domain(),
|
||||
@@ -332,9 +323,9 @@ async fn test_multiple_maintainers_all_reprocessed() {
|
||||
identifier
|
||||
)],
|
||||
),
|
||||
Tag::custom(TagKind::custom("relays"), vec![relay_a.url().to_string()]),
|
||||
Tag::custom("relays", vec![relay_a.url().to_string()]),
|
||||
])
|
||||
.sign_with_keys(maintainer_keys)
|
||||
.finalize(*maintainer_keys)
|
||||
.unwrap();
|
||||
send_to_relay(&relay_a, &announcement).await.unwrap();
|
||||
// Use push_unique_git_data_to_relay so each maintainer gets a distinct commit
|
||||
@@ -395,7 +386,7 @@ async fn test_multiple_maintainers_all_reprocessed() {
|
||||
.tags(vec![
|
||||
Tag::identifier(identifier),
|
||||
Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
"clone",
|
||||
vec![format!(
|
||||
"http://{}/{}/{}.git",
|
||||
relay_b.domain(),
|
||||
@@ -404,11 +395,11 @@ async fn test_multiple_maintainers_all_reprocessed() {
|
||||
)],
|
||||
),
|
||||
Tag::custom(
|
||||
TagKind::custom("relays"),
|
||||
"relays",
|
||||
vec![relay_a.url().to_string(), relay_b.url().to_string()],
|
||||
),
|
||||
Tag::custom(
|
||||
TagKind::custom("maintainers"),
|
||||
"maintainers",
|
||||
vec![
|
||||
maintainer1_keys.public_key().to_hex(),
|
||||
maintainer2_keys.public_key().to_hex(),
|
||||
@@ -416,7 +407,7 @@ async fn test_multiple_maintainers_all_reprocessed() {
|
||||
],
|
||||
),
|
||||
])
|
||||
.sign_with_keys(&owner_keys)
|
||||
.finalize(&owner_keys)
|
||||
.unwrap();
|
||||
|
||||
send_to_relay(&relay_b, &owner_announcement).await.unwrap();
|
||||
@@ -482,15 +473,12 @@ async fn test_invalid_maintainer_pubkey_handled_gracefully() {
|
||||
.tags(vec![
|
||||
Tag::identifier(identifier),
|
||||
Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
"clone",
|
||||
vec![format!("https://example.com/{}.git", identifier)],
|
||||
),
|
||||
Tag::custom(
|
||||
TagKind::custom("relays"),
|
||||
vec!["wss://example.com".to_string()],
|
||||
),
|
||||
Tag::custom("relays", vec!["wss://example.com".to_string()]),
|
||||
])
|
||||
.sign_with_keys(&maintainer_keys)
|
||||
.finalize(&maintainer_keys)
|
||||
.unwrap();
|
||||
|
||||
// Send maintainer announcement - expect it to be rejected
|
||||
@@ -509,7 +497,7 @@ async fn test_invalid_maintainer_pubkey_handled_gracefully() {
|
||||
.tags(vec![
|
||||
Tag::identifier(identifier),
|
||||
Tag::custom(
|
||||
TagKind::custom("clone"),
|
||||
"clone",
|
||||
vec![format!(
|
||||
"http://{}/{}/{}.git",
|
||||
relay.domain(),
|
||||
@@ -517,13 +505,10 @@ async fn test_invalid_maintainer_pubkey_handled_gracefully() {
|
||||
identifier
|
||||
)],
|
||||
),
|
||||
Tag::custom(TagKind::custom("relays"), vec![relay.url().to_string()]),
|
||||
Tag::custom(
|
||||
TagKind::custom("maintainers"),
|
||||
vec!["invalid-hex-not-a-pubkey".to_string()],
|
||||
),
|
||||
Tag::custom("relays", vec![relay.url().to_string()]),
|
||||
Tag::custom("maintainers", vec!["invalid-hex-not-a-pubkey".to_string()]),
|
||||
])
|
||||
.sign_with_keys(&owner_keys)
|
||||
.finalize(&owner_keys)
|
||||
.unwrap();
|
||||
|
||||
send_to_relay(&relay, &owner_announcement).await.unwrap();
|
||||
|
||||
@@ -183,14 +183,11 @@ async fn test_metric_values_are_numeric() {
|
||||
///
|
||||
/// Used to create Layer 2 events like patches that reference a repository.
|
||||
fn create_event_referencing_repo(keys: &Keys, repo_coord: &str, kind: u16, content: &str) -> Event {
|
||||
let tags = vec![Tag::custom(
|
||||
TagKind::custom("a"),
|
||||
vec![repo_coord.to_string()],
|
||||
)];
|
||||
let tags = vec![Tag::custom("a", vec![repo_coord.to_string()])];
|
||||
|
||||
EventBuilder::new(Kind::from_u16(kind), content)
|
||||
.tags(tags)
|
||||
.sign_with_keys(keys)
|
||||
.finalize(keys)
|
||||
.expect("Failed to sign event")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user