From 5f137994850773114d8a4f8ba70f34aaf2eb1992 Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Wed, 5 Nov 2025 13:32:50 +0000 Subject: tag test events with audit-grasp-test-event --- grasp-audit/src/audit.rs | 40 +++++++++++++++++++++++- grasp-audit/src/client.rs | 78 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 116 insertions(+), 2 deletions(-) (limited to 'grasp-audit/src') diff --git a/grasp-audit/src/audit.rs b/grasp-audit/src/audit.rs index fad4bf2..105fa00 100644 --- a/grasp-audit/src/audit.rs +++ b/grasp-audit/src/audit.rs @@ -61,7 +61,45 @@ impl AuditConfig { } } - /// Get audit tags for an event + /// Get audit tags that are automatically added to all events + /// + /// These tags are automatically added to all events created via [`AuditEventBuilder`]. + /// They provide isolation, cleanup scheduling, and easy discovery of audit events. + /// + /// # Tag Format + /// + /// All tags use the `"t"` (hashtag) format for maximum relay compatibility: + /// + /// 1. `["t", "grasp-audit-test-event"]` - Identifies all audit-related events + /// 2. `["t", "audit-{run_id}"]` - Unique identifier for this audit run + /// - CI mode: `audit-ci-{uuid}` + /// - Production mode: `audit-prod-audit-{timestamp}` + /// 3. `["t", "audit-cleanup-after-{unix_timestamp}"]` - Cleanup timestamp + /// - CI mode: Current time + 3600 seconds (1 hour) + /// - Production mode: Current time + 300 seconds (5 minutes) + /// + /// # Purpose + /// + /// - **Isolation**: Each test run has a unique ID for event filtering in CI mode + /// - **Cleanup**: Events marked for cleanup after timestamp (enables direct DB cleanup) + /// - **Discovery**: Easy to query all audit events via hashtag + /// - **No deletion trails**: Avoids NIP-09 deletion events by using direct cleanup + /// + /// # Example + /// + /// ```rust + /// use grasp_audit::AuditConfig; + /// + /// let config = AuditConfig::ci(); + /// let tags = config.audit_tags(); + /// + /// // Tags will look like: + /// // [ + /// // ["t", "grasp-audit-test-event"], + /// // ["t", "audit-ci-a1b2c3d4-e5f6-7890-abcd-ef1234567890"], + /// // ["t", "audit-cleanup-after-1730822334"] + /// // ] + /// ``` pub fn audit_tags(&self) -> Vec { use nostr_sdk::prelude::{Alphabet, SingleLetterTag}; diff --git a/grasp-audit/src/client.rs b/grasp-audit/src/client.rs index 7706ee3..cbefeb9 100644 --- a/grasp-audit/src/client.rs +++ b/grasp-audit/src/client.rs @@ -104,7 +104,38 @@ impl AuditClient { Ok(event_id) } - /// Create an event builder with audit tags + /// Create an event builder that automatically includes audit tags + /// + /// All events built through this method will automatically have audit tags appended + /// when you call `.build()`. These tags provide isolation, cleanup scheduling, and + /// easy discovery of audit events. + /// + /// # Automatic Tags Added + /// + /// When you call `.build()` on the returned builder, these tags will be automatically added: + /// - `["t", "grasp-audit-test-event"]` - Identifies all audit events + /// - `["t", "audit-{run_id}"]` - Unique ID for this audit run + /// - `["t", "audit-cleanup-after-{timestamp}"]` - Cleanup scheduling + /// + /// # Example + /// + /// ```no_run + /// # use grasp_audit::*; + /// # async fn example() -> anyhow::Result<()> { + /// let config = AuditConfig::ci(); + /// let client = AuditClient::new("ws://localhost:7000", config).await?; + /// + /// // Create event with automatic audit tags + /// let event = client.event_builder(Kind::TextNote, "test content") + /// .tag(Tag::custom(TagKind::custom("custom"), vec!["value"])) + /// .build(client.keys())?; + /// + /// // Event now has both your custom tag AND the 3 audit tags + /// # Ok(()) + /// # } + /// ``` + /// + /// See [`AuditConfig::audit_tags()`] for details on the tag format. pub fn event_builder(&self, kind: Kind, content: impl Into) -> AuditEventBuilder { AuditEventBuilder::new(kind, content, self.config.clone()) } @@ -237,4 +268,49 @@ mod tests { // Builder should be created successfully // (We can't test the internal config field as it's private, which is correct) } + + #[test] + fn test_audit_tags_automatically_added() { + let config = AuditConfig::ci(); + let keys = Keys::generate(); + let client = AuditClient { + client: Client::new(keys.clone()), + config: config.clone(), + keys: keys.clone(), + }; + + // Create an event with a custom tag + let event = client.event_builder(Kind::TextNote, "test content") + .tag(Tag::custom(TagKind::custom("custom"), vec!["value"])) + .build(&keys) + .unwrap(); + + // Should have custom tag (1) + 3 audit tags = at least 4 tags + assert!(event.tags.len() >= 4, "Expected at least 4 tags, got {}", event.tags.len()); + + // Verify audit tags are present by checking tag content + let tag_contents: Vec = event.tags.iter() + .filter_map(|t| t.content().map(|s| s.to_string())) + .collect(); + + // Check for the three required audit tags + assert!( + tag_contents.contains(&"grasp-audit-test-event".to_string()), + "Missing 'grasp-audit-test-event' tag" + ); + assert!( + tag_contents.iter().any(|t| t.starts_with("audit-ci-")), + "Missing 'audit-ci-*' tag" + ); + assert!( + tag_contents.iter().any(|t| t.starts_with("audit-cleanup-after-")), + "Missing 'audit-cleanup-after-*' tag" + ); + + // Verify the custom tag is also present + assert!( + tag_contents.contains(&"value".to_string()), + "Missing custom tag value" + ); + } } -- cgit v1.2.3