gpg: add 'spack gpg subcommand (#3845)
- Add a `spack gpg` subcommand in anticipation of signed binaries. - GPG keys are stored in var/spack/gpg, and the spack gpg command manages them. - Docs are included on the command.
This commit is contained in:
parent
71cc4e2ad1
commit
f38d250e50
@ -71,12 +71,14 @@ addons:
|
||||
- gfortran
|
||||
- mercurial
|
||||
- graphviz
|
||||
- gnupg2
|
||||
|
||||
# Work around Travis's lack of support for Python on OSX
|
||||
before_install:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew ls --versions python > /dev/null || brew install python; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew ls --versions gcc > /dev/null || brew install gcc; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew ls --versions gnupg2 > /dev/null || brew install gnupg2; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then virtualenv venv; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then source venv/bin/activate; fi
|
||||
|
||||
|
@ -276,6 +276,70 @@ Seeing installed packages
|
||||
We know that ``spack list`` shows you the names of available packages,
|
||||
but how do you figure out which are already installed?
|
||||
|
||||
.. _cmd-spack-gpg:
|
||||
|
||||
^^^^^^^^^^^^^
|
||||
``spack gpg``
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
Spack has support for signing and verifying packages using GPG keys. A
|
||||
separate keyring is used for Spack, so any keys available in the user's home
|
||||
directory are not used.
|
||||
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
``spack gpg init``
|
||||
^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When Spack is first installed, its keyring is empty. Keys stored in
|
||||
:file:`var/spack/gpg` are the default keys for a Spack installation. These
|
||||
keys may be imported by running ``spack gpg init``. This will import the
|
||||
default keys into the keyring as trusted keys.
|
||||
|
||||
-------------
|
||||
Trusting keys
|
||||
-------------
|
||||
|
||||
Additional keys may be added to the keyring using
|
||||
``spack gpg trust <keyfile>``. Once a key is trusted, packages signed by the
|
||||
owner of they key may be installed.
|
||||
|
||||
-------------
|
||||
Creating keys
|
||||
-------------
|
||||
|
||||
You may also create your own key so that you may sign your own packages using
|
||||
``spack gpg create <name> <email>``. By default, the key has no expiration,
|
||||
but it may be set with the ``--expires <date>`` flag (see the ``gnupg2``
|
||||
documentation for accepted date formats). It is also recommended to add a
|
||||
comment as to the use of the key using the ``--comment <comment>`` flag. The
|
||||
public half of the key can also be exported for sharing with others so that
|
||||
they may use packages you have signed using the ``--export <keyfile>`` flag.
|
||||
Secret keys may also be later exported using the
|
||||
``spack gpg export <location> [<key>...]`` command.
|
||||
|
||||
------------
|
||||
Listing keys
|
||||
------------
|
||||
|
||||
In order to list the keys available in the keyring, the
|
||||
``spack gpg list`` command will list trusted keys with the ``--trusted`` flag
|
||||
and keys available for signing using ``--signing``. If you would like to
|
||||
remove keys from your keyring, ``spack gpg untrust <keyid>``. Key IDs can be
|
||||
email addresses, names, or (best) fingerprints.
|
||||
|
||||
------------------------------
|
||||
Signing and Verifying Packages
|
||||
------------------------------
|
||||
|
||||
In order to sign a package, ``spack gpg sign <file>`` should be used. By
|
||||
default, the signature will be written to ``<file>.asc``, but that may be
|
||||
changed by using the ``--output <file>`` flag. If there is only one signing
|
||||
key available, it will be used, but if there is more than one, the key to use
|
||||
must be specified using the ``--key <keyid>`` flag. The ``--clearsign`` flag
|
||||
may also be used to create a signed file which contains the contents, but it
|
||||
is not recommended. Signed packages may be verified by using
|
||||
``spack gpg verify <file>``.
|
||||
|
||||
.. _cmd-spack-find:
|
||||
|
||||
^^^^^^^^^^^^^^
|
||||
|
@ -14,6 +14,7 @@ before Spack is run:
|
||||
1. Python 2 (2.6 or 2.7) or 3 (3.3 - 3.6)
|
||||
2. A C/C++ compiler
|
||||
3. The ``git`` and ``curl`` commands.
|
||||
4. If using the ``gpg`` subcommand, ``gnupg2`` is required.
|
||||
|
||||
These requirements can be easily installed on most modern Linux systems;
|
||||
on Macintosh, XCode is required. Spack is designed to run on HPC
|
||||
|
@ -68,6 +68,13 @@
|
||||
etc_path = join_path(prefix, "etc")
|
||||
|
||||
|
||||
# GPG paths.
|
||||
gpg_keys_path = join_path(var_path, "gpg")
|
||||
mock_gpg_data_path = join_path(var_path, "gpg.mock", "data")
|
||||
mock_gpg_keys_path = join_path(var_path, "gpg.mock", "keys")
|
||||
gpg_path = join_path(opt_path, "spack", "gpg")
|
||||
|
||||
|
||||
#-----------------------------------------------------------------------------
|
||||
# Initial imports (only for use in this file -- see __all__ below.)
|
||||
#-----------------------------------------------------------------------------
|
||||
|
168
lib/spack/spack/cmd/gpg.py
Normal file
168
lib/spack/spack/cmd/gpg.py
Normal file
@ -0,0 +1,168 @@
|
||||
##############################################################################
|
||||
# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC.
|
||||
# Produced at the Lawrence Livermore National Laboratory.
|
||||
#
|
||||
# This file is part of Spack.
|
||||
# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
|
||||
# LLNL-CODE-647188
|
||||
#
|
||||
# For details, see https://github.com/llnl/spack
|
||||
# Please also see the LICENSE file for our notice and the LGPL.
|
||||
#
|
||||
# This program 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) version 2.1, February 1999.
|
||||
#
|
||||
# This program 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 terms and
|
||||
# conditions of 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 program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
from spack.util.gpg import Gpg
|
||||
import spack
|
||||
import os
|
||||
|
||||
description = "handle GPG actions for spack"
|
||||
section = "developer"
|
||||
level = "long"
|
||||
|
||||
|
||||
def setup_parser(subparser):
|
||||
setup_parser.parser = subparser
|
||||
subparsers = subparser.add_subparsers(help='GPG sub-commands')
|
||||
|
||||
verify = subparsers.add_parser('verify')
|
||||
verify.add_argument('package', type=str,
|
||||
help='the package to verify')
|
||||
verify.add_argument('signature', type=str, nargs='?',
|
||||
help='the signature file')
|
||||
verify.set_defaults(func=gpg_verify)
|
||||
|
||||
trust = subparsers.add_parser('trust')
|
||||
trust.add_argument('keyfile', type=str,
|
||||
help='add a key to the trust store')
|
||||
trust.set_defaults(func=gpg_trust)
|
||||
|
||||
untrust = subparsers.add_parser('untrust')
|
||||
untrust.add_argument('--signing', action='store_true',
|
||||
help='allow untrusting signing keys')
|
||||
untrust.add_argument('keys', nargs='+', type=str,
|
||||
help='remove keys from the trust store')
|
||||
untrust.set_defaults(func=gpg_untrust)
|
||||
|
||||
sign = subparsers.add_parser('sign')
|
||||
sign.add_argument('--output', metavar='DEST', type=str,
|
||||
help='the directory to place signatures')
|
||||
sign.add_argument('--key', metavar='KEY', type=str,
|
||||
help='the key to use for signing')
|
||||
sign.add_argument('--clearsign', action='store_true',
|
||||
help='if specified, create a clearsign signature')
|
||||
sign.add_argument('package', type=str,
|
||||
help='the package to sign')
|
||||
sign.set_defaults(func=gpg_sign)
|
||||
|
||||
create = subparsers.add_parser('create')
|
||||
create.add_argument('name', type=str,
|
||||
help='the name to use for the new key')
|
||||
create.add_argument('email', type=str,
|
||||
help='the email address to use for the new key')
|
||||
create.add_argument('--comment', metavar='COMMENT', type=str,
|
||||
default='GPG created for Spack',
|
||||
help='a description for the intended use of the key')
|
||||
create.add_argument('--expires', metavar='EXPIRATION', type=str,
|
||||
default='0', help='when the key should expire')
|
||||
create.add_argument('--export', metavar='DEST', type=str,
|
||||
help='export the public key to a file')
|
||||
create.set_defaults(func=gpg_create)
|
||||
|
||||
list = subparsers.add_parser('list')
|
||||
list.add_argument('--trusted', action='store_true',
|
||||
help='list trusted keys')
|
||||
list.add_argument('--signing', action='store_true',
|
||||
help='list keys which may be used for signing')
|
||||
list.set_defaults(func=gpg_list)
|
||||
|
||||
init = subparsers.add_parser('init')
|
||||
init.set_defaults(func=gpg_init)
|
||||
init.set_defaults(import_dir=spack.gpg_keys_path)
|
||||
|
||||
export = subparsers.add_parser('export')
|
||||
export.add_argument('location', type=str,
|
||||
help='where to export keys')
|
||||
export.add_argument('keys', nargs='*',
|
||||
help='the keys to export; '
|
||||
'all secret keys if unspecified')
|
||||
export.set_defaults(func=gpg_export)
|
||||
|
||||
|
||||
def gpg_create(args):
|
||||
if args.export:
|
||||
old_sec_keys = Gpg.signing_keys()
|
||||
Gpg.create(name=args.name, email=args.email,
|
||||
comment=args.comment, expires=args.expires)
|
||||
if args.export:
|
||||
new_sec_keys = set(Gpg.signing_keys())
|
||||
new_keys = new_sec_keys.difference(old_sec_keys)
|
||||
Gpg.export_keys(args.export, *new_keys)
|
||||
|
||||
|
||||
def gpg_export(args):
|
||||
keys = args.keys
|
||||
if not keys:
|
||||
keys = Gpg.signing_keys()
|
||||
Gpg.export_keys(args.location, *keys)
|
||||
|
||||
|
||||
def gpg_list(args):
|
||||
Gpg.list(args.trusted, args.signing)
|
||||
|
||||
|
||||
def gpg_sign(args):
|
||||
key = args.key
|
||||
if key is None:
|
||||
keys = Gpg.signing_keys()
|
||||
if len(keys) == 1:
|
||||
key = keys[0]
|
||||
elif not keys:
|
||||
raise RuntimeError('no signing keys are available')
|
||||
else:
|
||||
raise RuntimeError('multiple signing keys are available; '
|
||||
'please choose one')
|
||||
output = args.output
|
||||
if not output:
|
||||
output = args.package + '.asc'
|
||||
# TODO: Support the package format Spack creates.
|
||||
Gpg.sign(key, args.package, output, args.clearsign)
|
||||
|
||||
|
||||
def gpg_trust(args):
|
||||
Gpg.trust(args.keyfile)
|
||||
|
||||
|
||||
def gpg_init(args):
|
||||
for root, _, filenames in os.walk(args.import_dir):
|
||||
for filename in filenames:
|
||||
if not filename.endswith('.key'):
|
||||
continue
|
||||
Gpg.trust(os.path.join(root, filename))
|
||||
|
||||
|
||||
def gpg_untrust(args):
|
||||
Gpg.untrust(args.signing, *args.keys)
|
||||
|
||||
|
||||
def gpg_verify(args):
|
||||
# TODO: Support the package format Spack creates.
|
||||
signature = args.signature
|
||||
if signature is None:
|
||||
signature = args.package + '.asc'
|
||||
Gpg.verify(signature, args.package)
|
||||
|
||||
|
||||
def gpg(parser, args):
|
||||
if args.func:
|
||||
args.func(args)
|
181
lib/spack/spack/test/cmd/gpg.py
Normal file
181
lib/spack/spack/test/cmd/gpg.py
Normal file
@ -0,0 +1,181 @@
|
||||
##############################################################################
|
||||
# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC.
|
||||
# Produced at the Lawrence Livermore National Laboratory.
|
||||
#
|
||||
# This file is part of Spack.
|
||||
# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
|
||||
# LLNL-CODE-647188
|
||||
#
|
||||
# For details, see https://github.com/llnl/spack
|
||||
# Please also see the LICENSE file for our notice and the LGPL.
|
||||
#
|
||||
# This program 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) version 2.1, February 1999.
|
||||
#
|
||||
# This program 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 terms and
|
||||
# conditions of 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 program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
import argparse
|
||||
import os.path
|
||||
|
||||
import pytest
|
||||
import spack
|
||||
import spack.cmd.gpg as gpg
|
||||
import spack.util.gpg as gpg_util
|
||||
from spack.util.executable import ProcessError
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def testing_gpg_directory(tmpdir):
|
||||
old_gpg_path = gpg_util.GNUPGHOME
|
||||
gpg_util.GNUPGHOME = str(tmpdir.join('gpg'))
|
||||
yield
|
||||
gpg_util.GNUPGHOME = old_gpg_path
|
||||
|
||||
|
||||
def has_gnupg2():
|
||||
try:
|
||||
gpg_util.Gpg.gpg()('--version')
|
||||
return True
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
@pytest.mark.usefixtures('testing_gpg_directory')
|
||||
@pytest.mark.skipif(not has_gnupg2(),
|
||||
reason='These tests require gnupg2')
|
||||
def test_gpg(tmpdir):
|
||||
parser = argparse.ArgumentParser()
|
||||
gpg.setup_parser(parser)
|
||||
|
||||
# Verify a file with an empty keyring.
|
||||
args = parser.parse_args(['verify', os.path.join(
|
||||
spack.mock_gpg_data_path, 'content.txt')])
|
||||
with pytest.raises(ProcessError):
|
||||
gpg.gpg(parser, args)
|
||||
|
||||
# Import the default key.
|
||||
args = parser.parse_args(['init'])
|
||||
args.import_dir = spack.mock_gpg_keys_path
|
||||
gpg.gpg(parser, args)
|
||||
|
||||
# List the keys.
|
||||
# TODO: Test the output here.
|
||||
args = parser.parse_args(['list', '--trusted'])
|
||||
gpg.gpg(parser, args)
|
||||
args = parser.parse_args(['list', '--signing'])
|
||||
gpg.gpg(parser, args)
|
||||
|
||||
# Verify the file now that the key has been trusted.
|
||||
args = parser.parse_args(['verify', os.path.join(
|
||||
spack.mock_gpg_data_path, 'content.txt')])
|
||||
gpg.gpg(parser, args)
|
||||
|
||||
# Untrust the default key.
|
||||
args = parser.parse_args(['untrust', 'Spack testing'])
|
||||
gpg.gpg(parser, args)
|
||||
|
||||
# Now that the key is untrusted, verification should fail.
|
||||
args = parser.parse_args(['verify', os.path.join(
|
||||
spack.mock_gpg_data_path, 'content.txt')])
|
||||
with pytest.raises(ProcessError):
|
||||
gpg.gpg(parser, args)
|
||||
|
||||
# Create a file to test signing.
|
||||
test_path = tmpdir.join('to-sign.txt')
|
||||
with open(str(test_path), 'w+') as fout:
|
||||
fout.write('Test content for signing.\n')
|
||||
|
||||
# Signing without a private key should fail.
|
||||
args = parser.parse_args(['sign', str(test_path)])
|
||||
with pytest.raises(RuntimeError) as exc_info:
|
||||
gpg.gpg(parser, args)
|
||||
assert exc_info.value.args[0] == 'no signing keys are available'
|
||||
|
||||
# Create a key for use in the tests.
|
||||
keypath = tmpdir.join('testing-1.key')
|
||||
args = parser.parse_args(['create',
|
||||
'--comment', 'Spack testing key',
|
||||
'--export', str(keypath),
|
||||
'Spack testing 1',
|
||||
'spack@googlegroups.com'])
|
||||
gpg.gpg(parser, args)
|
||||
keyfp = gpg_util.Gpg.signing_keys()[0]
|
||||
|
||||
# List the keys.
|
||||
# TODO: Test the output here.
|
||||
args = parser.parse_args(['list', '--trusted'])
|
||||
gpg.gpg(parser, args)
|
||||
args = parser.parse_args(['list', '--signing'])
|
||||
gpg.gpg(parser, args)
|
||||
|
||||
# Signing with the default (only) key.
|
||||
args = parser.parse_args(['sign', str(test_path)])
|
||||
gpg.gpg(parser, args)
|
||||
|
||||
# Verify the file we just verified.
|
||||
args = parser.parse_args(['verify', str(test_path)])
|
||||
gpg.gpg(parser, args)
|
||||
|
||||
# Export the key for future use.
|
||||
export_path = tmpdir.join('export.testing.key')
|
||||
args = parser.parse_args(['export', str(export_path)])
|
||||
gpg.gpg(parser, args)
|
||||
|
||||
# Create a second key for use in the tests.
|
||||
args = parser.parse_args(['create',
|
||||
'--comment', 'Spack testing key',
|
||||
'Spack testing 2',
|
||||
'spack@googlegroups.com'])
|
||||
gpg.gpg(parser, args)
|
||||
|
||||
# List the keys.
|
||||
# TODO: Test the output here.
|
||||
args = parser.parse_args(['list', '--trusted'])
|
||||
gpg.gpg(parser, args)
|
||||
args = parser.parse_args(['list', '--signing'])
|
||||
gpg.gpg(parser, args)
|
||||
|
||||
test_path = tmpdir.join('to-sign-2.txt')
|
||||
with open(str(test_path), 'w+') as fout:
|
||||
fout.write('Test content for signing.\n')
|
||||
|
||||
# Signing with multiple signing keys is ambiguous.
|
||||
args = parser.parse_args(['sign', str(test_path)])
|
||||
with pytest.raises(RuntimeError) as exc_info:
|
||||
gpg.gpg(parser, args)
|
||||
assert exc_info.value.args[0] == \
|
||||
'multiple signing keys are available; please choose one'
|
||||
|
||||
# Signing with a specified key.
|
||||
args = parser.parse_args(['sign', '--key', keyfp, str(test_path)])
|
||||
gpg.gpg(parser, args)
|
||||
|
||||
# Untrusting signing keys needs a flag.
|
||||
args = parser.parse_args(['untrust', 'Spack testing 1'])
|
||||
with pytest.raises(ProcessError):
|
||||
gpg.gpg(parser, args)
|
||||
|
||||
# Untrust the key we created.
|
||||
args = parser.parse_args(['untrust', '--signing', keyfp])
|
||||
gpg.gpg(parser, args)
|
||||
|
||||
# Verification should now fail.
|
||||
args = parser.parse_args(['verify', str(test_path)])
|
||||
with pytest.raises(ProcessError):
|
||||
gpg.gpg(parser, args)
|
||||
|
||||
# Trust the exported key.
|
||||
args = parser.parse_args(['trust', str(export_path)])
|
||||
gpg.gpg(parser, args)
|
||||
|
||||
# Verification should now succeed again.
|
||||
args = parser.parse_args(['verify', str(test_path)])
|
||||
gpg.gpg(parser, args)
|
120
lib/spack/spack/util/gpg.py
Normal file
120
lib/spack/spack/util/gpg.py
Normal file
@ -0,0 +1,120 @@
|
||||
##############################################################################
|
||||
# Copyright (c) 2013-2016, Lawrence Livermore National Security, LLC.
|
||||
# Produced at the Lawrence Livermore National Laboratory.
|
||||
#
|
||||
# This file is part of Spack.
|
||||
# Created by Todd Gamblin, tgamblin@llnl.gov, All rights reserved.
|
||||
# LLNL-CODE-647188
|
||||
#
|
||||
# For details, see https://github.com/llnl/spack
|
||||
# Please also see the LICENSE file for our notice and the LGPL.
|
||||
#
|
||||
# This program 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) version 2.1, February 1999.
|
||||
#
|
||||
# This program 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 terms and
|
||||
# conditions of 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 program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
##############################################################################
|
||||
|
||||
import os
|
||||
|
||||
import spack
|
||||
from spack.util.executable import Executable
|
||||
|
||||
|
||||
GNUPGHOME = spack.gpg_path
|
||||
|
||||
|
||||
class Gpg(object):
|
||||
@staticmethod
|
||||
def gpg():
|
||||
# TODO: Support loading up a GPG environment from a built gpg.
|
||||
gpg = Executable('gpg2')
|
||||
if not os.path.exists(GNUPGHOME):
|
||||
os.makedirs(GNUPGHOME)
|
||||
os.chmod(GNUPGHOME, 0o700)
|
||||
gpg.add_default_env('GNUPGHOME', GNUPGHOME)
|
||||
return gpg
|
||||
|
||||
@classmethod
|
||||
def create(cls, **kwargs):
|
||||
r, w = os.pipe()
|
||||
r = os.fdopen(r, 'r')
|
||||
w = os.fdopen(w, 'w')
|
||||
w.write('''
|
||||
Key-Type: rsa
|
||||
Key-Length: 4096
|
||||
Key-Usage: sign
|
||||
Name-Real: %(name)s
|
||||
Name-Email: %(email)s
|
||||
Name-Comment: %(comment)s
|
||||
Expire-Date: %(expires)s
|
||||
%%no-protection
|
||||
%%commit
|
||||
''' % kwargs)
|
||||
w.close()
|
||||
cls.gpg()('--gen-key', '--batch', input=r)
|
||||
r.close()
|
||||
|
||||
@classmethod
|
||||
def signing_keys(cls):
|
||||
keys = []
|
||||
output = cls.gpg()('--list-secret-keys', '--with-colons',
|
||||
'--fingerprint', output=str)
|
||||
for line in output.split('\n'):
|
||||
if line.startswith('fpr'):
|
||||
keys.append(line.split(':')[9])
|
||||
return keys
|
||||
|
||||
@classmethod
|
||||
def export_keys(cls, location, *keys):
|
||||
cls.gpg()('--armor', '--export', '--output', location, *keys)
|
||||
|
||||
@classmethod
|
||||
def trust(cls, keyfile):
|
||||
cls.gpg()('--import', keyfile)
|
||||
|
||||
@classmethod
|
||||
def untrust(cls, signing, *keys):
|
||||
args = [
|
||||
'--yes',
|
||||
'--batch',
|
||||
]
|
||||
if signing:
|
||||
signing_args = args + ['--delete-secret-keys'] + list(keys)
|
||||
cls.gpg()(*signing_args)
|
||||
args.append('--delete-keys')
|
||||
args.extend(keys)
|
||||
cls.gpg()(*args)
|
||||
|
||||
@classmethod
|
||||
def sign(cls, key, file, output, clearsign=False):
|
||||
args = [
|
||||
'--armor',
|
||||
'--default-key', key,
|
||||
'--output', output,
|
||||
file,
|
||||
]
|
||||
if clearsign:
|
||||
args.insert(0, '--clearsign')
|
||||
else:
|
||||
args.insert(0, '--detach-sign')
|
||||
cls.gpg()(*args)
|
||||
|
||||
@classmethod
|
||||
def verify(cls, signature, file):
|
||||
cls.gpg()('--verify', signature, file)
|
||||
|
||||
@classmethod
|
||||
def list(cls, trusted, signing):
|
||||
if trusted:
|
||||
cls.gpg()('--list-public-keys')
|
||||
if signing:
|
||||
cls.gpg()('--list-secret-keys')
|
3
var/spack/gpg.mock/README.md
Normal file
3
var/spack/gpg.mock/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Mock GPG directory
|
||||
|
||||
This directory contains keys and data used in the testing Spack.
|
1
var/spack/gpg.mock/data/content.txt
Normal file
1
var/spack/gpg.mock/data/content.txt
Normal file
@ -0,0 +1 @@
|
||||
This file has a signature signed by an external key.
|
17
var/spack/gpg.mock/data/content.txt.asc
Normal file
17
var/spack/gpg.mock/data/content.txt.asc
Normal file
@ -0,0 +1,17 @@
|
||||
-----BEGIN PGP SIGNATURE-----
|
||||
Version: GnuPG v2
|
||||
|
||||
iQIcBAABCAAGBQJZELiKAAoJENygJBhApdriPvgP/0shBTmx4jg6QaI0zyie8a+R
|
||||
+L/o9iIV4MqvBI5g+Ti+nktoCSxSOPOYFW4af740A7/43wIML9LK+gIhx/QbCrMb
|
||||
bNqzyIry9/L6PK1cCuXvd10CT+MCF1P0hdaMtKihdBYB3J8f5y1i30z+a8YWsRsX
|
||||
tPMVF/HunlpAkSWIpjmbJzFPT1R/UiBHl4VJ+mM3NNZYNIq8ZhKUiXwlQkZ8R8zg
|
||||
M0IEFkwfFtp7JxnhG7jR0k63cNm3KSocAJpwENy46RKGsAvwvqTzRh4T2MlmQIjH
|
||||
TC1MA8alJvtSdBHpkKffSU8jLewKHe1H48nc9NifMy04Ni8fSlGZe14Oe7Krqla0
|
||||
qWs+XHrGCmSleyiRUQes1MKQ7NhumKEoEaU+q0/c+lUDILZp1TlfvTPg2fzng4M/
|
||||
YF6+f+wqM+xY6z1/IloOMHis5oALjARSO88ldrLU4DQp/6jTKJO/+I4uWhMnPkMW
|
||||
+a3GLWl1CShReHKbWZTLFtdQATZXA8M6wQ8FAsLOmRLb0AlEQ28A8fHrBCCdU2xj
|
||||
tSG++U1ZUo64cMYQmIMsvIApnkTh7qCkDjaVBP1to3qc83YHncxorydz9ERpuDvP
|
||||
d1IOHlJyUSM4+sLkCPvH9QyTaJn/x7D/VraznEiptGON7G6G9AgyAzIgYamm1Kwh
|
||||
UDhbQDFDhLLvUSDGzO3l
|
||||
=kwo9
|
||||
-----END PGP SIGNATURE-----
|
30
var/spack/gpg.mock/keys/external.key
Normal file
30
var/spack/gpg.mock/keys/external.key
Normal file
@ -0,0 +1,30 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: GnuPG v2
|
||||
|
||||
mQINBFkQuFIBEAC7DiUM7jQ01kaGX+4nguzVeYquBRYoEUiObl5UIVSavMn4I7Oy
|
||||
aytG+qR26tUpunjEB6ftIQMJSyPKueclUJBaQ9lzQ3WpFC3ItpBNkMxHpiqPa9DX
|
||||
ddMk2QtJt4TlCWJEdnhR/92mMF+vf7B5/OvFvKOi0P+AwzBHC8IKTxml/UosmeVI
|
||||
Cs69FzRDXyqQxQAkATmuDmHXPaC6RkDmpVRe3ej+Kr+Xu4vcb/EBHg/vcZkFdSmi
|
||||
hyOj21/8LQZzcwTg4TSgHzKqbjPtIEQM3NNksvcFYlq2X0ad4cBcxa1Hj5xV8oS/
|
||||
bdYOFSdsh3QRROcEeKYVQZhvCR12qS93P4b2egbamBxCQK0Sn6QPIjlR6+Ya2/6p
|
||||
/hHddF+YVA6HJ22QZjaORf9lImYfYMs1ka2GtgkczOeaFEfcJ96nIa8Qb1jcrOon
|
||||
/3k/l+Ae09HRCcGB2DgKXw7S+CXKt46Oadp3bIDAyceotGnrG3cVA6A9Lwqy6U/5
|
||||
ywry8ETu3wlIR3EAIwM0a/3xCPg3cC/bt9rSqsFcmXyxltGI2CBTWcTqcyjW4VAw
|
||||
nVI8otBd4yNdimhpxLfx6AaMjA+D+OSltnAZUrp1fSFVhWLpTxLbcTv+HJ/g4U+x
|
||||
+PAsQ79Hzmzvy/8nOvIprGzY4LCmBPbLUB47Yu761HhYQhkuJiYP1R/GzQARAQAB
|
||||
tDpTcGFjayB0ZXN0aW5nIChTcGFjayB0ZXN0aW5nIGtleSkgPHNwYWNrQGdvb2ds
|
||||
ZWdyb3Vwcy5jb20+iQI3BBMBCAAhBQJZELhSAhsDBQsJCAcCBhUICQoLAgQWAgMB
|
||||
Ah4BAheAAAoJENygJBhApdriOnUP/iLC1ZxyBP3STSVgBBTS1L6FnRAc9ya6eXNT
|
||||
EwLLoSL0I0srs0sThmhyW38ZamsXYDhggaetShxemcO0BoNAii/oNK9yQoXNF4f6
|
||||
7wg2ZxCDuDjp/3VsbiI+kNlH2kj1tQ/M53ak9nYhmwLJFfKzjQBWJiyTwYZwO3MB
|
||||
QvXBvLIKj6IDS20o+7jbOq8F243vo5/uNHc/6C9eC3i4jzXWVlln2+iN/e5sVt+X
|
||||
ZiggLK2Goj5CZ7ZjZQvdoH4wKbSPLBg0Lh5FYSih9p0wx0UTEoi0jPqFUDw81duz
|
||||
IyxjbGASSaUxoz16C2U/olPEAAXeBe4266jRQwTrn+sEIX5FD+RGoryXQ97pV5up
|
||||
I9wb2anVAMHOf20iYep3vYTjnFG/81ykODm8+I4D/Jj0EEe1E2b0D+7RQ9xKNYxC
|
||||
fDgY3isXBFzmS6O4h8N27P06yfzQX+zvjPrrHRB7ka2pmDT3M421p2wN0n9aCq1J
|
||||
8+M5UdpF98A38oosyE53KcItoCUFLgEP3KrWPwvpDUC2sNQAOFiHeitzc+v1iwmD
|
||||
RScdefCQ8qc2JJdCqMG6M0tlFy6Tw1o0eBYOhhDGa0rq/PQ4NewR2dj+yDXXBGJy
|
||||
ElR0VChqniMCyd2Q4SDPnhcVrWPTYSKL1MpsL0lXED8TGOdoAHHmQNU8MWhqmdBy
|
||||
zcWArNUY
|
||||
=yVqw
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
5
var/spack/gpg/README.md
Normal file
5
var/spack/gpg/README.md
Normal file
@ -0,0 +1,5 @@
|
||||
# GPG Keys
|
||||
|
||||
This directory contains keys that should be trusted by this installation of
|
||||
Spack. They are imported when running `spack gpg init`, but may also be
|
||||
imported manually with `spack gpg trust path/to/key`.
|
Loading…
Reference in New Issue
Block a user