diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2025-11-26 15:36:12 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2025-11-26 17:16:24 +0000 |
| commit | 734d255efaa26bcb18b29d655bf30f8affb3a852 (patch) | |
| tree | b0d5b72e38bd4ceb6d35334741708f2a774a4994 /grasp-audit/src/client.rs | |
| parent | 158d3f0722e731f2b534951069c322c5cbb5a721 (diff) | |
test: use fixtures in push tests
Diffstat (limited to 'grasp-audit/src/client.rs')
| -rw-r--r-- | grasp-audit/src/client.rs | 147 |
1 files changed, 85 insertions, 62 deletions
diff --git a/grasp-audit/src/client.rs b/grasp-audit/src/client.rs index b2a4e38..8b96f4f 100644 --- a/grasp-audit/src/client.rs +++ b/grasp-audit/src/client.rs | |||
| @@ -10,6 +10,10 @@ pub struct AuditClient { | |||
| 10 | client: Client, | 10 | client: Client, |
| 11 | pub config: AuditConfig, | 11 | pub config: AuditConfig, |
| 12 | keys: Keys, | 12 | keys: Keys, |
| 13 | /// Maintainer keys for testing push authorization scenarios | ||
| 14 | maintainer_keys: Keys, | ||
| 15 | /// Recursive maintainer keys for testing recursive authorization scenarios | ||
| 16 | recursive_maintainer_keys: Keys, | ||
| 13 | } | 17 | } |
| 14 | 18 | ||
| 15 | impl AuditClient { | 19 | impl AuditClient { |
| @@ -17,17 +21,23 @@ impl AuditClient { | |||
| 17 | #[cfg(test)] | 21 | #[cfg(test)] |
| 18 | pub fn new_test(config: AuditConfig) -> Self { | 22 | pub fn new_test(config: AuditConfig) -> Self { |
| 19 | let keys = Keys::generate(); | 23 | let keys = Keys::generate(); |
| 24 | let maintainer_keys = Keys::generate(); | ||
| 25 | let recursive_maintainer_keys = Keys::generate(); | ||
| 20 | let client = Client::new(keys.clone()); | 26 | let client = Client::new(keys.clone()); |
| 21 | Self { | 27 | Self { |
| 22 | client, | 28 | client, |
| 23 | config, | 29 | config, |
| 24 | keys, | 30 | keys, |
| 31 | maintainer_keys, | ||
| 32 | recursive_maintainer_keys, | ||
| 25 | } | 33 | } |
| 26 | } | 34 | } |
| 27 | 35 | ||
| 28 | /// Create a new audit client | 36 | /// Create a new audit client |
| 29 | pub async fn new(relay_url: &str, config: AuditConfig) -> Result<Self> { | 37 | pub async fn new(relay_url: &str, config: AuditConfig) -> Result<Self> { |
| 30 | let keys = Keys::generate(); | 38 | let keys = Keys::generate(); |
| 39 | let maintainer_keys = Keys::generate(); | ||
| 40 | let recursive_maintainer_keys = Keys::generate(); | ||
| 31 | let client = Client::new(keys.clone()); | 41 | let client = Client::new(keys.clone()); |
| 32 | 42 | ||
| 33 | // Add relay and connect | 43 | // Add relay and connect |
| @@ -76,6 +86,8 @@ impl AuditClient { | |||
| 76 | client, | 86 | client, |
| 77 | config, | 87 | config, |
| 78 | keys, | 88 | keys, |
| 89 | maintainer_keys, | ||
| 90 | recursive_maintainer_keys, | ||
| 79 | }) | 91 | }) |
| 80 | } | 92 | } |
| 81 | 93 | ||
| @@ -222,17 +234,45 @@ impl AuditClient { | |||
| 222 | &self.keys | 234 | &self.keys |
| 223 | } | 235 | } |
| 224 | 236 | ||
| 225 | /// Create a NIP-34 repository announcement event | 237 | /// Get the maintainer keys (for push authorization testing) |
| 238 | pub fn maintainer_keys(&self) -> &Keys { | ||
| 239 | &self.maintainer_keys | ||
| 240 | } | ||
| 241 | |||
| 242 | /// Get the maintainer public key as a hex string | ||
| 243 | pub fn maintainer_pubkey_hex(&self) -> String { | ||
| 244 | self.maintainer_keys.public_key().to_hex() | ||
| 245 | } | ||
| 246 | |||
| 247 | /// Get the recursive maintainer keys (for recursive authorization testing) | ||
| 248 | pub fn recursive_maintainer_keys(&self) -> &Keys { | ||
| 249 | &self.recursive_maintainer_keys | ||
| 250 | } | ||
| 251 | |||
| 252 | /// Get the recursive maintainer public key as a hex string | ||
| 253 | pub fn recursive_maintainer_pubkey_hex(&self) -> String { | ||
| 254 | self.recursive_maintainer_keys.public_key().to_hex() | ||
| 255 | } | ||
| 256 | |||
| 257 | /// Create a NIP-34 repository announcement event with full customization | ||
| 226 | /// | 258 | /// |
| 227 | /// This helper creates a properly formatted NIP-34 announcement that will be | 259 | /// This is the core method for creating repository announcements. It allows |
| 228 | /// accepted by GRASP relays (which require events to list the relay in clone/relays tags). | 260 | /// specifying the signing keys and maintainers, making it suitable for all |
| 261 | /// repo creation scenarios including maintainer and recursive maintainer testing. | ||
| 229 | /// | 262 | /// |
| 230 | /// # Arguments | 263 | /// # Arguments |
| 231 | /// * `test_name` - Name of the test (used to create unique repo identifier) | 264 | /// * `test_name` - Name of the test (used to create unique repo identifier) |
| 265 | /// * `signing_keys` - The keys to sign the event with (also used for clone URL) | ||
| 266 | /// * `maintainer_pubkeys` - Hex pubkeys of maintainers who can push to the repository | ||
| 232 | /// | 267 | /// |
| 233 | /// # Returns | 268 | /// # Returns |
| 234 | /// A built and signed Event ready to be sent to the relay | 269 | /// A tuple of (Event, repo_id) - the built event and the repository identifier |
| 235 | pub async fn create_repo_announcement(&self, test_name: &str) -> Result<Event> { | 270 | pub async fn create_repo_announcement_custom( |
| 271 | &self, | ||
| 272 | test_name: &str, | ||
| 273 | signing_keys: &Keys, | ||
| 274 | maintainer_pubkeys: &[String], | ||
| 275 | ) -> Result<(Event, String)> { | ||
| 236 | // Get relay URL from client | 276 | // Get relay URL from client |
| 237 | let relay_url = self | 277 | let relay_url = self |
| 238 | .client | 278 | .client |
| @@ -251,8 +291,8 @@ impl AuditClient { | |||
| 251 | // Create unique repository identifier using UUID for consistency | 291 | // Create unique repository identifier using UUID for consistency |
| 252 | let repo_id = format!("{}-{}", test_name, &uuid::Uuid::new_v4().to_string()[..8]); | 292 | let repo_id = format!("{}-{}", test_name, &uuid::Uuid::new_v4().to_string()[..8]); |
| 253 | 293 | ||
| 254 | // Get npub for clone URL | 294 | // Get npub for clone URL from signing keys |
| 255 | let npub = self | 295 | let npub = signing_keys |
| 256 | .public_key() | 296 | .public_key() |
| 257 | .to_bech32() | 297 | .to_bech32() |
| 258 | .map_err(|e| anyhow!("Failed to convert public key to bech32 npub format: {}", e))?; | 298 | .map_err(|e| anyhow!("Failed to convert public key to bech32 npub format: {}", e))?; |
| @@ -280,9 +320,35 @@ impl AuditClient { | |||
| 280 | TagKind::custom("relays"), | 320 | TagKind::custom("relays"), |
| 281 | vec![relay_url.clone()], | 321 | vec![relay_url.clone()], |
| 282 | )) | 322 | )) |
| 283 | .build(self.keys()) | 323 | .tag(Tag::custom( |
| 324 | TagKind::custom("maintainers"), | ||
| 325 | maintainer_pubkeys.to_vec(), | ||
| 326 | )) | ||
| 327 | .build(signing_keys) | ||
| 284 | .map_err(|e| anyhow!("Failed to build repository announcement event: {}", e))?; | 328 | .map_err(|e| anyhow!("Failed to build repository announcement event: {}", e))?; |
| 285 | 329 | ||
| 330 | Ok((event, repo_id)) | ||
| 331 | } | ||
| 332 | |||
| 333 | /// Create a NIP-34 repository announcement event with the client's maintainer | ||
| 334 | /// | ||
| 335 | /// This helper creates a properly formatted NIP-34 announcement that will be | ||
| 336 | /// accepted by GRASP relays (which require events to list the relay in clone/relays tags). | ||
| 337 | /// The client's maintainer key is automatically added to the maintainers tag. | ||
| 338 | /// | ||
| 339 | /// # Arguments | ||
| 340 | /// * `test_name` - Name of the test (used to create unique repo identifier) | ||
| 341 | /// | ||
| 342 | /// # Returns | ||
| 343 | /// A built and signed Event ready to be sent to the relay | ||
| 344 | pub async fn create_repo_announcement(&self, test_name: &str) -> Result<Event> { | ||
| 345 | let (event, _repo_id) = self | ||
| 346 | .create_repo_announcement_custom( | ||
| 347 | test_name, | ||
| 348 | self.keys(), | ||
| 349 | &[self.maintainer_pubkey_hex()], | ||
| 350 | ) | ||
| 351 | .await?; | ||
| 286 | Ok(event) | 352 | Ok(event) |
| 287 | } | 353 | } |
| 288 | 354 | ||
| @@ -303,60 +369,9 @@ impl AuditClient { | |||
| 303 | test_name: &str, | 369 | test_name: &str, |
| 304 | maintainer_pubkeys: &[String], | 370 | maintainer_pubkeys: &[String], |
| 305 | ) -> Result<Event> { | 371 | ) -> Result<Event> { |
| 306 | // Get relay URL from client | 372 | let (event, _repo_id) = self |
| 307 | let relay_url = self | 373 | .create_repo_announcement_custom(test_name, self.keys(), maintainer_pubkeys) |
| 308 | .client | 374 | .await?; |
| 309 | .relays() | ||
| 310 | .await | ||
| 311 | .keys() | ||
| 312 | .next() | ||
| 313 | .ok_or_else(|| anyhow!("No relay connected"))? | ||
| 314 | .to_string(); | ||
| 315 | |||
| 316 | // Convert WebSocket URL to HTTP URL for clone tag | ||
| 317 | let http_url = relay_url | ||
| 318 | .replace("ws://", "http://") | ||
| 319 | .replace("wss://", "https://"); | ||
| 320 | |||
| 321 | // Create unique repository identifier using UUID for consistency | ||
| 322 | let repo_id = format!("{}-{}", test_name, &uuid::Uuid::new_v4().to_string()[..8]); | ||
| 323 | |||
| 324 | // Get npub for clone URL | ||
| 325 | let npub = self | ||
| 326 | .public_key() | ||
| 327 | .to_bech32() | ||
| 328 | .map_err(|e| anyhow!("Failed to convert public key to bech32 npub format: {}", e))?; | ||
| 329 | |||
| 330 | // Build kind 30617 repository announcement with maintainers tag | ||
| 331 | let event = self | ||
| 332 | .event_builder( | ||
| 333 | Kind::GitRepoAnnouncement, | ||
| 334 | format!("Test repository for {}", test_name), | ||
| 335 | ) | ||
| 336 | .tag(Tag::identifier(&repo_id)) | ||
| 337 | .tag(Tag::custom( | ||
| 338 | TagKind::custom("name"), | ||
| 339 | vec![format!("{} Test Repository", test_name)], | ||
| 340 | )) | ||
| 341 | .tag(Tag::custom( | ||
| 342 | TagKind::custom("description"), | ||
| 343 | vec![format!("Repository for {} testing", test_name)], | ||
| 344 | )) | ||
| 345 | .tag(Tag::custom( | ||
| 346 | TagKind::custom("clone"), | ||
| 347 | vec![format!("{}/{}/{}.git", http_url, npub, repo_id)], | ||
| 348 | )) | ||
| 349 | .tag(Tag::custom( | ||
| 350 | TagKind::custom("relays"), | ||
| 351 | vec![relay_url.clone()], | ||
| 352 | )) | ||
| 353 | .tag(Tag::custom( | ||
| 354 | TagKind::custom("maintainers"), | ||
| 355 | maintainer_pubkeys.to_vec(), | ||
| 356 | )) | ||
| 357 | .build(self.keys()) | ||
| 358 | .map_err(|e| anyhow!("Failed to build repository announcement event: {}", e))?; | ||
| 359 | |||
| 360 | Ok(event) | 375 | Ok(event) |
| 361 | } | 376 | } |
| 362 | 377 | ||
| @@ -465,10 +480,14 @@ mod tests { | |||
| 465 | fn test_event_builder() { | 480 | fn test_event_builder() { |
| 466 | let config = AuditConfig::ci(); | 481 | let config = AuditConfig::ci(); |
| 467 | let keys = Keys::generate(); | 482 | let keys = Keys::generate(); |
| 483 | let maintainer_keys = Keys::generate(); | ||
| 484 | let recursive_maintainer_keys = Keys::generate(); | ||
| 468 | let client = AuditClient { | 485 | let client = AuditClient { |
| 469 | client: Client::new(keys.clone()), | 486 | client: Client::new(keys.clone()), |
| 470 | config: config.clone(), | 487 | config: config.clone(), |
| 471 | keys: keys.clone(), | 488 | keys: keys.clone(), |
| 489 | maintainer_keys, | ||
| 490 | recursive_maintainer_keys, | ||
| 472 | }; | 491 | }; |
| 473 | 492 | ||
| 474 | let _builder = client.event_builder(Kind::TextNote, "test content"); | 493 | let _builder = client.event_builder(Kind::TextNote, "test content"); |
| @@ -481,10 +500,14 @@ mod tests { | |||
| 481 | fn test_audit_tags_automatically_added() { | 500 | fn test_audit_tags_automatically_added() { |
| 482 | let config = AuditConfig::ci(); | 501 | let config = AuditConfig::ci(); |
| 483 | let keys = Keys::generate(); | 502 | let keys = Keys::generate(); |
| 503 | let maintainer_keys = Keys::generate(); | ||
| 504 | let recursive_maintainer_keys = Keys::generate(); | ||
| 484 | let client = AuditClient { | 505 | let client = AuditClient { |
| 485 | client: Client::new(keys.clone()), | 506 | client: Client::new(keys.clone()), |
| 486 | config: config.clone(), | 507 | config: config.clone(), |
| 487 | keys: keys.clone(), | 508 | keys: keys.clone(), |
| 509 | maintainer_keys, | ||
| 510 | recursive_maintainer_keys, | ||
| 488 | }; | 511 | }; |
| 489 | 512 | ||
| 490 | // Create an event with a custom tag | 513 | // Create an event with a custom tag |