diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2025-12-03 11:38:07 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2025-12-03 11:38:07 +0000 |
| commit | e30dfd5e5abb96cdc89b80f1d085466e55c347e0 (patch) | |
| tree | c12c1d54d30f0541c9689acbcb3b64d54cc8b996 /docs/learnings/grasp-audit.md | |
| parent | 2eaff5b79fed364d5eba5eb38e4b7bf76326884d (diff) | |
remove depricated audit mode label ci / production ~> isolated / shared
Diffstat (limited to 'docs/learnings/grasp-audit.md')
| -rw-r--r-- | docs/learnings/grasp-audit.md | 46 |
1 files changed, 32 insertions, 14 deletions
diff --git a/docs/learnings/grasp-audit.md b/docs/learnings/grasp-audit.md index 531ebda..14e5a2b 100644 --- a/docs/learnings/grasp-audit.md +++ b/docs/learnings/grasp-audit.md | |||
| @@ -18,6 +18,7 @@ | |||
| 18 | **Decision:** Build `grasp-audit` as a separate crate from `ngit-grasp` | 18 | **Decision:** Build `grasp-audit` as a separate crate from `ngit-grasp` |
| 19 | 19 | ||
| 20 | **Why:** | 20 | **Why:** |
| 21 | |||
| 21 | 1. **Parallel Development**: Can build tests before implementation | 22 | 1. **Parallel Development**: Can build tests before implementation |
| 22 | 2. **Isolated Testing**: Tests run in isolation (CI/CD safe) | 23 | 2. **Isolated Testing**: Tests run in isolation (CI/CD safe) |
| 23 | 3. **Production Auditing**: Can audit live production services | 24 | 3. **Production Auditing**: Can audit live production services |
| @@ -43,6 +44,7 @@ | |||
| 43 | ``` | 44 | ``` |
| 44 | 45 | ||
| 45 | **Benefits:** | 46 | **Benefits:** |
| 47 | |||
| 46 | - ✅ **Queryable**: Can find all audit events via tag filter | 48 | - ✅ **Queryable**: Can find all audit events via tag filter |
| 47 | - ✅ **Isolated**: Each test run has unique run ID | 49 | - ✅ **Isolated**: Each test run has unique run ID |
| 48 | - ✅ **Self-cleaning**: Cleanup timestamp indicates when to delete | 50 | - ✅ **Self-cleaning**: Cleanup timestamp indicates when to delete |
| @@ -56,10 +58,12 @@ | |||
| 56 | ### Standard "t" Tags vs Custom Tags | 58 | ### Standard "t" Tags vs Custom Tags |
| 57 | 59 | ||
| 58 | **Evolution:** | 60 | **Evolution:** |
| 61 | |||
| 59 | 1. **Original**: Custom single-letter tags (`g`, `r`, `c`) | 62 | 1. **Original**: Custom single-letter tags (`g`, `r`, `c`) |
| 60 | 2. **Current**: Standard NIP-01 "t" tags with prefixed values | 63 | 2. **Current**: Standard NIP-01 "t" tags with prefixed values |
| 61 | 64 | ||
| 62 | **Why we changed:** | 65 | **Why we changed:** |
| 66 | |||
| 63 | - ❌ Custom tags could conflict with other systems | 67 | - ❌ Custom tags could conflict with other systems |
| 64 | - ✅ "t" tag is standard for categorization/topics | 68 | - ✅ "t" tag is standard for categorization/topics |
| 65 | - ✅ Multiple "t" tags are expected and supported | 69 | - ✅ Multiple "t" tags are expected and supported |
| @@ -78,17 +82,18 @@ | |||
| 78 | use grasp_audit::audit::AuditConfig; | 82 | use grasp_audit::audit::AuditConfig; |
| 79 | 83 | ||
| 80 | // CI mode - isolated test runs | 84 | // CI mode - isolated test runs |
| 81 | let config = AuditConfig::ci(); | 85 | let config = AuditConfig::isolated(); |
| 82 | // Generates UUID run ID: "ci-{uuid}" | 86 | // Generates UUID run ID: "ci-{uuid}" |
| 83 | // Cleanup after 1 hour | 87 | // Cleanup after 1 hour |
| 84 | 88 | ||
| 85 | // Production mode - persistent run ID | 89 | // Production mode - persistent run ID |
| 86 | let config = AuditConfig::production("prod-server-1"); | 90 | let config = AuditConfig::shared(); |
| 87 | // Uses provided run ID | 91 | // Uses provided run ID |
| 88 | // Cleanup after 24 hours | 92 | // Cleanup after 24 hours |
| 89 | ``` | 93 | ``` |
| 90 | 94 | ||
| 91 | **When to use:** | 95 | **When to use:** |
| 96 | |||
| 92 | - **CI mode**: Automated testing, parallel runs, temporary | 97 | - **CI mode**: Automated testing, parallel runs, temporary |
| 93 | - **Production mode**: Manual audits, monitoring, persistent | 98 | - **Production mode**: Manual audits, monitoring, persistent |
| 94 | 99 | ||
| @@ -100,7 +105,7 @@ let config = AuditConfig::production("prod-server-1"); | |||
| 100 | use grasp_audit::audit::{AuditConfig, AuditEventBuilder}; | 105 | use grasp_audit::audit::{AuditConfig, AuditEventBuilder}; |
| 101 | use nostr_sdk::prelude::*; | 106 | use nostr_sdk::prelude::*; |
| 102 | 107 | ||
| 103 | let config = AuditConfig::ci(); | 108 | let config = AuditConfig::isolated(); |
| 104 | let keys = Keys::generate(); | 109 | let keys = Keys::generate(); |
| 105 | 110 | ||
| 106 | // Create audit event | 111 | // Create audit event |
| @@ -121,7 +126,7 @@ let event = AuditEventBuilder::new(&config, Kind::TextNote, "test content") | |||
| 121 | use grasp_audit::client::AuditClient; | 126 | use grasp_audit::client::AuditClient; |
| 122 | use grasp_audit::audit::AuditConfig; | 127 | use grasp_audit::audit::AuditConfig; |
| 123 | 128 | ||
| 124 | let config = AuditConfig::ci(); | 129 | let config = AuditConfig::isolated(); |
| 125 | let client = AuditClient::new(config, keys); | 130 | let client = AuditClient::new(config, keys); |
| 126 | 131 | ||
| 127 | // Connect to relay | 132 | // Connect to relay |
| @@ -144,14 +149,15 @@ let events = client.query().await?; | |||
| 144 | 149 | ||
| 145 | ```rust | 150 | ```rust |
| 146 | // CI mode generates unique UUID per run | 151 | // CI mode generates unique UUID per run |
| 147 | let config1 = AuditConfig::ci(); | 152 | let config1 = AuditConfig::isolated(); |
| 148 | let config2 = AuditConfig::ci(); | 153 | let config2 = AuditConfig::isolated(); |
| 149 | 154 | ||
| 150 | // config1.run_id != config2.run_id | 155 | // config1.run_id != config2.run_id |
| 151 | // Tests won't interfere with each other | 156 | // Tests won't interfere with each other |
| 152 | ``` | 157 | ``` |
| 153 | 158 | ||
| 154 | **Benefits:** | 159 | **Benefits:** |
| 160 | |||
| 155 | - ✅ Parallel CI/CD runs don't conflict | 161 | - ✅ Parallel CI/CD runs don't conflict |
| 156 | - ✅ Can run multiple test suites simultaneously | 162 | - ✅ Can run multiple test suites simultaneously |
| 157 | - ✅ Easy to identify which run created which events | 163 | - ✅ Easy to identify which run created which events |
| @@ -194,18 +200,20 @@ grasp-audit/src/specs/ | |||
| 194 | ### Unit vs Integration Tests | 200 | ### Unit vs Integration Tests |
| 195 | 201 | ||
| 196 | **Unit Tests** (no relay required): | 202 | **Unit Tests** (no relay required): |
| 203 | |||
| 197 | ```rust | 204 | ```rust |
| 198 | #[cfg(test)] | 205 | #[cfg(test)] |
| 199 | mod tests { | 206 | mod tests { |
| 200 | #[test] | 207 | #[test] |
| 201 | fn test_audit_config() { | 208 | fn test_audit_config() { |
| 202 | let config = AuditConfig::ci(); | 209 | let config = AuditConfig::isolated(); |
| 203 | assert!(config.run_id.starts_with("ci-")); | 210 | assert!(config.run_id.starts_with("ci-")); |
| 204 | } | 211 | } |
| 205 | } | 212 | } |
| 206 | ``` | 213 | ``` |
| 207 | 214 | ||
| 208 | **Integration Tests** (relay required): | 215 | **Integration Tests** (relay required): |
| 216 | |||
| 209 | ```rust | 217 | ```rust |
| 210 | #[cfg(test)] | 218 | #[cfg(test)] |
| 211 | mod tests { | 219 | mod tests { |
| @@ -218,6 +226,7 @@ mod tests { | |||
| 218 | ``` | 226 | ``` |
| 219 | 227 | ||
| 220 | **Running tests:** | 228 | **Running tests:** |
| 229 | |||
| 221 | ```bash | 230 | ```bash |
| 222 | # Unit tests (fast, no dependencies) | 231 | # Unit tests (fast, no dependencies) |
| 223 | cargo test --lib | 232 | cargo test --lib |
| @@ -248,7 +257,7 @@ for result in &results { | |||
| 248 | // Summary | 257 | // Summary |
| 249 | let passed = results.iter().filter(|r| r.is_pass()).count(); | 258 | let passed = results.iter().filter(|r| r.is_pass()).count(); |
| 250 | let total = results.len(); | 259 | let total = results.len(); |
| 251 | println!("Results: {}/{} passed ({:.1}%)", | 260 | println!("Results: {}/{} passed ({:.1}%)", |
| 252 | passed, total, (passed as f64 / total as f64) * 100.0); | 261 | passed, total, (passed as f64 / total as f64) * 100.0); |
| 253 | ``` | 262 | ``` |
| 254 | 263 | ||
| @@ -300,6 +309,7 @@ grasp-audit audit --relay ws://localhost:7000 | |||
| 300 | **Impact:** Events created with old tags won't be found by new queries. | 309 | **Impact:** Events created with old tags won't be found by new queries. |
| 301 | 310 | ||
| 302 | **Mitigation:** | 311 | **Mitigation:** |
| 312 | |||
| 303 | - ✅ Accept breaking changes in alpha stage | 313 | - ✅ Accept breaking changes in alpha stage |
| 304 | - ✅ Document migration clearly | 314 | - ✅ Document migration clearly |
| 305 | - ✅ Old events auto-expire via cleanup | 315 | - ✅ Old events auto-expire via cleanup |
| @@ -316,6 +326,7 @@ grasp-audit audit --relay ws://localhost:7000 | |||
| 316 | **Solution:** Built-in cleanup strategy from day one. | 326 | **Solution:** Built-in cleanup strategy from day one. |
| 317 | 327 | ||
| 318 | **Implementation:** | 328 | **Implementation:** |
| 329 | |||
| 319 | - Every event has cleanup timestamp | 330 | - Every event has cleanup timestamp |
| 320 | - Relay can cleanup expired events | 331 | - Relay can cleanup expired events |
| 321 | - No deletion event pollution (direct DB cleanup) | 332 | - No deletion event pollution (direct DB cleanup) |
| @@ -329,9 +340,10 @@ grasp-audit audit --relay ws://localhost:7000 | |||
| 329 | **Benefit:** CI/CD can run multiple test suites simultaneously. | 340 | **Benefit:** CI/CD can run multiple test suites simultaneously. |
| 330 | 341 | ||
| 331 | **Pattern:** | 342 | **Pattern:** |
| 343 | |||
| 332 | ```rust | 344 | ```rust |
| 333 | // Each CI run gets unique ID | 345 | // Each CI run gets unique ID |
| 334 | let config = AuditConfig::ci(); | 346 | let config = AuditConfig::isolated(); |
| 335 | // run_id = "ci-{uuid}" | 347 | // run_id = "ci-{uuid}" |
| 336 | 348 | ||
| 337 | // Tests isolated by run ID | 349 | // Tests isolated by run ID |
| @@ -346,6 +358,7 @@ let events = client.query().await?; | |||
| 346 | **Lesson:** Using standard NIP-01 "t" tags instead of custom tags. | 358 | **Lesson:** Using standard NIP-01 "t" tags instead of custom tags. |
| 347 | 359 | ||
| 348 | **Benefits:** | 360 | **Benefits:** |
| 361 | |||
| 349 | - ✅ No conflicts with other systems | 362 | - ✅ No conflicts with other systems |
| 350 | - ✅ Standard relay filtering works | 363 | - ✅ Standard relay filtering works |
| 351 | - ✅ Better interoperability | 364 | - ✅ Better interoperability |
| @@ -382,11 +395,13 @@ let events = client.query().await?; | |||
| 382 | **Symptoms:** Tests timeout or fail to connect | 395 | **Symptoms:** Tests timeout or fail to connect |
| 383 | 396 | ||
| 384 | **Causes:** | 397 | **Causes:** |
| 398 | |||
| 385 | 1. No relay running | 399 | 1. No relay running |
| 386 | 2. Wrong relay URL | 400 | 2. Wrong relay URL |
| 387 | 3. Firewall blocking connection | 401 | 3. Firewall blocking connection |
| 388 | 402 | ||
| 389 | **Solution:** | 403 | **Solution:** |
| 404 | |||
| 390 | ```bash | 405 | ```bash |
| 391 | # Start relay | 406 | # Start relay |
| 392 | docker run --rm -p 7000:7000 scsibug/nostr-rs-relay | 407 | docker run --rm -p 7000:7000 scsibug/nostr-rs-relay |
| @@ -405,14 +420,16 @@ cargo test -- --ignored | |||
| 405 | **Symptoms:** Query returns empty even though events were sent | 420 | **Symptoms:** Query returns empty even though events were sent |
| 406 | 421 | ||
| 407 | **Causes:** | 422 | **Causes:** |
| 423 | |||
| 408 | 1. Wrong run ID (querying different run) | 424 | 1. Wrong run ID (querying different run) |
| 409 | 2. Connection timing (query before event propagated) | 425 | 2. Connection timing (query before event propagated) |
| 410 | 3. Tag mismatch (uppercase vs lowercase) | 426 | 3. Tag mismatch (uppercase vs lowercase) |
| 411 | 427 | ||
| 412 | **Solution:** | 428 | **Solution:** |
| 429 | |||
| 413 | ```rust | 430 | ```rust |
| 414 | // Use same config for send and query | 431 | // Use same config for send and query |
| 415 | let config = AuditConfig::ci(); | 432 | let config = AuditConfig::isolated(); |
| 416 | 433 | ||
| 417 | // Wait for event to propagate | 434 | // Wait for event to propagate |
| 418 | tokio::time::sleep(Duration::from_millis(500)).await; | 435 | tokio::time::sleep(Duration::from_millis(500)).await; |
| @@ -430,6 +447,7 @@ let t_tag = SingleLetterTag::lowercase(Alphabet::T); // Lowercase! | |||
| 430 | **Cause:** Not in Nix dev environment | 447 | **Cause:** Not in Nix dev environment |
| 431 | 448 | ||
| 432 | **Solution:** | 449 | **Solution:** |
| 450 | |||
| 433 | ```bash | 451 | ```bash |
| 434 | # Enter Nix environment first | 452 | # Enter Nix environment first |
| 435 | cd grasp-audit | 453 | cd grasp-audit |
| @@ -447,10 +465,10 @@ cargo build | |||
| 447 | 465 | ||
| 448 | ```rust | 466 | ```rust |
| 449 | // CI mode | 467 | // CI mode |
| 450 | let config = AuditConfig::ci(); | 468 | let config = AuditConfig::isolated(); |
| 451 | 469 | ||
| 452 | // Production mode | 470 | // Production mode |
| 453 | let config = AuditConfig::production("run-id"); | 471 | let config = AuditConfig::shared(); |
| 454 | ``` | 472 | ``` |
| 455 | 473 | ||
| 456 | ### Event Creation | 474 | ### Event Creation |
| @@ -494,5 +512,5 @@ cargo run -- audit --relay ws://localhost:7000 | |||
| 494 | 512 | ||
| 495 | --- | 513 | --- |
| 496 | 514 | ||
| 497 | *Last updated: November 4, 2025* | 515 | _Last updated: November 4, 2025_ |
| 498 | *Status: Living document - update as grasp-audit evolves* | 516 | _Status: Living document - update as grasp-audit evolves_ |