CONTRIBUTING.md¶
Shipped surface first
Contribute against 0.6 shipped APIs (Core, async, streaming, ORM/SQLModel,
callback/quarantine/log). Plugin, reflection, and raw-SQL helper work is
deferred—see Supported vs planned. Prefer
make install / make all (matches CI).
Contributing to RowGuard¶
Thank you for helping build RowGuard.
RowGuard coordinates SQLAlchemy, SQLRules, and Pydantic to provide validation- first database reads with explicit rejected-row handling. Contributions should protect that focused mission.
Project Mission¶
RowGuard exists to:
Execute SQLAlchemy queries
Apply SQLRules pushdown where safe
Validate returned rows with Pydantic
Classify every row as accepted or rejected
Handle rejections explicitly
Provide observable and typed results
RowGuard is not intended to become:
A new ORM
A migration tool
A database driver
A SQL parser
A replacement for SQLAlchemy
A replacement for Pydantic
A replacement for SQLModel
Ways to Contribute¶
Contributions may include:
Bug reports
Feature proposals
Documentation
Tests
Performance improvements
Examples
Type improvements
Security reports
Small, focused pull requests on the shipped surface are preferred.
Before Starting¶
For significant changes:
Read the relevant architecture documents.
Search existing issues and discussions.
Open a design issue before implementing a broad feature.
Identify the package boundary involved:
SQLRules
RowGuard core
Plugin
Documentation
Describe compatibility and validation implications.
Do not implement major architectural changes only in code.
Development Setup¶
Clone the repository and create a virtual environment.
git clone https://github.com/eddiethedean/rowguard.git
cd rowguard
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
Install development dependencies:
python -m pip install --upgrade pip
python -m pip install -e ".[dev,async,sqlmodel]"
Additional extras may include:
python -m pip install -e ".[dev,postgresql,async]"
python -m pip install -e ".[docs]"
Exact extras are defined in pyproject.toml (dev, docs, async, postgresql,
sqlmodel).
To build documentation locally (Sphinx / Read the Docs):
python -m pip install -e ".[docs]"
make docs
See docs/README.md for Read the Docs project import steps.
Supported Tooling¶
Expected development tools:
Python
pytest
pytest-cov
pytest-asyncio
Ruff
mypy
pre-commit
Docker or compatible containers for dialect tests
Optional:
pytest-benchmark
Hypothesis
py-spy
Scalene
Common Commands¶
Run unit tests:
pytest tests/unit
Run all default tests:
pytest
Run coverage:
pytest --cov=rowguard --cov-report=term-missing
Run linting:
ruff check .
Run formatting:
ruff format .
Run type checking:
mypy src/rowguard
Run pre-commit:
pre-commit run --all-files
Run benchmarks:
pytest benchmarks --benchmark-only
Architecture First¶
Major changes should update the relevant planning documents.
Examples:
New rejection behavior → update
REJECTION_POLICIES.mdNew adapter → update
ROW_ADAPTER.mdCache changes → update
CACHE.mdPlugin changes → update
PLUGIN_SYSTEM.mdSQLModel changes → update
SQLMODEL.mdNew public API → update
API.mdNew milestone scope → update
ROADMAP.mdandMILESTONES.md
Documentation is part of the design, not an afterthought.
Design Boundaries¶
SQLAlchemy¶
SQLAlchemy owns:
SQL expressions
SQL rendering
Sessions
Connections
ORM mapping
Dialects
Drivers
Do not reimplement SQLAlchemy behavior in RowGuard.
SQLRules¶
SQLRules owns:
Pydantic constraint extraction
Constraint-to-SQLAlchemy translation
Dialect-specific translators
RowGuard should depend only on SQLRules’ public API.
Pydantic¶
Pydantic owns:
Type validation
Strictness
Aliases
Field validators
Model validators
Nested models
Validation errors
Do not create a parallel validation system.
RowGuard¶
RowGuard owns:
Planning
Query execution
Row adaptation
Pydantic invocation
Rejection handling
Diagnostics
Results
Coding Standards¶
Use Python 3.10+ syntax according to project support.
Add type annotations to public and internal APIs.
Prefer small, composable functions.
Prefer immutable planning objects.
Keep mutable state scoped to one execution.
Avoid global mutable registries.
Preserve original exception causes.
Avoid broad
except Exceptionunless wrapping at a deliberate boundary.Never silently discard a rejected row.
Never interpolate SQL values.
Avoid import-time side effects.
Keep optional dependencies lazy.
Type Checking¶
Core code should pass strict type checking.
Requirements:
No untyped public functions
Generic result types preserve target models
Protocol implementations type-check
Sync and async APIs have accurate signatures
type: ignorecomments include a reasonAvoid
Anywhere a protocol or generic can express the contract
Typing changes should include typing tests when inference behavior matters.
Public API Changes¶
A public API change must include:
Motivation
Examples
Type signature
Error behavior
Sync/async implications
Streaming implications
Backward compatibility
Documentation
Tests
Before 1.0, changes are possible but should still be deliberate.
After 1.0, semantic versioning applies.
Error Design¶
New public errors should:
Inherit from the correct subsystem base
Preserve original exceptions
Include structured context
Avoid leaking sensitive values
Have stable behavior
Be documented
Be tested
Do not use a new exception when an existing structured error fits.
Diagnostics¶
New diagnostic codes should:
Use the correct namespace
Be stable and machine-readable
Avoid raw sensitive values
Include only bounded metadata
Be documented
Have tests
Namespaces include:
planning.*
pushdown.*
execution.*
adaptation.*
validation.*
rejection.*
callback.*
quarantine.*
stream.*
cache.*
plugin.*
Security¶
Never:
Construct SQL through value interpolation
Log raw rejected rows by default
Expose credentials in diagnostics
Pass sessions to plugins implicitly
Stringify arbitrary objects for quarantine
Disable authorization filters through validation configuration
Treat Pydantic constraints as access-control rules
Retain raw ORM entities without explicit configuration
Security-sensitive fixes should follow the private reporting process.
Testing Requirements¶
Every behavior change should include tests.
At minimum:
Success path
Failure path
Statistics
Diagnostics where relevant
Sync/async parity where relevant
Buffered/streaming parity where relevant
Security behavior where relevant
Cache-enabled/disabled equivalence where relevant
Bug fixes should include a regression test that fails before the fix.
Test Style¶
Prefer behavior-focused tests.
def test_collect_policy_preserves_rejection_order() -> None:
...
Avoid tests that assert private call order unless that order is a documented invariant.
Use real Pydantic and SQLAlchemy objects when their semantics matter.
Database Tests¶
SQLite is useful but not sufficient for all behavior.
Features involving:
Server-side streaming
UUID
JSONB
Arrays
Native enums
Driver-specific values
Async drivers
should include the relevant database integration test.
Async Contributions¶
Async changes must not duplicate the entire sync pipeline.
Share:
Planning
Adaptation
Validation
Rejection decisions
Statistics
Diagnostics
Result assembly
Separate only I/O and lifecycle operations.
Test cancellation and cleanup.
Streaming Contributions¶
Streaming changes must prove:
Accepted models are not retained
Resources close on all exits
Ordering remains stable
Rejections behave consistently
Memory remains bounded for the chosen policy (
collectretains rejects)
(Quarantine batch flush is a 0.6+ concern, not required for 0.5 PRs.)
Performance Contributions¶
Performance changes must include:
Benchmark before
Benchmark after
Correctness tests
Explanation of tradeoffs
Memory impact
Accepted/rejected path impact
Do not merge optimizations that weaken guarantees.
Plugin Contributions¶
Deferred to 0.7
There is no public plugin API in 0.5. Do not open PRs that invent plugin registries unless an issue explicitly scopes that milestone.
Public plugins should:
Implement documented protocols
Declare metadata and capabilities
Validate configuration
Avoid global mutable state
Document lifecycle
Document privacy behavior
Document transaction behavior
Pass conformance tests
Keep heavy dependencies optional
New official plugins require a maintenance commitment.
Dialect Contributions¶
A dialect contribution should include:
Supported database versions
Supported drivers
Sync/async status
Streaming status
Type-return notes
Integration tests
Known limitations
Documentation
SQLRules plugin dependency when relevant
Do not claim full support from SQL compilation tests alone.
Documentation Style¶
Documentation should:
Be precise
Use complete examples
Distinguish current behavior from planned behavior
Avoid overstating SQLModel limitations
Explain security and transaction implications
Prefer explicit contracts over vague promises
Keep package boundaries clear
Examples should be tested where practical.
Commit Style¶
Use focused commits with descriptive messages.
Examples:
Add nested row adapter planning
Fix async stream cleanup on callback failure
Document PostgreSQL array behavior
Avoid combining unrelated refactors and features.
Pull Requests¶
A pull request should include:
Problem statement
Proposed solution
Alternatives considered
Public API impact
Tests
Documentation
Performance impact
Security/privacy impact
Compatibility notes
Keep pull requests reviewable.
Large changes may be split into:
Architecture/docs
Internal interfaces
Implementation
Integrations
Examples
Pull Request Checklist¶
Scope is focused
Architecture documents updated
Public API documented
Tests added
Failure paths tested
Sync/async parity considered
Streaming considered
Security and redaction considered
Type checking passes
Linting passes
Benchmarks added or reviewed where relevant
Changelog entry added when appropriate
No unnecessary dependency added
Review Priorities¶
Reviewers should prioritize:
Correctness
Validation guarantees
Security/privacy
Resource cleanup
API clarity
Type safety
Compatibility
Performance
Style
Backward Compatibility¶
Before 1.0:
Public APIs may evolve
Changes should include migration notes
Avoid unnecessary churn
After 1.0:
Breaking public changes require a major release
Public result objects and errors are compatibility commitments
Plugin API major versions are explicit
Private modules remain unstable unless documented.
Deprecation¶
Deprecations should:
Emit a clear warning
Include replacement guidance
Be documented
Include a migration example
Remain for a reasonable transition period
Avoid silent behavior changes
Dependency Policy¶
New dependencies should be justified.
Prefer:
Standard library
Existing core dependencies
Optional extras
Small focused packages
Avoid adding heavy cloud, analytics, or observability dependencies to core.
Release Notes¶
User-visible changes should be recorded under categories such as:
Added
Changed
Fixed
Deprecated
Removed
Security
Performance
Mention:
Validation behavior changes
Rejection-policy changes
Dialect changes
Plugin API changes
Dependency range changes
Issue Reports¶
A good bug report includes:
RowGuard version
Python version
SQLAlchemy version
Pydantic version
SQLRules version
SQLModel version where relevant
Database and driver
Minimal model
Minimal query
Rejection policy
Expected behavior
Actual behavior
Traceback with sensitive values removed
Feature Requests¶
A feature request should answer:
What problem does it solve?
Why is RowGuard the correct layer?
Could it be a plugin?
Does it affect validation guarantees?
Does it affect SQLRules?
What are sync/async and streaming implications?
What is the smallest useful API?
Security Reports¶
Do not open a public issue for a vulnerability involving:
SQL injection
Redaction bypass
Credential exposure
Cross-tenant data exposure
Unsafe plugin execution
Quarantine data leakage
Use the repository’s documented private security contact.
Code of Conduct¶
Contributors must follow the project’s Code of Conduct.
Security reports: see SECURITY.md (do not open public issues for vulnerabilities).
Technical disagreement should remain respectful, specific, and grounded in the project’s goals and evidence.
Good First Contributions¶
Prefer work on the shipped 0.6 surface:
Improve documentation examples and guides
Add missing rejection / streaming / ORM tests
Add typing stubs under
tests/typingAdd SQLite edge-case tests
Improve diagnostics messages (without leaking row values)
Improve error messages without exposing values
Benchmark reporting for existing APIs
Avoid starting with deferred milestones (plugins, reflection, raw SQL helpers) unless an issue explicitly scopes that work.
Maintainer Responsibilities¶
Maintainers should:
Protect project scope
Review validation guarantees carefully
Keep architecture docs current
Avoid unsupported compatibility claims
Publish transparent benchmark results
Maintain plugin and dialect support levels honestly
Provide migration guidance
Treat security and privacy as core concerns
Design Principles¶
Focus on validation-first reads.
Extend SQLAlchemy; do not replace it.
Delegate validation to Pydantic.
Delegate SQL constraint compilation to SQLRules.
Make rejections explicit.
Prefer immutable plans and narrow protocols.
Keep optional integrations outside core.
Test failure paths as seriously as success paths.
Document before adding complexity.