Skip to content

fix(billing): B5 sandbox-IAP blocker + review hardening (post-merge)#273

Merged
oratis merged 1 commit into
mainfrom
harden
Jul 22, 2026
Merged

fix(billing): B5 sandbox-IAP blocker + review hardening (post-merge)#273
oratis merged 1 commit into
mainfrom
harden

Conversation

@oratis

@oratis oratis commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Post-merge hardening from the batch review of the accounts/billing epic (PRs #259#272). One blocker surfaced in review plus three low-risk fixes. typecheck + full test suite (1089 pass / 0 fail) + build all green.

⛔️ Blocker — StoreKit sandbox credits real money (#265)

verifyAppleJWS was already sound (real ES256 + x5c chain to a pinned Apple Root G3), but validateTransaction parsed environment and never enforced it. Sandbox transactions are Apple-signed with the same chain and cost the buyer $0 → a free sandbox tester Apple ID could mint real credit by POSTing a sandbox JWS to prod /api/billing/iap.
Fix: the cloud IAP endpoint now rejects any non-Production transaction (sandbox_rejected); LISA_IAP_ALLOW_SANDBOX=1 re-opts a non-prod/staging deploy back in. Local/mac dev is unaffected.

Optimizations

Deferred to follow-up (tracked separately)

Firestore turn-lease heartbeat (#272), fail-closed global cap (#267), request body caps (#264/#266/#260), SIWA nonce (#261/#269), async scrypt + /register rate-limit (#260), and the pre-existing cross-user moodBus/SSE broadcast (#262) — the top item to close before multi-user launch.

🤖 Generated with Claude Code

Post-merge hardening from the batch review of the accounts/billing epic
(PRs #259#272). One blocker found in review + three low-risk fixes:

- [BLOCKER, #265] Enforce StoreKit `environment` on the cloud IAP endpoint.
  Sandbox transactions are Apple-signed with the SAME cert chain as
  Production and cost the buyer $0, so /api/billing/iap accepting them =
  free real credit for anyone with a sandbox tester Apple ID. The endpoint
  now rejects any non-Production transaction in the cloud edition
  (LISA_IAP_ALLOW_SANDBOX=1 re-opts a non-prod/staging deploy back in).
  The JWS signature verification itself was already sound.
- [#263] costMicroUSD: clamp a non-finite token count (NaN/Infinity) -> 0,
  so it can't poison the usage ledger, balance.json, or the budget breaker.
- [#263] GET /api/billing/usage: on cloud, a shared-demo-token caller (no
  account) no longer reads the GLOBAL home's aggregate usage; mirrors /quota.
- [#260/#269] Session cookies gain the Secure attribute on the cloud (HTTPS)
  edition (HttpOnly + SameSite=Strict already present); local/mac http path
  is unchanged.

typecheck + full test suite (1089 pass / 0 fail) + build all green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@oratis
oratis merged commit 6923194 into main Jul 22, 2026
1 check passed
@oratis
oratis deleted the harden branch July 22, 2026 09:16
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