mirror of
https://github.com/freedomofpress/dangerzone.git
synced 2025-04-28 18:02:38 +02:00
Extend the interface of the isolation provider
Add the following two methods in the isolation provider: 1. `.is_available()`: Mainly used for the Container isolation provider, it specifies whether the container runtime is up and running. May be used in the future by other similar providers. 2. `.should_wait_install()`: Whether the isolation provider takes a while to be installed. Should be `True` only for the Container isolation provider, for the time being.
This commit is contained in:
parent
e54567b7d4
commit
25fba42022
7 changed files with 38 additions and 22 deletions
|
@ -26,12 +26,10 @@ else:
|
||||||
from .. import errors
|
from .. import errors
|
||||||
from ..document import SAFE_EXTENSION, Document
|
from ..document import SAFE_EXTENSION, Document
|
||||||
from ..isolation_provider.container import (
|
from ..isolation_provider.container import (
|
||||||
Container,
|
|
||||||
NoContainerTechException,
|
NoContainerTechException,
|
||||||
NotAvailableContainerTechException,
|
NotAvailableContainerTechException,
|
||||||
)
|
)
|
||||||
from ..isolation_provider.dummy import Dummy
|
from ..isolation_provider.qubes import is_qubes_native_conversion
|
||||||
from ..isolation_provider.qubes import Qubes, is_qubes_native_conversion
|
|
||||||
from ..util import format_exception, get_resource_path, get_version
|
from ..util import format_exception, get_resource_path, get_version
|
||||||
from .logic import Alert, CollapsibleBox, DangerzoneGui, UpdateDialog
|
from .logic import Alert, CollapsibleBox, DangerzoneGui, UpdateDialog
|
||||||
from .updater import UpdateReport
|
from .updater import UpdateReport
|
||||||
|
@ -197,14 +195,11 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||||
header_layout.addWidget(self.hamburger_button)
|
header_layout.addWidget(self.hamburger_button)
|
||||||
header_layout.addSpacing(15)
|
header_layout.addSpacing(15)
|
||||||
|
|
||||||
if isinstance(self.dangerzone.isolation_provider, Container):
|
if self.dangerzone.isolation_provider.should_wait_install():
|
||||||
# Waiting widget replaces content widget while container runtime isn't available
|
# Waiting widget replaces content widget while container runtime isn't available
|
||||||
self.waiting_widget: WaitingWidget = WaitingWidgetContainer(self.dangerzone)
|
self.waiting_widget: WaitingWidget = WaitingWidgetContainer(self.dangerzone)
|
||||||
self.waiting_widget.finished.connect(self.waiting_finished)
|
self.waiting_widget.finished.connect(self.waiting_finished)
|
||||||
|
else:
|
||||||
elif isinstance(self.dangerzone.isolation_provider, Dummy) or isinstance(
|
|
||||||
self.dangerzone.isolation_provider, Qubes
|
|
||||||
):
|
|
||||||
# Don't wait with dummy converter and on Qubes.
|
# Don't wait with dummy converter and on Qubes.
|
||||||
self.waiting_widget = WaitingWidget()
|
self.waiting_widget = WaitingWidget()
|
||||||
self.dangerzone.is_waiting_finished = True
|
self.dangerzone.is_waiting_finished = True
|
||||||
|
@ -500,8 +495,7 @@ class WaitingWidgetContainer(WaitingWidget):
|
||||||
error: Optional[str] = None
|
error: Optional[str] = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
assert isinstance(self.dangerzone.isolation_provider, (Dummy, Container))
|
self.dangerzone.isolation_provider.is_available()
|
||||||
self.dangerzone.isolation_provider.is_runtime_available()
|
|
||||||
except NoContainerTechException as e:
|
except NoContainerTechException as e:
|
||||||
log.error(str(e))
|
log.error(str(e))
|
||||||
state = "not_installed"
|
state = "not_installed"
|
||||||
|
|
|
@ -254,6 +254,16 @@ class IsolationProvider(ABC):
|
||||||
)
|
)
|
||||||
return errors.exception_from_error_code(error_code)
|
return errors.exception_from_error_code(error_code)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def should_wait_install(self) -> bool:
|
||||||
|
"""Whether this isolation provider takes a lot of time to install."""
|
||||||
|
pass
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def is_available(self) -> bool:
|
||||||
|
"""Whether the backing implementation of the isolation provider is available."""
|
||||||
|
pass
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def get_max_parallel_conversions(self) -> int:
|
def get_max_parallel_conversions(self) -> int:
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -304,7 +304,11 @@ class Container(IsolationProvider):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_runtime_available() -> bool:
|
def should_wait_install() -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_available() -> bool:
|
||||||
container_runtime = Container.get_runtime()
|
container_runtime = Container.get_runtime()
|
||||||
runtime_name = Container.get_runtime_name()
|
runtime_name = Container.get_runtime_name()
|
||||||
# Can we run `docker/podman image ls` without an error
|
# Can we run `docker/podman image ls` without an error
|
||||||
|
|
|
@ -40,9 +40,13 @@ class Dummy(IsolationProvider):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def is_runtime_available() -> bool:
|
def is_available() -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def should_wait_install() -> bool:
|
||||||
|
return False
|
||||||
|
|
||||||
def start_doc_to_pixels_proc(self, document: Document) -> subprocess.Popen:
|
def start_doc_to_pixels_proc(self, document: Document) -> subprocess.Popen:
|
||||||
cmd = [
|
cmd = [
|
||||||
sys.executable,
|
sys.executable,
|
||||||
|
|
|
@ -21,6 +21,14 @@ class Qubes(IsolationProvider):
|
||||||
def install(self) -> bool:
|
def install(self) -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def is_available() -> bool:
|
||||||
|
return True
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def should_wait_install() -> bool:
|
||||||
|
return False
|
||||||
|
|
||||||
def get_max_parallel_conversions(self) -> int:
|
def get_max_parallel_conversions(self) -> int:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
|
@ -512,7 +512,7 @@ def test_not_available_container_tech_exception(
|
||||||
# Setup
|
# Setup
|
||||||
mock_app = mocker.MagicMock()
|
mock_app = mocker.MagicMock()
|
||||||
dummy = Dummy()
|
dummy = Dummy()
|
||||||
fn = mocker.patch.object(dummy, "is_runtime_available")
|
fn = mocker.patch.object(dummy, "is_available")
|
||||||
fn.side_effect = NotAvailableContainerTechException(
|
fn.side_effect = NotAvailableContainerTechException(
|
||||||
"podman", "podman image ls logs"
|
"podman", "podman image ls logs"
|
||||||
)
|
)
|
||||||
|
@ -536,7 +536,7 @@ def test_no_container_tech_exception(qtbot: QtBot, mocker: MockerFixture) -> Non
|
||||||
dummy = mocker.MagicMock()
|
dummy = mocker.MagicMock()
|
||||||
|
|
||||||
# Raise
|
# Raise
|
||||||
dummy.is_runtime_available.side_effect = NoContainerTechException("podman")
|
dummy.is_available.side_effect = NoContainerTechException("podman")
|
||||||
|
|
||||||
dz = DangerzoneGui(mock_app, dummy)
|
dz = DangerzoneGui(mock_app, dummy)
|
||||||
widget = WaitingWidgetContainer(dz)
|
widget = WaitingWidgetContainer(dz)
|
||||||
|
|
|
@ -27,9 +27,7 @@ def provider() -> Container:
|
||||||
|
|
||||||
|
|
||||||
class TestContainer(IsolationProviderTest):
|
class TestContainer(IsolationProviderTest):
|
||||||
def test_is_runtime_available_raises(
|
def test_is_available_raises(self, provider: Container, fp: FakeProcess) -> None:
|
||||||
self, provider: Container, fp: FakeProcess
|
|
||||||
) -> None:
|
|
||||||
"""
|
"""
|
||||||
NotAvailableContainerTechException should be raised when
|
NotAvailableContainerTechException should be raised when
|
||||||
the "podman image ls" command fails.
|
the "podman image ls" command fails.
|
||||||
|
@ -40,18 +38,16 @@ class TestContainer(IsolationProviderTest):
|
||||||
stderr="podman image ls logs",
|
stderr="podman image ls logs",
|
||||||
)
|
)
|
||||||
with pytest.raises(NotAvailableContainerTechException):
|
with pytest.raises(NotAvailableContainerTechException):
|
||||||
provider.is_runtime_available()
|
provider.is_available()
|
||||||
|
|
||||||
def test_is_runtime_available_works(
|
def test_is_available_works(self, provider: Container, fp: FakeProcess) -> None:
|
||||||
self, provider: Container, fp: FakeProcess
|
|
||||||
) -> None:
|
|
||||||
"""
|
"""
|
||||||
No exception should be raised when the "podman image ls" can return properly.
|
No exception should be raised when the "podman image ls" can return properly.
|
||||||
"""
|
"""
|
||||||
fp.register_subprocess(
|
fp.register_subprocess(
|
||||||
[provider.get_runtime(), "image", "ls"],
|
[provider.get_runtime(), "image", "ls"],
|
||||||
)
|
)
|
||||||
provider.is_runtime_available()
|
provider.is_available()
|
||||||
|
|
||||||
def test_install_raise_if_image_cant_be_installed(
|
def test_install_raise_if_image_cant_be_installed(
|
||||||
self, mocker: MockerFixture, provider: Container, fp: FakeProcess
|
self, mocker: MockerFixture, provider: Container, fp: FakeProcess
|
||||||
|
|
Loading…
Reference in a new issue