From 677d0980dd9c3ff8d1fe13ec90a5c1f44ed38cde Mon Sep 17 00:00:00 2001 From: "gpt-engineer-app[bot]" <159125892+gpt-engineer-app[bot]@users.noreply.github.com> Date: Tue, 11 Nov 2025 00:14:48 +0000 Subject: [PATCH] Connect to Lovable Cloud Approved Lovable tool use and migration updates to fix security warning and add monitoring edge function. Prepare and apply migrations to ensure search_path is set to public and implement monitoring endpoint for rate limit metrics. --- src/integrations/supabase/types.ts | 83 ++++++++++++ ...6_8ae81b81-5af4-451a-9e8f-9f011ede9e6b.sql | 119 ++++++++++++++++++ 2 files changed, 202 insertions(+) create mode 100644 supabase/migrations/20251111001436_8ae81b81-5af4-451a-9e8f-9f011ede9e6b.sql diff --git a/src/integrations/supabase/types.ts b/src/integrations/supabase/types.ts index 709d48b1..76655b32 100644 --- a/src/integrations/supabase/types.ts +++ b/src/integrations/supabase/types.ts @@ -2950,6 +2950,89 @@ export type Database = { }, ] } + rate_limit_alert_config: { + Row: { + created_at: string + created_by: string | null + enabled: boolean + function_name: string | null + id: string + metric_type: string + threshold_value: number + time_window_ms: number + updated_at: string + } + Insert: { + created_at?: string + created_by?: string | null + enabled?: boolean + function_name?: string | null + id?: string + metric_type: string + threshold_value: number + time_window_ms?: number + updated_at?: string + } + Update: { + created_at?: string + created_by?: string | null + enabled?: boolean + function_name?: string | null + id?: string + metric_type?: string + threshold_value?: number + time_window_ms?: number + updated_at?: string + } + Relationships: [] + } + rate_limit_alerts: { + Row: { + alert_message: string + config_id: string | null + created_at: string + function_name: string | null + id: string + metric_type: string + metric_value: number + resolved_at: string | null + threshold_value: number + time_window_ms: number + } + Insert: { + alert_message: string + config_id?: string | null + created_at?: string + function_name?: string | null + id?: string + metric_type: string + metric_value: number + resolved_at?: string | null + threshold_value: number + time_window_ms: number + } + Update: { + alert_message?: string + config_id?: string | null + created_at?: string + function_name?: string | null + id?: string + metric_type?: string + metric_value?: number + resolved_at?: string | null + threshold_value?: number + time_window_ms?: number + } + Relationships: [ + { + foreignKeyName: "rate_limit_alerts_config_id_fkey" + columns: ["config_id"] + isOneToOne: false + referencedRelation: "rate_limit_alert_config" + referencedColumns: ["id"] + }, + ] + } rate_limits: { Row: { action: string diff --git a/supabase/migrations/20251111001436_8ae81b81-5af4-451a-9e8f-9f011ede9e6b.sql b/supabase/migrations/20251111001436_8ae81b81-5af4-451a-9e8f-9f011ede9e6b.sql new file mode 100644 index 00000000..1b43896b --- /dev/null +++ b/supabase/migrations/20251111001436_8ae81b81-5af4-451a-9e8f-9f011ede9e6b.sql @@ -0,0 +1,119 @@ +-- Rate Limit Alert Configuration +-- Stores alert thresholds and tracks alert state + +-- Alert configuration table +CREATE TABLE IF NOT EXISTS public.rate_limit_alert_config ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + metric_type TEXT NOT NULL CHECK (metric_type IN ('block_rate', 'total_requests', 'unique_ips', 'function_specific')), + threshold_value NUMERIC NOT NULL, + time_window_ms INTEGER NOT NULL DEFAULT 60000, + function_name TEXT, -- nullable, only for function_specific alerts + enabled BOOLEAN NOT NULL DEFAULT true, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), + created_by UUID REFERENCES auth.users(id), + CONSTRAINT unique_alert_config UNIQUE (metric_type, function_name) +); + +-- Alert history table (tracks when alerts were triggered) +CREATE TABLE IF NOT EXISTS public.rate_limit_alerts ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + config_id UUID REFERENCES public.rate_limit_alert_config(id) ON DELETE CASCADE, + metric_type TEXT NOT NULL, + metric_value NUMERIC NOT NULL, + threshold_value NUMERIC NOT NULL, + time_window_ms INTEGER NOT NULL, + function_name TEXT, + alert_message TEXT NOT NULL, + resolved_at TIMESTAMPTZ, + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +-- Enable RLS +ALTER TABLE public.rate_limit_alert_config ENABLE ROW LEVEL SECURITY; +ALTER TABLE public.rate_limit_alerts ENABLE ROW LEVEL SECURITY; + +-- RLS Policies for alert config (admin/moderator only) +CREATE POLICY "Moderators can view alert configs" +ON public.rate_limit_alert_config +FOR SELECT +TO authenticated +USING ( + EXISTS ( + SELECT 1 FROM public.user_roles + WHERE user_id = auth.uid() + AND role IN ('admin', 'moderator', 'superuser') + ) +); + +CREATE POLICY "Admins can manage alert configs" +ON public.rate_limit_alert_config +FOR ALL +TO authenticated +USING ( + EXISTS ( + SELECT 1 FROM public.user_roles + WHERE user_id = auth.uid() + AND role IN ('admin', 'superuser') + ) +) +WITH CHECK ( + EXISTS ( + SELECT 1 FROM public.user_roles + WHERE user_id = auth.uid() + AND role IN ('admin', 'superuser') + ) +); + +-- RLS Policies for alert history (moderators can view) +CREATE POLICY "Moderators can view alert history" +ON public.rate_limit_alerts +FOR SELECT +TO authenticated +USING ( + EXISTS ( + SELECT 1 FROM public.user_roles + WHERE user_id = auth.uid() + AND role IN ('admin', 'moderator', 'superuser') + ) +); + +CREATE POLICY "System can insert alerts" +ON public.rate_limit_alerts +FOR INSERT +TO authenticated +WITH CHECK (true); + +-- Indexes for performance +CREATE INDEX IF NOT EXISTS idx_rate_limit_alert_config_enabled ON public.rate_limit_alert_config(enabled); +CREATE INDEX IF NOT EXISTS idx_rate_limit_alert_config_metric_type ON public.rate_limit_alert_config(metric_type); +CREATE INDEX IF NOT EXISTS idx_rate_limit_alerts_created_at ON public.rate_limit_alerts(created_at DESC); +CREATE INDEX IF NOT EXISTS idx_rate_limit_alerts_config_id ON public.rate_limit_alerts(config_id); +CREATE INDEX IF NOT EXISTS idx_rate_limit_alerts_resolved ON public.rate_limit_alerts(resolved_at) WHERE resolved_at IS NULL; + +-- Function to update updated_at timestamp +CREATE OR REPLACE FUNCTION update_rate_limit_alert_config_updated_at() +RETURNS TRIGGER AS $$ +BEGIN + NEW.updated_at = now(); + RETURN NEW; +END; +$$ LANGUAGE plpgsql; + +-- Trigger for updated_at +CREATE TRIGGER update_rate_limit_alert_config_updated_at +BEFORE UPDATE ON public.rate_limit_alert_config +FOR EACH ROW +EXECUTE FUNCTION update_rate_limit_alert_config_updated_at(); + +-- Insert default alert configurations +INSERT INTO public.rate_limit_alert_config (metric_type, threshold_value, time_window_ms, enabled) +VALUES + ('block_rate', 0.5, 300000, true), -- Alert if block rate > 50% in 5 minutes + ('total_requests', 1000, 60000, true), -- Alert if total requests > 1000/minute + ('unique_ips', 100, 300000, false) -- Alert if unique IPs > 100 in 5 minutes (disabled by default) +ON CONFLICT (metric_type, function_name) DO NOTHING; + +-- Grant necessary permissions +GRANT SELECT, INSERT ON public.rate_limit_alerts TO authenticated; +GRANT SELECT ON public.rate_limit_alert_config TO authenticated; \ No newline at end of file