#!/usr/bin/env python3 """All-in-one: generate seeds, rebuild secondary packs + core/daily, print DGA domains.""" from __future__ import annotations import argparse import json import secrets import subprocess import sys from pathlib import Path TOOLS = Path(__file__).resolve().parent LAB_ROOT = TOOLS.parent def gen_seed() -> str: """32 lowercase hex chars (fits the 32-byte seed slot).""" return secrets.token_hex(16) def run(cmd: list[str]) -> None: print("+", " ".join(cmd), flush=True) subprocess.run(cmd, cwd=str(LAB_ROOT), check=True) def main() -> int: parser = argparse.ArgumentParser( description=( "Generate Deployment/Reporting seeds, run patch_secondary_packs → " "patch_core → compute_dga_domains, print final domains." ) ) parser.add_argument( "--deployment-seed", help="optional; default: random 32 hex chars", ) parser.add_argument( "--reporting-seed", help="optional; default: random 32 hex chars", ) parser.add_argument( "--root", type=Path, help="project root with web/ + sync/ (required with --apply)", ) parser.add_argument( "--apply", action="store_true", help="pass --apply to patch_secondary_packs and patch_core (write into --root)", ) parser.add_argument( "-n", "--count", type=int, default=5, help="DGA candidates to print per pool (default 5)", ) args = parser.parse_args() if args.apply and not args.root: raise SystemExit("--apply requires --root ") dep = args.deployment_seed or gen_seed() rep = args.reporting_seed or gen_seed() if dep == rep: # avoid accidental identical pools while rep == dep: rep = gen_seed() out_root = (args.root.resolve() / "out") if args.root else (LAB_ROOT / "out") out_root.mkdir(parents=True, exist_ok=True) seeds_path = out_root / "seeds.json" seeds_path.write_text( json.dumps( { "deployment_seed": dep, "reporting_seed": rep, }, indent=2, ) + "\n" ) print("=== seeds ===") print(f"deployment: {dep}") print(f"reporting: {rep}") print(f"saved: {seeds_path}") if args.root: print(f"root: {args.root.resolve()}") print() py = sys.executable apply = ["--apply"] if args.apply else [] root = ["--root", str(args.root.resolve())] if args.root else [] print("=== 1/3 patch_secondary_packs ===") run( [ py, str(TOOLS / "patch_secondary_packs.py"), "--deployment-seed", dep, "--reporting-seed", rep, *root, *apply, ] ) print() print("=== 2/3 patch_core ===") run( [ py, str(TOOLS / "patch_core.py"), "--deployment-seed", dep, "--reporting-seed", rep, *root, *apply, ] ) print() print("=== 3/3 compute_dga_domains ===") result = subprocess.run( [ py, str(TOOLS / "compute_dga_domains.py"), "--deployment-seed", dep, "--reporting-seed", rep, "-n", str(args.count), "--json", ], cwd=str(LAB_ROOT), check=True, capture_output=True, text=True, ) domains = json.loads(result.stdout) domains_path = out_root / "domains.json" domains_path.write_text(json.dumps(domains, indent=2) + "\n") print() print("=== final domains ===") print(f"deployment seed={dep}") for i, domain in enumerate(domains["deployment"]["domains"], 1): print(f" {i:03d} {domain}") print(f"reporting seed={rep}") for i, domain in enumerate(domains["reporting"]["domains"], 1): print(f" {i:03d} {domain}") print() print(f"seeds: {seeds_path}") print(f"domains: {domains_path}") if not args.apply: print("Note: outputs are under out/ only. Use new_project.py or --apply --root .") return 0 if __name__ == "__main__": raise SystemExit(main())