Skip to content

Fix controlled-launch contact intake persistence#188

Open
support371 wants to merge 2 commits into
mainfrom
fix/contact-intake-supabase-fallback-clean
Open

Fix controlled-launch contact intake persistence#188
support371 wants to merge 2 commits into
mainfrom
fix/contact-intake-supabase-fallback-clean

Conversation

@support371

@support371 support371 commented Jul 13, 2026

Copy link
Copy Markdown
Owner

Objective

Make the public GEM Enterprise contact form durable during the controlled production launch even when the canonical Vercel runtime does not have a direct Prisma/PostgreSQL connection.

Changes

  • Add a fail-closed gem-contact-gateway Supabase Edge Function.
  • Persist public enquiries to the existing support_bookings table before returning success.
  • Reuse the existing centralized Supabase gateway client; no new embedded credential or key file is introduced.
  • Preserve the direct Prisma path when database variables are configured.
  • Add per-email throttling, honeypot handling, audit recording, and optional Resend notification.
  • Return 503 rather than claiming success when neither persistence path is available.
  • Add regression coverage for routing order, persistence-before-notification, throttling, auditing, and accurate UI wording.
  • Activate the existing GitHub verification workflow for pull requests and align it with the repository's declared Node.js 24 runtime.

Clean-history security remediation

This PR supersedes closed PR #187. The superseded branch temporarily duplicated an existing Supabase publishable JWT in a new client file and was blocked by GitGuardian. The replacement branch was recreated directly from main, excludes that intermediate history, reuses src/lib/supabase-gateway.ts, and does not add another embedded credential location.

Current change set

  • Head: 026c9fdbbcea480d2a7560cd5ac95608b3069e3e
  • Two focused commits from current main
  • Six changed files: contact API route, centralized gateway helper, Edge Function source/configuration, regression test, and CI workflow

Data and schema impact

  • Uses existing support_bookings and audit_logs tables.
  • No Prisma schema change.
  • No migration.
  • No production seed or backfill.
  • No client, KYC, billing, or authentication data mutation.

Security and privacy

  • Edge Function requires an accepted Supabase client credential and uses the service-role key only inside the Supabase runtime.
  • Server and Edge Function both validate field lengths.
  • Website honeypot remains active.
  • Server IP throttling remains active; gateway adds per-email throttling.
  • Messages are persisted before optional notification delivery.
  • Operational errors do not return database details or secrets.

Verified

  • gem-contact-gateway is deployed on the canonical Supabase project as ACTIVE, version 1, with verify_jwt=true.
  • Authenticated invalid-input smoke returned HTTP 400, code INVALID_REQUEST, with no timeout or transport error.
  • The smoke request created zero matching support_bookings rows, proving rejected data is not persisted.
  • The replacement PR has no unresolved inline review thread.
  • Sourcery generated a reviewer guide and did not report an inline defect at the time of this record.

Infrastructure-blocked checks

  • Vercel preview did not execute because the linked accounts exceeded the daily free-plan deployment quota: api-deployments-free-per-day.
  • GitHub Actions created Build Verification run 29266090608, but the job terminated before recording any step and its log object was unavailable. This is not a passing code-verification result.
  • Codex automated review was unavailable because its review-usage limit was reached.

Merge gate

Do not merge until all of the following are recorded:

  1. pnpm run verify completes successfully on Node.js 24 through a working approved runner.
  2. A canonical Vercel preview or equivalent production-build verification succeeds for the exact PR head.
  3. The merged production route receives one controlled end-to-end submission and the corresponding support_bookings and audit records are verified.
  4. Final security review confirms that no new secret occurrence was introduced.

@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Deployment failed with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/garciamirandaramirez-2606s-projects?upgradeToPro=build-rate-limit

@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.

@sourcery-ai

sourcery-ai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds a fail-closed Supabase Edge Function-based contact intake path, wires the API route to prefer Prisma when available and fall back to the gateway otherwise, ensures persistence before optional notification with throttling, honeypot, and auditing, and adds regression tests and Deno config for the new gateway.

Sequence diagram for contact intake via Supabase gateway fallback

sequenceDiagram
  actor User
  participant ContactRoute as ContactRoute_POST
  participant SupabaseGatewayClient as submitContactGateway
  participant EdgeFunction as gem_contact_gateway
  participant DB as support_bookings
  participant Resend as ResendAPI
  participant Audit as audit_logs

  User->>ContactRoute: POST /api/contact
  ContactRoute->>ContactRoute: shouldUseSupabaseGateway
  alt use_supabase_gateway
    ContactRoute->>SupabaseGatewayClient: submitContactGateway
    SupabaseGatewayClient->>EdgeFunction: invokeGateway action_submit
    EdgeFunction->>EdgeFunction: submitContact
    EdgeFunction->>DB: enforceEmailRateLimit select_support_bookings
    EdgeFunction->>DB: insert_support_bookings
    EdgeFunction->>Resend: sendNotification
    Resend-->>EdgeFunction: notificationDelivery
    EdgeFunction->>DB: update_support_bookings_delivery_status
    EdgeFunction->>Audit: insert_audit_logs
    EdgeFunction-->>SupabaseGatewayClient: ContactGatewayResult
    SupabaseGatewayClient-->>ContactRoute: ContactGatewayResult
    ContactRoute-->>User: 200 ok_true_persistence_supabase_gateway
  else gateway_unavailable
    SupabaseGatewayClient--xContactRoute: error
    ContactRoute-->>User: 503 ok_false_error_message
  end
Loading

File-Level Changes

Change Details Files
Introduce Supabase contact gateway client types and submission helper and wire API contact route to use it as a fail-closed fallback when Prisma is unavailable.
  • Import gateway helper functions into the contact API route and branch early based on a Supabase gateway feature flag.
  • Call the Supabase gateway with normalized contact payload and return gateway persistence metadata on success.
  • Return a 503 error with non-secret messaging when both persistence paths are unavailable.
  • Add TypeScript interfaces for contact submissions and gateway results and implement a typed submitContactGateway helper around the generic invokeGateway.
src/app/api/contact/route.ts
src/lib/supabase-gateway.ts
Implement gem-contact-gateway Supabase Edge Function that validates input, rate-limits by email, persists to support_bookings, optionally sends Resend notification, and records audit_logs.
  • Set up Supabase client with service-role key and fail fast on missing runtime configuration.
  • Implement CORS and JSON helpers plus a ContactGatewayError class for structured HTTP error handling.
  • Validate required and optional fields with length constraints and normalize email, honeypot field, IP address, and user agent.
  • Enforce per-email hourly rate limit via support_bookings count query and return 429 on abuse.
  • Insert support_bookings record with pending notification notes, then update notes with final notification status.
  • Send optional Resend notification and handle failure without leaking provider details.
  • Insert an audit_logs row per submission capturing source, subject, notification delivery, IP, and user agent.
  • Expose GET health endpoint with configuration summary and POST submit action dispatch, returning structured errors for invalid actions and internal failures.
supabase/functions/gem-contact-gateway/index.ts
Add regression tests to validate routing order, gateway usage, persistence-before-notification semantics, spam controls, audit behavior, and UI wording.
  • Read contact route, Supabase gateway client, Edge Function, and contact form sources as text fixtures.
  • Assert that the contact route prefers Supabase gateway when direct DB access is unavailable but retains Prisma as the primary path when configured.
  • Assert fail-closed behavior when gateway or persistence fails, including 503 status and user-facing wording.
  • Assert that support_bookings insert occurs before notification, and that notification status is recorded in notes and metadata.
  • Verify honeypot handling, throttling constants, audit resource/source names, and that UI success text promises acceptance but not guaranteed response.
src/__tests__/contact-intake-gateway.test.ts
Configure Deno for the new Supabase function with strict type-checking and appropriate libs.
  • Add deno.json for gem-contact-gateway with strict compiler options and ns/dom libs to support Edge runtime and fetch APIs.
supabase/functions/gem-contact-gateway/deno.json

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Deployment failed with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/dpj58sq6xc-2324s-projects?upgradeToPro=build-rate-limit

@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Deployment failed with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/legal-9831s-projects?upgradeToPro=build-rate-limit

@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Deployment failed with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/admin-25521151s-projects?upgradeToPro=build-rate-limit

@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Deployment failed with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/jamesaugustine199726-2076s-projects?upgradeToPro=build-rate-limit

@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Deployment failed with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/carolinasuarez8419-9338s-projects?upgradeToPro=build-rate-limit

@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Deployment failed with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/alliancetrustrealtyearner-cells-projects?upgradeToPro=build-rate-limit

@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Deployment failed with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/gemassists-projects-3feb3fa9?upgradeToPro=build-rate-limit

@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Deployment failed with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/geraldhoeven-4141s-projects?upgradeToPro=build-rate-limit

@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Deployment failed with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/gilbertmichael561-5155s-projects?upgradeToPro=build-rate-limit

@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Deployment failed with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/victoriaeleanor544-2270s-projects?upgradeToPro=build-rate-limit

@vercel

vercel Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Deployment failed with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/support-8685s-projects?upgradeToPro=build-rate-limit

@sourcery-ai sourcery-ai 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.

Hey - I've left some high level feedback:

  • In the /api/contact route, the catch block for submitContactGateway always returns a 503 with a generic message; consider propagating meaningful status codes (e.g. 429 for RATE_LIMITED) and/or gateway error codes/messages so clients can distinguish transient failures from spam throttling.
  • The contact gateway audit log currently hardcodes action: "admin_action"; consider using a more specific action string (e.g. "contact_message_received") so these events are easier to distinguish from actual admin actions in downstream audit analysis.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the `/api/contact` route, the catch block for `submitContactGateway` always returns a 503 with a generic message; consider propagating meaningful status codes (e.g. 429 for RATE_LIMITED) and/or gateway error codes/messages so clients can distinguish transient failures from spam throttling.
- The contact gateway audit log currently hardcodes `action: "admin_action"`; consider using a more specific action string (e.g. `"contact_message_received"`) so these events are easier to distinguish from actual admin actions in downstream audit analysis.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Copy link
Copy Markdown
Owner Author

Edge Function validation smoke — passed

Authenticated invocation was executed against canonical Supabase function gem-contact-gateway using the modern publishable credential and an intentionally invalid payload.

Evidence:

  • pg_net request ID: 1
  • HTTP status: 400
  • Response code: INVALID_REQUEST
  • Response message: name is invalid.
  • Timed out: false
  • Transport error: none
  • Matching support_bookings rows after execution: 0

This proves the deployed function accepts authenticated invocation, executes its validation path, fails closed for invalid input, and does not persist rejected contact data. No real contact details were used.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 13, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Updated (UTC)
❌ Deployment failed
View logs
gem-enterprise 026c9fd Jul 13 2026, 05:26 PM

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