Files
setec_cdm/setec-web/sec_updates.py

142 lines
6.0 KiB
Python
Raw Permalink Normal View History

# Security update management via .sec files
# Each function returns a bash command string that app.py executes via ssh_run()
SEC_DIR = "/var/www/updates.seteclabs.io/sec"
def os_detect_cmd():
"""Return bash cmd to detect OS distro and version."""
return (
"echo '=== OS Detection ===' && "
"if [ -f /etc/os-release ]; then "
" . /etc/os-release && "
" echo \"DISTRO_ID=$ID\" && "
" echo \"DISTRO_VERSION=$VERSION_ID\" && "
" echo \"DISTRO_CODENAME=$VERSION_CODENAME\" && "
" echo \"DISTRO_NAME=$PRETTY_NAME\"; "
"else "
" echo 'ERROR: /etc/os-release not found'; "
"fi && "
"echo \"KERNEL=$(uname -r)\" && "
"echo \"ARCH=$(dpkg --print-architecture 2>/dev/null || uname -m)\""
)
def list_available_cmd():
"""Return bash cmd to list all available .sec files on the update server."""
return (
f"echo '=== Available Security Updates ===' && "
f"ls -1 {SEC_DIR}/*.sec 2>/dev/null | while read f; do "
f" name=$(basename \"$f\"); "
f" desc=$(head -5 \"$f\" | grep '^# Setec Labs' | sed 's/^# //'); "
f" target=$(head -5 \"$f\" | grep '^# Target:' | sed 's/^# Target: //'); "
f" echo \"$name | $target | $desc\"; "
f"done || echo 'No .sec files found in {SEC_DIR}'"
)
def check_updates_cmd(distro_id, version_id):
"""Return bash cmd to find .sec files matching a distro+version prefix."""
# Construct prefix: e.g. ubuntu + 22.04 -> ubuntu2204_
ver_clean = version_id.replace(".", "")
prefix = f"{distro_id}{ver_clean}_"
return (
f"echo '=== Updates for {distro_id} {version_id} ===' && "
f"ls -1 {SEC_DIR}/{prefix}*.sec 2>/dev/null | while read f; do "
f" name=$(basename \"$f\"); "
f" echo \"$name\"; "
f"done || echo 'No updates found for prefix: {prefix}'"
)
def download_update_cmd(filename):
"""Return bash cmd to show the contents of a .sec file (it's already local on VPS)."""
if ".." in filename or "/" in filename:
return "echo 'ERROR: invalid filename'"
return f"cat {SEC_DIR}/{filename} 2>&1"
def preview_update_cmd(filename):
"""Return bash cmd to preview what a .sec file will do without applying it."""
if ".." in filename or "/" in filename:
return "echo 'ERROR: invalid filename'"
path = f"{SEC_DIR}/{filename}"
return (
f"echo '=== Preview: {filename} ===' && "
f"if [ ! -f '{path}' ]; then echo 'File not found: {filename}'; exit 1; fi && "
f"echo '' && echo '--- [packages] ---' && "
f"sed -n '/^\\[packages\\]/,/^\\[/{{ /^\\[/!p }}' '{path}' | grep -v '^#' | grep -v '^$' && "
f"echo '' && echo '--- [sysctl] ---' && "
f"sed -n '/^\\[sysctl\\]/,/^\\[/{{ /^\\[/!p }}' '{path}' | grep -v '^#' | grep -v '^$' && "
f"echo '' && echo '--- [services] ---' && "
f"sed -n '/^\\[services\\]/,/^\\[/{{ /^\\[/!p }}' '{path}' | grep -v '^#' | grep -v '^$' && "
f"echo '' && echo '--- [files] ---' && "
f"sed -n '/^\\[files\\]/,/^\\[/{{ /^\\[/!p }}' '{path}' | grep -v '^#' | grep -v '^$' && "
f"echo '' && echo '--- [custom] ---' && "
f"sed -n '/^\\[custom\\]/,/^\\[/{{ /^\\[/!p }}' '{path}' | grep -v '^#' | grep -v '^$' && "
f"echo '' && echo '=== End Preview ==='"
)
def parse_and_apply_cmd(filename):
"""Return bash cmd to parse a .sec file and apply all sections."""
if ".." in filename or "/" in filename:
return "echo 'ERROR: invalid filename'"
path = f"{SEC_DIR}/{filename}"
return (
f"if [ ! -f '{path}' ]; then echo 'File not found: {filename}'; exit 1; fi && "
f"echo '=== Applying: {filename} ===' && "
f"echo \"Started: $(date)\" && "
f"echo '' && "
# Log the apply
f"echo \"$(date '+%Y-%m-%d %H:%M:%S') APPLY {filename}\" >> /var/log/setec-updates.log && "
# [packages] section — run each line as a command
f"echo '>>> [packages]' && "
f"sed -n '/^\\[packages\\]/,/^\\[/{{ /^\\[/!p }}' '{path}' | grep -v '^#' | grep -v '^$' | "
f"while IFS= read -r cmd; do "
f" echo \"+ $cmd\" && "
f" eval \"DEBIAN_FRONTEND=noninteractive $cmd\" 2>&1; "
f"done && "
# [sysctl] section — write to conf file, then apply
f"echo '' && echo '>>> [sysctl]' && "
f"sed -n '/^\\[sysctl\\]/,/^\\[/{{ /^\\[/!p }}' '{path}' | grep -v '^#' | grep -v '^$' > /etc/sysctl.d/99-setec-update.conf && "
f"sysctl -p /etc/sysctl.d/99-setec-update.conf 2>&1 && "
# [services] section — run each line
f"echo '' && echo '>>> [services]' && "
f"sed -n '/^\\[services\\]/,/^\\[/{{ /^\\[/!p }}' '{path}' | grep -v '^#' | grep -v '^$' | "
f"while IFS= read -r cmd; do "
f" echo \"+ $cmd\" && "
f" eval \"$cmd\" 2>&1; "
f"done && "
# [files] section — run each line
f"echo '' && echo '>>> [files]' && "
f"sed -n '/^\\[files\\]/,/^\\[/{{ /^\\[/!p }}' '{path}' | grep -v '^#' | grep -v '^$' | "
f"while IFS= read -r cmd; do "
f" echo \"+ $cmd\" && "
f" eval \"$cmd\" 2>&1; "
f"done && "
# [custom] section — strip bash:-: prefix, run each line
f"echo '' && echo '>>> [custom]' && "
f"sed -n '/^\\[custom\\]/,/^\\[/{{ /^\\[/!p }}' '{path}' | grep -v '^#' | grep -v '^$' | "
f"sed 's/^bash:-://' | "
f"while IFS= read -r cmd; do "
f" echo \"+ $cmd\" && "
f" eval \"$cmd\" 2>&1; "
f"done && "
f"echo '' && echo \"Completed: $(date)\" && "
f"echo \"$(date '+%Y-%m-%d %H:%M:%S') DONE {filename}\" >> /var/log/setec-updates.log && "
f"echo '=== Update Applied Successfully ==='"
)
def update_history_cmd():
"""Return bash cmd to show the update application history."""
return (
"echo '=== Setec Update History ===' && "
"if [ -f /var/log/setec-updates.log ]; then "
" cat /var/log/setec-updates.log; "
"else "
" echo 'No update history found'; "
"fi"
)