96 lines
3.6 KiB
SQL
96 lines
3.6 KiB
SQL
-- -----------------------------------------------------------------------------
|
|
-- Migration: 20260129_001_create_identity_watchlist
|
|
-- Sprint: SPRINT_0129_001_ATTESTOR_identity_watchlist_alerting
|
|
-- Task: WATCH-004
|
|
-- Description: Creates identity watchlist and alert deduplication tables.
|
|
-- -----------------------------------------------------------------------------
|
|
|
|
-- Watchlist entries table
|
|
CREATE TABLE IF NOT EXISTS attestor.identity_watchlist (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
tenant_id TEXT NOT NULL,
|
|
scope TEXT NOT NULL DEFAULT 'Tenant',
|
|
display_name TEXT NOT NULL,
|
|
description TEXT,
|
|
|
|
-- Identity matching fields (at least one required)
|
|
issuer TEXT,
|
|
subject_alternative_name TEXT,
|
|
key_id TEXT,
|
|
match_mode TEXT NOT NULL DEFAULT 'Exact',
|
|
|
|
-- Alert configuration
|
|
severity TEXT NOT NULL DEFAULT 'Warning',
|
|
enabled BOOLEAN NOT NULL DEFAULT TRUE,
|
|
channel_overrides JSONB,
|
|
suppress_duplicates_minutes INT NOT NULL DEFAULT 60,
|
|
|
|
-- Metadata
|
|
tags TEXT[],
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
|
created_by TEXT NOT NULL,
|
|
updated_by TEXT NOT NULL,
|
|
|
|
-- Constraints
|
|
CONSTRAINT chk_at_least_one_identity CHECK (
|
|
issuer IS NOT NULL OR
|
|
subject_alternative_name IS NOT NULL OR
|
|
key_id IS NOT NULL
|
|
),
|
|
CONSTRAINT chk_scope_valid CHECK (scope IN ('Tenant', 'Global', 'System')),
|
|
CONSTRAINT chk_match_mode_valid CHECK (match_mode IN ('Exact', 'Prefix', 'Glob', 'Regex')),
|
|
CONSTRAINT chk_severity_valid CHECK (severity IN ('Info', 'Warning', 'Critical')),
|
|
CONSTRAINT chk_suppress_duplicates_positive CHECK (suppress_duplicates_minutes >= 1)
|
|
);
|
|
|
|
-- Performance indexes for active entry lookup
|
|
CREATE INDEX IF NOT EXISTS idx_watchlist_tenant_enabled
|
|
ON attestor.identity_watchlist(tenant_id)
|
|
WHERE enabled = TRUE;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_watchlist_scope_enabled
|
|
ON attestor.identity_watchlist(scope)
|
|
WHERE enabled = TRUE;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_watchlist_issuer
|
|
ON attestor.identity_watchlist(issuer)
|
|
WHERE enabled = TRUE AND issuer IS NOT NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_watchlist_san
|
|
ON attestor.identity_watchlist(subject_alternative_name)
|
|
WHERE enabled = TRUE AND subject_alternative_name IS NOT NULL;
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_watchlist_keyid
|
|
ON attestor.identity_watchlist(key_id)
|
|
WHERE enabled = TRUE AND key_id IS NOT NULL;
|
|
|
|
-- Alert deduplication table
|
|
CREATE TABLE IF NOT EXISTS attestor.identity_alert_dedup (
|
|
watchlist_id UUID NOT NULL,
|
|
identity_hash TEXT NOT NULL,
|
|
last_alert_at TIMESTAMPTZ NOT NULL,
|
|
alert_count INT NOT NULL DEFAULT 0,
|
|
PRIMARY KEY (watchlist_id, identity_hash)
|
|
);
|
|
|
|
-- Index for cleanup
|
|
CREATE INDEX IF NOT EXISTS idx_alert_dedup_last_alert
|
|
ON attestor.identity_alert_dedup(last_alert_at);
|
|
|
|
-- Comment documentation
|
|
COMMENT ON TABLE attestor.identity_watchlist IS
|
|
'Watchlist entries for monitoring signing identity appearances in transparency logs.';
|
|
|
|
COMMENT ON COLUMN attestor.identity_watchlist.scope IS
|
|
'Visibility scope: Tenant (owning tenant only), Global (all tenants), System (read-only).';
|
|
|
|
COMMENT ON COLUMN attestor.identity_watchlist.match_mode IS
|
|
'Pattern matching mode: Exact, Prefix, Glob, or Regex.';
|
|
|
|
COMMENT ON COLUMN attestor.identity_watchlist.suppress_duplicates_minutes IS
|
|
'Deduplication window in minutes. Alerts for same identity within window are suppressed.';
|
|
|
|
COMMENT ON TABLE attestor.identity_alert_dedup IS
|
|
'Tracks alert deduplication state to prevent alert storms.';
|