Skip to main content

zanzibar-index

Zanzibar-style relationship-based access control (ReBAC) for Python, on top of SQLModel. Schemas are written in the OpenFGA modelling DSL, including the and / but not operators. The package is not affiliated with Google or OpenFGA.

Two evaluation backends give the same answers with opposite cost models:

  • zanzibar.setengine stores only the raw tuples and computes memberships on the fly with bitmap algebra (roaring bitmaps). Writes are cheap, reads do the work.
  • zanzibar.graphindex materializes the transitive closure as reference-counted edges, so check is a single indexed lookup. Writes do the work, reads are cheap.

zanzibar.connectedstore composes them: an append-only tuple log is the source of truth, the graph index is a materialized view over it, and reads fall back to the set engine when the index is behind.

Status: alpha, research code, no support promised

This is a personal research project. It is tested heavily: a differential suite checks both backends against an independent reference oracle, there is property-based fuzzing, and the core algorithms have machine-checked Lean proofs. It has never run in production, there is no performance target, and the API may change between 0.x releases. Issues and pull requests are welcome, but answers are best-effort.

Install

pip install zanzibar-index              # SQLite
pip install "zanzibar-index[postgres]"  # adds psycopg2-binary for PostgreSQL

Python 3.13 or later. The import name is zanzibar.

Quickstart

from sqlmodel import SQLModel, Session, create_engine
from zanzibar.connectedstore import ConnectedStore

SCHEMA = """
model
  schema 1.1
type user
type group
  relations
    define member: [user, group#member]
type doc
  relations
    define banned: [user]
    define viewer: [user, group#member] but not banned
"""

engine = create_engine("sqlite:///perms.db")
SQLModel.metadata.create_all(engine)   # creates the zanzibar_* tables (see below)

with Session(engine) as session:
    store = ConnectedStore(session, "my-app", schema=SCHEMA)
    # add_tuple(subject_predicate, subject_type, subject_name, relation, object_type, object_name)
    store.add_tuple("...", "user", "alice", "member", "group", "eng")      # "..." = the bare user
    store.add_tuple("member", "group", "eng", "viewer", "doc", "d1")       # group#member is a viewer
    store.check("...", "user", "alice", "viewer", "doc", "d1")             # True

    store.add_tuple("...", "user", "alice", "banned", "doc", "d1")
    store.check("...", "user", "alice", "viewer", "doc", "d1")             # False

Each write commits and returns a log id. Pass it back as check(..., at_least=token) to read your own writes when the index is maintained asynchronously (sync=False). Reopening a store with ConnectedStore(session, "my-app") reads its persisted schema; a store's schema is write-once.

Things to know before you use it

  • Tables. The library declares its tables on SQLModel's default metadata, all named zanzibar_*, so SQLModel.metadata.create_all(engine) creates them next to your own. A table of yours that reuses one of those names is a loud InvalidRequestError, whichever is declared first; the two are never silently merged.
  • Databases. SQLite and PostgreSQL only. On PostgreSQL the session must use READ COMMITTED; any other isolation level is refused at construction.
  • Runtime checks. ConnectedStore(..., paranoia="residue") or the ZANZIBAR_PARANOIA=residue environment variable turns on a cheap runtime corruption detector for the index. It is off by default and recommended for anything security-sensitive.
  • Schema shapes. Some valid OpenFGA shapes are refused with an explanation of what to write instead: for example, a from tupleset must be a direct relation. Wildcard usersets ([group:*#member]) and object wildcards go beyond OpenFGA. They work, but they are outside the proved fragment and emit UnprovenExtensionWarning.
  • Write cap. A single write that would add more than ZANZIBAR_MAX_CLOSURE_FANOUT closure edges (default 100,000; 0 disables) is refused with ClosureFanoutExceeded. The write then lands in neither backend.
  • Public API. Each subpackage's __all__ is the public surface. Underscore-prefixed names that happen to be re-exported are internal.

Documentation

Design docs, the correctness argument and the Lean proofs live in the repository: https://github.com/averykhoo/graph-reachability-zanzibar-index. Start at docs/architecture/overview.md.

License

Apache-2.0. See LICENSE.

Metadata

Release files for zanzibar-index 0.0.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for zanzibar-index 0.0.3
File Size Uploaded
zanzibar_index-0.0.3.tar.gz 245.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for zanzibar-index 0.0.3
File Interpreter ABI Platform
zanzibar_index-0.0.3-py3-none-any.whl Python 3 none any Details

Total release size: 493.1 kB

Release files / zanzibar_index-0.0.3.tar.gz

Download URL zanzibar_index-0.0.3.tar.gz
Size 245.7 kB
Tags Source
SHA-256 checksum
How to use checksums
a3bc59b4a2e7ba2b1f3c3069fb4f293b7a45b85a3099c814ff18a275cf4f8b91
BLAKE2b-256 checksum
How to use checksums
b7978c15abad530cc4dc4946d2c6f4f0cdf9a37ea629666b7e749cd7e83a9a93
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 8, 2026.

Transparency log

Release files / zanzibar_index-0.0.3-py3-none-any.whl

Download URL zanzibar_index-0.0.3-py3-none-any.whl
Size 247.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
bab798a2fe41cd6aae0cb025491098f8f244467b36df43cdc0b78fc0fd3354bc
BLAKE2b-256 checksum
How to use checksums
a5361cc723c768707ec4f645828d3a9d9ada9f6b84bfc7f007d44eca66374582
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 8, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.0.3 This release

2 release files

0.0.2

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page