diff options
Diffstat (limited to 'src/nostr/policy')
| -rw-r--r-- | src/nostr/policy/announcement.rs | 18 | ||||
| -rw-r--r-- | src/nostr/policy/deletion.rs | 45 | ||||
| -rw-r--r-- | src/nostr/policy/pr_event.rs | 10 | ||||
| -rw-r--r-- | src/nostr/policy/state.rs | 6 |
4 files changed, 50 insertions, 29 deletions
diff --git a/src/nostr/policy/announcement.rs b/src/nostr/policy/announcement.rs index b366f0b..aba5181 100644 --- a/src/nostr/policy/announcement.rs +++ b/src/nostr/policy/announcement.rs | |||
| @@ -70,7 +70,10 @@ impl AnnouncementPolicy { | |||
| 70 | .is_some_and(|entry| event.created_at > entry.event.created_at); | 70 | .is_some_and(|entry| event.created_at > entry.event.created_at); |
| 71 | 71 | ||
| 72 | if should_evict { | 72 | if should_evict { |
| 73 | self.remove_purgatory_announcement(&event.pubkey, &announcement.identifier); | 73 | self.remove_purgatory_announcement( |
| 74 | &event.pubkey, | ||
| 75 | &announcement.identifier, | ||
| 76 | ); | ||
| 74 | } | 77 | } |
| 75 | 78 | ||
| 76 | match self | 79 | match self |
| @@ -145,10 +148,9 @@ impl AnnouncementPolicy { | |||
| 145 | ); | 148 | ); |
| 146 | AnnouncementResult::AcceptPurgatory | 149 | AnnouncementResult::AcceptPurgatory |
| 147 | } | 150 | } |
| 148 | Err(e) => AnnouncementResult::Reject(format!( | 151 | Err(e) => { |
| 149 | "Failed to parse announcement: {}", | 152 | AnnouncementResult::Reject(format!("Failed to parse announcement: {}", e)) |
| 150 | e | 153 | } |
| 151 | )), | ||
| 152 | } | 154 | } |
| 153 | } | 155 | } |
| 154 | // AcceptPurgatory shouldn't come from validate_announcement, but handle it | 156 | // AcceptPurgatory shouldn't come from validate_announcement, but handle it |
| @@ -161,11 +163,7 @@ impl AnnouncementPolicy { | |||
| 161 | /// Called when a replacement announcement arrives for a (pubkey, identifier) pair | 163 | /// Called when a replacement announcement arrives for a (pubkey, identifier) pair |
| 162 | /// that is currently in purgatory. Updates the purgatory entry and extends the | 164 | /// that is currently in purgatory. Updates the purgatory entry and extends the |
| 163 | /// expiry so the new announcement has a fresh waiting window. | 165 | /// expiry so the new announcement has a fresh waiting window. |
| 164 | fn replace_purgatory_announcement( | 166 | fn replace_purgatory_announcement(&self, event: &Event, announcement: &RepositoryAnnouncement) { |
| 165 | &self, | ||
| 166 | event: &Event, | ||
| 167 | announcement: &RepositoryAnnouncement, | ||
| 168 | ) { | ||
| 169 | let repo_path = self.ctx.git_data_path.join(announcement.repo_path()); | 167 | let repo_path = self.ctx.git_data_path.join(announcement.repo_path()); |
| 170 | let relays: HashSet<String> = announcement.relays.iter().cloned().collect(); | 168 | let relays: HashSet<String> = announcement.relays.iter().cloned().collect(); |
| 171 | 169 | ||
diff --git a/src/nostr/policy/deletion.rs b/src/nostr/policy/deletion.rs index 6457c90..c5a52d4 100644 --- a/src/nostr/policy/deletion.rs +++ b/src/nostr/policy/deletion.rs | |||
| @@ -155,7 +155,9 @@ impl DeletionPolicy { | |||
| 155 | author = %author.to_hex(), | 155 | author = %author.to_hex(), |
| 156 | "Deletion request: removing purgatory state event by event ID" | 156 | "Deletion request: removing purgatory state event by event ID" |
| 157 | ); | 157 | ); |
| 158 | self.ctx.purgatory.remove_state_event(&identifier, &entry.event.id); | 158 | self.ctx |
| 159 | .purgatory | ||
| 160 | .remove_state_event(&identifier, &entry.event.id); | ||
| 159 | return; // event IDs are unique | 161 | return; // event IDs are unique |
| 160 | } | 162 | } |
| 161 | } | 163 | } |
| @@ -223,7 +225,9 @@ impl DeletionPolicy { | |||
| 223 | if entry.author == *author | 225 | if entry.author == *author |
| 224 | && entry.event.created_at.as_secs() <= deletion_created_at | 226 | && entry.event.created_at.as_secs() <= deletion_created_at |
| 225 | { | 227 | { |
| 226 | self.ctx.purgatory.remove_state_event(identifier, &entry.event.id); | 228 | self.ctx |
| 229 | .purgatory | ||
| 230 | .remove_state_event(identifier, &entry.event.id); | ||
| 227 | removed += 1; | 231 | removed += 1; |
| 228 | } | 232 | } |
| 229 | } | 233 | } |
| @@ -306,7 +310,10 @@ mod tests { | |||
| 306 | EventBuilder::new(Kind::GitRepoAnnouncement, "") | 310 | EventBuilder::new(Kind::GitRepoAnnouncement, "") |
| 307 | .tags(vec![ | 311 | .tags(vec![ |
| 308 | Tag::identifier(identifier), | 312 | Tag::identifier(identifier), |
| 309 | Tag::custom(TagKind::custom("clone"), vec!["https://example.com/repo.git"]), | 313 | Tag::custom( |
| 314 | TagKind::custom("clone"), | ||
| 315 | vec!["https://example.com/repo.git"], | ||
| 316 | ), | ||
| 310 | ]) | 317 | ]) |
| 311 | .sign_with_keys(keys) | 318 | .sign_with_keys(keys) |
| 312 | .unwrap() | 319 | .unwrap() |
| @@ -331,7 +338,9 @@ mod tests { | |||
| 331 | let announcement = make_announcement_event(&keys, identifier); | 338 | let announcement = make_announcement_event(&keys, identifier); |
| 332 | add_to_purgatory(&ctx, &announcement, identifier); | 339 | add_to_purgatory(&ctx, &announcement, identifier); |
| 333 | 340 | ||
| 334 | assert!(ctx.purgatory.has_purgatory_announcement(&keys.public_key(), identifier)); | 341 | assert!(ctx |
| 342 | .purgatory | ||
| 343 | .has_purgatory_announcement(&keys.public_key(), identifier)); | ||
| 335 | 344 | ||
| 336 | // Build kind 5 deletion event referencing the announcement by event ID | 345 | // Build kind 5 deletion event referencing the announcement by event ID |
| 337 | let deletion = EventBuilder::new(Kind::EventDeletion, "") | 346 | let deletion = EventBuilder::new(Kind::EventDeletion, "") |
| @@ -347,7 +356,8 @@ mod tests { | |||
| 347 | 356 | ||
| 348 | assert!(matches!(result, WritePolicyResult::Accept)); | 357 | assert!(matches!(result, WritePolicyResult::Accept)); |
| 349 | assert!( | 358 | assert!( |
| 350 | !ctx.purgatory.has_purgatory_announcement(&keys.public_key(), identifier), | 359 | !ctx.purgatory |
| 360 | .has_purgatory_announcement(&keys.public_key(), identifier), | ||
| 351 | "Purgatory entry should have been removed" | 361 | "Purgatory entry should have been removed" |
| 352 | ); | 362 | ); |
| 353 | } | 363 | } |
| @@ -361,7 +371,9 @@ mod tests { | |||
| 361 | let announcement = make_announcement_event(&keys, identifier); | 371 | let announcement = make_announcement_event(&keys, identifier); |
| 362 | add_to_purgatory(&ctx, &announcement, identifier); | 372 | add_to_purgatory(&ctx, &announcement, identifier); |
| 363 | 373 | ||
| 364 | assert!(ctx.purgatory.has_purgatory_announcement(&keys.public_key(), identifier)); | 374 | assert!(ctx |
| 375 | .purgatory | ||
| 376 | .has_purgatory_announcement(&keys.public_key(), identifier)); | ||
| 365 | 377 | ||
| 366 | // Build kind 5 deletion event referencing the announcement by coordinate | 378 | // Build kind 5 deletion event referencing the announcement by coordinate |
| 367 | let coord = format!("30617:{}:{}", keys.public_key().to_hex(), identifier); | 379 | let coord = format!("30617:{}:{}", keys.public_key().to_hex(), identifier); |
| @@ -378,7 +390,8 @@ mod tests { | |||
| 378 | 390 | ||
| 379 | assert!(matches!(result, WritePolicyResult::Accept)); | 391 | assert!(matches!(result, WritePolicyResult::Accept)); |
| 380 | assert!( | 392 | assert!( |
| 381 | !ctx.purgatory.has_purgatory_announcement(&keys.public_key(), identifier), | 393 | !ctx.purgatory |
| 394 | .has_purgatory_announcement(&keys.public_key(), identifier), | ||
| 382 | "Purgatory entry should have been removed" | 395 | "Purgatory entry should have been removed" |
| 383 | ); | 396 | ); |
| 384 | } | 397 | } |
| @@ -407,7 +420,8 @@ mod tests { | |||
| 407 | 420 | ||
| 408 | assert!(matches!(result, WritePolicyResult::Accept)); | 421 | assert!(matches!(result, WritePolicyResult::Accept)); |
| 409 | assert!( | 422 | assert!( |
| 410 | ctx.purgatory.has_purgatory_announcement(&owner_keys.public_key(), identifier), | 423 | ctx.purgatory |
| 424 | .has_purgatory_announcement(&owner_keys.public_key(), identifier), | ||
| 411 | "Purgatory entry should NOT have been removed by wrong author" | 425 | "Purgatory entry should NOT have been removed by wrong author" |
| 412 | ); | 426 | ); |
| 413 | } | 427 | } |
| @@ -438,7 +452,8 @@ mod tests { | |||
| 438 | 452 | ||
| 439 | assert!(matches!(result, WritePolicyResult::Accept)); | 453 | assert!(matches!(result, WritePolicyResult::Accept)); |
| 440 | assert!( | 454 | assert!( |
| 441 | ctx.purgatory.has_purgatory_announcement(&owner_keys.public_key(), identifier), | 455 | ctx.purgatory |
| 456 | .has_purgatory_announcement(&owner_keys.public_key(), identifier), | ||
| 442 | "Purgatory entry should NOT have been removed by wrong author" | 457 | "Purgatory entry should NOT have been removed by wrong author" |
| 443 | ); | 458 | ); |
| 444 | } | 459 | } |
| @@ -450,11 +465,10 @@ mod tests { | |||
| 450 | 465 | ||
| 451 | // No purgatory entry exists — deletion should still be accepted | 466 | // No purgatory entry exists — deletion should still be accepted |
| 452 | let deletion = EventBuilder::new(Kind::EventDeletion, "") | 467 | let deletion = EventBuilder::new(Kind::EventDeletion, "") |
| 453 | .tags(vec![ | 468 | .tags(vec![Tag::custom( |
| 454 | Tag::custom(TagKind::custom("a"), vec![ | 469 | TagKind::custom("a"), |
| 455 | format!("30617:{}:nonexistent", keys.public_key().to_hex()) | 470 | vec![format!("30617:{}:nonexistent", keys.public_key().to_hex())], |
| 456 | ]), | 471 | )]) |
| 457 | ]) | ||
| 458 | .sign_with_keys(&keys) | 472 | .sign_with_keys(&keys) |
| 459 | .unwrap(); | 473 | .unwrap(); |
| 460 | 474 | ||
| @@ -491,7 +505,8 @@ mod tests { | |||
| 491 | 505 | ||
| 492 | assert!(matches!(result, WritePolicyResult::Accept)); | 506 | assert!(matches!(result, WritePolicyResult::Accept)); |
| 493 | assert!( | 507 | assert!( |
| 494 | ctx.purgatory.has_purgatory_announcement(&keys.public_key(), identifier), | 508 | ctx.purgatory |
| 509 | .has_purgatory_announcement(&keys.public_key(), identifier), | ||
| 495 | "Purgatory entry should NOT be removed: entry is newer than deletion request" | 510 | "Purgatory entry should NOT be removed: entry is newer than deletion request" |
| 496 | ); | 511 | ); |
| 497 | } | 512 | } |
diff --git a/src/nostr/policy/pr_event.rs b/src/nostr/policy/pr_event.rs index 52747a4..e4a64b8 100644 --- a/src/nostr/policy/pr_event.rs +++ b/src/nostr/policy/pr_event.rs | |||
| @@ -7,7 +7,9 @@ use nostr_relay_builder::prelude::Event; | |||
| 7 | 7 | ||
| 8 | use super::PolicyContext; | 8 | use super::PolicyContext; |
| 9 | use crate::git; | 9 | use crate::git; |
| 10 | use crate::git::authorization::{collect_authorized_maintainers, fetch_repository_data_excluding_purgatory}; | 10 | use crate::git::authorization::{ |
| 11 | collect_authorized_maintainers, fetch_repository_data_excluding_purgatory, | ||
| 12 | }; | ||
| 11 | 13 | ||
| 12 | /// Policy for validating PR and PR Update events | 14 | /// Policy for validating PR and PR Update events |
| 13 | #[derive(Clone)] | 15 | #[derive(Clone)] |
| @@ -131,7 +133,8 @@ impl PrEventPolicy { | |||
| 131 | // only be accepted for announcements that have been promoted (validated). | 133 | // only be accepted for announcements that have been promoted (validated). |
| 132 | // If the announcement is still in purgatory, the PR event should also go | 134 | // If the announcement is still in purgatory, the PR event should also go |
| 133 | // to purgatory and wait for the announcement to be promoted. | 135 | // to purgatory and wait for the announcement to be promoted. |
| 134 | let db_repo_data = fetch_repository_data_excluding_purgatory(&self.ctx.database, &identifier).await?; | 136 | let db_repo_data = |
| 137 | fetch_repository_data_excluding_purgatory(&self.ctx.database, &identifier).await?; | ||
| 135 | 138 | ||
| 136 | // Extract owner pubkey from source repo path | 139 | // Extract owner pubkey from source repo path |
| 137 | let owner_pubkey = crate::git::sync::extract_owner_from_repo_path( | 140 | let owner_pubkey = crate::git::sync::extract_owner_from_repo_path( |
| @@ -211,7 +214,8 @@ impl PrEventPolicy { | |||
| 211 | // only be accepted for announcements that have been promoted (validated). | 214 | // only be accepted for announcements that have been promoted (validated). |
| 212 | // If the announcement is still in purgatory, the PR event should also go | 215 | // If the announcement is still in purgatory, the PR event should also go |
| 213 | // to purgatory and wait for the announcement to be promoted. | 216 | // to purgatory and wait for the announcement to be promoted. |
| 214 | let db_repo_data = fetch_repository_data_excluding_purgatory(&self.ctx.database, identifier).await?; | 217 | let db_repo_data = |
| 218 | fetch_repository_data_excluding_purgatory(&self.ctx.database, identifier).await?; | ||
| 215 | 219 | ||
| 216 | // 3. Extract list of maintainers from "a 30617:<maintainer>:<identifier>" tags | 220 | // 3. Extract list of maintainers from "a 30617:<maintainer>:<identifier>" tags |
| 217 | let mut maintainer_pubkeys = std::collections::HashSet::new(); | 221 | let mut maintainer_pubkeys = std::collections::HashSet::new(); |
diff --git a/src/nostr/policy/state.rs b/src/nostr/policy/state.rs index df743ae..80fe84c 100644 --- a/src/nostr/policy/state.rs +++ b/src/nostr/policy/state.rs | |||
| @@ -158,7 +158,11 @@ impl StatePolicy { | |||
| 158 | // authorized it. | 158 | // authorized it. |
| 159 | for owner_hex in &authorized_owners { | 159 | for owner_hex in &authorized_owners { |
| 160 | if let Ok(owner_pk) = nostr_sdk::PublicKey::from_hex(owner_hex) { | 160 | if let Ok(owner_pk) = nostr_sdk::PublicKey::from_hex(owner_hex) { |
| 161 | if self.ctx.purgatory.has_purgatory_announcement(&owner_pk, &state.identifier) { | 161 | if self |
| 162 | .ctx | ||
| 163 | .purgatory | ||
| 164 | .has_purgatory_announcement(&owner_pk, &state.identifier) | ||
| 165 | { | ||
| 162 | self.ctx.purgatory.extend_announcement_expiry( | 166 | self.ctx.purgatory.extend_announcement_expiry( |
| 163 | &owner_pk, | 167 | &owner_pk, |
| 164 | &state.identifier, | 168 | &state.identifier, |