"""Audit dead push-PATs in fleet_deploy.json (read-only, no side effects).""" import json import os import sys import urllib.error import urllib.request FLEET = r"C:\Users\User\Desktop\keyhunter\data\fleet_deploy.json" fleet = json.load(open(FLEET, encoding="utf-8")) ok_nodes = [r for r in fleet if r.get("ok")] print(f"Fleet: {len(fleet)} total, {len(ok_nodes)} ok") dead = [] for i, rec in enumerate(ok_nodes): tok = rec.get("pat", "") if not tok: dead.append((rec["login"], rec.get("repo", "?"), "no-push-pat")) continue req = urllib.request.Request( "https://api.github.com/user", headers={"Authorization": "Bearer " + tok, "Accept": "application/vnd.github+json", "User-Agent": "keyfarm-audit", "X-GitHub-Api-Version": "2022-11-28"}) try: with urllib.request.urlopen(req, timeout=15) as r: pass except urllib.error.HTTPError as e: if e.code == 401: dead.append((rec["login"], rec.get("repo", "?"), "401")) elif e.code in (403, 429): dead.append((rec["login"], rec.get("repo", "?"), f"{e.code}-blocked")) else: dead.append((rec["login"], rec.get("repo", "?"), f"HTTP-{e.code}")) except Exception as e: dead.append((rec["login"], rec.get("repo", "?"), type(e).__name__)) if (i + 1) % 100 == 0: print(f" {i+1}/{len(ok_nodes)} checked, {len(dead)} dead", flush=True) print(f"\nDead push-PATs: {len(dead)}") for login, repo, reason in dead[:50]: print(f" {login}/{repo}: {reason}") if len(dead) > 50: print(f" ... and {len(dead)-50} more")