Files
AWatch-rus/clickhouse-1c/security/security_finding_inbox.sql
T
igor04091968 757fd3125d
CI / Rust checks (push) Waiting to run
CI / Docs and registry checks (push) Waiting to run
CI / Smoke checks (push) Waiting to run
Coverage / Coverage baseline (push) Waiting to run
Security / Cargo audit (push) Waiting to run
Security / Cargo deny (push) Waiting to run
Security / Secret pattern check (push) Waiting to run
Security / Dependency review (push) Waiting to run
Add shadow security finding inbox
2026-07-01 06:12:08 +03:00

98 lines
3.2 KiB
SQL

CREATE TABLE IF NOT EXISTS analytics_1c.security_findings
(
ts DateTime64(3, 'UTC'),
finding_id String,
host String,
user String,
ip String,
department LowCardinality(String),
state LowCardinality(String),
severity LowCardinality(String),
confidence LowCardinality(String),
score UInt16,
source LowCardinality(String),
rule_id String,
rule_title String,
summary String,
recommended_action LowCardinality(String),
management_channel_checked UInt8,
evidence_ref String,
raw_json String,
ingested_at DateTime64(3, 'UTC') DEFAULT now64(3)
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(ts)
ORDER BY (state, severity, host, ts, finding_id);
CREATE TABLE IF NOT EXISTS analytics_1c.security_finding_workflow_events
(
ts DateTime64(3, 'UTC'),
finding_id String,
event_type LowCardinality(String),
status LowCardinality(String),
actor String,
comment String,
decision_status String,
rollback_plan_id String,
plan_id String,
evidence_json String
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(ts)
ORDER BY (finding_id, ts, event_type);
DROP VIEW IF EXISTS analytics_1c.security_finding_inbox;
CREATE VIEW analytics_1c.security_finding_inbox AS
SELECT
f.finding_id AS finding_id,
min(f.ts) AS first_seen,
max(f.ts) AS last_seen,
argMax(f.host, f.ingested_at) AS host,
argMax(f.user, f.ingested_at) AS user,
argMax(f.ip, f.ingested_at) AS ip,
argMax(f.department, f.ingested_at) AS department,
argMax(f.state, f.ingested_at) AS state,
argMax(f.severity, f.ingested_at) AS severity,
argMax(f.confidence, f.ingested_at) AS confidence,
argMax(f.score, f.ingested_at) AS score,
argMax(f.source, f.ingested_at) AS source,
argMax(f.rule_id, f.ingested_at) AS rule_id,
argMax(f.rule_title, f.ingested_at) AS rule_title,
argMax(f.summary, f.ingested_at) AS summary,
argMax(f.recommended_action, f.ingested_at) AS recommended_action,
argMax(f.management_channel_checked, f.ingested_at) AS management_channel_checked,
argMax(f.evidence_ref, f.ingested_at) AS evidence_ref,
argMax(f.raw_json, f.ingested_at) AS raw_json,
coalesce(nullIf(w.status, ''), 'new') AS workflow_status,
coalesce(nullIf(w.event_type, ''), 'created') AS last_workflow_event,
w.workflow_updated_at AS workflow_updated_at,
coalesce(w.actor, '') AS workflow_actor,
coalesce(w.decision_status, '') AS decision_status,
coalesce(w.rollback_plan_id, '') AS rollback_plan_id,
coalesce(w.plan_id, '') AS plan_id
FROM analytics_1c.security_findings AS f
LEFT JOIN
(
SELECT
finding_id,
argMax(event_type, ts) AS event_type,
argMax(status, ts) AS status,
argMax(actor, ts) AS actor,
argMax(decision_status, ts) AS decision_status,
argMax(rollback_plan_id, ts) AS rollback_plan_id,
argMax(plan_id, ts) AS plan_id,
max(ts) AS workflow_updated_at
FROM analytics_1c.security_finding_workflow_events
GROUP BY finding_id
) AS w USING finding_id
GROUP BY
f.finding_id,
w.status,
w.event_type,
w.workflow_updated_at,
w.actor,
w.decision_status,
w.rollback_plan_id,
w.plan_id;