tag test events with audit-grasp-test-event

This commit is contained in:
DanConwayDev
2025-11-05 13:32:50 +00:00
parent 64a86de9fc
commit 5f13799485
4 changed files with 176 additions and 10 deletions
+40
View File
@@ -158,6 +158,46 @@ EventBuilder::new(kind, content).tags(tags)
See `docs/archive/2025-11-04-nostr-sdk-upgrade.md` for full migration.
### Audit Event Tagging (grasp-audit)
**All audit events automatically include cleanup tags:**
The grasp-audit system automatically adds three tags to every event for production cleanup and test isolation. These tags are added transparently via [`AuditEventBuilder::build()`](grasp-audit/src/audit.rs:120-129) with 100% coverage through [`AuditClient::event_builder()`](grasp-audit/src/client.rs:107-138).
**Automatic Tags (no manual intervention needed):**
```rust
// These tags are automatically added to EVERY audit event:
["t", "grasp-audit-test-event"] // Identifies all audit test events
["t", "audit-{run_id}"] // Unique ID for this audit run (correlates events)
["t", "audit-cleanup-after-{unix_timestamp}"] // Unix timestamp for cleanup scheduling
```
**Tag Format Details:**
- Uses standard NIP-01 `"t"` (hashtag) tags for maximum compatibility
- Unix timestamps (not ISO 8601) for easier database queries
- All tags added automatically when calling `client.event_builder().build()`
- No manual tag management required
**Verifying Tags in Tests:**
```rust
// Test that verifies automatic tag addition:
// See: grasp-audit/src/client.rs:273-302
#[test]
fn test_audit_tags_automatically_added() {
// Creates event and verifies all three tags are present
}
```
**Testing Implications:**
- All audit events are tagged for easy cleanup
- Use `run_id` tag to correlate events from same audit run
- Tags enable production relay cleanup scripts
- No special handling needed in test code - tags are automatic
## Documentation
**Diátaxis Framework Used:**
+20 -8
View File
@@ -94,23 +94,35 @@ Basic Nostr relay functionality:
## Audit Event Strategy
All audit events include special tags:
All audit events automatically include special tags for isolation and cleanup:
```json
{
"tags": [
["t", "grasp-audit"],
["r", "audit-run-id-ci-a1b2c3d4-e5f6-7890-abcd-ef1234567890"],
["r", "audit-cleanup-2025-11-03T12:00:00Z"]
["t", "grasp-audit-test-event"],
["t", "audit-ci-a1b2c3d4-e5f6-7890-abcd-ef1234567890"],
["t", "audit-cleanup-after-1730822334"]
]
}
```
This allows:
**Tag Format:**
- **Isolation**: Each test run has unique ID
- **Cleanup**: Events marked for cleanup after timestamp
- **No deletion trails**: Direct database cleanup (no NIP-09 deletion events)
- `["t", "grasp-audit-test-event"]` - Identifies all audit-related events
- `["t", "audit-{run_id}"]` - Unique identifier for each audit run
- CI mode: `audit-ci-{uuid}`
- Production mode: `audit-prod-audit-{timestamp}`
- `["t", "audit-cleanup-after-{unix_timestamp}"]` - Cleanup scheduling
- CI mode: Current time + 3600 seconds (1 hour)
- Production mode: Current time + 300 seconds (5 minutes)
**Benefits:**
- **Automatic**: Tags added automatically to all events via `AuditEventBuilder`
- **Isolation**: Each test run has unique ID for event filtering
- **Cleanup**: Events marked for cleanup after timestamp (direct database cleanup)
- **No deletion trails**: No NIP-09 deletion events needed
- **Discovery**: Easy to query all audit events via hashtag
## Modes
+39 -1
View File
@@ -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<Tag> {
use nostr_sdk::prelude::{Alphabet, SingleLetterTag};
+77 -1
View File
@@ -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<String>) -> 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<String> = 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"
);
}
}