upleb.uk

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

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2026-02-18 08:59:52 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2026-02-18 08:59:52 +0000
commit467690f33bbbfd442852e61de221e4e5e161b878 (patch)
tree2fc88bb35824143c6b670c0c4962a562d5816362
parentcad58fccae7ed84bb033e56de0f1323b714a854d (diff)
fix: check purgatory in maintainer announcement lookup
is_maintainer_in_any_announcement only queried the database, missing announcements still in purgatory. A maintainer's announcement (which lists the recursive maintainer) may arrive and enter purgatory before the recursive maintainer's announcement does, causing the maintainer exception check to return false and reject the recursive maintainer's announcement.
-rw-r--r--src/nostr/policy/announcement.rs27
1 files changed, 23 insertions, 4 deletions
diff --git a/src/nostr/policy/announcement.rs b/src/nostr/policy/announcement.rs
index 1118497..abe9651 100644
--- a/src/nostr/policy/announcement.rs
+++ b/src/nostr/policy/announcement.rs
@@ -222,6 +222,11 @@ impl AnnouncementPolicy {
222 /// 222 ///
223 /// This enables accepting announcements from maintainers even when they don't list 223 /// This enables accepting announcements from maintainers even when they don't list
224 /// this GRASP server, for maintainer chain discovery and GRASP-02 sync. 224 /// this GRASP server, for maintainer chain discovery and GRASP-02 sync.
225 ///
226 /// Checks both the database (promoted announcements) and purgatory (announcements
227 /// waiting for git data). This is necessary because a maintainer's announcement
228 /// (which lists the recursive maintainer) may still be in purgatory when the
229 /// recursive maintainer's announcement arrives.
225 async fn is_maintainer_in_any_announcement( 230 async fn is_maintainer_in_any_announcement(
226 &self, 231 &self,
227 identifier: &str, 232 identifier: &str,
@@ -233,12 +238,26 @@ impl AnnouncementPolicy {
233 identifier.to_string(), 238 identifier.to_string(),
234 ); 239 );
235 240
236 let announcements: Vec<Event> = match self.ctx.database.query(filter).await { 241 let db_announcements: Vec<Event> = match self.ctx.database.query(filter).await {
237 Ok(events) => events.into_iter().collect(), 242 Ok(events) => events.into_iter().collect(),
238 Err(e) => return Err(format!("Database query failed: {}", e)), 243 Err(e) => return Err(format!("Database query failed: {}", e)),
239 }; 244 };
240 245
241 if announcements.is_empty() { 246 // Also collect purgatory announcements for this identifier
247 let purgatory_announcements: Vec<Event> = self
248 .ctx
249 .purgatory
250 .get_announcements_by_identifier(identifier)
251 .into_iter()
252 .map(|entry| entry.event)
253 .collect();
254
255 let all_announcements: Vec<&Event> = db_announcements
256 .iter()
257 .chain(purgatory_announcements.iter())
258 .collect();
259
260 if all_announcements.is_empty() {
242 // No existing announcements for this identifier - author cannot be a maintainer 261 // No existing announcements for this identifier - author cannot be a maintainer
243 return Ok(false); 262 return Ok(false);
244 } 263 }
@@ -246,14 +265,14 @@ impl AnnouncementPolicy {
246 let author_hex = author.to_hex(); 265 let author_hex = author.to_hex();
247 266
248 // Check each announcement to see if author is listed as a maintainer 267 // Check each announcement to see if author is listed as a maintainer
249 for event in &announcements { 268 for event in &all_announcements {
250 // Check if author is the owner of this announcement 269 // Check if author is the owner of this announcement
251 if event.pubkey == *author { 270 if event.pubkey == *author {
252 return Ok(true); 271 return Ok(true);
253 } 272 }
254 273
255 // Check if author is listed in the maintainers tag 274 // Check if author is listed in the maintainers tag
256 if let Ok(announcement) = RepositoryAnnouncement::from_event(event.clone()) { 275 if let Ok(announcement) = RepositoryAnnouncement::from_event((*event).clone()) {
257 if announcement.maintainers.contains(&author_hex) { 276 if announcement.maintainers.contains(&author_hex) {
258 return Ok(true); 277 return Ok(true);
259 } 278 }