mirror of
https://github.com/FuzzingLabs/fuzzforge_ai.git
synced 2026-02-12 17:12:46 +00:00
* fix: block Podman on macOS and remove ghcr.io default - Add platform check in PodmanCLI.__init__() that raises FuzzForgeError on macOS with instructions to use Docker instead - Change RegistrySettings.url default from "ghcr.io/fuzzinglabs" to "" (empty string) for local-only mode since no images are published yet - Update _ensure_module_image() to show helpful error when image not found locally and no registry configured - Update tests to mock Linux platform for Podman tests - Add root ruff.toml to fix broken configuration in fuzzforge-runner * rewrite guides for module architecture and update repo links --------- Co-authored-by: AFredefon <antoinefredefon@yahoo.fr>
150 lines
4.9 KiB
Python
150 lines
4.9 KiB
Python
"""Tests for the PodmanCLI engine (OSS container engine)."""
|
|
|
|
import os
|
|
import shutil
|
|
import sys
|
|
import uuid
|
|
from pathlib import Path
|
|
from unittest import mock
|
|
|
|
import pytest
|
|
|
|
from fuzzforge_common.exceptions import FuzzForgeError
|
|
from fuzzforge_common.sandboxes.engines.podman.cli import PodmanCLI, _is_running_under_snap
|
|
|
|
|
|
# Helper to mock Linux platform for testing (since Podman is Linux-only)
|
|
def _mock_linux_platform() -> mock._patch[str]:
|
|
"""Context manager to mock sys.platform as 'linux'."""
|
|
return mock.patch.object(sys, "platform", "linux")
|
|
|
|
|
|
@pytest.fixture
|
|
def podman_cli_engine() -> PodmanCLI:
|
|
"""Create a PodmanCLI engine with temporary storage.
|
|
|
|
Uses short paths in /tmp to avoid podman's 50-char runroot limit.
|
|
Simulates Snap environment to test custom storage paths.
|
|
Mocks Linux platform since Podman is Linux-only.
|
|
"""
|
|
short_id = str(uuid.uuid4())[:8]
|
|
graphroot = Path(f"/tmp/ff-{short_id}/storage")
|
|
runroot = Path(f"/tmp/ff-{short_id}/run")
|
|
|
|
# Simulate Snap environment for testing on Linux
|
|
with _mock_linux_platform(), mock.patch.dict(os.environ, {"SNAP": "/snap/code/123"}):
|
|
engine = PodmanCLI(graphroot=graphroot, runroot=runroot)
|
|
|
|
yield engine
|
|
|
|
# Cleanup
|
|
parent = graphroot.parent
|
|
if parent.exists():
|
|
shutil.rmtree(parent, ignore_errors=True)
|
|
|
|
|
|
def test_snap_detection_when_snap_set() -> None:
|
|
"""Test that SNAP environment is detected."""
|
|
with mock.patch.dict(os.environ, {"SNAP": "/snap/code/123"}):
|
|
assert _is_running_under_snap() is True
|
|
|
|
|
|
def test_snap_detection_when_snap_not_set() -> None:
|
|
"""Test that non-Snap environment is detected."""
|
|
env = os.environ.copy()
|
|
env.pop("SNAP", None)
|
|
with mock.patch.dict(os.environ, env, clear=True):
|
|
assert _is_running_under_snap() is False
|
|
|
|
|
|
def test_podman_cli_blocks_macos() -> None:
|
|
"""Test that PodmanCLI raises error on macOS."""
|
|
with mock.patch.object(sys, "platform", "darwin"):
|
|
with pytest.raises(FuzzForgeError) as exc_info:
|
|
PodmanCLI()
|
|
assert "Podman is not supported on macOS" in str(exc_info.value)
|
|
assert "Docker" in str(exc_info.value)
|
|
|
|
|
|
def test_podman_cli_creates_storage_directories_under_snap() -> None:
|
|
"""Test that PodmanCLI creates storage directories when under Snap."""
|
|
short_id = str(uuid.uuid4())[:8]
|
|
graphroot = Path(f"/tmp/ff-{short_id}/storage")
|
|
runroot = Path(f"/tmp/ff-{short_id}/run")
|
|
|
|
assert not graphroot.exists()
|
|
assert not runroot.exists()
|
|
|
|
with _mock_linux_platform(), mock.patch.dict(os.environ, {"SNAP": "/snap/code/123"}):
|
|
PodmanCLI(graphroot=graphroot, runroot=runroot)
|
|
|
|
assert graphroot.exists()
|
|
assert runroot.exists()
|
|
|
|
# Cleanup
|
|
shutil.rmtree(graphroot.parent, ignore_errors=True)
|
|
|
|
|
|
def test_podman_cli_base_cmd_under_snap() -> None:
|
|
"""Test that base command includes --root/--runroot under Snap."""
|
|
short_id = str(uuid.uuid4())[:8]
|
|
graphroot = Path(f"/tmp/ff-{short_id}/storage")
|
|
runroot = Path(f"/tmp/ff-{short_id}/run")
|
|
|
|
with _mock_linux_platform(), mock.patch.dict(os.environ, {"SNAP": "/snap/code/123"}):
|
|
engine = PodmanCLI(graphroot=graphroot, runroot=runroot)
|
|
base_cmd = engine._base_cmd()
|
|
|
|
assert "podman" in base_cmd
|
|
assert "--root" in base_cmd
|
|
assert "--runroot" in base_cmd
|
|
|
|
# Cleanup
|
|
shutil.rmtree(graphroot.parent, ignore_errors=True)
|
|
|
|
|
|
def test_podman_cli_base_cmd_without_snap() -> None:
|
|
"""Test that base command is plain 'podman' when not under Snap."""
|
|
short_id = str(uuid.uuid4())[:8]
|
|
graphroot = Path(f"/tmp/ff-{short_id}/storage")
|
|
runroot = Path(f"/tmp/ff-{short_id}/run")
|
|
|
|
env = os.environ.copy()
|
|
env.pop("SNAP", None)
|
|
with _mock_linux_platform(), mock.patch.dict(os.environ, env, clear=True):
|
|
engine = PodmanCLI(graphroot=graphroot, runroot=runroot)
|
|
base_cmd = engine._base_cmd()
|
|
|
|
assert base_cmd == ["podman"]
|
|
assert "--root" not in base_cmd
|
|
|
|
# Directories should NOT be created when not under Snap
|
|
assert not graphroot.exists()
|
|
|
|
|
|
def test_podman_cli_default_mode() -> None:
|
|
"""Test PodmanCLI without custom storage paths."""
|
|
with _mock_linux_platform():
|
|
engine = PodmanCLI() # No paths provided
|
|
base_cmd = engine._base_cmd()
|
|
|
|
assert base_cmd == ["podman"]
|
|
assert "--root" not in base_cmd
|
|
|
|
|
|
def test_podman_cli_list_images_returns_list(podman_cli_engine: PodmanCLI) -> None:
|
|
"""Test that list_images returns a list (even if empty)."""
|
|
images = podman_cli_engine.list_images()
|
|
|
|
assert isinstance(images, list)
|
|
|
|
|
|
@pytest.mark.skip(reason="Requires pulling images, slow integration test")
|
|
def test_podman_cli_can_pull_and_list_image(podman_cli_engine: PodmanCLI) -> None:
|
|
"""Test pulling an image and listing it."""
|
|
# Pull a small image
|
|
podman_cli_engine._run(["pull", "docker.io/library/alpine:latest"])
|
|
|
|
images = podman_cli_engine.list_images()
|
|
assert any("alpine" in img.identifier for img in images)
|