diff options
Diffstat (limited to 'grasp-audit/src/bin/grasp-audit.rs')
| -rw-r--r-- | grasp-audit/src/bin/grasp-audit.rs | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/grasp-audit/src/bin/grasp-audit.rs b/grasp-audit/src/bin/grasp-audit.rs index d192f04..e77a698 100644 --- a/grasp-audit/src/bin/grasp-audit.rs +++ b/grasp-audit/src/bin/grasp-audit.rs | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | use clap::{Parser, Subcommand}; | 3 | use clap::{Parser, Subcommand}; |
| 4 | use grasp_audit::*; | 4 | use grasp_audit::*; |
| 5 | use std::path::PathBuf; | 5 | use std::path::PathBuf; |
| 6 | use std::time::Duration; | ||
| 6 | 7 | ||
| 7 | #[derive(Parser)] | 8 | #[derive(Parser)] |
| 8 | #[command(name = "grasp-audit")] | 9 | #[command(name = "grasp-audit")] |
| @@ -14,6 +15,33 @@ struct Cli { | |||
| 14 | 15 | ||
| 15 | #[derive(Subcommand)] | 16 | #[derive(Subcommand)] |
| 16 | enum Commands { | 17 | enum Commands { |
| 18 | /// Run a probe/smoke test against a server | ||
| 19 | Probe { | ||
| 20 | /// Relay URL (e.g., ws://localhost:7000) | ||
| 21 | #[arg(short, long)] | ||
| 22 | relay: String, | ||
| 23 | |||
| 24 | /// Output machine-readable JSON | ||
| 25 | #[arg(long, default_value_t = false)] | ||
| 26 | json: bool, | ||
| 27 | |||
| 28 | /// Per-step timeout in seconds | ||
| 29 | #[arg(long, default_value_t = 30)] | ||
| 30 | timeout: u64, | ||
| 31 | |||
| 32 | /// Re-run every N seconds (watch mode) | ||
| 33 | #[arg(long)] | ||
| 34 | watch: Option<u64>, | ||
| 35 | |||
| 36 | /// Secret key in nsec bech32 format (for whitelisted relays) | ||
| 37 | #[arg(long)] | ||
| 38 | nsec: Option<String>, | ||
| 39 | |||
| 40 | /// Read-only mode: skip write steps, only check existing repos | ||
| 41 | #[arg(long, default_value_t = false)] | ||
| 42 | read_only: bool, | ||
| 43 | }, | ||
| 44 | |||
| 17 | /// Run audit tests against a server | 45 | /// Run audit tests against a server |
| 18 | Audit { | 46 | Audit { |
| 19 | /// Relay URL (e.g., ws://localhost:7000) | 47 | /// Relay URL (e.g., ws://localhost:7000) |
| @@ -50,6 +78,53 @@ async fn main() -> Result<()> { | |||
| 50 | let cli = Cli::parse(); | 78 | let cli = Cli::parse(); |
| 51 | 79 | ||
| 52 | match cli.command { | 80 | match cli.command { |
| 81 | Commands::Probe { | ||
| 82 | relay, | ||
| 83 | json, | ||
| 84 | timeout, | ||
| 85 | watch, | ||
| 86 | nsec, | ||
| 87 | read_only, | ||
| 88 | } => { | ||
| 89 | // Parse nsec if provided | ||
| 90 | let keys = if let Some(nsec_str) = nsec { | ||
| 91 | use nostr_sdk::prelude::SecretKey; | ||
| 92 | let sk = SecretKey::from_bech32(&nsec_str) | ||
| 93 | .map_err(|e| anyhow!("Invalid nsec: {}", e))?; | ||
| 94 | Some(Keys::new(sk)) | ||
| 95 | } else { | ||
| 96 | None | ||
| 97 | }; | ||
| 98 | |||
| 99 | if let Some(interval) = watch { | ||
| 100 | let mut run = 1u64; | ||
| 101 | loop { | ||
| 102 | println!("\n[Run {}]", run); | ||
| 103 | let report = | ||
| 104 | grasp_audit::probe::run_probe(&relay, keys.clone(), read_only, timeout) | ||
| 105 | .await; | ||
| 106 | if json { | ||
| 107 | report.print_json(); | ||
| 108 | } else { | ||
| 109 | report.print_human(); | ||
| 110 | } | ||
| 111 | run += 1; | ||
| 112 | tokio::time::sleep(Duration::from_secs(interval)).await; | ||
| 113 | } | ||
| 114 | } else { | ||
| 115 | let report = | ||
| 116 | grasp_audit::probe::run_probe(&relay, keys, read_only, timeout).await; | ||
| 117 | if json { | ||
| 118 | report.print_json(); | ||
| 119 | } else { | ||
| 120 | report.print_human(); | ||
| 121 | } | ||
| 122 | if !report.all_passed { | ||
| 123 | std::process::exit(1); | ||
| 124 | } | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 53 | Commands::Audit { | 128 | Commands::Audit { |
| 54 | relay, | 129 | relay, |
| 55 | mode, | 130 | mode, |