Skip to content

Conversation

@kevinrutledge
Copy link
Collaborator

@kevinrutledge kevinrutledge commented Dec 14, 2025

PR 17: Security Hardening

This PR adds security infrastructure and production readiness for the referral API before developer onboarding.

Changes

Prisma Migrations replaces db push workflow. Initial migration created, CI workflow updated with MySQL service container. Team workflow: npx prisma migrate dev for development, npx prisma migrate deploy for CI/production.

Schema Updates adds @unique constraint on referralCode to prevent duplicates and updatedAt field with @updatedAt for audit tracking.

Rate Limiting protects POST /api/referral from spam (5 requests/60s per IP) and auth endpoint from brute force (5 attempts/15min per IP). Uses Upstash Redis sliding window, falls back gracefully when unavailable.

CSRF Protection validates origin headers on POST requests. Checks Sec-Fetch-Site first, then falls back to Origin vs Host comparison. Blocks cross-site requests with 403.

Idempotency Keys prevent duplicate referral submissions on network retry. Client generates UUID, server caches response in Redis for 24 hours.

Error Boundaries catch React errors at root layout (global-error.tsx) and protected route levels. Custom 404 page replaces Next.js default.

Content-Security-Policy header added to next.config.js for XSS defense-in-depth.

Environment Validation via src/env.ts fails fast on missing required variables at startup.

Other Changes

  • Next.js 15.5.7 → 15.5.9 (fixes GHSA-w37m-7fhw-fmv9 source code exposure)
  • Added form labels for accessibility (sr-only)
  • CI workflow: npm caching, MySQL service container, migration deployment step
  • Added .nvmrc for Node version consistency
  • Consistent error response format across all API endpoints
  • Variable naming refactors for self-documenting code
  • ESLint config updated to ignore /coverage/

Test Coverage

Added 22 tests: POST endpoint, batch operations, email service, server actions, JSON date coercion. All 55 tests pass.

Files

New: prisma/migrations/, src/app/global-error.tsx, src/env.ts, test/actions/referral.test.ts, .nvmrc

Modified: prisma/schema.prisma, src/middleware.ts, src/app/api/referral/route.ts, src/components/referral/referral-form.tsx, next.config.js, .github/workflows/ci.yml, package.json, eslint.config.mjs

Deleted: src/schema/index.ts

Desktop viewport of 404 page

Screenshot 2025-12-14 at 10 19 51 AM

Mobile viewport of 404 page

Screenshot 2025-12-14 at 10 21 12 AM

Note

Other error pages follow the same layout

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements comprehensive security hardening for the referral API, adding rate limiting, CSRF protection, idempotency keys, and error boundaries. The changes prepare the application for production use by preventing abuse, protecting against cross-site attacks, and handling duplicate submissions gracefully.

Key Changes:

  • Added rate limiting via Upstash Redis with graceful fallback (5 requests per 60 seconds per IP)
  • Implemented CSRF validation using Sec-Fetch-Site and Origin/Host header checking
  • Added idempotency key support to prevent duplicate referral submissions on retry
  • Created custom error boundaries and 404 page for better error handling
  • Fixed memory leak in useToast hook by correcting the useEffect dependency array

Reviewed changes

Copilot reviewed 24 out of 26 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
src/app/api/referral/route.ts Added CSRF validation, rate limiting, and idempotency checks to POST endpoint
src/lib/rate-limit.ts Implements Upstash Redis-based sliding window rate limiter with graceful degradation
src/lib/idempotency.ts Provides Redis-backed idempotency key caching with 24-hour TTL
src/lib/csrf.ts Validates request origin using Sec-Fetch-Site and Origin headers
src/lib/db.ts Added server-only import to prevent client-side bundling
src/services/referral.ts Added server-only import to prevent client-side bundling
src/services/email.ts Added server-only import to prevent client-side bundling
src/components/referral/referral-form.tsx Generates UUID idempotency key for each submission
src/hooks/use-toast.ts Fixed memory leak by removing state from useEffect dependency array
src/app/error.tsx Root-level error boundary with styled error page
src/app/(protected)/error.tsx Protected routes error boundary with database-specific messaging
src/app/not-found.tsx Custom 404 page matching application design system
next.config.js Added security headers (X-Frame-Options, HSTS, CSP-related headers)
test/api/referral-route.test.ts Added comprehensive tests for POST endpoint security features
test/services/email.test.ts New test suite for email service with 3 test cases
test/services/referral.test.ts Added tests for batch operations and updateReferralRedeemed
test/mocks/*.ts Created mock implementations for rate limiter, idempotency, CSRF, and email transport
package.json Added @upstash/ratelimit and @upstash/redis dependencies
.env.local.example Added environment variables for Upstash Redis configuration
src/schema/index.ts Removed unused barrel file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 48 out of 50 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@kevinrutledge kevinrutledge merged commit 2416d09 into develop Dec 18, 2025
3 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.

3 participants