Spaces:
Running on Zero
Running on Zero
| """Beta-gate access policy — who may use the dev Space and see the Review tab. | |
| Separate from ``auth.py`` (identity resolution) on purpose: this module owns the | |
| *policy* (allowlist / owner / enforcement), reusing ``resolve_user`` for the | |
| *identity*. The whole module is inert unless ``BETA_GATE_ENABLED`` is set, so it | |
| is a no-op on prod and local. | |
| """ | |
| from __future__ import annotations | |
| from typing import Any | |
| import gradio as gr | |
| from config import BETA_ALLOWLIST, BETA_GATE_ENABLED, REVIEW_TAB_OWNERS | |
| from src.sessions.auth import resolve_user | |
| # Shown in the gate overlay to a signed-in user who isn't on the allowlist. | |
| # Polite "no access / request access" — acknowledges restricted access. | |
| # TODO: replace <contact> with the real request-access link/handle at deploy time. | |
| BETA_REJECT_MESSAGE = ( | |
| "### You don't have access to this space\n" | |
| "This is a restricted beta. Your Hugging Face account isn't on the access " | |
| "list yet — [request access](mailto:ahmed.ibrahim8165@gmail.com) and we'll " | |
| "add you." | |
| ) | |
| # Raised at compute entry points for a non-allowlisted (incl. anonymous/API) caller. | |
| _ENFORCE_MESSAGE = ( | |
| "This Space is in restricted beta. Please sign in with an approved " | |
| "Hugging Face account to use it." | |
| ) | |
| def _username(profile: Any | None) -> str | None: | |
| """Resolved, normalized (lowercase) HF username, or None if unauthenticated.""" | |
| user = resolve_user(profile) | |
| return user.username.lower() if user else None | |
| def is_review_owner(profile: Any | None) -> bool: | |
| """True if the signed-in user is an owner who may see the Review tab.""" | |
| name = _username(profile) | |
| return bool(name and name in REVIEW_TAB_OWNERS) | |
| def is_beta_allowed(profile: Any | None) -> bool: | |
| """True if the caller may use the app. | |
| When the gate is disabled (prod/local) everyone is allowed. When enabled, | |
| anonymous callers are blocked and signed-in callers must be on the allowlist | |
| (owners are implicitly allowed so they can never self-lock-out). | |
| """ | |
| if not BETA_GATE_ENABLED: | |
| return True | |
| name = _username(profile) | |
| if not name: | |
| return False | |
| return name in BETA_ALLOWLIST or name in REVIEW_TAB_OWNERS | |
| def enforce_beta_access(profile: Any | None) -> None: | |
| """Raise ``gr.Error`` if the gate is on and the caller isn't allowlisted. | |
| Server-side counterpart to the UI overlay: rejects scripted/API callers | |
| (``profile`` is None for them) and signed-in-but-not-allowlisted users. | |
| """ | |
| if not is_beta_allowed(profile): | |
| raise gr.Error(_ENFORCE_MESSAGE) | |