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
98 lines
3.2 KiB
SQL
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;
|