secubox-openwrt/scripts/secubox-seed.sh
CyberMind-FR 7d0f47f465 feat(scripts): Add SecuBox seed and slipstream scripts for auto-install
Add comprehensive scripts for bootstrapping SecuBox on fresh OpenWrt:

- secubox-seed.sh: Bootstrap script for fresh installations
  - Auto-detects architecture (x86_64, aarch64, armv7l)
  - Configures SecuBox repository with fallback mechanisms
  - Installation profiles: minimal, standard, full
  - Graceful handling when repo.secubox.in is unavailable

- secubox-slipstream.sh: Bake SecuBox config into images during build
  - Pre-configures repository feeds in rootfs
  - Installs seed script and first-boot setup
  - Adds SecuBox branding (banner, release info)
  - Works with rootfs directories or image files

Update GitHub Actions workflows:
- build-secubox-vm.yml: Add slipstream step for x86_64 VMs
- build-secubox-images.yml: Add slipstream step for GlobalScale devices

Images now include:
- Pre-configured SecuBox repository (/etc/opkg/customfeeds.conf)
- Seed script (/usr/sbin/secubox-seed)
- First-boot auto-setup script
- SecuBox banner

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-20 10:23:05 +01:00

480 lines
14 KiB
Bash
Executable File

#!/bin/sh
#
# SecuBox Seed Script
# Bootstrap a fresh OpenWrt installation with SecuBox packages
#
# Usage:
# wget -O- https://repo.secubox.in/seed.sh | sh
# OR
# curl -fsSL https://repo.secubox.in/seed.sh | sh
#
# Options (via environment):
# SECUBOX_PROFILE=minimal|standard|full (default: standard)
# SECUBOX_MIRROR=url (override repo URL)
# SECUBOX_SKIP_UPDATE=1 (skip opkg update)
# SECUBOX_DRY_RUN=1 (show what would be installed)
#
set -e
# Colors (if terminal supports it)
if [ -t 1 ]; then
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
else
RED='' GREEN='' YELLOW='' BLUE='' NC=''
fi
log_info() { printf "${BLUE}[INFO]${NC} %s\n" "$1"; }
log_ok() { printf "${GREEN}[OK]${NC} %s\n" "$1"; }
log_warn() { printf "${YELLOW}[WARN]${NC} %s\n" "$1"; }
log_error() { printf "${RED}[ERROR]${NC} %s\n" "$1"; }
# Detect architecture
detect_arch() {
local arch
if [ -f /etc/openwrt_release ]; then
arch=$(grep "DISTRIB_ARCH" /etc/openwrt_release | cut -d"'" -f2)
fi
if [ -z "$arch" ]; then
# Fallback: detect from uname
case "$(uname -m)" in
x86_64) arch="x86_64" ;;
aarch64) arch="aarch64_cortex-a72" ;;
armv7l) arch="arm_cortex-a7_neon-vfpv4" ;;
*) arch="$(uname -m)" ;;
esac
fi
echo "$arch"
}
# Repository URLs in order of preference
REPO_URLS="
https://repo.secubox.in
https://secubox.in/repo
https://github.com/CyberMind-FR/secubox-openwrt/releases/download/packages
"
# Check connectivity and find working repo
check_connectivity() {
log_info "Checking network connectivity..."
# First check general connectivity
if ! ping -c 1 -W 3 "downloads.openwrt.org" >/dev/null 2>&1; then
if ! wget -q -T 5 --spider "https://downloads.openwrt.org" 2>/dev/null; then
log_error "No network connectivity. Please check your network configuration."
return 1
fi
fi
log_ok "Network connectivity OK"
return 0
}
# Find a working SecuBox repository
find_working_repo() {
local arch="$1"
# If user specified a mirror, use it directly
if [ -n "$SECUBOX_MIRROR" ]; then
log_info "Using user-specified mirror: $SECUBOX_MIRROR"
echo "$SECUBOX_MIRROR"
return 0
fi
# Check local feed first (for bonus package)
if [ -d "/www/secubox-feed" ] && [ -f "/www/secubox-feed/Packages" ]; then
log_info "Found local SecuBox feed at /www/secubox-feed"
echo "file:///www/secubox-feed"
return 0
fi
# Try each remote URL
log_info "Searching for working SecuBox repository..."
for base_url in $REPO_URLS; do
local test_url="${base_url}/packages/${arch}/Packages.gz"
log_info "Trying: $base_url"
# Try wget first (more common on OpenWrt)
if wget -q -T 10 --spider "$test_url" 2>/dev/null; then
log_ok "Found working repository: $base_url"
echo "$base_url"
return 0
fi
# Try curl as fallback
if command -v curl >/dev/null 2>&1; then
if curl -sf -m 10 "$test_url" >/dev/null 2>&1; then
log_ok "Found working repository: $base_url"
echo "$base_url"
return 0
fi
fi
done
log_warn "No remote SecuBox repository available"
return 1
}
# Configure SecuBox repository
configure_repo() {
local arch="$1"
local feeds_file="/etc/opkg/customfeeds.conf"
log_info "Configuring SecuBox package repository..."
# Find a working repository
local repo_url
repo_url=$(find_working_repo "$arch")
if [ -z "$repo_url" ]; then
log_warn "No SecuBox repository found. Packages will need to be installed manually."
log_info "You can set SECUBOX_MIRROR to specify a custom repository URL."
# Still configure the default URL for future use
repo_url="https://repo.secubox.in"
SECUBOX_REPO_AVAILABLE=0
else
SECUBOX_REPO_AVAILABLE=1
fi
# Backup existing customfeeds.conf
if [ -f "$feeds_file" ]; then
cp "$feeds_file" "${feeds_file}.bak"
fi
# Check if SecuBox feed already configured
if grep -q "secubox_packages" "$feeds_file" 2>/dev/null; then
log_warn "SecuBox feeds already configured, updating..."
sed -i '/secubox_/d' "$feeds_file"
fi
# Handle local file:// URLs differently
if echo "$repo_url" | grep -q "^file://"; then
cat >> "$feeds_file" << EOF
# SecuBox Local Package Repository
# Added by secubox-seed.sh on $(date +%Y-%m-%d)
src secubox_local ${repo_url}
EOF
else
cat >> "$feeds_file" << EOF
# SecuBox Package Repository
# Added by secubox-seed.sh on $(date +%Y-%m-%d)
src/gz secubox_packages ${repo_url}/packages/${arch}
src/gz secubox_luci ${repo_url}/luci/${arch}
EOF
fi
log_ok "Repository configured: ${repo_url}"
}
# Update package lists
update_packages() {
if [ "${SECUBOX_SKIP_UPDATE:-0}" = "1" ]; then
log_warn "Skipping package list update (SECUBOX_SKIP_UPDATE=1)"
return 0
fi
log_info "Updating package lists..."
if ! opkg update 2>&1; then
log_warn "Some feeds failed to update, continuing anyway..."
fi
log_ok "Package lists updated"
}
# Install a package with fallback
install_pkg() {
local pkg="$1"
local optional="${2:-0}"
if [ "${SECUBOX_DRY_RUN:-0}" = "1" ]; then
log_info "[DRY RUN] Would install: $pkg"
return 0
fi
# Check if already installed
if opkg list-installed | grep -q "^${pkg} "; then
log_ok "$pkg already installed"
return 0
fi
log_info "Installing $pkg..."
if opkg install "$pkg" 2>&1; then
log_ok "$pkg installed successfully"
return 0
else
if [ "$optional" = "1" ]; then
log_warn "$pkg installation failed (optional, continuing)"
return 0
else
log_error "$pkg installation failed"
return 1
fi
fi
}
# Install package group with error handling
install_group() {
local group_name="$1"
shift
local packages="$@"
local failed=""
log_info "Installing $group_name packages..."
for pkg in $packages; do
# Check if package is optional (prefixed with ?)
local optional=0
if echo "$pkg" | grep -q "^?"; then
optional=1
pkg="${pkg#?}"
fi
if ! install_pkg "$pkg" "$optional"; then
failed="$failed $pkg"
fi
done
if [ -n "$failed" ]; then
log_warn "Some packages failed to install:$failed"
return 1
fi
log_ok "$group_name packages installed"
return 0
}
# Define package profiles
get_profile_packages() {
local profile="${1:-standard}"
case "$profile" in
minimal)
# Minimal: Just core + theme
echo "CORE:secubox-core secubox-base"
echo "THEME:luci-theme-secubox"
;;
standard)
# Standard: Core + Security + Basic LuCI apps
echo "CORE:secubox-core secubox-base secubox-identity"
echo "THEME:luci-theme-secubox"
echo "SECURITY:?secubox-app-crowdsec ?secubox-app-cs-firewall-bouncer secubox-app-ipblocklist"
echo "NETWORK:secubox-app-haproxy secubox-app-mitmproxy"
echo "LUCI:luci-app-secubox luci-app-haproxy ?luci-app-crowdsec-dashboard"
;;
full)
# Full: Everything
echo "CORE:secubox-core secubox-base secubox-identity secubox-master-link secubox-p2p"
echo "THEME:luci-theme-secubox"
echo "SECURITY:?secubox-app-crowdsec ?secubox-app-cs-firewall-bouncer secubox-app-ipblocklist secubox-app-mitmproxy"
echo "NETWORK:secubox-app-haproxy secubox-app-dns-master secubox-app-exposure secubox-app-tor"
echo "MONITORING:secubox-app-glances secubox-app-netifyd secubox-app-watchdog"
echo "LUCI:luci-app-secubox luci-app-haproxy luci-app-exposure luci-app-dns-master"
echo "LUCI:?luci-app-crowdsec-dashboard luci-app-glances luci-app-master-link"
echo "BONUS:?secubox-app-bonus"
;;
*)
log_error "Unknown profile: $profile"
log_info "Available profiles: minimal, standard, full"
return 1
;;
esac
}
# Post-installation setup
post_install() {
log_info "Running post-installation setup..."
# Initialize SecuBox if secubox-core is installed
if [ -x /usr/sbin/secuboxctl ]; then
log_info "Initializing SecuBox..."
/usr/sbin/secuboxctl init 2>/dev/null || true
fi
# Enable and start key services
local services="secubox haproxy"
for svc in $services; do
if [ -f "/etc/init.d/$svc" ]; then
log_info "Enabling $svc service..."
/etc/init.d/$svc enable 2>/dev/null || true
fi
done
# Reload rpcd for new RPC methods
if [ -f /etc/init.d/rpcd ]; then
log_info "Reloading RPCD..."
/etc/init.d/rpcd restart 2>/dev/null || true
fi
log_ok "Post-installation setup complete"
}
# Print summary
print_summary() {
local profile="$1"
echo ""
echo "=========================================="
printf "${GREEN}SecuBox Installation Complete${NC}\n"
echo "=========================================="
echo ""
echo "Profile: $profile"
echo "Architecture: $(detect_arch)"
echo ""
echo "Access LuCI at: http://$(uci get network.lan.ipaddr 2>/dev/null || echo '192.168.1.1')"
echo ""
echo "Installed packages:"
opkg list-installed | grep -E "^secubox-|^luci-.*secubox|^luci-theme-secubox" | while read line; do
echo " - $line"
done
echo ""
echo "For more information:"
echo " https://docs.secubox.in"
echo ""
}
# Main installation flow
main() {
local profile="${SECUBOX_PROFILE:-standard}"
echo ""
echo "=========================================="
printf "${BLUE}SecuBox Seed Installer${NC}\n"
echo "=========================================="
echo ""
log_info "Profile: $profile"
# Pre-flight checks
if [ "$(id -u)" != "0" ]; then
log_error "This script must be run as root"
exit 1
fi
if ! command -v opkg >/dev/null 2>&1; then
log_error "opkg not found. Is this an OpenWrt system?"
exit 1
fi
# Detect architecture
local arch
arch=$(detect_arch)
log_info "Detected architecture: $arch"
# Check connectivity
if ! check_connectivity; then
exit 1
fi
# Configure repository
configure_repo "$arch"
# Update package lists
update_packages
# Check if repo is available before trying to install
if [ "${SECUBOX_REPO_AVAILABLE:-1}" = "0" ]; then
log_warn "SecuBox repository not available. Skipping package installation."
log_info "Repository has been configured for future use."
log_info "When packages are available, run: opkg update && opkg install secubox-core"
if [ "${SECUBOX_DRY_RUN:-0}" != "1" ]; then
echo ""
echo "=========================================="
printf "${YELLOW}SecuBox Setup Incomplete${NC}\n"
echo "=========================================="
echo ""
echo "Repository configured but packages not available."
echo "To complete installation later:"
echo " opkg update"
echo " opkg install secubox-core secubox-base luci-theme-secubox"
echo ""
fi
exit 0
fi
# Get packages for selected profile
local profile_data
profile_data=$(get_profile_packages "$profile")
if [ -z "$profile_data" ]; then
exit 1
fi
# Install each package group
local install_failed=0
echo "$profile_data" | while IFS=: read group packages; do
if ! install_group "$group" $packages; then
install_failed=1
fi
done
# Post-installation
if [ "${SECUBOX_DRY_RUN:-0}" != "1" ]; then
post_install
print_summary "$profile"
else
log_info "[DRY RUN] Skipping post-installation"
fi
if [ "$install_failed" = "1" ]; then
log_warn "Installation completed with some errors"
exit 1
fi
log_ok "SecuBox installation completed successfully!"
}
# Handle command-line arguments
while [ $# -gt 0 ]; do
case "$1" in
--profile=*)
SECUBOX_PROFILE="${1#*=}"
;;
--mirror=*)
SECUBOX_MIRROR="${1#*=}"
;;
--dry-run)
SECUBOX_DRY_RUN=1
;;
--skip-update)
SECUBOX_SKIP_UPDATE=1
;;
--help|-h)
echo "SecuBox Seed Installer"
echo ""
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " --profile=PROFILE Installation profile (minimal|standard|full)"
echo " --mirror=URL Override repository URL"
echo " --dry-run Show what would be installed"
echo " --skip-update Skip opkg update"
echo " --help Show this help"
echo ""
echo "Environment variables:"
echo " SECUBOX_PROFILE Same as --profile"
echo " SECUBOX_MIRROR Same as --mirror"
echo " SECUBOX_DRY_RUN=1 Same as --dry-run"
echo " SECUBOX_SKIP_UPDATE=1 Same as --skip-update"
echo ""
exit 0
;;
*)
log_error "Unknown option: $1"
exit 1
;;
esac
shift
done
main