Skip to content

Commit ff8c2ce

Browse files
committed
Cleaning up the whole GNUPGHOME mess
1 parent b8e0b0b commit ff8c2ce

File tree

4 files changed

+54
-48
lines changed

4 files changed

+54
-48
lines changed

.github/workflows/test.yml

+1-5
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,6 @@ jobs:
3636
- name: Preprare Keys
3737
shell: bash
3838
run: |
39-
export GNUPGHOME=$GITHUB_WORKSPACE/.gpg
40-
mkdir -p $GNUPGHOME
4139
echo -n "${{ secrets.PGP_KEY }}" | base64 --decode | gpg --import --batch --pinentry-mode=loopback
4240
echo -n "${{ secrets.BSD_KEY }}" > $GITHUB_WORKSPACE/bsd-key
4341
@@ -52,7 +50,5 @@ jobs:
5250

5351
- name: Test
5452
shell: bash
55-
run: |
56-
export GNUPGHOME=$GITHUB_WORKSPACE/.gpg
57-
nox --sessions test --force-python ${{ steps.setup-python.outputs.python-path }}
53+
run: nox --sessions test --force-python ${{ steps.setup-python.outputs.python-path }}
5854

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ dist = repo.add_distribution('jammy',
7272
repo.assign_package(package1, dist, component='main')
7373
repo.assign_package(package2, dist, component='main')
7474

75-
signer = PgpSigner(Path.home() / '.gnupg', 'name_of_key_to_use', 'password_of_that_key')
75+
signer = PgpSigner('name_of_key_to_use', 'password_of_that_key')
7676

7777
repo.export(Path('/path/of/new/repo'), signer)
7878

@@ -88,7 +88,7 @@ repo = RpmRepo()
8888
repo.add_package(Path('/path/to/awesome-3.14-1.el9.x86_64.rpm'))
8989
repo.add_package(Path('/path/to/awesome-3.14-1.el9.aarch64.rpm'))
9090

91-
signer = PgpSigner(Path.home() / '.gnupg', 'name_of_key_to_use', 'password_of_that_key')
91+
signer = PgpSigner('name_of_key_to_use', 'password_of_that_key')
9292

9393
repo.export(Path('/path/of/new/repo'), signer)
9494

@@ -105,7 +105,7 @@ repo = PacmanRepo('myrepo')
105105
# otherwise new signature will be generated at export time
106106
repo.add_package(Path('/path/to/awesome-3.14-1-x86_64.pkg.tar.zst'))
107107

108-
signer = PgpSigner(Path.home() / '.gnupg', 'name_of_key_to_use', 'password_of_that_key')
108+
signer = PgpSigner('name_of_key_to_use', 'password_of_that_key')
109109

110110
repo.export(Path('/path/of/new/repo'), signer)
111111

src/repopulator/pgp_signer.py

+47-34
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import subprocess
1010
from pathlib import Path
11+
from typing import Optional
1112

1213
class PgpSigner:
1314
"""Implementation of PGP signing
@@ -20,18 +21,18 @@ class PgpSigner:
2021
You are required to supply key name and password for signing. Signing is done non-interactively without any
2122
user prompts.
2223
"""
23-
def __init__(self, homedir: Path, key_name: str, key_pwd: str):
24+
def __init__(self, *, key_name: str, key_pwd: str, homedir: Optional[str | Path] = None):
2425
"""Constructor for PgpSigner class
2526
2627
Args:
27-
homedir: GPG home directory. This is normally Path.home() / '.gpg' but can be set to anything for
28-
custom configuration
2928
key_name: name or identifier of the key to use
3029
key_pwd: password of the key
30+
homedir: GPG home directory. If not specified the gpg defaults are used (including
31+
honoring GNUPGHOME environment variable)
3132
"""
3233
self.__homedir = homedir
33-
self.__keyName = key_name
34-
self.__keyPwd = key_pwd
34+
self.__key_name = key_name
35+
self.__key_pwd = key_pwd
3536

3637
def sign_external(self, path: Path, sig_path: Path):
3738
"""Signs a given file producing text (aka "armored") signature in a separate file
@@ -40,14 +41,17 @@ def sign_external(self, path: Path, sig_path: Path):
4041
path: file to sign
4142
sig_path: path to write the signature to
4243
"""
43-
subprocess.run(['gpg', '--batch', '--quiet', '--pinentry-mode=loopback',
44-
'--homedir', self.__homedir,
45-
'--armor', '--detach-sign', '--sign',
46-
'--default-key', self.__keyName,
47-
'--passphrase', self.__keyPwd,
48-
'--digest-algo', 'sha512',
49-
'-o', sig_path, path
50-
], check=True)
44+
command = ['gpg', '--batch', '--quiet', '--pinentry-mode=loopback']
45+
if self.__homedir is not None:
46+
command += ['--homedir', self.__homedir]
47+
command += [
48+
'--armor', '--detach-sign', '--sign',
49+
'--default-key', self.__key_name,
50+
'--passphrase', self.__key_pwd,
51+
'--digest-algo', 'sha512',
52+
'-o', sig_path, path
53+
]
54+
subprocess.run(command, check=True)
5155

5256
def binary_sign_external(self, path: Path, sig_path: Path):
5357
"""Signs a given file producing binary signature in a separate file
@@ -56,14 +60,17 @@ def binary_sign_external(self, path: Path, sig_path: Path):
5660
path: file to sign
5761
sig_path: path to write the signature to
5862
"""
59-
subprocess.run(['gpg', '--batch', '--quiet', '--pinentry-mode=loopback',
60-
'--homedir', self.__homedir,
61-
'--detach-sign', '--sign',
62-
'--default-key', self.__keyName,
63-
'--passphrase', self.__keyPwd,
64-
'--digest-algo', 'sha512',
65-
'-o', sig_path, path
66-
], check=True)
63+
command = ['gpg', '--batch', '--quiet', '--pinentry-mode=loopback']
64+
if self.__homedir is not None:
65+
command += ['--homedir', self.__homedir]
66+
command += [
67+
'--detach-sign', '--sign',
68+
'--default-key', self.__key_name,
69+
'--passphrase', self.__key_pwd,
70+
'--digest-algo', 'sha512',
71+
'-o', sig_path, path
72+
]
73+
subprocess.run(command, check=True)
6774

6875
def sign_inline(self, path: Path, out_path: Path):
6976
"""Adds a signature to a given text file
@@ -72,23 +79,29 @@ def sign_inline(self, path: Path, out_path: Path):
7279
path: file to sign
7380
out_path: path to write the signed content to
7481
"""
75-
subprocess.run(['gpg', '--batch', '--quiet', '--pinentry-mode=loopback',
76-
'--homedir', self.__homedir,
77-
'--armor', '--detach-sign', '--sign', '--clearsign',
78-
'--default-key', self.__keyName,
79-
'--passphrase', self.__keyPwd,
80-
'--digest-algo', 'sha512',
81-
'-o', out_path, path
82-
], check=True)
82+
command = ['gpg', '--batch', '--quiet', '--pinentry-mode=loopback']
83+
if self.__homedir is not None:
84+
command += ['--homedir', self.__homedir]
85+
command += [
86+
'--armor', '--detach-sign', '--sign', '--clearsign',
87+
'--default-key', self.__key_name,
88+
'--passphrase', self.__key_pwd,
89+
'--digest-algo', 'sha512',
90+
'-o', out_path, path
91+
]
92+
subprocess.run(command, check=True)
8393

8494
def export_public_key(self, path: Path):
8595
"""Utility method to export the public key of the signing key into a file
8696
Args:
8797
path: path of the file to write the public key to
8898
"""
89-
subprocess.run(['gpg', '--batch', '--quiet',
90-
'--homedir', self.__homedir,
91-
'--output', path,
92-
'--armor', '--export', self.__keyName
93-
], check=True)
99+
command = ['gpg', '--batch', '--quiet']
100+
if self.__homedir is not None:
101+
command += ['--homedir', self.__homedir]
102+
command += [
103+
'--output', path,
104+
'--armor', '--export', self.__key_name
105+
]
106+
subprocess.run(command, check=True)
94107

tests/conftest.py

+3-6
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,11 @@ def should_populate(request) -> bool:
8484
should_populate: bool = request.config.option.populate_expected
8585
return should_populate
8686

87-
def find_gpg_home():
88-
return subprocess.run(['gpgconf', '--list-dirs', 'homedir'], check=True, capture_output=True).stdout.decode().strip()
89-
9087
@pytest.fixture
9188
def pgp_signer():
92-
return PgpSigner(Path(os.environ.get('GNUPGHOME', find_gpg_home())),
93-
os.environ['PGP_KEY_NAME'],
94-
os.environ['PGP_KEY_PASSWD'])
89+
return PgpSigner(key_name=os.environ['PGP_KEY_NAME'],
90+
key_pwd = os.environ['PGP_KEY_PASSWD'],
91+
homedir=os.environ.get('GNUPGHOME'))
9592

9693
@pytest.fixture
9794
def pki_signer():

0 commit comments

Comments
 (0)