From 4e992afacc2657a74f8eb0b37e60fc5f0132491f Mon Sep 17 00:00:00 2001 From: Echo Date: Fri, 24 Apr 2026 00:58:38 +0000 Subject: [PATCH] feat: Add .deb packaging for Ubuntu 24.04 release - debian/control: Package metadata with dependencies - debian/postinst: Service user, dirs, JWT key gen, config, cron setup - debian/prerm: Graceful service stop before upgrade - debian/postrm: Purge cleanup (user, data, config, cron) - debian/changelog: 1.0.0-1 initial release - debian/install: File manifest - scripts/build-package.sh: Full build pipeline (cargo release, frontend, dpkg-deb) - .gitignore: Exclude *.deb and package-build/ --- .gitignore | 4 ++ debian/changelog | 8 +++ debian/compat | 1 + debian/control | 26 +++++++ debian/install | 9 +++ debian/postinst | 80 +++++++++++++++++++++ debian/postrm | 36 ++++++++++ debian/prerm | 20 ++++++ scripts/build-package.sh | 148 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 332 insertions(+) create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/install create mode 100644 debian/postinst create mode 100644 debian/postrm create mode 100644 debian/prerm create mode 100755 scripts/build-package.sh diff --git a/.gitignore b/.gitignore index 0cf6978..4ee6f5e 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,7 @@ venv/** # Frontend dependencies frontend/node_modules frontend/dist + +# Package build artifacts +*.deb +package-build/ diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..1335e16 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,8 @@ +linux-patch-manager (1.0.0-1) noble; urgency=medium + + * Initial release of Linux Patch Manager + * Full M1-M12 feature set implemented + * MFA, RBAC, mTLS, CA, reporting, audit integrity + * HIPAA/PCI-DSS compliance mapping documented + + -- Echo Thu, 24 Apr 2026 00:00:00 +0000 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..f599e28 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +10 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..2c3fa20 --- /dev/null +++ b/debian/control @@ -0,0 +1,26 @@ +Package: linux-patch-manager +Version: 1.0.0-1 +Architecture: amd64 +Maintainer: Moon Dragon +Installed-Size: 45000 +Depends: postgresql-16, libssl3, libc6 (>= 2.39) +Recommends: postgresql-client-16 +Suggests: gpg +Section: admin +Priority: optional +Description: Enterprise Linux Patch Management System + Linux Patch Manager is a secure, web-based management interface for + controlling patching and updates on Linux servers and workstations. + . + Features include: + - Multi-factor authentication (TOTP + WebAuthn) + - Role-based access control (Admin/Operator) + - Mutual TLS agent communication + - Internal Certificate Authority + - Automated patch deployment with rollback + - Maintenance window scheduling + - Real-time WebSocket job monitoring + - CSV/PDF compliance reporting + - Audit logging with hash-chain integrity + - Email notifications + - Azure SSO (OAuth2/OIDC with PKCE) diff --git a/debian/install b/debian/install new file mode 100644 index 0000000..3a95397 --- /dev/null +++ b/debian/install @@ -0,0 +1,9 @@ +usr/local/bin/pm-web +usr/local/bin/pm-worker +usr/local/bin/backup.sh +usr/share/patch-manager/frontend/* +usr/share/patch-manager/config.example.toml +usr/share/patch-manager/migrations/* +lib/systemd/system/patch-manager-web.service +lib/systemd/system/patch-manager-worker.service +lib/systemd/system/patch-manager.target diff --git a/debian/postinst b/debian/postinst new file mode 100644 index 0000000..f7f82e1 --- /dev/null +++ b/debian/postinst @@ -0,0 +1,80 @@ +#!/bin/bash +set -e + +# ============================================================================= +# Linux Patch Manager — Post-install script +# ============================================================================= + +case "$1" in + configure) + # Create service user if not exists + if ! id patch-manager &>/dev/null; then + useradd --system --no-create-home --shell /usr/sbin/nologin \ + --comment "Linux Patch Manager service account" patch-manager + fi + + # Create required directories + mkdir -p /etc/patch-manager/ca /etc/patch-manager/certs \ + /etc/patch-manager/jwt /etc/patch-manager/tls \ + /var/log/patch-manager /opt/patch-manager \ + /var/backups/patch-manager + + chown -R patch-manager:patch-manager \ + /etc/patch-manager /var/log/patch-manager \ + /opt/patch-manager /usr/share/patch-manager/frontend + + chmod 750 /etc/patch-manager/ca /etc/patch-manager/jwt + chmod 700 /var/backups/patch-manager + + # Generate JWT signing key if not present + if [[ ! -f /etc/patch-manager/jwt/signing.pem ]]; then + openssl genpkey -algorithm ed25519 -out /etc/patch-manager/jwt/signing.pem 2>/dev/null + openssl pkey -in /etc/patch-manager/jwt/signing.pem -pubout -out /etc/patch-manager/jwt/verify.pem 2>/dev/null + chown patch-manager:patch-manager /etc/patch-manager/jwt/signing.pem /etc/patch-manager/jwt/verify.pem + chmod 600 /etc/patch-manager/jwt/signing.pem + chmod 644 /etc/patch-manager/jwt/verify.pem + fi + + # Write default config if not present + if [[ ! -f /etc/patch-manager/config.toml ]]; then + cp /usr/share/patch-manager/config.example.toml /etc/patch-manager/config.toml + chown patch-manager:patch-manager /etc/patch-manager/config.toml + chmod 640 /etc/patch-manager/config.toml + fi + + # Install backup cron if not present + if ! crontab -l 2>/dev/null | grep -qF "backup.sh"; then + (crontab -l 2>/dev/null; echo "0 2 * * * /usr/local/bin/backup.sh >> /var/log/patch-manager/backup.log 2>&1") | crontab - + fi + + # Reload systemd + systemctl daemon-reload + + echo "" + echo "Linux Patch Manager installed successfully!" + echo "===========================================" + echo "" + echo "Next steps:" + echo " 1. Install and configure PostgreSQL:" + echo " apt install postgresql-16" + echo " 2. Create the database:" + echo " sudo -u postgres createdb -O patch_manager patch_manager" + echo " 3. Edit /etc/patch-manager/config.toml with your database URL" + echo " 4. Enable and start services:" + echo " systemctl enable --now patch-manager.target" + echo " 5. Access the web UI at https://localhost" + echo " Default admin credentials are set via the seed migration." + echo "" + echo "IMPORTANT: Change the default admin password immediately after first login!" + echo "" + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + ;; +esac + +exit 0 diff --git a/debian/postrm b/debian/postrm new file mode 100644 index 0000000..5f40b09 --- /dev/null +++ b/debian/postrm @@ -0,0 +1,36 @@ +#!/bin/bash +set -e + +case "$1" in + purge) + # Remove service user (only if purge) + if id patch-manager &>/dev/null; then + userdel patch-manager 2>/dev/null || true + fi + + # Remove runtime data + rm -rf /var/log/patch-manager + rm -rf /opt/patch-manager + rm -rf /var/backups/patch-manager + + # Remove configuration and keys (purge only) + rm -rf /etc/patch-manager + + # Remove backup cron + crontab -l 2>/dev/null | grep -vF "backup.sh" | crontab - 2>/dev/null || true + + # Reload systemd + systemctl daemon-reload + ;; + + remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + # On remove (not purge), keep config and keys + systemctl daemon-reload 2>/dev/null || true + ;; + + *) + echo "postrm called with unknown argument \`$1'" >&2 + ;; +esac + +exit 0 diff --git a/debian/prerm b/debian/prerm new file mode 100644 index 0000000..3829ac2 --- /dev/null +++ b/debian/prerm @@ -0,0 +1,20 @@ +#!/bin/bash +set -e + +case "$1" in + remove|upgrade|deconfigure) + # Stop services gracefully + if systemctl is-active --quiet patch-manager.target 2>/dev/null; then + systemctl stop patch-manager.target 2>/dev/null || true + fi + ;; + + failed-upgrade) + ;; + + *) + echo "prerm called with unknown argument \`$1'" >&2 + ;; +esac + +exit 0 diff --git a/scripts/build-package.sh b/scripts/build-package.sh new file mode 100755 index 0000000..bf95488 --- /dev/null +++ b/scripts/build-package.sh @@ -0,0 +1,148 @@ +#!/usr/bin/env bash +# ============================================================================= +# Linux Patch Manager — Build .deb Package for Ubuntu 24.04 +# ============================================================================= +# Produces: linux-patch-manager_1.0.0-1_amd64.deb +# Prerequisites: +# - Rust toolchain (cargo, rustc >= 1.75) +# - Node.js >= 18 + npm +# - dpkg-deb +# ============================================================================= + +set -euo pipefail + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +NC='\033[0m' + +info() { echo -e "${GREEN}[INFO]${NC} $*"; } +warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } +error() { echo -e "${RED}[ERROR]${NC} $*" >&2; exit 1; } + +PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +VERSION="1.0.0" +RELEASE="1" +PKG_NAME="linux-patch-manager" +DEB_NAME="${PKG_NAME}_${VERSION}-${RELEASE}_amd64.deb" +BUILD_DIR="${PROJECT_ROOT}/package-build" + +info "=== Linux Patch Manager — Package Build ===" +info "Version: ${VERSION}-${RELEASE}" +info "Target: Ubuntu 24.04 (noble) amd64" +echo + +# --------------------------------------------------------------------------- +# 1. Build Rust binaries (release mode) +# --------------------------------------------------------------------------- +info "Step 1/5: Building Rust binaries (release mode)..." +cd "${PROJECT_ROOT}" +cargo build --release 2>&1 | tail -5 + +# Verify binaries exist +for bin in pm-web pm-worker; do + [[ -f "${PROJECT_ROOT}/target/release/${bin}" ]] || error "${bin} not found in target/release/" +done +info "Rust binaries built successfully." + +# Strip debug symbols for smaller package +for bin in pm-web pm-worker; do + strip "${PROJECT_ROOT}/target/release/${bin}" 2>/dev/null || warn "strip failed for ${bin} (may already be stripped)" +done +info "Binaries stripped." + +# --------------------------------------------------------------------------- +# 2. Build frontend +# --------------------------------------------------------------------------- +info "Step 2/5: Building frontend..." +cd "${PROJECT_ROOT}/frontend" + +if [[ ! -d "node_modules" ]]; then + info "Installing frontend dependencies..." + npm ci --production 2>&1 | tail -3 +fi + +npm run build 2>&1 | tail -5 +[[ -d "${PROJECT_ROOT}/frontend/dist" ]] || error "Frontend build failed: dist/ not found" +info "Frontend built successfully." + +# --------------------------------------------------------------------------- +# 3. Assemble package directory structure +# --------------------------------------------------------------------------- +info "Step 3/5: Assembling package structure..." +rm -rf "${BUILD_DIR}" +mkdir -p "${BUILD_DIR}/DEBIAN" +mkdir -p "${BUILD_DIR}/usr/local/bin" +mkdir -p "${BUILD_DIR}/usr/share/patch-manager/frontend" +mkdir -p "${BUILD_DIR}/usr/share/patch-manager/migrations" +mkdir -p "${BUILD_DIR}/lib/systemd/system" + +# Binaries +cp "${PROJECT_ROOT}/target/release/pm-web" "${BUILD_DIR}/usr/local/bin/pm-web" +cp "${PROJECT_ROOT}/target/release/pm-worker" "${BUILD_DIR}/usr/local/bin/pm-worker" +cp "${PROJECT_ROOT}/scripts/backup.sh" "${BUILD_DIR}/usr/local/bin/backup.sh" +chmod 755 "${BUILD_DIR}/usr/local/bin/pm-web" +chmod 755 "${BUILD_DIR}/usr/local/bin/pm-worker" +chmod 700 "${BUILD_DIR}/usr/local/bin/backup.sh" + +# Frontend +cp -r "${PROJECT_ROOT}/frontend/dist/"* "${BUILD_DIR}/usr/share/patch-manager/frontend/" + +# Config example +cp "${PROJECT_ROOT}/config/config.example.toml" "${BUILD_DIR}/usr/share/patch-manager/config.example.toml" + +# Migrations +cp "${PROJECT_ROOT}/migrations/"*.sql "${BUILD_DIR}/usr/share/patch-manager/migrations/" + +# Systemd units +cp "${PROJECT_ROOT}/systemd/patch-manager-web.service" "${BUILD_DIR}/lib/systemd/system/" +cp "${PROJECT_ROOT}/systemd/patch-manager-worker.service" "${BUILD_DIR}/lib/systemd/system/" +cp "${PROJECT_ROOT}/systemd/patch-manager.target" "${BUILD_DIR}/lib/systemd/system/" + +# DEBIAN control files +cp "${PROJECT_ROOT}/debian/control" "${BUILD_DIR}/DEBIAN/control" +cp "${PROJECT_ROOT}/debian/postinst" "${BUILD_DIR}/DEBIAN/postinst" +cp "${PROJECT_ROOT}/debian/prerm" "${BUILD_DIR}/DEBIAN/prerm" +cp "${PROJECT_ROOT}/debian/postrm" "${BUILD_DIR}/DEBIAN/postrm" +chmod 755 "${BUILD_DIR}/DEBIAN/postinst" "${BUILD_DIR}/DEBIAN/prerm" "${BUILD_DIR}/DEBIAN/postrm" + +# Calculate installed size (in KB) +INSTALLED_SIZE=$(du -sk "${BUILD_DIR}" | cut -f1) +sed -i "s/^Installed-Size: .*/Installed-Size: ${INSTALLED_SIZE}/" "${BUILD_DIR}/DEBIAN/control" + +info "Package structure assembled (${INSTALLED_SIZE} KB)." + +# --------------------------------------------------------------------------- +# 4. Build .deb package +# --------------------------------------------------------------------------- +info "Step 4/5: Building .deb package..." +dpkg-deb --build "${BUILD_DIR}" "${PROJECT_ROOT}/${DEB_NAME}" +info ".deb package created: ${DEB_NAME}" + +# --------------------------------------------------------------------------- +# 5. Verify and summarize +# --------------------------------------------------------------------------- +info "Step 5/5: Verifying package..." +dpkg-deb --info "${PROJECT_ROOT}/${DEB_NAME}" +echo +dpkg-deb --contents "${PROJECT_ROOT}/${DEB_NAME}" | head -20 +echo + +PKG_SIZE=$(du -h "${PROJECT_ROOT}/${DEB_NAME}" | cut -f1) + +info "=== Package Build Complete ===" +info "Package: ${DEB_NAME}" +info "Size: ${PKG_SIZE}" +echo +echo -e "${CYAN}Installation instructions:${NC}" +echo " 1. Copy ${DEB_NAME} to the target Ubuntu 24.04 host" +echo " 2. Install: sudo dpkg -i ${DEB_NAME}" +echo " 3. Or with auto-deps: sudo apt install ./${DEB_NAME}" +echo " 4. Configure database URL in /etc/patch-manager/config.toml" +echo " 5. Start: systemctl enable --now patch-manager.target" +echo + +# Cleanup build directory +rm -rf "${BUILD_DIR}" +info "Build directory cleaned up."