Conversation
…d rate limiting - Add clustering support based on available CPU cores and environment settings - Integrate PostHog analytics for API request and server metrics tracking - Implement rate limiting with IP validation and bounded in-memory storage - Enhance VercelRequest and VercelResponse interfaces with robust parsing and security headers - Improve CORS handling with origin allowlists and credential support - Validate and sanitize API endpoint paths to prevent directory traversal attacks - Add request body size limit and enforce request timeout handling - Provide structured logging for requests, responses, errors, and server lifecycle events - Add health endpoint with uptime, metrics, environment, and version info - Support graceful shutdown with analytics capture on termination signals - Update create-checkout-session API with stricter CORS origin checks and OPTIONS method handling - Refine hono-polar API subscription syncing with date object conversions and improved checkout flow - Enhance secret-chat API error handling with detailed status codes and messages - Update service worker cache revision for production deployment
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
High Priority Fixes: - Replace vulnerable regex patterns in IP validation with safe string operations - Secure cookie parsing with Object.create(null) to prevent prototype pollution - Enhanced file system operations with additional validation layers - Add PostHog analytics payload size limits (32KB) and comprehensive PII sanitization - Implement error message sanitization to prevent information leakage Security Improvements: - Safe IPv4/IPv6 validation without regex DoS vulnerability - Cookie name/value validation with length limits and safe patterns - Multi-layer path traversal protection for API endpoint resolution - PII pattern detection and redaction for analytics - Development vs production error handling with safe messaging - ESLint security rule compliance with appropriate exemptions for validated cases 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
…ration limits - Updated regex patterns for sanitizing metadata, navigation, images, stylesheets, scripts, fonts, and meta tags to prevent potential vulnerabilities. - Implemented iteration limits to avoid catastrophic backtracking in regex operations. - Added validation checks for extracted URLs and text to ensure safety and compliance with length restrictions. This commit addresses security concerns and improves the robustness of HTML content extraction.
- Resolved CORS configuration conflict in api-dev-server.ts using secure whitelist approach - Resolved git provider detection conflict in lib/deployment/netlify.ts using comprehensive URL parsing - Fixed regex escape character issue in netlify.ts for security compliance 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
**HIGH RISK - CORS Misconfiguration Fixed:** - Separate trusted origins from allowed origins in api-dev-server.ts - Only enable credentials for explicitly trusted domains - Prevent credential hijacking via dynamic origin setting **MEDIUM RISK - URL Validation Bypass Fixed:** - Replace vulnerable substring matching with secure hostname validation - Use proper URL parsing to prevent domain spoofing attacks - Affected files: netlify.ts and vercel.ts deployment services **MEDIUM RISK - Information Exposure Prevention:** - Enhanced error sanitization in both development and production modes - Remove ALL sensitive paths, environment variables, credentials from error messages - Stricter character limits and complete information sanitization Security improvements protect against: - Credential theft via CORS misconfiguration - Domain spoofing attacks (evil.com/github.com bypasses) - Internal system information disclosure through error messages 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Fix Promise being passed to Convex in EnhancedChatInterface.tsx by properly consuming textStream - Fix 404 error on tRPC billing endpoint by correcting URL path to /hono/trpc/ - Add robust array checks to prevent Se.map undefined errors - Improve metadata handling with proper values instead of undefined - Enhanced error handling and logging for tRPC requests 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
Take the more secure origin validation from main branch that includes additional isValidOrigin checks for both trusted and allowed origins. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Replace `existsSync` with `statSync` for safer file existence checks in API endpoints. - Improve error handling for non-file responses and inaccessible directories. - Update CORS handling in `create-checkout-session` to validate origins more robustly. - Introduce helper functions for validating environment variables in `hono-polar` API. - Refactor input sanitization and validation logic in various components for enhanced security. - Clean up unused imports and optimize component structures across multiple files.
- Update analytics configuration to enable based on the presence of the PostHog API key. - Improve IP hashing method for better privacy using SHA-256. - Refine IP validation logic with comprehensive regex for IPv6 support. - Enhance error responses in API endpoints to include decoded endpoint information. - Implement structured logging for API requests and errors, ensuring sensitive data is scrubbed. - Update README to reflect enhanced security features and request timeout settings. - Add new environment variables for Sentry error monitoring and privacy consent management. - Optimize dependency versions in package.json and bun.lock for improved stability.
- Simplified regex patterns for email and phone number validation. - Improved handling of sensitive headers in the scrubHeaders function. - Updated error sanitization methods to prevent sensitive data leaks. - Enhanced URL validation patterns for GitHub links. - Refined object sanitization to prevent prototype pollution and ensure safe handling of sensitive fields.
…for credentials transfer Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
- Resolved IP validation function conflicts by choosing the newer, more robust implementation - Resolved cookie parsing conflicts by keeping enhanced prototype pollution protection - Resolved file existence check conflicts by using the safer validation approach - Resolved HTML sanitization conflicts by keeping the sanitize-html library approach - All conflicts resolved while maintaining security best practices 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
…m our branch Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
…ranch Merged security enhancements while preserving functionality: - Enhanced error sanitization with comprehensive path and credential redaction - Improved CORS handling with secure credential-only for trusted origins - Upgraded IP hashing from base64 to SHA-256 for better anonymization - Tightened error message length limits and expanded error pattern matching - More comprehensive PII detection and sanitization patterns - Regenerated bun.lock to resolve dependency conflicts All security improvements from dev-branch have been prioritized while maintaining existing functionality from qoder branch. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
- Introduced `ZapdevDeploymentSecrets` to handle sensitive deployment tokens securely. - Updated `ZapdevDeploymentConfig` to exclude sensitive access tokens, ensuring they are retrieved at runtime. - Enhanced deployment manager to utilize the new secrets structure for Netlify and Vercel services. - Improved error handling and logging in various API endpoints for better security and maintainability. - Updated README to reflect changes in deployment configuration and security practices.
…pdate service worker registration - Removed commented-out critical CSS resources for clarity. - Added module preload link for improved loading performance of main module. - Updated service worker registration to use a more generic '/sw.js' path for better maintainability.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| 20372498 | Triggered | Generic High Entropy Secret | 72993ac | .env.deployment.template | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
WalkthroughThis PR adds Docker/Kubernetes deployment assets, introduces a service worker and PWA configuration, restructures deployment secrets, updates API handlers (auth flow and domain validation), adds several frontend performance optimizations (preloading, critical CSS, lazy loading), adjusts utilities for security/sanitization, and refines documentation and configs. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant C as Client
participant S as /api/success
participant Auth as Auth Service
participant Sub as /api/get-subscription
C->>S: POST with Authorization header
S->>Auth: verifyAuth(authHeader)
Auth-->>S: { userId | error }
alt Auth ok
S->>Sub: GET (Authorization forwarded)
alt Subscription ok
Sub-->>S: { planId, status }
S-->>C: 200 { success:true, planId, status }
else Subscription error
S-->>C: 200 { success:true, message:fallback, planId:"free", status:"none" }
end
else Auth missing/invalid
S-->>C: 401
end
sequenceDiagram
autonumber
participant U as User
participant D as /api/domains
participant M as DeploymentManager
Note over D: On first request, lazy init manager
U->>D: POST { action, subdomain, platform, ... }
D->>D: validateRequestBody + validateSubdomain
alt invalid body/subdomain
D-->>U: 400
else valid
opt first use
D->>M: getDeploymentManager(config, secrets)
M-->>D: instance or error
end
alt manager unavailable
D-->>U: 503
else proceed
D-->>U: 200 (availability/suggestions/instructions)
end
end
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
✨ Finishing Touches
🧪 Generate 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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR/Issue comments)Type Other keywords and placeholders
CodeRabbit Configuration File (
|
Resolved merge conflicts prioritizing security improvements and maintaining functionality: - API-SERVER-README.md: Fixed malformed line in graceful shutdown feature - api/deploy.ts: Used main branch approach with runtime secrets validation - api/domains.ts: Kept deployment manager configuration comment from main - api/success.ts: Maintained strict authentication requirements from qoder - lib/deployment/types.ts: Used main branch configuration comment - lib/deployment/vercel.ts: Kept enhanced extractRepoPath with security improvements - src/components/PrivacyConsentBanner.tsx: Used function declaration style from main - src/components/SubscriptionUpgradeModal.tsx: Removed SafeText dependency - src/components/auth/EnhancedSignUp.tsx: Kept clean interface without unused onComplete prop - src/components/auth/PrivacyAwareSignInButton.tsx: Used function declaration style - src/main.tsx: Removed unused imports from qoder branch - src/utils/security.ts: Kept simpler script tag regex pattern from qoder - src/utils/text-sanitizer.ts: Preserved Zod validation enhancements from qoder All conflicts resolved while maintaining security improvements and code quality. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
|
Claude finished @otdoges's task —— View job PR Review: Qoder - Comprehensive Security & Performance Analysis ✅I've completed a thorough review of this large PR with 1908 additions across 30 files. Here's my comprehensive analysis: Review Checklist
🔍 Critical Security Issues1. RESOLVED: GitGuardian Secret Detection (False Positive)
2. CRITICAL: Service Worker Syntax Error
// Remove these lines (8-10):
const CRITICAL_RESOURCES = [
'/',🏗️ Architecture & Performance Analysis✅ Exceptional Security Implementations
✅ Outstanding Performance Optimizations
✅ Production-Ready Infrastructure
🧪 Test Coverage Assessment: GOODExisting Test Files:
Missing Test Coverage:
🚨 Issues to AddressHigh Priority (Must Fix Before Merge)
Medium Priority (Recommended)
📊 Performance Impact Assessment: POSITIVEBenefits:
Considerations:
🔐 Security Assessment: EXCELLENT 🏆This PR demonstrates exceptional security awareness:
🏆 Overall Assessment: STRONG APPROVE ⭐⭐⭐⭐⭐This is an exceptionally high-quality PR that significantly enhances:
Required Actions Before Merge:
Strongly Recommended:
Final Verdict: APPROVE with Critical FixThis PR represents outstanding engineering work with exceptional attention to security, performance, and production readiness. The architectural decisions are sound, the implementation quality is high, and the security measures are comprehensive. The only blocking issue is the service worker syntax error, which is a simple 2-line fix. Once that's resolved, this PR is ready for production deployment. Excellent work! 🚀 |
| height, | ||
| quality = 85, | ||
| loading = 'lazy', | ||
| placeholder = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCIgdmlld0JveD0iMCAwIDIwMCAyMDAiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxyZWN0IHdpZHRoPSIyMDAiIGhlaWdodD0iMjAwIiBmaWxsPSIjRjNGNEY2Ii8+Cjx0ZXh0IHg9IjEwMCIgeT0iMTEwIiB0ZXh0LWFuY2hvcj0ibWlkZGxlIiBmb250LWZhbWlseT0ic2Fucy1zZXJpZiIgZm9udC1zaXplPSIxNCIgZmlsbD0iIzlDQTNBRiI+TG9hZGluZy4uLjwvdGV4dD4KPHN2Zz4=', |
Check failure
Code scanning / ESLint
Disallow unused variables Error
| setIsLoading(false); | ||
| }, []); | ||
|
|
||
| const { webpSrcSet, avifSrcSet } = generateSrcSet(src); |
Check failure
Code scanning / ESLint
Disallow unused variables Error
| setIsLoading(false); | ||
| }, []); | ||
|
|
||
| const { webpSrcSet, avifSrcSet } = generateSrcSet(src); |
Check failure
Code scanning / ESLint
Disallow unused variables Error
| getFCP(({ name, value, rating }) => sendMetrics(name, value, rating)); | ||
| getLCP(({ name, value, rating }) => sendMetrics(name, value, rating)); | ||
| getTTFB(({ name, value, rating }) => sendMetrics(name, value, rating)); | ||
| } catch (error) { |
Check failure
Code scanning / ESLint
Disallow unused variables Error
| // web-vitals library not available, use Performance API | ||
| measureWithPerformanceAPI(); | ||
| } | ||
| }, []); |
Check warning
Code scanning / ESLint
verifies the list of dependencies for Hooks like useEffect and similar Warning
|
|
||
| // Memory usage (Chrome only) | ||
| if ('memory' in performance) { | ||
| const memory = (performance as any).memory; |
Check failure
Code scanning / ESLint
Disallow the `any` type Error
There was a problem hiding this comment.
Actionable comments posted: 24
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (17)
src/components/auth/PrivacyAwareSignInButton.tsx (3)
40-78: Respect consent result and add error handling with Sonner toastsYou ignore the
hasConsentflag and always open the Clerk modal. That violates consent UX and our toast/error-handling guidelines. Guard onhasConsent, keep the banner open on denial, and wrapopenSignInin try/catch with Sonner feedback.Apply this diff within the handler:
- const handlePrivacyConsentComplete = (hasConsent: boolean) => { - setShowPrivacyConsent(false); - - // Open Clerk modal with enhanced styling - openSignIn({ - redirectUrl: forceRedirectUrl, - fallbackRedirectUrl: fallbackRedirectUrl, - appearance: { + const handlePrivacyConsentComplete = (hasConsent: boolean) => { + if (!hasConsent) { + toast.error('We need your consent to proceed with sign in.'); + // Keep the consent banner open so the user can reconsider or review details. + return; + } + + setShowPrivacyConsent(false); + + try { + // Open Clerk modal with enhanced styling + openSignIn({ + redirectUrl: forceRedirectUrl, + fallbackRedirectUrl: fallbackRedirectUrl, + appearance: { elements: { modalContent: 'bg-gray-900 border border-gray-700', modalCloseButton: 'text-gray-400 hover:text-white', card: 'bg-gray-900 border border-gray-700', formButtonPrimary: 'bg-blue-600 hover:bg-blue-700', formFieldInput: 'bg-gray-800 border-gray-600 text-white placeholder:text-gray-400', formFieldLabel: 'text-gray-300', headerTitle: 'text-white', headerSubtitle: 'text-gray-300', socialButtonsBlockButton: 'bg-gray-800 border-gray-600 hover:bg-gray-700', socialButtonsBlockButtonText: 'text-white', dividerText: 'text-gray-400', formFieldSuccessText: 'text-green-400', formFieldErrorText: 'text-red-400', identityPreviewText: 'text-gray-300', identityPreviewEditButton: 'text-blue-400 hover:text-blue-300', footer: 'bg-gray-800/50', footerActionText: 'text-gray-400', footerActionLink: 'text-blue-400 hover:text-blue-300' }, variables: { colorPrimary: '#3B82F6', colorBackground: '#111827', colorInputBackground: '#1F2937', colorInputText: '#FFFFFF', colorText: '#FFFFFF', colorTextSecondary: '#D1D5DB' } - } - }); + } + }); + } catch (err: unknown) { + console.error(err); + toast.error('Failed to open sign-in. Please try again.'); + } };Additionally add the Sonner import:
import PrivacyConsentBanner from '../PrivacyConsentBanner'; +import { toast } from 'sonner';
24-29: Default all redirect URLs to /chat to meet auth guidelinePer coding guidelines for auth components, force redirect to
/chatafter auth unless explicitly overridden. Set safe defaults on props destructuring.export function PrivacyAwareSignInButton({ children, mode = 'modal', - forceRedirectUrl, - fallbackRedirectUrl, - signUpForceRedirectUrl, - signUpFallbackRedirectUrl, + forceRedirectUrl = '/chat', + fallbackRedirectUrl = '/chat', + signUpForceRedirectUrl = '/chat', + signUpFallbackRedirectUrl = '/chat', }: PrivacyAwareSignInButtonProps) {
103-111: Use a real button for accessibility (keyboard + semantics)Interactive
divharms a11y. Usemotion.buttonwithtype="button".- <motion.div - onClick={handleSignInClick} - whileHover={{ scale: 1.02 }} - whileTap={{ scale: 0.98 }} - style={{ cursor: 'pointer' }} - > + <motion.button + type="button" + onClick={handleSignInClick} + whileHover={{ scale: 1.02 }} + whileTap={{ scale: 0.98 }} + > {children} - </motion.div> + </motion.button>src/components/auth/EnhancedSignUp.tsx (2)
23-42: Signup modal may never open (handler never wired) and users with prior consent see a blank screen.
handlePrivacyComplete(Line 23) is never invoked. The consent step renders<PrivacyConsentStep />(Line 65) without any completion callback, so Clerk’s sign-up modal is never opened.- If
showConsentis false (e.g., user previously consented), the component returnsnull(Lines 109-111) and nothing else triggersopenSignUp.Wire the handler and auto-open for previously-consented users:
- import React, { useState } from 'react'; + import React, { useEffect, useState } from 'react'; @@ const { openSignUp } = useClerk(); @@ const handlePrivacyComplete = () => { setStep('signup'); closeConsent(); // Open Clerk's signup modal after privacy consent openSignUp({ redirectUrl, appearance: { elements: { modalContent: 'bg-gray-900 border border-gray-700', modalCloseButton: 'text-gray-400 hover:text-white', formButtonPrimary: 'bg-primary hover:bg-primary/90', card: 'bg-gray-900 border border-gray-700', formFieldInput: 'bg-gray-800 border-gray-600 text-white', formFieldLabel: 'text-gray-300', headerTitle: 'text-white', headerSubtitle: 'text-gray-300' } } }); }; + + // Auto-advance when consent already exists to avoid a blank screen + useEffect(() => { + if (!showConsent && hasConsent && step === 'privacy') { + handlePrivacyComplete(); + } + }, [showConsent, hasConsent, step]); @@ - <PrivacyConsentStep /> + <PrivacyConsentStep onComplete={handlePrivacyComplete} />If
PrivacyConsentStepdoesn’t acceptonComplete, keep the effect and instead invokecloseConsent()within that step and rely on the effect to open Clerk.Also applies to: 62-66, 109-111
8-13: Handle auth states and redirect to /chat for signed-in users; show loading UI per guidelines.Per the repo’s auth guidelines and prior learnings, components under
auth/**must:
- Redirect authenticated users to
/chat.- Show a loading spinner while auth state is resolving.
- Provide a sign-in path configured with
forceRedirectUrl: '/chat'.Minimal changes:
- import { SignUp, useClerk } from '@clerk/clerk-react'; + import { useClerk, useAuth, SignInButton } from '@clerk/clerk-react'; @@ -export function EnhancedSignUp({ redirectUrl = '/chat' }: EnhancedSignUpProps) { +export function EnhancedSignUp({ redirectUrl = '/chat' }: EnhancedSignUpProps) { const [step, setStep] = useState<'privacy' | 'signup' | 'welcome'>('privacy'); const { showConsent, hasConsent, PrivacyConsentStep, closeConsent } = useSignupPrivacyConsent(); const { openSignUp } = useClerk(); + const { isLoaded, isSignedIn } = useAuth(); + + // Redirect authenticated users to /chat + useEffect(() => { + if (isLoaded && isSignedIn) { + window.location.assign('/chat'); + } + }, [isLoaded, isSignedIn]); + + // Loading state while auth resolves + if (!isLoaded) { + return ( + <div className="flex items-center justify-center h-48" role="status" aria-live="polite"> + <span className="animate-spin inline-block w-6 h-6 border-2 border-white/70 border-t-transparent rounded-full" /> + <span className="sr-only">Loading</span> + </div> + ); + } @@ - // Once privacy consent is handled, Clerk modal will handle the rest + // Once privacy consent is handled, Clerk modal will handle the rest return null;Optional UI follow-up: in the privacy screen add an “Already have an account?” CTA using
<SignInButton forceRedirectUrl="/chat" mode="modal">Sign in</SignInButton>for parity with the guideline.Also applies to: 18-22, 109-111
src/utils/security.ts (1)
93-105: Harden closing </script> detection and cover iframe srcdoc.The updated regex misses valid closing tags like
</script >(whitespace before>), which can allow a bypass. Also consider blockingiframe srcdoc=, a frequent inline-HTML vector.Apply this diff to tighten matching and add
srcdoc:- /<script[^>]*>[\s\S]*?<\/script>/is, + /<script[^>]*>[\s\S]*?<\/script\s*>/is, @@ - // restrict risky data URI media types commonly used for HTML/script delivery + // block iframe inline HTML via srcdoc + /\bsrcdoc\s*=/i, + // restrict risky data URI media types commonly used for HTML/script deliverylib/deployment/types.ts (1)
167-195: Sensitive tokens reintroduced into ZapdevDeploymentConfig (violates secrets split).
ZapdevDeploymentConfigcurrently includesnetlify.accessTokenandvercel.accessToken(Lines 170–177), while the PR and file comments state tokens must live only inZapdevDeploymentSecrets. Keeping tokens here risks serialization/logging leaks and contradicts the new architecture.Apply this diff to remove sensitive fields from
ZapdevDeploymentConfigand keep only non-sensitive teamId:export interface ZapdevDeploymentConfig { - // Include sensitive deployment configuration - netlify: { - accessToken: string; - teamId?: string; - }; - vercel: { - accessToken: string; - teamId?: string; - }; // Main domain for custom subdomains baseDomain: string; // "zapdev.link" @@ - // Non-sensitive platform configuration - netlify?: { - teamId?: string; // Team ID is generally not secret - // Note: accessToken must be retrieved from ZapdevDeploymentSecrets - }; - - vercel?: { - teamId?: string; // Team ID is generally not secret - // Note: accessToken must be retrieved from ZapdevDeploymentSecrets - }; + // Non-sensitive platform configuration (tokens must be retrieved from ZapdevDeploymentSecrets) + netlify?: { teamId?: string }; + vercel?: { teamId?: string };Follow-up: ensure all code paths source tokens exclusively from
ZapdevDeploymentSecrets..dockerignore (1)
128-132: Over-broad*.yamlignore may exclude non-K8s config.This can hide app configs from the image. Narrow the scope to k8s manifests only and drop no-op exceptions.
-# Kubernetes -k8s-*.yaml -*.yaml -!package.json -!bun.lock +# Kubernetes +# Only ignore k8s manifests, don’t blanket-ignore YAML +k8s/**/*.yamlapi/success.ts (2)
66-71:authorizationreferenced outside scope in catch block.
authorizationis declared inside thetryand used in thecatch, causing a compile/runtime error. Hoist it.-export default async function handler(req: VercelRequest, res: VercelResponse) { +export default async function handler(req: VercelRequest, res: VercelResponse) { + let authorization: string | undefined; // CORS headers @@ - try { + try { // Require authentication - const rawAuthHeader = Array.isArray(req.headers['authorization']) + const rawAuthHeader = Array.isArray(req.headers['authorization']) ? req.headers['authorization'][0] : req.headers['authorization']; - const authorization = typeof rawAuthHeader === 'string' ? rawAuthHeader : undefined; + authorization = typeof rawAuthHeader === 'string' ? rawAuthHeader : undefined; @@ } catch (error) { @@ - hasAuth: !!authorization + hasAuth: !!authorizationAlso applies to: 19-33
57-64: Enforce strict typing of the subscription payload with Zod in api/success.tsThe call to
response.json()currently returns an untypedanyand bypasses our Zod-based validation guidelines. Since Zod is already declared in yourpackage.json, we should:
- Import
zfromzod.- Define a
SubscriptionSchemamatching the expected shape.- Treat the raw JSON as
unknown, parse it via Zod, and then use the validatedplanIdandstatusvalues.This ensures no implicit
anyand surfaces schema errors early.• File: api/success.ts
– Around line 57: replace the directawait response.json()with a two-step parse via Zod.
– Addimport { z } from 'zod';at the top of the file.Suggested diff:
+ import { z } from 'zod'; // ...other imports // Get subscription status from Polar.sh API const response = await fetch(/* ... */); if (!response.ok) { // existing error handling... } + // Validate subscription payload + const SubscriptionSchema = z.object({ + planId: z.string().min(1).optional(), + status: z.string().min(1).optional(), + }); - - const subscription = await response.json(); + const subscriptionUnknown: unknown = await response.json(); + const { planId = 'free', status = 'none' } = SubscriptionSchema.parse(subscriptionUnknown); return res.status(200).json({ success: true, message: 'Subscription status synced successfully', - planId: subscription.planId || 'free', - status: subscription.status || 'none' + planId, + status });api/deploy.ts (2)
286-299: Critical: Deployment API is unauthenticated and CORS-wide open.Anyone can deploy/delete/list using your org’s provider tokens. Add authentication/authorization before processing actions. At minimum, enforce a static server-side API key; ideally verify a signed Clerk session and user role.
Apply this minimal guard (API key) near the start of handler:
export default async function handler(req: VercelRequest, res: VercelResponse) { // CORS headers res.setHeader('Access-Control-Allow-Origin', '*'); res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); if (req.method === 'OPTIONS') { return res.status(200).end(); } + // Authentication + const configuredKey = process.env.DEPLOY_API_KEY; + const headerKey = + (req.headers['x-api-key'] as string) || + (req.headers.authorization?.startsWith('Bearer ') ? req.headers.authorization.slice(7) : undefined); + if (!configuredKey || headerKey !== configuredKey) { + return res.status(401).json({ error: 'Unauthorized' }); + } + if (req.method !== 'POST' && req.method !== 'GET') { return res.status(405).json({ error: 'Method not allowed' }); }Optional: narrow CORS to your app’s origin(s) and add basic rate limiting to reduce abuse.
138-154: Separate DeploymentManager config and secrets per the updated APIThe
DeploymentManagerOptionsinterface now requires both aconfig(of typeZapdevDeploymentConfig) and a distinctsecretsobject (ZapdevDeploymentSecrets). Currently you’re embedding access tokens directly in yourdeploymentConfigand not passing asecretsoption—this will break the types and diverge from the intended design.Please update
api/deploy.ts(as well as the similar block at lines 160–169) to:
- Declare
deploymentConfigusing only the public config fields (no tokens).- Pass the tokens separately in the
secretsproperty when initializingZapdevDeploymentManager.Suggested diff:
-// Extended configuration interface that includes runtime secrets -interface ZapdevDeploymentConfigWithSecrets extends ZapdevDeploymentConfig { - netlify: { - accessToken: string; - teamId?: string; - }; - vercel: { - accessToken: string; - teamId?: string; - }; -} - -// Deployment manager configuration (with runtime secrets) -const deploymentConfig: ZapdevDeploymentConfigWithSecrets = { +// Deployment manager configuration (no secrets) +const deploymentConfig: ZapdevDeploymentConfig = { baseDomain: 'zapdev.link', netlify: { - accessToken: validatedEnv.netlifyAccessToken, teamId: process.env.NETLIFY_TEAM_ID, }, vercel: { - accessToken: validatedEnv.vercelAccessToken, teamId: process.env.VERCEL_TEAM_ID, }, defaults: { platform: validatedEnv.defaultPlatform, buildCommand: process.env.DEFAULT_BUILD_COMMAND || 'npm run build', outputDirectory: process.env.DEFAULT_OUTPUT_DIR || 'dist', nodeVersion: process.env.DEFAULT_NODE_VERSION || '18.x', }, }; // Deployment manager will be initialized in the handler let deploymentManager: ZapdevDeploymentManager | null = null; // Helper function to get or initialize deployment manager function getDeploymentManager(): ZapdevDeploymentManager { if (!deploymentManager) { deploymentManager = new ZapdevDeploymentManager({ config: deploymentConfig, + secrets: { + netlifyAccessToken: validatedEnv.netlifyAccessToken, + vercelAccessToken: validatedEnv.vercelAccessToken, + }, analytics: { track: analytics.track.bind(analytics) }, logger, }); } return deploymentManager; }This change aligns with the
DeploymentManagerOptionsdefinition inlib/deployment/manager.ts(which declares bothconfigandsecrets) and ensures your tokens are handled correctly.lib/deployment/manager.ts (1)
410-413: Fix inconsistent type import specifiers for DeploymentStatusYou’re mixing
import('./types.js')andimport('./types')in the same file forDeploymentStatus. With NodeNext/Bundler resolution this can create two distinct module identities and lead to subtle type incompatibilities. Standardize on one specifier (recommend:./types.jsto match the top-level import).Apply this diff:
- status: import('./types.js').DeploymentStatus; + status: import('./types.js').DeploymentStatus; ... - status: import('./types').DeploymentStatus; + status: import('./types.js').DeploymentStatus;Also applies to: 421-423
api/domains.ts (4)
191-195: Restrict permissive CORS to trusted origins.Current headers allow any origin to call this endpoint, which is risky given mutating actions exist. Gate responses to an allowlist from environment.
Apply this diff to scope CORS:
- res.setHeader('Access-Control-Allow-Origin', '*'); - res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); - res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization'); + // Restrict CORS to trusted origins + const allowOrigin = (() => { + const origin = req.headers.origin as string | undefined; + const allowed = (process.env.ALLOWED_ORIGINS || '') + .split(',') + .map(o => o.trim()) + .filter(Boolean); + return origin && allowed.includes(origin) + ? origin + : (process.env.DEFAULT_CORS_ORIGIN || 'https://app.zapdev.link'); + })(); + res.setHeader('Access-Control-Allow-Origin', allowOrigin); + res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); + res.setHeader('Access-Control-Allow-Headers', 'Content-Type, Authorization');
237-254: Require authentication and ownership checks for mutating actions (setup/verify).Unauthenticated “setup” and “verify” let anyone configure/verify subdomains. Add auth and assert the caller owns the target project/site before proceeding.
Apply this minimal guard (replace with your real auth later):
case 'setup': if (!body) { return res.status(400).json({ error: 'Setup action requires POST method with body' }); } + if (!req.headers.authorization) { + return res.status(401).json({ error: 'Unauthorized' }); + } return await handleSetupDomain(req, res, body); case 'verify': if (!body) { return res.status(400).json({ error: 'Verify action requires POST method with body' }); } + if (!req.headers.authorization) { + return res.status(401).json({ error: 'Unauthorized' }); + } return await handleVerifyDomain(req, res, body);Follow-up (non-diff): integrate a proper
requireAuth(req)that:
- Validates the bearer/session token.
- Derives
userIdand enforces ownership ofprojectId|siteId.- Logs the auth’d
userIdin analytics rather than trusting client-provided values.I can wire this to your existing auth (Clerk/NextAuth/Supabase/etc.) if you share which provider you use.
Also applies to: 256-262
437-440: Enforce the “no consecutive hyphens” rule and align the API contract with validation.Docs say “Cannot contain consecutive hyphens,” but code only warns. Make it a hard validation error to avoid surprises.
Apply these diffs:
function isValidSubdomain(subdomain: string): boolean { if (subdomain.length < SUBDOMAIN_MIN_LENGTH || subdomain.length > SUBDOMAIN_MAX_LENGTH) return false; - return SUBDOMAIN_PATTERN.test(subdomain); + if (subdomain.includes('--')) return false; + return SUBDOMAIN_PATTERN.test(subdomain); }- if (subdomain.includes('--')) { - warnings.push('Consecutive hyphens may cause confusion'); - } + if (subdomain.includes('--')) { + errors.push('Subdomain cannot contain consecutive hyphens'); + }Optionally, clarify the rules text (no functional change if you prefer warnings — but then update “restrictions” to reflect that).
function getSubdomainRules() { - return { + const currentYear = new Date().getFullYear(); + return { minLength: SUBDOMAIN_MIN_LENGTH, maxLength: SUBDOMAIN_MAX_LENGTH, allowedCharacters: 'letters (a-z), numbers (0-9), and hyphens (-)', restrictions: [ - 'Cannot start or end with hyphens', - 'Cannot contain consecutive hyphens', + 'Cannot start or end with hyphens', + 'Cannot contain consecutive hyphens', 'Cannot use reserved words (api, www, mail, etc.)' ], - examples: ['myproject', 'awesome-app', 'portfolio2024'] + examples: ['myproject', 'awesome-app', `portfolio${currentYear}`] }; }Also applies to: 454-456, 480-491
280-283: Avoid leaking internal error messages in 500 responses.Returning
error.messagecan expose stack details or upstream provider errors. Log the details server-side and return a generic message to clients.Apply this diff:
return res.status(500).json({ error: 'Internal server error', - message: error instanceof Error ? error.message : String(error) + message: 'An unexpected error occurred.' });
♻️ Duplicate comments (3)
src/components/ui/OptimizedImage.tsx (1)
75-81: Make use of the placeholder prop to satisfy ESLint and improve UXThe placeholder prop is currently unused. Use it to style the loading overlay background to avoid unused-var errors and provide a better LQIP.
- <div - className="absolute inset-0 bg-gray-100 animate-pulse flex items-center justify-center" - style={{ width, height }} + <div + className="absolute inset-0 bg-gray-100 animate-pulse flex items-center justify-center" + style={{ + width, + height, + backgroundImage: placeholder ? `url(${placeholder})` : undefined, + backgroundSize: placeholder ? 'cover' : undefined, + backgroundPosition: placeholder ? 'center' : undefined, + }} >src/hooks/usePerformanceMonitoring.ts (1)
103-111: Eliminate any by typing performance.memoryAvoid any by defining a compatible type for the non-standard memory API.
- // Memory usage (Chrome only) - if ('memory' in performance) { - const memory = (performance as any).memory; - perfData.memoryInfo = memory; + // Memory usage (Chrome only) + type MemoryInfo = { usedJSHeapSize: number; totalJSHeapSize?: number; jsHeapSizeLimit?: number }; + type PerformanceWithMemory = Performance & { memory?: MemoryInfo }; + const perfWithMemory = performance as PerformanceWithMemory; + if (perfWithMemory.memory) { + const memory = perfWithMemory.memory; + perfData.memoryInfo = memory;api/deploy.ts (1)
14-14: Remove unused import to satisfy ESLint.ZapdevDeploymentSecrets is imported but not used.
Apply this diff:
- ZapdevDeploymentSecrets,
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
Chores