From d428baf30feec295870fadda2d335d1e7f89507b Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Mon, 3 Nov 2025 17:02:31 +0000 Subject: docs: one-prompt architecture plan ok 2 prompts, the second one was about the test strategy so we could reuse it. I was thinking of a tool like blossom audit. but i didnt mention it specifically. --- docs/GETTING_STARTED.md | 437 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 437 insertions(+) create mode 100644 docs/GETTING_STARTED.md (limited to 'docs/GETTING_STARTED.md') diff --git a/docs/GETTING_STARTED.md b/docs/GETTING_STARTED.md new file mode 100644 index 0000000..7fea590 --- /dev/null +++ b/docs/GETTING_STARTED.md @@ -0,0 +1,437 @@ +# Getting Started with Implementation + +This guide helps you start implementing ngit-grasp based on the architecture design. + +## Prerequisites + +- Rust 1.75 or later +- Git 2.x +- Basic understanding of async Rust (tokio) +- Familiarity with actix-web (helpful) +- Understanding of Nostr basics (helpful) + +## Step 1: Initialize Cargo Project + +```bash +# Create new binary project +cargo init --name ngit-grasp + +# Or if already created: +cargo build +``` + +## Step 2: Add Dependencies + +Edit `Cargo.toml`: + +```toml +[package] +name = "ngit-grasp" +version = "0.1.0" +edition = "2021" +rust-version = "1.75" + +[dependencies] +# HTTP Server +actix-web = "4" +actix-cors = "0.7" + +# Async Runtime +tokio = { version = "1", features = ["full"] } + +# Git Protocol +git-http-backend = "0.1.3" + +# Nostr +nostr-sdk = { version = "0.43", features = ["all-nips"] } +nostr-relay-builder = "0.43" + +# Serialization +serde = { version = "1", features = ["derive"] } +serde_json = "1" + +# Error Handling +anyhow = "1" +thiserror = "1" + +# Logging +tracing = "0.1" +tracing-subscriber = { version = "0.3", features = ["env-filter"] } + +# Environment +dotenv = "0.15" + +# Utilities +async-trait = "0.1" +futures = "0.3" +bytes = "1" + +[dev-dependencies] +tokio-test = "0.4" +``` + +## Step 3: Project Structure + +Create the directory structure: + +```bash +mkdir -p src/{git,nostr,storage} +mkdir -p tests/{integration,fixtures} +mkdir -p data/{git,relay} +``` + +## Step 4: Configuration Module + +Create `src/config.rs`: + +```rust +use anyhow::Result; +use std::env; +use std::net::SocketAddr; +use std::path::PathBuf; + +#[derive(Debug, Clone)] +pub struct Config { + pub domain: String, + pub owner_npub: String, + pub relay_name: String, + pub relay_description: String, + pub git_data_path: PathBuf, + pub relay_data_path: PathBuf, + pub bind_address: SocketAddr, +} + +impl Config { + pub fn from_env() -> Result { + dotenv::dotenv().ok(); + + Ok(Config { + domain: env::var("NGIT_DOMAIN")?, + owner_npub: env::var("NGIT_OWNER_NPUB")?, + relay_name: env::var("NGIT_RELAY_NAME")?, + relay_description: env::var("NGIT_RELAY_DESCRIPTION")?, + git_data_path: PathBuf::from( + env::var("NGIT_GIT_DATA_PATH") + .unwrap_or_else(|_| "./data/git".to_string()) + ), + relay_data_path: PathBuf::from( + env::var("NGIT_RELAY_DATA_PATH") + .unwrap_or_else(|_| "./data/relay".to_string()) + ), + bind_address: env::var("NGIT_BIND_ADDRESS") + .unwrap_or_else(|_| "127.0.0.1:8080".to_string()) + .parse()?, + }) + } +} +``` + +## Step 5: Core Types + +Create `src/git/types.rs`: + +```rust +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct RefUpdate { + pub old_oid: String, + pub new_oid: String, + pub ref_name: String, +} + +impl RefUpdate { + pub fn is_create(&self) -> bool { + self.old_oid == "0000000000000000000000000000000000000000" + } + + pub fn is_delete(&self) -> bool { + self.new_oid == "0000000000000000000000000000000000000000" + } + + pub fn is_update(&self) -> bool { + !self.is_create() && !self.is_delete() + } +} + +#[derive(Debug, thiserror::Error)] +pub enum GitError { + #[error("Invalid pkt-line format")] + InvalidPktLine, + + #[error("Invalid ref update format")] + InvalidRefUpdate, + + #[error("Repository not found: {0}")] + RepositoryNotFound(String), + + #[error("Invalid repository path")] + InvalidPath, +} +``` + +## Step 6: Main Application State + +Create `src/main.rs`: + +```rust +use actix_web::{web, App, HttpServer}; +use anyhow::Result; +use std::sync::Arc; +use tracing::info; + +mod config; +mod git; +mod nostr; +mod storage; + +use config::Config; + +#[derive(Clone)] +pub struct AppState { + pub config: Arc, + // TODO: Add NostrClient, RepositoryManager, etc. +} + +#[actix_web::main] +async fn main() -> Result<()> { + // Initialize logging + tracing_subscriber::fmt() + .with_env_filter( + tracing_subscriber::EnvFilter::from_default_env() + ) + .init(); + + // Load configuration + let config = Config::from_env()?; + info!("Starting ngit-grasp on {}", config.bind_address); + + // Create application state + let state = AppState { + config: Arc::new(config.clone()), + }; + + // Start HTTP server + HttpServer::new(move || { + App::new() + .app_data(web::Data::new(state.clone())) + .configure(git::routes::configure) + .configure(nostr::routes::configure) + }) + .bind(config.bind_address)? + .run() + .await?; + + Ok(()) +} +``` + +## Step 7: Git Module Skeleton + +Create `src/git/mod.rs`: + +```rust +pub mod routes; +pub mod handler; +pub mod parser; +pub mod authorization; +pub mod types; + +pub use types::{RefUpdate, GitError}; +``` + +Create `src/git/routes.rs`: + +```rust +use actix_web::web; + +pub fn configure(cfg: &mut web::ServiceConfig) { + cfg.service( + web::scope("/{npub}/{identifier}.git") + .route("/info/refs", web::get().to(super::handler::info_refs)) + .route("/git-upload-pack", web::post().to(super::handler::git_upload_pack)) + .route("/git-receive-pack", web::post().to(super::handler::git_receive_pack)) + ); +} +``` + +## Step 8: First Test + +Create `tests/integration/basic_test.rs`: + +```rust +use actix_web::{test, App}; + +#[actix_web::test] +async fn test_server_starts() { + // TODO: Initialize test app + // TODO: Make test request + assert!(true); +} +``` + +Run tests: + +```bash +cargo test +``` + +## Step 9: Implementation Order + +Follow this order for implementation: + +### Phase 1: Basic Infrastructure (Week 1) +1. ✅ Config module +2. ✅ Main server setup +3. ✅ Core types +4. ⏭️ Git pkt-line parser +5. ⏭️ Ref update parser +6. ⏭️ Parser tests + +### Phase 2: Git Protocol (Week 2) +1. ⏭️ Git upload-pack handler (read-only) +2. ⏭️ Repository manager +3. ⏭️ Path validation and security +4. ⏭️ Integration tests for cloning + +### Phase 3: Nostr Relay (Week 2-3) +1. ⏭️ Nostr relay setup with nostr-relay-builder +2. ⏭️ Repository announcement policy +3. ⏭️ Event hooks for repo creation +4. ⏭️ NIP-11 configuration + +### Phase 4: Authorization (Week 3-4) +1. ⏭️ Maintainer resolution logic +2. ⏭️ State validation logic +3. ⏭️ Git receive-pack with inline validation +4. ⏭️ Integration tests for pushing + +### Phase 5: Polish (Week 4-6) +1. ⏭️ Error handling improvements +2. ⏭️ Logging and observability +3. ⏭️ Performance optimization +4. ⏭️ GRASP-01 compliance testing +5. ⏭️ Documentation updates + +## Development Workflow + +### Running Locally + +```bash +# Copy environment template +cp .env.example .env + +# Edit configuration +vim .env + +# Run in development mode +cargo run + +# With debug logging +RUST_LOG=debug cargo run +``` + +### Testing + +```bash +# Run all tests +cargo test + +# Run with output +cargo test -- --nocapture + +# Run specific test +cargo test test_parse_ref_updates + +# Run integration tests only +cargo test --test '*' +``` + +### Code Quality + +```bash +# Format code +cargo fmt + +# Check formatting +cargo fmt --check + +# Lint +cargo clippy + +# Lint with all features +cargo clippy --all-features -- -D warnings +``` + +## Debugging Tips + +### Enable Detailed Logging + +```bash +RUST_LOG=trace cargo run +``` + +### Test with Real Git Client + +```bash +# In another terminal, after server is running +mkdir test-repo && cd test-repo +git init +echo "test" > README.md +git add . && git commit -m "test" + +# Try to push (will fail without Nostr setup) +git remote add origin http://localhost:8080/npub.../test.git +git push origin main +``` + +### Use curl for HTTP Testing + +```bash +# Test info/refs endpoint +curl -v http://localhost:8080/npub.../test.git/info/refs?service=git-upload-pack +``` + +## Common Issues + +### "Repository not found" +- Check that repository announcement was sent to Nostr relay +- Verify repository was created in git_data_path +- Check logs for repo creation + +### "Push rejected" +- Verify state event exists on relay +- Check state event matches push refs +- Verify maintainer list includes pusher + +### "Cannot connect to relay" +- Check relay is running +- Verify WebSocket endpoint +- Check firewall/network settings + +## Next Steps + +After basic setup: + +1. Implement pkt-line parser (see [GIT_PROTOCOL.md](GIT_PROTOCOL.md)) +2. Add comprehensive tests +3. Implement Nostr relay policies +4. Add authorization logic +5. Test with ngit CLI + +## Resources + +- [ARCHITECTURE.md](ARCHITECTURE.md) - Detailed design +- [GIT_PROTOCOL.md](GIT_PROTOCOL.md) - Git protocol reference +- [actix-web docs](https://actix.rs/docs/) +- [nostr-sdk docs](https://docs.rs/nostr-sdk/) +- [tokio docs](https://docs.rs/tokio/) + +## Getting Help + +- Check existing documentation in `docs/` +- Review reference implementation at `../ngit-relay` +- Open an issue for questions +- Read GRASP protocol spec + +Good luck! 🚀 -- cgit v1.2.3