Skip to main content

Shadow-Sandbox DB Layer -- let AI agents modify your database safely with tenant isolation, Pydantic validation, and atomic sync.

Project description

SafeAgentDB

Shadow-Sandbox DB Layer for AI Agents.

Let AI modify your production database without the terror. SafeAgentDB intercepts every AI-generated write, isolates it in an in-memory sandbox, validates it with Pydantic, shows you a diff, and only syncs on your explicit approval — in a single atomic transaction.

Production DB ──► ShadowDB clones tenant rows ──► In-Memory SQLite Sandbox
                                                          │
                                                   AI operates freely
                                                          │
                                                   Diff + Validate
                                                          │
                                              approve? ──► Atomic Sync

Why SafeAgentDB?

You're building AI-powered features — an agent that updates tasks, a copilot that manages billing, an assistant that edits user profiles. But two things keep you up at night:

1. AI Logical Errors An LLM sets status = 'yolo_swag' instead of 'done'. Or it writes -500 to a balance field. Without a safety net, that goes straight to production.

2. Multi-Tenancy Breach Your AI agent operates on behalf of User 42 but accidentally updates User 99's rows. One misplaced WHERE clause and you have a data breach.

SafeAgentDB eliminates both risks. Every AI operation is sandboxed, validated, diffed, and tenant-scoped — before it touches production.


The 4 Safety Gates

Every commit_to_production() call passes through 4 sequential gates. If any gate fails, the entire transaction rolls back. Nothing is written.

Gate What It Does Catches
1. Tenant Isolation at Clone Only rows matching tenant_id are copied into the sandbox. Other tenants' data never enters memory. AI accessing wrong user's data
2. Row-Level Diffing Changes are computed as explicit INSERT/UPDATE/DELETE ops with before/after values. You see exactly what the AI changed. Silent data corruption
3. Pydantic Re-Validation Every row is validated against your SafeModel schema. Strict mode, no type coercion. Invalid enums, wrong types, missing fields
4. Atomic Sync + Tenant WHERE Entire changeset runs in one transaction. Every UPDATE/DELETE includes WHERE tenant_id = ? regardless of what the AI wrote. Partial writes, tenant escape at SQL level

Quick Start

Install

pip install safeagentdb

Define a validator

from typing import Literal
from safeagentdb import SafeModel

class TaskValidator(SafeModel):
    __table_name__ = "tasks"

    id: int
    user_id: int
    title: str
    status: Literal["todo", "in_progress", "done"]

Sandbox an AI agent

from sqlalchemy import create_engine
from safeagentdb import ShadowDB

prod_engine = create_engine("postgresql://user:pass@localhost/mydb")

with ShadowDB(prod_engine, tables=["tasks"], tenant_id=42) as sandbox:
    # AI does its thing — full CRUD, raw SQL, whatever
    sandbox.execute("UPDATE tasks SET status = 'done' WHERE id = 1")
    sandbox.execute(
        "INSERT INTO tasks (id, user_id, title, status) "
        "VALUES (99, 42, 'New task from AI', 'todo')"
    )

    # Review the diff
    print(sandbox.diff().display())

    # Only if you approve:
    sandbox.commit_to_production()

What the diff looks like

SafeAgentDB ChangeSet: 1 insert(s), 1 update(s), 0 delete(s)

Table | Op     | PK | Column  | Old  | New              | Validation
------+--------+----+---------+------+------------------+-----------
tasks | INSERT | 99 | id      | -    | 99               | PASS
      |        |    | user_id | -    | 42               |
      |        |    | title   | -    | New task from AI |
      |        |    | status  | -    | todo             |
tasks | UPDATE | 1  | status  | todo | done             | PASS
------+--------+----+---------+------+------------------+-----------
  >> ALL VALIDATIONS PASSED

When validation fails

# AI writes garbage
sandbox.execute("UPDATE tasks SET status = 'yolo_swag' WHERE id = 1")

changeset = sandbox.diff()
print(changeset.display())
# >> VALIDATION FAILURES DETECTED

sandbox.commit_to_production()  # Raises pydantic.ValidationError
# Production is untouched.

API Reference

ShadowDB(prod_engine, tables, tenant_id, tenant_column="user_id")

The main context manager. Accepts any SQLAlchemy Engine.

Method Description
sandbox.execute(sql, params) Execute raw SQL in the sandbox. Returns CursorResult.
sandbox.query(sql, params) Execute a SELECT, return list[dict].
sandbox.diff() Compute and return a ChangeSet with visual diff.
sandbox.commit_to_production() Validate + sync atomically. Returns rows affected.
sandbox.clone_stats dict[str, int] — rows cloned per table.
sandbox.dialect Production DB dialect name ('postgresql', 'mysql', etc.).
sandbox.session Raw SQLAlchemy Session for ORM-style operations.

SafeModel

Pydantic v2 base model with strict=True and extra="forbid". Set __table_name__ on subclasses to auto-register validators.

ChangeSet

Property/Method Description
.display() CLI-formatted diff table with validation status.
.is_empty True if no changes detected.
.is_valid True if all rows pass Pydantic validation.
.summary {"INSERT": n, "UPDATE": n, "DELETE": n}
.diffs list[RowDiff] — raw diff objects.

Supported Databases

SafeAgentDB works with any database that SQLAlchemy supports as the production source. The sandbox is always in-memory SQLite (for speed and zero-config isolation).

Database Production Source Sandbox Target Status
PostgreSQL Yes Auto-mapped Fully supported
MySQL / MariaDB Yes Auto-mapped Fully supported
SQLite Yes Direct clone Fully supported
Microsoft SQL Server Yes Auto-mapped Supported via SQLAlchemy
Oracle Yes Auto-mapped Supported via SQLAlchemy

Dialect-aware type mapping: PostgreSQL types like JSONB, UUID, ARRAY, INET, HSTORE, and TSVECTOR are automatically mapped to SQLite-safe equivalents in the sandbox. The production sync always uses the original metadata — zero fidelity loss.


How Sync Works Internally

sandbox.commit_to_production()
    │
    ├─ 1. Flush sandbox session
    ├─ 2. Snapshot current sandbox state
    ├─ 3. Compute row-level diff vs original clone
    │
    ├─ FOR EACH diff:
    │   ├─ 4. Assert tenant_id matches in row data      ← SyncError if breach
    │   ├─ 5. Run Pydantic model_validate(row)          ← ValidationError if bad
    │   └─ 6. Build SQLAlchemy Core statement:
    │       ├─ INSERT: insert(table).values(row)
    │       ├─ UPDATE: update(table).where(pk AND tenant_id).values(row)
    │       └─ DELETE: delete(table).where(pk AND tenant_id)
    │
    └─ 7. All statements execute inside engine.begin()   ← Single atomic transaction
         └─ Any failure → full rollback, zero writes

No raw SQL is generated. Every statement uses SQLAlchemy Core constructs, making the sync engine dialect-agnostic and injection-safe.


Architecture

safeagentdb/
├── __init__.py     # Public API: ShadowDB, SafeModel, ChangeSet, SyncError
├── engine.py       # Schema reflection, type mapping, sandbox creation
├── sandbox.py      # ShadowDB context manager
├── models.py       # SafeModel base + auto-registration registry
├── diff.py         # Row-level diff engine + CLI table renderer
└── sync.py         # Atomic production sync with tenant guards

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

safeagentdb-0.1.0.tar.gz (17.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

safeagentdb-0.1.0-py3-none-any.whl (16.2 kB view details)

Uploaded Python 3

File details

Details for the file safeagentdb-0.1.0.tar.gz.

File metadata

  • Download URL: safeagentdb-0.1.0.tar.gz
  • Upload date:
  • Size: 17.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for safeagentdb-0.1.0.tar.gz
Algorithm Hash digest
SHA256 f65bd0b7159d335c8585851762c04d830106dab8c4e899fb192f33402abaf766
MD5 8397419ff6e85a281d949b57200b53cf
BLAKE2b-256 d1ed5b87febfacc012b2f37951bad4612d1de6060f952d89ff765784d766cb23

See more details on using hashes here.

File details

Details for the file safeagentdb-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: safeagentdb-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 16.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.9

File hashes

Hashes for safeagentdb-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1d48b55e9f9d8bf0a70676ef65a83d5e2673d2c6a1c540035665c966e37a902a
MD5 cf6cae002d81913b1507c716f817979b
BLAKE2b-256 a1b47764c7ae0a39c5ac56fc19f427d08e364d27e26bd70a0e29037800876cdd

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page