Spaces:
Sleeping
Sleeping
| -- 008_log_analysis_challenges.sql | |
| -- Creates the log-analysis challenge table + storage bucket for blue team | |
| -- ========================================================================= | |
| -- 1. Challenge table | |
| -- ========================================================================= | |
| CREATE TABLE IF NOT EXISTS public.log_analysis_challenges ( | |
| id uuid PRIMARY KEY DEFAULT gen_random_uuid(), | |
| team_role text NOT NULL DEFAULT 'blue' CHECK (team_role IN ('blue')), | |
| log_type text NOT NULL CHECK (log_type IN ('apache','nginx','syslog','auth','firewall','waf','iis')), | |
| module text NOT NULL DEFAULT 'forensics', | |
| title text NOT NULL, | |
| story text NOT NULL, | |
| task_outline text NOT NULL, | |
| -- Storage (Supabase Storage bucket "log-analysis-files") | |
| storage_path text NOT NULL, | |
| file_size_bytes integer, | |
| log_metadata jsonb DEFAULT '{}'::jsonb, | |
| -- Expected answers (for grading) | |
| expected_attack_type text NOT NULL, | |
| expected_attacker_ip text, | |
| expected_timestamp text, | |
| expected_ioc text, | |
| vulnerability_description text NOT NULL, | |
| hints jsonb DEFAULT '[]'::jsonb, | |
| difficulty text CHECK (difficulty IN ('مبتدئ','متوسط','قوي')), | |
| xp_reward integer DEFAULT 150, | |
| created_at timestamptz DEFAULT now() | |
| ); | |
| CREATE INDEX IF NOT EXISTS idx_log_analysis_team_type ON public.log_analysis_challenges(team_role, log_type); | |
| CREATE INDEX IF NOT EXISTS idx_log_analysis_difficulty ON public.log_analysis_challenges(difficulty); | |
| ALTER TABLE public.log_analysis_challenges ENABLE ROW LEVEL SECURITY; | |
| -- Public read for anon | |
| DROP POLICY IF EXISTS "Open read for anon" ON public.log_analysis_challenges; | |
| CREATE POLICY "Open read for anon" ON public.log_analysis_challenges | |
| FOR SELECT USING (true); | |
| -- Backend can write (anon key bypass via service-role OR via API key with elevated perms) | |
| DROP POLICY IF EXISTS "Service role insert" ON public.log_analysis_challenges; | |
| CREATE POLICY "Service role insert" ON public.log_analysis_challenges | |
| FOR INSERT WITH CHECK (true); | |
| DROP POLICY IF EXISTS "Service role delete" ON public.log_analysis_challenges; | |
| CREATE POLICY "Service role delete" ON public.log_analysis_challenges | |
| FOR DELETE USING (true); | |
| -- ========================================================================= | |
| -- 2. Supabase Storage bucket | |
| -- ========================================================================= | |
| INSERT INTO storage.buckets (id, name, public, file_size_limit, allowed_mime_types) | |
| VALUES ( | |
| 'log-analysis-files', | |
| 'log-analysis-files', | |
| true, | |
| 2097152, -- 2 MB max | |
| ARRAY['text/plain', 'text/x-log', 'application/octet-stream'] | |
| ) | |
| ON CONFLICT (id) DO UPDATE SET | |
| public = EXCLUDED.public, | |
| file_size_limit = EXCLUDED.file_size_limit, | |
| allowed_mime_types = EXCLUDED.allowed_mime_types; | |
| -- ========================================================================= | |
| -- 3. Storage RLS — public read for the log-analysis bucket | |
| -- ========================================================================= | |
| DROP POLICY IF EXISTS "Public read log-analysis-files" ON storage.objects; | |
| CREATE POLICY "Public read log-analysis-files" | |
| ON storage.objects | |
| FOR SELECT | |
| USING (bucket_id = 'log-analysis-files'); | |
| -- Allow uploads to log-analysis-files (backend uses service-role key, which bypasses RLS anyway) | |
| DROP POLICY IF EXISTS "Service role upload log-analysis-files" ON storage.objects; | |
| CREATE POLICY "Service role upload log-analysis-files" | |
| ON storage.objects | |
| FOR INSERT | |
| WITH CHECK (bucket_id = 'log-analysis-files'); | |
| DROP POLICY IF EXISTS "Service role delete log-analysis-files" ON storage.objects; | |
| CREATE POLICY "Service role delete log-analysis-files" | |
| ON storage.objects | |
| FOR DELETE | |
| USING (bucket_id = 'log-analysis-files'); | |