@murk-security/runner-linux-x64 0.7.1 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/harness +0 -0
- package/package.json +1 -1
- package/runners/basic_harness_run.py +39 -0
package/bin/harness
CHANGED
|
Binary file
|
package/package.json
CHANGED
|
@@ -30,6 +30,7 @@ import json
|
|
|
30
30
|
import os
|
|
31
31
|
import re
|
|
32
32
|
import signal
|
|
33
|
+
import socket
|
|
33
34
|
import sqlite3
|
|
34
35
|
import subprocess
|
|
35
36
|
import sys
|
|
@@ -959,6 +960,23 @@ def _run_remediate(spec: dict, em: "Emitter") -> int:
|
|
|
959
960
|
return 0
|
|
960
961
|
|
|
961
962
|
|
|
963
|
+
def _target_listening(origin: str, timeout: float = 6.0) -> bool:
|
|
964
|
+
"""Whether something is listening at the origin's host:port (a quick TCP connect). A refused or
|
|
965
|
+
timed-out connect means the app isn't running there, so the scan would hunt against nothing and
|
|
966
|
+
report no findings -- which reads as 'found nothing' rather than 'nothing was there'. An
|
|
967
|
+
unparseable origin returns True (don't block on a parse failure)."""
|
|
968
|
+
try:
|
|
969
|
+
u = urlparse(origin if "//" in origin else "http://" + origin)
|
|
970
|
+
host = u.hostname or ""
|
|
971
|
+
port = u.port or (443 if u.scheme == "https" else 80)
|
|
972
|
+
if not host:
|
|
973
|
+
return True
|
|
974
|
+
with socket.create_connection((host, port), timeout=timeout):
|
|
975
|
+
return True
|
|
976
|
+
except Exception:
|
|
977
|
+
return False
|
|
978
|
+
|
|
979
|
+
|
|
962
980
|
def main() -> int:
|
|
963
981
|
ap = argparse.ArgumentParser()
|
|
964
982
|
ap.add_argument("--spec", required=True)
|
|
@@ -1015,6 +1033,21 @@ def main() -> int:
|
|
|
1015
1033
|
em.emit("run.completed", {"stop": "halt", "findings": 0, "ok": True,
|
|
1016
1034
|
"message": "no findings with a reproduction recipe to retest"})
|
|
1017
1035
|
return 0
|
|
1036
|
+
# Fail fast if a live target isn't actually up. Otherwise the whole hunt runs against a dead
|
|
1037
|
+
# origin and reports no findings, which reads as "the scanner found nothing" rather than
|
|
1038
|
+
# "nothing was running there to scan". The `murk scan` CLI pre-checks before booking a local
|
|
1039
|
+
# run; this covers hosted runs and is a backstop for local. Skippable for tests/dev.
|
|
1040
|
+
_live_origins = (spec.get("target") or {}).get("origins") or []
|
|
1041
|
+
if kind == "assess" and _live_origins and os.environ.get("BASIC_HARNESS_SKIP_REACHABILITY") != "1":
|
|
1042
|
+
if all(not _target_listening(o) for o in _live_origins):
|
|
1043
|
+
em.emit("run.failed", {
|
|
1044
|
+
"category": "target",
|
|
1045
|
+
"message": ("couldn't reach the target (" + ", ".join(_live_origins) + ") — is the "
|
|
1046
|
+
"application running and listening there? No scan was performed."),
|
|
1047
|
+
"stop": "unreachable",
|
|
1048
|
+
})
|
|
1049
|
+
return 4
|
|
1050
|
+
|
|
1018
1051
|
goal = build_retest_brief(retest_findings) if kind == "retest" else build_brief(spec)
|
|
1019
1052
|
rounds = (os.environ.get("BASIC_HARNESS_RETEST_ROUNDS", "1") if kind == "retest"
|
|
1020
1053
|
else os.environ.get("BASIC_HARNESS_ROUNDS", "3"))
|
|
@@ -1093,6 +1126,12 @@ def main() -> int:
|
|
|
1093
1126
|
"-max-cost", os.environ.get("BASIC_HARNESS_MAX_COST", prof["max_cost"]),
|
|
1094
1127
|
"-compact-tokens", "100000", "-ui", "", "-hold=false",
|
|
1095
1128
|
]
|
|
1129
|
+
# How far the agents may go. Pass the spec's action tier through to the harness so the Go
|
|
1130
|
+
# side (the exploiter agent and its tier-gated behaviour) matches what prod_env enforces for
|
|
1131
|
+
# its ops on the same spec. Without this the harness stayed at its "passive" default no matter
|
|
1132
|
+
# the spec. The harness fail-closes to passive on anything unrecognized.
|
|
1133
|
+
action_tier = str((spec.get("policy") or {}).get("actionTier") or "passive")
|
|
1134
|
+
cmd += ["-action-tier", action_tier]
|
|
1096
1135
|
# Route model calls through the murk model gateway when the control plane set
|
|
1097
1136
|
# OPENROUTER_BASE_URL (then OPENROUTER_API_KEY is a signed gateway token, not the
|
|
1098
1137
|
# OpenRouter key); direct to OpenRouter otherwise.
|