rapid7-insightidr 1.14.3: the log window is computed from the alert's time

query_log_set takes anchor_time with hours_before / minutes_after and computes
the window itself, and returns it as text: on a real run the agent computed
"24 hours before 2026-10-11T00:04Z" as ending on the 10th and reported a
day-old window. Static passes the alert's first seen time instead of dates,
and lists domain controllers apart from the new assets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RhL2gy6Sx6Y3FEsyBE3mZ
This commit is contained in:
2026-10-11 22:38:42 +00:00
parent 4bd468e671
commit 2245d5500e
4 changed files with 39 additions and 11 deletions
@@ -55,6 +55,18 @@ def _to_ms(v):
return None
def _num(v, default):
try:
return float(v) if v not in (None, "") else default
except (TypeError, ValueError):
return default
def _iso(ms):
"""The window as it was queried, in the form the agent reports it."""
return datetime.datetime.fromtimestamp(ms / 1000, tz=datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
def request(method, url, params=None):
base, headers = _cfg()
full = url if url.startswith("http") else base + url.lstrip("/")
@@ -156,6 +168,16 @@ def run():
end_time = _to_ms(inp.get("end_time"))
if inp.get("time_range"):
start_time, end_time = _rel_ms_range(inp.get("time_range"))
# An agent copies a timestamp right and gets date arithmetic wrong: on a real
# run "24 hours before 2026-10-11T00:04Z" came out ending on the 10th, and
# the events it found were a day too early. Given the alert's own time, the
# window is computed here.
anchor = _to_ms(inp.get("anchor_time"))
if anchor is not None:
before = _num(inp.get("hours_before"), 24.0)
after = _num(inp.get("minutes_after"), 30.0)
start_time = int(anchor - before * 3600 * 1000)
end_time = int(anchor + after * 60 * 1000)
# Log Search wants both bounds. A scheduled run hands over start_time alone
# (the watermark), and the very first run may hand over nothing at all.
now_ms = int(time.time() * 1000)
@@ -188,7 +210,8 @@ def run():
first = request("GET", "log_search/query/logsets/" + urllib.parse.quote(log_set_id, safe=""), params=params)
# No fallback log id: a log set spans several logs and every event names its own.
events = _identify(_collect(first, limit), "", inp.get("detection_name"))
print(json.dumps({"events": events, "count": len(events), "from": start_time, "to": end_time}))
print(json.dumps({"events": events, "count": len(events), "from": start_time, "to": end_time,
"window": "%s to %s" % (_iso(start_time), _iso(end_time))}))
try: