Skip to main content

RBACX

CI Docs Coverage

License: MIT

PyPI Python

Universal RBAC/ABAC/ReBAC policy engine for Python with a clean core, policy sets, a compact condition DSL (including time ops), and adapters for common web frameworks.

Features

  • Algorithms: deny-overrides (default), permit-overrides, first-applicable
  • Conditions: ==, !=, <, <=, >, >=, contains, in, hasAll, hasAny, startsWith, endsWith, before, after, between
  • Role shorthand: "roles": ["admin", "editor"] on any rule — sugar for hasAny on subject.roles
  • Explainability: decision, reason, rule_id/last_rule_id, obligations
  • Policy sets: combine multiple policies with the same algorithms
  • Hot reload: file/HTTP/S3 sources with ETag and a polling manager
  • Types & lint: mypy-friendly core, Ruff-ready
  • AI Policy Authoring (rbacx[ai]): generate, refine, and explain policies using any OpenAI-compatible LLM

Installation

pip install rbacx

Optional extras include adapters, metrics, YAML support, and AI policy authoring.

Quickstart

from rbacx import Action, Context, Guard, Subject, Resource

policy = {
    "algorithm": "deny-overrides",
    "rules": [
        {
            "id": "doc_read",
            "effect": "permit",
            "actions": ["read"],
            "resource": {"type": "doc", "attrs": {"visibility": ["public", "internal"]}},
            "roles": ["reader", "admin"],  # shorthand: hasAny on subject.roles
            # Or using the explicit condition syntax:
            # "condition": {"hasAny": [ {"attr": "subject.roles"}, ["reader", "admin"] ]},
            "obligations": [ {"type": "require_mfa"} ]
        },
        {"id": "doc_deny_archived", "effect": "deny", "actions": ["*"],
         "resource": {"type": "doc", "attrs": {"archived": True}}}
    ],
}

g = Guard(policy)

d = g.evaluate_sync(
    subject=Subject(id="u1", roles=["reader"]),
    action=Action("read"),
    resource=Resource(type="doc", id="42", attrs={"visibility": "public"}),
    context=Context(attrs={"mfa": True}),
)

assert d.allowed is True
assert d.effect == "permit"
print(d.reason, d.rule_id)  # "matched", "doc_read"

Decision schema

  • decision: "permit" or "deny"
  • reason: one of "matched", "explicit_deny", "action_mismatch", "condition_mismatch", "condition_type_mismatch", "resource_mismatch", "no_match", "obligation_failed"
  • rule_id and last_rule_id (both included for compatibility; last_rule_id is the matched rule id)
  • policy_id (present for policy sets; None for single policies)
  • obligations: list passed to the obligation checker (if a permit was gated)
  • (optional) challenge: present when an authentication/step-up is required (e.g., for MFA); may be used to return 401 with the appropriate challenge header

Policy sets

Default algorithm is:

from rbacx.core.policyset import decide as decide_policyset

policyset = {"algorithm":"deny-overrides", "policies":[ policy, {"rules":[...]} ]}
result = decide_policyset(policyset, {"subject":..., "action":"read", "resource":...})

If you want to test, try this:

from rbacx.core.policyset import decide as decide_policyset

# example set of policies
policyset = {
    "algorithm": "deny-overrides",
    "policies": [
        {"rules": [
            {"id": "allow_public_read", "effect": "permit", "actions": ["read"],
             "resource": {"type": "doc", "attrs": {"visibility": ["public"]}}}
        ]},
        {"rules": [
            {"id": "deny_archived", "effect": "deny", "actions": ["*"],
             "resource": {"type": "doc", "attrs": {"archived": True}}}
        ]},
    ],
}

# example request
req = {
    "subject": {"id": "u1", "roles": ["reader"]},
    "action": "read",
    "resource": {"type": "doc", "id": "42", "attrs": {"visibility": "public", "archived": False}},  # can try: would be `deny` if archived `True`
    "context": {},
}

res = decide_policyset(policyset, req)
print(res.get("decision", res))  # -> "permit"

Hot reloading

Default algorithm is:

from rbacx import Guard, HotReloader
from rbacx.store import FilePolicySource

guard = Guard(policy={})
mgr = HotReloader(guard, FilePolicySource("policy.json"), initial_load=...)
mgr.check_and_reload()        # initial load
mgr.start(10)  # background polling thread

If you want to test, try this:

⚠️ Important: this example creates a file on disk. You also can rewrite it with TempFile (tempfile.NamedTemporaryFile)

import json
import time
from rbacx import Action, Context, Guard, HotReloader, Resource, Subject
from rbacx.store import FilePolicySource

# create a tiny policy file next to the script
policy_path = "policy.json"
json.dump({
    "algorithm": "deny-overrides",
    "rules": [{
        "id": "allow_public_read", "effect": "permit", "actions": ["read"],
        "resource": {"type": "doc", "attrs": {"visibility": ["public"]}}
    }]
}, open(policy_path, "w", encoding="utf-8"))

guard = Guard({})
mgr = HotReloader(guard, FilePolicySource(policy_path), initial_load=True)
mgr.check_and_reload()  # initial load

print(guard.evaluate_sync(
    subject=Subject(id="u1", roles=["reader"]),
    action=Action("read"),
    resource=Resource(type="doc", id="1", attrs={"visibility": "public"}),
    context=Context(),
).effect)  # -> "permit"

# update policy and wait 3 second for reload
json.dump({
    "algorithm": "deny-overrides",
    "rules": [{"id": "deny_all", "effect": "deny", "actions": ["*"], "resource": {"type": "doc"}}]
}, open(policy_path, "w", encoding="utf-8"))
mgr.start(3)  # starting polling
time.sleep(3)

print(guard.evaluate_sync(
    subject=Subject(id="u1", roles=["reader"]),
    action=Action("read"),
    resource=Resource(type="doc", id="1", attrs={"visibility": "public"}),
    context=Context(),
).effect)  # -> "deny"

Quick links

Packaging

  • We ship py.typed so type checkers pick up annotations.
  • Standard PyPA flow: python -m build, then twine upload to (Test)PyPI.

License

MIT

Download files

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

Source Distribution

rbacx-1.18.0.tar.gz (92.9 kB view details)

Uploaded Source

Built Distribution

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

rbacx-1.18.0-py3-none-any.whl (115.0 kB view details)

Uploaded Python 3

File details

Details for the file rbacx-1.18.0.tar.gz.

File metadata

  • Download URL: rbacx-1.18.0.tar.gz
  • Upload date:
  • Size: 92.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rbacx-1.18.0.tar.gz
Algorithm Hash digest
SHA256 e45232ee9b3328a34819b8869c8aeb18e7d9e1d5a93f370a2ba762435832e1aa
MD5 cdb637fe074c261fc74c541e276bf87c
BLAKE2b-256 b8cc05e7b32cd0d060c40c846577eccb43972b6044ca8f1a1e6239af3608bf64

See more details on using hashes here.

Provenance

The following attestation bundles were made for rbacx-1.18.0.tar.gz:

Publisher: release.yml on Cheater121/rbacx

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rbacx-1.18.0-py3-none-any.whl.

File metadata

  • Download URL: rbacx-1.18.0-py3-none-any.whl
  • Upload date:
  • Size: 115.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rbacx-1.18.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9cf251ea3f02f0ae8e3c8337c7ab05d1a2da9be86047f4a3d3eece86357f5ec1
MD5 55e1480ff30c897fa2b2593a32214be8
BLAKE2b-256 da905b53bd15e7f8dfb8a70add067b949bf6d2611581b07f962bf0190a9ac615

See more details on using hashes here.

Provenance

The following attestation bundles were made for rbacx-1.18.0-py3-none-any.whl:

Publisher: release.yml on Cheater121/rbacx

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

1.18.0 This release

2 files

1.17.0

2 files

1.16.1

2 files

1.16.0

2 files

1.15.0

2 files

1.14.0

2 files

1.13.0

2 files

1.12.1

2 files

1.12.0

2 files

1.11.0

2 files

1.10.0

2 files

1.9.5

2 files

1.9.4

2 files

1.9.3

2 files

1.9.2

2 files

1.9.1

2 files

1.9.0

2 files

1.8.1

2 files

1.8.0

2 files

1.7.1

2 files

1.7.0

2 files

1.6.0

2 files

1.5.0

2 files

1.4.0

2 files

1.3.0

2 files

1.2.0

2 files

1.1.0

2 files

1.0.0

2 files

0.9.0

2 files

0.8.2

2 files

0.8.1

2 files

0.8.0

2 files

0.7.0

2 files

0.6.0

2 files

0.5.2

2 files

0.5.1

2 files

0.5.0

2 files

0.4.3

2 files

0.4.2

2 files

0.4.1

2 files

0.4.0

2 files

0.3.2

2 files

0.3.1

2 files

0.3.0

2 files

0.2.1

2 files

0.2.0

2 files

0.1.1

2 files

0.1.0

2 files

Supported by

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