Added gpg verification for repos

This commit is contained in:
Kevin Veen-Birkenbach
2025-03-12 10:47:29 +01:00
parent 156506c3de
commit bb98e52a17
7 changed files with 266 additions and 95 deletions

View File

@@ -10,40 +10,54 @@ repositories:
repository: analysis-ready-code
description: Analysis-Ready Code (ARC) is a Python utility that recursively scans directories and transforms source code into a streamlined, analysis-ready format by removing comments, filtering files, and compressing content—perfect for AI and automated code analysis.
homepage: https://github.com/kevinveenbirkenbach/analysis-ready-code
verified: bef5f392d7e8a292fb9e4ee40809e434dd6142a9
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
description: A configurable Python package manager that automates repository tasks—including cloning, installation, updates, and status reporting—based on a YAML configuration file for streamlined software management which gives you access to the Kevin Veen-Birkenbach Code Universe.
homepage: https://github.com/kevinveenbirkenbach/package-manager
provider: github.com
repository: package-manager
alias: 'pkgmgr'
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
description: Money Monitor is a comprehensive financial document organizer that scans bank statements and invoices to extract, filter, and export transaction data in multiple formats. Installable via Kevin's Package Manager as "momo", it simplifies financial logging and tax preparation.
homepage: https://github.com/kevinveenbirkenbach/money-monitor
provider: github.com
repository: money-monitor
alias: 'momo'
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
alias: os
provider: github.com
repository: omni-search
description: OmniSearch (OS) is a versatile file content search tool that scans directories for strings across multiple formats (PDFs, text, images, spreadsheets, etc.), offering robust filtering, error handling, and JSON output. Easily installable via Kevin's Package Manager under the alias os 🔍🚀.
homepage: https://github.com/kevinveenbirkenbach/omni-search
verified: 93875b27280191c317806056847809464d9f5282
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
alias: bsr
provider: github.com
repository: bulk-string-replacer
description: Bulk String Replacer CLI (bsr) is a command-line tool for efficiently searching and replacing strings in file names, folder names, and file contents across directories. It's perfect for bulk updates and streamlining your workflow.
homepage: https://github.com/kevinveenbirkenbach/bulk-string-replacer
verified: daf45389383ef6b3d6569d63eb3e052ab811916d
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
alias: imgrszr
provider: github.com
repository: image-resizer-cli
description: Image Resizer CLI (imgrszr) is a lightweight command-line tool that resizes images by percentage, maximum dimensions, or target file size. Easily installable via Kevin's Package Manager. Its perfect for preparing large photos for upload and streamlining your image workflow. 🚀
homepage: https://github.com/kevinveenbirkenbach/image-resizer-cli
verified: e8b48c08679a1fc73339514db55f42a6ba55b44e
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
provider: github.com
alias: chroso
@@ -51,131 +65,169 @@ repositories:
description: ChronoSorter (chroso) is a CLI tool that updates media file metadata and renames images based on their earliest timestamps. Easily installed via Kevin's Package Manager under the alias chroso, it helps organize your photos chronologically.
homepage: https://github.com/kevinveenbirkenbach/chrono-sorter
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
provider: github.com
repository: media-sorter
alias: medso
description: MediaSorter (medso) is a command-line tool that automatically sorts media files by moving them between your Pictures and Videos directories based on file extensions, with support for preview and verbose modes.
homepage: https://github.com/kevinveenbirkenbach/media-sorter
verified: 502fba5198474caaf805fb6bc3a7bbe63e699d69
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
alias: ansenc
provider: github.com
repository: ansible-encryptor
description: Ansible Encrypter is a versatile Python script for secure file management using Ansible Vault. It allows encryption and decryption of files within a directory, supports temporary file access, and automatically updates .gitignore to secure sensitive data. Ideal for enhancing data security in Ansible-managed environments
homepage: https://github.com/kevinveenbirkenbach/ansible-encryptor/
verified: 2803ea3102cf3bc3d9caf670493b4270cf2d3293
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
alias: lim
provider: github.com
repository: linux-image-manager
description: Linux Image Manager is a powerful suite of shell scripts for downloading, configuring, and managing Linux images—including encrypted storage, RAID1 setups, chroot environments, and backups.
homepage: https://github.com/kevinveenbirkenbach/linux-image-manager
verified: 7f82c6fcb9e5e6e8a03713e6e21184761ca0c719
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
alias: dufiha
provider: github.com
repository: duplicate-file-handler
description: Duplicate File Handler is a CLI tool that detects duplicate files and lets you manage them by deleting or replacing with hard/symbolic links. Easily installable via Kevin's Package Manager under the alias dufiha, it supports file-type filtering and offers interactive, preview, or active modes.
homepage: https://github.com/kevinveenbirkenbach/duplicate-file-handler
verified: 89e15dd023aee82190bacaadc337c282b91f5357
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
provider: github.com
alias: swafo
repository: swap-forge
description: SwapForge (swafo) is a Bash script that automates the creation and management of Linux swapfiles. It easily creates a swapfile of a specified size, sets proper permissions, and updates /etc/fstab to ensure the swap is activated at boot, streamlining swap management for your Linux system.
homepage: https://github.com/kevinveenbirkenbach/swap-forge
verified: 0af1e6ea425ecc46f4055a10cfa00dad7b1cc511
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
alias: sisec
provider: github.com
repository: splitted-secret
description: Split Secret (sisec) is a command-line tool that securely splits a master secret among multiple users using secret sharing. Only a predefined quorum of users can combine their shares to decrypt the original secret. The tool supports robust encryption, decryption, and cleanup operations.
homepage: https://github.com/kevinveenbirkenbach/splitted-secret
verified: 5e4fe2c01a8b024e5f455e555adfc99e9f131311
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
alias: dirval
provider: github.com
repository: directory-validator
description: Directory Validator (dirval) is a Python CLI tool that creates a unique hash stamp for a directory and validates its contents, ensuring you can quickly detect any changes.
homepage: https://github.com/kevinveenbirkenbach/directory-validator
verified: 7db99608dd1ce4cf442cc4e3d37d2b61e6a6ec00
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
alias: lukyma
provider: github.com
repository: luks-key-manager
description: LUKS Key Manager(lukyma) is a Python-based utility that simplifies the management of LUKS encryption keys on Linux systems. It enables you to add new keys with a configurable memory cost and securely remove old ones, making it ideal for resource-constrained devices like the Raspberry Pi.
homepage: https://github.com/kevinveenbirkenbach/luks-key-manager
verified: 18ef26f9878ff9c605b9f6af0a5bd96c8da4fc9d
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
alias: 4dvt
provider: github.com
repository: 4d-video-titel
homepage: https://github.com/kevinveenbirkenbach/4d-video-titel
description: 4D Video Titel is a CLI tool that extracts metadata from video files and automatically generates descriptive titles including local date, time, timezone, and GPS coordinates perfect for organizing and enriching your video content!
verified: eb31cde28a940f01a3068142f93dfb2954c9adef
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
alias: btrfsauba
description: The btrfs-balance-automator automates Btrfs filesystem balancing with dynamic decrementing usage thresholds. It provides real-time status updates, enhancing system performance and storage optimization. This Python script is essential for system admins aiming to streamline Btrfs maintenance.
provider: github.com
repository: btrfs-auto-balancer
verified: 24acdf9643f946ea3513890b0ddc547c2426c0c4
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
alias: baudolo
homepage: https://github.com/kevinveenbirkenbach/backup-docker-to-local
description: Backup Docker Volumes to Local is a comprehensive solution that leverages rsync to create incremental backups of Docker volumes, providing seamless recovery for both file and database data. Ideal for ensuring the integrity and security of your container data.
provider: github.com
repository: backup-docker-to-local
verified: a355f34e6ebce608ce1bad5464d7c52cf8b80f8b
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
alias: clndoba
homepage: https://github.com/kevinveenbirkenbach/cleanup-failed-docker-backups
description: Backup Docker Volumes to Local is a comprehensive solution that leverages rsync to create incremental backups of Docker volumes, providing seamless recovery for both file and database data. Ideal for ensuring the integrity and security of your container data.
provider: github.com
repository: cleanup-failed-docker-backups
verified: 13b1b7d49394f9d82f8e53e3559ddbe1155e9dbb
verified:
gpg_keys:
- 44D8F11FD62F878E
- alias: cedama
account: kevinveenbirkenbach
homepage: https://github.com/kevinveenbirkenbach/central-database-manager
description: Scripts to manage the Central Databases Postgres in CyMaIS
provider: github.com
repository: central-database-manager
verified: f350c135e63946f9840c1d205deb8f62fbb6fcf1
verified:
gpg_keys:
- 44D8F11FD62F878E
- alias: dovore
account: kevinveenbirkenbach
homepage: https://github.com/kevinveenbirkenbach/docker-volume-renamer
description: A Bash script to create a new Docker volume, copy data from an existing volume to it, and remove the old volume.
provider: github.com
repository: docker-volume-renamer
verified: e702deb3347bc868134ce89273cd81b70af51899
verified:
gpg_keys:
- 44D8F11FD62F878E
- alias: gigimi
account: kevinveenbirkenbach
homepage: https://github.com/kevinveenbirkenbach/github-to-gitea-mirror/
description: A tool designed to automate the process of mirroring repositories from GitHub to Gitea. By leveraging the APIs of both platforms, this script identifies repositories on GitHub that aren't mirrored on Gitea and seamlessly mirrors them. Ideal for developers aiming to maintain a backup or a consistent repo state across both platforms.
provider: github.com
repository: github-to-gitea-mirror
verified: a6037b955425c256c535ac55047867af5d991e37
verified:
gpg_keys:
- 44D8F11FD62F878E
- alias: seedssh
account: kevinveenbirkenbach
homepage: https://github.com/kevinveenbirkenbach/seed-ssh-key
description: A tool designed to automate the process of mirroring repositories from GitHub to Gitea. By leveraging the APIs of both platforms, this script identifies repositories on GitHub that aren't mirrored on Gitea and seamlessly mirrors them. Ideal for developers aiming to maintain a backup or a consistent repo state across both platforms.
provider: github.com
repository: seed-ssh-key
verified: 0e605e23220a29d54e0867a37c57ca42bf63aec9
verified:
gpg_keys:
- 44D8F11FD62F878E
- alias: anscrico
account: kevinveenbirkenbach
homepage: https://github.com/kevinveenbirkenbach/analyze-script-collection
description: A versatile set of Bash scripts for Linux system diagnostics. Easily check SSH key encryption, find duplicate files, inspect your kernel version, locate large files, and list installed Java versions—all designed to simplify system management and troubleshooting.
provider: github.com
repository: analyze-script-collection
verified: ab8c92ef1d65fb5082930f80cf1736141d94a149
verified:
gpg_keys:
- 44D8F11FD62F878E
- alias: heicma
account: kevinveenbirkenbach
homepage: https://github.com/kevinveenbirkenbach/heic-management
description: "Bash scripts for handling HEIC images: converting to JPEG, deleting, and listing in a directory and subdirectories."
provider: github.com
repository: heic-management
verified: 3dd336b67f0f9d1f7ee4cd66724ca6c9bd091409
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
account: kevinveenbirkenbach
alias: portfolio
@@ -183,33 +235,43 @@ repositories:
description: Portfolio CMS is a Flask-based content management system that lets you effortlessly showcase your projects and online presence. With customizable cards, dynamic navigation, and YAML-driven configuration, it's a flexible solution for building modern, responsive portfolio websites.
repository: portfolio
homepage: https://github.com/kevinveenbirkenbach/portfolio
verified: fe1c038d1aea062ce7ad1d7ff186463994fd7f85
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
alias: goexma
provider: github.com
homepage: https://github.com/kevinveenbirkenbach/cli-gnome-extension-manager
description: CLI GNOME Extension Manager (goexma) is a Bash script that lets you install, update, enable, and disable GNOME extensions directly from the command line—perfect for automation and power users.
repository: cli-gnome-extension-manager
verified: 834e6e95636a4875ca9d9c73c0521508e2192aed
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
alias: cymais
provider: github.com
description: CyMaIS streamlines Linux-based system setups and Docker image administration, perfect for servers and PCs. It offers extensive solutions for system initialization, admin tools, backups, monitoring, updates, driver management, security, and VPNs.
homepage: https://github.com/kevinveenbirkenbach/cymais
repository: cymais
verified: 2898cc60868403220dcb69e0588d2d9aeb55bb27
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
provider: github.com
repository: dynamic-miner
homepage: https://github.com/kevinveenbirkenbach/dynamic-miner
desciption: Automated Ethereum mining setup using Docker and a GPU/CPU monitoring script. Includes a Docker Compose file for an Ethereum miner container and a Bash script to start/stop mining based on system usage thresholds, ensuring efficient resource utilization. Perfect for idle-time mining.
verified: 27d85cf220f6c603487b61cb4518c5a5ad00b35d
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
provider: github.com
description: This repository provides automated bridges for transferring content from federated platforms (like Pixelfed, Mastodon, and PeerTube) to centralized social networks (such as Instagram, X (Twitter), Facebook, and YouTube). It enables seamless cross-posting to maximize content reach across decentralized and mainstream platforms.
repository: fediverse-to-oligopolies-bridge
homepage: https://github.com/kevinveenbirkenbach/fediverse-to-oligopolies-bridge
verified: 1f6ace3fe84cb537436839a8a8164f1dc7b6e0c3
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
alias: bure
provider: github.com
@@ -218,7 +280,9 @@ repositories:
Bulk Rename is a Python-based CLI tool that renames files in bulk by replacing specified substrings in file names.
It supports both recursive and non-recursive renaming with verbose output.
homepage: https://github.com/kevinveenbirkenbach/bulk-rename
verified: f76b29720edf2df5760070e34eacae23beb9d3a7
verified:
gpg_keys:
- 44D8F11FD62F878E
- account: kevinveenbirkenbach
alias: gitconfig
provider: github.com
@@ -228,4 +292,6 @@ repositories:
It offers both interactive prompts and command-line options to set merge strategies, user details,
and commit signing preferences.
homepage: https://github.com/kevinveenbirkenbach/git-configurator
verified: 8441c2c34a6916a0610bf52155f8e63c0dbe203b
verified:
gpg_keys:
- 44D8F11FD62F878E

12
main.py
View File

@@ -42,6 +42,7 @@ GIT_DEFAULT_COMMANDS = [
"clone",
"reset",
"revert",
"rebase",
"commit"
]
@@ -98,7 +99,7 @@ For detailed help on each command, use:
install_parser = subparsers.add_parser("install", help="Setup repository/repositories alias links to executables")
add_identifier_arguments(install_parser)
install_parser.add_argument("-q", "--quiet", action="store_true", help="Suppress warnings and info messages")
install_parser.add_argument("--no-verification", default=False, action="store_true", help="Disable verification of repository commit")
install_parser.add_argument("--no-verification", action="store_true", default=False, help="Disable verification via commit/gpg")
deinstall_parser = subparsers.add_parser("deinstall", help="Remove alias links to repository/repositories")
add_identifier_arguments(deinstall_parser)
@@ -110,7 +111,7 @@ For detailed help on each command, use:
add_identifier_arguments(update_parser)
update_parser.add_argument("--system", action="store_true", help="Include system update commands")
update_parser.add_argument("-q", "--quiet", action="store_true", help="Suppress warnings and info messages")
update_parser.add_argument("--no-verification", action="store_true", default=False, help="Disable verification of repository commit")
update_parser.add_argument("--no-verification", action="store_true", default=False, help="Disable verification via commit/gpg")
status_parser = subparsers.add_parser("status", help="Show status for repository/repositories or system")
add_identifier_arguments(status_parser)
@@ -158,8 +159,9 @@ For detailed help on each command, use:
formatter_class=argparse.RawTextHelpFormatter
)
add_identifier_arguments(git_command_parsers[git_command])
if git_command == "pull":
git_command_parsers[git_command].add_argument("--no-verification", action="store_true", default=False, help="Disable verification of repository commit")
if git_command in ["pull","clone"]:
git_command_parsers[git_command].add_argument("--no-verification", action="store_true", default=False, help="Disable verification via commit/gpg")
args = parser.parse_args()
@@ -171,7 +173,7 @@ For detailed help on each command, use:
install_repos(selected,repositories_base_dir, BIN_DIR, all_repos_list, args.no_verification, preview=args.preview, quiet=args.quiet)
elif args.command in GIT_DEFAULT_COMMANDS:
if args.command == "clone":
clone_repos(selected, repositories_base_dir, all_repos_list, args.preview)
clone_repos(selected, repositories_base_dir, all_repos_list, args.preview, no_verification=args.no_verification)
elif args.command == "pull":
from pkgmgr.pull_with_verification import pull_with_verification
pull_with_verification(selected, repositories_base_dir, all_repos_list, args.extra_args, no_verification=args.no_verification, preview=args.preview)

View File

@@ -2,8 +2,9 @@ import subprocess
import os
from pkgmgr.get_repo_dir import get_repo_dir
from pkgmgr.get_repo_identifier import get_repo_identifier
from pkgmgr.verify import verify_repository
def clone_repos(selected_repos, repositories_base_dir: str, all_repos, preview=False):
def clone_repos(selected_repos, repositories_base_dir: str, all_repos, preview:bool, no_verification:bool):
for repo in selected_repos:
repo_identifier = get_repo_identifier(repo, all_repos)
repo_dir = get_repo_dir(repositories_base_dir, repo)
@@ -21,12 +22,10 @@ def clone_repos(selected_repos, repositories_base_dir: str, all_repos, preview=F
if preview:
print(f"[Preview] Would run: git clone {clone_url} {repo_dir} in {parent_dir}")
# Simulate a successful clone in preview mode.
result = subprocess.CompletedProcess(args=[], returncode=0)
else:
result = subprocess.run(f"git clone {clone_url} {repo_dir}", cwd=parent_dir, shell=True)
# If SSH clone returns an error code, ask user whether to try HTTPS.
if result.returncode != 0:
print(f"[WARNING] SSH clone failed for '{repo_identifier}' with return code {result.returncode}.")
choice = input("Do you want to attempt HTTPS clone instead? (y/N): ").strip().lower()
@@ -36,7 +35,21 @@ def clone_repos(selected_repos, repositories_base_dir: str, all_repos, preview=F
print(f"[INFO] Attempting to clone '{repo_identifier}' using HTTPS from {clone_url} into '{repo_dir}'.")
if preview:
print(f"[Preview] Would run: git clone {clone_url} {repo_dir} in {parent_dir}")
result = subprocess.CompletedProcess(args=[], returncode=0)
else:
subprocess.run(f"git clone {clone_url} {repo_dir}", cwd=parent_dir, shell=True)
result = subprocess.run(f"git clone {clone_url} {repo_dir}", cwd=parent_dir, shell=True)
else:
print(f"[INFO] HTTPS clone not attempted for '{repo_identifier}'.")
continue
# After cloning, perform verification in local mode.
verified_info = repo.get("verified")
if verified_info:
verified_ok, errors, commit_hash, signing_key = verify_repository(repo, repo_dir, mode="local", no_verification=no_verification)
if not no_verification and not verified_ok:
print(f"Warning: Verification failed for {repo_identifier} after cloning:")
for err in errors:
print(f" - {err}")
choice = input("Proceed anyway? (y/N): ").strip().lower()
if choice != "y":
print(f"Skipping repository {repo_identifier} due to failed verification.")

View File

@@ -1,5 +1,7 @@
import shutil
import os
from pkgmgr.get_repo_identifier import get_repo_identifier
from pkgmgr.get_repo_dir import get_repo_dir
def delete_repos(selected_repos, repositories_base_dir, all_repos, preview=False):
for repo in selected_repos:

View File

@@ -5,16 +5,13 @@ from pkgmgr.get_repo_identifier import get_repo_identifier
from pkgmgr.get_repo_dir import get_repo_dir
from pkgmgr.create_ink import create_ink
from pkgmgr.run_command import run_command
from pkgmgr.verify import verify_repository
def install_repos(selected_repos, repositories_base_dir, bin_dir, all_repos, no_verification, preview=False, quiet=False):
"""
Install repositories by creating symbolic links (via create_ink) and running setup commands.
Install repositories by creating symbolic links and running setup commands.
This version applies hash verification:
- It retrieves the current commit hash using 'git rev-parse HEAD' and compares it to the
configured 'verified' hash.
- If the hashes do not match and no_verification is False, the user is prompted for confirmation.
- If the user does not confirm, the installation for that repository is skipped.
Verifies repository state using verify_repository in local mode.
"""
for repo in selected_repos:
repo_identifier = get_repo_identifier(repo, all_repos)
@@ -23,28 +20,19 @@ def install_repos(selected_repos, repositories_base_dir, bin_dir, all_repos, no_
print(f"Repository directory '{repo_dir}' does not exist. Clone it first.")
continue
# Apply hash verification if a verified hash is defined.
verified_hash = repo.get("verified")
if verified_hash:
current_hash = ""
try:
result = subprocess.run("git rev-parse HEAD", cwd=repo_dir, shell=True, check=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
current_hash = result.stdout.strip()
except Exception as e:
print(f"Error retrieving current commit for {repo_identifier}: {e}")
verified_info = repo.get("verified")
verified_ok, errors, commit_hash, signing_key = verify_repository(repo, repo_dir, mode="local", no_verification=no_verification)
proceed = True
if not no_verification and current_hash and current_hash != verified_hash:
print(f"Warning: For {repo_identifier}, the current commit hash ({current_hash}) does not match the verified hash ({verified_hash}).")
choice = input("Proceed with installation? (y/N): ").strip().lower()
if choice != "y":
proceed = False
if not proceed:
if not no_verification and verified_info and not verified_ok:
print(f"Warning: Verification failed for {repo_identifier}:")
for err in errors:
print(f" - {err}")
choice = input("Proceed with installation? (y/N): ").strip().lower()
if choice != "y":
print(f"Skipping installation for {repo_identifier}.")
continue
# Create the symlink using the new create_ink function.
# Create the symlink using the create_ink function.
create_ink(repo, repositories_base_dir, bin_dir, all_repos, quiet=quiet, preview=preview)
setup_cmd = repo.get("setup")

View File

@@ -3,15 +3,15 @@ import subprocess
import sys
from pkgmgr.get_repo_identifier import get_repo_identifier
from pkgmgr.get_repo_dir import get_repo_dir
from pkgmgr.verify import verify_repository
def pull_with_verification(selected_repos, repositories_base_dir, all_repos, extra_args, no_verification, preview=False):
"""
Executes "git pull" for each repository with hash verification.
Executes "git pull" for each repository with verification.
For repositories with a 'verified' hash in the configuration, this function first
retrieves the remote commit hash (using 'git ls-remote origin HEAD'). If the remote hash
does not match the verified hash, the user is prompted to confirm the pull (unless --no-verification
is set, in which case the pull proceeds automatically).
Uses the verify_repository function in "pull" mode.
If verification fails (and verification info is set) and --no-verification is not enabled,
the user is prompted to confirm the pull.
"""
for repo in selected_repos:
repo_identifier = get_repo_identifier(repo, all_repos)
@@ -20,30 +20,23 @@ def pull_with_verification(selected_repos, repositories_base_dir, all_repos, ext
print(f"Repository directory '{repo_dir}' not found for {repo_identifier}.")
continue
verified_hash = repo.get("verified")
remote_hash = ""
try:
result = subprocess.run("git ls-remote origin HEAD", cwd=repo_dir, shell=True, check=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
# The first token in the output is the remote HEAD commit hash.
remote_hash = result.stdout.split()[0].strip()
except Exception as e:
print(f"Error retrieving remote commit for {repo_identifier}: {e}")
verified_info = repo.get("verified")
verified_ok, errors, commit_hash, signing_key = verify_repository(repo, repo_dir, mode="pull", no_verification=no_verification)
proceed = True
if not no_verification and verified_hash and remote_hash and remote_hash != verified_hash:
print(f"Warning: For {repo_identifier}, the remote hash ({remote_hash}) does not match the verified hash ({verified_hash}).")
if not no_verification and verified_info and not verified_ok:
print(f"Warning: Verification failed for {repo_identifier}:")
for err in errors:
print(f" - {err}")
choice = input("Proceed with 'git pull'? (y/N): ").strip().lower()
if choice != "y":
proceed = False
continue
if proceed:
full_cmd = f"git pull {' '.join(extra_args)}"
if preview:
print(f"[Preview] In '{repo_dir}': {full_cmd}")
else:
print(f"Running in '{repo_dir}': {full_cmd}")
result = subprocess.run(full_cmd, cwd=repo_dir, shell=True)
if result.returncode != 0:
print(f"'git pull' for {repo_identifier} failed with exit code {result.returncode}.")
sys.exit(result.returncode)
full_cmd = f"git pull {' '.join(extra_args)}"
if preview:
print(f"[Preview] In '{repo_dir}': {full_cmd}")
else:
print(f"Running in '{repo_dir}': {full_cmd}")
result = subprocess.run(full_cmd, cwd=repo_dir, shell=True)
if result.returncode != 0:
print(f"'git pull' for {repo_identifier} failed with exit code {result.returncode}.")
sys.exit(result.returncode)

107
pkgmgr/verify.py Normal file
View File

@@ -0,0 +1,107 @@
import subprocess
def verify_repository(repo, repo_dir, mode="local", no_verification=False):
"""
Verifies the repository based on its 'verified' field.
The 'verified' field can be a dictionary with the following keys:
commit: The expected commit hash.
gpg_keys: A list of valid GPG key IDs (at least one must match the signing key).
If mode == "pull", the remote HEAD commit is checked via "git ls-remote origin HEAD".
Otherwise (mode "local", used for install and clone), the local HEAD commit is checked via "git rev-parse HEAD".
Returns a tuple:
(verified_ok, error_details, commit_hash, signing_key)
- verified_ok: True if the verification passed (or no verification info is set), False otherwise.
- error_details: A list of error messages for any failed checks.
- commit_hash: The obtained commit hash.
- signing_key: The GPG key ID that signed the latest commit (obtained via "git log -1 --format=%GK").
"""
verified_info = repo.get("verified")
if not verified_info:
# Nothing to verify.
commit_hash = ""
signing_key = ""
if mode == "pull":
try:
result = subprocess.run("git ls-remote origin HEAD", cwd=repo_dir, shell=True, check=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
commit_hash = result.stdout.split()[0].strip()
except Exception:
commit_hash = ""
else:
try:
result = subprocess.run("git rev-parse HEAD", cwd=repo_dir, shell=True, check=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
commit_hash = result.stdout.strip()
except Exception:
commit_hash = ""
try:
result = subprocess.run(["git", "log", "-1", "--format=%GK"], cwd=repo_dir, shell=False, check=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
signing_key = result.stdout.strip()
except Exception:
signing_key = ""
return True, [], commit_hash, signing_key
expected_commit = None
expected_gpg_keys = None
if isinstance(verified_info, dict):
expected_commit = verified_info.get("commit")
expected_gpg_keys = verified_info.get("gpg_keys")
else:
# If verified is a plain string, treat it as the expected commit.
expected_commit = verified_info
error_details = []
# Get commit hash according to the mode.
commit_hash = ""
if mode == "pull":
try:
result = subprocess.run("git ls-remote origin HEAD", cwd=repo_dir, shell=True, check=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
commit_hash = result.stdout.split()[0].strip()
except Exception as e:
error_details.append(f"Error retrieving remote commit: {e}")
else:
try:
result = subprocess.run("git rev-parse HEAD", cwd=repo_dir, shell=True, check=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
commit_hash = result.stdout.strip()
except Exception as e:
error_details.append(f"Error retrieving local commit: {e}")
# Get the signing key using "git log -1 --format=%GK"
signing_key = ""
try:
result = subprocess.run(["git", "log", "-1", "--format=%GK"], cwd=repo_dir, shell=False, check=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
signing_key = result.stdout.strip()
except Exception as e:
error_details.append(f"Error retrieving signing key: {e}")
commit_check_passed = True
gpg_check_passed = True
if expected_commit:
if commit_hash != expected_commit:
commit_check_passed = False
error_details.append(f"Expected commit: {expected_commit}, found: {commit_hash}")
if expected_gpg_keys:
if signing_key not in expected_gpg_keys:
gpg_check_passed = False
error_details.append(f"Expected one of GPG keys: {expected_gpg_keys}, found: {signing_key}")
if expected_commit and expected_gpg_keys:
verified_ok = commit_check_passed and gpg_check_passed
elif expected_commit:
verified_ok = commit_check_passed
elif expected_gpg_keys:
verified_ok = gpg_check_passed
else:
verified_ok = True
return verified_ok, error_details, commit_hash, signing_key