Tennant Guard (10-grd)
Tenant isolation primitives for developers building agentic tools in any environment.
GRD keeps the authenticated tenant scope attached to protected data operations. Its Z3 engine checks whether a supported selector can include foreign-owned or unlabeled data. The guarded client adds tenant scope, checks before execution, and validates complete result batches before returning them.
This is a standalone project with its own audience and architecture. It has no dependency on invariant-sast or AWS.
Install
Requires Python 3.10 or later:
python -m pip install ten-grd
The distribution is named ten-grd; the Python import is ten_grd.
Runnable examples, including Claude Agent SDK agents, are in the public
ten-grd-examples repository, and the
documentation is at ikurira.github.io/ten-grd-examples.
Use in an agent memory tool
from ten_grd import InMemoryAdapter, TenantContext, TenantGuard, tenant_scope
memory = TenantGuard(InMemoryAdapter())
# Your host authenticates the subject and validates tenant membership first.
with tenant_scope(TenantContext("acme", "alice", "request-1")):
memory.put("plan", {"text": "Acme's private plan"}, metadata={"kind": "plan"})
assert memory.get("plan").data["text"] == "Acme's private plan"
with tenant_scope(TenantContext("other", "bob", "request-2")):
assert memory.get("plan") is None
Tenant IDs in these examples are already authenticated by the host. Constructing TenantContext validates identifier format; it does not authenticate a user or establish tenant membership. Never construct it from an unchecked prompt, tool argument, or request field.
Tool implementations can call memory.get, search, put, and delete
inside the host-established scope. A tool argument cannot override the tenant
parameter because the guarded methods expose no such parameter.
Try tenant-scoped RAG
Run a local vector retrieval and answer assembly example without API keys:
git clone https://github.com/Ikurira/ten-grd-examples.git
cd ten-grd-examples
python -m pip install -r requirements.txt
python basic/tenant_rag.py
The example seeds two tenants with the same document ID. A foreign document has the closest vector, but only the active tenant's document reaches the answer. It also demonstrates an OR expression attempting to widen access and an explicit foreign-tenant selector returning no documents. Fixed vectors and extractive answers keep the demo reproducible; production embeddings and LLM generation remain host integrations. Retrieved content is still untrusted input.
Selectors and formal checks
from ten_grd import Eq, Or, VerificationStatus, Z3InvariantEngine
engine = Z3InvariantEngine(timeout_ms=1000)
context = TenantContext("acme", "alice", "request-3")
safe = engine.verify_selector(context, Eq("tenant_id", "acme"))
assert safe.status is VerificationStatus.PROVEN
unsafe = engine.verify_selector(
context, Or((Eq("tenant_id", "acme"), Eq("tenant_id", "other")))
)
assert unsafe.status is VerificationStatus.VIOLATION
The public selector language supports Eq, And, Or, and Not over string metadata.
Missing fields are modeled explicitly. Raw SQL, filter strings, caller-supplied
filter_applied flags, and unsupported expression types are not security evidence.
The guarded client always places user selectors beneath its own tenant predicate. A user selector that requests another tenant returns no data; it never replaces the mandatory tenant restriction.
What this release protects
The included in-memory adapter provides atomic, tenant-partitioned create/replace, read, search, and delete operations. Record ownership is separate from user data. Payloads are JSON snapshots; reserved metadata cannot override tenant identity. Context uses contextvars; the engine creates a separate Z3 context per check.
Only PROVEN permits execution. SAT is a violation; UNKNOWN (including solver timeouts), unsupported expressions, and errors deny. Result validation occurs before returning a batch. There is no runtime soft-fail option.
Assurance boundary
A proof applies to the supported selector model. It does not prove arbitrary agent code, backend implementations, prompts, or deployment security. An empty selector can be safely unsatisfiable; this is not evidence of useful access.
The host authentication boundary, enforcement client, and storage adapter are trusted. An in-process SDK cannot prevent hostile application code from using raw credentials or bypassing the client. Custom adapters must execute exactly the checked operation and uphold ownership atomically. Read-result validation cannot undo an unsafe write by a faulty adapter.
Version 0.2 adds SQLite/PostgreSQL storage, Qdrant retrieval, Redis exact caching, Qdrant semantic caching, and LangChain tools. Authentication remains the host responsibility.
Incident-inspired regression requirements
Tests use verified Spring AI filter-injection and LiteLLM cache-isolation advisories to define general attack patterns and adapter acceptance criteria. These are regression guides, not claims of complete CVE mitigation or certification of affected third-party products.
Integrations
Install optional backends as extras:
| Backend | Install |
|---|---|
| PostgreSQL storage | python -m pip install "ten-grd[postgres]" |
| Qdrant retrieval and semantic cache | python -m pip install "ten-grd[qdrant]" |
| Redis exact cache | python -m pip install "ten-grd[redis]" |
| LangChain tools | python -m pip install "ten-grd[langchain]" |
| All of the above | python -m pip install "ten-grd[all]" |
SQLite storage needs no extra.
Claude Agent SDK examples
The Claude memory and RAG examples use host-bound MCP tools and synthetic tenant data. Both provide deterministic local checks and opt-in live Claude execution; see their setup guide for commands and assurance limits.
Development
python -m pip install -e ".[dev]"
python -m pytest -q
python -m compileall -q src
Tests cover foreign access, tenant scope injection, result leakage, write partitioning, async/thread isolation, inconclusive solvers, evidence binding, immutable snapshots, and differential checks of generated selector expressions.
Licensed under Apache-2.0.
Metadata
Release files for ten-grd 0.2.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| ten_grd-0.2.2.tar.gz | 30.8 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| ten_grd-0.2.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 58.7 kB
Release files / ten_grd-0.2.2.tar.gz
| Download URL | ten_grd-0.2.2.tar.gz |
|---|---|
| Size | 30.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
4eb024a010ae856fdc68fa90c9f059b51b7b18ec112b0aead037cc061dcce591
|
|
BLAKE2b-256 checksum How to use checksums |
2fd1162e3416e1e3071fce6d8dd098b541c96a09e447889905dc194e81cc4ae6
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logRelease files / ten_grd-0.2.2-py3-none-any.whl
| Download URL | ten_grd-0.2.2-py3-none-any.whl |
|---|---|
| Size | 27.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
187e1d374a9582bc7e7cf288b4490f1b9d3f919807a7547f5de6a4e2ca4dd217
|
|
BLAKE2b-256 checksum How to use checksums |
a010d86e870092b74f502d845b21423e31132f1ca9d963e69c4dd6f3731f4450
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logSecurity for ten-grd 0.2.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for ten_grd-0.2.2.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 24, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.