Skip to content

fix(deploy): enhance API token handling and improve user feedback#475

Open
dynamo-pentester wants to merge 2 commits into
piyushdotcomm:mainfrom
dynamo-pentester:bug/vercel-master
Open

fix(deploy): enhance API token handling and improve user feedback#475
dynamo-pentester wants to merge 2 commits into
piyushdotcomm:mainfrom
dynamo-pentester:bug/vercel-master

Conversation

@dynamo-pentester

@dynamo-pentester dynamo-pentester commented Jun 5, 2026

Copy link
Copy Markdown

Summary

  • Removed the VERCEL_MASTER_TOKEN silent fallback in app/api/deploy/vercel/route.ts
  • The route now requires callers to supply their own userApiKey; missing or empty tokens return a clear 400
  • Added per-user rate limiting (5 deploys/min) to match the existing Netlify deploy route
  • Tightened the auth guard to check session?.user?.id instead of session?.user
  • Removed the "Use Editron Deployment" option from deploy-dialog.tsx since it relied on the master token fallback; the dialog now always prompts for a personal API token

Type of change

  • Bug fix

Related issue

Closes #449

Validation

  • npm run lint
  • npm test
  • npm run build

Manual verification:

  • Sent POST /api/deploy/vercel without userApiKey while authenticated — confirmed 400 with error message
  • Sent POST /api/deploy/vercel with userApiKey: "" and userApiKey: null — both correctly return 400
  • Sent a valid userApiKey — deployment proceeds normally
  • Confirmed deploy dialog no longer sends userApiKey: undefined to the route

Checklist

  • I kept this PR focused on one primary change
  • I updated documentation if behavior changed
  • I did not commit secrets, local logs, or scratch files
  • I am requesting review on the correct scope

Summary by CodeRabbit

  • New Features

    • Per-user deployment rate limiting (5 deploys/min) with clear retry feedback on limit hit.
    • Added "Visit Site" button and direct external link in post-deployment success UI.
  • Improvements

    • Deployments now require each user to provide their own provider API key; shared fallback removed.
    • Deployment form simplified to a single provider token input with provider-specific labeling and validation.
    • Deploy button disabled until a valid token is entered; clearer error handling and messages on failure.

@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@github-actions

github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

👋 Thanks for opening a PR, @dynamo-pentester!

Your PR has entered the 🚦 PR Review Pipeline.

Standard PR detected — your PR will follow the standard review pipeline.


What happens next

Stage Reviewer Checks
Stage 1 — Automated Validation 🤖 Bot DCO · Format · AI/Slop · Duplicate
Stage 2 — Human Review 👥 Maintainer Code + Quality Review
Stage 3 — PA / Maintainer Review 🔑 Project Admin Final Merge Decision

A pipeline status comment will appear below and update automatically as your PR progresses.


While you wait

  • Sign all commits (git commit -s)
  • Link your issue (Closes #123)
  • Use a feature branch (not main)
  • Avoid unrelated changes

This comment is posted only once.

@coderabbitai

coderabbitai Bot commented Jun 5, 2026

Copy link
Copy Markdown

Linter diff in the way? Review this PR in Change Stack to focus on meaningful changes and expand context only when needed.

Review Change Stack

Warning

Review limit reached

@dynamo-pentester, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 16 minutes and 3 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

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.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 9d0d37bc-afe0-4f33-9453-21a0b8b57ab2

📥 Commits

Reviewing files that changed from the base of the PR and between 2996b73 and 99ed963.

📒 Files selected for processing (2)
  • app/api/deploy/vercel/route.ts
  • modules/playground/components/deploy-dialog.tsx

Walkthrough

Backend deploy route now requires a trimmed user-supplied Vercel API key, enforces per-user rate limiting (5 deploys/min) with 429/Retry-After/X-RateLimit headers, and returns readyState on success. Frontend deploy dialog always collects and validates the user token, sends it as userApiKey, and updates the success UI and error handling.

Changes

Vercel Deploy Security Enforcement

Layer / File(s) Summary
Backend: Per-user rate limiting and API key enforcement
app/api/deploy/vercel/route.ts
Handler uses NextRequest, validates session.user.id, enforces per-user 5/min rate limit (429 + Retry-After + X-RateLimit-*), requires trimmed userApiKey (rejects missing/blank, no fallback to master token), formats Vercel payload (includes target: "production") and returns readyState in successful responses.
Frontend: User key state, validation, and deploy payload
modules/playground/components/deploy-dialog.tsx
Refactors state to a single userKey and providerLabel; flattenFileTree preserves file content; deploy validation requires userKey.trim() and shows provider-specific toast; always sends userApiKey: userKey.trim() with filtered files; response handling verifies data.url before setting deployedUrl and formats catch messages via instanceof Error.
Frontend: Dialog UI rendering and success state
modules/playground/components/deploy-dialog.tsx
Removes authentication-policy UI, adds provider-labeled password input for token, disables deploy button when isDeploying or !userKey.trim(), and renders deployedUrl as a styled external anchor plus a "Visit Site" button on success.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • piyushdotcomm/Editron#210: Adds per-user authentication gating and deploy rate limiting to app/api/deploy/netlify/route.ts with 429 handling and Retry-After headers.
  • piyushdotcomm/Editron#389: Modifies app/api/deploy/vercel/route.ts POST handler to use NextRequest, require session.user.id, and add per-user deploy rate limiting with 429 and rate-limit headers.

Suggested labels

bug, security, level:critical, type:bug, type:refactor, type:devops

Suggested reviewers

  • piyushdotcomm

Poem

🐰 I hopped in code to mend the key,

No master token roaming free.
Five quick hops, then pause a beat,
Each deploy now mindfully fleet.
Secure and neat—now go deploy with glee!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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
Title check ✅ Passed The title accurately and specifically summarizes the main changes—API token handling enforcement and user feedback improvements—reflecting the core intent of the PR.
Description check ✅ Passed The PR description follows the template structure with all required sections complete: clear summary, type of change marked, related issue linked, validation steps with checkboxes checked, and manual verification listed.
Linked Issues check ✅ Passed The PR successfully addresses issue #449: removes the VERCEL_MASTER_TOKEN fallback, requires explicit userApiKey with validation returning 400 on missing tokens, adds per-user rate limiting, and tightens auth checks to session?.user?.id.
Out of Scope Changes check ✅ Passed All code changes are directly scoped to the objectives: token validation, rate limiting, auth guard tightening, and UI removal of the fallback option—no extraneous changes detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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 and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
modules/playground/components/deploy-dialog.tsx (1)

83-90: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Guard against missing url in API response.

If the backend returns a success response but data.url is undefined or null, data.url.startsWith("http") will throw a TypeError, crashing the UI.

🛡️ Proposed defensive check
             if (!res.ok) {
                 throw new Error(data.error || "Deployment failed");
             }

-            setDeployedUrl(data.url.startsWith("http") ? data.url : `https://${data.url}`);
+            const url = data.url;
+            if (!url) {
+                throw new Error("Deployment succeeded but no URL was returned");
+            }
+            setDeployedUrl(url.startsWith("http") ? url : `https://${url}`);
             toast.success("Successfully deployed!");
🤖 Prompt for 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.

In `@modules/playground/components/deploy-dialog.tsx` around lines 83 - 90, The
response handling assumes data.url is a string and calls data.url.startsWith,
which will throw if url is null/undefined; update the deploy result handling
(after const data = await res.json()) to defensively check that data.url is a
non-empty string (e.g., typeof data.url === "string" && data.url) before using
startsWith, and if it's missing either throw a meaningful Error or
setDeployedUrl to a safe fallback (or skip calling
setDeployedUrl/toast.success). Modify the logic around setDeployedUrl and
toast.success to only run when the validated url exists, referencing data.url
and setDeployedUrl.
🧹 Nitpick comments (1)
app/api/deploy/vercel/route.ts (1)

44-53: 💤 Low value

Consider explicit type guard for userApiKey.

If a malformed request sends a non-string userApiKey (e.g., a number), calling .trim() on it will throw at runtime, resulting in a 500 instead of a clear 400 validation error.

🛡️ Proposed defensive check
-        const token = (userApiKey as string | undefined)?.trim();
+        const token = typeof userApiKey === "string" ? userApiKey.trim() : undefined;
🤖 Prompt for 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.

In `@app/api/deploy/vercel/route.ts` around lines 44 - 53, The code currently
calls (userApiKey as string | undefined)?.trim() which will throw if userApiKey
is not a string; update the validation in the route handler to first check
typeof userApiKey === "string" before calling .trim(), and if it's not a string
(or is missing/empty after trimming) return the same NextResponse.json 400
error; reference the userApiKey/token validation block (token variable and the
NextResponse.json error response) and apply this explicit type guard to avoid
runtime exceptions.
🤖 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.

Outside diff comments:
In `@modules/playground/components/deploy-dialog.tsx`:
- Around line 83-90: The response handling assumes data.url is a string and
calls data.url.startsWith, which will throw if url is null/undefined; update the
deploy result handling (after const data = await res.json()) to defensively
check that data.url is a non-empty string (e.g., typeof data.url === "string" &&
data.url) before using startsWith, and if it's missing either throw a meaningful
Error or setDeployedUrl to a safe fallback (or skip calling
setDeployedUrl/toast.success). Modify the logic around setDeployedUrl and
toast.success to only run when the validated url exists, referencing data.url
and setDeployedUrl.

---

Nitpick comments:
In `@app/api/deploy/vercel/route.ts`:
- Around line 44-53: The code currently calls (userApiKey as string |
undefined)?.trim() which will throw if userApiKey is not a string; update the
validation in the route handler to first check typeof userApiKey === "string"
before calling .trim(), and if it's not a string (or is missing/empty after
trimming) return the same NextResponse.json 400 error; reference the
userApiKey/token validation block (token variable and the NextResponse.json
error response) and apply this explicit type guard to avoid runtime exceptions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: c1b81fd1-3801-48dd-aa83-43b2767a54eb

📥 Commits

Reviewing files that changed from the base of the PR and between f12b223 and 22e17f0.

📒 Files selected for processing (2)
  • app/api/deploy/vercel/route.ts
  • modules/playground/components/deploy-dialog.tsx

Signed-off-by: dynamo-pentester <giveawaynino143@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

1 participant