Initial release
This commit is contained in:
commit
87338a564a
5 changed files with 243 additions and 0 deletions
37
.pre-commit-config.yaml
Normal file
37
.pre-commit-config.yaml
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
# Pre-commit hooks to run tests and ensure code is cleaned.
|
||||||
|
# See https://pre-commit.com for more information
|
||||||
|
repos:
|
||||||
|
- repo: https://github.com/asottile/pyupgrade
|
||||||
|
rev: v3.3.1
|
||||||
|
hooks:
|
||||||
|
- id: pyupgrade
|
||||||
|
args: ['--keep-percent-format', '--py37-plus']
|
||||||
|
- repo: https://github.com/psf/black
|
||||||
|
rev: 22.12.0
|
||||||
|
hooks:
|
||||||
|
- id: black
|
||||||
|
args: ['--target-version', 'py37', '--line-length', '100']
|
||||||
|
- repo: https://github.com/PyCQA/isort
|
||||||
|
rev: 5.11.5
|
||||||
|
hooks:
|
||||||
|
- id: isort
|
||||||
|
args: ['--profile', 'black', '--line-length', '100']
|
||||||
|
- repo: https://github.com/PyCQA/flake8
|
||||||
|
rev: 6.0.0
|
||||||
|
hooks:
|
||||||
|
- id: flake8
|
||||||
|
args: ['--max-line-length=100']
|
||||||
|
- repo: local
|
||||||
|
hooks:
|
||||||
|
- id: pylint
|
||||||
|
name: pylint
|
||||||
|
entry: pylint --extension-pkg-whitelist=cx_Oracle
|
||||||
|
language: system
|
||||||
|
types: [python]
|
||||||
|
require_serial: true
|
||||||
|
- repo: https://github.com/Lucas-C/pre-commit-hooks-bandit
|
||||||
|
rev: v1.0.5
|
||||||
|
hooks:
|
||||||
|
- id: python-bandit-vulnerability-check
|
||||||
|
name: bandit
|
||||||
|
args: [--skip, "B101", --recursive, mylib]
|
7
.pylintrc
Normal file
7
.pylintrc
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
[MESSAGES CONTROL]
|
||||||
|
disable=invalid-name,
|
||||||
|
locally-disabled,
|
||||||
|
|
||||||
|
[FORMAT]
|
||||||
|
# Maximum number of characters on a single line.
|
||||||
|
max-line-length=100
|
57
README.md
Normal file
57
README.md
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
# Migrate APT trusted keys
|
||||||
|
|
||||||
|
Script to handle migration of obsolete /etc/apt/trusted.gpg to split GPG
|
||||||
|
keyrings in /etc/apt/trusted.gpg.d.
|
||||||
|
|
||||||
|
Note: Useful to fix this type of APT error:
|
||||||
|
|
||||||
|
```
|
||||||
|
Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
apt install python3 wget
|
||||||
|
wget -O /usr/local/sbin/migrate-apt-trusted-keys \
|
||||||
|
https://gitea.zionetrix.net/bn8/migrate-apt-trusted-keys/raw/branch/main/migrate-apt-trusted-keys
|
||||||
|
chmod 750 /usr/local/sbin/migrate-apt-trusted-keys
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
usage: migrate-apt-trusted-keys [-h] [-p KEYRING_PATH] [-o OUTPUT_PATH] [-a]
|
||||||
|
[-f]
|
||||||
|
|
||||||
|
Script to manage the migration from the deprecated /etc/apt/trusted.gpg file
|
||||||
|
to splited GPG keyring in /etc/apt/trusted.gpg.d.
|
||||||
|
|
||||||
|
options:
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
-p KEYRING_PATH, --keyring-path KEYRING_PATH
|
||||||
|
APT keyring file path.
|
||||||
|
-o OUTPUT_PATH, --output-path OUTPUT_PATH
|
||||||
|
Output directory path.
|
||||||
|
-a, --auto Migrate all GPG keys, without user interaction.
|
||||||
|
-f, --force Force mode: overwrite output file if already exists.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Copyright
|
||||||
|
|
||||||
|
Copyright (c) 2023 Benjamin Renard <brenard@zionetrix.net>
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU General Public License version 3
|
||||||
|
as published by the Free Software Foundation.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
139
migrate-apt-trusted-keys
Executable file
139
migrate-apt-trusted-keys
Executable file
|
@ -0,0 +1,139 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
#
|
||||||
|
# Script to handle migration of obsolete /etc/apt/trusted.gpg to split GPG
|
||||||
|
# keyrings in /etc/apt/trusted.gpg.d.
|
||||||
|
#
|
||||||
|
# Author : Benjamin Renard <brenard@zionetrix.net>
|
||||||
|
# Date : Fri, 07 Jul 2023 12:26:54 +0200
|
||||||
|
# Source : http://gitea.zionetrix.net/bn8/migrate-apt-trusted-keys
|
||||||
|
# Licence : GPL v3
|
||||||
|
#
|
||||||
|
|
||||||
|
"""
|
||||||
|
Script to handle migration of obsolete /etc/apt/trusted.gpg to split GPG
|
||||||
|
keyrings in /etc/apt/trusted.gpg.d.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
# Variables
|
||||||
|
raw_output = ""
|
||||||
|
|
||||||
|
# Args Parsing
|
||||||
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
|
|
||||||
|
parser.add_argument(
|
||||||
|
"-p", "--keyring-path", help="APT keyring file path.", type=str, default="/etc/apt/trusted.gpg"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-o", "--output-path", help="Output directory path.", type=str, default="/etc/apt/trusted.gpg.d"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-a", "--auto", help="Migrate all GPG keys, without user interaction.", action="store_true"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-f",
|
||||||
|
"--force",
|
||||||
|
help="Force mode: overwrite output file if already exists.",
|
||||||
|
action="store_true",
|
||||||
|
)
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
if not os.path.exists(args.keyring_path):
|
||||||
|
parser.error(f"APT keyring file {args.keyring_path} not found.")
|
||||||
|
|
||||||
|
if not os.path.isdir(args.output_path):
|
||||||
|
parser.error(f"Output directory {args.output_path} not found (or is not a directory).")
|
||||||
|
|
||||||
|
# Execute Command
|
||||||
|
process = subprocess.run(
|
||||||
|
args=["gpg", "--keyring", args.keyring_path, "--list-keys"], capture_output=True, check=True
|
||||||
|
)
|
||||||
|
if process.returncode > 0:
|
||||||
|
print("No fingerprints found!")
|
||||||
|
sys.exit()
|
||||||
|
raw_output = str(process.stdout.decode("utf-8"))
|
||||||
|
|
||||||
|
all_keys = []
|
||||||
|
current_key = None
|
||||||
|
key_id_line = re.compile("^ +([0-9A-F]+)$")
|
||||||
|
uid_line = re.compile("^uid +.*<[^@]+@([^>]+)>$")
|
||||||
|
for line in raw_output.split("\n")[2:]:
|
||||||
|
if not line:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if line.startswith("pub") and current_key:
|
||||||
|
all_keys.append(current_key)
|
||||||
|
current_key = None
|
||||||
|
|
||||||
|
if current_key is None:
|
||||||
|
current_key = {"lines": [], "id": None, "domain": None}
|
||||||
|
|
||||||
|
current_key["lines"].append(line)
|
||||||
|
m = key_id_line.match(line)
|
||||||
|
if m:
|
||||||
|
current_key["id"] = m.group(1)
|
||||||
|
m = uid_line.match(line)
|
||||||
|
if m:
|
||||||
|
current_key["domain"] = m.group(1)
|
||||||
|
|
||||||
|
|
||||||
|
if current_key:
|
||||||
|
all_keys.append(current_key)
|
||||||
|
|
||||||
|
for key in all_keys:
|
||||||
|
if not args.auto:
|
||||||
|
print("\n\n")
|
||||||
|
print("\n".join(key["lines"]))
|
||||||
|
answer = input("Do you want to migrate this key [Y/n or q to exit]? ")
|
||||||
|
answer = answer.strip().lower()
|
||||||
|
if answer == 'q':
|
||||||
|
sys.exit()
|
||||||
|
if answer and answer != "y":
|
||||||
|
continue
|
||||||
|
|
||||||
|
print(f"Migrate key {key['id']}...")
|
||||||
|
name = "-".join(key["domain"].lower().split(".")[:-1]) if key["domain"] else key["id"]
|
||||||
|
name += ".gpg"
|
||||||
|
if not args.auto:
|
||||||
|
answer = input(f"Key name [{name}]? ")
|
||||||
|
name = answer.strip() if answer else name
|
||||||
|
|
||||||
|
output_path = os.path.join(args.output_path, name)
|
||||||
|
print(f"Export key {key['id']} to {output_path}...")
|
||||||
|
try:
|
||||||
|
if os.path.exists(output_path):
|
||||||
|
if not args.force:
|
||||||
|
if args.auto:
|
||||||
|
print(f"Outfile '{output_path}' already exists, pass")
|
||||||
|
continue
|
||||||
|
answer = input(f"Outfile '{output_path}' already exists, overwrite [y/N or q to exit]? ")
|
||||||
|
answer = answer.strip().lower()
|
||||||
|
if answer == 'q':
|
||||||
|
sys.exit()
|
||||||
|
if answer != "y":
|
||||||
|
continue
|
||||||
|
print(f"Remove existing output file '{output_path}'")
|
||||||
|
os.remove(output_path)
|
||||||
|
|
||||||
|
# pylint: disable=consider-using-with
|
||||||
|
export_cmd = subprocess.Popen(
|
||||||
|
("gpg", "--keyring", args.keyring_path, "--export", key["id"]), stdout=subprocess.PIPE
|
||||||
|
)
|
||||||
|
output_cmd = subprocess.check_output(
|
||||||
|
("gpg", "--dearmour", "-o", output_path), stdin=export_cmd.stdout
|
||||||
|
)
|
||||||
|
export_cmd.wait()
|
||||||
|
print(f"Key {key['id']} exported to {output_path}")
|
||||||
|
print()
|
||||||
|
except Exception: # pylint: disable=broad-exception-caught
|
||||||
|
print(f"Fail to export key {key['id']} to {output_path}")
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
# vim: tabstop=4 shiftwidth=4 softtabstop=4 expandtab
|
3
setup.cfg
Normal file
3
setup.cfg
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
[flake8]
|
||||||
|
ignore = E501,W503
|
||||||
|
max-line-length = 100
|
Loading…
Reference in a new issue