2020-09-03 19:56:15 +02:00
|
|
|
from unittest import mock
|
|
|
|
import argparse
|
|
|
|
import asyncio
|
|
|
|
import datetime
|
|
|
|
import io
|
|
|
|
import os
|
|
|
|
import pathlib
|
|
|
|
import subprocess
|
|
|
|
import tempfile
|
|
|
|
|
|
|
|
import rpm
|
|
|
|
|
|
|
|
import qubesadmin.tests
|
|
|
|
import qubesadmin.tools.qvm_template
|
|
|
|
|
|
|
|
class TC_00_qvm_template(qubesadmin.tests.QubesTestCase):
|
|
|
|
def setUp(self):
|
|
|
|
super().setUp()
|
|
|
|
|
|
|
|
def tearDown(self):
|
|
|
|
super().tearDown()
|
|
|
|
|
|
|
|
def test_000_verify_rpm_success(self):
|
|
|
|
ts = mock.MagicMock()
|
|
|
|
# Just return a dict instead of rpm.hdr
|
|
|
|
hdr = {
|
|
|
|
rpm.RPMTAG_SIGPGP: 'xxx', # non-empty
|
|
|
|
rpm.RPMTAG_SIGGPG: 'xxx', # non-empty
|
|
|
|
}
|
|
|
|
ts.hdrFromFdno.return_value = hdr
|
|
|
|
ret = qubesadmin.tools.qvm_template.verify_rpm('/dev/null', ts)
|
|
|
|
ts.hdrFromFdno.assert_called_once()
|
|
|
|
self.assertEqual(hdr, ret)
|
|
|
|
self.assertAllCalled()
|
|
|
|
|
|
|
|
def test_001_verify_rpm_nosig_fail(self):
|
|
|
|
ts = mock.MagicMock()
|
|
|
|
# Just return a dict instead of rpm.hdr
|
|
|
|
hdr = {
|
|
|
|
rpm.RPMTAG_SIGPGP: None, # empty
|
|
|
|
rpm.RPMTAG_SIGGPG: None, # empty
|
|
|
|
}
|
|
|
|
ts.hdrFromFdno.return_value = hdr
|
|
|
|
ret = qubesadmin.tools.qvm_template.verify_rpm('/dev/null', ts)
|
|
|
|
ts.hdrFromFdno.assert_called_once()
|
|
|
|
self.assertEqual(ret, None)
|
|
|
|
self.assertAllCalled()
|
|
|
|
|
|
|
|
def test_002_verify_rpm_nosig_success(self):
|
|
|
|
ts = mock.MagicMock()
|
|
|
|
# Just return a dict instead of rpm.hdr
|
|
|
|
hdr = {
|
|
|
|
rpm.RPMTAG_SIGPGP: None, # empty
|
|
|
|
rpm.RPMTAG_SIGGPG: None, # empty
|
|
|
|
}
|
|
|
|
ts.hdrFromFdno.return_value = hdr
|
|
|
|
ret = qubesadmin.tools.qvm_template.verify_rpm('/dev/null', ts, True)
|
|
|
|
ts.hdrFromFdno.assert_called_once()
|
|
|
|
self.assertEqual(ret, hdr)
|
|
|
|
self.assertAllCalled()
|
|
|
|
|
|
|
|
def test_003_verify_rpm_badsig_fail(self):
|
|
|
|
ts = mock.MagicMock()
|
|
|
|
def f(*args):
|
|
|
|
raise rpm.error('public key not trusted')
|
|
|
|
ts.hdrFromFdno.side_effect = f
|
|
|
|
ret = qubesadmin.tools.qvm_template.verify_rpm('/dev/null', ts)
|
|
|
|
ts.hdrFromFdno.assert_called_once()
|
|
|
|
self.assertEqual(ret, None)
|
|
|
|
self.assertAllCalled()
|
|
|
|
|
|
|
|
@mock.patch('subprocess.Popen')
|
|
|
|
def test_010_extract_rpm_success(self, mock_popen):
|
|
|
|
pipe = mock.Mock()
|
|
|
|
mock_popen.return_value.stdout = pipe
|
|
|
|
mock_popen.return_value.wait.return_value = 0
|
|
|
|
with tempfile.NamedTemporaryFile() as fd, \
|
|
|
|
tempfile.TemporaryDirectory() as dir:
|
|
|
|
path = fd.name
|
|
|
|
dirpath = dir
|
|
|
|
ret = qubesadmin.tools.qvm_template.extract_rpm(
|
|
|
|
'test-vm', path, dirpath)
|
|
|
|
self.assertEqual(ret, True)
|
|
|
|
self.assertEqual(mock_popen.mock_calls, [
|
|
|
|
mock.call(['rpm2cpio', path], stdout=subprocess.PIPE),
|
|
|
|
mock.call([
|
|
|
|
'cpio',
|
|
|
|
'-idm',
|
|
|
|
'-D',
|
|
|
|
dirpath,
|
|
|
|
'./var/lib/qubes/vm-templates/test-vm/*'
|
|
|
|
], stdin=pipe, stdout=subprocess.DEVNULL),
|
|
|
|
mock.call().wait(),
|
|
|
|
mock.call().wait()
|
|
|
|
])
|
|
|
|
self.assertAllCalled()
|
|
|
|
|
|
|
|
@mock.patch('subprocess.Popen')
|
|
|
|
def test_011_extract_rpm_fail(self, mock_popen):
|
|
|
|
pipe = mock.Mock()
|
|
|
|
mock_popen.return_value.stdout = pipe
|
|
|
|
mock_popen.return_value.wait.return_value = 1
|
|
|
|
with tempfile.NamedTemporaryFile() as fd, \
|
|
|
|
tempfile.TemporaryDirectory() as dir:
|
|
|
|
path = fd.name
|
|
|
|
dirpath = dir
|
|
|
|
ret = qubesadmin.tools.qvm_template.extract_rpm(
|
|
|
|
'test-vm', path, dirpath)
|
|
|
|
self.assertEqual(ret, False)
|
|
|
|
self.assertEqual(mock_popen.mock_calls, [
|
|
|
|
mock.call(['rpm2cpio', path], stdout=subprocess.PIPE),
|
|
|
|
mock.call([
|
|
|
|
'cpio',
|
|
|
|
'-idm',
|
|
|
|
'-D',
|
|
|
|
dirpath,
|
|
|
|
'./var/lib/qubes/vm-templates/test-vm/*'
|
|
|
|
], stdin=pipe, stdout=subprocess.DEVNULL),
|
|
|
|
mock.call().wait()
|
|
|
|
])
|
|
|
|
self.assertAllCalled()
|
|
|
|
|
|
|
|
def add_new_vm_side_effect(self, *args, **kwargs):
|
|
|
|
self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \
|
|
|
|
b'0\0test-vm class=TemplateVM state=Halted\n'
|
|
|
|
self.app.domains.clear_cache()
|
|
|
|
return self.app.domains['test-vm']
|
|
|
|
|
|
|
|
@mock.patch('os.remove')
|
|
|
|
@mock.patch('os.rename')
|
|
|
|
@mock.patch('os.makedirs')
|
|
|
|
@mock.patch('subprocess.check_call')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.confirm_action')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.extract_rpm')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.download')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.get_dl_list')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.verify_rpm')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.rpm_transactionset')
|
|
|
|
def test_100_install_local_success(
|
|
|
|
self,
|
|
|
|
mock_ts,
|
|
|
|
mock_verify,
|
|
|
|
mock_dl_list,
|
|
|
|
mock_dl,
|
|
|
|
mock_extract,
|
|
|
|
mock_confirm,
|
|
|
|
mock_call,
|
|
|
|
mock_mkdirs,
|
|
|
|
mock_rename,
|
|
|
|
mock_remove):
|
|
|
|
self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = b'0\0'
|
2020-09-06 17:57:42 +02:00
|
|
|
build_time = '2020-09-01 14:30:00' # 1598970600
|
|
|
|
install_time = '2020-09-01 15:30:00'
|
2020-09-03 19:56:15 +02:00
|
|
|
for key, val in [
|
|
|
|
('name', 'test-vm'),
|
|
|
|
('epoch', '2'),
|
|
|
|
('version', '4.1'),
|
|
|
|
('release', '2020'),
|
|
|
|
('reponame', '@commandline'),
|
|
|
|
('buildtime', build_time),
|
|
|
|
('installtime', install_time),
|
|
|
|
('license', 'GPL'),
|
|
|
|
('url', 'https://qubes-os.org'),
|
|
|
|
('summary', 'Summary'),
|
|
|
|
('description', 'Desc|desc')]:
|
|
|
|
self.app.expected_calls[(
|
|
|
|
'test-vm',
|
|
|
|
'admin.vm.feature.Set',
|
|
|
|
f'template-{key}',
|
|
|
|
val.encode())] = b'0\0'
|
|
|
|
mock_verify.return_value = {
|
|
|
|
rpm.RPMTAG_NAME : 'qubes-template-test-vm',
|
|
|
|
rpm.RPMTAG_BUILDTIME : 1598970600,
|
|
|
|
rpm.RPMTAG_DESCRIPTION : 'Desc\ndesc',
|
|
|
|
rpm.RPMTAG_EPOCHNUM : 2,
|
|
|
|
rpm.RPMTAG_LICENSE : 'GPL',
|
|
|
|
rpm.RPMTAG_RELEASE : '2020',
|
|
|
|
rpm.RPMTAG_SUMMARY : 'Summary',
|
|
|
|
rpm.RPMTAG_URL : 'https://qubes-os.org',
|
|
|
|
rpm.RPMTAG_VERSION : '4.1'
|
|
|
|
}
|
|
|
|
mock_dl_list.return_value = {}
|
|
|
|
mock_call.side_effect = self.add_new_vm_side_effect
|
|
|
|
mock_time = mock.Mock(wraps=datetime.datetime)
|
|
|
|
mock_time.today.return_value = \
|
|
|
|
datetime.datetime.fromisoformat(install_time)
|
|
|
|
with mock.patch('builtins.open', mock.mock_open()) as mock_open, \
|
|
|
|
mock.patch('datetime.datetime', new=mock_time), \
|
|
|
|
mock.patch('tempfile.TemporaryDirectory') as mock_tmpdir, \
|
|
|
|
mock.patch('sys.stderr', new=io.StringIO()) as mock_err, \
|
|
|
|
tempfile.NamedTemporaryFile(suffix='.rpm') as template_file:
|
|
|
|
path = template_file.name
|
|
|
|
args = argparse.Namespace(
|
|
|
|
templates=[path],
|
|
|
|
keyring='/usr/share/qubes/repo-templates/keys',
|
|
|
|
nogpgcheck=False,
|
|
|
|
cachedir='/var/cache/qvm-template',
|
|
|
|
yes=False,
|
|
|
|
allow_pv=False,
|
|
|
|
pool=None
|
|
|
|
)
|
|
|
|
mock_tmpdir.return_value.__enter__.return_value = \
|
|
|
|
'/var/tmp/qvm-template-tmpdir'
|
|
|
|
qubesadmin.tools.qvm_template.install(args, self.app)
|
|
|
|
# Lock file created
|
|
|
|
self.assertEqual(mock_open.mock_calls, [
|
|
|
|
mock.call('/var/tmp/qvm-template.lck', 'x'),
|
|
|
|
mock.call().__enter__(),
|
|
|
|
mock.call().__exit__(None, None, None)
|
|
|
|
])
|
|
|
|
# Keyring created
|
|
|
|
self.assertEqual(mock_ts.mock_calls, [
|
|
|
|
mock.call('/usr/share/qubes/repo-templates/keys')
|
|
|
|
])
|
|
|
|
# Package verified
|
|
|
|
self.assertEqual(mock_verify.mock_calls, [
|
|
|
|
mock.call(path, mock_ts('/usr/share/qubes/repo-templates/keys'),
|
|
|
|
False)
|
|
|
|
])
|
|
|
|
# Attempt to get download list
|
|
|
|
selector = qubesadmin.tools.qvm_template.VersionSelector.LATEST
|
|
|
|
self.assertEqual(mock_dl_list.mock_calls, [
|
|
|
|
mock.call(args, self.app, version_selector=selector)
|
|
|
|
])
|
|
|
|
# Nothing downloaded
|
|
|
|
self.assertEqual(mock_dl.mock_calls, [
|
|
|
|
mock.call(args, self.app, path_override='/var/cache/qvm-template',
|
|
|
|
dl_list={}, suffix='.unverified', version_selector=selector)
|
|
|
|
])
|
|
|
|
# Package is extracted
|
|
|
|
self.assertEqual(mock_extract.mock_calls, [
|
|
|
|
mock.call('test-vm', path, '/var/tmp/qvm-template-tmpdir')
|
|
|
|
])
|
|
|
|
# No packages overwritten, so no confirm needed
|
|
|
|
self.assertEqual(mock_confirm.mock_calls, [])
|
|
|
|
# qvm-template-postprocess is called
|
|
|
|
self.assertEqual(mock_call.mock_calls, [
|
|
|
|
mock.call([
|
|
|
|
'qvm-template-postprocess',
|
|
|
|
'--really',
|
|
|
|
'--no-installed-by-rpm',
|
|
|
|
'post-install',
|
|
|
|
'test-vm',
|
|
|
|
'/var/tmp/qvm-template-tmpdir'
|
|
|
|
'/var/lib/qubes/vm-templates/test-vm'
|
|
|
|
])
|
|
|
|
])
|
|
|
|
# Cache directory created
|
|
|
|
self.assertEqual(mock_mkdirs.mock_calls, [
|
|
|
|
mock.call(args.cachedir, exist_ok=True)
|
|
|
|
])
|
|
|
|
# No templates downloaded, thus no renames needed
|
|
|
|
self.assertEqual(mock_rename.mock_calls, [])
|
|
|
|
# Lock file removed
|
|
|
|
self.assertEqual(mock_remove.mock_calls, [
|
|
|
|
mock.call('/var/tmp/qvm-template.lck')
|
|
|
|
])
|
|
|
|
self.assertAllCalled()
|
|
|
|
|
|
|
|
@mock.patch('os.remove')
|
|
|
|
@mock.patch('os.rename')
|
|
|
|
@mock.patch('os.makedirs')
|
|
|
|
@mock.patch('subprocess.check_call')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.confirm_action')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.extract_rpm')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.download')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.get_dl_list')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.verify_rpm')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.rpm_transactionset')
|
|
|
|
def test_101_install_local_postprocargs_success(
|
|
|
|
self,
|
|
|
|
mock_ts,
|
|
|
|
mock_verify,
|
|
|
|
mock_dl_list,
|
|
|
|
mock_dl,
|
|
|
|
mock_extract,
|
|
|
|
mock_confirm,
|
|
|
|
mock_call,
|
|
|
|
mock_mkdirs,
|
|
|
|
mock_rename,
|
|
|
|
mock_remove):
|
|
|
|
self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = b'0\0'
|
2020-09-06 17:57:42 +02:00
|
|
|
build_time = '2020-09-01 14:30:00' # 1598970600
|
|
|
|
install_time = '2020-09-01 15:30:00'
|
2020-09-03 19:56:15 +02:00
|
|
|
for key, val in [
|
|
|
|
('name', 'test-vm'),
|
|
|
|
('epoch', '2'),
|
|
|
|
('version', '4.1'),
|
|
|
|
('release', '2020'),
|
|
|
|
('reponame', '@commandline'),
|
|
|
|
('buildtime', build_time),
|
|
|
|
('installtime', install_time),
|
|
|
|
('license', 'GPL'),
|
|
|
|
('url', 'https://qubes-os.org'),
|
|
|
|
('summary', 'Summary'),
|
|
|
|
('description', 'Desc|desc')]:
|
|
|
|
self.app.expected_calls[(
|
|
|
|
'test-vm',
|
|
|
|
'admin.vm.feature.Set',
|
|
|
|
f'template-{key}',
|
|
|
|
val.encode())] = b'0\0'
|
|
|
|
mock_verify.return_value = {
|
|
|
|
rpm.RPMTAG_NAME : 'qubes-template-test-vm',
|
|
|
|
rpm.RPMTAG_BUILDTIME : 1598970600,
|
|
|
|
rpm.RPMTAG_DESCRIPTION : 'Desc\ndesc',
|
|
|
|
rpm.RPMTAG_EPOCHNUM : 2,
|
|
|
|
rpm.RPMTAG_LICENSE : 'GPL',
|
|
|
|
rpm.RPMTAG_RELEASE : '2020',
|
|
|
|
rpm.RPMTAG_SUMMARY : 'Summary',
|
|
|
|
rpm.RPMTAG_URL : 'https://qubes-os.org',
|
|
|
|
rpm.RPMTAG_VERSION : '4.1'
|
|
|
|
}
|
|
|
|
mock_dl_list.return_value = {}
|
|
|
|
mock_call.side_effect = self.add_new_vm_side_effect
|
|
|
|
mock_time = mock.Mock(wraps=datetime.datetime)
|
|
|
|
mock_time.today.return_value = \
|
|
|
|
datetime.datetime.fromisoformat(install_time)
|
|
|
|
with mock.patch('builtins.open', mock.mock_open()) as mock_open, \
|
|
|
|
mock.patch('datetime.datetime', new=mock_time), \
|
|
|
|
mock.patch('tempfile.TemporaryDirectory') as mock_tmpdir, \
|
|
|
|
mock.patch('sys.stderr', new=io.StringIO()) as mock_err, \
|
|
|
|
tempfile.NamedTemporaryFile(suffix='.rpm') as template_file:
|
|
|
|
path = template_file.name
|
|
|
|
args = argparse.Namespace(
|
|
|
|
templates=[path],
|
|
|
|
keyring='/usr/share/qubes/repo-templates/keys',
|
|
|
|
nogpgcheck=False,
|
|
|
|
cachedir='/var/cache/qvm-template',
|
|
|
|
yes=False,
|
|
|
|
allow_pv=True,
|
|
|
|
pool='my-pool'
|
|
|
|
)
|
|
|
|
mock_tmpdir.return_value.__enter__.return_value = \
|
|
|
|
'/var/tmp/qvm-template-tmpdir'
|
|
|
|
qubesadmin.tools.qvm_template.install(args, self.app)
|
|
|
|
# Lock file created
|
|
|
|
self.assertEqual(mock_open.mock_calls, [
|
|
|
|
mock.call('/var/tmp/qvm-template.lck', 'x'),
|
|
|
|
mock.call().__enter__(),
|
|
|
|
mock.call().__exit__(None, None, None)
|
|
|
|
])
|
|
|
|
# Keyring created
|
|
|
|
self.assertEqual(mock_ts.mock_calls, [
|
|
|
|
mock.call('/usr/share/qubes/repo-templates/keys')
|
|
|
|
])
|
|
|
|
# Package verified
|
|
|
|
self.assertEqual(mock_verify.mock_calls, [
|
|
|
|
mock.call(path, mock_ts('/usr/share/qubes/repo-templates/keys'),
|
|
|
|
False)
|
|
|
|
])
|
|
|
|
# Attempt to get download list
|
|
|
|
selector = qubesadmin.tools.qvm_template.VersionSelector.LATEST
|
|
|
|
self.assertEqual(mock_dl_list.mock_calls, [
|
|
|
|
mock.call(args, self.app, version_selector=selector)
|
|
|
|
])
|
|
|
|
# Nothing downloaded
|
|
|
|
self.assertEqual(mock_dl.mock_calls, [
|
|
|
|
mock.call(args, self.app, path_override='/var/cache/qvm-template',
|
|
|
|
dl_list={}, suffix='.unverified', version_selector=selector)
|
|
|
|
])
|
|
|
|
# Package is extracted
|
|
|
|
self.assertEqual(mock_extract.mock_calls, [
|
|
|
|
mock.call('test-vm', path, '/var/tmp/qvm-template-tmpdir')
|
|
|
|
])
|
|
|
|
# No packages overwritten, so no confirm needed
|
|
|
|
self.assertEqual(mock_confirm.mock_calls, [])
|
|
|
|
# qvm-template-postprocess is called
|
|
|
|
self.assertEqual(mock_call.mock_calls, [
|
|
|
|
mock.call([
|
|
|
|
'qvm-template-postprocess',
|
|
|
|
'--really',
|
|
|
|
'--no-installed-by-rpm',
|
|
|
|
'--allow-pv',
|
|
|
|
'--pool',
|
|
|
|
'my-pool',
|
|
|
|
'post-install',
|
|
|
|
'test-vm',
|
|
|
|
'/var/tmp/qvm-template-tmpdir'
|
|
|
|
'/var/lib/qubes/vm-templates/test-vm'
|
|
|
|
])
|
|
|
|
])
|
|
|
|
# Cache directory created
|
|
|
|
self.assertEqual(mock_mkdirs.mock_calls, [
|
|
|
|
mock.call(args.cachedir, exist_ok=True)
|
|
|
|
])
|
|
|
|
# No templates downloaded, thus no renames needed
|
|
|
|
self.assertEqual(mock_rename.mock_calls, [])
|
|
|
|
# Lock file removed
|
|
|
|
self.assertEqual(mock_remove.mock_calls, [
|
|
|
|
mock.call('/var/tmp/qvm-template.lck')
|
|
|
|
])
|
|
|
|
self.assertAllCalled()
|
|
|
|
|
|
|
|
@mock.patch('os.remove')
|
|
|
|
@mock.patch('os.rename')
|
|
|
|
@mock.patch('os.makedirs')
|
|
|
|
@mock.patch('subprocess.check_call')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.confirm_action')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.extract_rpm')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.download')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.get_dl_list')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.verify_rpm')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.rpm_transactionset')
|
|
|
|
def test_102_install_local_badsig_fail(
|
|
|
|
self,
|
|
|
|
mock_ts,
|
|
|
|
mock_verify,
|
|
|
|
mock_dl_list,
|
|
|
|
mock_dl,
|
|
|
|
mock_extract,
|
|
|
|
mock_confirm,
|
|
|
|
mock_call,
|
|
|
|
mock_mkdirs,
|
|
|
|
mock_rename,
|
|
|
|
mock_remove):
|
|
|
|
mock_verify.return_value = None
|
|
|
|
mock_time = mock.Mock(wraps=datetime.datetime)
|
|
|
|
with mock.patch('builtins.open', mock.mock_open()) as mock_open, \
|
|
|
|
mock.patch('datetime.datetime', new=mock_time), \
|
|
|
|
mock.patch('tempfile.TemporaryDirectory') as mock_tmpdir, \
|
|
|
|
mock.patch('sys.stderr', new=io.StringIO()) as mock_err, \
|
|
|
|
tempfile.NamedTemporaryFile(suffix='.rpm') as template_file:
|
|
|
|
path = template_file.name
|
|
|
|
args = argparse.Namespace(
|
|
|
|
templates=[path],
|
|
|
|
keyring='/usr/share/qubes/repo-templates/keys',
|
|
|
|
nogpgcheck=False,
|
|
|
|
cachedir='/var/cache/qvm-template',
|
|
|
|
yes=False,
|
|
|
|
allow_pv=False,
|
|
|
|
pool=None
|
|
|
|
)
|
|
|
|
mock_tmpdir.return_value.__enter__.return_value = \
|
|
|
|
'/var/tmp/qvm-template-tmpdir'
|
|
|
|
# Should raise parser.error
|
|
|
|
with self.assertRaises(SystemExit):
|
|
|
|
qubesadmin.tools.qvm_template.install(args, self.app)
|
|
|
|
# Lock file created
|
|
|
|
self.assertEqual(mock_open.mock_calls, [
|
|
|
|
mock.call('/var/tmp/qvm-template.lck', 'x'),
|
|
|
|
mock.call().__enter__(),
|
|
|
|
mock.call().__exit__(None, None, None)
|
|
|
|
])
|
|
|
|
# Check error message
|
|
|
|
self.assertTrue('verification failed' in mock_err.getvalue())
|
|
|
|
# Keyring created
|
|
|
|
self.assertEqual(mock_ts.mock_calls, [
|
|
|
|
mock.call('/usr/share/qubes/repo-templates/keys')
|
|
|
|
])
|
|
|
|
# Package verified
|
|
|
|
self.assertEqual(mock_verify.mock_calls, [
|
|
|
|
mock.call(path, mock_ts('/usr/share/qubes/repo-templates/keys'),
|
|
|
|
False)
|
|
|
|
])
|
|
|
|
# Should not be executed:
|
|
|
|
self.assertEqual(mock_dl_list.mock_calls, [])
|
|
|
|
self.assertEqual(mock_dl.mock_calls, [])
|
|
|
|
self.assertEqual(mock_extract.mock_calls, [])
|
|
|
|
self.assertEqual(mock_confirm.mock_calls, [])
|
|
|
|
self.assertEqual(mock_call.mock_calls, [])
|
|
|
|
self.assertEqual(mock_rename.mock_calls, [])
|
|
|
|
# Lock file removed
|
|
|
|
self.assertEqual(mock_remove.mock_calls, [
|
|
|
|
mock.call('/var/tmp/qvm-template.lck')
|
|
|
|
])
|
|
|
|
self.assertAllCalled()
|
|
|
|
|
|
|
|
@mock.patch('os.remove')
|
|
|
|
@mock.patch('os.rename')
|
|
|
|
@mock.patch('os.makedirs')
|
|
|
|
@mock.patch('subprocess.check_call')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.confirm_action')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.extract_rpm')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.download')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.get_dl_list')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.verify_rpm')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.rpm_transactionset')
|
|
|
|
def test_103_install_local_exists_fail(
|
|
|
|
self,
|
|
|
|
mock_ts,
|
|
|
|
mock_verify,
|
|
|
|
mock_dl_list,
|
|
|
|
mock_dl,
|
|
|
|
mock_extract,
|
|
|
|
mock_confirm,
|
|
|
|
mock_call,
|
|
|
|
mock_mkdirs,
|
|
|
|
mock_rename,
|
|
|
|
mock_remove):
|
|
|
|
self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \
|
|
|
|
b'0\0test-vm class=TemplateVM state=Halted\n'
|
|
|
|
mock_verify.return_value = {
|
|
|
|
rpm.RPMTAG_NAME : 'qubes-template-test-vm',
|
|
|
|
rpm.RPMTAG_BUILDTIME : 1598970600,
|
|
|
|
rpm.RPMTAG_DESCRIPTION : 'Desc\ndesc',
|
|
|
|
rpm.RPMTAG_EPOCHNUM : 2,
|
|
|
|
rpm.RPMTAG_LICENSE : 'GPL',
|
|
|
|
rpm.RPMTAG_RELEASE : '2020',
|
|
|
|
rpm.RPMTAG_SUMMARY : 'Summary',
|
|
|
|
rpm.RPMTAG_URL : 'https://qubes-os.org',
|
|
|
|
rpm.RPMTAG_VERSION : '4.1'
|
|
|
|
}
|
|
|
|
mock_dl_list.return_value = {}
|
|
|
|
mock_time = mock.Mock(wraps=datetime.datetime)
|
|
|
|
with mock.patch('builtins.open', mock.mock_open()) as mock_open, \
|
|
|
|
mock.patch('datetime.datetime', new=mock_time), \
|
|
|
|
mock.patch('tempfile.TemporaryDirectory') as mock_tmpdir, \
|
|
|
|
mock.patch('sys.stderr', new=io.StringIO()) as mock_err, \
|
|
|
|
tempfile.NamedTemporaryFile(suffix='.rpm') as template_file:
|
|
|
|
path = template_file.name
|
|
|
|
args = argparse.Namespace(
|
|
|
|
templates=[path],
|
|
|
|
keyring='/usr/share/qubes/repo-templates/keys',
|
|
|
|
nogpgcheck=False,
|
|
|
|
cachedir='/var/cache/qvm-template',
|
|
|
|
yes=False,
|
|
|
|
allow_pv=False,
|
|
|
|
pool=None
|
|
|
|
)
|
|
|
|
mock_tmpdir.return_value.__enter__.return_value = \
|
|
|
|
'/var/tmp/qvm-template-tmpdir'
|
|
|
|
qubesadmin.tools.qvm_template.install(args, self.app)
|
|
|
|
# Lock file created
|
|
|
|
self.assertEqual(mock_open.mock_calls, [
|
|
|
|
mock.call('/var/tmp/qvm-template.lck', 'x'),
|
|
|
|
mock.call().__enter__(),
|
|
|
|
mock.call().__exit__(None, None, None)
|
|
|
|
])
|
|
|
|
# Check warning message
|
|
|
|
self.assertTrue('already installed' in mock_err.getvalue())
|
|
|
|
# Keyring created
|
|
|
|
self.assertEqual(mock_ts.mock_calls, [
|
|
|
|
mock.call('/usr/share/qubes/repo-templates/keys')
|
|
|
|
])
|
|
|
|
# Package verified
|
|
|
|
self.assertEqual(mock_verify.mock_calls, [
|
|
|
|
mock.call(path, mock_ts('/usr/share/qubes/repo-templates/keys'),
|
|
|
|
False)
|
|
|
|
])
|
|
|
|
# Attempt to get download list
|
|
|
|
selector = qubesadmin.tools.qvm_template.VersionSelector.LATEST
|
|
|
|
self.assertEqual(mock_dl_list.mock_calls, [
|
|
|
|
mock.call(args, self.app, version_selector=selector)
|
|
|
|
])
|
|
|
|
# Nothing downloaded
|
|
|
|
self.assertEqual(mock_dl.mock_calls, [
|
|
|
|
mock.call(args, self.app, path_override='/var/cache/qvm-template',
|
|
|
|
dl_list={}, suffix='.unverified', version_selector=selector)
|
|
|
|
])
|
|
|
|
# Should not be executed:
|
|
|
|
self.assertEqual(mock_extract.mock_calls, [])
|
|
|
|
self.assertEqual(mock_confirm.mock_calls, [])
|
|
|
|
self.assertEqual(mock_call.mock_calls, [])
|
|
|
|
self.assertEqual(mock_rename.mock_calls, [])
|
|
|
|
# Lock file removed
|
|
|
|
self.assertEqual(mock_remove.mock_calls, [
|
|
|
|
mock.call('/var/tmp/qvm-template.lck')
|
|
|
|
])
|
|
|
|
self.assertAllCalled()
|
|
|
|
|
|
|
|
@mock.patch('os.remove')
|
|
|
|
@mock.patch('os.rename')
|
|
|
|
@mock.patch('os.makedirs')
|
|
|
|
@mock.patch('subprocess.check_call')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.confirm_action')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.extract_rpm')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.download')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.get_dl_list')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.verify_rpm')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.rpm_transactionset')
|
|
|
|
def test_104_install_local_badpkgname_fail(
|
|
|
|
self,
|
|
|
|
mock_ts,
|
|
|
|
mock_verify,
|
|
|
|
mock_dl_list,
|
|
|
|
mock_dl,
|
|
|
|
mock_extract,
|
|
|
|
mock_confirm,
|
|
|
|
mock_call,
|
|
|
|
mock_mkdirs,
|
|
|
|
mock_rename,
|
|
|
|
mock_remove):
|
|
|
|
mock_verify.return_value = {
|
|
|
|
rpm.RPMTAG_NAME : 'Xqubes-template-test-vm',
|
|
|
|
rpm.RPMTAG_BUILDTIME : 1598970600,
|
|
|
|
rpm.RPMTAG_DESCRIPTION : 'Desc\ndesc',
|
|
|
|
rpm.RPMTAG_EPOCHNUM : 2,
|
|
|
|
rpm.RPMTAG_LICENSE : 'GPL',
|
|
|
|
rpm.RPMTAG_RELEASE : '2020',
|
|
|
|
rpm.RPMTAG_SUMMARY : 'Summary',
|
|
|
|
rpm.RPMTAG_URL : 'https://qubes-os.org',
|
|
|
|
rpm.RPMTAG_VERSION : '4.1'
|
|
|
|
}
|
|
|
|
mock_time = mock.Mock(wraps=datetime.datetime)
|
|
|
|
with mock.patch('builtins.open', mock.mock_open()) as mock_open, \
|
|
|
|
mock.patch('datetime.datetime', new=mock_time), \
|
|
|
|
mock.patch('tempfile.TemporaryDirectory') as mock_tmpdir, \
|
|
|
|
mock.patch('sys.stderr', new=io.StringIO()) as mock_err, \
|
|
|
|
tempfile.NamedTemporaryFile(suffix='.rpm') as template_file:
|
|
|
|
path = template_file.name
|
|
|
|
args = argparse.Namespace(
|
|
|
|
templates=[path],
|
|
|
|
keyring='/usr/share/qubes/repo-templates/keys',
|
|
|
|
nogpgcheck=False,
|
|
|
|
cachedir='/var/cache/qvm-template',
|
|
|
|
yes=False,
|
|
|
|
allow_pv=False,
|
|
|
|
pool=None
|
|
|
|
)
|
|
|
|
mock_tmpdir.return_value.__enter__.return_value = \
|
|
|
|
'/var/tmp/qvm-template-tmpdir'
|
|
|
|
with self.assertRaises(SystemExit):
|
|
|
|
qubesadmin.tools.qvm_template.install(args, self.app)
|
|
|
|
# Lock file created
|
|
|
|
self.assertEqual(mock_open.mock_calls, [
|
|
|
|
mock.call('/var/tmp/qvm-template.lck', 'x'),
|
|
|
|
mock.call().__enter__(),
|
|
|
|
mock.call().__exit__(None, None, None)
|
|
|
|
])
|
|
|
|
# Check error message
|
|
|
|
self.assertTrue('Illegal package name' in mock_err.getvalue())
|
|
|
|
# Keyring created
|
|
|
|
self.assertEqual(mock_ts.mock_calls, [
|
|
|
|
mock.call('/usr/share/qubes/repo-templates/keys')
|
|
|
|
])
|
|
|
|
# Package verified
|
|
|
|
self.assertEqual(mock_verify.mock_calls, [
|
|
|
|
mock.call(path, mock_ts('/usr/share/qubes/repo-templates/keys'),
|
|
|
|
False)
|
|
|
|
])
|
|
|
|
# Should not be executed:
|
|
|
|
self.assertEqual(mock_dl_list.mock_calls, [])
|
|
|
|
self.assertEqual(mock_dl.mock_calls, [])
|
|
|
|
self.assertEqual(mock_extract.mock_calls, [])
|
|
|
|
self.assertEqual(mock_confirm.mock_calls, [])
|
|
|
|
self.assertEqual(mock_call.mock_calls, [])
|
|
|
|
self.assertEqual(mock_rename.mock_calls, [])
|
|
|
|
# Lock file removed
|
|
|
|
self.assertEqual(mock_remove.mock_calls, [
|
|
|
|
mock.call('/var/tmp/qvm-template.lck')
|
|
|
|
])
|
|
|
|
self.assertAllCalled()
|
|
|
|
|
|
|
|
@mock.patch('os.rename')
|
|
|
|
@mock.patch('os.makedirs')
|
|
|
|
@mock.patch('subprocess.check_call')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.confirm_action')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.extract_rpm')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.download')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.get_dl_list')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.verify_rpm')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.rpm_transactionset')
|
|
|
|
def test_105_install_local_existinginstance_fail(
|
|
|
|
self,
|
|
|
|
mock_ts,
|
|
|
|
mock_verify,
|
|
|
|
mock_dl_list,
|
|
|
|
mock_dl,
|
|
|
|
mock_extract,
|
|
|
|
mock_confirm,
|
|
|
|
mock_call,
|
|
|
|
mock_mkdirs,
|
|
|
|
mock_rename):
|
|
|
|
mock_time = mock.Mock(wraps=datetime.datetime)
|
|
|
|
with mock.patch('datetime.datetime', new=mock_time), \
|
|
|
|
mock.patch('tempfile.TemporaryDirectory') as mock_tmpdir, \
|
|
|
|
mock.patch('sys.stderr', new=io.StringIO()) as mock_err, \
|
|
|
|
tempfile.NamedTemporaryFile(suffix='.rpm') as template_file:
|
|
|
|
path = template_file.name
|
|
|
|
args = argparse.Namespace(
|
|
|
|
templates=[path],
|
|
|
|
keyring='/usr/share/qubes/repo-templates/keys',
|
|
|
|
nogpgcheck=False,
|
|
|
|
cachedir='/var/cache/qvm-template',
|
|
|
|
yes=False,
|
|
|
|
allow_pv=False,
|
|
|
|
pool=None
|
|
|
|
)
|
|
|
|
mock_tmpdir.return_value.__enter__.return_value = \
|
|
|
|
'/var/tmp/qvm-template-tmpdir'
|
|
|
|
pathlib.Path('/var/tmp/qvm-template.lck').touch()
|
|
|
|
try:
|
|
|
|
with self.assertRaises(SystemExit), \
|
|
|
|
mock.patch('os.remove') as mock_remove:
|
|
|
|
qubesadmin.tools.qvm_template.install(args, self.app)
|
|
|
|
self.assertEqual(mock_remove.mock_calls, [])
|
|
|
|
finally:
|
|
|
|
# Lock file not removed
|
|
|
|
self.assertTrue(os.path.exists('/var/tmp/qvm-template.lck'))
|
|
|
|
os.remove('/var/tmp/qvm-template.lck')
|
|
|
|
# Check error message
|
|
|
|
self.assertTrue('another instance of qvm-template is running' \
|
|
|
|
in mock_err.getvalue())
|
|
|
|
# Should not be executed:
|
|
|
|
self.assertEqual(mock_ts.mock_calls, [])
|
|
|
|
self.assertEqual(mock_verify.mock_calls, [])
|
|
|
|
self.assertEqual(mock_dl_list.mock_calls, [])
|
|
|
|
self.assertEqual(mock_dl.mock_calls, [])
|
|
|
|
self.assertEqual(mock_extract.mock_calls, [])
|
|
|
|
self.assertEqual(mock_confirm.mock_calls, [])
|
|
|
|
self.assertEqual(mock_call.mock_calls, [])
|
|
|
|
self.assertEqual(mock_rename.mock_calls, [])
|
|
|
|
self.assertAllCalled()
|
|
|
|
|
|
|
|
@mock.patch('os.remove')
|
|
|
|
@mock.patch('os.rename')
|
|
|
|
@mock.patch('os.makedirs')
|
|
|
|
@mock.patch('subprocess.check_call')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.confirm_action')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.extract_rpm')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.download')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.get_dl_list')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.verify_rpm')
|
|
|
|
@mock.patch('qubesadmin.tools.qvm_template.rpm_transactionset')
|
|
|
|
def test_106_install_local_badpath_fail(
|
|
|
|
self,
|
|
|
|
mock_ts,
|
|
|
|
mock_verify,
|
|
|
|
mock_dl_list,
|
|
|
|
mock_dl,
|
|
|
|
mock_extract,
|
|
|
|
mock_confirm,
|
|
|
|
mock_call,
|
|
|
|
mock_mkdirs,
|
|
|
|
mock_rename,
|
|
|
|
mock_remove):
|
|
|
|
mock_time = mock.Mock(wraps=datetime.datetime)
|
|
|
|
with mock.patch('builtins.open', mock.mock_open()) as mock_open, \
|
|
|
|
mock.patch('datetime.datetime', new=mock_time), \
|
|
|
|
mock.patch('tempfile.TemporaryDirectory') as mock_tmpdir, \
|
|
|
|
mock.patch('sys.stderr', new=io.StringIO()) as mock_err:
|
|
|
|
path = '/var/tmp/ShOulD-NoT-ExIsT.rpm'
|
|
|
|
args = argparse.Namespace(
|
|
|
|
templates=[path],
|
|
|
|
keyring='/usr/share/qubes/repo-templates/keys',
|
|
|
|
nogpgcheck=False,
|
|
|
|
cachedir='/var/cache/qvm-template',
|
|
|
|
yes=False,
|
|
|
|
allow_pv=False,
|
|
|
|
pool=None
|
|
|
|
)
|
|
|
|
mock_tmpdir.return_value.__enter__.return_value = \
|
|
|
|
'/var/tmp/qvm-template-tmpdir'
|
|
|
|
with self.assertRaises(SystemExit):
|
|
|
|
qubesadmin.tools.qvm_template.install(args, self.app)
|
|
|
|
# Lock file created
|
|
|
|
self.assertEqual(mock_open.mock_calls, [
|
|
|
|
mock.call('/var/tmp/qvm-template.lck', 'x'),
|
|
|
|
mock.call().__enter__(),
|
|
|
|
mock.call().__exit__(None, None, None)
|
|
|
|
])
|
|
|
|
# Check error message
|
|
|
|
self.assertTrue(f"RPM file '{path}' not found" \
|
|
|
|
in mock_err.getvalue())
|
|
|
|
# Keyring created
|
|
|
|
self.assertEqual(mock_ts.mock_calls, [
|
|
|
|
mock.call('/usr/share/qubes/repo-templates/keys')
|
|
|
|
])
|
|
|
|
# Should not be executed:
|
|
|
|
self.assertEqual(mock_verify.mock_calls, [])
|
|
|
|
self.assertEqual(mock_dl_list.mock_calls, [])
|
|
|
|
self.assertEqual(mock_dl.mock_calls, [])
|
|
|
|
self.assertEqual(mock_extract.mock_calls, [])
|
|
|
|
self.assertEqual(mock_confirm.mock_calls, [])
|
|
|
|
self.assertEqual(mock_call.mock_calls, [])
|
|
|
|
self.assertEqual(mock_rename.mock_calls, [])
|
|
|
|
# Lock file removed
|
|
|
|
self.assertEqual(mock_remove.mock_calls, [
|
|
|
|
mock.call('/var/tmp/qvm-template.lck')
|
|
|
|
])
|
|
|
|
self.assertAllCalled()
|
2020-09-06 18:41:03 +02:00
|
|
|
|
|
|
|
def test_110_qrexec_payload_refresh_success(self):
|
|
|
|
with tempfile.NamedTemporaryFile() as repo_conf1, \
|
|
|
|
tempfile.NamedTemporaryFile() as repo_conf2:
|
|
|
|
repo_str1 = \
|
|
|
|
'''[qubes-templates-itl]
|
|
|
|
name = Qubes Templates repository
|
|
|
|
#baseurl = https://yum.qubes-os.org/r$releasever/templates-itl
|
|
|
|
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-itl
|
|
|
|
metalink = https://yum.qubes-os.org/r$releasever/templates-itl/repodata/repomd.xml.metalink
|
|
|
|
enabled = 1
|
|
|
|
fastestmirror = 1
|
|
|
|
metadata_expire = 7d
|
|
|
|
gpgcheck = 1
|
|
|
|
gpgkey = file:///usr/share/qubes/repo-templates/keys/RPM-GPG-KEY-qubes-$releasever-primary
|
|
|
|
'''
|
|
|
|
repo_str2 = \
|
|
|
|
'''[qubes-templates-itl-testing]
|
|
|
|
name = Qubes Templates repository
|
|
|
|
#baseurl = https://yum.qubes-os.org/r$releasever/templates-itl-testing
|
|
|
|
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-itl-testing
|
|
|
|
metalink = https://yum.qubes-os.org/r$releasever/templates-itl-testing/repodata/repomd.xml.metalink
|
|
|
|
enabled = 0
|
|
|
|
fastestmirror = 1
|
|
|
|
gpgcheck = 1
|
|
|
|
gpgkey = file:///usr/share/qubes/repo-templates/keys/RPM-GPG-KEY-qubes-$releasever-primary
|
|
|
|
'''
|
|
|
|
repo_conf1.write(repo_str1.encode())
|
|
|
|
repo_conf1.flush()
|
|
|
|
repo_conf2.write(repo_str2.encode())
|
|
|
|
repo_conf2.flush()
|
|
|
|
args = argparse.Namespace(
|
|
|
|
enablerepo=['repo1', 'repo2'],
|
|
|
|
disablerepo=['repo3', 'repo4', 'repo5'],
|
|
|
|
repoid=[],
|
|
|
|
releasever='4.1',
|
|
|
|
repo_files=[repo_conf1.name, repo_conf2.name]
|
|
|
|
)
|
|
|
|
res = qubesadmin.tools.qvm_template.qrexec_payload(args, self.app,
|
|
|
|
'qubes-template-fedora-32', True)
|
|
|
|
self.assertEqual(res,
|
|
|
|
'''--enablerepo=repo1
|
|
|
|
--enablerepo=repo2
|
|
|
|
--disablerepo=repo3
|
|
|
|
--disablerepo=repo4
|
|
|
|
--disablerepo=repo5
|
|
|
|
--refresh
|
|
|
|
--releasever=4.1
|
|
|
|
qubes-template-fedora-32
|
|
|
|
---
|
|
|
|
''' + repo_str1 + '\n' + repo_str2 + '\n')
|
|
|
|
self.assertAllCalled()
|
|
|
|
|
|
|
|
def test_111_qrexec_payload_norefresh_success(self):
|
|
|
|
with tempfile.NamedTemporaryFile() as repo_conf1:
|
|
|
|
repo_str1 = \
|
|
|
|
'''[qubes-templates-itl]
|
|
|
|
name = Qubes Templates repository
|
|
|
|
#baseurl = https://yum.qubes-os.org/r$releasever/templates-itl
|
|
|
|
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-itl
|
|
|
|
metalink = https://yum.qubes-os.org/r$releasever/templates-itl/repodata/repomd.xml.metalink
|
|
|
|
enabled = 1
|
|
|
|
fastestmirror = 1
|
|
|
|
metadata_expire = 7d
|
|
|
|
gpgcheck = 1
|
|
|
|
gpgkey = file:///usr/share/qubes/repo-templates/keys/RPM-GPG-KEY-qubes-$releasever-primary
|
|
|
|
'''
|
|
|
|
repo_conf1.write(repo_str1.encode())
|
|
|
|
repo_conf1.flush()
|
|
|
|
args = argparse.Namespace(
|
|
|
|
enablerepo=[],
|
|
|
|
disablerepo=[],
|
|
|
|
repoid=['repo1', 'repo2'],
|
|
|
|
releasever='4.1',
|
|
|
|
repo_files=[repo_conf1.name]
|
|
|
|
)
|
|
|
|
res = qubesadmin.tools.qvm_template.qrexec_payload(args, self.app,
|
|
|
|
'qubes-template-fedora-32', False)
|
|
|
|
self.assertEqual(res,
|
|
|
|
'''--repoid=repo1
|
|
|
|
--repoid=repo2
|
|
|
|
--releasever=4.1
|
|
|
|
qubes-template-fedora-32
|
|
|
|
---
|
|
|
|
''' + repo_str1 + '\n')
|
|
|
|
self.assertAllCalled()
|
|
|
|
|
|
|
|
def test_112_qrexec_payload_specnewline_fail(self):
|
|
|
|
with tempfile.NamedTemporaryFile() as repo_conf1:
|
|
|
|
repo_str1 = \
|
|
|
|
'''[qubes-templates-itl]
|
|
|
|
name = Qubes Templates repository
|
|
|
|
#baseurl = https://yum.qubes-os.org/r$releasever/templates-itl
|
|
|
|
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-itl
|
|
|
|
metalink = https://yum.qubes-os.org/r$releasever/templates-itl/repodata/repomd.xml.metalink
|
|
|
|
enabled = 1
|
|
|
|
fastestmirror = 1
|
|
|
|
metadata_expire = 7d
|
|
|
|
gpgcheck = 1
|
|
|
|
gpgkey = file:///usr/share/qubes/repo-templates/keys/RPM-GPG-KEY-qubes-$releasever-primary
|
|
|
|
'''
|
|
|
|
repo_conf1.write(repo_str1.encode())
|
|
|
|
repo_conf1.flush()
|
|
|
|
args = argparse.Namespace(
|
|
|
|
enablerepo=[],
|
|
|
|
disablerepo=[],
|
|
|
|
repoid=['repo1', 'repo2'],
|
|
|
|
releasever='4.1',
|
|
|
|
repo_files=[repo_conf1.name]
|
|
|
|
)
|
|
|
|
with self.assertRaises(SystemExit), \
|
|
|
|
mock.patch('sys.stderr', new=io.StringIO()) as mock_err:
|
|
|
|
qubesadmin.tools.qvm_template.qrexec_payload(args, self.app,
|
|
|
|
'qubes-template-fedora\n-32', False)
|
|
|
|
# Check error message
|
|
|
|
self.assertTrue('Malformed template name'
|
|
|
|
in mock_err.getvalue())
|
|
|
|
self.assertTrue("argument should not contain '\\n'"
|
|
|
|
in mock_err.getvalue())
|
|
|
|
self.assertAllCalled()
|
|
|
|
|
|
|
|
def test_113_qrexec_payload_enablereponewline_fail(self):
|
|
|
|
with tempfile.NamedTemporaryFile() as repo_conf1:
|
|
|
|
repo_str1 = \
|
|
|
|
'''[qubes-templates-itl]
|
|
|
|
name = Qubes Templates repository
|
|
|
|
#baseurl = https://yum.qubes-os.org/r$releasever/templates-itl
|
|
|
|
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-itl
|
|
|
|
metalink = https://yum.qubes-os.org/r$releasever/templates-itl/repodata/repomd.xml.metalink
|
|
|
|
enabled = 1
|
|
|
|
fastestmirror = 1
|
|
|
|
metadata_expire = 7d
|
|
|
|
gpgcheck = 1
|
|
|
|
gpgkey = file:///usr/share/qubes/repo-templates/keys/RPM-GPG-KEY-qubes-$releasever-primary
|
|
|
|
'''
|
|
|
|
repo_conf1.write(repo_str1.encode())
|
|
|
|
repo_conf1.flush()
|
|
|
|
args = argparse.Namespace(
|
|
|
|
enablerepo=['repo\n0'],
|
|
|
|
disablerepo=[],
|
|
|
|
repoid=['repo1', 'repo2'],
|
|
|
|
releasever='4.1',
|
|
|
|
repo_files=[repo_conf1.name]
|
|
|
|
)
|
|
|
|
with self.assertRaises(SystemExit), \
|
|
|
|
mock.patch('sys.stderr', new=io.StringIO()) as mock_err:
|
|
|
|
qubesadmin.tools.qvm_template.qrexec_payload(args, self.app,
|
|
|
|
'qubes-template-fedora-32', False)
|
|
|
|
# Check error message
|
|
|
|
self.assertTrue('Malformed --enablerepo'
|
|
|
|
in mock_err.getvalue())
|
|
|
|
self.assertTrue("argument should not contain '\\n'"
|
|
|
|
in mock_err.getvalue())
|
|
|
|
self.assertAllCalled()
|
|
|
|
|
|
|
|
def test_114_qrexec_payload_disablereponewline_fail(self):
|
|
|
|
with tempfile.NamedTemporaryFile() as repo_conf1:
|
|
|
|
repo_str1 = \
|
|
|
|
'''[qubes-templates-itl]
|
|
|
|
name = Qubes Templates repository
|
|
|
|
#baseurl = https://yum.qubes-os.org/r$releasever/templates-itl
|
|
|
|
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-itl
|
|
|
|
metalink = https://yum.qubes-os.org/r$releasever/templates-itl/repodata/repomd.xml.metalink
|
|
|
|
enabled = 1
|
|
|
|
fastestmirror = 1
|
|
|
|
metadata_expire = 7d
|
|
|
|
gpgcheck = 1
|
|
|
|
gpgkey = file:///usr/share/qubes/repo-templates/keys/RPM-GPG-KEY-qubes-$releasever-primary
|
|
|
|
'''
|
|
|
|
repo_conf1.write(repo_str1.encode())
|
|
|
|
repo_conf1.flush()
|
|
|
|
args = argparse.Namespace(
|
|
|
|
enablerepo=[],
|
|
|
|
disablerepo=['repo\n0'],
|
|
|
|
repoid=['repo1', 'repo2'],
|
|
|
|
releasever='4.1',
|
|
|
|
repo_files=[repo_conf1.name]
|
|
|
|
)
|
|
|
|
with self.assertRaises(SystemExit), \
|
|
|
|
mock.patch('sys.stderr', new=io.StringIO()) as mock_err:
|
|
|
|
qubesadmin.tools.qvm_template.qrexec_payload(args, self.app,
|
|
|
|
'qubes-template-fedora-32', False)
|
|
|
|
# Check error message
|
|
|
|
self.assertTrue('Malformed --disablerepo'
|
|
|
|
in mock_err.getvalue())
|
|
|
|
self.assertTrue("argument should not contain '\\n'"
|
|
|
|
in mock_err.getvalue())
|
|
|
|
self.assertAllCalled()
|
|
|
|
|
|
|
|
def test_115_qrexec_payload_repoidnewline_fail(self):
|
|
|
|
with tempfile.NamedTemporaryFile() as repo_conf1:
|
|
|
|
repo_str1 = \
|
|
|
|
'''[qubes-templates-itl]
|
|
|
|
name = Qubes Templates repository
|
|
|
|
#baseurl = https://yum.qubes-os.org/r$releasever/templates-itl
|
|
|
|
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-itl
|
|
|
|
metalink = https://yum.qubes-os.org/r$releasever/templates-itl/repodata/repomd.xml.metalink
|
|
|
|
enabled = 1
|
|
|
|
fastestmirror = 1
|
|
|
|
metadata_expire = 7d
|
|
|
|
gpgcheck = 1
|
|
|
|
gpgkey = file:///usr/share/qubes/repo-templates/keys/RPM-GPG-KEY-qubes-$releasever-primary
|
|
|
|
'''
|
|
|
|
repo_conf1.write(repo_str1.encode())
|
|
|
|
repo_conf1.flush()
|
|
|
|
args = argparse.Namespace(
|
|
|
|
enablerepo=[],
|
|
|
|
disablerepo=[],
|
|
|
|
repoid=['repo\n1', 'repo2'],
|
|
|
|
releasever='4.1',
|
|
|
|
repo_files=[repo_conf1.name]
|
|
|
|
)
|
|
|
|
with self.assertRaises(SystemExit), \
|
|
|
|
mock.patch('sys.stderr', new=io.StringIO()) as mock_err:
|
|
|
|
qubesadmin.tools.qvm_template.qrexec_payload(args, self.app,
|
|
|
|
'qubes-template-fedora-32', False)
|
|
|
|
# Check error message
|
|
|
|
self.assertTrue('Malformed --repoid'
|
|
|
|
in mock_err.getvalue())
|
|
|
|
self.assertTrue("argument should not contain '\\n'"
|
|
|
|
in mock_err.getvalue())
|
|
|
|
self.assertAllCalled()
|
|
|
|
|
|
|
|
def test_116_qrexec_payload_releasevernewline_fail(self):
|
|
|
|
with tempfile.NamedTemporaryFile() as repo_conf1:
|
|
|
|
repo_str1 = \
|
|
|
|
'''[qubes-templates-itl]
|
|
|
|
name = Qubes Templates repository
|
|
|
|
#baseurl = https://yum.qubes-os.org/r$releasever/templates-itl
|
|
|
|
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-itl
|
|
|
|
metalink = https://yum.qubes-os.org/r$releasever/templates-itl/repodata/repomd.xml.metalink
|
|
|
|
enabled = 1
|
|
|
|
fastestmirror = 1
|
|
|
|
metadata_expire = 7d
|
|
|
|
gpgcheck = 1
|
|
|
|
gpgkey = file:///usr/share/qubes/repo-templates/keys/RPM-GPG-KEY-qubes-$releasever-primary
|
|
|
|
'''
|
|
|
|
repo_conf1.write(repo_str1.encode())
|
|
|
|
repo_conf1.flush()
|
|
|
|
args = argparse.Namespace(
|
|
|
|
enablerepo=[],
|
|
|
|
disablerepo=[],
|
|
|
|
repoid=['repo1', 'repo2'],
|
|
|
|
releasever='4\n.1',
|
|
|
|
repo_files=[repo_conf1.name]
|
|
|
|
)
|
|
|
|
with self.assertRaises(SystemExit), \
|
|
|
|
mock.patch('sys.stderr', new=io.StringIO()) as mock_err:
|
|
|
|
qubesadmin.tools.qvm_template.qrexec_payload(args, self.app,
|
|
|
|
'qubes-template-fedora-32', False)
|
|
|
|
# Check error message
|
|
|
|
self.assertTrue('Malformed --releasever'
|
|
|
|
in mock_err.getvalue())
|
|
|
|
self.assertTrue("argument should not contain '\\n'"
|
|
|
|
in mock_err.getvalue())
|
|
|
|
self.assertAllCalled()
|
|
|
|
|
|
|
|
def test_117_qrexec_payload_specdash_fail(self):
|
|
|
|
with tempfile.NamedTemporaryFile() as repo_conf1:
|
|
|
|
repo_str1 = \
|
|
|
|
'''[qubes-templates-itl]
|
|
|
|
name = Qubes Templates repository
|
|
|
|
#baseurl = https://yum.qubes-os.org/r$releasever/templates-itl
|
|
|
|
#baseurl = http://yum.qubesosfasa4zl44o4tws22di6kepyzfeqv3tg4e3ztknltfxqrymdad.onion/r$releasever/templates-itl
|
|
|
|
metalink = https://yum.qubes-os.org/r$releasever/templates-itl/repodata/repomd.xml.metalink
|
|
|
|
enabled = 1
|
|
|
|
fastestmirror = 1
|
|
|
|
metadata_expire = 7d
|
|
|
|
gpgcheck = 1
|
|
|
|
gpgkey = file:///usr/share/qubes/repo-templates/keys/RPM-GPG-KEY-qubes-$releasever-primary
|
|
|
|
'''
|
|
|
|
repo_conf1.write(repo_str1.encode())
|
|
|
|
repo_conf1.flush()
|
|
|
|
args = argparse.Namespace(
|
|
|
|
enablerepo=[],
|
|
|
|
disablerepo=[],
|
|
|
|
repoid=['repo1', 'repo2'],
|
|
|
|
releasever='4.1',
|
|
|
|
repo_files=[repo_conf1.name]
|
|
|
|
)
|
|
|
|
with self.assertRaises(SystemExit), \
|
|
|
|
mock.patch('sys.stderr', new=io.StringIO()) as mock_err:
|
|
|
|
qubesadmin.tools.qvm_template.qrexec_payload(args, self.app,
|
|
|
|
'---', False)
|
|
|
|
# Check error message
|
|
|
|
self.assertTrue('Malformed template name'
|
|
|
|
in mock_err.getvalue())
|
|
|
|
self.assertTrue("argument should not be '---'"
|
|
|
|
in mock_err.getvalue())
|
|
|
|
self.assertAllCalled()
|