diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2025-11-19 17:01:36 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2025-11-19 17:01:36 +0000 |
| commit | bf7f4d5381203d5c27b2811d62c5b1781533aa2b (patch) | |
| tree | 26903bbf535d83abd7242370d8b6932eb80e3389 /grasp-audit/src/audit.rs | |
| parent | fa065ad128882755f2a988d6203b59a2ab5e38ff (diff) | |
fix some clippy fmt warnings
Diffstat (limited to 'grasp-audit/src/audit.rs')
| -rw-r--r-- | grasp-audit/src/audit.rs | 84 |
1 files changed, 44 insertions, 40 deletions
diff --git a/grasp-audit/src/audit.rs b/grasp-audit/src/audit.rs index 8afe660..5e84409 100644 --- a/grasp-audit/src/audit.rs +++ b/grasp-audit/src/audit.rs | |||
| @@ -7,13 +7,13 @@ use nostr_sdk::prelude::*; | |||
| 7 | pub struct AuditConfig { | 7 | pub struct AuditConfig { |
| 8 | /// Unique ID for this audit run | 8 | /// Unique ID for this audit run |
| 9 | pub run_id: String, | 9 | pub run_id: String, |
| 10 | 10 | ||
| 11 | /// Mode: CI (isolated) or Production (live) | 11 | /// Mode: CI (isolated) or Production (live) |
| 12 | pub mode: AuditMode, | 12 | pub mode: AuditMode, |
| 13 | 13 | ||
| 14 | /// Cleanup timestamp (events can be cleaned after this) | 14 | /// Cleanup timestamp (events can be cleaned after this) |
| 15 | pub cleanup_after: Timestamp, | 15 | pub cleanup_after: Timestamp, |
| 16 | 16 | ||
| 17 | /// Whether to actually create events or just query | 17 | /// Whether to actually create events or just query |
| 18 | pub read_only: bool, | 18 | pub read_only: bool, |
| 19 | } | 19 | } |
| @@ -23,7 +23,7 @@ pub struct AuditConfig { | |||
| 23 | pub enum AuditMode { | 23 | pub enum AuditMode { |
| 24 | /// Isolated CI/CD tests - only see own events | 24 | /// Isolated CI/CD tests - only see own events |
| 25 | CI, | 25 | CI, |
| 26 | 26 | ||
| 27 | /// Production audit - see all events, minimal writes | 27 | /// Production audit - see all events, minimal writes |
| 28 | Production, | 28 | Production, |
| 29 | } | 29 | } |
| @@ -39,7 +39,7 @@ impl AuditConfig { | |||
| 39 | read_only: false, | 39 | read_only: false, |
| 40 | } | 40 | } |
| 41 | } | 41 | } |
| 42 | 42 | ||
| 43 | /// Create config for production audit | 43 | /// Create config for production audit |
| 44 | pub fn production() -> Self { | 44 | pub fn production() -> Self { |
| 45 | let run_id = format!("prod-audit-{}", Timestamp::now().as_u64()); | 45 | let run_id = format!("prod-audit-{}", Timestamp::now().as_u64()); |
| @@ -47,10 +47,10 @@ impl AuditConfig { | |||
| 47 | run_id, | 47 | run_id, |
| 48 | mode: AuditMode::Production, | 48 | mode: AuditMode::Production, |
| 49 | cleanup_after: Timestamp::now() + 300, // 5 minutes from now | 49 | cleanup_after: Timestamp::now() + 300, // 5 minutes from now |
| 50 | read_only: true, // Default to read-only for production | 50 | read_only: true, // Default to read-only for production |
| 51 | } | 51 | } |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | /// Create config with custom run ID | 54 | /// Create config with custom run ID |
| 55 | pub fn with_run_id(run_id: String, mode: AuditMode) -> Self { | 55 | pub fn with_run_id(run_id: String, mode: AuditMode) -> Self { |
| 56 | Self { | 56 | Self { |
| @@ -60,7 +60,7 @@ impl AuditConfig { | |||
| 60 | read_only: mode == AuditMode::Production, | 60 | read_only: mode == AuditMode::Production, |
| 61 | } | 61 | } |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | /// Get audit tags that are automatically added to all events | 64 | /// Get audit tags that are automatically added to all events |
| 65 | /// | 65 | /// |
| 66 | /// These tags are automatically added to all events created via [`AuditEventBuilder`]. | 66 | /// These tags are automatically added to all events created via [`AuditEventBuilder`]. |
| @@ -102,22 +102,22 @@ impl AuditConfig { | |||
| 102 | /// ``` | 102 | /// ``` |
| 103 | pub fn audit_tags(&self) -> Vec<Tag> { | 103 | pub fn audit_tags(&self) -> Vec<Tag> { |
| 104 | use nostr_sdk::prelude::{Alphabet, SingleLetterTag}; | 104 | use nostr_sdk::prelude::{Alphabet, SingleLetterTag}; |
| 105 | 105 | ||
| 106 | // Use "t" tags for categorization (standard NIP-01 hashtag type) | 106 | // Use "t" tags for categorization (standard NIP-01 hashtag type) |
| 107 | let t_tag = SingleLetterTag::lowercase(Alphabet::T); | 107 | let t_tag = SingleLetterTag::lowercase(Alphabet::T); |
| 108 | 108 | ||
| 109 | vec![ | 109 | vec![ |
| 110 | Tag::custom(TagKind::SingleLetter(t_tag), vec!["grasp-audit-test-event"]), | ||
| 110 | Tag::custom( | 111 | Tag::custom( |
| 111 | TagKind::SingleLetter(t_tag), | 112 | TagKind::SingleLetter(t_tag), |
| 112 | vec!["grasp-audit-test-event"] | 113 | vec![format!("audit-{}", self.run_id)], |
| 113 | ), | 114 | ), |
| 114 | Tag::custom( | 115 | Tag::custom( |
| 115 | TagKind::SingleLetter(t_tag), | 116 | TagKind::SingleLetter(t_tag), |
| 116 | vec![format!("audit-{}", self.run_id)] | 117 | vec![format!( |
| 117 | ), | 118 | "audit-cleanup-after-{}", |
| 118 | Tag::custom( | 119 | self.cleanup_after.as_u64() |
| 119 | TagKind::SingleLetter(t_tag), | 120 | )], |
| 120 | vec![format!("audit-cleanup-after-{}", self.cleanup_after.as_u64())] | ||
| 121 | ), | 121 | ), |
| 122 | ] | 122 | ] |
| 123 | } | 123 | } |
| @@ -141,28 +141,28 @@ impl AuditEventBuilder { | |||
| 141 | config, | 141 | config, |
| 142 | } | 142 | } |
| 143 | } | 143 | } |
| 144 | 144 | ||
| 145 | /// Add a tag | 145 | /// Add a tag |
| 146 | pub fn tag(mut self, tag: Tag) -> Self { | 146 | pub fn tag(mut self, tag: Tag) -> Self { |
| 147 | self.tags.push(tag); | 147 | self.tags.push(tag); |
| 148 | self | 148 | self |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | /// Add multiple tags | 151 | /// Add multiple tags |
| 152 | pub fn tags(mut self, tags: Vec<Tag>) -> Self { | 152 | pub fn tags(mut self, tags: Vec<Tag>) -> Self { |
| 153 | self.tags.extend(tags); | 153 | self.tags.extend(tags); |
| 154 | self | 154 | self |
| 155 | } | 155 | } |
| 156 | 156 | ||
| 157 | /// Build the event with audit tags | 157 | /// Build the event with audit tags |
| 158 | pub fn build(self, keys: &Keys) -> anyhow::Result<Event> { | 158 | pub fn build(self, keys: &Keys) -> anyhow::Result<Event> { |
| 159 | let mut all_tags = self.tags; | 159 | let mut all_tags = self.tags; |
| 160 | all_tags.extend(self.config.audit_tags()); | 160 | all_tags.extend(self.config.audit_tags()); |
| 161 | 161 | ||
| 162 | let event = EventBuilder::new(self.kind, self.content) | 162 | let event = EventBuilder::new(self.kind, self.content) |
| 163 | .tags(all_tags) | 163 | .tags(all_tags) |
| 164 | .sign_with_keys(keys)?; | 164 | .sign_with_keys(keys)?; |
| 165 | 165 | ||
| 166 | Ok(event) | 166 | Ok(event) |
| 167 | } | 167 | } |
| 168 | } | 168 | } |
| @@ -170,7 +170,7 @@ impl AuditEventBuilder { | |||
| 170 | #[cfg(test)] | 170 | #[cfg(test)] |
| 171 | mod tests { | 171 | mod tests { |
| 172 | use super::*; | 172 | use super::*; |
| 173 | 173 | ||
| 174 | #[test] | 174 | #[test] |
| 175 | fn test_ci_config() { | 175 | fn test_ci_config() { |
| 176 | let config = AuditConfig::ci(); | 176 | let config = AuditConfig::ci(); |
| @@ -178,7 +178,7 @@ mod tests { | |||
| 178 | assert!(!config.read_only); | 178 | assert!(!config.read_only); |
| 179 | assert!(config.run_id.starts_with("ci-")); | 179 | assert!(config.run_id.starts_with("ci-")); |
| 180 | } | 180 | } |
| 181 | 181 | ||
| 182 | #[test] | 182 | #[test] |
| 183 | fn test_production_config() { | 183 | fn test_production_config() { |
| 184 | let config = AuditConfig::production(); | 184 | let config = AuditConfig::production(); |
| @@ -186,18 +186,18 @@ mod tests { | |||
| 186 | assert!(config.read_only); | 186 | assert!(config.read_only); |
| 187 | assert!(config.run_id.starts_with("prod-audit-")); | 187 | assert!(config.run_id.starts_with("prod-audit-")); |
| 188 | } | 188 | } |
| 189 | 189 | ||
| 190 | #[test] | 190 | #[test] |
| 191 | fn test_audit_tags() { | 191 | fn test_audit_tags() { |
| 192 | use nostr_sdk::prelude::{Alphabet, SingleLetterTag}; | 192 | use nostr_sdk::prelude::{Alphabet, SingleLetterTag}; |
| 193 | 193 | ||
| 194 | let config = AuditConfig::ci(); | 194 | let config = AuditConfig::ci(); |
| 195 | let tags = config.audit_tags(); | 195 | let tags = config.audit_tags(); |
| 196 | 196 | ||
| 197 | assert_eq!(tags.len(), 3); | 197 | assert_eq!(tags.len(), 3); |
| 198 | 198 | ||
| 199 | let t_tag = SingleLetterTag::lowercase(Alphabet::T); | 199 | let t_tag = SingleLetterTag::lowercase(Alphabet::T); |
| 200 | 200 | ||
| 201 | // All tags should be "t" tags (hashtags) | 201 | // All tags should be "t" tags (hashtags) |
| 202 | for tag in &tags { | 202 | for tag in &tags { |
| 203 | if let TagKind::SingleLetter(letter) = tag.kind() { | 203 | if let TagKind::SingleLetter(letter) = tag.kind() { |
| @@ -206,36 +206,40 @@ mod tests { | |||
| 206 | panic!("Expected SingleLetter tag"); | 206 | panic!("Expected SingleLetter tag"); |
| 207 | } | 207 | } |
| 208 | } | 208 | } |
| 209 | 209 | ||
| 210 | // Check for "t" tag with "grasp-audit-test-event" | 210 | // Check for "t" tag with "grasp-audit-test-event" |
| 211 | assert!(tags.iter().any(|t| { | 211 | assert!(tags |
| 212 | t.content() == Some("grasp-audit-test-event") | 212 | .iter() |
| 213 | })); | 213 | .any(|t| { t.content() == Some("grasp-audit-test-event") })); |
| 214 | 214 | ||
| 215 | // Check for "t" tag with "audit-{run_id}" | 215 | // Check for "t" tag with "audit-{run_id}" |
| 216 | assert!(tags.iter().any(|t| { | 216 | assert!(tags.iter().any(|t| { |
| 217 | t.content().map(|c| c.starts_with("audit-ci-")).unwrap_or(false) | 217 | t.content() |
| 218 | .map(|c| c.starts_with("audit-ci-")) | ||
| 219 | .unwrap_or(false) | ||
| 218 | })); | 220 | })); |
| 219 | 221 | ||
| 220 | // Check for "t" tag with "audit-cleanup-after-{timestamp}" | 222 | // Check for "t" tag with "audit-cleanup-after-{timestamp}" |
| 221 | assert!(tags.iter().any(|t| { | 223 | assert!(tags.iter().any(|t| { |
| 222 | t.content().map(|c| c.starts_with("audit-cleanup-after-")).unwrap_or(false) | 224 | t.content() |
| 225 | .map(|c| c.starts_with("audit-cleanup-after-")) | ||
| 226 | .unwrap_or(false) | ||
| 223 | })); | 227 | })); |
| 224 | } | 228 | } |
| 225 | 229 | ||
| 226 | #[test] | 230 | #[test] |
| 227 | fn test_audit_event_builder() { | 231 | fn test_audit_event_builder() { |
| 228 | let config = AuditConfig::ci(); | 232 | let config = AuditConfig::ci(); |
| 229 | let keys = Keys::generate(); | 233 | let keys = Keys::generate(); |
| 230 | 234 | ||
| 231 | let event = AuditEventBuilder::new(Kind::TextNote, "test", config.clone()) | 235 | let event = AuditEventBuilder::new(Kind::TextNote, "test", config.clone()) |
| 232 | .tag(Tag::custom(TagKind::Custom("test".into()), vec!["value"])) | 236 | .tag(Tag::custom(TagKind::Custom("test".into()), vec!["value"])) |
| 233 | .build(&keys) | 237 | .build(&keys) |
| 234 | .unwrap(); | 238 | .unwrap(); |
| 235 | 239 | ||
| 236 | // Should have our custom tag + 3 audit tags | 240 | // Should have our custom tag + 3 audit tags |
| 237 | assert!(event.tags.len() >= 4); | 241 | assert!(event.tags.len() >= 4); |
| 238 | 242 | ||
| 239 | // Verify event is valid | 243 | // Verify event is valid |
| 240 | assert!(event.verify().is_ok()); | 244 | assert!(event.verify().is_ok()); |
| 241 | } | 245 | } |