Contributing#
We welcome contributions to DBSurveyor! This guide will help you get started with contributing to the project.
Code of Conduct#
DBSurveyor follows the Rust Code of Conduct. Please be respectful and inclusive in all interactions.
Getting Started#
Prerequisites#
- Rust 1.93.1+ (MSRV)
- Git
- Docker (for integration tests)
- Just task runner
Development Setup#
# Clone the repository
git clone https://github.com/EvilBit-Labs/dbsurveyor.git
cd dbsurveyor
# Install development tools
just install
# Run initial checks
just dev
Project Structure#
dbsurveyor/
├── dbsurveyor-core/ # Shared library
├── dbsurveyor-collect/ # Collection binary
├── dbsurveyor/ # Documentation binary
├── docs/ # Documentation source
│ └── solutions/ # Documented solutions to past problems
└── justfile # Development tasks
Development Workflow#
Daily Development#
# Format, lint, test, and check coverage
just dev
# Run specific test categories
just test-unit
just test-integration
just test-security
# Security validation
just security-full
# Pre-commit checks
just pre-commit
Code Quality Standards#
DBSurveyor enforces strict quality standards:
- Zero Warnings:
cargo clippy -- -D warningsmust pass - Test Coverage: 55% minimum coverage required (target: 80%, to be raised incrementally)
- Security First: All code must pass security validation
- Documentation: All public APIs must have
///documentation
Testing Requirements#
All contributions must include appropriate tests:
// Unit tests in source files
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_credential_sanitization() {
let config = ConnectionConfig::new("postgres://user:secret@host/db");
let safe_display = config.to_safe_string();
assert!(!safe_display.contains("secret"));
}
}
// Integration tests in tests/ directory
#[tokio::test]
async fn test_postgres_collection() {
let docker = testcontainers::clients::Cli::default();
let postgres = docker.run(testcontainers::images::postgres::Postgres::default());
// Test implementation
}
// Security tests are mandatory for security-sensitive code
#[tokio::test]
async fn test_no_credentials_in_output() {
let schema = collect_schema("postgres://user:secret@localhost/db").await?;
let json = serde_json::to_string(&schema)?;
assert!(!json.contains("secret"));
}
Contribution Types#
Bug Reports#
When reporting bugs, please include:
- System Information: OS, Rust version, DBSurveyor version
- Reproduction Steps: Minimal example that reproduces the issue
- Expected vs Actual Behavior: Clear description of the problem
- Debug Information: Output with
RUST_LOG=debug
Security Note: Never include actual database credentials in bug reports.
Feature Requests#
For new features, please:
- Check Existing Issues: Avoid duplicates
- Describe Use Case: Why is this feature needed?
- Propose Implementation: High-level approach
- Consider Security: How does this maintain security guarantees?
Code Contributions#
Pull Request Process#
- Fork and Branch: Create a feature branch from
main - Implement Changes: Follow coding standards
- Add Tests: Comprehensive test coverage
- Update Documentation: Keep docs in sync
- Run Quality Checks:
just devmust pass - Submit PR: Clear description and context
Commit Standards#
Follow Conventional Commits:
# Feature additions
feat(postgres): add connection pooling with timeout handling
feat(security): implement AES-GCM encryption with random nonces
# Bug fixes
fix(mysql): handle connection failures without exposing credentials
fix(core): ensure proper cleanup of sensitive data structures
# Security improvements
security(core): prevent credential leakage in error messages
security(encryption): add key derivation parameter validation
# Documentation
docs(readme): update installation instructions
docs(security): add encryption implementation details
Database Adapter Development#
Adding New Database Support#
To add support for a new database:
-
Create Adapter Module:
// dbsurveyor-core/src/adapters/newdb.rs pub struct NewDbAdapter { config: ConnectionConfig, } #[async_trait] impl DatabaseAdapter for NewDbAdapter { async fn test_connection(&self) -> Result<()> { ... } async fn collect_schema(&self) -> Result<DatabaseSchema> { ... } async fn sample_table(&self, table_ref: TableRef<'_>, config: &SamplingConfig) -> Result<TableSample> { ... } fn database_type(&self) -> DatabaseType { ... } fn supports_feature(&self, feature: AdapterFeature) -> bool { ... } fn connection_config(&self) -> ConnectionConfig { ... } } -
Add Feature Flag:
# Cargo.toml [features] newdb = ["dep:newdb-driver"] -
Update Factory:
// dbsurveyor-core/src/adapters.rs match database_type { #[cfg(feature = "newdb")] DatabaseType::NewDb => { let adapter = NewDbAdapter::new(connection_string).await?; Ok(Box::new(adapter)) } // ... } -
Add Tests:
// tests/integration/newdb_tests.rs #[tokio::test] async fn test_newdb_collection() { // Integration test with testcontainers }
Database Adapter Requirements#
All database adapters must:
- Implement
DatabaseAdaptertrait completelytest_connection(): Verify database connectivitycollect_schema(): Collect full database schema informationsample_table(): Sample data from a specific tabledatabase_type(): Return the database typesupports_feature(): Indicate supported featuresconnection_config(): Provide connection configuration
- Use read-only operations only (SELECT, DESCRIBE, SHOW)
- Handle connection timeouts (default: 30 seconds)
- Sanitize credentials in all error messages
- Support connection pooling where applicable
- Include comprehensive tests with testcontainers
- Document database-specific features and limitations
The sample_table() Method#
The sample_table() method performs per-table sampling for a specific table:
async fn sample_table(
&self,
table_ref: TableRef<'_>,
config: &SamplingConfig,
) -> Result<TableSample>;
Parameters:
table_ref: ATableRefcontaining the table name and optional schema nameconfig: ASamplingConfigwith sampling parameters (sample size, throttle, etc.)
Returns: A TableSample that includes:
- Sampled rows as JSON values
- Sample metadata (size, total rows, strategy used)
- Collection timestamp and any warnings
sample_status: An optional field indicating the sampling outcome
Sample Status Values:
Some(SampleStatus::Complete): Sampling completed successfullySome(SampleStatus::PartialRetry { original_limit }): Sampling partially completed with a reduced limitSome(SampleStatus::Skipped { reason }): Sampling was skipped (e.g., not implemented)None: For backward compatibility with existing data
Implementation Notes:
- The
TableRefstruct wraps the table name and optional schema for the method signature - Implementations should populate
sample_statuswithSampleStatus::Completeon successful sampling - If sampling is not implemented, return
SampleStatus::Skippedwith an appropriate reason - The method supports optional schema qualification (e.g.,
public.usersvsusers)
Testing Database Adapters#
# Test specific database adapter
just test-postgres
just test-mysql
just test-sqlite
# Test with real databases using testcontainers
cargo test --test postgres_integration -- --nocapture
# Security testing for new adapters
cargo test --test security_credential_protection
Security Contributions#
Security-First Development#
All contributions must maintain DBSurveyor's security guarantees:
- No Credential Exposure: Never log or output credentials
- Offline Operation: No external network calls except to databases
- Encryption Security: Use AES-GCM with random nonces
- Memory Safety: Use
zeroizefor sensitive data
Security Review Process#
Security-sensitive changes require additional review:
- Security Tests: Must include security-specific tests
- Threat Model: Consider impact on threat model
- Documentation: Update security documentation
- Review: Additional security-focused code review
Security Testing#
// Example security test
#[tokio::test]
async fn test_new_feature_credential_security() {
// Test that new feature doesn't leak credentials
let result = new_feature("postgres://user:secret@localhost/db").await?;
let output = format!("{:?}", result);
assert!(!output.contains("secret"));
assert!(!output.contains("user:secret"));
}
Documentation Contributions#
Documentation Standards#
- User-Focused: Write for the end user
- Security-Aware: Highlight security implications
- Example-Rich: Include working code examples
- Up-to-Date: Keep in sync with code changes
Documentation Types#
- API Documentation:
///comments in code - User Guide: Markdown files in
docs/src/ - README: Project overview and quick start
- Security Documentation: Security features and guarantees
Building Documentation#
# Build API documentation
cargo doc --all-features --document-private-items --open
# Build user guide
just docs
# Check documentation
just docs-check
Release Process#
Version Management#
DBSurveyor uses semantic versioning:
- Major: Breaking changes
- Minor: New features (backward compatible)
- Patch: Bug fixes
Release Checklist#
- Update Version: Bump version in
Cargo.toml - Update Changelog: Document all changes
- Run Full Tests:
just security-full - Update Documentation: Ensure docs are current
- Create Release: Tag and create GitHub release
- Verify Artifacts: Test release binaries
Community Guidelines#
Communication#
- GitHub Issues: Bug reports and feature requests
- Pull Requests: Code contributions and discussions
- Security Issues: Email security@evilbitlabs.io
Review Process#
- Automated Checks: CI must pass
- Code Review: Maintainer review required
- Security Review: For security-sensitive changes
- Documentation Review: For user-facing changes
Recognition#
Contributors are recognized in:
CONTRIBUTORS.mdfile- Release notes
- Git commit history
Development Environment#
Recommended Tools#
- IDE: VS Code with Rust Analyzer
- Git Hooks: Pre-commit hooks for quality checks
- Testing: Nextest for faster test execution
- Debugging:
RUST_LOG=debugfor detailed logging
Environment Variables#
# Development environment
export RUST_LOG=debug
export DATABASE_URL="postgres://dev:dev@localhost/dev_db"
# Testing environment
export RUST_LOG=trace
export DBSURVEYOR_TEST_TIMEOUT=60
Docker Development#
# Start test databases
docker-compose up -d postgres mysql mongodb
# Run integration tests
just test-integration
# Clean up
docker-compose down
Troubleshooting Development Issues#
Common Issues#
Build failures:
# Clean and rebuild
cargo clean
cargo build --all-features
# Update toolchain
rustup update
Test failures:
# Run specific test with output
cargo test test_name -- --nocapture
# Run with debug logging
RUST_LOG=debug cargo test test_name
Clippy warnings:
# Fix automatically where possible
cargo clippy --fix --allow-dirty
# Check specific warnings
cargo clippy --workspace --all-targets --all-features -- -D warnings
Getting Help#
- Documentation: Check existing docs first
- Issues: Search existing GitHub issues
- Code: Look at similar implementations
- Community: Ask questions in GitHub discussions
License and Legal#
License#
DBSurveyor is licensed under the Apache License 2.0. By contributing, you agree to license your contributions under the same license.
Copyright#
All contributions must include appropriate copyright headers:
// Copyright 2024 EvilBit Labs
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Contributor License Agreement#
By submitting a pull request, you represent that:
- You have the right to license your contribution
- You agree to license it under the Apache License 2.0
- Your contribution is your original work
Thank you for contributing to DBSurveyor! Your contributions help make database documentation more secure and accessible for everyone.