diff --git a/bin/job-dispatch.py b/bin/job-dispatch.py index b42c5af..27e00ae 100755 --- a/bin/job-dispatch.py +++ b/bin/job-dispatch.py @@ -222,44 +222,45 @@ def send_dm(agent, target, message, dry_run=False, followup_tags=None, if HAS_RATE_LIMITER: rate_limit_wait(agent) - # Cryptographic attestation: sign message with local SSH key + # Cryptographic attestation: only sign if explicitly requested by job config + # to avoid blowing up agent context windows with massive base64 SSH signature blocks. signed_payload = None - dm_sign_sh = NETVM_ROOT / "bin" / "dm-sign.sh" - priv_key = Path(os.path.expanduser("~/.ssh/id_ed25519")) - if dm_sign_sh.exists() and priv_key.exists(): - try: - sign_res = subprocess.run( - [str(dm_sign_sh), "--from", "super", "--key", str(priv_key), message], - capture_output=True, text=True, timeout=10 - ) - if sign_res.returncode == 0 and "-----BEGIN SSH SIGNATURE-----" in sign_res.stdout: - signed_payload = sign_res.stdout.strip() - # Extract message id and register proof to crypt.muse-dev.online - id_m = re.search(r"\[id:([a-f0-9]+)\]", signed_payload) - proof_id = id_m.group(1) if id_m else None - if proof_id: - proof_data = { - "id": proof_id, - "signer": "super", - "target_agent": agent, - "target_conversation": target, - "raw_payload": signed_payload, - "ts": datetime.now(timezone.utc).isoformat() - } - try: - import urllib.request - req = urllib.request.Request( - "https://crypt.muse-dev.online/proofs", - data=json.dumps(proof_data).encode("utf-8"), - headers={"Content-Type": "application/json", "User-Agent": "job-dispatch/1.0"}, - method="POST" - ) - with urllib.request.urlopen(req, timeout=3) as resp: - pass - except Exception as pe: - sys.stderr.write(f"warning: proof registration to crypt.muse-dev.online failed: {pe}\n") - except Exception as se: - sys.stderr.write(f"warning: dm signing failed: {se}\n") + if os.environ.get("JOB_REQUIRE_SIGNATURE") == "1": + dm_sign_sh = NETVM_ROOT / "bin" / "dm-sign.sh" + priv_key = Path(os.path.expanduser("~/.ssh/id_ed25519")) + if dm_sign_sh.exists() and priv_key.exists(): + try: + sign_res = subprocess.run( + [str(dm_sign_sh), "--from", "super", "--key", str(priv_key), message], + capture_output=True, text=True, timeout=10 + ) + if sign_res.returncode == 0 and "-----BEGIN SSH SIGNATURE-----" in sign_res.stdout: + signed_payload = sign_res.stdout.strip() + id_m = re.search(r"\[id:([a-f0-9]+)\]", signed_payload) + proof_id = id_m.group(1) if id_m else None + if proof_id: + proof_data = { + "id": proof_id, + "signer": "super", + "target_agent": agent, + "target_conversation": target, + "raw_payload": signed_payload, + "ts": datetime.now(timezone.utc).isoformat() + } + try: + import urllib.request + req = urllib.request.Request( + "https://crypt.muse-dev.online/proofs", + data=json.dumps(proof_data).encode("utf-8"), + headers={"Content-Type": "application/json", "User-Agent": "job-dispatch/1.0"}, + method="POST" + ) + with urllib.request.urlopen(req, timeout=3) as resp: + pass + except Exception as pe: + sys.stderr.write(f"warning: proof registration to crypt.muse-dev.online failed: {pe}\n") + except Exception as se: + sys.stderr.write(f"warning: dm signing failed: {se}\n") payload_to_send = signed_payload or message diff --git a/jobs/box-http-health.json b/jobs/box-http-health.json index 57197d0..8025596 100644 --- a/jobs/box-http-health.json +++ b/jobs/box-http-health.json @@ -11,11 +11,12 @@ }, "name": "box-http-health", "on_failure": "alert", - "prompt_template": "Box HTTP health check.\nJob ID: {job_id}\nTime: {datetime}\n\nRun the Box HTTP checks on the VM:\n ssh dev-operator-646@34.139.37.135 \"/srv/box/bin/box-health-check.sh http\"\n(or run /srv/box/bin/box-health-check.sh http via any VM access you have)\n\nAlso verify the new live Box Console endpoints:\n1. https://box.muse-dev.online/ (Front-Door Console loads, assets box.js and box.css return 200)\n2. https://box.muse-dev.online/api/box/fleet (Returns 200 with live fleet array)\n3. https://box.muse-dev.online/api/box/dm/log (Returns 200 with recent DM log entries)\n\nExpected: all OK. If any FAIL, investigate immediately (check board.service,\nCaddy, recent deploys) and include the failure lines in your reply.\n\nReply with OK or FAIL .", + "prompt_template": "Box HTTP endpoint health check.\nJob ID: {job_id}\nTime: {datetime}\n\nRun the fleet health check:\n[TOOL health.check {}]\n\nCheck recent scheduled runs:\n[TOOL cron.runs {}]\n\nIf all endpoints and fleet nodes return green, reply with [RESULT {job_id}] OK.\nOtherwise reply with [RESULT {job_id}] FAIL .", "schedule": "*/15 * * * *", "sidechat": { "create": true, - "name_template": "box-http-health-{datetime}" + "name_template": "box-http-health-{datetime}", + "reuse_key": "box-http-health" }, "timeout": 600 -} +} \ No newline at end of file diff --git a/jobs/box-service-health.json b/jobs/box-service-health.json index 14b0398..5e1c3d2 100644 --- a/jobs/box-service-health.json +++ b/jobs/box-service-health.json @@ -1,7 +1,7 @@ { "agent": "646", "chain_next": null, - "description": "Box service + data health — every 15 minutes (offset 7m)", + "description": "Box service + data health \u2014 every 15 minutes (offset 7m)", "followup": { "escalate": "opm", "expect_reply": true, @@ -11,11 +11,12 @@ }, "name": "box-service-health", "on_failure": "alert", - "prompt_template": "Box service health check.\nJob ID: {job_id}\nTime: {datetime}\n\nRun the Box service and data checks on the VM:\n ssh dev-operator-646@34.139.37.135 \"/srv/box/bin/box-health-check.sh services\"\n ssh dev-operator-646@34.139.37.135 \"/srv/box/bin/box-health-check.sh data\"\n(or run /srv/box/bin/box-health-check.sh via any VM access you have)\n\nExpected: board.service active, caddy active, sweeper timer firing,\n/srv/box writable. If any FAIL, investigate and include failure lines.\n\nReply with [RESULT {job_id}] OK or [RESULT {job_id}] FAIL .", + "prompt_template": "Box service and data health check.\nJob ID: {job_id}\nTime: {datetime}\n\nExecute the service check on the VM:\n[TOOL service.status {\"unit\": \"board.service\"}]\n\nCheck caddy and harvester timer status:\n[TOOL service.status {\"unit\": \"response-harvester.timer\"}]\n\nIf healthy, end with [RESULT {job_id}] OK.\nIf any service fails, reply with [RESULT {job_id}] FAIL .", "schedule": "7,22,37,52 * * * *", "sidechat": { "create": true, - "name_template": "box-service-health-{datetime}" + "name_template": "box-service-health-{datetime}", + "reuse_key": "box-service-health" }, "timeout": 600 } \ No newline at end of file