SAW-Kinoite/post-install/setup-updates.sh
2026-04-02 17:23:23 -05:00

374 lines
9.3 KiB
Bash

#!/bin/bash
# Update Approval System for SAW
# Version: 1.0
# Date: 2026-04-02
#
# This script implements a controlled workflow for applying system updates,
# ensuring that updates are reviewed and approved before being applied.
#
# Usage: sudo ./approve-update.sh
#
# SECURITY RATIONALE:
# The update approval system provides:
# 1. Prevents unauthorized updates
# 2. Allows security team review before deployment
# 3. Enables testing in staging environment
# 4. Provides audit trail for updates
# 5. Prevents automatic deployment of compromised updates
# 6. Ensures updates don't break security controls
#
# How it works:
# 1. Check for available updates
# 2. Display update details to user
# 3. Require explicit approval
# 4. Log all update activities
# 5. Enable easy rollback if needed
#
# Reference: https://docs.fedoraproject.org/en-US/fedora-coreos/atomic-updates/
set -e
# Configuration
LOG_FILE="/var/log/update-approval.log"
APPROVAL_LOG="/var/log/update-approval-records.log"
LOCK_FILE="/var/lock/saw-update-lock"
UPDATE_LOG="/var/log/saw-updates.log"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
# Print functions
log_info() {
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo -e "${GREEN}[$timestamp]${NC} ${BLUE}[INFO]${NC} $1" | tee -a "$LOG_FILE"
}
log_warning() {
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo -e "${YELLOW}[$timestamp]${NC} ${YELLOW}[WARNING]${NC} $1" | tee -a "$LOG_FILE"
}
log_error() {
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo -e "${RED}[$timestamp]${NC} ${RED}[ERROR]${NC} $1" | tee -a "$LOG_FILE"
}
log_approval() {
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
local user=$(whoami)
echo "[$timestamp] User: $user - $1" | tee -a "$APPROVAL_LOG"
}
# Check if running as root
check_root() {
if [ "$EUID" -ne 0 ]; then
log_error "This script must be run as root"
exit 1
fi
}
# Check if another update is running
check_lock() {
if [ -f "$LOCK_FILE" ]; then
log_error "Another update is already running"
log_info "Lock file: $LOCK_FILE"
log_info "If this is an error, remove the lock file"
exit 1
fi
# Create lock file
touch "$LOCK_FILE"
log_info "Lock file created"
# Set up trap to remove lock on exit
trap 'rm -f "$LOCK_FILE"; log_info "Lock file removed"; exit' EXIT
}
# Check for updates
check_updates() {
log_info "Checking for updates..."
# Use rpm-ostree to check for updates
if ! rpm-ostree update --check 2>&1 | tee /tmp/update-check.txt; then
# No updates available
log_info "No updates available"
return 1
fi
# Save update information
cp /tmp/update-check.txt /var/log/saw-latest-update.txt
return 0
}
# Display update details
display_updates() {
echo ""
echo "=========================================="
echo " Available Updates"
echo "=========================================="
echo ""
if [ -f /tmp/update-check.txt ]; then
cat /tmp/update-check.txt
else
echo "No update information available"
fi
echo ""
echo "=========================================="
echo ""
}
# Get approval
#
# SECURITY RATIONALE:
# The approval process ensures:
# 1. Authorized personnel review updates
# 2. Updates are documented
# 3. No surprise updates
# 4. Accountability for update decisions
# 5. Audit trail for compliance
#
# We use a simple yes/no approval with logging.
get_approval() {
echo "=========================================="
echo " Update Approval Request"
echo "=========================================="
echo ""
echo "The following updates are available:"
echo ""
cat /tmp/update-check.txt | head -50
echo ""
echo "=========================================="
echo ""
# Ask for approval
read -p "Do you want to apply these updates? (yes/no): " response
case "$response" in
yes|YES|y|Y)
log_approval "APPROVED: User $USER approved update"
return 0
;;
no|NO|n|N)
log_approval "REJECTED: User $USER rejected update"
log_info "Update cancelled by user"
exit 0
;;
*)
log_error "Invalid response"
log_info "Please enter 'yes' or 'no'"
exit 1
;;
esac
}
# Apply updates
apply_updates() {
log_info "Applying updates..."
# Show warning
echo ""
echo "=========================================="
echo " WARNING"
echo "=========================================="
echo ""
echo "This will apply system updates."
echo "A reboot may be required."
echo "Ensure you have backups."
echo ""
echo "Updates will be applied to:"
echo "- System packages"
echo "- Kernel"
echo "- Security updates"
echo ""
echo "This process may take several minutes."
echo ""
read -p "Are you sure you want to proceed? (yes/no): " confirm
if [ "$confirm" != "yes" ]; then
log_approval "CANCELLED: User $USER cancelled update"
log_info "Update cancelled"
exit 0
fi
log_approval "STARTED: User $USER started update"
# Apply updates
if rpm-ostree upgrade; then
log_approval "COMPLETED: User $USER completed update"
log_info "Updates applied successfully"
log_info "A reboot is recommended"
return 0
else
log_approval "FAILED: User $USER update failed"
log_error "Update failed"
return 1
fi
}
# Show update history
show_history() {
echo ""
echo "=========================================="
echo " Update History"
echo "=========================================="
echo ""
if [ -f "$APPROVAL_LOG" ]; then
cat "$APPROVAL_LOG" | tail -20
else
echo "No update history available"
fi
echo ""
}
# Show update status
show_status() {
echo ""
echo "=========================================="
echo " Update Status"
echo "=========================================="
echo ""
# Show current deployment
echo "Current Deployment:"
rpm-ostree status | head -5
echo ""
# Show pending deployment
echo "Pending Deployment:"
if [ -f /tmp/update-check.txt ]; then
echo "Updates available for review"
else
echo "No updates pending"
fi
echo ""
# Show last update
echo "Last Update:"
if [ -f /var/log/saw-latest-update.txt ]; then
echo "Last update check: $(stat -c %y /var/log/saw-latest-update.txt)"
else
echo "No recent update check"
fi
echo ""
}
# Setup update check cron job
setup_cron() {
log_info "Setting up update check cron job..."
# Create cron job for daily check
cat > /etc/cron.d/saw-update-check << 'CRONJOB'
# SAW Update Check - Daily at 6:00 AM
# Only downloads updates, does not apply them
0 6 * * * root /usr/bin/rpm-ostree update --check >> /var/log/saw-updates.log 2>&1
CRONJOB
chmod 644 /etc/cron.d/saw-update-check
log_info "Cron job created"
log_info "Updates will be checked daily at 6:00 AM"
}
# Display help
show_help() {
cat << 'HELP'
Update Approval System for SAW
==============================
Usage: ./approve-update.sh [OPTIONS]
Options:
--check Check for available updates
--approve Check and prompt for approval
--apply Apply updates (requires approval first)
--history Show update history
--status Show update status
--cron Set up daily update check
--help Show this help message
Examples:
# Check for updates
./approve-update.sh --check
# Check and prompt for approval
./approve-update.sh --approve
# Apply updates
./approve-update.sh --apply
Security Notes:
- Updates require explicit approval
- All approval decisions are logged
- Updates can be reviewed before applying
- Rollback is available if needed
Reference: https://docs.fedoraproject.org/en-US/fedora-coreos/atomic-updates/
HELP
}
# Main execution
main() {
echo ""
echo "=========================================="
echo " Update Approval System"
echo " Fedora Kinoite SAW"
echo "=========================================="
echo ""
check_root
check_lock
case "${1:-}" in
--check)
if check_updates; then
display_updates
log_info "Updates available for review"
else
log_info "No updates available"
fi
;;
--approve)
check_updates
display_updates
get_approval
;;
--apply)
if [ ! -f /tmp/update-check.txt ]; then
log_error "No update information available"
log_info "Run with --check first"
exit 1
fi
display_updates
get_approval
apply_updates
;;
--history)
show_history
;;
--status)
show_status
;;
--cron)
setup_cron
;;
--help|-h)
show_help
;;
*)
show_help
;;
esac
}
# Run main function
main "$@"