Finalize nx9-wg production release
This commit is contained in:
1 parent
4dfe42fe68
commit
d704c1e131
30 files changed
+2502
-370
No files matched your search
Executable
+85
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env bash
|
||||
# ==============================================================================
|
||||
# nx9-wg Source Repository Backup Tool
|
||||
# ==============================================================================
|
||||
# PURPOSE:
|
||||
# Creates a timestamped, compressed source code backup archive while strictly
|
||||
# excluding build artifacts (target/) and temporary databases, while retaining
|
||||
# the full .git version history for recovery and auditability.
|
||||
#
|
||||
# PREREQUISITES:
|
||||
# - tar
|
||||
# - xz or gzip
|
||||
# - sha256sum
|
||||
#
|
||||
# BEHAVIOR:
|
||||
# - Non-destructive to the source tree.
|
||||
# - Verifies the integrity of the generated archive.
|
||||
# - Generates a companion .sha256 checksum file.
|
||||
#
|
||||
# USAGE:
|
||||
# bash scripts/backup-source.sh [DESTINATION_DIR]
|
||||
# ./scripts/backup-source.sh /backup/sources
|
||||
# ==============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
DEST_DIR="${1:-${ROOT_DIR}/..}"
|
||||
mkdir -p "${DEST_DIR}"
|
||||
DEST_DIR="$(cd "${DEST_DIR}" && pwd)"
|
||||
|
||||
PROJECT_NAME="nx9-wg"
|
||||
TIMESTAMP="$(date +%Y-%m-%d-%H%M%S)"
|
||||
ARCHIVE_BASE="${PROJECT_NAME}-source-${TIMESTAMP}"
|
||||
ARCHIVE_PATH="${DEST_DIR}/${ARCHIVE_BASE}.tar.xz"
|
||||
|
||||
log() {
|
||||
echo -e "\033[1;34m[BACKUP-SRC]\033[0m \033[1;37m$*\033[0m"
|
||||
}
|
||||
|
||||
success() {
|
||||
echo -e "\033[1;32m[SUCCESS]\033[0m $*"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "\033[1;31m[ERROR]\033[0m $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
log "Creating source backup of ${ROOT_DIR}..."
|
||||
log "Destination archive: ${ARCHIVE_PATH}"
|
||||
|
||||
# Create archive excluding heavy/temporary build outputs
|
||||
tar --exclude='target' \
|
||||
--exclude='.cargo' \
|
||||
--exclude='*.log' \
|
||||
--exclude='*.tmp' \
|
||||
--exclude='*.db' \
|
||||
--exclude='*.db-wal' \
|
||||
--exclude='*.db-shm' \
|
||||
--exclude='*.tar.gz' \
|
||||
--exclude='*.tar.xz' \
|
||||
-cJf "${ARCHIVE_PATH}" \
|
||||
-C "$(dirname "${ROOT_DIR}")" "$(basename "${ROOT_DIR}")" || error "Failed to create source archive."
|
||||
|
||||
# Verify archive integrity
|
||||
log "Verifying archive integrity..."
|
||||
tar -tf "${ARCHIVE_PATH}" >/dev/null || error "Archive verification check failed."
|
||||
|
||||
# Generate checksum
|
||||
(cd "${DEST_DIR}" && sha256sum "$(basename "${ARCHIVE_PATH}")" > "${ARCHIVE_BASE}.sha256")
|
||||
|
||||
ARCHIVE_SIZE="$(du -h "${ARCHIVE_PATH}" | cut -f1)"
|
||||
ARCHIVE_SHA="$(cat "${DEST_DIR}/${ARCHIVE_BASE}.sha256" | awk '{print $1}')"
|
||||
|
||||
echo -e "\n================================================================="
|
||||
echo -e "\033[1;32m SOURCE BACKUP COMPLETED SUCCESSFULLY!\033[0m"
|
||||
echo -e "================================================================="
|
||||
echo " Archive Path: ${ARCHIVE_PATH}"
|
||||
echo " Archive Size: ${ARCHIVE_SIZE}"
|
||||
echo " SHA-256: ${ARCHIVE_SHA}"
|
||||
echo " Checksum File:${DEST_DIR}/${ARCHIVE_BASE}.sha256"
|
||||
echo -e "=================================================================\n"
|
||||
Executable
+85
@@ -0,0 +1,85 @@
|
||||
#!/usr/bin/env bash
|
||||
# ==============================================================================
|
||||
# nx9-wg Production Release Builder
|
||||
# ==============================================================================
|
||||
# PURPOSE:
|
||||
# Runs release quality gates and compiles an optimized release binary:
|
||||
# 1. Format verification
|
||||
# 2. Check & Clippy (-D warnings)
|
||||
# 3. Full workspace test suite
|
||||
# 4. Release build (cargo build --release --workspace)
|
||||
# 5. Artifact verification (binary size, permissions, SHA-256)
|
||||
#
|
||||
# PREREQUISITES:
|
||||
# - Rust toolchain (stable)
|
||||
# - Linux C build tools (libsqlite3 / pkg-config / ldd)
|
||||
#
|
||||
# BEHAVIOR:
|
||||
# - Non-destructive to existing deployments.
|
||||
# - Does NOT run 'cargo clean' to prevent accidental removal of release artifacts.
|
||||
# - Produces target/release/nx9-wg.
|
||||
#
|
||||
# USAGE:
|
||||
# bash scripts/build-release.sh
|
||||
# ./scripts/build-release.sh
|
||||
# ==============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
log() {
|
||||
echo -e "\n\033[1;34m[RELEASE-BUILD]\033[0m \033[1;37m$*\033[0m"
|
||||
}
|
||||
|
||||
success() {
|
||||
echo -e "\033[1;32m[PASS]\033[0m $*"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "\033[1;31m[ERROR]\033[0m $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
cd "${ROOT_DIR}"
|
||||
|
||||
log "1/4 Verifying code formatting..."
|
||||
cargo fmt --all -- --check || error "Formatting verification failed."
|
||||
success "Formatting verified."
|
||||
|
||||
log "2/4 Running compiler and Clippy checks..."
|
||||
cargo check --workspace --all-targets || error "Cargo check failed."
|
||||
cargo clippy --workspace --all-targets --all-features -- -D warnings || error "Clippy check failed."
|
||||
success "Lint checks passed with 0 warnings."
|
||||
|
||||
log "3/4 Running full workspace test suite..."
|
||||
cargo test --workspace --all-targets || error "Workspace test suite failed."
|
||||
success "All unit and integration tests passed."
|
||||
|
||||
log "4/4 Compiling optimized release binary (cargo build --release --workspace)..."
|
||||
cargo build --release --workspace || error "Release build failed."
|
||||
|
||||
TARGET_BIN="${ROOT_DIR}/target/release/nx9-wg"
|
||||
|
||||
if [[ ! -f "${TARGET_BIN}" ]]; then
|
||||
error "Expected release binary not found at ${TARGET_BIN}"
|
||||
fi
|
||||
|
||||
if [[ ! -x "${TARGET_BIN}" ]]; then
|
||||
error "Release binary is not executable at ${TARGET_BIN}"
|
||||
fi
|
||||
|
||||
BIN_SIZE="$(du -h "${TARGET_BIN}" | cut -f1)"
|
||||
BIN_SHA="$(sha256sum "${TARGET_BIN}" | awk '{print $1}')"
|
||||
BIN_DATE="$(date -r "${TARGET_BIN}" '+%Y-%m-%d %H:%M:%S')"
|
||||
|
||||
echo -e "\n================================================================="
|
||||
echo -e "\033[1;32m RELEASE BUILD SUCCESSFUL!\033[0m"
|
||||
echo -e "================================================================="
|
||||
echo " Binary Path: ${TARGET_BIN}"
|
||||
echo " Binary Size: ${BIN_SIZE}"
|
||||
echo " Timestamp: ${BIN_DATE}"
|
||||
echo " SHA-256: ${BIN_SHA}"
|
||||
echo " Version: $("${TARGET_BIN}" version | head -n 1)"
|
||||
echo -e "=================================================================\n"
|
||||
Executable
+216
@@ -0,0 +1,216 @@
|
||||
#!/usr/bin/env bash
|
||||
# ==============================================================================
|
||||
# nx9-wg Production Deployment Tool
|
||||
# ==============================================================================
|
||||
# PURPOSE:
|
||||
# Deploys the compiled release binary target/release/nx9-wg to the production
|
||||
# system path (/usr/local/bin/nx9-wg) with validated controlled replacement,
|
||||
# automatic backup of the previous binary, and controlled systemd service management.
|
||||
#
|
||||
# PREREQUISITES:
|
||||
# - Root privileges (or sudo)
|
||||
# - Pre-compiled release binary at target/release/nx9-wg
|
||||
# - Linux with systemd
|
||||
#
|
||||
# SAFETY INVARIANTS:
|
||||
# - Never overwrites the existing production binary without creating a timestamped backup.
|
||||
# - Never modifies or overwrites database files (/var/lib/nx9-wg/nx9-wg.db).
|
||||
# - Never deletes WireGuard interfaces or kills processes automatically on port conflict.
|
||||
# - Uses the standard 'install' command for controlled binary replacement and strict permissions.
|
||||
# - Returns non-zero exit code on failure.
|
||||
#
|
||||
# USAGE:
|
||||
# sudo bash scripts/deploy.sh [OPTIONS]
|
||||
#
|
||||
# OPTIONS:
|
||||
# --no-restart Install binary without restarting nx9-wg.service
|
||||
# --dry-run Simulate deployment actions without applying changes
|
||||
# -h, --help Show this help message
|
||||
# ==============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
SOURCE_BIN="${ROOT_DIR}/target/release/nx9-wg"
|
||||
DEST_BIN="/usr/local/bin/nx9-wg"
|
||||
CONF_DIR="/etc/nx9-wg"
|
||||
DATA_DIR="/var/lib/nx9-wg"
|
||||
BACKUP_DIR="${DATA_DIR}/backups"
|
||||
LOG_DIR="/var/log/nx9-wg"
|
||||
SERVICE_DEST="/etc/systemd/system/nx9-wg.service"
|
||||
SERVICE_SRC="${ROOT_DIR}/nx9-wg.service"
|
||||
|
||||
DRY_RUN=0
|
||||
NO_RESTART=0
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
nx9-wg Production Deployment Tool
|
||||
|
||||
Usage:
|
||||
sudo bash scripts/deploy.sh [OPTIONS]
|
||||
|
||||
Options:
|
||||
--no-restart Install binary without restarting nx9-wg.service
|
||||
--dry-run Simulate deployment actions without applying changes
|
||||
-h, --help Show this help message
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--dry-run)
|
||||
DRY_RUN=1
|
||||
shift
|
||||
;;
|
||||
--no-restart)
|
||||
NO_RESTART=1
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1" >&2
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
log() {
|
||||
echo -e "\033[1;34m[DEPLOY]\033[0m \033[1;37m$*\033[0m"
|
||||
}
|
||||
|
||||
success() {
|
||||
echo -e "\033[1;32m[SUCCESS]\033[0m $*"
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo -e "\033[1;33m[WARN]\033[0m $*"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "\033[1;31m[ERROR]\033[0m $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 1. Privilege Verification
|
||||
if [[ "${EUID}" -ne 0 && "${DRY_RUN}" -eq 0 ]]; then
|
||||
error "Deployment must be run as root (or via sudo)."
|
||||
fi
|
||||
|
||||
# 2. Source Binary Verification
|
||||
if [[ ! -f "${SOURCE_BIN}" ]]; then
|
||||
error "Source binary not found at ${SOURCE_BIN}. Run 'bash scripts/build-release.sh' first."
|
||||
fi
|
||||
|
||||
if [[ ! -x "${SOURCE_BIN}" ]]; then
|
||||
error "Source binary at ${SOURCE_BIN} is not executable."
|
||||
fi
|
||||
|
||||
SOURCE_SIZE="$(du -h "${SOURCE_BIN}" | cut -f1)"
|
||||
SOURCE_SHA="$(sha256sum "${SOURCE_BIN}" | awk '{print $1}')"
|
||||
SOURCE_DATE="$(date -r "${SOURCE_BIN}" '+%Y-%m-%d %H:%M:%S')"
|
||||
|
||||
log "Source binary verified:"
|
||||
echo " Path: ${SOURCE_BIN}"
|
||||
echo " Size: ${SOURCE_SIZE}"
|
||||
echo " Timestamp: ${SOURCE_DATE}"
|
||||
echo " SHA-256: ${SOURCE_SHA}"
|
||||
|
||||
# 3. Create Filesystem Layout with Strict Permissions
|
||||
log "Ensuring directory permissions..."
|
||||
if [[ "${DRY_RUN}" -eq 0 ]]; then
|
||||
install -d -m 0750 "${CONF_DIR}"
|
||||
install -d -m 0700 "${DATA_DIR}"
|
||||
install -d -m 0700 "${BACKUP_DIR}"
|
||||
install -d -m 0750 "${LOG_DIR}"
|
||||
else
|
||||
echo " [DRY-RUN] install -d directories: ${CONF_DIR}, ${DATA_DIR}, ${BACKUP_DIR}, ${LOG_DIR}"
|
||||
fi
|
||||
|
||||
# 4. Backup Existing Production Binary
|
||||
if [[ -f "${DEST_BIN}" ]]; then
|
||||
TIMESTAMP="$(date +%Y%m%d_%H%M%S)"
|
||||
BACKUP_DEST="${DEST_BIN}.backup.${TIMESTAMP}"
|
||||
log "Backing up active binary to ${BACKUP_DEST}..."
|
||||
if [[ "${DRY_RUN}" -eq 0 ]]; then
|
||||
cp -p "${DEST_BIN}" "${BACKUP_DEST}"
|
||||
chmod 0755 "${BACKUP_DEST}"
|
||||
success "Backup created: ${BACKUP_DEST}"
|
||||
else
|
||||
echo " [DRY-RUN] cp -p ${DEST_BIN} ${BACKUP_DEST}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 5. Controlled Installation of New Binary
|
||||
log "Installing new release binary to ${DEST_BIN}..."
|
||||
if [[ "${DRY_RUN}" -eq 0 ]]; then
|
||||
install -m 0755 "${SOURCE_BIN}" "${DEST_BIN}"
|
||||
success "Binary installed to ${DEST_BIN}"
|
||||
else
|
||||
echo " [DRY-RUN] install -m 0755 ${SOURCE_BIN} ${DEST_BIN}"
|
||||
fi
|
||||
|
||||
# 6. Install or Update systemd Service Unit
|
||||
if [[ -f "${SERVICE_SRC}" && -d "/etc/systemd/system" ]]; then
|
||||
log "Installing/updating systemd service unit..."
|
||||
if [[ "${DRY_RUN}" -eq 0 ]]; then
|
||||
install -m 0644 "${SERVICE_SRC}" "${SERVICE_DEST}"
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
systemctl daemon-reload
|
||||
fi
|
||||
success "systemd service unit updated at ${SERVICE_DEST}"
|
||||
else
|
||||
echo " [DRY-RUN] install -m 0644 ${SERVICE_SRC} ${SERVICE_DEST}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# 7. Safe Socket Inspection
|
||||
if command -v ss >/dev/null 2>&1; then
|
||||
log "Inspecting active UDP listen sockets without modifying the host..."
|
||||
ACTIVE_UDP_SOCKETS="$(ss -lunp 2>/dev/null | grep -v '^State' || true)"
|
||||
if [[ -n "${ACTIVE_UDP_SOCKETS}" ]]; then
|
||||
echo "${ACTIVE_UDP_SOCKETS}"
|
||||
else
|
||||
echo " No UDP listeners reported by ss."
|
||||
fi
|
||||
fi
|
||||
|
||||
# 8. Service Restart & Verification
|
||||
if [[ "${NO_RESTART}" -eq 0 && "${DRY_RUN}" -eq 0 ]]; then
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
log "Restarting nx9-wg.service..."
|
||||
systemctl restart nx9-wg || error "Failed to restart nx9-wg service."
|
||||
sleep 1
|
||||
|
||||
if systemctl is-active --quiet nx9-wg; then
|
||||
success "nx9-wg.service is active and running."
|
||||
else
|
||||
warn "nx9-wg.service is not in active state. Inspecting journal..."
|
||||
journalctl -u nx9-wg -n 20 --no-pager || true
|
||||
error "Service failed to start."
|
||||
fi
|
||||
fi
|
||||
elif [[ "${NO_RESTART}" -eq 1 ]]; then
|
||||
log "Skipping service restart as requested (--no-restart)."
|
||||
fi
|
||||
|
||||
# 9. Final Deployment Verification
|
||||
log "Verifying deployed binary version..."
|
||||
if [[ "${DRY_RUN}" -eq 0 ]]; then
|
||||
DEPLOYED_VER="$("${DEST_BIN}" version | head -n 1)"
|
||||
success "Deployed binary active: ${DEPLOYED_VER}"
|
||||
fi
|
||||
|
||||
echo -e "\n================================================================="
|
||||
echo -e "\033[1;32m DEPLOYMENT COMPLETED SUCCESSFULLY!\033[0m"
|
||||
echo -e "================================================================="
|
||||
echo " Installed Binary: ${DEST_BIN}"
|
||||
echo " Configuration: ${CONF_DIR}/config.toml"
|
||||
echo " Database: ${DATA_DIR}/nx9-wg.db"
|
||||
echo " Service Status: systemctl status nx9-wg"
|
||||
echo -e "=================================================================\n"
|
||||
Executable
+155
@@ -0,0 +1,155 @@
|
||||
#!/usr/bin/env bash
|
||||
# ==============================================================================
|
||||
# nx9-wg Production Diagnostic Collector
|
||||
# ==============================================================================
|
||||
# PURPOSE:
|
||||
# Collects a comprehensive, non-destructive diagnostic snapshot across both
|
||||
# desired SQLite state and live Linux kernel networking state:
|
||||
# - Systemd service & journal log health
|
||||
# - UDP socket bindings & conflict inspection
|
||||
# - Kernel IP link, address, and routing status
|
||||
# - Kernel WireGuard link/interface and peer telemetry (via secret-safe 'wg show')
|
||||
# - Netfilter / nftables ruleset in 'table inet nx9_wg'
|
||||
# - Linux sysctl IP packet forwarding
|
||||
# - Application-level diagnostic subsystem inspections
|
||||
#
|
||||
# PREREQUISITES:
|
||||
# - Root privileges (recommended for kernel/socket inspection, or run via sudo)
|
||||
#
|
||||
# SECURITY INVARIANTS:
|
||||
# - NEVER calls 'wg showconf' (which prints private keys in cleartext).
|
||||
# - Relies exclusively on 'wg show' which masks private keys.
|
||||
# - Strictly non-destructive: only performs read-only inspections.
|
||||
#
|
||||
# USAGE:
|
||||
# sudo bash scripts/diagnose.sh
|
||||
# ./scripts/diagnose.sh
|
||||
# ==============================================================================
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
BIN="/usr/local/bin/nx9-wg"
|
||||
if [[ ! -x "${BIN}" ]]; then
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
if [[ -x "${ROOT_DIR}/target/release/nx9-wg" ]]; then
|
||||
BIN="${ROOT_DIR}/target/release/nx9-wg"
|
||||
elif [[ -x "${ROOT_DIR}/target/debug/nx9-wg" ]]; then
|
||||
BIN="${ROOT_DIR}/target/debug/nx9-wg"
|
||||
fi
|
||||
fi
|
||||
|
||||
section() {
|
||||
echo -e "\n================================================================="
|
||||
echo -e "\033[1;36m>> $*\033[0m"
|
||||
echo -e "================================================================="
|
||||
}
|
||||
|
||||
subsection() {
|
||||
echo -e "\n\033[1;33m--- $*\033[0m"
|
||||
}
|
||||
|
||||
section "1. System & Host Runtime Environment"
|
||||
echo "Timestamp: $(date --iso-8601=seconds)"
|
||||
echo "Hostname: $(hostname)"
|
||||
echo "Kernel: $(uname -r)"
|
||||
echo "Architecture: $(uname -m)"
|
||||
echo "Uptime: $(uptime -p 2>/dev/null || uptime)"
|
||||
if [[ -x "${BIN}" ]]; then
|
||||
echo "nx9-wg: $("${BIN}" version | head -n 1)"
|
||||
else
|
||||
echo "nx9-wg: Binary not found"
|
||||
fi
|
||||
|
||||
section "2. Systemd Service & Process State"
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
subsection "Service Status (nx9-wg.service)"
|
||||
systemctl status nx9-wg --no-pager -l || true
|
||||
|
||||
subsection "Recent Journalctl Logs (Last 30 entries)"
|
||||
journalctl -u nx9-wg -n 30 --no-pager || true
|
||||
else
|
||||
echo "systemctl not available on this host."
|
||||
fi
|
||||
|
||||
section "3. UDP Sockets & Listen Port Inspection"
|
||||
if command -v ss >/dev/null 2>&1; then
|
||||
subsection "Active UDP Listen Sockets (ss -lunp)"
|
||||
ss -lunp 2>/dev/null || true
|
||||
else
|
||||
echo "ss utility not found."
|
||||
fi
|
||||
|
||||
section "4. Linux Network Interfaces & Addresses"
|
||||
if command -v ip >/dev/null 2>&1; then
|
||||
subsection "Brief Interface State (ip -br link)"
|
||||
ip -br link show || true
|
||||
|
||||
subsection "Brief IPv4 / IPv6 Addresses (ip -br addr)"
|
||||
ip -br addr show || true
|
||||
|
||||
subsection "WireGuard Interface Addresses"
|
||||
if command -v wg >/dev/null 2>&1; then
|
||||
WG_INTERFACES="$(wg show interfaces 2>/dev/null || true)"
|
||||
if [[ -n "${WG_INTERFACES}" ]]; then
|
||||
for WG_IFACE in ${WG_INTERFACES}; do
|
||||
echo "Interface: ${WG_IFACE}"
|
||||
ip addr show dev "${WG_IFACE}" 2>/dev/null || true
|
||||
done
|
||||
else
|
||||
echo "No WireGuard interfaces reported by the kernel."
|
||||
fi
|
||||
else
|
||||
echo "wg utility not found; WireGuard interface-specific address inspection skipped."
|
||||
fi
|
||||
else
|
||||
echo "ip utility not found."
|
||||
fi
|
||||
|
||||
section "5. Kernel Routing Table"
|
||||
if command -v ip >/dev/null 2>&1; then
|
||||
subsection "IPv4 Routes (ip route show)"
|
||||
ip route show || true
|
||||
|
||||
subsection "IPv6 Routes (ip -6 route show)"
|
||||
ip -6 route show || true
|
||||
fi
|
||||
|
||||
section "6. Kernel WireGuard Telemetry (Secret-Safe 'wg show')"
|
||||
if command -v wg >/dev/null 2>&1; then
|
||||
wg show 2>&1 || echo "wg show returned non-zero (may require root privileges)."
|
||||
else
|
||||
echo "wg utility not found on host."
|
||||
fi
|
||||
|
||||
section "7. Netfilter / nftables Firewall State (table inet nx9_wg)"
|
||||
if command -v nft >/dev/null 2>&1; then
|
||||
nft list table inet nx9_wg 2>/dev/null || echo "nftables table 'inet nx9_wg' not present."
|
||||
else
|
||||
echo "nft utility not found on host."
|
||||
fi
|
||||
|
||||
section "8. IP Packet Forwarding (Kernel Sysctl)"
|
||||
echo -n "net.ipv4.ip_forward: "
|
||||
cat /proc/sys/net/ipv4/ip_forward 2>/dev/null || echo "Unable to read /proc/sys/net/ipv4/ip_forward"
|
||||
echo -n "net.ipv6.conf.all.forwarding: "
|
||||
cat /proc/sys/net/ipv6/conf/all/forwarding 2>/dev/null || echo "Unable to read /proc/sys/net/ipv6/conf/all/forwarding"
|
||||
|
||||
section "9. Application Desired State & Health Checks"
|
||||
if [[ -x "${BIN}" ]]; then
|
||||
subsection "Appliance Health Check"
|
||||
"${BIN}" system health 2>&1 || true
|
||||
|
||||
subsection "All Subsystems Diagnostics"
|
||||
"${BIN}" diagnostics all 2>&1 || true
|
||||
|
||||
subsection "Reconciliation Drift Status"
|
||||
"${BIN}" reconcile status 2>&1 || true
|
||||
|
||||
subsection "Live WireGuard Interface Status"
|
||||
"${BIN}" live interface list 2>&1 || true
|
||||
else
|
||||
echo "nx9-wg binary not executable; skipping application-level diagnostics."
|
||||
fi
|
||||
|
||||
section "Diagnostic Collection Complete"
|
||||
Regular → Executable
+1
-1
@@ -161,7 +161,7 @@ fi
|
||||
if [[ "${NO_INIT}" -eq 0 && "${DRY_RUN}" -eq 0 ]]; then
|
||||
PW_FILE="${DATA_DIR}/admin-initial-password"
|
||||
log "Checking administrator account initialization..."
|
||||
if "${BIN_DIR}/nx9-wg" --config "${CONF_DIR}/config.toml" --data-dir "${DATA_DIR}" admin info >/dev/null 2>&1; then
|
||||
if "${BIN_DIR}/nx9-wg" --config "${CONF_DIR}/config.toml" --data-dir "${DATA_DIR}" admin status >/dev/null 2>&1; then
|
||||
log "Administrator account already initialized in database."
|
||||
else
|
||||
log "Initializing administrator account with secure random credentials..."
|
||||
|
||||
Regular → Executable
File mode changed.
Executable
+174
@@ -0,0 +1,174 @@
|
||||
#!/usr/bin/env bash
|
||||
# ==============================================================================
|
||||
# nx9-wg Production Rollback Tool
|
||||
# ==============================================================================
|
||||
# PURPOSE:
|
||||
# Rolls back the active production binary (/usr/local/bin/nx9-wg) to the most
|
||||
# recent (or specified) backup binary created during previous deployments.
|
||||
#
|
||||
# PREREQUISITES:
|
||||
# - Root privileges (or sudo)
|
||||
# - At least one backup binary at /usr/local/bin/nx9-wg.backup.*
|
||||
#
|
||||
# SAFETY INVARIANTS:
|
||||
# - Never modifies or deletes the SQLite database.
|
||||
# - Restores executable permissions (0755) and root ownership.
|
||||
# - Confirms service restoration and binary version after rollback.
|
||||
#
|
||||
# USAGE:
|
||||
# sudo bash scripts/rollback.sh [OPTIONS] [SPECIFIC_BACKUP_PATH]
|
||||
#
|
||||
# OPTIONS:
|
||||
# -y, --yes Skip confirmation prompt
|
||||
# -l, --list List available backup binaries and exit
|
||||
# -h, --help Show this help message
|
||||
# ==============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
BIN_DIR="/usr/local/bin"
|
||||
ACTIVE_BIN="${BIN_DIR}/nx9-wg"
|
||||
ASSUME_YES=0
|
||||
LIST_ONLY=0
|
||||
SPECIFIED_BACKUP=""
|
||||
|
||||
usage() {
|
||||
cat <<EOF
|
||||
nx9-wg Production Rollback Tool
|
||||
|
||||
Usage:
|
||||
sudo bash scripts/rollback.sh [OPTIONS] [BACKUP_FILE]
|
||||
|
||||
Options:
|
||||
-y, --yes Skip interactive confirmation prompt
|
||||
-l, --list List available backup binaries and exit
|
||||
-h, --help Show this help message
|
||||
EOF
|
||||
exit 0
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
-y|--yes)
|
||||
ASSUME_YES=1
|
||||
shift
|
||||
;;
|
||||
-l|--list)
|
||||
LIST_ONLY=1
|
||||
shift
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
;;
|
||||
-*)
|
||||
echo "Unknown option: $1" >&2
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
SPECIFIED_BACKUP="$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
log() {
|
||||
echo -e "\033[1;34m[ROLLBACK]\033[0m \033[1;37m$*\033[0m"
|
||||
}
|
||||
|
||||
success() {
|
||||
echo -e "\033[1;32m[SUCCESS]\033[0m $*"
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo -e "\033[1;33m[WARN]\033[0m $*"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "\033[1;31m[ERROR]\033[0m $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 1. Privilege Verification (unless list only)
|
||||
if [[ "${EUID}" -ne 0 && "${LIST_ONLY}" -eq 0 ]]; then
|
||||
error "Rollback must be run as root (or via sudo)."
|
||||
fi
|
||||
|
||||
# 2. Discover Available Backups
|
||||
BACKUPS=($(ls -1t "${ACTIVE_BIN}".backup.* 2>/dev/null || true))
|
||||
|
||||
if [[ "${#BACKUPS[@]}" -eq 0 ]]; then
|
||||
error "No backup binaries found in ${BIN_DIR} matching nx9-wg.backup.*"
|
||||
fi
|
||||
|
||||
if [[ "${LIST_ONLY}" -eq 1 ]]; then
|
||||
echo "Available production backup binaries in ${BIN_DIR}:"
|
||||
for b in "${BACKUPS[@]}"; do
|
||||
SIZE="$(du -h "$b" | cut -f1)"
|
||||
DATE="$(date -r "$b" '+%Y-%m-%d %H:%M:%S')"
|
||||
echo " $b (${SIZE}, ${DATE})"
|
||||
done
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# 3. Select Target Backup
|
||||
TARGET_BACKUP=""
|
||||
if [[ -n "${SPECIFIED_BACKUP}" ]]; then
|
||||
if [[ -f "${SPECIFIED_BACKUP}" ]]; then
|
||||
TARGET_BACKUP="${SPECIFIED_BACKUP}"
|
||||
elif [[ -f "${BIN_DIR}/${SPECIFIED_BACKUP}" ]]; then
|
||||
TARGET_BACKUP="${BIN_DIR}/${SPECIFIED_BACKUP}"
|
||||
else
|
||||
error "Specified backup file not found: ${SPECIFIED_BACKUP}"
|
||||
fi
|
||||
else
|
||||
TARGET_BACKUP="${BACKUPS[0]}"
|
||||
fi
|
||||
|
||||
log "Selected rollback target: ${TARGET_BACKUP}"
|
||||
BACKUP_SIZE="$(du -h "${TARGET_BACKUP}" | cut -f1)"
|
||||
BACKUP_DATE="$(date -r "${TARGET_BACKUP}" '+%Y-%m-%d %H:%M:%S')"
|
||||
echo " Size: ${BACKUP_SIZE}"
|
||||
echo " Timestamp: ${BACKUP_DATE}"
|
||||
|
||||
# 4. Confirmation Prompt
|
||||
if [[ "${ASSUME_YES}" -eq 0 ]]; then
|
||||
echo -e "\n\033[1;33mAre you sure you want to replace active binary ${ACTIVE_BIN} with ${TARGET_BACKUP}?\033[0m"
|
||||
read -r -p "Type 'yes' to proceed with rollback: " CONFIRM
|
||||
if [[ "${CONFIRM}" != "yes" ]]; then
|
||||
error "Rollback aborted by user."
|
||||
fi
|
||||
fi
|
||||
|
||||
# 5. Execute Rollback
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
if systemctl is-active --quiet nx9-wg 2>/dev/null; then
|
||||
log "Stopping nx9-wg service..."
|
||||
systemctl stop nx9-wg || true
|
||||
fi
|
||||
fi
|
||||
|
||||
log "Restoring binary from ${TARGET_BACKUP} to ${ACTIVE_BIN}..."
|
||||
install -m 0755 "${TARGET_BACKUP}" "${ACTIVE_BIN}"
|
||||
|
||||
# 6. Restart Service
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
log "Starting nx9-wg service..."
|
||||
systemctl start nx9-wg || error "Failed to restart nx9-wg service after rollback."
|
||||
sleep 1
|
||||
|
||||
if systemctl is-active --quiet nx9-wg; then
|
||||
success "nx9-wg.service is active and running."
|
||||
else
|
||||
warn "nx9-wg.service is not active. Checking logs:"
|
||||
journalctl -u nx9-wg -n 20 --no-pager || true
|
||||
error "Service failed to become active after rollback."
|
||||
fi
|
||||
fi
|
||||
|
||||
# 7. Verify Restored Version
|
||||
RESTORED_VER="$("${ACTIVE_BIN}" version | head -n 1)"
|
||||
success "Rollback successful. Active binary version: ${RESTORED_VER}"
|
||||
|
||||
echo -e "\n================================================================="
|
||||
echo -e "\033[1;32m PRODUCTION ROLLBACK COMPLETED SUCCESSFULLY!\033[0m"
|
||||
echo -e "=================================================================\n"
|
||||
@@ -154,9 +154,14 @@ log_pass "Pre-flight baseline captured in ${BASELINE_DIR}"
|
||||
# ----------------------------------------------------------------------------
|
||||
section "02 — SQLite Store Initialization"
|
||||
|
||||
TEMP_ADMIN_PW="$(head -c 24 /dev/urandom | base64 | tr -dc 'A-Za-z0-9!@#%^&*_-' | head -c 20)"
|
||||
PW_FILE="${TEST_ROOT}/admin_pw.txt"
|
||||
echo -n "${TEMP_ADMIN_PW}" > "${PW_FILE}"
|
||||
chmod 0600 "${PW_FILE}"
|
||||
|
||||
"${BIN}" --data-dir "${DATA_DIR}" --database "${DB_PATH}" init \
|
||||
--username "admin" \
|
||||
--password "AdminPassword123!" >/dev/null
|
||||
--password-file "${PW_FILE}" >/dev/null
|
||||
|
||||
if [[ -f "${DB_PATH}" ]]; then
|
||||
log_pass "SQLite authoritative store created and migrated"
|
||||
@@ -288,7 +293,7 @@ all_dumps="${TEST_ROOT}/all_dumps.txt"
|
||||
"${BIN}" --data-dir "${DATA_DIR}" --database "${DB_PATH}" --json reconcile plan >> "${all_dumps}" 2>&1 || true
|
||||
"${BIN}" --data-dir "${DATA_DIR}" --database "${DB_PATH}" --json diagnostics all >> "${all_dumps}" 2>&1 || true
|
||||
|
||||
if grep -q "AdminPassword123!" "${all_dumps}"; then
|
||||
if grep -F -q "${TEMP_ADMIN_PW}" "${all_dumps}"; then
|
||||
log_fail "Plaintext administrator password found in command output"
|
||||
else
|
||||
log_pass "Zero plaintext passwords leaked in CLI/diagnostics output"
|
||||
|
||||
Regular → Executable
-1
@@ -119,4 +119,3 @@ else
|
||||
fi
|
||||
|
||||
log "nx9-wg uninstalled successfully."
|
||||
EOF
|
||||
Executable
+83
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env bash
|
||||
# ==============================================================================
|
||||
# nx9-wg Development Verification Gate
|
||||
# ==============================================================================
|
||||
# PURPOSE:
|
||||
# Executes the full development and release quality gate suite in sequence:
|
||||
# 1. Formatting verification (cargo fmt --all -- --check)
|
||||
# 2. Workspace compilation (cargo check --workspace --all-targets)
|
||||
# 3. Strict Clippy linting (cargo clippy --workspace --all-targets --all-features -- -D warnings)
|
||||
# 4. Complete workspace unit & integration tests (cargo test --workspace --all-targets)
|
||||
# 5. Comprehensive CLI verification (scripts/test-cli-comprehensive.sh)
|
||||
#
|
||||
# PREREQUISITES:
|
||||
# - Rust toolchain (cargo, rustc, rustfmt, clippy)
|
||||
#
|
||||
# BEHAVIOR:
|
||||
# - 100% Non-destructive.
|
||||
# - Returns exit code 0 if all checks pass.
|
||||
# - Returns non-zero exit code immediately on any failure.
|
||||
#
|
||||
# USAGE:
|
||||
# bash scripts/verify.sh
|
||||
# ./scripts/verify.sh
|
||||
# ==============================================================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
|
||||
log() {
|
||||
echo -e "\n\033[1;34m[VERIFY]\033[0m \033[1;37m$*\033[0m"
|
||||
}
|
||||
|
||||
success() {
|
||||
echo -e "\033[1;32m[PASS]\033[0m $*"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "\033[1;31m[FAIL]\033[0m $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
cd "${ROOT_DIR}"
|
||||
|
||||
log "1/5 Checking code formatting..."
|
||||
if cargo fmt --all -- --check; then
|
||||
success "Code formatting is clean."
|
||||
else
|
||||
error "Formatting check failed. Run 'cargo fmt --all' to fix."
|
||||
fi
|
||||
|
||||
log "2/5 Compiling workspace targets..."
|
||||
if cargo check --workspace --all-targets; then
|
||||
success "Workspace compilation check passed."
|
||||
else
|
||||
error "Compilation check failed."
|
||||
fi
|
||||
|
||||
log "3/5 Running Clippy with -D warnings..."
|
||||
if cargo clippy --workspace --all-targets --all-features -- -D warnings; then
|
||||
success "Clippy linting passed with 0 warnings."
|
||||
else
|
||||
error "Clippy check failed."
|
||||
fi
|
||||
|
||||
log "4/5 Running complete workspace test suite..."
|
||||
if cargo test --workspace --all-targets; then
|
||||
success "All workspace unit and integration tests passed."
|
||||
else
|
||||
error "Workspace test suite failed."
|
||||
fi
|
||||
|
||||
log "5/5 Running comprehensive CLI verification..."
|
||||
if bash "${SCRIPT_DIR}/test-cli-comprehensive.sh"; then
|
||||
success "CLI comprehensive verification suite passed."
|
||||
else
|
||||
error "CLI verification failed."
|
||||
fi
|
||||
|
||||
echo -e "\n================================================================="
|
||||
echo -e "\033[1;32m ALL VERIFICATION QUALITY GATES PASSED SUCCESSFULLY!\033[0m"
|
||||
echo -e "=================================================================\n"
|
||||
Reference in new issue
Block a user