mirror of
https://github.com/marcredhat/kql
synced 2026-06-08 21:27:09 +00:00
93 lines
3.2 KiB
Python
93 lines
3.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Probe: does SDL index JSON keys that contain literal dots?
|
|
|
|
If yes, we can ship synthetic OCSF events with keys like
|
|
`"event.category": "logins"` and query them with the same dotted
|
|
syntax the published runnable example uses, keeping the OCSF
|
|
look-and-feel without needing a server-side parser to flatten
|
|
nested objects.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import sys
|
|
import time
|
|
import uuid
|
|
from datetime import datetime, timedelta, timezone
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
sys.path.insert(0, str(ROOT))
|
|
from harness.sdl_client import upload_logs, power_query # noqa: E402
|
|
|
|
|
|
def main() -> int:
|
|
run_id = f"dot-probe-{uuid.uuid4().hex[:8]}"
|
|
now = datetime.now(timezone.utc).replace(microsecond=0)
|
|
ts_ms = int((now - timedelta(seconds=30)).timestamp() * 1000)
|
|
|
|
e = {
|
|
"TimeGenerated": now.strftime("%Y-%m-%dT%H:%M:%S.000Z"),
|
|
"ts_epoch_ms": ts_ms,
|
|
"proof_run_id": run_id,
|
|
# literal dots in the key (NOT nested objects)
|
|
"event.category": "logins",
|
|
"event.login.userName": "alice@contoso.com",
|
|
"event.login.loginIsSuccessful": False,
|
|
"endpoint.name": "host-alpha",
|
|
}
|
|
r = upload_logs(json.dumps(e))
|
|
print("upload:", r.get("status"))
|
|
|
|
print("indexing", end="", flush=True)
|
|
n = 0
|
|
for _ in range(20):
|
|
time.sleep(2)
|
|
rr = power_query(f"proof_run_id='{run_id}' | group n=count()", "5m")
|
|
vals = rr.get("values") or []
|
|
n = int(vals[0][0]) if vals and vals[0] and vals[0][0] is not None else 0
|
|
print(f" {n}", end="", flush=True)
|
|
if n >= 1:
|
|
break
|
|
print()
|
|
|
|
if n == 0:
|
|
print("event did not become queryable; aborting")
|
|
return 1
|
|
|
|
probes = [
|
|
("filter event.category",
|
|
f"proof_run_id='{run_id}' AND event.category='logins' | limit 2"),
|
|
("project event.category",
|
|
f"proof_run_id='{run_id}' | columns c=event.category | limit 2"),
|
|
("project endpoint.name",
|
|
f"proof_run_id='{run_id}' | columns h=endpoint.name | limit 2"),
|
|
("project event.login.userName",
|
|
f"proof_run_id='{run_id}' | columns u=event.login.userName | limit 2"),
|
|
("filter event.login.loginIsSuccessful",
|
|
f"proof_run_id='{run_id}' AND event.login.loginIsSuccessful='false' | limit 2"),
|
|
("bracket access",
|
|
f"proof_run_id='{run_id}' AND \"event.category\"='logins' | limit 2"),
|
|
("see all top-level cols of one row",
|
|
f"proof_run_id='{run_id}' | limit 1"),
|
|
]
|
|
for label, q in probes:
|
|
r = power_query(q, "5m")
|
|
status = r.get("status")
|
|
matching = r.get("matchingEvents")
|
|
msg = (r.get("message") or "")[:140]
|
|
print(f"\n[{label}]")
|
|
print(f" q : {q}")
|
|
print(f" status: {status} matching: {matching} msg: {msg}")
|
|
cols = r.get("columns") or []
|
|
col_names = [c.get("name") if isinstance(c, dict) else c for c in cols]
|
|
print(f" cols : {col_names}")
|
|
for v in (r.get("values") or [])[:2]:
|
|
v_str = str(v)
|
|
print(f" val : {v_str[:200]}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|