Skip to main content

Track A (FERPA/COPPA) application-layer authorization resolver (PDP+PEP) — Python sibling of @superbuilders/authz for bridge's Python tier.

Project description

superbuilders-authz (Python)

Part of the superbuilders/timeback-authz monorepo (python/). It shares the cross-language conformance vectors in ../conformance/vectors.json with the TS package — policy changes must update the vectors and pass both suites.

Track A (FERPA/COPPA) application-layer authorization resolver — the Python sibling of @super-oar/authz, built for bridge's Python tier (TA-PEP-03 / TA-PEP-10, WS3 shadow-authz seam). Faithful port: same gate order, same verdicts, same reasons, same shadow-log shape — both languages' [authz-shadow] logs aggregate identically on the deny-storm dashboards.

  • Pure stdlib, no DB required, no native deps → runs anywhere (Lambda, containers, cron workers).
  • Application-layer first. decide() returns a decision + a filter spec and works with no database — because most consumers read student data over REST / MySQL / DynamoDB, not a Postgres the package can attach to. RLS/GUC enforcement is a later phase and is intentionally not in this package.
  • Decision core is swappable (ADR-11): SQL capability merge now → Cedar/OpenFGA later, same surface.
  • Import package: superbuilders_authz. Python >= 3.11 (bridge pins 3.12).

API

  • await decide(DecideInput(...), deps) → Decision(verdict, reason, filter?, mask_fields?) — the core. Ordered gates (tenant → role active+window → read-only → capability+scope → sensitivity → consent → elevation); first-fail-denies; dual_read/shadow downgrade to would_* (deploying denies nobody). Omit resource for a list read → returns a filter (allowed org/user/class ids) to constrain your query.
  • Shadow seam (the WS3 deliverable): shadow_compare(...) runs decide() beside your existing check and logs the comparison. Never raises, never changes the request outcome (returns None on any error). build_coarse_principal(...) / coarse_role_capabilities(role) build an INTERIM principal from the coarse OneRoster role until WS5 seeds role_capabilities (fail-closed on unknown roles).
  • Guards (raise AuthzError (403) in enforce, return would_* in shadow): authorize, assert_parent_child_access, assert_teacher_class_access, assert_school_access, assert_can_read (object-level BOLA), require_admin / require_teacher_or_admin / require_parent_or_guardian.
  • Capability merge: merge_capabilities (role_capabilities ⊕ user_capability_grants, deny-precedence, NULL tier → most-restrictive, M2M client_app keys).
  • Consent: classify_consent_boundary, method_satisfies_basis / is_vpc (COPPA under-13 VPC split), evaluate_consent / mask_fields_for (opt-out / Sec-GPC hard deny; special_pops + McKinney-Vento + directory-opt-out field masking).
  • Escalation: can_grant — the TA-PEP-15 no-escalation invariant (roles.manage precondition, in-set at equal-or-lesser scope, dual-control on compliance_gated).

You inject your store + identity (the per-app glue)

from superbuilders_authz import DecideDeps, ScopeResult

async def resolve_scope(scope, subject) -> ScopeResult:
    ...  # your enrollments / guardianship_links / orgs query -> ScopeResult

async def consent_ok(child_sourced_id: str, purpose: str, tenant_id: str) -> bool:
    ...  # your consent_records lookup -> bool

deps = DecideDeps(resolve_scope=resolve_scope, consent_ok=consent_ok)
  • Build Principal from your already-verified identity (Cognito JWT / Clerk / Supabase). Never trust an IdP group/claim/metadata for capabilities — resolve them from the authoritative store. Use system=True for non-HTTP workers (cron/sync), read_only=True for read-only service accounts.
  • Postgres consumers can use the bundled adapter instead of hand-writing the glue: create_scope_resolver(q) / create_consent_checker(q) over any driver wrapped to satisfy the AuthzQuery protocol (asyncpg/psycopg/supabase).

Shadow usage (WS3)

from superbuilders_authz import build_coarse_principal, shadow_compare, ResourceRef, ScopeResult

subject = build_coarse_principal(user_sourced_id="T1", role="teacher", org_sourced_id="S1")
await shadow_compare(
    subject=subject,
    action="academics.read",
    resource=ResourceRef(kind="student", owner_sourced_id=student_id, tenant_id=subject.tenant_id),
    scope=ScopeResult(user_sourced_ids=my_already_resolved_student_ids),  # relationship truth the app already has
    current_allowed=existing_check_passed,  # what your current authorization decided
    label="lalilo.rostered_students",       # stable call-site label for the dashboards
)

Emits (identical to the TS package — same prefix, same field names, same order):

[authz-shadow] {"label":"lalilo.rostered_students","action":"academics.read","role":"teacher","owner":"stu1","current":"allow","would":"would_allow","agree":true,"reason":"ok","maskFields":[]}

Test / build

python3 -m venv .venv
.venv/bin/pip install -e '.[dev]'
.venv/bin/pytest   # capability merge + RC fail-closed regressions + shadow would_* downgrade + log-shape parity

Not covered (mirrors the TS package)

RLS / GUC enforcement, the signed impersonation grant, break-glass MFA activation, and the biometric short-lived VPC capability token are app/infra-side deliverables, not in this package.

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

superbuilders_authz-0.0.4.tar.gz (30.5 kB view details)

Uploaded Source

Built Distribution

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

superbuilders_authz-0.0.4-py3-none-any.whl (25.8 kB view details)

Uploaded Python 3

File details

Details for the file superbuilders_authz-0.0.4.tar.gz.

File metadata

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

File hashes

Hashes for superbuilders_authz-0.0.4.tar.gz
Algorithm Hash digest
SHA256 cb3dca5ec66749597ac818af3c122abe72f7da9979d48717312b3854147fc8ef
MD5 b32c3e22f6823098dba935eb0815b0f3
BLAKE2b-256 22c403d3929f73384a51045fea7059848b3fbba2b04c9ccc10ce7675f16b6314

See more details on using hashes here.

Provenance

The following attestation bundles were made for superbuilders_authz-0.0.4.tar.gz:

Publisher: publish-python.yml on superbuilders/timeback-authz

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

File details

Details for the file superbuilders_authz-0.0.4-py3-none-any.whl.

File metadata

File hashes

Hashes for superbuilders_authz-0.0.4-py3-none-any.whl
Algorithm Hash digest
SHA256 3ad2dc39363bd938eec73cda85ece5b1724ee374981f8deff8d404b78a21dcce
MD5 94d17e5c99b1553acee4399923243a82
BLAKE2b-256 a4cac79b455ddb80980211b6801281b317086d70bc870f943067bbae54d34cfa

See more details on using hashes here.

Provenance

The following attestation bundles were made for superbuilders_authz-0.0.4-py3-none-any.whl:

Publisher: publish-python.yml on superbuilders/timeback-authz

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

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