-- OfficeCom Sentinel central reporting store. -- Apply once as a PostgreSQL administrator to the dedicated ocsentinel database. BEGIN; CREATE SCHEMA IF NOT EXISTS ocsentinel; CREATE TABLE IF NOT EXISTS ocsentinel.device ( id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, machine_name TEXT NOT NULL, machine_name_key TEXT NOT NULL UNIQUE, first_seen_at TIMESTAMPTZ NOT NULL DEFAULT now(), last_seen_at TIMESTAMPTZ NOT NULL DEFAULT now(), last_client_version TEXT NOT NULL DEFAULT '' ); CREATE TABLE IF NOT EXISTS ocsentinel.scan_report ( id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY, device_id BIGINT NOT NULL REFERENCES ocsentinel.device(id) ON DELETE CASCADE, generated_at_utc TIMESTAMPTZ NOT NULL, received_at TIMESTAMPTZ NOT NULL DEFAULT now(), client_version TEXT NOT NULL, alert_state TEXT NOT NULL CHECK (alert_state IN ('ok', 'warning', 'critical', 'unknown')), base_alert_state TEXT NOT NULL CHECK (base_alert_state IN ('ok', 'warning', 'critical', 'unknown')), total_events INTEGER NOT NULL CHECK (total_events >= 0), unique_ip_count INTEGER NOT NULL CHECK (unique_ip_count >= 0), cve_total INTEGER NOT NULL DEFAULT 0 CHECK (cve_total >= 0), cve_critical INTEGER NOT NULL DEFAULT 0 CHECK (cve_critical >= 0), payload_sha256 CHAR(64) NOT NULL, payload JSONB NOT NULL, UNIQUE (device_id, generated_at_utc, payload_sha256) ); CREATE INDEX IF NOT EXISTS ix_ocsentinel_scan_report_device_received ON ocsentinel.scan_report (device_id, received_at DESC); CREATE INDEX IF NOT EXISTS ix_ocsentinel_scan_report_alert_received ON ocsentinel.scan_report (alert_state, received_at DESC); CREATE TABLE IF NOT EXISTS ocsentinel.ingest_nonce ( nonce CHAR(32) PRIMARY KEY, device_id BIGINT NOT NULL REFERENCES ocsentinel.device(id) ON DELETE CASCADE, received_at TIMESTAMPTZ NOT NULL DEFAULT now(), expires_at TIMESTAMPTZ NOT NULL ); CREATE INDEX IF NOT EXISTS ix_ocsentinel_ingest_nonce_expires ON ocsentinel.ingest_nonce (expires_at); CREATE OR REPLACE VIEW ocsentinel.current_device_status AS SELECT DISTINCT ON (d.id) d.machine_name, d.first_seen_at, d.last_seen_at, d.last_client_version, r.generated_at_utc, r.received_at, r.alert_state, r.base_alert_state, r.total_events, r.unique_ip_count, r.cve_total, r.cve_critical, r.payload FROM ocsentinel.device AS d LEFT JOIN ocsentinel.scan_report AS r ON r.device_id = d.id ORDER BY d.id, r.generated_at_utc DESC NULLS LAST, r.received_at DESC NULLS LAST; CREATE OR REPLACE VIEW ocsentinel.organization_summary AS SELECT count(*) FILTER (WHERE generated_at_utc IS NOT NULL) AS devices_reporting, count(*) FILTER (WHERE alert_state = 'warning') AS devices_warning, count(*) FILTER (WHERE alert_state = 'critical') AS devices_critical, coalesce(sum(total_events), 0) AS total_events, coalesce(sum(unique_ip_count), 0) AS total_unique_ips, coalesce(sum(cve_total), 0) AS total_cves, coalesce(sum(cve_critical), 0) AS critical_cves, max(received_at) AS last_report_received_at FROM ocsentinel.current_device_status; COMMIT;