summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKonstantin Ryabitsev <konstantin@linuxfoundation.org>2021-05-21 14:50:23 -0400
committerKonstantin Ryabitsev <konstantin@linuxfoundation.org>2021-05-21 14:50:23 -0400
commitaafc61a2009c1b5c45dcdd6326e9d4010ed7cba4 (patch)
tree02c4615191264ff20d419f7c6eb8470b4a550470
parent10dcc9f8fe8bce21d3f3cf465070736da207fd75 (diff)
downloadb4-aafc61a2009c1b5c45dcdd6326e9d4010ed7cba4.tar.gz
Move --show-keys into its own kr subcommand
There will be more keyring operations supported in the future, probably, but for now just move the --show-keys subcommand from "mbox" to "kr". Signed-off-by: Konstantin Ryabitsev <konstantin@linuxfoundation.org>
-rw-r--r--b4/command.py32
-rw-r--r--b4/kr.py93
-rw-r--r--b4/mbox.py112
-rw-r--r--man/b4.533
-rw-r--r--man/b4.5.rst21
5 files changed, 195 insertions, 96 deletions
diff --git a/b4/command.py b/b4/command.py
index d3b0c95..3f130c8 100644
--- a/b4/command.py
+++ b/b4/command.py
@@ -13,23 +13,27 @@ import sys
logger = b4.logger
-def cmd_mbox_common_opts(sp):
+def cmd_retrieval_common_opts(sp):
sp.add_argument('msgid', nargs='?',
help='Message ID to process, or pipe a raw message')
- sp.add_argument('-o', '--outdir', default='.',
- help='Output into this directory (or use - to output mailbox contents to stdout)')
sp.add_argument('-p', '--use-project', dest='useproject', default=None,
help='Use a specific project instead of guessing (linux-mm, linux-hardening, etc)')
+ sp.add_argument('-m', '--use-local-mbox', dest='localmbox', default=None,
+ help='Instead of grabbing a thread from lore, process this mbox file (or - for stdin)')
+ sp.add_argument('-C', '--no-cache', dest='nocache', action='store_true', default=False,
+ help='Do not use local cache')
+
+
+def cmd_mbox_common_opts(sp):
+ cmd_retrieval_common_opts(sp)
+ sp.add_argument('-o', '--outdir', default='.',
+ help='Output into this directory (or use - to output mailbox contents to stdout)')
sp.add_argument('-c', '--check-newer-revisions', dest='checknewer', action='store_true', default=False,
help='Check if newer patch revisions exist')
sp.add_argument('-n', '--mbox-name', dest='wantname', default=None,
help='Filename to name the mbox destination')
- sp.add_argument('-m', '--use-local-mbox', dest='localmbox', default=None,
- help='Instead of grabbing a thread from lore, process this mbox file (or - for stdin)')
sp.add_argument('-M', '--save-as-maildir', dest='maildir', action='store_true', default=False,
help='Save as maildir (avoids mbox format ambiguities)')
- sp.add_argument('-C', '--no-cache', dest='nocache', action='store_true', default=False,
- help='Do not use local cache')
def cmd_mbox(cmdargs):
@@ -37,6 +41,11 @@ def cmd_mbox(cmdargs):
b4.mbox.main(cmdargs)
+def cmd_kr(cmdargs):
+ import b4.kr
+ b4.kr.main(cmdargs)
+
+
def cmd_am(cmdargs):
import b4.mbox
b4.mbox.main(cmdargs)
@@ -86,8 +95,6 @@ def cmd():
cmd_mbox_common_opts(sp_mbox)
sp_mbox.add_argument('-f', '--filter-dupes', dest='filterdupes', action='store_true', default=False,
help='When adding messages to existing maildir, filter out duplicates')
- sp_mbox.add_argument('--show-keys', dest='showkeys', action='store_true', default=False,
- help='Show all developer keys from the thread')
sp_mbox.set_defaults(func=cmd_mbox)
# b4 am
@@ -199,6 +206,13 @@ def cmd():
help='Compare two mbx files prepared with "b4 am"')
sp_diff.set_defaults(func=cmd_diff)
+ # b4 kr
+ sp_kr = subparsers.add_parser('kr', help='Keyring operations')
+ cmd_retrieval_common_opts(sp_kr)
+ sp_kr.add_argument('--show-keys', dest='showkeys', action='store_true', default=False,
+ help='Show all developer keys found in a thread')
+ sp_kr.set_defaults(func=cmd_kr)
+
cmdargs = parser.parse_args()
logger.setLevel(logging.DEBUG)
diff --git a/b4/kr.py b/b4/kr.py
new file mode 100644
index 0000000..9f642bb
--- /dev/null
+++ b/b4/kr.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (C) 2020-2021 by the Linux Foundation
+#
+__author__ = 'Konstantin Ryabitsev <konstantin@linuxfoundation.org>'
+
+import os
+import sys
+import pathlib
+import re
+
+import b4
+import b4.mbox
+
+
+logger = b4.logger
+
+
+def main(cmdargs):
+ msgid, msgs = b4.mbox.get_msgs(cmdargs)
+ if cmdargs.showkeys:
+ logger.info('---')
+ try:
+ import patatt
+ except ModuleNotFoundError:
+ logger.info('--show-keys requires the patatt library')
+ sys.exit(1)
+
+ keydata = set()
+ for msg in msgs:
+ xdk = msg.get('x-developer-key')
+ xds = msg.get('x-developer-signature')
+ if not xdk or not xds:
+ continue
+ # grab the selector they used
+ kdata = b4.LoreMessage.get_parts_from_header(xdk)
+ sdata = b4.LoreMessage.get_parts_from_header(xds)
+ algo = kdata.get('a')
+ identity = kdata.get('i')
+ selector = sdata.get('s', 'default')
+ if algo == 'openpgp':
+ keyinfo = kdata.get('fpr')
+ elif algo == 'ed25519':
+ keyinfo = kdata.get('pk')
+ else:
+ logger.debug('Unknown key type: %s', algo)
+ continue
+ keydata.add((identity, algo, selector, keyinfo))
+
+ if not keydata:
+ logger.info('No keys found in the thread.')
+ sys.exit(0)
+ krpath = os.path.join(b4.get_data_dir(), 'keyring')
+ pgp = False
+ ecc = False
+ for identity, algo, selector, keyinfo in keydata:
+ keypath = patatt.make_pkey_path(algo, identity, selector)
+ fullpath = os.path.join(krpath, keypath)
+ if os.path.exists(fullpath):
+ status = 'known'
+ else:
+ status = 'unknown'
+ if algo == 'openpgp':
+ try:
+ uids = b4.get_gpg_uids(keyinfo)
+ if len(uids):
+ status = 'in default keyring'
+ except KeyError:
+ pass
+ pathlib.Path(os.path.dirname(fullpath)).mkdir(parents=True, exist_ok=True)
+
+ logger.info('%s: (%s)', identity, status)
+ logger.info(' keytype: %s', algo)
+ if algo == 'openpgp':
+ pgp = True
+ logger.info(' keyid: %s', keyinfo[-16:])
+ logger.info(' fpr: %s', ':'.join(re.findall(r'.{4}', keyinfo)))
+ else:
+ ecc = True
+ logger.info(' pubkey: %s', keyinfo)
+ logger.info(' krpath: %s', keypath)
+ logger.info(' fullpath: %s', fullpath)
+ logger.info('---')
+ if pgp:
+ logger.info('For openpgp keys:')
+ logger.info(' gpg --recv-key [keyid]')
+ logger.info(' gpg -a --export [keyid] > [fullpath]')
+ if ecc:
+ logger.info('For ed25519 keys:')
+ logger.info(' echo [pubkey] > [fullpath]')
+
+ sys.exit(0)
diff --git a/b4/mbox.py b/b4/mbox.py
index 55b456a..5a1670c 100644
--- a/b4/mbox.py
+++ b/b4/mbox.py
@@ -24,7 +24,7 @@ import xml.etree.ElementTree
import b4
-from typing import Optional
+from typing import Optional, Tuple
logger = b4.logger
@@ -535,12 +535,8 @@ def get_extra_series(msgs: list, direction: int = 1, wantvers: Optional[int] = N
return msgs
-def main(cmdargs):
- if cmdargs.checknewer:
- # Force nocache mode
- cmdargs.nocache = True
-
- msgs = list()
+def get_msgs(cmdargs) -> Tuple[Optional[str], Optional[list]]:
+ msgid = None
if not cmdargs.localmbox:
msgid = b4.get_msgid(cmdargs)
if not msgid:
@@ -548,13 +544,16 @@ def main(cmdargs):
sys.exit(1)
pickings = set()
- if cmdargs.cherrypick == '_':
- # Just that msgid, please
- pickings = {msgid}
+ try:
+ if cmdargs.cherrypick == '_':
+ # Just that msgid, please
+ pickings = {msgid}
+ except AttributeError:
+ pass
msgs = b4.get_pi_thread_by_msgid(msgid, useproject=cmdargs.useproject, nocache=cmdargs.nocache,
onlymsgids=pickings)
if not msgs:
- return
+ return None, msgs
else:
if cmdargs.localmbox == '-':
# The entire mbox is passed via stdin, so mailsplit it and use the first message for our msgid
@@ -563,7 +562,6 @@ def main(cmdargs):
if not len(msgs):
logger.critical('Stdin did not contain any messages')
sys.exit(1)
- msgid = msgs[0].get('Message-ID', None).strip('<>')
elif os.path.exists(cmdargs.localmbox):
msgid = b4.get_msgid(cmdargs)
@@ -583,6 +581,23 @@ def main(cmdargs):
logger.critical('Mailbox %s does not exist', cmdargs.localmbox)
sys.exit(1)
+ if not msgid and msgs:
+ for msg in msgs:
+ msgid = msg.get('Message-ID', None)
+ if msgid:
+ msgid = msgid.strip('<>')
+ break
+
+ return msgid, msgs
+
+
+def main(cmdargs):
+ if cmdargs.checknewer:
+ # Force nocache mode
+ cmdargs.nocache = True
+
+ msgid, msgs = get_msgs(cmdargs)
+
if len(msgs) and cmdargs.checknewer:
msgs = get_extra_series(msgs, direction=1)
@@ -590,79 +605,6 @@ def main(cmdargs):
make_am(msgs, cmdargs, msgid)
return
- if cmdargs.showkeys:
- logger.info('---')
- try:
- import patatt
- except ModuleNotFoundError:
- logger.info('--show-keys requires the patatt library')
- sys.exit(1)
-
- keydata = set()
- for msg in msgs:
- xdk = msg.get('x-developer-key')
- xds = msg.get('x-developer-signature')
- if not xdk or not xds:
- continue
- # grab the selector they used
- kdata = b4.LoreMessage.get_parts_from_header(xdk)
- sdata = b4.LoreMessage.get_parts_from_header(xds)
- algo = kdata.get('a')
- identity = kdata.get('i')
- selector = sdata.get('s', 'default')
- if algo == 'openpgp':
- keyinfo = kdata.get('fpr')
- elif algo == 'ed25519':
- keyinfo = kdata.get('pk')
- else:
- logger.debug('Unknown key type: %s', algo)
- continue
- keydata.add((identity, algo, selector, keyinfo))
-
- if not keydata:
- logger.info('No keys found in the thread.')
- sys.exit(0)
- krpath = os.path.join(b4.get_data_dir(), 'keyring')
- pgp = False
- ecc = False
- for identity, algo, selector, keyinfo in keydata:
- keypath = patatt.make_pkey_path(algo, identity, selector)
- fullpath = os.path.join(krpath, keypath)
- if os.path.exists(fullpath):
- status = 'known'
- else:
- status = 'unknown'
- if algo == 'openpgp':
- try:
- uids = b4.get_gpg_uids(keyinfo)
- if len(uids):
- status = 'in default keyring'
- except KeyError:
- pass
- pathlib.Path(os.path.dirname(fullpath)).mkdir(parents=True, exist_ok=True)
-
- logger.info('%s: (%s)', identity, status)
- logger.info(' keytype: %s', algo)
- if algo == 'openpgp':
- pgp = True
- logger.info(' keyid: %s', keyinfo[-16:])
- logger.info(' fpr: %s', ':'.join(re.findall(r'.{4}', keyinfo)))
- else:
- ecc = True
- logger.info(' pubkey: %s', keyinfo)
- logger.info(' krpath: %s', keypath)
- logger.info(' fullpath: %s', fullpath)
- logger.info('---')
- if pgp:
- logger.info('For openpgp keys:')
- logger.info(' gpg --recv-key [keyid]')
- logger.info(' gpg -a --export [keyid] > [fullpath]')
- if ecc:
- logger.info('For ed25519 keys:')
- logger.info(' echo [pubkey] > [fullpath]')
-
- sys.exit(0)
-
logger.info('%s messages in the thread', len(msgs))
if cmdargs.outdir == '-':
logger.info('---')
diff --git a/man/b4.5 b/man/b4.5
index 0edae24..d8e971e 100644
--- a/man/b4.5
+++ b/man/b4.5
@@ -53,9 +53,11 @@ precursor to Lore and Data in the Star Trek universe.
.IP \(bu 2
\fIb4 diff\fP: Show range\-diff style diffs between patch versions
.IP \(bu 2
-\fIb4 ty\fP: (EXPERIMENTAL) Create templated replies for processed patches and pull requests
+\fIb4 ty\fP: Create templated replies for processed patches and pull requests
.IP \(bu 2
\fIb4 attest\fP: (EXPERIMENTAL) Add cryptographic attestation to patches
+.IP \(bu 2
+\fIb4 kr\fP (EXPERIMENTAL) Operate on patatt\-compatible keyrings
.UNINDENT
.SH OPTIONS
.INDENT 0.0
@@ -325,6 +327,35 @@ Compare two mbx files prepared with "b4 am"
.UNINDENT
.sp
\fIExample\fP: b4 diff \fI\%20200526205322.23465\-1\-mic@digikod.net\fP
+.SS b4 kr
+.sp
+usage: b4 kr [\-h] [\-p USEPROJECT] [\-m LOCALMBOX] [\-C] [\-\-show\-keys] [msgid]
+.INDENT 0.0
+.TP
+.B positional arguments:
+msgid Message ID to process, or pipe a raw message
+.TP
+.B optional arguments:
+.INDENT 7.0
+.TP
+.B \-h\fP,\fB \-\-help
+show this help message and exit
+.TP
+.BI \-p \ USEPROJECT\fR,\fB \ \-\-use\-project \ USEPROJECT
+Use a specific project instead of guessing (linux\-mm, linux\-hardening, etc)
+.TP
+.BI \-m \ LOCALMBOX\fR,\fB \ \-\-use\-local\-mbox \ LOCALMBOX
+Instead of grabbing a thread from lore, process this mbox file (or \- for stdin)
+.TP
+.B \-C\fP,\fB \-\-no\-cache
+Do not use local cache
+.TP
+.B \-\-show\-keys
+Show all developer keys from the thread
+.UNINDENT
+.UNINDENT
+.sp
+\fIExample\fP: b4 kr \-\-show\-keys \fI\%20210521184811.617875\-1\-konstantin@linuxfoundation.org\fP
.SH CONFIGURATION
.sp
B4 configuration is handled via git\-config(1), so you can store it in
diff --git a/man/b4.5.rst b/man/b4.5.rst
index 2b803e0..ecbd3e8 100644
--- a/man/b4.5.rst
+++ b/man/b4.5.rst
@@ -31,8 +31,9 @@ SUBCOMMANDS
* *b4 am*: Create an mbox file that is ready to git-am
* *b4 pr*: Work with pull requests
* *b4 diff*: Show range-diff style diffs between patch versions
-* *b4 ty*: (EXPERIMENTAL) Create templated replies for processed patches and pull requests
+* *b4 ty*: Create templated replies for processed patches and pull requests
* *b4 attest*: (EXPERIMENTAL) Add cryptographic attestation to patches
+* *b4 kr* (EXPERIMENTAL) Operate on patatt-compatible keyrings
OPTIONS
-------
@@ -205,6 +206,24 @@ optional arguments:
*Example*: b4 diff 20200526205322.23465-1-mic@digikod.net
+b4 kr
+~~~~~
+usage: b4 kr [-h] [-p USEPROJECT] [-m LOCALMBOX] [-C] [--show-keys] [msgid]
+
+positional arguments:
+ msgid Message ID to process, or pipe a raw message
+
+optional arguments:
+ -h, --help show this help message and exit
+ -p USEPROJECT, --use-project USEPROJECT
+ Use a specific project instead of guessing (linux-mm, linux-hardening, etc)
+ -m LOCALMBOX, --use-local-mbox LOCALMBOX
+ Instead of grabbing a thread from lore, process this mbox file (or - for stdin)
+ -C, --no-cache Do not use local cache
+ --show-keys Show all developer keys from the thread
+
+*Example*: b4 kr --show-keys 20210521184811.617875-1-konstantin@linuxfoundation.org
+
CONFIGURATION
-------------
B4 configuration is handled via git-config(1), so you can store it in