signatures.lore.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Konstantin Ryabitsev <konstantin@linuxfoundation.org>
To: signatures@kernel.org
Subject: [PATCH 2/3] Support other git dirs as sources
Date: Wed, 12 May 2021 16:37:53 +0000	[thread overview]
Message-ID: <20210512163754.4865-2-konstantin@linuxfoundation.org> (raw)
In-Reply-To: <20210512163754.4865-1-konstantin@linuxfoundation.org>

We need to have a way to specify other git dirs as sources, so change
how our ref: locations work. Instead of:

ref:[refname]:[subpath]

we now have:

ref:[repopath]:[refname]:[subpath]

Additionally, add a way to deal with one level of symlinks.

Signed-off-by: Konstantin Ryabitsev <konstantin@linuxfoundation.org>
---
 README.rst         | 22 ++++++-------
 man/patatt.5       |  2 +-
 man/patatt.5.rst   |  4 +--
 patatt/__init__.py | 79 ++++++++++++++++++++++++++++------------------
 4 files changed, 63 insertions(+), 44 deletions(-)

diff --git a/README.rst b/README.rst
index e0272b8..6cde177 100644
--- a/README.rst
+++ b/README.rst
@@ -368,12 +368,12 @@ check, via the ``keyringsrc`` setting (can be specified multiple
 times and will be checked in the listed order)::
 
     [patatt]
-        # Empty ref means "use currently checked out ref"
-        keyringsrc = ref::.keys
-        # Use a dedicated ref called refs/meta/keyring
-        keyringsrc = ref:refs/meta/keyring:
-        # You can fetch other project's keyring into its own ref
-        keyringsrc = ref:refs/meta/someone-elses-keyring:
+        # Empty ref means "use currently checked out ref in this repo"
+        keyringsrc = ref:::.keys
+        # Use a dedicated ref in this repo called refs/meta/keyring
+        keyringsrc = ref::refs/meta/keyring:
+        # Use a ref in a different repo
+        keyringsrc = ref:~/path/to/another/repo:refs/heads/main:.keys
         # Use a regular dir on disk
         keyringsrc = ~/git/pgpkeys/keyring
 
@@ -385,13 +385,13 @@ Any path on disk can be used for a keyring location, and some will
 always be checked just in case. The following locations are added by
 default::
 
-    ref::.keys
-    ref::.local-keys
-    ref:refs/meta/keyring:
+    ref:::.keys
+    ref:::.local-keys
+    ref::refs/meta/keyring:
     $XDG_DATA_HOME/patatt/public
 
-The "::" means "whatever ref is currently checked out", and
-$XDG_DATA_HOME usually points at ~/.local/share.
+The ":::" means "whatever ref is checked out in the current repo",
+and $XDG_DATA_HOME usually points at $HOME/.local/share.
 
 Getting support and contributing patches
 ----------------------------------------
diff --git a/man/patatt.5 b/man/patatt.5
index 5e97753..70cea05 100644
--- a/man/patatt.5
+++ b/man/patatt.5
@@ -1,6 +1,6 @@
 .\" Man page generated from reStructuredText.
 .
-.TH PATATT 5 "2021-05-07" "0.1.0" ""
+.TH PATATT 5 "2021-05-11" "0.2.0" ""
 .SH NAME
 PATATT \- DKIM-like cryptographic patch attestation
 .
diff --git a/man/patatt.5.rst b/man/patatt.5.rst
index f607ed9..2ab345c 100644
--- a/man/patatt.5.rst
+++ b/man/patatt.5.rst
@@ -5,10 +5,10 @@ DKIM-like cryptographic patch attestation
 -----------------------------------------
 
 :Author:    mricon@kernel.org
-:Date:      2021-05-07
+:Date:      2021-05-11
 :Copyright: The Linux Foundation and contributors
 :License:   MIT-0
-:Version:   0.1.0
+:Version:   0.2.0
 :Manual section: 5
 
 SYNOPSIS
diff --git a/patatt/__init__.py b/patatt/__init__.py
index be32e36..e547b28 100644
--- a/patatt/__init__.py
+++ b/patatt/__init__.py
@@ -41,9 +41,6 @@ RES_ERROR = 16
 RES_BADSIG = 32
 
 REQ_HDRS = [b'from', b'subject']
-DEFAULT_CONFIG = {
-    'keyringsrc': ['ref::.keys', 'ref::.local-keys', 'ref:refs/meta/keyring:'],
-}
 
 # Quick cache for key info
 KEYCACHE = dict()
@@ -598,9 +595,9 @@ def _run_command(cmdargs: list, stdin: bytes = None, env: Optional[dict] = None)
 def git_run_command(gitdir: Optional[str], args: list, stdin: Optional[bytes] = None,
                     env: Optional[dict] = None) -> Tuple[int, bytes, bytes]:
     if gitdir:
-        env = {'GIT_DIR': gitdir}
-
-    args = ['git', '--no-pager'] + args
+        args = ['git', '--git-dir', gitdir, '--no-pager'] + args
+    else:
+        args = ['git', '--no-pager'] + args
     return _run_command(args, stdin=stdin, env=env)
 
 
@@ -688,36 +685,55 @@ def get_public_key(source: str, keytype: str, identity: str, selector: str) -> T
     keypath = make_pkey_path(keytype, identity, selector)
     logger.debug('Looking for %s in %s', keypath, source)
 
-    if source.find('ref:') == 0:
-        gittop = get_git_toplevel()
+    # ref:refs/heads/someref:in-repo/path
+    if source.startswith('ref:'):
+        # split by :
+        parts = source.split(':', 4)
+        if len(parts) < 4:
+            raise ConfigurationError('Invalid ref, must have at least 3 colons: %s' % source)
+        gittop = parts[1]
+        gitref = parts[2]
+        gitsub = parts[3]
+        if not gittop:
+            gittop = get_git_toplevel()
         if not gittop:
             raise KeyError('Not in a git tree, so cannot use a ref: source')
-        # format is: ref:refspec:path
-        # or it could omit the refspec, meaning "whatever the current ref"
-        # but it should always have at least two ":"
-        chunks = source.split(':', 2)
-        if len(chunks) < 3:
-            logger.debug('ref: sources must have refspec and path, e.g.: ref:refs/heads/master:.keys')
-            raise ConfigurationError('Invalid ref: source: %s' % source)
+
+        gittop = os.path.expanduser(gittop)
+        if gittop.find('$') >= 0:
+            gittop = os.path.expandvars(gittop)
+        if os.path.isdir(os.path.join(gittop, '.git')):
+            gittop = os.path.join(gittop, '.git')
+
+        # it could omit the refspec, meaning "whatever the current ref"
         # grab the key from a fully ref'ed path
-        ref = chunks[1]
-        pathtop = chunks[2]
-        subpath = os.path.join(pathtop, keypath)
+        subpath = os.path.join(gitsub, keypath)
 
-        if not ref:
+        if not gitref:
             # What is our current ref?
-            cmdargs = ['git', 'symbolic-ref', 'HEAD']
-            ecode, out, err = _run_command(cmdargs)
+            cmdargs = ['symbolic-ref', 'HEAD']
+            ecode, out, err = git_run_command(gittop, cmdargs)
             if ecode == 0:
-                ref = out.decode().strip()
+                gitref = out.decode().strip()
+        if not gitref:
+            raise KeyError('Could not figure out current ref in %s' % gittop)
 
-        cmdargs = ['git']
-        keysrc = f'{ref}:{subpath}'
-        cmdargs += ['show', keysrc]
-        ecode, out, err = _run_command(cmdargs)
+        keysrc = f'{gitref}:{subpath}'
+        cmdargs = ['show', keysrc]
+        ecode, out, err = git_run_command(gittop, cmdargs)
         if ecode == 0:
+            # Handle one level of symlinks
+            if out.find(b'\n') < 0 < out.find(b'/'):
+                # Check this path as well
+                linktgt = os.path.normpath(os.path.join(os.path.dirname(subpath), out.decode()))
+                keysrc = f'{gitref}:{linktgt}'
+                cmdargs = ['show', keysrc]
+                ecode, out, err = git_run_command(gittop, cmdargs)
+                if ecode == 0:
+                    logger.debug('KEYSRC  : %s (symlinked)', keysrc)
+                    return out, 'ref:%s:%s' % (gittop, keysrc)
             logger.debug('KEYSRC  : %s', keysrc)
-            return out, keysrc
+            return out, 'ref:%s:%s' % (gittop, keysrc)
 
         # Does it exist on disk in gittop?
         fullpath = os.path.join(gittop, subpath)
@@ -726,7 +742,7 @@ def get_public_key(source: str, keytype: str, identity: str, selector: str) -> T
                 logger.debug('KEYSRC  : %s', fullpath)
                 return fh.read(), fullpath
 
-        raise KeyError('Could not find %s in %s' % (subpath, ref))
+        raise KeyError('Could not find %s in %s:%s' % (subpath, gittop, gitref))
 
     # It's a disk path, then
     # Expand ~ and env vars
@@ -1084,8 +1100,11 @@ def command() -> None:
         ch.setLevel(logging.CRITICAL)
 
     logger.addHandler(ch)
-    config = get_config_from_git(r'patatt\..*', section=_args.section,
-                                 defaults=DEFAULT_CONFIG, multivals=['keyringsrc'])
+    config = get_config_from_git(r'patatt\..*', section=_args.section, multivals=['keyringsrc'])
+    # Append some extra keyring locations
+    if 'keyringsrc' not in config:
+        config['keyringsrc'] = list()
+    config['keyringsrc'] += ['ref:::.keys', 'ref:::.local-keys', 'ref::refs/meta/keyring:']
     logger.debug('config: %s', config)
 
     if 'func' not in _args:
-- 
2.25.1


  reply	other threads:[~2021-05-12 16:37 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-12 16:37 [PATCH 1/3] Return better result than just pass/fail Konstantin Ryabitsev
2021-05-12 16:37 ` Konstantin Ryabitsev [this message]
2021-05-12 16:37 ` [PATCH 3/3] Release as v0.2.0 Konstantin Ryabitsev

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210512163754.4865-2-konstantin@linuxfoundation.org \
    --to=konstantin@linuxfoundation.org \
    --cc=signatures@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).