Skip to content

release: /keys/mine order_id second factor (paywall bypass fix) - #26

Merged
hrco merged 17 commits into
releasefrom
main
Jul 1, 2026
Merged

release: /keys/mine order_id second factor (paywall bypass fix)#26
hrco merged 17 commits into
releasefrom
main

Conversation

@hrco

@hrco hrco commented Jul 1, 2026

Copy link
Copy Markdown
Owner

Promotes mainrelease to deploy the /keys/mine paywall-bypass fix (PR #25).

What ships

  • /keys/mine now requires {email, order_id} — email alone is no longer authorization. Order id (from the LemonSqueezy webhook) is the second factor, compared with hmac.compare_digest. Unknown email and wrong order_id both return an identical 404 (no oracle).
  • webhook_ls persists the LemonSqueezy order id (attrs.order_id → fallback data.id) idempotently on first key issuance.

Safety

  • 18 tests pass (test_key_provisioning.py + test_http_server_security.py).
  • Runtime state (issued_keys.json, etc.) is untracked under XBRIDGE_DB_PATH — survives the git reset --hard deploy. Zero keys issued to date, so no migration needed.
  • No secrets touched.

Deploy gate

Merging this triggers deploy-release.yml, which parks at the production environment approval gate (reviewer: hrco). Deploy only proceeds on founder approval.

Closes the bypass tracked in the automated security review.

Summary by CodeRabbit

  • New Features

    • Self-serve key retrieval now requires both an email address and an order ID.
  • Bug Fixes

    • Key lookup is now more secure and consistent, returning no key unless the submitted order ID matches the one on record.
    • Webhook processing now preserves order IDs with issued keys, improving retrieval reliability.

hrco and others added 2 commits July 1, 2026 14:38
/keys/mine returned a purchaser's paid signed license key given only
their email, which is not a secret. Anyone who knew a buyer's email
could retrieve their paid key.

webhook_ls now persists the LemonSqueezy order_id alongside the issued
key (idempotent, no overwrite on repeat webhooks). keys_mine now
requires both email and order_id, comparing the submitted order_id to
the stored one with hmac.compare_digest, and returns the same 404 for
an unknown email or a mismatched order_id so the response doesn't leak
which one was wrong. Missing/blank order_id returns 400.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@hrco, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 41 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 8b94fa7b-0aa2-4800-a863-66d01959b7f0

📥 Commits

Reviewing files that changed from the base of the PR and between 45fc4dc and 734354c.

📒 Files selected for processing (23)
  • .github/workflows/docker.yml
  • CLAUDE.md
  • README.md
  • docker-compose.yml
  • docs/UPDATE-PLAN.md
  • docs/superpowers/plans/2026-03-30-vps-migration.md
  • docs/wiki/Home.md
  • docs/wiki/Setup.md
  • docs/xai-delta-2026-07.md
  • posts/day-02-march-19/post-1100-antiAI.md
  • posts/day-02-march-19/post-1300-thread-pumpfun1b.md
  • posts/day-02-march-19/post-2100-galaxybrain.md
  • posts/day-02-march-19/post-2300-fairnessstack.md
  • server.json
  • site/assets/combot-announcements.md
  • site/assets/combot-moderation-setup.md
  • site/assets/meme-captions.md
  • site/assets/tweet-thread.md
  • tests/test_core.py
  • tests/test_image_tools.py
  • tests/test_key_provisioning.py
  • xbridge_mcp/http_server.py
  • xbridge_mcp/server.py
📝 Walkthrough

Walkthrough

The webhook handler now captures and persists an order_id for each issued key. The /keys/mine endpoint requires a matching order_id alongside email, using constant-time comparison against the stored value, rejecting mismatches with the existing "No key found" response. Tests are updated accordingly.

Changes

Order ID verification for key retrieval

Layer / File(s) Summary
Persist order_id during webhook processing
xbridge_mcp/http_server.py
webhook_ls derives order_id from webhook attributes (falling back to payload id) and stores it in the issued key record.
Enforce order_id validation on /keys/mine
xbridge_mcp/http_server.py
/keys/mine requires a non-empty order_id, rate-limits by email, loads the stored entry, and compares submitted vs. stored order_id via hmac.compare_digest, returning "No key found" on mismatch. Docstring updated.
Test coverage for order_id-based retrieval
tests/test_key_provisioning.py
Test helper and retrieval tests updated to send order_id in webhook payloads and /keys/mine requests, covering unknown/invalid email, wrong, missing, and blank order id cases.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Buyer
  participant KeysMineEndpoint
  participant IssuedKeysStore

  Buyer->>KeysMineEndpoint: POST /keys/mine (email, order_id)
  KeysMineEndpoint->>KeysMineEndpoint: validate order_id present
  KeysMineEndpoint->>IssuedKeysStore: load entry for email
  IssuedKeysStore-->>KeysMineEndpoint: stored entry (order_id)
  KeysMineEndpoint->>KeysMineEndpoint: hmac.compare_digest(submitted, stored)
  KeysMineEndpoint-->>Buyer: signed key or "No key found" 404
Loading

Poem

A rabbit hops with order slip in paw,
No key shall pass without this extra law!
hmac checks with steady, watchful eye,
Mismatched IDs get a soft "goodbye" 🐇
Now every buyer's key is snug and tight,
Safe in burrows, locked up right! 🔑

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main security change to /keys/mine and mentions the paywall bypass fix.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch main

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@xbridge_mcp/http_server.py`:
- Around line 256-258: In http_server.py, the order_id check in the handler that
uses stored_order_id and submitted_order_id can raise TypeError when either
value contains non-ASCII characters because hmac.compare_digest only accepts
ASCII-safe inputs. Update the comparison logic to normalize both values to
ASCII-safe bytes (or otherwise reject non-ASCII order_id values before
comparison) and keep the not_found path for mismatches. Use the existing
stored_order_id/submitted_order_id flow near compare_digest so the fix stays
localized.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 561ebfca-e121-4a59-a21c-f1cf2e46ba63

📥 Commits

Reviewing files that changed from the base of the PR and between 3819638 and 45fc4dc.

📒 Files selected for processing (2)
  • tests/test_key_provisioning.py
  • xbridge_mcp/http_server.py

Comment thread xbridge_mcp/http_server.py
hrco and others added 4 commits July 1, 2026 18:26
The docker.yml pipeline authenticated as nexuswedge but pushed to the
hrco/ namespace, which Docker Hub denied (surfacing as insufficient_scope).
It has failed on every main push since 2026-06-19; the image never published.

Point the image name at the account that actually owns the token. Only the
Docker Hub image references change — the GitHub repo URLs and the
io.github.hrco MCP registry name (tied to GitHub OIDC) stay as-is.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Research-only report diffing xBridge against the live xAI docs MCP
(docs.x.ai/api/mcp) as of 2026-07-01. Feeds the Safe-refresh workstream.

Key findings: grok-4.20 family context is 1M not 2M and mispriced;
grok-build-0.1 missing; DEFAULT_MODEL grok-4-1-fast is on the May-15-2026
retirement list (liveness needs a live probe); video polling ignores the
'failed' status (server.py:326-355); service_tier + cost_in_usd_ticks absent.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
hmac.compare_digest raises TypeError on non-ASCII str input, so a
crafted non-ASCII order_id on /keys/mine crashed with a 500 instead
of the intended 404. Flagged by CodeRabbit on PR #26.
hrco added 5 commits July 1, 2026 20:29
The poll loop in make_video_request only handled "done" and "expired"
statuses. A "failed" status (or any poll response carrying an "error"
key) fell through silently and kept polling until the full 600s
VIDEO_POLL_TIMEOUT elapsed, then raised a generic TimeoutError -
discarding the API's actual error.code/error.message and wasting 10
minutes before the caller found out anything was wrong.
Per the xAI API delta report (docs/xai-delta-2026-07.md, issue #18):
grok-4.20-* was documented as 2M context / $2.00-$6.00 per 1M tokens;
xAI's current docs list the whole family at 1M / $1.25-$2.50 flat.
Also adds grok-build-0.1 (the coding-focused replacement for the
retired grok-code-fast-1) to AVAILABLE_MODELS, so it's picked up by
every tool schema's model enum automatically.

Legacy slugs (grok-4, grok-4-1-fast, grok-3-fast/mini, grok-2 family)
are kept in AVAILABLE_MODELS for backward compatibility but their
handle_grok_models text is now marked as last-known/unconfirmed,
since none of them appear in xAI's current pricing docs post the
May-15-2026 model retirement.

Additive/corrective only - no tool contract or enum removals.
Threads an optional service_tier ("default"/"priority") parameter
through make_grok_request into the xAI request payload for
grok-chat, grok-web-search, and grok-x-search - the three tools
directly backed by make_grok_request's chat-completions-style
payload. Priority processing is opportunistic (2x price premium,
billed only if the response confirms priority was actually used),
per xAI's priority-processing docs.

Also adds extract_cost_footer(), which surfaces the response's
actual service_tier and usage.cost_in_usd_ticks (converted to USD,
1 USD = 1e10 ticks) as a short footer appended to the tool's text
response - the caller now sees exactly what was billed without any
change to CallToolResult's shape.

grok-session-chat and the grok-chain-* tools also go through
make_grok_request but via session_manager.py/tool_chains.py -
left out of this pass to keep the diff scoped; service_tier isn't
supported for image/video generation or Batch per xAI docs, so
those tool schemas are untouched.

Additive only - no existing tool contract/schema fields changed.

@hrco hrco left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📦 ROAST: release promotion (main → release) (#26)

The good: Security fix for /keys/mine. Order_id second factor closes the paywall bypass. Good work.

The roast:

20 files changed. 614 additions. This release PR ships a security fix alongside 166 lines of docs/UPDATE-PLAN.md, 361 lines of docs/xai-delta-2026-07.md, and — I am not making this up — grammar fixes in meme captions (site/assets/meme-captions.md). Your release promotion PR is doubling as a content strategy session and a VPS migration plan. This is the PR equivalent of "while I'm in the neighborhood, let me also rearrange the garage and write a novel."

"Zero keys issued to date, so no migration needed." — The security fix for a paywall nobody has ever paid. You built a fortress to guard an empty treasury, complete with HMAC-based second-factor authentication. I respect the preparedness. But maybe spend that energy on, you know, selling a single key first?

Also, this PR is from mainrelease and still shows as OPEN. Either merge it or close it. Stale release PRs are the GitHub equivalent of a blinking "12:00" on a VCR.

Verdict: Right thing, wrong scope. A release should ship a release, not rearrange the entire repo.

hrco added 4 commits July 1, 2026 21:03
fix: raise immediately on failed video generation status
feat: add service_tier priority processing + cost tracking (#20)
fix: encode order_id to bytes before hmac.compare_digest
fix: correct grok-4.20 model info, add grok-build-0.1 (#18)
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 1, 2026
hrco added 2 commits July 1, 2026 21:05
Per the xAI API delta report (docs/xai-delta-2026-07.md, issue #19):
xAI's current docs list grok-imagine-image-quality and
grok-imagine-video-1.5 as the current top-tier Imagine models
(replacing the retired grok-imagine-image-pro), plus a 1080p video
resolution that's exclusive to grok-imagine-video-1.5 for
image-to-video generation.

- IMAGE_MODELS / VIDEO_MODELS gain the two new model slugs.
- VIDEO_RESOLUTIONS gains "1080p".
- grok-video-generate's schema gains a "model" field (it previously
  had no way to select a video model at all - always hardcoded to
  DEFAULT_VIDEO_MODEL). handle_video_generate now threads the
  selected model through to make_video_request.
- Explicit gating: requesting 1080p with any model/mode other than
  grok-imagine-video-1.5 + image-to-video is rejected before hitting
  the API, with a clear error - avoids paying for a request xAI
  would 400 on.
- handle_image_models / grok-image-generate description text updated
  with the new models' pricing and capabilities.

grok-2-image-1212 kept (no doc presence, retirement status
unconfirmed - flagged as unverified, not removed).

Additive/corrective only - existing model slugs and default
behavior unchanged; the only new required-input surface is the
optional "model" field on grok-video-generate.
feat: add grok-imagine-image-quality, video-1.5, gated 1080p (#19)
@hrco
hrco merged commit e7ee108 into release Jul 1, 2026
2 checks passed
@hrco

hrco commented Jul 1, 2026

Copy link
Copy Markdown
Owner Author

ok

@hrco
hrco deleted the main branch July 1, 2026 19:10
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