hte-cli 0.2.28__tar.gz → 0.2.29__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hte_cli-0.2.28 → hte_cli-0.2.29}/PKG-INFO +1 -1
- {hte_cli-0.2.28 → hte_cli-0.2.29}/pyproject.toml +1 -1
- {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/cli.py +211 -13
- {hte_cli-0.2.28 → hte_cli-0.2.29}/uv.lock +1 -1
- {hte_cli-0.2.28 → hte_cli-0.2.29}/.gitignore +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/README.md +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/__init__.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/__main__.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/api_client.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/config.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/errors.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/events.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/image_utils.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/runner.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/scorers.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/src/hte_cli/version_check.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/__init__.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/e2e/__init__.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/e2e/automated_runner.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/e2e/conftest.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/e2e/e2e_test.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/e2e/test_benchmark_flows.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/e2e/test_eval_logs.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/e2e/test_infrastructure.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/e2e/test_runtime_imports.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/e2e/test_session_lifecycle.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/e2e/verify_docker_deps.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/unit/__init__.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/unit/conftest.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/unit/test_image_utils.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/unit/test_runner.py +0 -0
- {hte_cli-0.2.28 → hte_cli-0.2.29}/tests/unit/test_scorers.py +0 -0
|
@@ -347,6 +347,7 @@ def session_join(ctx, session_id: str, force_setup: bool):
|
|
|
347
347
|
console.print(f"[bold]Step 2:[/bold] Pulling {len(images)} Docker image(s)...")
|
|
348
348
|
pull_start = time.monotonic()
|
|
349
349
|
pull_errors = {}
|
|
350
|
+
x86_images_on_arm = [] # Track x86 images that need QEMU
|
|
350
351
|
|
|
351
352
|
for img in images:
|
|
352
353
|
short_name = img.split("/")[-1][:40]
|
|
@@ -386,6 +387,25 @@ def session_join(ctx, session_id: str, force_setup: bool):
|
|
|
386
387
|
)
|
|
387
388
|
pulled_images.append(img)
|
|
388
389
|
continue
|
|
390
|
+
elif "failed to re-pull" in fix_msg:
|
|
391
|
+
# No ARM variant available - this is an x86-only image
|
|
392
|
+
# Re-pull the amd64 version and warn about QEMU
|
|
393
|
+
console.print(
|
|
394
|
+
f" [dim]No ARM variant available - re-pulling x86 version...[/dim]"
|
|
395
|
+
)
|
|
396
|
+
success = pull_image_with_progress(img)
|
|
397
|
+
if success:
|
|
398
|
+
console.print(
|
|
399
|
+
f" [yellow]![/yellow] {short_name} [dim](x86-only image, needs QEMU)[/dim]"
|
|
400
|
+
)
|
|
401
|
+
x86_images_on_arm.append(img)
|
|
402
|
+
pulled_images.append(img)
|
|
403
|
+
continue
|
|
404
|
+
else:
|
|
405
|
+
console.print(f" [red]✗[/red] {short_name} [dim](failed to pull)[/dim]")
|
|
406
|
+
failed_images.append(img)
|
|
407
|
+
pull_errors[img] = "failed to pull x86 fallback"
|
|
408
|
+
continue
|
|
389
409
|
else:
|
|
390
410
|
console.print(f" [red]✗[/red] {short_name} [dim]({fix_msg})[/dim]")
|
|
391
411
|
failed_images.append(img)
|
|
@@ -396,14 +416,9 @@ def session_join(ctx, session_id: str, force_setup: bool):
|
|
|
396
416
|
last_status = ["connecting..."]
|
|
397
417
|
last_error = [""]
|
|
398
418
|
|
|
399
|
-
#
|
|
400
|
-
#
|
|
419
|
+
# Use platform from compose if specified, otherwise let Docker decide
|
|
420
|
+
# (Docker will prefer native arch for multi-arch images, or pull what's available)
|
|
401
421
|
pull_platform = platform
|
|
402
|
-
if not pull_platform and is_linux_arm and host_platform:
|
|
403
|
-
pull_platform = host_platform
|
|
404
|
-
console.print(
|
|
405
|
-
f" [dim]Pulling {short_name} with platform {host_platform}...[/dim]"
|
|
406
|
-
)
|
|
407
422
|
|
|
408
423
|
with console.status(
|
|
409
424
|
f"[yellow]↓[/yellow] {short_name} [dim]connecting...[/dim]"
|
|
@@ -432,12 +447,28 @@ def session_join(ctx, session_id: str, force_setup: bool):
|
|
|
432
447
|
)
|
|
433
448
|
|
|
434
449
|
if success:
|
|
435
|
-
#
|
|
436
|
-
if is_linux_arm
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
450
|
+
# On Linux ARM64, verify pulled image architecture
|
|
451
|
+
if is_linux_arm:
|
|
452
|
+
from hte_cli.image_utils import get_image_architecture
|
|
453
|
+
pulled_arch = get_image_architecture(img)
|
|
454
|
+
|
|
455
|
+
if pulled_arch == "arm64":
|
|
456
|
+
console.print(
|
|
457
|
+
f" [green]✓[/green] {short_name} [dim](downloaded, arch: arm64)[/dim]"
|
|
458
|
+
)
|
|
459
|
+
elif pulled_arch == "amd64":
|
|
460
|
+
# x86 image on ARM host - needs QEMU emulation
|
|
461
|
+
console.print(
|
|
462
|
+
f" [yellow]![/yellow] {short_name} [dim](downloaded, arch: amd64)[/dim]"
|
|
463
|
+
)
|
|
464
|
+
console.print(
|
|
465
|
+
f" [yellow]This is an x86 image - requires QEMU emulation on ARM[/yellow]"
|
|
466
|
+
)
|
|
467
|
+
x86_images_on_arm.append(img)
|
|
468
|
+
else:
|
|
469
|
+
console.print(
|
|
470
|
+
f" [green]✓[/green] {short_name} [dim](downloaded)[/dim]"
|
|
471
|
+
)
|
|
441
472
|
else:
|
|
442
473
|
console.print(f" [green]✓[/green] {short_name} [dim](downloaded)[/dim]")
|
|
443
474
|
pulled_images.append(img)
|
|
@@ -458,6 +489,19 @@ def session_join(ctx, session_id: str, force_setup: bool):
|
|
|
458
489
|
)
|
|
459
490
|
console.print()
|
|
460
491
|
|
|
492
|
+
# Warn about x86 images on ARM that need QEMU
|
|
493
|
+
if x86_images_on_arm:
|
|
494
|
+
console.print(
|
|
495
|
+
f"[yellow]⚠ Warning:[/yellow] {len(x86_images_on_arm)} x86 image(s) detected on ARM host"
|
|
496
|
+
)
|
|
497
|
+
console.print(
|
|
498
|
+
" These require QEMU emulation. If container fails to start, run:"
|
|
499
|
+
)
|
|
500
|
+
console.print(
|
|
501
|
+
" [bold]docker run --privileged --rm tonistiigi/binfmt --install all[/bold]"
|
|
502
|
+
)
|
|
503
|
+
console.print()
|
|
504
|
+
|
|
461
505
|
# Fail fast if any required image couldn't be pulled
|
|
462
506
|
if failed_images:
|
|
463
507
|
console.print(
|
|
@@ -750,6 +794,160 @@ def tasks_pull_images(ctx, count: int):
|
|
|
750
794
|
console.print("[yellow]Image pulling not yet implemented.[/yellow]")
|
|
751
795
|
|
|
752
796
|
|
|
797
|
+
@cli.command("diagnose")
|
|
798
|
+
def diagnose_cmd():
|
|
799
|
+
"""
|
|
800
|
+
Diagnose Docker and architecture setup.
|
|
801
|
+
|
|
802
|
+
Checks Docker installation, architecture detection, and image compatibility.
|
|
803
|
+
Useful for troubleshooting before running tasks.
|
|
804
|
+
"""
|
|
805
|
+
import subprocess
|
|
806
|
+
import sys as system_module
|
|
807
|
+
from hte_cli.image_utils import (
|
|
808
|
+
get_host_architecture,
|
|
809
|
+
get_host_docker_platform,
|
|
810
|
+
is_running_in_linux_vm_on_arm,
|
|
811
|
+
get_image_architecture,
|
|
812
|
+
check_image_exists_locally,
|
|
813
|
+
)
|
|
814
|
+
|
|
815
|
+
console.print("[bold]HTE-CLI Diagnostics[/bold]")
|
|
816
|
+
console.print("=" * 50)
|
|
817
|
+
console.print()
|
|
818
|
+
|
|
819
|
+
# CLI version
|
|
820
|
+
console.print(f"[bold]CLI Version:[/bold] {__version__}")
|
|
821
|
+
console.print()
|
|
822
|
+
|
|
823
|
+
# Platform info
|
|
824
|
+
console.print("[bold]Platform:[/bold]")
|
|
825
|
+
host_arch = get_host_architecture()
|
|
826
|
+
host_platform = get_host_docker_platform()
|
|
827
|
+
is_linux_arm = is_running_in_linux_vm_on_arm()
|
|
828
|
+
|
|
829
|
+
console.print(f" OS: {system_module.platform}")
|
|
830
|
+
console.print(f" Architecture: {host_arch}")
|
|
831
|
+
console.print(f" Docker platform: {host_platform or 'unknown'}")
|
|
832
|
+
|
|
833
|
+
if is_linux_arm:
|
|
834
|
+
console.print()
|
|
835
|
+
console.print("[yellow]⚠ Linux ARM64 detected![/yellow]")
|
|
836
|
+
console.print(" This environment may have architecture compatibility issues.")
|
|
837
|
+
console.print(" The CLI will automatically handle multi-arch images.")
|
|
838
|
+
console.print(" For x86-only images (CTF challenges), QEMU emulation is required.")
|
|
839
|
+
console.print()
|
|
840
|
+
|
|
841
|
+
# Docker checks
|
|
842
|
+
console.print("[bold]Docker:[/bold]")
|
|
843
|
+
|
|
844
|
+
# Check Docker installed
|
|
845
|
+
try:
|
|
846
|
+
result = subprocess.run(
|
|
847
|
+
["docker", "--version"],
|
|
848
|
+
capture_output=True,
|
|
849
|
+
text=True,
|
|
850
|
+
timeout=10,
|
|
851
|
+
)
|
|
852
|
+
if result.returncode == 0:
|
|
853
|
+
console.print(f" [green]✓[/green] Docker: {result.stdout.strip()}")
|
|
854
|
+
else:
|
|
855
|
+
console.print(" [red]✗[/red] Docker not working")
|
|
856
|
+
except Exception as e:
|
|
857
|
+
console.print(f" [red]✗[/red] Docker not found: {e}")
|
|
858
|
+
|
|
859
|
+
# Check Docker daemon
|
|
860
|
+
try:
|
|
861
|
+
result = subprocess.run(
|
|
862
|
+
["docker", "info"],
|
|
863
|
+
capture_output=True,
|
|
864
|
+
text=True,
|
|
865
|
+
timeout=10,
|
|
866
|
+
)
|
|
867
|
+
if result.returncode == 0:
|
|
868
|
+
console.print(" [green]✓[/green] Docker daemon running")
|
|
869
|
+
else:
|
|
870
|
+
console.print(" [red]✗[/red] Docker daemon not running")
|
|
871
|
+
except Exception:
|
|
872
|
+
console.print(" [red]✗[/red] Cannot connect to Docker daemon")
|
|
873
|
+
|
|
874
|
+
# Check Compose version
|
|
875
|
+
try:
|
|
876
|
+
result = subprocess.run(
|
|
877
|
+
["docker", "compose", "version", "--short"],
|
|
878
|
+
capture_output=True,
|
|
879
|
+
text=True,
|
|
880
|
+
timeout=10,
|
|
881
|
+
)
|
|
882
|
+
if result.returncode == 0:
|
|
883
|
+
version = result.stdout.strip()
|
|
884
|
+
console.print(f" [green]✓[/green] Docker Compose: {version}")
|
|
885
|
+
else:
|
|
886
|
+
console.print(" [yellow]![/yellow] Docker Compose not available")
|
|
887
|
+
except Exception:
|
|
888
|
+
console.print(" [yellow]![/yellow] Docker Compose not found")
|
|
889
|
+
|
|
890
|
+
console.print()
|
|
891
|
+
|
|
892
|
+
# Test images
|
|
893
|
+
console.print("[bold]Image Architecture Test:[/bold]")
|
|
894
|
+
test_images = [
|
|
895
|
+
("python:3.12-slim", "multi-arch (nl2bash/cybashbench)"),
|
|
896
|
+
("cybench/cybench:latest", "x86-only (cybench/cybergym)"),
|
|
897
|
+
]
|
|
898
|
+
|
|
899
|
+
for image, description in test_images:
|
|
900
|
+
if check_image_exists_locally(image):
|
|
901
|
+
arch = get_image_architecture(image)
|
|
902
|
+
if arch:
|
|
903
|
+
if is_linux_arm and arch == "amd64":
|
|
904
|
+
console.print(
|
|
905
|
+
f" [yellow]![/yellow] {image}: {arch} [dim](x86 on ARM - needs QEMU)[/dim]"
|
|
906
|
+
)
|
|
907
|
+
else:
|
|
908
|
+
console.print(f" [green]✓[/green] {image}: {arch}")
|
|
909
|
+
else:
|
|
910
|
+
console.print(f" [dim]?[/dim] {image}: cached (unknown arch)")
|
|
911
|
+
else:
|
|
912
|
+
console.print(f" [dim]-[/dim] {image}: not cached - {description}")
|
|
913
|
+
|
|
914
|
+
console.print()
|
|
915
|
+
|
|
916
|
+
# QEMU check (for Linux ARM64)
|
|
917
|
+
if is_linux_arm:
|
|
918
|
+
console.print("[bold]QEMU Emulation:[/bold]")
|
|
919
|
+
try:
|
|
920
|
+
# Check if binfmt is set up for x86
|
|
921
|
+
result = subprocess.run(
|
|
922
|
+
["docker", "run", "--rm", "--platform", "linux/amd64", "alpine", "uname", "-m"],
|
|
923
|
+
capture_output=True,
|
|
924
|
+
text=True,
|
|
925
|
+
timeout=30,
|
|
926
|
+
)
|
|
927
|
+
if result.returncode == 0 and "x86_64" in result.stdout:
|
|
928
|
+
console.print(" [green]✓[/green] QEMU x86 emulation working")
|
|
929
|
+
else:
|
|
930
|
+
console.print(" [red]✗[/red] QEMU x86 emulation NOT working")
|
|
931
|
+
console.print()
|
|
932
|
+
console.print(" [yellow]To enable QEMU emulation, run:[/yellow]")
|
|
933
|
+
console.print(" [bold]docker run --privileged --rm tonistiigi/binfmt --install all[/bold]")
|
|
934
|
+
except subprocess.TimeoutExpired:
|
|
935
|
+
console.print(" [yellow]![/yellow] QEMU test timed out")
|
|
936
|
+
except Exception as e:
|
|
937
|
+
console.print(f" [red]✗[/red] QEMU test failed: {e}")
|
|
938
|
+
console.print()
|
|
939
|
+
|
|
940
|
+
console.print("[bold]Recommendation:[/bold]")
|
|
941
|
+
if is_linux_arm:
|
|
942
|
+
console.print(" For nl2bash/cybashbench: Should work with native ARM images")
|
|
943
|
+
console.print(" For CTF challenges (cybench, nyuctf, etc.): Requires QEMU emulation")
|
|
944
|
+
else:
|
|
945
|
+
console.print(" [green]✓[/green] Standard platform - all benchmarks should work")
|
|
946
|
+
|
|
947
|
+
console.print()
|
|
948
|
+
console.print("[dim]Run 'hte-cli session join <id>' to test with a real task[/dim]")
|
|
949
|
+
|
|
950
|
+
|
|
753
951
|
# =============================================================================
|
|
754
952
|
# Helper Functions
|
|
755
953
|
# =============================================================================
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|