Download ghidra-re-loop/progress.py from Luminia/README: direct link, hf CLI and curl.
- Browser
- Download file 5.8 kB
-
https://huggingface.co/spaces/Luminia/README/resolve/main/ghidra-re-loop/progress.py
- Command line
-
hf download hf://spaces/Luminia/README/ghidra-re-loop/progress.py
-
curl -L -o progress.py https://huggingface.co/spaces/Luminia/README/resolve/main/ghidra-re-loop/progress.py
5.8 kB
| #!/usr/bin/env python3 | |
| """Session / progress tracker — adapted port of auto-re-agent's core/session.py, | |
| reports/tracker.py, and reports/formatter.py. JSON-backed, append-only, atomic | |
| writes. Mirrors the original's REPORT format so runs are resumable and progress | |
| claims are auditable against recorded tool evidence (never the model's memory). | |
| A "function" record = one analysis target (a gate/feature/function) the loop has | |
| attempted, keyed by normalized address. Record after EACH attempt so a crash or | |
| new session resumes where it left off. | |
| Usage: | |
| python progress.py record --file re-progress.json --address 0x401abc \ | |
| --name "CLicense::Validate" --component license \ | |
| --success true --rounds 2 --verdict PASS --parity GREEN \ | |
| --objective PASS --note "jz at 0x401ad0 gates the dialog" | |
| python progress.py summary --file re-progress.json | |
| python progress.py table --file re-progress.json [--component license] | |
| python progress.py attempted --file re-progress.json --address 0x401abc # exit 0 if attempted | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import sys | |
| import time | |
| from pathlib import Path | |
| def norm_addr(a: str) -> str: | |
| a = a.strip().lower() | |
| if a.startswith("0x"): | |
| try: | |
| return hex(int(a, 16)) | |
| except ValueError: | |
| return a | |
| return a | |
| class Session: | |
| def __init__(self, path: str | Path): | |
| self.path = Path(path) | |
| self.data = {"functions": {}, "runs": []} | |
| if self.path.exists(): | |
| try: | |
| self.data = json.loads(self.path.read_text(encoding="utf-8")) | |
| except (json.JSONDecodeError, OSError): | |
| pass | |
| self.data.setdefault("functions", {}) | |
| self.data.setdefault("runs", []) | |
| def save(self): | |
| self.path.parent.mkdir(parents=True, exist_ok=True) | |
| tmp = self.path.with_suffix(".tmp") | |
| tmp.write_text(json.dumps(self.data, indent=2), encoding="utf-8") | |
| tmp.replace(self.path) | |
| def record(self, entry: dict): | |
| addr = norm_addr(entry["address"]) | |
| entry["timestamp"] = time.strftime("%Y-%m-%dT%H:%M:%S") | |
| self.data["functions"][addr] = entry | |
| self.data["runs"].append(entry) | |
| self.save() | |
| def is_attempted(self, address: str) -> bool: | |
| return norm_addr(address) in self.data["functions"] | |
| def summary(self) -> dict: | |
| funcs = self.data["functions"].values() | |
| total = len(self.data["functions"]) | |
| passed = sum(1 for f in funcs if f.get("success")) | |
| comps = {f.get("component", "") for f in funcs if f.get("component")} | |
| return {"total": total, "passed": passed, "failed": total - passed, | |
| "components": len(comps)} | |
| def table(self, component: str | None): | |
| rows = [] | |
| for f in self.data["functions"].values(): | |
| if component and f.get("component") != component: | |
| continue | |
| rows.append(f) | |
| return rows | |
| def _b(v: str | None) -> bool: | |
| return str(v).lower() in {"1", "true", "yes", "pass", "y"} | |
| def cmd_record(a): | |
| s = Session(a.file) | |
| s.record({ | |
| "address": a.address, | |
| "function_name": a.name or "", | |
| "component": a.component or "", | |
| "success": _b(a.success), | |
| "rounds_used": a.rounds, | |
| "verdict": a.verdict, | |
| "objective_verdict": a.objective, | |
| "parity_status": a.parity, | |
| "note": a.note or "", | |
| }) | |
| print(f"recorded {norm_addr(a.address)} ({'PASS' if _b(a.success) else 'FAIL'})") | |
| return 0 | |
| def cmd_summary(a): | |
| s = Session(a.file) | |
| su = s.summary() | |
| print("RE Progress Summary") | |
| print("=" * 40) | |
| print(f"Total targets: {su['total']}") | |
| print(f"Passed: {su['passed']}") | |
| print(f"Failed: {su['failed']}") | |
| print(f"Components: {su['components']}") | |
| return 0 | |
| def cmd_table(a): | |
| s = Session(a.file) | |
| rows = s.table(a.component) | |
| print("| Address | Function | Comp | Status | Rounds | Parity | Obj |") | |
| print("|---------|----------|------|--------|--------|--------|-----|") | |
| for f in rows: | |
| st = "PASS" if f.get("success") else "FAIL" | |
| print(f"| {f.get('address','')} | {f.get('function_name','')} | " | |
| f"{f.get('component','')} | {st} | {f.get('rounds_used','')} | " | |
| f"{f.get('parity_status') or '-'} | {f.get('objective_verdict') or '-'} |") | |
| return 0 | |
| def cmd_attempted(a): | |
| return 0 if Session(a.file).is_attempted(a.address) else 1 | |
| def main() -> int: | |
| ap = argparse.ArgumentParser(description=__doc__, | |
| formatter_class=argparse.RawDescriptionHelpFormatter) | |
| sub = ap.add_subparsers(dest="cmd", required=True) | |
| r = sub.add_parser("record") | |
| r.add_argument("--file", required=True) | |
| r.add_argument("--address", required=True) | |
| r.add_argument("--name", default="") | |
| r.add_argument("--component", default="") | |
| r.add_argument("--success", default="false") | |
| r.add_argument("--rounds", type=int, default=0) | |
| r.add_argument("--verdict", default=None) | |
| r.add_argument("--objective", default=None) | |
| r.add_argument("--parity", default=None) | |
| r.add_argument("--note", default="") | |
| r.set_defaults(fn=cmd_record) | |
| for name, fn in (("summary", cmd_summary), ("table", cmd_table)): | |
| p = sub.add_parser(name) | |
| p.add_argument("--file", required=True) | |
| if name == "table": | |
| p.add_argument("--component", default=None) | |
| p.set_defaults(fn=fn) | |
| at = sub.add_parser("attempted") | |
| at.add_argument("--file", required=True) | |
| at.add_argument("--address", required=True) | |
| at.set_defaults(fn=cmd_attempted) | |
| a = ap.parse_args() | |
| return a.fn(a) | |
| if __name__ == "__main__": | |
| sys.exit(main()) | |