All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.