mirror of
https://github.com/freedomofpress/dangerzone.git
synced 2025-04-28 18:02:38 +02:00

The isolation provider `install()` method is now passed a `should_upgrade` argument, which is read from the settings and represents the user decision about updates. The tests have been updated to reflect these changes.
251 lines
7.8 KiB
Python
251 lines
7.8 KiB
Python
import os
|
|
import platform
|
|
|
|
import pytest
|
|
from pytest_mock import MockerFixture
|
|
from pytest_subprocess import FakeProcess
|
|
|
|
from dangerzone import errors
|
|
from dangerzone.container_utils import CONTAINER_NAME, Runtime
|
|
from dangerzone.isolation_provider.container import Container
|
|
from dangerzone.isolation_provider.qubes import is_qubes_native_conversion
|
|
from dangerzone.updater import SignatureError, UpdaterError
|
|
from dangerzone.util import get_resource_path
|
|
|
|
from .base import IsolationProviderTermination, IsolationProviderTest
|
|
|
|
# Run the tests in this module only if we can spawn containers.
|
|
if is_qubes_native_conversion():
|
|
pytest.skip("Qubes native conversion is enabled", allow_module_level=True)
|
|
elif os.environ.get("DUMMY_CONVERSION", False):
|
|
pytest.skip("Dummy conversion is enabled", allow_module_level=True)
|
|
|
|
|
|
@pytest.fixture
|
|
def provider() -> Container:
|
|
return Container()
|
|
|
|
|
|
@pytest.fixture
|
|
def runtime_path() -> str:
|
|
return str(Runtime().path)
|
|
|
|
|
|
class TestContainer(IsolationProviderTest):
|
|
def test_is_available_raises(
|
|
self, provider: Container, fp: FakeProcess, runtime_path: str
|
|
) -> None:
|
|
"""
|
|
NotAvailableContainerTechException should be raised when
|
|
the "podman image ls" command fails.
|
|
"""
|
|
fp.register_subprocess(
|
|
[runtime_path, "image", "ls"],
|
|
returncode=-1,
|
|
stderr="podman image ls logs",
|
|
)
|
|
with pytest.raises(errors.NotAvailableContainerTechException):
|
|
provider.is_available()
|
|
|
|
def test_is_available_works(
|
|
self, provider: Container, fp: FakeProcess, runtime_path: str
|
|
) -> None:
|
|
"""
|
|
No exception should be raised when the "podman image ls" can return properly.
|
|
"""
|
|
fp.register_subprocess(
|
|
[runtime_path, "image", "ls"],
|
|
)
|
|
provider.is_available()
|
|
|
|
def test_install_raise_if_local_image_cant_be_installed(
|
|
self,
|
|
provider: Container,
|
|
fp: FakeProcess,
|
|
runtime_path: str,
|
|
skip_image_verification,
|
|
mocker: MockerFixture,
|
|
) -> None:
|
|
"""When an image installation fails, an exception should be raised"""
|
|
|
|
fp.register_subprocess(
|
|
[runtime_path, "image", "ls"],
|
|
)
|
|
|
|
# First check should return nothing.
|
|
fp.register_subprocess(
|
|
[
|
|
runtime_path,
|
|
"image",
|
|
"list",
|
|
"--format",
|
|
"{{ .Tag }}",
|
|
CONTAINER_NAME,
|
|
],
|
|
occurrences=2,
|
|
)
|
|
mocker.patch(
|
|
"dangerzone.isolation_provider.container.install_local_container_tar",
|
|
side_effect=UpdaterError,
|
|
)
|
|
|
|
with pytest.raises(UpdaterError):
|
|
provider.install(should_upgrade=False)
|
|
|
|
def test_install_raise_if_local_image_cant_be_verified(
|
|
self,
|
|
provider: Container,
|
|
runtime_path: str,
|
|
skip_image_verification,
|
|
mocker: MockerFixture,
|
|
) -> None:
|
|
"""In case an image has been installed but its signature cannot be verified, an exception should be raised"""
|
|
|
|
mocker.patch(
|
|
"dangerzone.isolation_provider.container.container_utils.list_image_tags",
|
|
return_value=["a-tag"],
|
|
)
|
|
mocker.patch(
|
|
"dangerzone.isolation_provider.container.verify_local_image",
|
|
side_effect=SignatureError,
|
|
)
|
|
|
|
with pytest.raises(SignatureError):
|
|
provider.install(should_upgrade=False)
|
|
|
|
def test_install_raise_if_local_image_install_works_on_second_try(
|
|
self,
|
|
provider: Container,
|
|
runtime_path: str,
|
|
skip_image_verification,
|
|
mocker: MockerFixture,
|
|
) -> None:
|
|
"""In case an image has been installed but its signature cannot be verified, an exception should be raised"""
|
|
|
|
mocker.patch(
|
|
"dangerzone.isolation_provider.container.container_utils.list_image_tags",
|
|
return_value=["a-tag"],
|
|
)
|
|
mocker.patch(
|
|
"dangerzone.isolation_provider.container.verify_local_image",
|
|
side_effect=[SignatureError, True],
|
|
)
|
|
|
|
provider.install(should_upgrade=False)
|
|
|
|
def test_install_upgrades_if_available(
|
|
self,
|
|
provider: Container,
|
|
runtime_path: str,
|
|
skip_image_verification,
|
|
mocker: MockerFixture,
|
|
) -> None:
|
|
"""In case an image has been installed but its signature cannot be verified, an exception should be raised"""
|
|
|
|
mocker.patch(
|
|
"dangerzone.isolation_provider.container.container_utils.list_image_tags",
|
|
return_value=["a-tag"],
|
|
)
|
|
mocker.patch(
|
|
"dangerzone.isolation_provider.container.is_update_available",
|
|
return_value=(True, "digest"),
|
|
)
|
|
upgrade = mocker.patch(
|
|
"dangerzone.isolation_provider.container.upgrade_container_image",
|
|
)
|
|
mocker.patch(
|
|
"dangerzone.isolation_provider.container.verify_local_image",
|
|
)
|
|
|
|
provider.install(should_upgrade=True)
|
|
upgrade.assert_called()
|
|
|
|
@pytest.mark.skipif(
|
|
platform.system() not in ("Windows", "Darwin"),
|
|
reason="macOS and Windows specific",
|
|
)
|
|
def test_old_docker_desktop_version_is_detected(
|
|
self, mocker: MockerFixture, provider: Container, fp: FakeProcess
|
|
) -> None:
|
|
fp.register_subprocess(
|
|
[
|
|
"docker",
|
|
"version",
|
|
"--format",
|
|
"{{.Server.Platform.Name}}",
|
|
],
|
|
stdout="Docker Desktop 1.0.0 (173100)",
|
|
)
|
|
|
|
mocker.patch(
|
|
"dangerzone.isolation_provider.container.MINIMUM_DOCKER_DESKTOP",
|
|
{"Darwin": "1.0.1", "Windows": "1.0.1"},
|
|
)
|
|
assert (False, "1.0.0") == provider.check_docker_desktop_version()
|
|
|
|
@pytest.mark.skipif(
|
|
platform.system() not in ("Windows", "Darwin"),
|
|
reason="macOS and Windows specific",
|
|
)
|
|
def test_up_to_date_docker_desktop_version_is_detected(
|
|
self, mocker: MockerFixture, provider: Container, fp: FakeProcess
|
|
) -> None:
|
|
fp.register_subprocess(
|
|
[
|
|
"docker",
|
|
"version",
|
|
"--format",
|
|
"{{.Server.Platform.Name}}",
|
|
],
|
|
stdout="Docker Desktop 1.0.1 (173100)",
|
|
)
|
|
|
|
# Require version 1.0.1
|
|
mocker.patch(
|
|
"dangerzone.isolation_provider.container.MINIMUM_DOCKER_DESKTOP",
|
|
{"Darwin": "1.0.1", "Windows": "1.0.1"},
|
|
)
|
|
assert (True, "1.0.1") == provider.check_docker_desktop_version()
|
|
|
|
fp.register_subprocess(
|
|
[
|
|
"docker",
|
|
"version",
|
|
"--format",
|
|
"{{.Server.Platform.Name}}",
|
|
],
|
|
stdout="Docker Desktop 2.0.0 (173100)",
|
|
)
|
|
assert (True, "2.0.0") == provider.check_docker_desktop_version()
|
|
|
|
@pytest.mark.skipif(
|
|
platform.system() not in ("Windows", "Darwin"),
|
|
reason="macOS and Windows specific",
|
|
)
|
|
def test_docker_desktop_version_failure_returns_true(
|
|
self, mocker: MockerFixture, provider: Container, fp: FakeProcess
|
|
) -> None:
|
|
fp.register_subprocess(
|
|
[
|
|
"docker",
|
|
"version",
|
|
"--format",
|
|
"{{.Server.Platform.Name}}",
|
|
],
|
|
stderr="Oopsie",
|
|
returncode=1,
|
|
)
|
|
assert provider.check_docker_desktop_version() == (True, "")
|
|
|
|
@pytest.mark.skipif(
|
|
platform.system() != "Linux",
|
|
reason="Linux specific",
|
|
)
|
|
def test_linux_skips_desktop_version_check_returns_true(
|
|
self, provider: Container
|
|
) -> None:
|
|
assert (True, "") == provider.check_docker_desktop_version()
|
|
|
|
|
|
class TestContainerTermination(IsolationProviderTermination):
|
|
pass
|