upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/grasp-audit/src/audit.rs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2025-11-19 17:01:36 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2025-11-19 17:01:36 +0000
commitbf7f4d5381203d5c27b2811d62c5b1781533aa2b (patch)
tree26903bbf535d83abd7242370d8b6932eb80e3389 /grasp-audit/src/audit.rs
parentfa065ad128882755f2a988d6203b59a2ab5e38ff (diff)
fix some clippy fmt warnings
Diffstat (limited to 'grasp-audit/src/audit.rs')
-rw-r--r--grasp-audit/src/audit.rs84
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::*;
7pub struct AuditConfig { 7pub 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 {
23pub enum AuditMode { 23pub 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)]
171mod tests { 171mod 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 }