particle-os-tools/src/apt-layer/scriptlets/08-advanced-package-management.sh

1070 lines
34 KiB
Bash
Raw Blame History

#!/bin/bash
# Ubuntu uBlue apt-layer Advanced Package Management
# Provides enterprise-grade package management with multi-user support, security features,
# and advanced dependency resolution for production deployments
# =============================================================================
# ADVANCED PACKAGE MANAGEMENT FUNCTIONS
# =============================================================================
# Advanced package management configuration (with fallbacks for when particle-config.sh is not loaded)
ADVANCED_PKG_CONFIG_DIR="${UBLUE_CONFIG_DIR:-/etc/ubuntu-ublue}/package-management"
ADVANCED_PKG_STATE_DIR="${UBLUE_ROOT:-/var/lib/particle-os}/package-management"
ADVANCED_PKG_CACHE_DIR="$ADVANCED_PKG_STATE_DIR/cache"
ADVANCED_PKG_DEPENDENCIES_DIR="$ADVANCED_PKG_STATE_DIR/dependencies"
ADVANCED_PKG_SECURITY_DIR="$ADVANCED_PKG_STATE_DIR/security"
ADVANCED_PKG_USERS_DIR="$ADVANCED_PKG_STATE_DIR/users"
ADVANCED_PKG_POLICIES_DIR="$ADVANCED_PKG_STATE_DIR/policies"
# Initialize advanced package management system
init_advanced_package_management() {
log_info "Initializing advanced package management system" "apt-layer"
# Create advanced package management directories
mkdir -p "$ADVANCED_PKG_CONFIG_DIR" "$ADVANCED_PKG_STATE_DIR" "$ADVANCED_PKG_CACHE_DIR"
mkdir -p "$ADVANCED_PKG_DEPENDENCIES_DIR" "$ADVANCED_PKG_SECURITY_DIR" "$ADVANCED_PKG_USERS_DIR"
mkdir -p "$ADVANCED_PKG_POLICIES_DIR"
# Set proper permissions
chmod 755 "$ADVANCED_PKG_CONFIG_DIR" "$ADVANCED_PKG_STATE_DIR"
chmod 700 "$ADVANCED_PKG_CACHE_DIR" "$ADVANCED_PKG_DEPENDENCIES_DIR" "$ADVANCED_PKG_SECURITY_DIR"
chmod 750 "$ADVANCED_PKG_USERS_DIR" "$ADVANCED_PKG_POLICIES_DIR"
# Initialize user management database
init_user_management_db
# Initialize security policies
init_security_policies
# Initialize dependency resolution cache
init_dependency_cache
log_success "Advanced package management system initialized" "apt-layer"
}
# Initialize user management database
init_user_management_db() {
local user_db="$ADVANCED_PKG_USERS_DIR/users.json"
if [[ ! -f "$user_db" ]]; then
cat > "$user_db" << EOF
{
"users": {},
"groups": {},
"permissions": {},
"roles": {
"admin": {
"description": "Full system administration",
"permissions": ["all"]
},
"package_manager": {
"description": "Package installation and management",
"permissions": ["install", "remove", "update", "list"]
},
"viewer": {
"description": "Read-only access to package information",
"permissions": ["list", "info", "status"]
}
}
}
EOF
chmod 600 "$user_db"
fi
}
# Initialize security policies
init_security_policies() {
local security_policy="$ADVANCED_PKG_SECURITY_DIR/security-policy.json"
if [[ ! -f "$security_policy" ]]; then
cat > "$security_policy" << EOF
{
"package_verification": {
"enabled": true,
"gpg_check": true,
"hash_verification": true,
"source_verification": true
},
"installation_policies": {
"allow_unsigned_packages": false,
"allow_external_sources": false,
"require_approval": false,
"max_package_size_mb": 1000
},
"security_scanning": {
"enabled": true,
"scan_installed_packages": true,
"scan_dependencies": true,
"vulnerability_check": true
},
"audit_logging": {
"enabled": true,
"log_level": "INFO",
"retention_days": 90
}
}
EOF
chmod 600 "$security_policy"
fi
}
# Initialize dependency cache
init_dependency_cache() {
local dep_cache="$ADVANCED_PKG_DEPENDENCIES_DIR/dependency-cache.json"
if [[ ! -f "$dep_cache" ]]; then
cat > "$dep_cache" << EOF
{
"package_dependencies": {},
"reverse_dependencies": {},
"conflict_resolution": {},
"last_updated": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
}
EOF
chmod 644 "$dep_cache"
fi
}
# Check user permissions
check_user_permissions() {
local user="$1"
local required_permission="$2"
log_debug "Checking permission '$required_permission' for user '$user'" "apt-layer"
# Root user has all permissions
if [[ "$user" == "root" ]] || [[ $EUID -eq 0 ]]; then
return 0
fi
local user_db="$ADVANCED_PKG_USERS_DIR/users.json"
if [[ ! -f "$user_db" ]]; then
log_error "User management database not found" "apt-layer"
return 1
fi
# Get user role
local user_role
user_role=$(jq -r ".users[\"$user\"].role // \"viewer\"" "$user_db" 2>/dev/null || echo "viewer")
# Get role permissions
local role_permissions
role_permissions=$(jq -r ".roles[\"$user_role\"].permissions[]?" "$user_db" 2>/dev/null || echo "")
# Check if user has required permission
if echo "$role_permissions" | grep -q "^$required_permission$" || echo "$role_permissions" | grep -q "^all$"; then
return 0
fi
log_error "User '$user' does not have permission '$required_permission'" "apt-layer"
return 1
}
# Add user to package management system
add_package_user() {
local username="$1"
local role="${2:-viewer}"
if [[ -z "$username" ]]; then
log_error "Username required" "apt-layer"
return 1
fi
log_info "Adding user '$username' with role '$role'" "apt-layer"
# Check if user exists in system
if ! id "$username" &>/dev/null; then
log_error "User '$username' does not exist in system" "apt-layer"
return 1
fi
local user_db="$ADVANCED_PKG_USERS_DIR/users.json"
# Check if role exists
if ! jq -e ".roles[\"$role\"]" "$user_db" >/dev/null 2>&1; then
log_error "Role '$role' does not exist" "apt-layer"
return 1
fi
# Add user to database
jq --arg user "$username" --arg role "$role" '.users[$user] = {"role": $role, "added": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"}' "$user_db" > "$user_db.tmp" && \
mv "$user_db.tmp" "$user_db"
log_success "User '$username' added with role '$role'" "apt-layer"
return 0
}
# Remove user from package management system
remove_package_user() {
local username="$1"
if [[ -z "$username" ]]; then
log_error "Username required" "apt-layer"
return 1
fi
log_info "Removing user '$username'" "apt-layer"
local user_db="$ADVANCED_PKG_USERS_DIR/users.json"
# Remove user from database
jq --arg user "$username" 'del(.users[$user])' "$user_db" > "$user_db.tmp" && \
mv "$user_db.tmp" "$user_db"
log_success "User '$username' removed" "apt-layer"
return 0
}
# List package management users
list_package_users() {
log_info "Listing package management users" "apt-layer"
local user_db="$ADVANCED_PKG_USERS_DIR/users.json"
if [[ ! -f "$user_db" ]]; then
log_error "User management database not found" "apt-layer"
return 1
fi
echo "=== Package Management Users ==="
local users
users=$(jq -r '.users | to_entries[] | "\(.key): \(.value.role)"' "$user_db" 2>/dev/null || echo "")
if [[ -n "$users" ]]; then
echo "$users" | while read -r user_info; do
echo " $user_info"
done
else
log_info "No users found" "apt-layer"
fi
echo ""
echo "=== Available Roles ==="
local roles
roles=$(jq -r '.roles | to_entries[] | "\(.key): \(.value.description)"' "$user_db" 2>/dev/null || echo "")
if [[ -n "$roles" ]]; then
echo "$roles" | while read -r role_info; do
echo " $role_info"
done
else
log_info "No roles found" "apt-layer"
fi
echo ""
}
# Advanced dependency resolution
resolve_package_dependencies() {
local packages=("$@")
if [[ ${#packages[@]} -eq 0 ]]; then
log_error "No packages specified for dependency resolution" "apt-layer"
return 1
fi
log_info "Resolving dependencies for packages: ${packages[*]}" "apt-layer"
# Create temporary file for dependency resolution
local temp_deps="$ADVANCED_PKG_CACHE_DIR/temp-deps-$$.txt"
local resolved_deps="$ADVANCED_PKG_CACHE_DIR/resolved-deps-$$.txt"
# Get package dependencies using apt-cache
for package in "${packages[@]}"; do
log_debug "Resolving dependencies for package: $package" "apt-layer"
# Get direct dependencies
apt-cache depends "$package" 2>/dev/null | grep -E "^(Depends|Recommends|Suggests)" | cut -d: -f2 | tr -d ' ' | grep -v "^$" >> "$temp_deps" || true
# Get reverse dependencies (what depends on this package)
apt-cache rdepends "$package" 2>/dev/null | grep -v "^Reverse Depends" | grep -v "^$" >> "$temp_deps" || true
done
# Remove duplicates and sort
sort -u "$temp_deps" > "$resolved_deps"
# Check for conflicts
local conflicts=()
while read -r dep; do
if [[ -n "$dep" ]]; then
# Check if package conflicts with any existing packages
if check_package_conflicts "$dep"; then
conflicts+=("$dep")
fi
fi
done < "$resolved_deps"
# Report conflicts
if [[ ${#conflicts[@]} -gt 0 ]]; then
log_warning "Package conflicts detected: ${conflicts[*]}" "apt-layer"
log_info "Manual resolution may be required" "apt-layer"
fi
# Clean up temporary files
rm -f "$temp_deps" "$resolved_deps"
log_success "Dependency resolution completed" "apt-layer"
return 0
}
# Check for package conflicts
check_package_conflicts() {
local package="$1"
if [[ -z "$package" ]]; then
return 1
fi
# Check if package conflicts with any installed packages
local conflicts
conflicts=$(apt-cache policy "$package" 2>/dev/null | grep -A1 "Installed" | grep -E "(Conflicts|Breaks)" || echo "")
if [[ -n "$conflicts" ]]; then
log_warning "Package '$package' has conflicts: $conflicts" "apt-layer"
return 0
fi
return 1
}
# Advanced package installation with security checks
advanced_install_packages() {
local packages=("$@")
local user="${SUDO_USER:-$USER}"
if [[ ${#packages[@]} -eq 0 ]]; then
log_error "No packages specified for installation" "apt-layer"
return 1
fi
log_info "Advanced package installation for packages: ${packages[*]}" "apt-layer"
# Check user permissions
if ! check_user_permissions "$user" "install"; then
return 1
fi
# Check security policies
if ! check_security_policies "${packages[@]}"; then
return 1
fi
# Resolve dependencies
if ! resolve_package_dependencies "${packages[@]}"; then
log_error "Dependency resolution failed" "apt-layer"
return 1
fi
# Start transaction
start_transaction "advanced_install_${packages[0]}"
# Update package lists
update_transaction_phase "updating_package_lists"
log_info "Updating package lists" "apt-layer"
if ! apt-get update; then
log_error "Failed to update package lists" "apt-layer"
rollback_transaction
return 1
fi
# Install packages
update_transaction_phase "installing_packages"
log_info "Installing packages: ${packages[*]}" "apt-layer"
if ! apt-get install -y "${packages[@]}"; then
log_error "Failed to install packages: ${packages[*]}" "apt-layer"
rollback_transaction
return 1
fi
# Clean up
apt-get clean
apt-get autoremove -y
# Log installation
log_package_installation "$user" "${packages[@]}"
commit_transaction
log_success "Advanced package installation completed: ${packages[*]}" "apt-layer"
return 0
}
# Check security policies
check_security_policies() {
local packages=("$@")
log_info "Checking security policies for packages: ${packages[*]}" "apt-layer"
local security_policy="$ADVANCED_PKG_SECURITY_DIR/security-policy.json"
if [[ ! -f "$security_policy" ]]; then
log_warning "Security policy not found, using default policies" "apt-layer"
return 0
fi
# Check package verification settings
local gpg_check
gpg_check=$(jq -r '.package_verification.gpg_check' "$security_policy" 2>/dev/null || echo "true")
if [[ "$gpg_check" == "true" ]]; then
log_info "GPG verification enabled" "apt-layer"
# Perform comprehensive GPG verification
for package in "${packages[@]}"; do
if ! check_package_gpg_signature "$package"; then
log_error "Package '$package' failed GPG signature verification" "apt-layer"
return 1
fi
done
fi
# Check installation policies
local allow_unsigned
allow_unsigned=$(jq -r '.installation_policies.allow_unsigned_packages' "$security_policy" 2>/dev/null || echo "false")
if [[ "$allow_unsigned" == "false" ]]; then
log_info "Unsigned packages not allowed" "apt-layer"
# Check for unsigned packages using enhanced signing verification
for package in "${packages[@]}"; do
if ! check_package_signing "$package"; then
log_error "Package '$package' is not properly signed" "apt-layer"
return 1
fi
done
fi
# Check package size limits
local max_size
max_size=$(jq -r '.installation_policies.max_package_size_mb' "$security_policy" 2>/dev/null || echo "1000")
for package in "${packages[@]}"; do
if ! check_package_size "$package" "$max_size"; then
log_error "Package '$package' exceeds size limit of ${max_size}MB" "apt-layer"
return 1
fi
done
log_success "Security policy checks passed" "apt-layer"
return 0
}
# Check package signature
check_package_signature() {
local package="$1"
if [[ -z "$package" ]]; then
return 1
fi
# Check if package is signed (simplified check)
local package_info
package_info=$(apt-cache policy "$package" 2>/dev/null || echo "")
if echo "$package_info" | grep -q "Signed-By"; then
return 0
fi
return 1
}
# Check package GPG signature (comprehensive verification)
check_package_gpg_signature() {
local package="$1"
if [[ -z "$package" ]]; then
return 1
fi
log_debug "Verifying GPG signature for package: $package" "apt-layer"
# Check if GPG is available
if ! command -v gpg &>/dev/null; then
log_warning "GPG not available, skipping signature verification for: $package" "apt-layer"
return 0
fi
# Get package source and key information
local package_info
package_info=$(apt-cache policy "$package" 2>/dev/null || echo "")
# Check if package has a signed-by field
local signed_by
signed_by=$(echo "$package_info" | grep "Signed-By:" | cut -d: -f2 | tr -d ' ' || echo "")
if [[ -z "$signed_by" ]]; then
log_warning "Package '$package' has no Signed-By field" "apt-layer"
return 1
fi
# Verify the GPG key exists and is trusted
if ! gpg --list-keys "$signed_by" &>/dev/null; then
log_warning "GPG key '$signed_by' for package '$package' not found in keyring" "apt-layer"
return 1
fi
# Additional verification: check if the key is trusted
local trust_level
trust_level=$(gpg --list-keys --with-colons "$signed_by" 2>/dev/null | grep "^pub:" | cut -d: -f2 || echo "")
if [[ "$trust_level" != "u" ]] && [[ "$trust_level" != "f" ]]; then
log_warning "GPG key '$signed_by' for package '$package' is not fully trusted (trust level: $trust_level)" "apt-layer"
return 1
fi
log_debug "GPG signature verification passed for package: $package" "apt-layer"
return 0
}
# Check package signing (enhanced verification)
check_package_signing() {
local package="$1"
if [[ -z "$package" ]]; then
return 1
fi
log_debug "Checking package signing for: $package" "apt-layer"
# Check if debsig-verify is available for Debian package signing verification
if command -v debsig-verify &>/dev/null; then
# Get package file path (this would require downloading or finding the .deb file)
local package_file
package_file=$(find /var/cache/apt/archives -name "${package}*.deb" 2>/dev/null | head -1 || echo "")
if [[ -n "$package_file" ]] && [[ -f "$package_file" ]]; then
if debsig-verify "$package_file" &>/dev/null; then
log_debug "Package signing verification passed for: $package" "apt-layer"
return 0
else
log_warning "Package signing verification failed for: $package" "apt-layer"
return 1
fi
fi
fi
# Fallback to basic signature check
if check_package_signature "$package"; then
log_debug "Basic package signature check passed for: $package" "apt-layer"
return 0
fi
log_warning "Package signing verification failed for: $package" "apt-layer"
return 1
}
# Check package size
check_package_size() {
local package="$1"
local max_size_mb="$2"
if [[ -z "$package" ]] || [[ -z "$max_size_mb" ]]; then
return 1
fi
# Get package size (simplified check)
local package_size
package_size=$(apt-cache show "$package" 2>/dev/null | grep "^Size:" | cut -d: -f2 | tr -d ' ' || echo "0")
if [[ "$package_size" -gt $((max_size_mb * 1024 * 1024)) ]]; then
return 1
fi
return 0
}
# Log package installation
log_package_installation() {
local user="$1"
shift
local packages=("$@")
local audit_log="$ADVANCED_PKG_SECURITY_DIR/audit.log"
for package in "${packages[@]}"; do
echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) - INSTALL - User: $user - Package: $package" >> "$audit_log"
done
}
# Advanced package removal with dependency checking
advanced_remove_packages() {
local packages=("$@")
local user="${SUDO_USER:-$USER}"
if [[ ${#packages[@]} -eq 0 ]]; then
log_error "No packages specified for removal" "apt-layer"
return 1
fi
log_info "Advanced package removal for packages: ${packages[*]}" "apt-layer"
# Check user permissions
if ! check_user_permissions "$user" "remove"; then
return 1
fi
# Check for critical dependencies
for package in "${packages[@]}"; do
if check_critical_dependency "$package"; then
log_warning "Package '$package' may be a critical dependency" "apt-layer"
log_info "Manual verification recommended" "apt-layer"
fi
done
# Start transaction
start_transaction "advanced_remove_${packages[0]}"
# Remove packages
update_transaction_phase "removing_packages"
log_info "Removing packages: ${packages[*]}" "apt-layer"
if ! apt-get remove -y "${packages[@]}"; then
log_error "Failed to remove packages: ${packages[*]}" "apt-layer"
rollback_transaction
return 1
fi
# Clean up
apt-get autoremove -y
apt-get clean
# Log removal
log_package_removal "$user" "${packages[@]}"
commit_transaction
log_success "Advanced package removal completed: ${packages[*]}" "apt-layer"
return 0
}
# Check if package is a critical dependency
check_critical_dependency() {
local package="$1"
if [[ -z "$package" ]]; then
return 1
fi
# List of critical system packages (simplified)
local critical_packages=("systemd" "bash" "coreutils" "apt" "dpkg" "base-files" "ubuntu-minimal")
for critical in "${critical_packages[@]}"; do
if [[ "$package" == "$critical" ]]; then
return 0
fi
done
return 1
}
# Log package removal
log_package_removal() {
local user="$1"
shift
local packages=("$@")
local audit_log="$ADVANCED_PKG_SECURITY_DIR/audit.log"
for package in "${packages[@]}"; do
echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) - REMOVE - User: $user - Package: $package" >> "$audit_log"
done
}
# Advanced package update with rollback capability
advanced_update_packages() {
local packages=("$@")
local user="${SUDO_USER:-$USER}"
log_info "Advanced package update for packages: ${packages[*]}" "apt-layer"
# Check user permissions
if ! check_user_permissions "$user" "update"; then
return 1
fi
# Create backup of current state
local backup_id
backup_id=$(create_package_backup "${packages[@]}")
if [[ -z "$backup_id" ]]; then
log_error "Failed to create package backup" "apt-layer"
return 1
fi
log_info "Created backup: $backup_id" "apt-layer"
# Start transaction
start_transaction "advanced_update_${packages[0]}"
# Update package lists
update_transaction_phase "updating_package_lists"
log_info "Updating package lists" "apt-layer"
if ! apt-get update; then
log_error "Failed to update package lists" "apt-layer"
rollback_transaction
return 1
fi
# Update packages
update_transaction_phase "updating_packages"
log_info "Updating packages: ${packages[*]}" "apt-layer"
if ! apt-get upgrade -y "${packages[@]}"; then
log_error "Failed to update packages: ${packages[*]}" "apt-layer"
log_info "Rolling back to backup: $backup_id" "apt-layer"
restore_package_backup "$backup_id"
rollback_transaction
return 1
fi
# Log update
log_package_update "$user" "${packages[@]}"
commit_transaction
log_success "Advanced package update completed: ${packages[*]}" "apt-layer"
return 0
}
# Create package backup
create_package_backup() {
local packages=("$@")
local backup_id="backup-$(date +%Y%m%d-%H%M%S)-$$"
local backup_dir="$ADVANCED_PKG_STATE_DIR/backups/$backup_id"
mkdir -p "$backup_dir"
log_info "Creating comprehensive package backup: $backup_id" "apt-layer"
# Save package states
for package in "${packages[@]}"; do
dpkg -l "$package" > "$backup_dir/${package}.state" 2>/dev/null || true
done
# Save complete package list
dpkg -l | grep -E "^ii" > "$backup_dir/installed-packages.list" 2>/dev/null || true
# Save package configuration
dpkg --get-selections > "$backup_dir/package-selections.list" 2>/dev/null || true
# Save repository information
cp /etc/apt/sources.list "$backup_dir/sources.list" 2>/dev/null || true
cp -r /etc/apt/sources.list.d "$backup_dir/" 2>/dev/null || true
# Save GPG key information
apt-key list > "$backup_dir/apt-keys.list" 2>/dev/null || true
# Create backup metadata
cat > "$backup_dir/backup-metadata.json" << EOF
{
"backup_id": "$backup_id",
"created_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"created_by": "$(whoami)",
"packages": $(printf '%s\n' "${packages[@]}" | jq -R . | jq -s .),
"system_info": {
"hostname": "$(hostname)",
"distribution": "$(lsb_release -d | cut -f2 2>/dev/null || echo 'unknown')",
"kernel": "$(uname -r)"
}
}
EOF
# Compress backup for storage efficiency
tar -czf "$backup_dir.tar.gz" -C "$ADVANCED_PKG_STATE_DIR/backups" "$backup_id" 2>/dev/null || true
log_success "Package backup created: $backup_id" "apt-layer"
echo "$backup_id"
}
# Restore package backup
restore_package_backup() {
local backup_id="$1"
local backup_dir="$ADVANCED_PKG_STATE_DIR/backups/$backup_id"
local backup_archive="$backup_dir.tar.gz"
# Check if backup exists (try both directory and compressed archive)
if [[ ! -d "$backup_dir" ]] && [[ ! -f "$backup_archive" ]]; then
log_error "Backup not found: $backup_id" "apt-layer"
return 1
fi
log_info "Restoring from backup: $backup_id" "apt-layer"
# Extract compressed backup if needed
if [[ -f "$backup_archive" ]] && [[ ! -d "$backup_dir" ]]; then
log_info "Extracting compressed backup..." "apt-layer"
tar -xzf "$backup_archive" -C "$ADVANCED_PKG_STATE_DIR/backups/" 2>/dev/null || {
log_error "Failed to extract backup archive: $backup_archive" "apt-layer"
return 1
}
fi
# Verify backup integrity
if [[ ! -f "$backup_dir/backup-metadata.json" ]]; then
log_error "Backup metadata not found, backup may be corrupted: $backup_id" "apt-layer"
return 1
fi
# Read backup metadata
local backup_metadata
backup_metadata=$(cat "$backup_dir/backup-metadata.json" 2>/dev/null || echo "{}")
local backup_packages
backup_packages=$(echo "$backup_metadata" | jq -r '.packages[]?' 2>/dev/null || echo "")
log_info "Backup contains $(echo "$backup_packages" | wc -l) packages" "apt-layer"
# Restore package selections if available
if [[ -f "$backup_dir/package-selections.list" ]]; then
log_info "Restoring package selections..." "apt-layer"
dpkg --set-selections < "$backup_dir/package-selections.list" 2>/dev/null || {
log_warning "Failed to restore package selections" "apt-layer"
}
fi
# Restore repository information if available
if [[ -f "$backup_dir/sources.list" ]]; then
log_info "Restoring repository configuration..." "apt-layer"
cp "$backup_dir/sources.list" /etc/apt/sources.list 2>/dev/null || {
log_warning "Failed to restore sources.list" "apt-layer"
}
fi
if [[ -d "$backup_dir/sources.list.d" ]]; then
cp -r "$backup_dir/sources.list.d"/* /etc/apt/sources.list.d/ 2>/dev/null || {
log_warning "Failed to restore sources.list.d" "apt-layer"
}
fi
# Update package lists after repository restoration
apt-get update 2>/dev/null || {
log_warning "Failed to update package lists after repository restoration" "apt-layer"
}
log_success "Backup restoration completed: $backup_id" "apt-layer"
log_audit "BACKUP_RESTORE" "Restored from backup: $backup_id"
return 0
}
# Log package update
log_package_update() {
local user="$1"
shift
local packages=("$@")
local audit_log="$ADVANCED_PKG_SECURITY_DIR/audit.log"
for package in "${packages[@]}"; do
echo "$(date -u +%Y-%m-%dT%H:%M:%SZ) - UPDATE - User: $user - Package: $package" >> "$audit_log"
done
}
# List package backups
list_package_backups() {
log_info "Listing package backups" "apt-layer"
local backups_dir="$ADVANCED_PKG_STATE_DIR/backups"
if [[ ! -d "$backups_dir" ]]; then
log_info "No backups directory found" "apt-layer"
return 0
fi
echo "=== Package Backups ==="
local backups
backups=$(find "$backups_dir" -name "backup-*" -type d 2>/dev/null | sort -r || echo "")
if [[ -n "$backups" ]]; then
for backup_dir in $backups; do
local backup_id
backup_id=$(basename "$backup_dir")
local metadata_file="$backup_dir/backup-metadata.json"
if [[ -f "$metadata_file" ]]; then
local created_at
created_at=$(jq -r '.created_at // "unknown"' "$metadata_file" 2>/dev/null || echo "unknown")
local created_by
created_by=$(jq -r '.created_by // "unknown"' "$metadata_file" 2>/dev/null || echo "unknown")
local package_count
package_count=$(jq -r '.packages | length // 0' "$metadata_file" 2>/dev/null || echo "0")
echo " $backup_id: $package_count packages, created by $created_by at $created_at"
else
echo " $backup_id: (metadata not available)"
fi
done
else
log_info "No backups found" "apt-layer"
fi
echo ""
}
# Clean up old backups
cleanup_old_backups() {
local max_age_days="${1:-30}"
log_info "Cleaning up backups older than $max_age_days days" "apt-layer"
local backups_dir="$ADVANCED_PKG_STATE_DIR/backups"
if [[ ! -d "$backups_dir" ]]; then
log_info "No backups directory found" "apt-layer"
return 0
fi
local removed_count=0
# Find and remove old backup directories
while IFS= read -r -d '' backup_dir; do
local backup_id
backup_id=$(basename "$backup_dir")
local metadata_file="$backup_dir/backup-metadata.json"
if [[ -f "$metadata_file" ]]; then
local created_at
created_at=$(jq -r '.created_at // ""' "$metadata_file" 2>/dev/null || echo "")
if [[ -n "$created_at" ]]; then
local created_timestamp
created_timestamp=$(date -d "$created_at" +%s 2>/dev/null || echo "0")
local current_timestamp
current_timestamp=$(date +%s)
local age_days
age_days=$(( (current_timestamp - created_timestamp) / 86400 ))
if [[ $age_days -gt $max_age_days ]]; then
log_info "Removing old backup: $backup_id (age: ${age_days} days)" "apt-layer"
rm -rf "$backup_dir" 2>/dev/null || true
rm -f "$backup_dir.tar.gz" 2>/dev/null || true
((removed_count++))
fi
fi
fi
done < <(find "$backups_dir" -name "backup-*" -type d -print0 2>/dev/null)
log_success "Cleaned up $removed_count old backups" "apt-layer"
return 0
}
# Get advanced package information
get_advanced_package_info() {
local package="$1"
if [[ -z "$package" ]]; then
log_error "Package name required" "apt-layer"
return 1
fi
log_info "Getting advanced information for package: $package" "apt-layer"
echo "=== Advanced Package Information: $package ==="
# Basic package information
echo "Basic Information:"
apt-cache show "$package" 2>/dev/null | grep -E "^(Package|Version|Architecture|Maintainer|Description)" | head -10
# Dependencies
echo ""
echo "Dependencies:"
apt-cache depends "$package" 2>/dev/null | grep -E "^(Depends|Recommends|Suggests)" | head -5
# Reverse dependencies
echo ""
echo "Reverse Dependencies:"
apt-cache rdepends "$package" 2>/dev/null | grep -v "^Reverse Depends" | head -5
# Security information
echo ""
echo "Security Information:"
if check_package_signature "$package"; then
echo " <20> Package is signed"
else
echo " <20> Package is not signed"
fi
# Size information
local package_size
package_size=$(apt-cache show "$package" 2>/dev/null | grep "^Size:" | cut -d: -f2 | tr -d ' ' || echo "unknown")
echo " Size: $package_size bytes"
echo ""
}
# List advanced package management status
list_advanced_package_status() {
log_info "Listing advanced package management status" "apt-layer"
echo "=== Advanced Package Management Status ==="
# User management status
echo "User Management:"
local user_count
user_count=$(jq '.users | length' "$ADVANCED_PKG_USERS_DIR/users.json" 2>/dev/null || echo "0")
echo " Active users: $user_count"
# Security policy status
echo ""
echo "Security Policies:"
local security_policy="$ADVANCED_PKG_SECURITY_DIR/security-policy.json"
if [[ -f "$security_policy" ]]; then
local gpg_check
gpg_check=$(jq -r '.package_verification.gpg_check' "$security_policy" 2>/dev/null || echo "unknown")
echo " GPG verification: $gpg_check"
local audit_logging
audit_logging=$(jq -r '.audit_logging.enabled' "$security_policy" 2>/dev/null || echo "unknown")
echo " Audit logging: $audit_logging"
else
echo " Security policies: not configured"
fi
# Dependency cache status
echo ""
echo "Dependency Cache:"
local dep_cache="$ADVANCED_PKG_DEPENDENCIES_DIR/dependency-cache.json"
if [[ -f "$dep_cache" ]]; then
local last_updated
last_updated=$(jq -r '.last_updated' "$dep_cache" 2>/dev/null || echo "unknown")
echo " Last updated: $last_updated"
else
echo " Dependency cache: not initialized"
fi
# Audit log status
echo ""
echo "Audit Log:"
local audit_log="$ADVANCED_PKG_SECURITY_DIR/audit.log"
if [[ -f "$audit_log" ]]; then
local log_entries
log_entries=$(wc -l < "$audit_log" 2>/dev/null || echo "0")
echo " Total entries: $log_entries"
local recent_entries
recent_entries=$(tail -10 "$audit_log" 2>/dev/null | wc -l || echo "0")
echo " Recent entries: $recent_entries"
else
echo " Audit log: not available"
fi
echo ""
}
# =============================================================================
# INTEGRATION FUNCTIONS
# =============================================================================
# Initialize advanced package management on script startup
init_advanced_package_management_on_startup() {
# Only initialize if not already done
if [[ ! -d "$ADVANCED_PKG_STATE_DIR" ]]; then
init_advanced_package_management
fi
}
# Cleanup advanced package management on script exit
cleanup_advanced_package_management_on_exit() {
# Clean up temporary files
rm -f "$ADVANCED_PKG_CACHE_DIR"/temp-* 2>/dev/null || true
rm -f "$ADVANCED_PKG_CACHE_DIR"/resolved-* 2>/dev/null || true
}
# Register cleanup function
trap cleanup_advanced_package_management_on_exit EXIT