(args)
| 946 | |
| 947 | |
| 948 | def _cmd_run(args) -> int: |
| 949 | # Resolve target |
| 950 | try: |
| 951 | target_dir = _resolve_target_dir(args.target) |
| 952 | target = TargetConfig.load(target_dir) |
| 953 | except Exception as e: |
| 954 | print(f"error: {e}", file=sys.stderr) |
| 955 | return 1 |
| 956 | global _current_target_name |
| 957 | _current_target_name = target.name |
| 958 | |
| 959 | agent_env = _resolve_auth_env() |
| 960 | if agent_env is None: |
| 961 | print(NO_AUTH_MSG, file=sys.stderr) |
| 962 | return 1 |
| 963 | |
| 964 | # Model: required, via --model or env |
| 965 | if not args.model: |
| 966 | print("error: --model required (or set VULN_PIPELINE_MODEL)", file=sys.stderr) |
| 967 | return 1 |
| 968 | |
| 969 | print(f"Target: {target.name}") |
| 970 | print(f" image_tag: {target.image_tag}") |
| 971 | print(f" model: {args.model}") |
| 972 | print(f" binary: {target.binary_path}") |
| 973 | print(f" source_root: {target.source_root}") |
| 974 | print(f" max_turns: {args.max_turns}") |
| 975 | print(f" runs: {args.runs}{' (parallel)' if args.parallel else ''}") |
| 976 | print(f" find_only: {args.find_only}") |
| 977 | if target.focus_areas and not args.auto_focus: |
| 978 | print(f" focus_areas: {len(target.focus_areas)} configured") |
| 979 | if args.auto_focus: |
| 980 | print(" auto_focus: True (recon will discover focus areas)") |
| 981 | print() |
| 982 | |
| 983 | if args.resume: |
| 984 | results_root = args.resume |
| 985 | if not results_root.is_dir(): |
| 986 | print(f"error: --resume dir {results_root} does not exist", file=sys.stderr) |
| 987 | return 1 |
| 988 | if (err := _resume_layout_error(results_root, args.runs)): |
| 989 | print(f"error: {err}", file=sys.stderr) |
| 990 | return 1 |
| 991 | print(f" resume: {results_root}") |
| 992 | else: |
| 993 | timestamp = datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ") |
| 994 | results_root = Path(args.results_dir) / target.name / timestamp |
| 995 | |
| 996 | pairs = asyncio.run(_run_all(target, args, agent_env, results_root)) |
| 997 | |
| 998 | print("\n── Summary ────────────────────────────────────────────────────────────────────") |
| 999 | exit_code = 0 |
| 1000 | for i, (out_dir, result) in enumerate(pairs): |
| 1001 | # result.json was already written inside _run_once as each run |
| 1002 | # finished. Rewrite here only for the error-path entries gather |
| 1003 | # synthesized (those never hit _run_once's _done()). |
| 1004 | if result.status == "error": |
| 1005 | _write_result(out_dir, result) |
no test coverage detected