Files
yvgude--lean-ctx/scripts/billing_entitlements_stub.py
wehub-resource-sync 26382a7ac6
CI / Clippy (push) Failing after 15m13s
CI / Test (ubuntu-latest) (push) Failing after 16m1s
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Build (no embeddings / no ORT) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Cookbook (Node) (push) Has been cancelled
CI / Pi Extension (Node) (push) Has been cancelled
CI / Rust SDK (lean-ctx-client) (push) Has been cancelled
CI / Embed SDK (lean-ctx-sdk) (push) Has been cancelled
CI / Python SDK (leanctx) (push) Has been cancelled
CI / Hermes Plugin (Python) (push) Has been cancelled
CI / SDK Conformance Matrix (push) Has been cancelled
CI / Coverage (push) Has been cancelled
CI / cargo-deny (push) Has been cancelled
CI / Adversarial Safety (push) Has been cancelled
CI / Benchmarks (push) Has been cancelled
CI / Output-Quality Gate (eval A/B) (push) Has been cancelled
CI / Documentation (push) Has been cancelled
CI / CI Green (push) Has been cancelled
JetBrains Plugin / Actionlint (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (rust) (push) Has been cancelled
JetBrains Plugin / Validation (push) Has been cancelled
JetBrains Plugin / Build (push) Has been cancelled
JetBrains Plugin / Test (push) Has been cancelled
Security Check / Security Scan (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:35:30 +08:00

68 lines
2.5 KiB
Python
Executable File

#!/usr/bin/env python3
"""Minimal stand-in for the private billing plane, for local E2E only.
The open backend (`billing_edge.rs`) learns an account's paid plan by calling
``GET {LEANCTX_CLOUD_BILLING_URL}/api/billing/entitlements/{user_id}`` with the
shared ``X-Internal-Key`` header, and reads only the ``plan`` field. This stub
answers exactly that contract so `scripts/cloud_pro_features_e2e.sh` can exercise
both the Pro path and the Free `402` gate without the real, private service.
It is deliberately tiny and dependency-free (Python stdlib). The Pro account's
UUID is read from ``PRO_UID_FILE`` on every request, so the harness can register
users *after* the stub is up and just drop the id into that file.
Env:
PORT bind port (default 18092)
INTERNAL_KEY expected X-Internal-Key (default "e2e-internal-key")
PRO_UID_FILE path to a file whose contents are the Pro account's UUID
"""
from __future__ import annotations
import json
import os
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
PORT = int(os.environ.get("PORT", "18092"))
INTERNAL_KEY = os.environ.get("INTERNAL_KEY", "e2e-internal-key")
PRO_UID_FILE = os.environ.get("PRO_UID_FILE", "")
PREFIX = "/api/billing/entitlements/"
def pro_uid() -> str:
try:
with open(PRO_UID_FILE, encoding="utf-8") as fh:
return fh.read().strip()
except OSError:
return ""
class Handler(BaseHTTPRequestHandler):
def _send(self, code: int, payload: dict) -> None:
body = json.dumps(payload).encode()
self.send_response(code)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(body)))
self.end_headers()
self.wfile.write(body)
def do_GET(self) -> None: # noqa: N802 (stdlib naming)
if not self.path.startswith(PREFIX):
self._send(404, {"error": "not found"})
return
if self.headers.get("X-Internal-Key") != INTERNAL_KEY:
self._send(403, {"error": "bad internal key"})
return
user_id = self.path[len(PREFIX):].strip("/")
plan = "pro" if user_id and user_id == pro_uid() else "free"
# Mirror the real plane's shape; the backend reads only `plan`.
self._send(200, {"plan": plan, "entitlements": {"cloud_sync": plan == "pro"}})
def log_message(self, *_args) -> None: # silence per-request logging
pass
if __name__ == "__main__":
ThreadingHTTPServer(("127.0.0.1", PORT), Handler).serve_forever()