2025-12-02 17:33:39 +00:00
2025-11-04 10:25:53 +00:00
2025-11-03 17:02:31 +00:00

ngit-grasp

A GRASP (Git Relays Authorized via Signed-Nostr Proofs) implementation in Rust.

Overview

ngit-grasp is a Rust-based implementation of the GRASP protocol, which enables decentralized Git repository hosting with Nostr-based authorization. This implementation combines:

  • Git Smart HTTP Backend: Serves Git repositories over HTTP
  • Nostr Relay: Stores and validates repository announcements and state events
  • Integrated Authorization: Validates Git pushes against Nostr state events without requiring external hooks

Unlike the reference implementation (ngit-relay) which uses nginx + git-http-backend + pre-receive hooks + Khatru (Go), ngit-grasp provides a unified Rust service that handles both Git and Nostr protocols natively.

Status

ALPHA - Under active development. API and architecture subject to change.

Key Features

  • Pure Rust Implementation: Single binary, no external dependencies beyond Git itself
  • Integrated Authorization: Push validation happens inline during the Git receive-pack operation
  • GRASP-01 Compliant: Core service requirements for Git hosting with Nostr authorization
  • Extensible Architecture: Designed to support GRASP-02 (Proactive Sync) and GRASP-05 (Archive) extensions
  • Developer-Friendly: Built with modern Rust async patterns using tokio and actix-web

Architecture Highlights

The key architectural decision is inline authorization rather than Git hooks:

  • Vendored and customised git-http-backend crate provides low-level access to the Git protocol
  • We intercept the git-receive-pack operation before spawning the Git process
  • Push validation happens by checking the Nostr relay for the latest state event
  • Only matching pushes are forwarded to the actual Git repository

This approach provides:

  • Better error messages: Direct HTTP responses vs. hook stderr
  • Simpler deployment: No hook management or symlinks
  • Tighter integration: Shared state between Git and Nostr components
  • Easier testing: Pure Rust unit and integration tests

GRASP Compliance

GRASP-01 (Core Service Requirements)

  • ✅ NIP-01 compliant Nostr relay at /
  • ✅ Accepts NIP-34 repository announcements and state events
  • ✅ Git Smart HTTP service at /<npub>/<identifier>.git
  • ✅ Push validation against Nostr state events
  • ✅ Multi-maintainer support via recursive maintainer sets
  • ✅ Support for refs/nostr/<event-id> for PRs
  • ✅ CORS support for web-based Git clients
  • ✅ NIP-11 relay information document

GRASP-02 (Proactive Sync) - Planned

  • 🔄 Proactive event sync from listed relays
  • 🔄 Proactive Git data sync from listed clone URLs
  • 🔄 PR data fetching and serving

GRASP-05 (Archive) - Planned

  • 🔄 Accept repositories not listing this instance
  • 🔄 Backup/mirror mode operation

Technology Stack

  • Rust: Core language
  • actix-web: HTTP server framework
  • git-http-backend: Git protocol handling but vendored and customised for authorisation logic
  • nostr-relay-builder: Nostr relay infrastructure from rust-nostr
  • nostr-sdk: Nostr event handling and validation
  • tokio: Async runtime

Quick Start

# install ngit
curl -Ls https://ngit.dev/install.sh | bash
# Clone the repository
git clone nostr://danconwaydev.com/relay.ngit.dev/ngit-grasp
cd ngit-grasp

# Build (using Nix for reproducible environment)
nix develop -c cargo build --release

# Configure
cp .env.example .env
# Edit .env with your settings

# Run
nix develop -c cargo run --release

# Run tests
nix develop -c cargo test --lib

Don't have Nix? See Getting Started Tutorial for alternative setup methods.

Configuration

Configuration is loaded with the following priority (highest to lowest):

  1. CLI flags (e.g., --domain example.com)
  2. Environment variables (e.g., NGIT_DOMAIN=example.com)
  3. .env file (loaded automatically if present)
  4. Built-in defaults

This means CLI flags always take precedence over environment variables, which take precedence over .env file values.

CLI Usage

# View all options with defaults
ngit-grasp --help

# Run with CLI flags (override everything else)
ngit-grasp --domain relay.example.com --owner-npub npub1... --bind-address 0.0.0.0:8080

# Mix CLI flags with environment variables
NGIT_OWNER_NPUB=npub1... ngit-grasp --domain relay.example.com

Configuration Options

Option CLI Flag Environment Variable Default
Domain --domain NGIT_DOMAIN (required)
Owner npub --owner-npub NGIT_OWNER_NPUB (optional)
Relay name --relay-name NGIT_RELAY_NAME ${domain} grasp relay
Relay description --relay-description NGIT_RELAY_DESCRIPTION Git Nostr Relay - a grasp implementation
Git data path --git-data-path NGIT_GIT_DATA_PATH ./data/git (temp dir for memory backend)
Relay data path --relay-data-path NGIT_RELAY_DATA_PATH ./data/relay (temp dir for memory backend)
Bind address --bind-address NGIT_BIND_ADDRESS 127.0.0.1:8080
Database backend --database-backend NGIT_DATABASE_BACKEND lmdb

Database Backends

  • lmdb: LMDB backend (default, persistent, general purpose)
  • memory: In-memory database (fastest, no persistence - uses temp directories)
  • nostrdb: NostrDB backend (persistent, optimized for Nostr) [Not yet implemented]

Note: When using the memory backend, git data are automatically stored in temporary directories for ephemeral testing. This is useful for development and CI/CD pipelines.

Example: Production Deployment

# Using environment variables (recommended for production)
export NGIT_DOMAIN=gitnostr.com
export NGIT_OWNER_NPUB=npub1...
export NGIT_BIND_ADDRESS=0.0.0.0:8080
export NGIT_DATABASE_BACKEND=lmdb
ngit-grasp

Example: Development

# Using .env file
cp .env.example .env
# Edit .env with your settings
ngit-grasp

# Or override specific values with CLI flags
ngit-grasp --domain localhost:3000 --bind-address 127.0.0.1:3000

Documentation

We use the Diátaxis framework for documentation:

  • Tutorials - Learn by doing (Getting Started, First Audit)
  • How-To Guides - Solve specific problems (Deploy, Configure)
  • Reference - Look up technical details (Config, Protocols)
  • Explanation - Understand concepts (Architecture, Decisions)

Start here: Documentation Index

Development

See Architecture Overview for system design and Test Strategy for testing approach.

Running Tests

We have two test suites:

1. Main Project Tests (ngit-grasp)

# Run unit tests (no external dependencies)
nix develop -c cargo test --lib

# Run all integration tests (automatic relay management)
nix develop -c cargo test --test nip01_compliance --test nip34_announcements

# Run NIP-01 compliance tests
nix develop -c cargo test --test nip01_compliance

# Run NIP-34 announcement tests
nix develop -c cargo test --test nip34_announcements

# With detailed output
nix develop -c cargo test --test nip01_compliance -- --nocapture

# Run specific test
nix develop -c cargo test --test nip01_compliance test_nip01_smoke

Integration tests automatically:

  • Start a fresh relay instance
  • Run compliance tests using grasp-audit library
  • Clean up when done
  • No manual relay management needed!

2. GRASP Audit Tool (grasp-audit)

The audit tool tests GRASP compliance of any relay (including ours or external ones).

# Enter grasp-audit directory
cd grasp-audit

# Run unit tests
nix develop -c cargo test

# Test against any relay (including external ones)
nix develop -c cargo run -- --url wss://relay.example.com

# Or test against any external relay:
nix develop -c cargo run -- --url wss://relay.example.com

Development Commands

# Run with logging
RUST_LOG=debug nix develop -c cargo run

# Check code
nix develop -c cargo clippy
nix develop -c cargo fmt --check

# Generate test coverage (requires tarpaulin)
nix develop -c cargo tarpaulin --out Html

Note: Always use nix develop to ensure the correct build environment. See docs/how-to/nix-flakes.md for details.

Project Structure

ngit-grasp/
├── src/
│   ├── main.rs              # Entry point, server setup
│   ├── git/
│   │   ├── mod.rs           # Git module
│   │   ├── handler.rs       # Git HTTP handlers
│   │   └── authorization.rs # Push validation logic
│   ├── nostr/
│   │   ├── mod.rs           # Nostr module
│   │   ├── relay.rs         # Relay setup and policies
│   │   └── events.rs        # Event handlers
│   ├── storage/
│   │   ├── mod.rs           # Storage abstraction
│   │   └── repository.rs    # Repository management
│   └── config.rs            # Configuration
├── docs/
│   └── ARCHITECTURE.md      # Detailed architecture
├── tests/
│   ├── integration/         # Integration tests
│   └── fixtures/            # Test data
└── README.md

Comparison with ngit-relay

Feature ngit-relay (Go) ngit-grasp (Rust)
Language Go Rust
Components nginx + git-http-backend + hooks + Khatru Single integrated binary
Authorization Pre-receive Git hook Inline during receive-pack
Deployment Docker + supervisord Single binary
Testing Go tests + shell scripts Rust unit + integration tests
Performance Good Excellent (zero-copy, async)

Contributing

Contributions welcome! Please:

  1. Read docs/explanation/architecture.md
  2. Open an issue to discuss major changes
  3. Follow Rust conventions and run cargo fmt + cargo clippy
  4. Add tests for new functionality

License

MIT License - see LICENSE for details

Acknowledgments

  • Reference implementation by @DanConwayDev
  • rust-nostr team for excellent Nostr libraries
  • Git community for the Smart HTTP protocol
S
Description
No description provided
Readme MIT
27 MiB
Languages
Rust 98.6%
Nix 0.7%
Shell 0.5%
HTML 0.2%