Skip to content

Commit 42660f3

Browse files
committed
add a command to add additonal gpg keys
This also fixes a bug resolving remote names with the trust command.
1 parent 8b69e92 commit 42660f3

File tree

3 files changed

+59
-9
lines changed

3 files changed

+59
-9
lines changed

README.md

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,10 @@ git incrypt init $URL $GPG_KEY_ID
5454

5555
where `$URL` is the URL of the remote repository prefixed with `incrypt::` to
5656
be initialized and `$GPG_KEY_ID` is one or multiple GPG key IDs to be used to
57-
encrypt the data in the repository. Note that this version does not yet have a
58-
command to change the list of keys later, so give it a thought before setting
59-
up the repository. However if you need to change keys you can always delete
60-
the encrypted repository later and re-initialize it with other keys. For sure
61-
we should have a command in future versions that an re-encrypt the data with
62-
new keys in the future.
57+
encrypt the data in the repository.
58+
59+
If needed you can later add additional keys using the `git incrypt add`
60+
command.
6361

6462
From now on you can just use the regular git commands to communicate with the
6563
encrypted remote repository. They all should work in the ususal way but

git-incrypt

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,7 @@ class MetaData:
424424
self.keyhash = None
425425
self.template = None
426426
self.defaultbranch = None
427+
self.gpgkeys = []
427428

428429
def init(self, gpgkeys, template, defaultbranch):
429430
'initialize the metadata'
@@ -447,6 +448,14 @@ class MetaData:
447448
self.write()
448449
return self
449450

451+
def addkey(self, gpgkeys):
452+
'add gpg key'
453+
self.gpgkeys += gpgkeys
454+
cryptedkey = subprocess.check_output(
455+
['gpg', '-q', '-e'] + ['-r' + k for k in self.gpgkeys],
456+
input=MetaData.KEYVER + b'\x00' + self.key)
457+
self.files['key'] = self.repo.create_blob(cryptedkey)
458+
450459
def read(self):
451460
'read the metadata'
452461
self.files = {}
@@ -468,6 +477,13 @@ class MetaData:
468477
keyver, self.key = data.split(b'\x00', 1)
469478
assert keyver == MetaData.KEYVER, \
470479
f'Key format is {keyver}, expected {MetaData.KEYVER}'
480+
keydata = subprocess.check_output(
481+
['gpg', '-q', '--list-packets'],
482+
input=obj.read_raw()).decode('utf-8').split('\n')
483+
for k in keydata:
484+
match = re.search(r'^:pubkey enc packet:.*keyid ([0-9A-F]+)', k)
485+
if match:
486+
self.gpgkeys.append(match.group(1))
471487
self.files['sig'] = tree['sig'].id
472488
obj = tree['msg']
473489
self.files['msg'] = obj.id
@@ -568,12 +584,27 @@ def init_command(args):
568584
crypt.push([])
569585

570586

587+
def addkey_command(args):
588+
'add key to incrypt repository'
589+
try:
590+
url = pygit2.Repository('.').remotes[args.remote].url
591+
except (KeyError, ValueError):
592+
url = args.remote
593+
assert url.startswith('incrypt::'), \
594+
f'url `{url}` must start with incrypt::'
595+
crypt = CryptRepo('.', url[9:])
596+
crypt.meta.addkey(args.keys)
597+
crypt.push([])
598+
599+
571600
def trust_command(args):
572601
'trust incrypt repository'
573-
remotes = pygit2.Repository('.').remotes
574-
url = remotes[args.remote].url if args.remote in remotes else args.remote
602+
try:
603+
url = pygit2.Repository('.').remotes[args.remote].url
604+
except (KeyError, ValueError):
605+
url = args.remote
575606
assert url.startswith('incrypt::'), \
576-
'url must start with incrypt::'
607+
f'url `{url}` must start with incrypt::'
577608
crypt = CryptRepo('.', url[9:], forcetrust=True)
578609
if args.sign:
579610
crypt.meta.sign()
@@ -607,6 +638,13 @@ def tool():
607638
init_parser.add_argument(
608639
'keys', nargs='+', help='GPG keys used to encrypt the data')
609640
init_parser.set_defaults(func=init_command)
641+
addkey_parser = subparsers.add_parser(
642+
'addkey', help='Add an encryption key')
643+
addkey_parser.add_argument(
644+
'remote', type=str, help='Name of the remote')
645+
addkey_parser.add_argument(
646+
'keys', nargs='+', help='GPG keys to add')
647+
addkey_parser.set_defaults(func=addkey_command)
610648
trust_parser = subparsers.add_parser(
611649
'trust', help='Trust the remote repository')
612650
trust_parser.add_argument(

git-incrypt.adoc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ SYNOPSIS
1010
--------
1111
[verse]
1212
'git incrypt' init [-n <name>] [-e <email>] [-d <date>] [-m <msg>] <repository> <key>...
13+
'git incrypt' addkey <repository> <key>...
1314
'git incrypt' trust [-s] <repository>
1415

1516

@@ -63,6 +64,19 @@ repository. If not provided, a standard message is used. Similar to
6364
the `git commit` command, this option can be specified multiple
6465
times to add multiple paragraphs to the commit message.
6566

67+
addkey <repository> <key>...::
68+
Add the given GPG key to the list of allowed keys for the
69+
repository.
70+
+
71+
<repository> is the URL of the remote repository to add the key to.
72+
It needs to start with `incrypt::` and the remainder needs to be a
73+
URL git can understand, e.g. `incrypt::https://github.com/foo/bar.git`.
74+
Alternatively, a registered remote name that points to a URL
75+
qualifying to the criteria above can be used.
76+
+
77+
<key> is a list of GPG keys to add as allowed keys to access the
78+
repository.
79+
6680
trust [-s] <repository>::
6781
Mark the given repository as trusted. If the `-s` option is
6882
given, the repository will also be signed with the users GPG

0 commit comments

Comments
 (0)