rapid7-insightidr 1.13.2: trim pasted log and log set IDs, explain the 404

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012bH7kirDAfMjDLj8AYRrNU
This commit is contained in:
2026-10-11 13:59:28 +00:00
parent b9e796e927
commit 4a339fda24
3 changed files with 34 additions and 6 deletions
@@ -131,6 +131,13 @@ 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"))
# 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)
if end_time is None:
end_time = now_ms
if start_time is None:
start_time = end_time - 24 * 3600 * 1000
try:
limit = int(inp.get("limit") or 1000)
except (TypeError, ValueError):
@@ -142,7 +149,11 @@ def run():
"per_page": inp.get("logs_per_page"),
"sequence_number": inp.get("sequence_number"),
}
log_id = inp.get("log_id", "")
# A pasted ID often drags a quote or a space along; quoted into the path it
# names no log, and the API answers a bare 404.
log_id = str(inp.get("log_id") or "").strip().strip("\"'").strip()
if not log_id:
raise ValueError("log_id is required (list_log_sets gives it)")
first = request("GET", "log_search/query/logs/" + urllib.parse.quote(log_id, safe=""), params=params)
events = _identify(_collect(first, limit), log_id, inp.get("detection_name"))
print(json.dumps({"events": events, "count": len(events), "from": start_time, "to": end_time}))
@@ -151,7 +162,10 @@ def run():
try:
run()
except urllib.error.HTTPError as e:
print(json.dumps({"error": "HTTP " + str(e.code), "detail": e.read().decode("utf-8", "replace")}))
out = {"error": "HTTP " + str(e.code), "detail": e.read().decode("utf-8", "replace")}
if e.code == 404:
out["hint"] = "No log with this log_id in the configured region. Check the ID against list_log_sets, and the instance region."
print(json.dumps(out))
sys.exit(1)
except Exception as e:
print(json.dumps({"error": str(e)}))
@@ -131,6 +131,13 @@ 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"))
# 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)
if end_time is None:
end_time = now_ms
if start_time is None:
start_time = end_time - 24 * 3600 * 1000
try:
limit = int(inp.get("limit") or 1000)
except (TypeError, ValueError):
@@ -142,7 +149,11 @@ def run():
"per_page": inp.get("logs_per_page"),
"sequence_number": inp.get("sequence_number"),
}
log_set_id = inp.get("log_set_id", "")
# A pasted ID often drags a quote or a space along; quoted into the path it
# names no log set, and the API answers a bare 404.
log_set_id = str(inp.get("log_set_id") or "").strip().strip("\"'").strip()
if not log_set_id:
raise ValueError("log_set_id is required (list_log_sets gives it)")
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"))
@@ -152,7 +163,10 @@ def run():
try:
run()
except urllib.error.HTTPError as e:
print(json.dumps({"error": "HTTP " + str(e.code), "detail": e.read().decode("utf-8", "replace")}))
out = {"error": "HTTP " + str(e.code), "detail": e.read().decode("utf-8", "replace")}
if e.code == 404:
out["hint"] = "No log set with this log_set_id in the configured region. Check the ID against list_log_sets, and the instance region."
print(json.dumps(out))
sys.exit(1)
except Exception as e:
print(json.dumps({"error": str(e)}))