Skip to content

Commit

Permalink
lib: Drop keyring creation
Browse files Browse the repository at this point in the history
The only use of the GPG keys is to validate the buildroot source. With
`mmdebstrap` a full GPG keyring was required. However, the `ostree`
`--gpg-import` option accepts individual keys and builds the remote
trusted keyring on its own. Stop creating the keyring and just pass the
key paths to `ostree`. After that the explicit host `gnupg` dependency
is no longer required (although `ostree` internally uses `gnupg`).

https://phabricator.endlessm.com/T35019
  • Loading branch information
dbnicholson committed Nov 13, 2023
1 parent a8d0732 commit c582949
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 174 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ Setup
Known to work on Debian Buster (10) and newer. Required packages:

* ostree
* gnupg
* python3

Image signing
Expand Down
1 change: 0 additions & 1 deletion config/defaults.ini
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ tmpconfig = ${tmpdir}/config.ini
tmpfullconfig = ${tmpdir}/fullconfig.ini
baselib = ${srcdir}/lib/eib.sh
ssh_options = -i ${sysconfdir}/ssh-key.pem -o StrictHostKeyChecking=no
keyring = ${tmpdir}/eib-keyring.gpg
manifestdir = ${tmpdir}/manifest

[buildroot]
Expand Down
61 changes: 19 additions & 42 deletions lib/eib.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
import struct
import subprocess
import sys
import tempfile
import time

logger = logging.getLogger(__name__)
Expand Down Expand Up @@ -402,49 +401,27 @@ def setup_logging():
logging.basicConfig(level=level, format=log_format, datefmt=date_format)


def get_keyring(config):
"""Get the path to the temporary GPG keyring
def get_ostree_trusted_keys(config):
"""Get the paths to all ostree GPG trusted keys
If it doesn't exist, it will be created.
All GPG keys in data/keys/*.asc and <localdir>/data/keys/*.asc are
included.
"""
keyring = config['build']['keyring']

if not os.path.isfile(keyring):
logger.info('Creating temporary GPG keyring %s', keyring)

keyspaths = [os.path.join(config['build']['datadir'], 'keys')]
if 'localdatadir' in config['build']:
keyspaths.append(os.path.join(config['build']['localdatadir'],
'keys'))

keysdirs = list(filter(os.path.isdir, keyspaths))
if len(keysdirs) == 0:
raise ImageBuildError('No gpg keys directories at',
' or '.join(keyspaths))

keys = list(itertools.chain.from_iterable(
[glob.iglob(os.path.join(d, '*.asc')) for d in keysdirs]
))
if len(keys) == 0:
raise ImageBuildError('No gpg keys in', ' or '.join(keysdirs))

# Use a temporary gpg homedir
with tempfile.TemporaryDirectory(dir=config['build']['tmpdir'],
prefix='eib-keyring') as homedir:
# Import the keys
for key in keys:
logger.info('Importing GPG key %s', key)
subprocess.check_call(['gpg', '--batch', '--quiet',
'--homedir', homedir,
'--import', key])

# Export all the keys as a normal PGP stream since newer
# gnupg imports to a keybox.
subprocess.check_call(['gpg', '--batch', '--quiet',
'--homedir', homedir,
'--export', '--output', keyring])

return keyring
keyspaths = [os.path.join(config['build']['datadir'], 'keys')]
if 'localdatadir' in config['build']:
keyspaths.append(os.path.join(config['build']['localdatadir'], 'keys'))

keysdirs = list(filter(os.path.isdir, keyspaths))
if len(keysdirs) == 0:
raise ImageBuildError('No gpg keys directories in', ' '.join(keyspaths))

keys = sorted(itertools.chain.from_iterable(
glob.iglob(os.path.join(d, '*.asc')) for d in keysdirs
))
if len(keys) == 0:
raise ImageBuildError('No gpg keys in', ' '.join(keysdirs))

return keys


def disk_usage(path):
Expand Down
13 changes: 8 additions & 5 deletions run-build
Original file line number Diff line number Diff line change
Expand Up @@ -592,8 +592,8 @@ class ImageBuilder(object):
else:
remote_url = self.config['ostree']['dev_pull_url']

# Make sure the keyring is created
keyring = eib.get_keyring(self.config)
# Get the list of ostree trusted keys.
keys = eib.get_ostree_trusted_keys(self.config)

# Recreate the remote setup to ensure there aren't any stale settings. Don't
# bother GPG verifying the summary if it's being fetched over HTTPS. This often
Expand All @@ -611,17 +611,20 @@ class ImageBuilder(object):
'--if-exists',
remote,
])
subprocess.check_call([
remote_add_cmd = [
'ostree',
f'--repo={repo_path}',
'remote',
'add',
f'--set=gpg-verify-summary={gpg_verify_summary_str}',
f'--gpg-import={keyring}',
]
remote_add_cmd += [f'--gpg-import={key}' for key in keys]
remote_add_cmd += [
remote,
remote_url,
self.config['ostree']['ref'],
])
]
subprocess.check_call(remote_add_cmd)

# Prune the builder's ostree to keep the local repo from growing unbounded. Only
# the latest commit on each ref is needed to minimize the pull size.
Expand Down
125 changes: 0 additions & 125 deletions tests/eib/test_keyring.py

This file was deleted.

61 changes: 61 additions & 0 deletions tests/eib/test_ostree_trusted_keys.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Tests for eib ostree trusted key handling

import eib
import os
import pytest
import shutil

from ..util import TESTSDIR


@pytest.fixture
def keys_config(tmp_path, config):
config['build']['tmpdir'] = str(tmp_path)

datadir = tmp_path / 'data'
config['build']['datadir'] = str(datadir)

localdatadir = tmp_path / 'local' / 'data'
config['build']['localdatadir'] = str(localdatadir)

return config


def test_errors(keys_config):
"""Test errors from get_ostree_trusted_keys"""
with pytest.raises(eib.ImageBuildError, match='No gpg keys directories'):
eib.get_ostree_trusted_keys(keys_config)

os.makedirs(os.path.join(keys_config['build']['datadir'], 'keys'))
os.makedirs(os.path.join(keys_config['build']['localdatadir'], 'keys'))
with pytest.raises(eib.ImageBuildError, match='No gpg keys in'):
eib.get_ostree_trusted_keys(keys_config)


def test_get_keys(keys_config):
"""Test the keys are gathered correctly"""
keysdir = os.path.join(keys_config['build']['datadir'], 'keys')
localkeysdir = os.path.join(keys_config['build']['localdatadir'],
'keys')
testdatadir = os.path.join(TESTSDIR, 'data')
os.makedirs(keysdir)
os.makedirs(localkeysdir)

shutil.copy2(os.path.join(testdatadir, 'test1.asc'), keysdir)
keys = eib.get_ostree_trusted_keys(keys_config)
assert keys == [os.path.join(keysdir, 'test1.asc')]

shutil.copy2(os.path.join(testdatadir, 'test2.asc'), keysdir)
keys = eib.get_ostree_trusted_keys(keys_config)
assert keys == [
os.path.join(keysdir, 'test1.asc'),
os.path.join(keysdir, 'test2.asc'),
]

shutil.copy2(os.path.join(testdatadir, 'test3.asc'), localkeysdir)
keys = eib.get_ostree_trusted_keys(keys_config)
assert keys == [
os.path.join(keysdir, 'test1.asc'),
os.path.join(keysdir, 'test2.asc'),
os.path.join(localkeysdir, 'test3.asc'),
]

0 comments on commit c582949

Please sign in to comment.