mirror of
https://relay.ngit.dev/npub15qydau2hjma6ngxkl2cyar74wzyjshvl65za5k5rl69264ar2exs5cyejr/ngit-grasp.git
synced 2026-10-05 15:08:24 +00:00
grasp-audit run all tests in audit mode
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
use clap::{Parser, Subcommand};
|
||||
use grasp_audit::*;
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Parser)]
|
||||
#[command(name = "grasp-audit")]
|
||||
@@ -23,9 +24,13 @@ enum Commands {
|
||||
#[arg(short, long, default_value = "ci")]
|
||||
mode: String,
|
||||
|
||||
/// Spec to test (nip01-smoke, all)
|
||||
#[arg(short, long, default_value = "nip01-smoke")]
|
||||
/// Spec to test (nip01-smoke, nip11, event-acceptance, cors, git-clone, push-auth, repo-creation, all)
|
||||
#[arg(short, long, default_value = "all")]
|
||||
spec: String,
|
||||
|
||||
/// Git data directory (required for cors, git-clone, push-auth, repo-creation specs)
|
||||
#[arg(short, long)]
|
||||
git_data_dir: Option<PathBuf>,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -42,19 +47,29 @@ async fn main() -> Result<()> {
|
||||
let cli = Cli::parse();
|
||||
|
||||
match cli.command {
|
||||
Commands::Audit { relay, mode, spec } => {
|
||||
Commands::Audit { relay, mode, spec, git_data_dir } => {
|
||||
let config = match mode.as_str() {
|
||||
"ci" => AuditConfig::ci(),
|
||||
"production" => AuditConfig::production(),
|
||||
_ => return Err(anyhow!("Invalid mode: {}. Use 'ci' or 'production'", mode)),
|
||||
};
|
||||
|
||||
// Derive relay_domain from relay URL (e.g., "ws://localhost:8081" -> "localhost:8081")
|
||||
let relay_domain = relay
|
||||
.replace("ws://", "")
|
||||
.replace("wss://", "")
|
||||
.trim_end_matches('/')
|
||||
.to_string();
|
||||
|
||||
println!("🔍 GRASP Audit Tool");
|
||||
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
||||
println!("Relay: {}", relay);
|
||||
println!("Mode: {}", mode);
|
||||
println!("Spec: {}", spec);
|
||||
println!("Run ID: {}", config.run_id);
|
||||
if let Some(ref dir) = git_data_dir {
|
||||
println!("Git Dir: {}", dir.display());
|
||||
}
|
||||
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
|
||||
println!();
|
||||
|
||||
@@ -69,18 +84,98 @@ async fn main() -> Result<()> {
|
||||
|
||||
println!("✓ Connected\n");
|
||||
|
||||
// Helper to check if git_data_dir is required
|
||||
let require_git_data_dir = |spec_name: &str| -> Result<PathBuf> {
|
||||
git_data_dir.clone().ok_or_else(|| {
|
||||
anyhow!(
|
||||
"The '{}' spec requires --git-data-dir to be specified",
|
||||
spec_name
|
||||
)
|
||||
})
|
||||
};
|
||||
|
||||
let results = match spec.as_str() {
|
||||
"nip01-smoke" => {
|
||||
println!("Running NIP-01 smoke tests...\n");
|
||||
specs::Nip01SmokeTests::run_all(&client).await
|
||||
}
|
||||
"nip11" => {
|
||||
println!("Running NIP-11 document tests...\n");
|
||||
specs::Nip11DocumentTests::run_all(&client).await
|
||||
}
|
||||
"event-acceptance" => {
|
||||
println!("Running event acceptance policy tests...\n");
|
||||
specs::EventAcceptancePolicyTests::run_all(&client).await
|
||||
}
|
||||
"cors" => {
|
||||
println!("Running CORS tests...\n");
|
||||
specs::CorsTests::run_all(&client, &relay_domain).await
|
||||
}
|
||||
"git-clone" => {
|
||||
let dir = require_git_data_dir("git-clone")?;
|
||||
println!("Running Git clone tests...\n");
|
||||
specs::GitCloneTests::run_all(&client, &dir, &relay_domain).await
|
||||
}
|
||||
"push-auth" => {
|
||||
let dir = require_git_data_dir("push-auth")?;
|
||||
println!("Running push authorization tests...\n");
|
||||
specs::PushAuthorizationTests::run_all(&client, &dir, &relay_domain).await
|
||||
}
|
||||
"repo-creation" => {
|
||||
let dir = require_git_data_dir("repo-creation")?;
|
||||
println!("Running repository creation tests...\n");
|
||||
specs::RepositoryCreationTests::run_all(&client, &dir).await
|
||||
}
|
||||
"all" => {
|
||||
println!("Running all tests...\n");
|
||||
specs::Nip01SmokeTests::run_all(&client).await
|
||||
let mut all_results = AuditResult::new("All GRASP-01 Tests");
|
||||
|
||||
// NIP-01 smoke tests
|
||||
println!(" → NIP-01 smoke tests...");
|
||||
let nip01_results = specs::Nip01SmokeTests::run_all(&client).await;
|
||||
all_results.merge(nip01_results);
|
||||
|
||||
// NIP-11 document tests
|
||||
println!(" → NIP-11 document tests...");
|
||||
let nip11_results = specs::Nip11DocumentTests::run_all(&client).await;
|
||||
all_results.merge(nip11_results);
|
||||
|
||||
// Event acceptance policy tests
|
||||
println!(" → Event acceptance policy tests...");
|
||||
let event_results = specs::EventAcceptancePolicyTests::run_all(&client).await;
|
||||
all_results.merge(event_results);
|
||||
|
||||
// CORS tests
|
||||
println!(" → CORS tests...");
|
||||
let cors_results = specs::CorsTests::run_all(&client, &relay_domain).await;
|
||||
all_results.merge(cors_results);
|
||||
|
||||
// Tests that require git_data_dir
|
||||
if let Some(ref dir) = git_data_dir {
|
||||
// Git clone tests
|
||||
println!(" → Git clone tests...");
|
||||
let clone_results = specs::GitCloneTests::run_all(&client, dir, &relay_domain).await;
|
||||
all_results.merge(clone_results);
|
||||
|
||||
// Push authorization tests
|
||||
println!(" → Push authorization tests...");
|
||||
let push_results = specs::PushAuthorizationTests::run_all(&client, dir, &relay_domain).await;
|
||||
all_results.merge(push_results);
|
||||
|
||||
// Repository creation tests
|
||||
println!(" → Repository creation tests...");
|
||||
let repo_results = specs::RepositoryCreationTests::run_all(&client, dir).await;
|
||||
all_results.merge(repo_results);
|
||||
} else {
|
||||
println!(" ⚠ Skipping git-clone, push-auth, repo-creation tests (no --git-data-dir)");
|
||||
}
|
||||
|
||||
println!();
|
||||
all_results
|
||||
}
|
||||
_ => {
|
||||
return Err(anyhow!(
|
||||
"Unknown spec: {}. Use 'nip01-smoke' or 'all'",
|
||||
"Unknown spec: {}. Use 'nip01-smoke', 'nip11', 'event-acceptance', 'cors', 'git-clone', 'push-auth', 'repo-creation', or 'all'",
|
||||
spec
|
||||
))
|
||||
}
|
||||
|
||||
@@ -24,6 +24,20 @@ use std::process::Command;
|
||||
pub struct GitCloneTests;
|
||||
|
||||
impl GitCloneTests {
|
||||
/// Run all Git clone tests
|
||||
pub async fn run_all(
|
||||
client: &AuditClient,
|
||||
git_data_dir: &Path,
|
||||
relay_domain: &str,
|
||||
) -> crate::AuditResult {
|
||||
let mut results = crate::AuditResult::new("GRASP-01 Git Clone Tests");
|
||||
|
||||
results.add(Self::test_basic_git_clone(client, git_data_dir, relay_domain).await);
|
||||
results.add(Self::test_clone_url_format(client, git_data_dir, relay_domain).await);
|
||||
|
||||
results
|
||||
}
|
||||
|
||||
/// Test that a repository can be cloned via Git HTTP backend
|
||||
///
|
||||
/// This test:
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
//! GRASP-01 specification tests
|
||||
//!
|
||||
//! This module contains all test suites for GRASP-01 compliance testing.
|
||||
//!
|
||||
//! ## Test Suites
|
||||
//!
|
||||
//! - [`Nip01SmokeTests`] - Basic NIP-01 relay functionality (WebSocket-only)
|
||||
//! - [`Nip11DocumentTests`] - NIP-11 relay information document (WebSocket-only)
|
||||
//! - [`EventAcceptancePolicyTests`] - Event acceptance rules (WebSocket-only)
|
||||
//! - [`CorsTests`] - CORS headers on Git HTTP endpoints (requires git-data-dir)
|
||||
//! - [`GitCloneTests`] - Git clone operations (requires git-data-dir)
|
||||
//! - [`PushAuthorizationTests`] - Push authorization (requires git-data-dir)
|
||||
//! - [`RepositoryCreationTests`] - Repository creation (requires git-data-dir)
|
||||
|
||||
pub mod cors;
|
||||
pub mod event_acceptance_policy;
|
||||
@@ -14,4 +26,4 @@ pub use git_clone::GitCloneTests;
|
||||
pub use nip01_smoke::Nip01SmokeTests;
|
||||
pub use nip11_document::Nip11DocumentTests;
|
||||
pub use push_authorization::PushAuthorizationTests;
|
||||
pub use repository_creation::RepositoryCreationTests;
|
||||
pub use repository_creation::{is_bare_repository, RepositoryCreationTests};
|
||||
|
||||
@@ -30,6 +30,22 @@ use std::path::Path;
|
||||
pub struct PushAuthorizationTests;
|
||||
|
||||
impl PushAuthorizationTests {
|
||||
/// Run all push authorization tests
|
||||
pub async fn run_all(
|
||||
client: &AuditClient,
|
||||
git_data_dir: &Path,
|
||||
relay_domain: &str,
|
||||
) -> crate::AuditResult {
|
||||
let mut results = crate::AuditResult::new("GRASP-01 Push Authorization Tests");
|
||||
|
||||
results.add(Self::test_push_authorized_by_owner_state(client, git_data_dir, relay_domain).await);
|
||||
results.add(Self::test_push_rejected_without_state_event(client, git_data_dir, relay_domain).await);
|
||||
results.add(Self::test_push_rejected_wrong_commit(client, git_data_dir, relay_domain).await);
|
||||
results.add(Self::test_push_authorized_by_maintainer_state_only(client, git_data_dir, relay_domain).await);
|
||||
|
||||
results
|
||||
}
|
||||
|
||||
/// Test that push is authorized when state event matches the commit
|
||||
///
|
||||
/// GRASP-01: "MUST accept pushes via this service that match the latest
|
||||
|
||||
@@ -24,6 +24,20 @@ use std::path::Path;
|
||||
pub struct RepositoryCreationTests;
|
||||
|
||||
impl RepositoryCreationTests {
|
||||
/// Run all repository creation tests
|
||||
pub async fn run_all(
|
||||
client: &AuditClient,
|
||||
git_data_dir: &Path,
|
||||
) -> crate::AuditResult {
|
||||
let mut results = crate::AuditResult::new("GRASP-01 Repository Creation Tests");
|
||||
|
||||
results.add(Self::test_bare_repo_created_on_announcement(client, git_data_dir).await);
|
||||
results.add(Self::test_repo_creation_idempotent(client, git_data_dir).await);
|
||||
results.add(Self::test_bare_repo_structure(client, git_data_dir).await);
|
||||
|
||||
results
|
||||
}
|
||||
|
||||
/// Test that a bare repository is created when a valid announcement is accepted
|
||||
///
|
||||
/// This test:
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
//! Test specifications
|
||||
//!
|
||||
//! This module contains all GRASP specification test suites.
|
||||
|
||||
pub mod grasp01;
|
||||
|
||||
// Re-export all test structs from grasp01 module
|
||||
pub use grasp01::{EventAcceptancePolicyTests, Nip01SmokeTests, Nip11DocumentTests};
|
||||
pub use grasp01::{
|
||||
CorsTests, EventAcceptancePolicyTests, GitCloneTests, Nip01SmokeTests, Nip11DocumentTests,
|
||||
PushAuthorizationTests, RepositoryCreationTests,
|
||||
};
|
||||
|
||||
@@ -35,19 +35,27 @@ OPTIONS:
|
||||
--mode <audit|test> Execution mode (default: audit)
|
||||
audit: Run grasp-audit CLI tool
|
||||
test: Run cargo test suite
|
||||
--spec <spec> Specification to test (default: nip01-smoke)
|
||||
--spec <spec> Specification to test (default: all)
|
||||
Available specs: nip01-smoke, nip11, event-acceptance,
|
||||
cors, git-clone, push-auth, repo-creation, all
|
||||
Only used in audit mode
|
||||
--help Show this help message
|
||||
|
||||
EXAMPLES:
|
||||
# Run audit with default settings (current behavior)
|
||||
# Run audit with all tests (default)
|
||||
./test-ngit-relay.sh
|
||||
|
||||
# Run cargo tests instead
|
||||
./test-ngit-relay.sh --mode test
|
||||
|
||||
# Run audit with specific spec
|
||||
./test-ngit-relay.sh --mode audit --spec grasp01
|
||||
./test-ngit-relay.sh --mode audit --spec nip01-smoke
|
||||
./test-ngit-relay.sh --mode audit --spec nip11
|
||||
./test-ngit-relay.sh --mode audit --spec event-acceptance
|
||||
./test-ngit-relay.sh --mode audit --spec cors
|
||||
./test-ngit-relay.sh --mode audit --spec git-clone
|
||||
./test-ngit-relay.sh --mode audit --spec push-auth
|
||||
./test-ngit-relay.sh --mode audit --spec repo-creation
|
||||
|
||||
EOF
|
||||
exit 0
|
||||
@@ -56,9 +64,9 @@ EOF
|
||||
# -----------------------------------------------------------------------------
|
||||
# Argument Parsing
|
||||
# -----------------------------------------------------------------------------
|
||||
# Default values maintain backward compatibility
|
||||
# Default: run audit mode with all specs
|
||||
MODE="audit"
|
||||
SPEC="nip01-smoke"
|
||||
SPEC="all"
|
||||
|
||||
# Parse command-line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
@@ -184,11 +192,13 @@ if [ "$MODE" = "audit" ]; then
|
||||
# - --relay: Command-line parameter for relay address
|
||||
# - --mode ci: Continuous integration mode (structured output)
|
||||
# - --spec: Which specification to test
|
||||
# - --git-data-dir: Path to git data directory (for git-clone, push-auth, repo-creation)
|
||||
# The '|| { }' block provides user-friendly messaging on failure
|
||||
RELAY_URL="ws://localhost:$PORT" cargo run -- audit \
|
||||
--relay "ws://localhost:$PORT" \
|
||||
--mode ci \
|
||||
--spec "$SPEC" || {
|
||||
--spec "$SPEC" \
|
||||
--git-data-dir "$TEST_DIR/repos" || {
|
||||
echo "⚠️ Some tests failed (expected for ngit-relay)"
|
||||
echo " Validation tests should have passed"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user