Spaces:
Running on Zero
Running on Zero
| """Self-check for the API-token guard. No torch, no gradio, instant. | |
| python test_auth.py | |
| This is the only thing standing between the open internet and free inference on | |
| your Space, so it gets a test. It reads the real `API_TOKEN` literal and the | |
| real guard condition out of `app.py`, rather than a copy that could drift. | |
| Regression covered: an earlier edit wrote | |
| `API_TOKEN = os.environ.get("<the-token>")`, passing the token as the *variable | |
| name*. That returns None, which broke every real request AND let a `null` token | |
| authenticate, since `None != None` is false. | |
| """ | |
| import ast | |
| import hmac | |
| SRC = "app.py" | |
| def api_token(): | |
| """The API_TOKEN literal from app.py. Fails loudly if it isn't a literal.""" | |
| tree = ast.parse(open(SRC, encoding="utf-8").read()) | |
| for n in tree.body: | |
| if isinstance(n, ast.Assign) and any( | |
| getattr(t, "id", "") == "API_TOKEN" for t in n.targets | |
| ): | |
| if not isinstance(n.value, ast.Constant) or not isinstance( | |
| n.value.value, str | |
| ): | |
| raise AssertionError( | |
| "API_TOKEN must be a plain string literal — an " | |
| "os.environ.get() with no default silently yields None, " | |
| "which breaks auth open for a null token." | |
| ) | |
| return n.value.value | |
| raise AssertionError("no API_TOKEN assignment found in app.py") | |
| def main(): | |
| token = api_token() | |
| assert len(token) >= 32, f"API_TOKEN is only {len(token)} chars — too short" | |
| print(f"API_TOKEN is a {len(token)}-char literal ✓") | |
| def guard(t): | |
| """Verbatim condition from detect().""" | |
| return isinstance(t, str) and hmac.compare_digest(t, token) | |
| cases = [ | |
| (token, True, "correct token"), | |
| (None, False, "null token (the historical bypass)"), | |
| ("", False, "empty string"), | |
| ("wrong-token", False, "wrong token"), | |
| (token[:-1], False, "token missing last char"), | |
| (token + "x", False, "token with extra char"), | |
| (token.upper(), False, "case-flipped token"), | |
| (12345, False, "numeric token"), | |
| ([token], False, "token wrapped in a list"), | |
| ({"t": token}, False, "token as an object"), | |
| ] | |
| bad = 0 | |
| for tok, want, note in cases: | |
| got = guard(tok) | |
| ok = got == want | |
| bad += not ok | |
| print(f" [{'ok ' if ok else 'FAIL'}] {note:<38} accepted={got}") | |
| if bad: | |
| raise SystemExit(f"\n{bad} auth case(s) FAILED") | |
| print("\nauth guard self-check OK") | |
| if __name__ == "__main__": | |
| main() | |