205 lines
6.7 KiB
Python
205 lines
6.7 KiB
Python
"""Utilities for searching and importing GPG keys locally."""
|
|
|
|
from subprocess import run, STDOUT, PIPE
|
|
from re import compile
|
|
|
|
|
|
_DEBIAN_KEY_SERVER_HOSTNAME = "keyring.debian.org"
|
|
_DEBIAN_CD_SIGNING_KEY_ID = "DA87E80D6294BE9B"
|
|
_DEBIAN_CD_TESTING_SIGNING_KEY_ID = "42468F4009EA8AC3"
|
|
|
|
|
|
def import_debian_signing_key():
|
|
"""Imports the public debian CD signing key using gpg.
|
|
|
|
The key is imported from keyring.debian.org into the invoking user's
|
|
GPG public key store using a shell command.
|
|
"""
|
|
|
|
# execute a gpg key import as a shell command, redirecting stderr to stdout
|
|
process_result = run(
|
|
[
|
|
"gpg", "--keyserver", _DEBIAN_KEY_SERVER_HOSTNAME,
|
|
"--recv-key", _DEBIAN_CD_SIGNING_KEY_ID
|
|
],
|
|
stdout=PIPE,
|
|
stderr=STDOUT,
|
|
text=True,
|
|
)
|
|
|
|
# check shell return code
|
|
if process_result.returncode != 0:
|
|
if process_result.stdout:
|
|
raise RuntimeError(
|
|
f"Failed to import key using gpg:\n{process_result.stdout}"
|
|
)
|
|
else:
|
|
raise RuntimeError("Failed to import key using gpg.")
|
|
|
|
# check shell output:
|
|
# verify that the key was imported successfully by checking for key patterns
|
|
stdout_lower = process_result.stdout.lower()
|
|
key_id_in_output = _DEBIAN_CD_SIGNING_KEY_ID.lower() in stdout_lower
|
|
imported_or_unchanged = any(word in stdout_lower for word in ["imported", "unchanged", "importée", "importées"])
|
|
|
|
if not (key_id_in_output and imported_or_unchanged):
|
|
raise RuntimeError(
|
|
f"Unexpected output while importing PGP public key:\n"
|
|
f"{process_result.stdout}"
|
|
)
|
|
|
|
|
|
def import_debian_testing_signing_key():
|
|
"""Imports the public debian testing CD signing key using gpg.
|
|
|
|
The key is imported from keyring.debian.org into the invoking user's
|
|
GPG public key store using a shell command.
|
|
"""
|
|
|
|
# execute a gpg key import as a shell command, redirecting stderr to stdout
|
|
process_result = run(
|
|
[
|
|
"gpg", "--keyserver", _DEBIAN_KEY_SERVER_HOSTNAME,
|
|
"--recv-key", _DEBIAN_CD_TESTING_SIGNING_KEY_ID
|
|
],
|
|
stdout=PIPE,
|
|
stderr=STDOUT,
|
|
text=True,
|
|
)
|
|
|
|
# check shell return code
|
|
if process_result.returncode != 0:
|
|
if process_result.stdout:
|
|
raise RuntimeError(
|
|
f"Failed to import key using gpg:\n{process_result.stdout}"
|
|
)
|
|
else:
|
|
raise RuntimeError("Failed to import key using gpg.")
|
|
|
|
# check shell output:
|
|
# verify that the key was imported successfully by checking for key patterns
|
|
stdout_lower = process_result.stdout.lower()
|
|
key_id_in_output = _DEBIAN_CD_TESTING_SIGNING_KEY_ID.lower() in stdout_lower
|
|
imported_or_unchanged = any(word in stdout_lower for word in ["imported", "unchanged", "importée", "importées"])
|
|
|
|
if not (key_id_in_output and imported_or_unchanged):
|
|
raise RuntimeError(
|
|
f"Unexpected output while importing PGP public key:\n"
|
|
f"{process_result.stdout}"
|
|
)
|
|
|
|
|
|
def debian_signing_key_is_imported():
|
|
"""Checks whether the debian PGP signing key exists in the local key store.
|
|
|
|
The invoking user's GPG key store is checked using a shell command.
|
|
|
|
Returns
|
|
-------
|
|
True : bool
|
|
If the public PGP debian cd signing key exists in the invoking user's
|
|
GPG key store.
|
|
False : bool
|
|
If the public PGP debian cd signing key does not exist in the invoking
|
|
user's GPG key store.
|
|
"""
|
|
|
|
# execute a local gpg key lookup as a shell command, redirecting stderr to
|
|
# stdout
|
|
# NOTE: this command returns 0 even if the key is not present
|
|
process_result = run(
|
|
["gpg", "--locate-keys", _DEBIAN_CD_SIGNING_KEY_ID],
|
|
stdout=PIPE,
|
|
stderr=STDOUT,
|
|
text=True,
|
|
)
|
|
|
|
# check shell return code
|
|
if process_result.returncode != 0:
|
|
raise RuntimeError("Failed to search local keys using gpg.")
|
|
|
|
# no shell output means that the key does not exist locally
|
|
if not process_result.stdout:
|
|
return False
|
|
|
|
# verify existing key shell output using regex:
|
|
# it should contain six lines in the following format
|
|
expected_output_lines_regexes = [
|
|
compile(r"^pub .*$"),
|
|
compile(r"^ *[0-9A-F]{40}$"),
|
|
compile(r"^uid .*$"),
|
|
compile(r"^sub .*$"),
|
|
compile(r"^$"),
|
|
compile(r"^$"),
|
|
]
|
|
|
|
actual_output_lines = process_result.stdout.split("\n")
|
|
if not len(actual_output_lines) == len(expected_output_lines_regexes):
|
|
raise RuntimeError(
|
|
f"Unexpected line count in shell output while performing local"
|
|
f"GPG key lookup:\n"
|
|
f"{process_result.stdout}"
|
|
)
|
|
for i in range(4):
|
|
if not expected_output_lines_regexes[i].match(actual_output_lines[i]):
|
|
raise RuntimeError(
|
|
f"Unexpected shell output format while performing local"
|
|
f"GPG key lookup:\n"
|
|
f"{process_result.stdout}"
|
|
)
|
|
|
|
return True
|
|
|
|
|
|
def debian_testing_signing_key_is_imported():
|
|
"""Checks whether the debian testing PGP signing key exists in the local key store.
|
|
|
|
The invoking user's GPG key store is checked using a shell command.
|
|
|
|
Returns True if the key exists, False otherwise.
|
|
"""
|
|
|
|
# execute a gpg key lookup as a shell command, redirecting stderr to stdout
|
|
process_result = run(
|
|
["gpg", "--locate-keys", _DEBIAN_CD_TESTING_SIGNING_KEY_ID],
|
|
stdout=PIPE,
|
|
stderr=STDOUT,
|
|
text=True,
|
|
)
|
|
|
|
# check shell return code
|
|
if process_result.returncode != 0:
|
|
raise RuntimeError("Failed to search local keys using gpg.")
|
|
|
|
# no shell output means that the key does not exist locally
|
|
if not process_result.stdout:
|
|
return False
|
|
|
|
# verify existing key shell output using regex:
|
|
# it should contain six lines in the following format
|
|
expected_output_lines_regexes = [
|
|
compile(r"^pub .*$"),
|
|
compile(r"^ *[0-9A-F]{40}$"),
|
|
compile(r"^uid .*$"),
|
|
compile(r"^sub .*$"),
|
|
compile(r"^$"),
|
|
compile(r"^$"),
|
|
]
|
|
|
|
actual_output_lines = process_result.stdout.split("\n")
|
|
if len(actual_output_lines) < 4:
|
|
raise RuntimeError(
|
|
f"Unexpected shell output format while performing local "
|
|
f"GPG key lookup:\n"
|
|
f"{process_result.stdout}"
|
|
)
|
|
for i in range(4):
|
|
if not expected_output_lines_regexes[i].match(actual_output_lines[i]):
|
|
raise RuntimeError(
|
|
f"Unexpected shell output format while performing local"
|
|
f"GPG key lookup:\n"
|
|
f"{process_result.stdout}"
|
|
)
|
|
|
|
return True
|