core-admin/qubespolicy/tests/rpcconfirmation.py
Marek Marczykowski-Górecki 68b6f1ec76
qubespolicy: use '@' instead of '$' for policy keywords
Using '$' is easy to misuse in shell scripts, shell commands etc. After
all this years, lets abandon this dangerous character and move to
something safer: '@'. The choice was made after reviewing specifications
of various shells on different operating systems and this is the
character that have no special meaning in none of them.

To preserve compatibility, automatically translate '$' to '@' when
loading policy files.
2018-02-19 03:33:40 +01:00

335 lines
12 KiB
Python
Executable File

#!/usr/bin/python
#
# The Qubes OS Project, https://www.qubes-os.org/
#
# Copyright (C) 2017 boring-stuff <boring-stuff@users.noreply.github.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, see <https://www.gnu.org/licenses/>.
#
import sys
import unittest
from qubespolicy.tests.gtkhelpers import GtkTestCase, FocusStealingHelperMock
from qubespolicy.tests.gtkhelpers import mock_domains_info, mock_whitelist
from qubespolicy.gtkhelpers import VMListModeler
from qubespolicy.rpcconfirmation import RPCConfirmationWindow
class MockRPCConfirmationWindow(RPCConfirmationWindow):
def _new_vm_list_modeler(self):
return VMListModeler(mock_domains_info)
def _new_focus_stealing_helper(self):
return FocusStealingHelperMock(
self._rpc_window,
self._rpc_ok_button,
self._focus_stealing_seconds)
def __init__(self, source, rpc_operation, whitelist,
target=None, focus_stealing_seconds=1):
self._focus_stealing_seconds = focus_stealing_seconds
RPCConfirmationWindow.__init__(
self, mock_domains_info, source, rpc_operation, whitelist,
target)
def is_error_visible(self):
return self._error_bar.get_visible()
def get_shown_domains(self):
model = self._rpc_combo_box.get_model()
model_iter = model.get_iter_first()
domains = []
while model_iter is not None:
domain_name = model.get_value(model_iter, 1)
domains += [domain_name]
model_iter = model.iter_next(model_iter)
return domains
class RPCConfirmationWindowTestBase(MockRPCConfirmationWindow, GtkTestCase):
def __init__(self, test_method, source_name="test-source",
rpc_operation="test.Operation", whitelist=mock_whitelist,
target_name=None):
GtkTestCase.__init__(self, test_method)
self.test_source_name = source_name
self.test_rpc_operation = rpc_operation
self.test_target_name = target_name
self._test_time = 0.1
self.test_called_close = False
self.test_called_show = False
self.test_clicked_ok = False
self.test_clicked_cancel = False
MockRPCConfirmationWindow.__init__(self,
self.test_source_name,
self.test_rpc_operation,
whitelist,
self.test_target_name,
focus_stealing_seconds=self._test_time)
def _can_perform_action(self):
return True
def _close(self):
self.test_called_close = True
def _show(self):
self.test_called_show = True
def _clicked_ok(self, button):
MockRPCConfirmationWindow._clicked_ok(self, button)
self.test_clicked_ok = True
def _clicked_cancel(self, button):
MockRPCConfirmationWindow._clicked_cancel(self, button)
self.test_clicked_cancel = True
def test_has_linked_the_fields(self):
self.assertIsNotNone(self._rpc_window)
self.assertIsNotNone(self._rpc_ok_button)
self.assertIsNotNone(self._rpc_cancel_button)
self.assertIsNotNone(self._rpc_label)
self.assertIsNotNone(self._source_entry)
self.assertIsNotNone(self._rpc_combo_box)
self.assertIsNotNone(self._error_bar)
self.assertIsNotNone(self._error_message)
def test_is_showing_source(self):
self.assertTrue(self.test_source_name in self._source_entry.get_text())
def test_is_showing_operation(self):
self.assertTrue(self.test_rpc_operation in self._rpc_label.get_text())
def test_escape_and_format_rpc_text(self):
self.assertEquals("qubes.<b>Test</b>",
self._escape_and_format_rpc_text("qubes.Test"))
self.assertEquals("custom.<b>Domain</b>",
self._escape_and_format_rpc_text("custom.Domain"))
self.assertEquals("<b>nodomain</b>",
self._escape_and_format_rpc_text("nodomain"))
self.assertEquals("domain.<b>Sub.Operation</b>",
self._escape_and_format_rpc_text("domain.Sub.Operation"))
self.assertEquals("<b></b>",
self._escape_and_format_rpc_text(""))
self.assertEquals("<b>.</b>",
self._escape_and_format_rpc_text("."))
self.assertEquals("inject.<b>&lt;script&gt;</b>",
self._escape_and_format_rpc_text("inject.<script>"))
self.assertEquals("&lt;script&gt;.<b>inject</b>",
self._escape_and_format_rpc_text("<script>.inject"))
def test_lifecycle_open_select_ok(self):
self._lifecycle_start(select_target=True)
self._lifecycle_click(click_type="ok")
def test_lifecycle_open_select_cancel(self):
self._lifecycle_start(select_target=True)
self._lifecycle_click(click_type="cancel")
def test_lifecycle_open_select_exit(self):
self._lifecycle_start(select_target=True)
self._lifecycle_click(click_type="exit")
def test_lifecycle_open_cancel(self):
self._lifecycle_start(select_target=False)
self._lifecycle_click(click_type="cancel")
def test_lifecycle_open_exit(self):
self._lifecycle_start(select_target=False)
self._lifecycle_click(click_type="exit")
def _lifecycle_click(self, click_type):
if click_type == "ok":
self._rpc_ok_button.clicked()
self.assertTrue(self.test_clicked_ok)
self.assertFalse(self.test_clicked_cancel)
self.assertTrue(self._confirmed)
self.assertIsNotNone(self._target_name)
elif click_type == "cancel":
self._rpc_cancel_button.clicked()
self.assertFalse(self.test_clicked_ok)
self.assertTrue(self.test_clicked_cancel)
self.assertFalse(self._confirmed)
elif click_type == "exit":
self._close()
self.assertFalse(self.test_clicked_ok)
self.assertFalse(self.test_clicked_cancel)
self.assertIsNone(self._confirmed)
self.assertTrue(self.test_called_close)
def _lifecycle_start(self, select_target):
self.assertFalse(self.test_called_close)
self.assertFalse(self.test_called_show)
self.assert_initial_state(False)
self.assertTrue(isinstance(self._focus_helper, FocusStealingHelperMock))
# Need the following because of pylint's complaints
if isinstance(self._focus_helper, FocusStealingHelperMock):
FocusStealingHelperMock.simulate_focus(self._focus_helper)
self.flush_gtk_events(self._test_time*2)
self.assert_initial_state(True)
try:
# We expect the call to exit immediately, since no window is opened
self.confirm_rpc()
except Exception:
pass
self.assertFalse(self.test_called_close)
self.assertTrue(self.test_called_show)
self.assert_initial_state(True)
if select_target:
self._rpc_combo_box.set_active(1)
self.assertTrue(self._rpc_ok_button.get_sensitive())
self.assertIsNotNone(self._target_name)
self.assertFalse(self.test_called_close)
self.assertTrue(self.test_called_show)
self.assertFalse(self.test_clicked_ok)
self.assertFalse(self.test_clicked_cancel)
self.assertFalse(self._confirmed)
def assert_initial_state(self, after_focus_timer):
self.assertIsNone(self._target_name)
self.assertFalse(self.test_clicked_ok)
self.assertFalse(self.test_clicked_cancel)
self.assertFalse(self._confirmed)
self.assertFalse(self._rpc_ok_button.get_sensitive())
self.assertFalse(self._error_bar.get_visible())
if after_focus_timer:
self.assertTrue(self._focus_helper.can_perform_action())
else:
self.assertFalse(self._focus_helper.can_perform_action())
class RPCConfirmationWindowTestWithTarget(RPCConfirmationWindowTestBase):
def __init__(self, test_method):
RPCConfirmationWindowTestBase.__init__(self, test_method,
source_name="test-source", rpc_operation="test.Operation",
target_name="test-target")
def test_lifecycle_open_ok(self):
self._lifecycle_start(select_target=False)
self._lifecycle_click(click_type="ok")
def assert_initial_state(self, after_focus_timer):
self.assertIsNotNone(self._target_name)
self.assertFalse(self.test_clicked_ok)
self.assertFalse(self.test_clicked_cancel)
self.assertFalse(self._confirmed)
if after_focus_timer:
self.assertTrue(self._rpc_ok_button.get_sensitive())
self.assertTrue(self._focus_helper.can_perform_action())
else:
self.assertFalse(self._rpc_ok_button.get_sensitive())
self.assertFalse(self._focus_helper.can_perform_action())
def _lifecycle_click(self, click_type):
RPCConfirmationWindowTestBase._lifecycle_click(self, click_type)
self.assertIsNotNone(self._target_name)
class RPCConfirmationWindowTestWithTargetInvalid(unittest.TestCase):
def __init__(self, *args, **kwargs):
unittest.TestCase.__init__(self, *args, **kwargs)
def test_unknown(self):
self.assert_raises_error(True, "test-source", "test-wrong-target")
def test_empty(self):
self.assert_raises_error(True, "test-source", "")
def test_equals_source(self):
self.assert_raises_error(True, "test-source", "test-source")
def assert_raises_error(self, expect, source, target):
rpcWindow = MockRPCConfirmationWindow(source, "test.Operation",
mock_whitelist, target=target)
self.assertEquals(expect, rpcWindow.is_error_visible())
class RPCConfirmationWindowTestWhitelist(unittest.TestCase):
def __init__(self, *args, **kwargs):
unittest.TestCase.__init__(self, *args, **kwargs)
def test_no_domains(self):
self._assert_whitelist([], [])
def test_all_red_domains(self):
self._assert_whitelist(["test-red1", "test-red2", "test-red3"],
["test-red1", "test-red2", "test-red3"])
def test_all_red_domains_plus_nonexistent(self):
self._assert_whitelist(
["test-red1", "test-red2", "test-red3",
"test-blue1", "test-blue2", "test-blue3"],
["test-red1", "test-red2", "test-red3"])
def test_all_allowed_domains(self):
self._assert_whitelist(
["test-red1", "test-red2", "test-red3",
"test-target", "@dispvm:test-disp6", "test-source", "dom0"],
["test-red1", "test-red2", "test-red3",
"test-target", "Disposable VM (test-disp6)", "test-source",
"dom0"])
def _assert_whitelist(self, whitelist, expected):
rpcWindow = MockRPCConfirmationWindow(
"test-source", "test.Operation", whitelist)
domains = rpcWindow.get_shown_domains()
self.assertCountEqual(domains, expected)
if __name__ == '__main__':
test = False
window = False
if len(sys.argv) == 1 or sys.argv[1] == '-t':
test = True
elif sys.argv[1] == '-w':
window = True
else:
print("Usage: " + __file__ + " [-t|-w]")
if window:
print(MockRPCConfirmationWindow("test-source",
"qubes.Filecopy",
mock_whitelist,
"test-red1").confirm_rpc())
elif test:
unittest.main(argv=[sys.argv[0]])