Skip to content

Production API W3+W5+W4-code: keys, trial, limits, isolation, Stripe core - #22

Merged
nrupala merged 1 commit into
mainfrom
build/production-api-w3w5
Oct 15, 2026
Merged

nrupala merged 1 commit into
mainfrom
build/production-api-w3w5

Conversation

@nrupala

@nrupala nrupala commented Oct 15, 2026

Copy link
Copy Markdown
Owner

Path (b) production build, second checkpoint (plan: production-build-plan.md). Builds on PR #21 (Ed25519 CA + durable store). REST/MCP behavior changes are the point of this one: both interfaces now run ONE shared verify flow (verify_service.py) so trial, metering and isolation cannot drift.

W3 — access control + trial enforcement

  • API keys (axk_...): store keeps only the SHA-256 hash + label; plaintext shown once at creation (python -m store create-key). /verify and /check require a key (X-Api-Key or Bearer); identity IS the key hash — caller-supplied identity is rejected. /health, /revoked and the keys payload stay open (public CRL / key publication).
  • Trial (owner's policy): a key's first 10 cases return verdict + attempts with certificate: null and a trial summary; trial cases meter at zero. Trial exhausted + no balance -> 402 raised BEFORE the proof runs (proven by a counting-stub test). Positive balance -> paid path: meter, issue, record.
  • Balances: credit_grants (external_id UNIQUE -> idempotent grants); balance = grants - metered usage.
  • Rate limit 60/min per key (429), per-key proof concurrency gate 2, both env-configurable (limits.py).
  • MCP: identity bound to the server-provisioned key (AXIOMCODE_API_KEY via ensure_api_key; a store revocation survives restarts); tools take no identity parameter.
  • Hardening from PR Production API W1+W2: Ed25519 CA + durable store #21 review, all four: CA-fixed fields win over subject fields in issue(); verify_certificate rejects kid mismatch (unknown_kid); record_cert/revoke write state + audit in one transaction; audit chain v2 binds prev_hash | event_type | ts | payload (pre-production DB, no migration owed).

W5 — job isolation

  • Submission cap 256 KB (413), proof wall-clock timeout 600s (504) via worker thread with finally cleanup on every path. Documented limit: Python threads can't be killed — on timeout the response ships and the orphan dies against its removed project dir; hard process isolation is a deploy-time concern.

W4 code layer (no live Stripe calls)

  • stripe_billing.py: pack catalogue (starter 1000cr/$10, growth 5000/$50, scale 20000/$200), pure checkout-payload builder, thin fake-able client, webhook core — checkout.session.completed grants idempotently on the session id (session carries the key HASH only), charge.refunded reverses via a payment-intent link row, refund replays are no-ops, unknown refunds return unhandled for alerting. POST /billing/webhook answers 501 until the stripe package + STRIPE_WEBHOOK_SECRET exist at deploy.

Tests: services/api suite 40/40 locally (26 new). Full-repo local replication (this tree over main): ruff check + format clean (latest ruff), mypy . clean, root suite identical to the pre-change baseline (214 passed; the same 7 QR tests fail locally in both trees — missing segno in the local venv; CI installs it). certs.py intentionally untouched (repo version kept; the local prototype copy had drifted).

Not deployed. Remaining for launch: Stripe sandbox products + webhook wiring (W4 live half), hosting (W6, owner's call), public flip + gate (W7).

@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying axiomcode-site with  Cloudflare Pages  Cloudflare Pages

Latest commit: ec37e73
Status: ✅  Deploy successful!
Preview URL: https://123299ab.axiomcode-site.pages.dev
Branch Preview URL: https://build-production-api-w3w5.axiomcode-site.pages.dev

View logs

@nrupala
nrupala merged commit 17935d3 into main Oct 15, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant