Skip to content

Latest commit

 

History

History
290 lines (215 loc) · 7.98 KB

File metadata and controls

290 lines (215 loc) · 7.98 KB

Contributing to Bloodhound

Thank you for your interest in contributing to Bloodhound! This document provides guidelines and instructions for contributing.

Code of Conduct

Please be respectful and constructive in all interactions. We welcome contributors of all backgrounds and experience levels.

Getting Started

Prerequisites

  • Rust 1.70+ (stable)
  • Docker (for integration tests)
  • Git

Development Setup

# Clone the repository
git clone https://github.com/nerdsane/bloodhound.git
cd bloodhound

# Build the project
cargo build

# Run tests
cargo test

# Run with verbose output
cargo run -- --verbose run --compose examples/simple/docker-compose.yml --seed 42

Project Structure

bloodhound/
├── src/
│   ├── main.rs           # CLI entry point
│   ├── lib.rs            # Library exports
│   ├── error.rs          # Typed error system (SimulationError, ActorError)
│   ├── actor/            # Actor-based simulation architecture
│   │   ├── mod.rs        # Actor trait and infrastructure
│   │   ├── time.rs       # TimeActor (virtual clock)
│   │   ├── fault.rs      # FaultActor (fault scheduling/injection)
│   │   ├── events.rs     # EventCollectorActor (trace recording)
│   │   ├── vm.rs         # VmActor (wraps Vm, lifecycle, faults)
│   │   └── workload.rs   # WorkloadActor (operation generation)
│   ├── buggify/          # BUGGIFY fault injection macros
│   │   └── mod.rs        # Deterministic probabilistic fault injection
│   ├── tigerstyle/       # TigerStyle assertion macros
│   │   └── mod.rs        # assert_precondition!, assert_postcondition!, etc.
│   ├── harness/          # Test harness infrastructure
│   │   └── mod.rs        # ScenarioBuilder for deterministic tests
│   ├── hypervisor/       # VM lifecycle and determinism control
│   │   ├── vm.rs         # VM management
│   │   ├── time.rs       # Virtual time system
│   │   ├── snapshot.rs   # State snapshots
│   │   ├── cow.rs        # Copy-on-write storage
│   │   └── qemu/         # QEMU integration
│   ├── fault/            # Fault injection
│   │   ├── network.rs    # Network faults
│   │   ├── disk.rs       # Disk faults
│   │   └── process.rs    # Process faults
│   ├── explore/          # State space exploration
│   │   ├── explorer.rs   # Basic explorer
│   │   ├── multiverse.rs # Full multiverse explorer
│   │   ├── coverage.rs   # Coverage tracking
│   │   └── property.rs   # Property checking
│   ├── container/        # Docker/container integration
│   │   ├── compose.rs    # docker-compose parsing
│   │   ├── translate.rs  # Container to VM translation
│   │   └── orchestrator.rs
│   ├── debug/            # Time-travel debugging
│   │   ├── trace.rs      # Execution traces
│   │   ├── replay.rs     # Replay engine
│   │   ├── gdb.rs        # GDB protocol
│   │   └── debugger.rs   # Main debugger
│   ├── simulation/       # Simulation runner
│   │   ├── runner.rs     # Async simulation loop
│   │   └── coordinator.rs # Actor-based SimulationCoordinator
│   ├── workload/         # Workload generation
│   │   └── http.rs       # HTTP workload driver
│   └── config.rs         # Configuration parsing
├── benches/              # Benchmarks
├── examples/             # Example projects
├── tests/
│   ├── regression_harness.rs    # Deterministic scenario tests
│   └── actor_vm_integration.rs  # VM actor integration tests
└── docs/                 # Documentation

Development Workflow

Branching

  • master - Main development and release branch
  • Feature branches: feature/description
  • Bug fixes: fix/description

Making Changes

  1. Fork the repository
  2. Create a feature branch from develop
  3. Make your changes
  4. Add tests for new functionality
  5. Ensure all tests pass: cargo test
  6. Ensure code is formatted: cargo fmt
  7. Ensure no clippy warnings: cargo clippy
  8. Submit a pull request

Commit Messages

Follow conventional commits:

type(scope): description

[optional body]

[optional footer]

Types:

  • feat: New feature
  • fix: Bug fix
  • docs: Documentation changes
  • test: Adding/updating tests
  • refactor: Code refactoring
  • perf: Performance improvement
  • chore: Build/tooling changes

Example:

feat(explore): add coverage-guided frontier prioritization

Implements weighted priority calculation for state exploration
that considers coverage, depth, and recency.

Testing

Unit Tests

# Run all tests
cargo test

# Run specific test
cargo test test_name

# Run tests with output
cargo test -- --nocapture

Benchmarks

# Run all benchmarks
cargo bench

# Run specific benchmark
cargo bench bench_name

Integration Tests

Integration tests require Docker and are marked #[ignore]:

# Run integration tests
cargo test -- --ignored

Documentation

Code Documentation

  • Document all public items with /// doc comments
  • Include examples where helpful
  • Use #[doc(hidden)] for internal items that must be public

README Updates

Update the README when:

  • Adding new features
  • Changing CLI interface
  • Modifying configuration format

Pull Request Process

  1. Title: Clear, descriptive title
  2. Description: Explain what and why
  3. Testing: Describe how to test changes
  4. Breaking Changes: Note any breaking changes

Review Process

  • At least one approval required
  • CI must pass
  • No merge conflicts

Release Process

Releases follow semantic versioning (MAJOR.MINOR.PATCH):

  • MAJOR: Breaking changes
  • MINOR: New features (backward compatible)
  • PATCH: Bug fixes

To release:

  1. Update version in Cargo.toml
  2. Update CHANGELOG.md
  3. Create git tag: git tag v0.x.y
  4. Push tag: git push origin v0.x.y
  5. CI will build and publish release

Getting Help

  • Open an issue for bugs or features
  • Discussions for questions and ideas
  • Tag maintainers for urgent items

Architecture Decisions

Why QEMU over bhyve?

  • Cross-platform (Linux, macOS, Windows)
  • TCG mode provides full CPU control
  • Well-documented internals
  • Native snapshot support

Why Copy-on-Write?

  • Efficient snapshot storage
  • Fast state forking for exploration
  • Minimal disk I/O

Why Single vCPU?

  • Eliminates CPU scheduling non-determinism
  • Simplifies state capture
  • Required for true determinism

Coding Style: TigerStyle

We follow TigerStyle principles. See CLAUDE.md for full details.

Key Principles

  • Use assertion macros for pre/postconditions and invariants:

    use crate::tigerstyle::{assert_precondition, assert_postcondition};
    
    fn transfer(from: &mut Account, to: &mut Account, amount: u64) -> Result<()> {
        assert_precondition!(amount > 0, "amount must be positive");
        // ... implementation
    }
  • Use typed errors (SimulationError, ActorError), not string errors

  • Prefer early returns over deep nesting

  • Use BUGGIFY for deterministic fault injection in tests:

    if buggify!("disk_write_fail", 0.01) {
        return Err(DiskError::WriteFailed);
    }
  • Watch for non-determinism: Use BTreeMap over HashMap, seeded RNG, virtual time

Performance Considerations

  • Use cargo bench before and after performance changes
  • Minimize allocations in hot paths
  • Prefer stack allocation where possible
  • Use appropriate data structures (HashMap vs BTreeMap)

Security

  • Never include secrets in commits
  • Report security issues privately
  • Follow secure coding practices

License

By contributing, you agree that your contributions will be licensed under the MIT License.