Skip to content

Commit

Permalink
apt_config: stop using the deprecated apt-key command
Browse files Browse the repository at this point in the history
This applies the same changes as apt-setup has for
dumping the keys specified in the configuration to
the target filesystem.

LP: #1892494
  • Loading branch information
nacc authored and Server Team CI Bot committed Dec 15, 2020
1 parent 698c5cd commit e099e32
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 43 deletions.
24 changes: 14 additions & 10 deletions curtin/commands/apt_config.py
Expand Up @@ -343,20 +343,24 @@ def apply_preserve_sources_list(target):
raise


def add_apt_key_raw(key, target=None):
def add_apt_key_raw(filename, key, target=None):
"""
actual adding of a key as defined in key argument
to the system
"""
LOG.debug("Adding key:\n'%s'", key)
try:
util.subp(['apt-key', 'add', '-'], data=key.encode(), target=target)
except util.ProcessExecutionError:
LOG.exception("failed to add apt GPG Key to apt keyring")
raise
if '-----BEGIN PGP PUBLIC KEY BLOCK-----' in str(key):
target_keyfile_ext = '.asc'
omode = 'w'
key = key.rstrip()
else:
target_keyfile_ext = '.gpg'
omode = 'wb'
target_keyfile = paths.target_path(target, filename + target_keyfile_ext)
util.write_file(target_keyfile, key, mode=0o644, omode=omode)
LOG.debug("Adding key to '%s':\n'%s'", target_keyfile, key)


def add_apt_key(ent, target=None):
def add_apt_key(filename, ent, target=None):
"""
Add key to the system as defined in ent (if any).
Supports raw keys or keyid's
Expand All @@ -371,7 +375,7 @@ def add_apt_key(ent, target=None):
retries=(1, 2, 5, 10))

if 'key' in ent:
add_apt_key_raw(ent['key'], target)
add_apt_key_raw(filename, ent['key'], target)


def add_apt_sources(srcdict, target=None, template_params=None,
Expand All @@ -395,7 +399,7 @@ def add_apt_sources(srcdict, target=None, template_params=None,
if 'filename' not in ent:
ent['filename'] = filename

add_apt_key(ent, target)
add_apt_key(ent['filename'], ent, target)

if 'source' not in ent:
continue
Expand Down
Binary file added tests/data/test.gpg
Binary file not shown.
125 changes: 92 additions & 33 deletions tests/unittests/test_apt_source.py
Expand Up @@ -33,17 +33,32 @@
=ACB2
-----END PGP PUBLIC KEY BLOCK-----"""

EXPECTEDKEY_NOVER = u"""-----BEGIN PGP PUBLIC KEY BLOCK-----
mI0ESuZLUgEEAKkqq3idtFP7g9hzOu1a8+v8ImawQN4TrvlygfScMU1TIS1eC7UQ
NUA8Qqgr9iUaGnejb0VciqftLrU9D6WYHSKz+EITefgdyJ6SoQxjoJdsCpJ7o9Jy
8PQnpRttiFm4qHu6BVnKnBNxw/z3ST9YMqW5kbMQpfxbGe+obRox59NpABEBAAG0
HUxhdW5jaHBhZCBQUEEgZm9yIFNjb3R0IE1vc2VyiLYEEwECACAFAkrmS1ICGwMG
CwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRAGILvPA2g/d3aEA/9tVjc10HOZwV29
OatVuTeERjjrIbxflO586GLA8cp0C9RQCwgod/R+cKYdQcHjbqVcP0HqxveLg0RZ
FJpWLmWKamwkABErwQLGlM/Hwhjfade8VvEQutH5/0JgKHmzRsoqfR+LMO6OS+Sm
S0ORP6HXET3+jC8BMG4tBWCTK/XEZw==
=ACB2
-----END PGP PUBLIC KEY BLOCK-----"""

EXPECTED_BINKEY = util.load_file("tests/data/test.gpg", decode=False)

ADD_APT_REPO_MATCH = r"^[\w-]+:\w"

TARGET = "/"


def load_tfile(filename):
def load_tfile(filename, decode=True):
""" load_tfile
load file and return content after decoding
"""
try:
content = util.load_file(filename, decode=True)
content = util.load_file(filename, decode=decode)
except Exception as error:
print('failed to load file content for test: %s' % error)
raise
Expand Down Expand Up @@ -75,8 +90,6 @@ def setUp(self):
self.aptlistfile3 = os.path.join(self.tmp, "single-deb3.list")
self.join = os.path.join
self.matcher = re.compile(ADD_APT_REPO_MATCH).search
self.add_patch('curtin.util.subp', 'm_subp')
self.m_subp.return_value = ('s390x', '')

@staticmethod
def _add_apt_sources(*args, **kwargs):
Expand Down Expand Up @@ -215,23 +228,48 @@ def test_apt_src_replace_tri(self):
self.aptlistfile3: {'source': 'deb $MIRROR $RELEASE universe'}}
self._apt_src_replace_tri(cfg)

def _apt_src_keyid(self, filename, cfg, keynum):
def _apt_src_keyid_txt(self, filename, cfg):
""" _apt_src_keyid
Test specification of a source + keyid
"""
params = self._get_default_params()

with mock.patch("curtin.util.subp",
return_value=('fakekey 1234', '')) as mockobj:
with mock.patch.object(gpg, 'getkeybyid',
return_value=EXPECTEDKEY_NOVER):
self._add_apt_sources(cfg, TARGET, template_params=params,
aa_repo_match=self.matcher)

# check if it added the right ammount of keys
calls = []
for _ in range(keynum):
calls.append(call(['apt-key', 'add', '-'], data=b'fakekey 1234',
target=TARGET))
mockobj.assert_has_calls(calls, any_order=True)
for ent in cfg:
key_filename = cfg[ent].get('filename', ent)
self.assertTrue(os.path.isfile(key_filename + '.asc'))
contents = load_tfile(key_filename + '.asc')
self.assertMultiLineEqual(EXPECTEDKEY_NOVER, contents)

def _apt_src_keyid_bin(self, filename, cfg):
""" _apt_src_keyid
Test specification of a source + keyid
"""
params = self._get_default_params()

with mock.patch.object(gpg, 'getkeybyid',
return_value=EXPECTED_BINKEY):
self._add_apt_sources(cfg, TARGET, template_params=params,
aa_repo_match=self.matcher)

for ent in cfg:
key_filename = cfg[ent].get('filename', ent)
self.assertTrue(os.path.isfile(key_filename + '.gpg'))
contents = load_tfile(key_filename + '.gpg', decode=False)
self.assertEqual(EXPECTED_BINKEY, contents)

def _apt_src_keyid(self, filename, cfg, key_type="txt"):
""" _apt_src_keyid
Test specification of a source + keyid
"""
if key_type == "txt":
self._apt_src_keyid_txt(filename, cfg)
else:
self._apt_src_keyid_bin(filename, cfg)

self.assertTrue(os.path.isfile(filename))

Expand All @@ -251,7 +289,17 @@ def test_apt_src_keyid(self):
'smoser/cloud-init-test/ubuntu'
' xenial main'),
'keyid': "03683F77"}}
self._apt_src_keyid(self.aptlistfile, cfg, 1)
self._apt_src_keyid(self.aptlistfile, cfg)

@mock.patch(ChrootableTargetStr, new=PseudoChrootableTarget)
def test_apt_src_keyid_bin(self):
"""test_apt_src_keyid - Test source + keyid with filename being set"""
cfg = {self.aptlistfile: {'source': ('deb '
'http://ppa.launchpad.net/'
'smoser/cloud-init-test/ubuntu'
' xenial main'),
'keyid': "03683F77"}}
self._apt_src_keyid(self.aptlistfile, cfg, key_type='bin')

@mock.patch(ChrootableTargetStr, new=PseudoChrootableTarget)
def test_apt_src_keyid_tri(self):
Expand All @@ -273,7 +321,7 @@ def test_apt_src_keyid_tri(self):
' xenial multiverse'),
'keyid': "03683F77"}}

self._apt_src_keyid(self.aptlistfile, cfg, 3)
self._apt_src_keyid(self.aptlistfile, cfg)
contents = load_tfile(self.aptlistfile2)
self.assertTrue(re.search(r"%s %s %s %s\n" %
("deb",
Expand All @@ -293,18 +341,23 @@ def test_apt_src_keyid_tri(self):
def test_apt_src_key(self):
"""test_apt_src_key - Test source + key"""
params = self._get_default_params()
fake_key = u"""-----BEGIN PGP PUBLIC KEY BLOCK-----
fakekey 4321"""

cfg = {self.aptlistfile: {'source': ('deb '
'http://ppa.launchpad.net/'
'smoser/cloud-init-test/ubuntu'
' xenial main'),
'key': "fakekey 4321"}}
'key': fake_key}}

with mock.patch.object(util, 'subp') as mockobj:
self._add_apt_sources(cfg, TARGET, template_params=params,
aa_repo_match=self.matcher)
self._add_apt_sources(cfg, TARGET, template_params=params,
aa_repo_match=self.matcher)

key_filename = self.aptlistfile + '.asc'
self.assertTrue(os.path.isfile(key_filename))

mockobj.assert_any_call(['apt-key', 'add', '-'], data=b'fakekey 4321',
target=TARGET)
contents = load_tfile(key_filename)
self.assertMultiLineEqual(fake_key, contents)

self.assertTrue(os.path.isfile(self.aptlistfile))

Expand All @@ -320,14 +373,18 @@ def test_apt_src_key(self):
def test_apt_src_keyonly(self):
"""test_apt_src_keyonly - Test key without source"""
params = self._get_default_params()
cfg = {self.aptlistfile: {'key': "fakekey 4242"}}
fake_key = u"""-----BEGIN PGP PUBLIC KEY BLOCK-----
fakekey 4321"""
cfg = {self.aptlistfile: {'key': fake_key}}

with mock.patch.object(util, 'subp') as mockobj:
self._add_apt_sources(cfg, TARGET, template_params=params,
aa_repo_match=self.matcher)
self._add_apt_sources(cfg, TARGET, template_params=params,
aa_repo_match=self.matcher)

key_filename = self.aptlistfile + '.asc'
self.assertTrue(os.path.isfile(key_filename))

mockobj.assert_any_call(['apt-key', 'add', '-'], data=b'fakekey 4242',
target=TARGET)
contents = load_tfile(key_filename)
self.assertMultiLineEqual(fake_key, contents)

# filename should be ignored on key only
self.assertFalse(os.path.isfile(self.aptlistfile))
Expand All @@ -338,13 +395,15 @@ def test_apt_src_keyidonly(self):
params = self._get_default_params()
cfg = {self.aptlistfile: {'keyid': "03683F77"}}

with mock.patch.object(util, 'subp',
return_value=('fakekey 1212', '')) as mockobj:
with mock.patch.object(gpg, 'getkeybyid',
return_value=EXPECTEDKEY_NOVER):
self._add_apt_sources(cfg, TARGET, template_params=params,
aa_repo_match=self.matcher)

mockobj.assert_any_call(['apt-key', 'add', '-'], data=b'fakekey 1212',
target=TARGET)
key_filename = self.aptlistfile
self.assertTrue(os.path.isfile(key_filename + '.asc'))
contents = load_tfile(key_filename + '.asc')
self.assertMultiLineEqual(EXPECTEDKEY_NOVER, contents)

# filename should be ignored on key only
self.assertFalse(os.path.isfile(self.aptlistfile))
Expand All @@ -368,7 +427,7 @@ def apt_src_keyid_real(self, cfg, expectedkey):
keycfg.get('keyserver',
'keyserver.ubuntu.com'),
retries=(1, 2, 5, 10))
mockkey.assert_called_with(expectedkey, TARGET)
mockkey.assert_called_with(self.aptlistfile, expectedkey, TARGET)

# filename should be ignored on key only
self.assertFalse(os.path.isfile(self.aptlistfile))
Expand Down Expand Up @@ -412,7 +471,7 @@ def test_apt_src_keyid_keyserver(self):

mockgetkey.assert_called_with('03683F77', 'test.random.com',
retries=(1, 2, 5, 10))
mockadd.assert_called_with('fakekey', TARGET)
mockadd.assert_called_with(self.aptlistfile, 'fakekey', TARGET)

# filename should be ignored on key only
self.assertFalse(os.path.isfile(self.aptlistfile))
Expand Down

0 comments on commit e099e32

Please sign in to comment.