From a5588ec061c48115103d07ca5964e4d244a99ac8 Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Mon, 20 Apr 2026 04:58:08 +0800 Subject: [PATCH] feat(supabase): schema migration for attack_attempt telemetry fields MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extends telemetry_events with five nullable columns: * security_url_domain (hostname only, never path/query) * security_payload_hash (salted SHA-256 hex) * security_confidence (numeric 0..1) * security_layer (enum-like text — see docstring for allowed values) * security_verdict (block | warn | log_only) Fields map 1:1 to the flags that gstack-telemetry-log accepts on --event-type attack_attempt (bin/gstack-telemetry-log commits 28ce883c + f68fa4a9). All nullable so existing skill_run inserts keep working. Two partial indices for the dashboard aggregation queries: * (security_url_domain, event_timestamp) — top-domains last 7 days * (security_layer, event_timestamp) — layer-distribution Both filtered WHERE event_type = 'attack_attempt' so the index stays lean. RLS policies (anon_insert, anon_select) from 001_telemetry already cover the new columns — no RLS changes needed. Co-Authored-By: Claude Opus 4.7 (1M context) --- supabase/migrations/004_attack_telemetry.sql | 44 ++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 supabase/migrations/004_attack_telemetry.sql diff --git a/supabase/migrations/004_attack_telemetry.sql b/supabase/migrations/004_attack_telemetry.sql new file mode 100644 index 00000000..0c0e4211 --- /dev/null +++ b/supabase/migrations/004_attack_telemetry.sql @@ -0,0 +1,44 @@ +-- gstack attack telemetry — schema extension for prompt injection events. +-- +-- Ships alongside the gstack-telemetry-log `--event-type attack_attempt` +-- flag (bin/gstack-telemetry-log, commits 28ce883c + f68fa4a9). These +-- columns are nullable so the existing skill_run events continue inserting +-- unchanged. +-- +-- Fields (1:1 with gstack-telemetry-log flags): +-- security_url_domain — hostname only, never path/query +-- security_payload_hash — salted SHA-256 hex +-- security_confidence — 0..1 numeric, clamped client-side +-- security_layer — stackone_content | testsavant_content +-- | transcript_classifier | aria_regex | canary +-- | deberta_content +-- security_verdict — block | warn | log_only +-- +-- Indices: +-- * (security_url_domain, event_timestamp) — for "top domains last 7 days" +-- * (security_layer, event_timestamp) WHERE event_type='attack_attempt' +-- — for layer-distribution queries +-- +-- Privacy rules (enforced client-side, documented here): +-- * domain only, never path or query string +-- * payload_hash is a salted hash, not the payload +-- * salt is per-device local file (~/.gstack/security/device-salt) — +-- preventing cross-device rainbow table attacks + +ALTER TABLE telemetry_events + ADD COLUMN security_url_domain TEXT, + ADD COLUMN security_payload_hash TEXT, + ADD COLUMN security_confidence NUMERIC, + ADD COLUMN security_layer TEXT, + ADD COLUMN security_verdict TEXT; + +-- Top-domains query: ORDER BY count DESC WHERE event_type='attack_attempt' +-- AND event_timestamp > now() - interval '7 days' +CREATE INDEX idx_telemetry_attack_domain + ON telemetry_events (security_url_domain, event_timestamp) + WHERE event_type = 'attack_attempt'; + +-- Layer-distribution query +CREATE INDEX idx_telemetry_attack_layer + ON telemetry_events (security_layer, event_timestamp) + WHERE event_type = 'attack_attempt';