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>
This commit is contained in:
CyberMind-FR 2026-03-20 10:23:05 +01:00
parent ccfb58124c
commit 7d0f47f465
6 changed files with 1093 additions and 6 deletions

View File

@ -605,7 +605,8 @@
"Bash({ echo \"=== ROOT .md FILES ===\")",
"Bash(if [ -f \"$d/README.md\" ])",
"Bash([ ! -f \"$d/README.fr.md\" ])",
"Bash(basename:*)"
"Bash(basename:*)",
"Bash(VBoxManage internalcommands sethduuid:*)"
]
}
}

View File

@ -232,6 +232,92 @@ jobs:
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
- name: Slipstream SecuBox configuration
if: ${{ github.event.inputs.include_secubox == 'true' || github.event_name == 'push' }}
run: |
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🔧 SLIPSTREAMING SECUBOX CONFIGURATION"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# Determine architecture for this device
ARCH="${{ matrix.subtarget }}"
case "$ARCH" in
cortexa72) OPKG_ARCH="aarch64_cortex-a72" ;;
cortexa53) OPKG_ARCH="aarch64_cortex-a53" ;;
*) OPKG_ARCH="aarch64_generic" ;;
esac
# Create files directory for slipstream content
mkdir -p openwrt/files/etc/opkg
mkdir -p openwrt/files/etc/uci-defaults
mkdir -p openwrt/files/usr/sbin
# Add SecuBox repository configuration
cat > openwrt/files/etc/opkg/customfeeds.conf << EOF
# SecuBox Package Repository
# Pre-configured by GitHub Actions build
# Device: ${{ matrix.device }}
src/gz secubox_packages https://repo.secubox.in/packages/${OPKG_ARCH}
src/gz secubox_luci https://repo.secubox.in/luci/${OPKG_ARCH}
EOF
echo " ✅ Repository configured for ${OPKG_ARCH}"
# Copy seed script
if [[ -f "scripts/secubox-seed.sh" ]]; then
cp scripts/secubox-seed.sh openwrt/files/usr/sbin/secubox-seed
chmod +x openwrt/files/usr/sbin/secubox-seed
echo " ✅ Seed script installed"
fi
# Create first-boot setup script
cat > openwrt/files/etc/uci-defaults/99-secubox-setup << 'FIRSTBOOT'
#!/bin/sh
# SecuBox First-Boot Setup
LOG="/tmp/secubox-firstboot.log"
echo "[$(date)] SecuBox first-boot starting..." >> "$LOG"
# Update package lists
opkg update >> "$LOG" 2>&1 || true
# Try to install core packages if repo is available
for pkg in secubox-core secubox-base; do
if opkg list | grep -q "^$pkg "; then
opkg install "$pkg" >> "$LOG" 2>&1 || true
fi
done
# Set SecuBox theme as default
if [ -f /etc/config/luci ]; then
uci set luci.main.mediaurlbase='/luci-static/secubox' 2>/dev/null || true
uci commit luci 2>/dev/null || true
fi
echo "[$(date)] SecuBox first-boot complete" >> "$LOG"
exit 0
FIRSTBOOT
chmod +x openwrt/files/etc/uci-defaults/99-secubox-setup
echo " ✅ First-boot script created"
# Create SecuBox banner
cat > openwrt/files/etc/banner << BANNER
____ ____
/ ___| ___ ___ _ _| __ ) _____ __
\___ \ / _ \/ __| | | | _ \ / _ \ \/ /
___) | __/ (__| |_| | |_) | (_) > <
|____/ \___|\___|\__,_|____/ \___/_/\_\
SecuBox - ${{ matrix.description }}
https://secubox.in
Run 'secubox-seed --help' for setup options
BANNER
echo " ✅ SecuBox banner created"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
- name: Generate SecuBox config
run: |
cd openwrt

View File

@ -170,6 +170,81 @@ jobs:
echo "📊 Total: $PKG_COUNT SecuBox packages copied"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
- name: Slipstream SecuBox configuration
run: |
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🔧 SLIPSTREAMING SECUBOX CONFIGURATION"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# Create files directory for slipstream content
mkdir -p openwrt/files/etc/opkg
mkdir -p openwrt/files/etc/uci-defaults
mkdir -p openwrt/files/usr/sbin
# Add SecuBox repository configuration
cat > openwrt/files/etc/opkg/customfeeds.conf << 'EOF'
# SecuBox Package Repository
# Pre-configured by GitHub Actions build
src/gz secubox_packages https://repo.secubox.in/packages/x86_64
src/gz secubox_luci https://repo.secubox.in/luci/x86_64
EOF
# Copy seed script
if [[ -f "scripts/secubox-seed.sh" ]]; then
cp scripts/secubox-seed.sh openwrt/files/usr/sbin/secubox-seed
chmod +x openwrt/files/usr/sbin/secubox-seed
echo " ✅ Seed script installed"
fi
# Create first-boot setup script
cat > openwrt/files/etc/uci-defaults/99-secubox-setup << 'FIRSTBOOT'
#!/bin/sh
# SecuBox First-Boot Setup
LOG="/tmp/secubox-firstboot.log"
echo "[$(date)] SecuBox first-boot starting..." >> "$LOG"
# Update package lists
opkg update >> "$LOG" 2>&1 || true
# Try to install core packages if repo is available
for pkg in secubox-core secubox-base; do
if opkg list | grep -q "^$pkg "; then
opkg install "$pkg" >> "$LOG" 2>&1 || true
fi
done
# Set SecuBox theme as default
if [ -f /etc/config/luci ]; then
uci set luci.main.mediaurlbase='/luci-static/secubox' 2>/dev/null || true
uci commit luci 2>/dev/null || true
fi
echo "[$(date)] SecuBox first-boot complete" >> "$LOG"
exit 0
FIRSTBOOT
chmod +x openwrt/files/etc/uci-defaults/99-secubox-setup
echo " ✅ First-boot script created"
# Create SecuBox banner
cat > openwrt/files/etc/banner << 'BANNER'
____ ____
/ ___| ___ ___ _ _| __ ) _____ __
\___ \ / _ \/ __| | | | _ \ / _ \ \/ /
___) | __/ (__| |_| | |_) | (_) > <
|____/ \___|\___|\__,_|____/ \___/_/\_\
SecuBox VM - Security Gateway for OpenWrt
https://secubox.in
Run 'secubox-seed --help' for setup options
BANNER
echo " ✅ SecuBox banner created"
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
- name: Generate VM configuration
run: |
cd openwrt

View File

@ -1,16 +1,66 @@
# Documentation Publishing Scripts
# SecuBox Scripts
English | [Francais](README.fr.md) | [中文](README.zh.md)
**Version:** 1.0.0
**Last Updated:** 2025-12-28
**Purpose:** Automated scripts for publishing SecuBox documentation
**Version:** 1.1.0
**Last Updated:** 2026-03-20
**Purpose:** Automated scripts for SecuBox installation and documentation publishing
---
## 📜 Available Scripts
### 1. setup-wiki.sh
### 1. secubox-seed.sh
**Purpose:** Bootstrap a fresh OpenWrt installation with SecuBox packages
**Usage:**
```bash
# Remote install (recommended)
wget -O- https://repo.secubox.in/seed.sh | sh
# Or with curl
curl -fsSL https://repo.secubox.in/seed.sh | sh
# Local install with options
./scripts/secubox-seed.sh --profile=full
```
**Installation Profiles:**
| Profile | Description | Packages |
|---------|-------------|----------|
| `minimal` | Core only | secubox-core, secubox-base, luci-theme-secubox |
| `standard` | Core + Security + Network | + crowdsec, haproxy, mitmproxy, ipblocklist |
| `full` | Everything | + tor, exposure, glances, master-link, p2p |
**Options:**
- `--profile=PROFILE` - Choose installation profile (minimal/standard/full)
- `--mirror=URL` - Override repository URL
- `--dry-run` - Show what would be installed
- `--skip-update` - Skip opkg update
**Environment Variables:**
- `SECUBOX_PROFILE` - Same as --profile
- `SECUBOX_MIRROR` - Same as --mirror
- `SECUBOX_DRY_RUN=1` - Same as --dry-run
- `SECUBOX_SKIP_UPDATE=1` - Same as --skip-update
**What it does:**
1. Detects system architecture (x86_64, aarch64, armv7l)
2. Configures SecuBox package repository
3. Updates package lists
4. Installs packages based on selected profile
5. Runs post-installation setup
6. Enables and starts services
**Requirements:**
- OpenWrt 24.10+
- Internet connectivity
- Root access
---
### 2. setup-wiki.sh
**Purpose:** Sync DOCS/ to GitHub Wiki
**Usage:**

479
scripts/secubox-seed.sh Executable file
View File

@ -0,0 +1,479 @@
#!/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

396
scripts/secubox-slipstream.sh Executable file
View File

@ -0,0 +1,396 @@
#!/bin/sh
#
# SecuBox Slipstream Script
# Bakes SecuBox repository configuration into OpenWrt images during build
#
# This script is designed to be run during the OpenWrt build process
# to pre-configure the SecuBox repository and optionally pre-install packages.
#
# Usage (during OpenWrt build):
# ./scripts/secubox-slipstream.sh <rootfs_dir> [--profile=PROFILE]
#
# Or as a standalone image modifier:
# ./scripts/secubox-slipstream.sh --image=<image.img.gz> [--profile=PROFILE]
#
set -e
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_URL="${SECUBOX_REPO_URL:-https://repo.secubox.in}"
PROFILE="${SECUBOX_PROFILE:-standard}"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() { printf "${BLUE}[SLIPSTREAM]${NC} %s\n" "$1"; }
log_ok() { printf "${GREEN}[SLIPSTREAM]${NC} %s\n" "$1"; }
log_warn() { printf "${YELLOW}[SLIPSTREAM]${NC} %s\n" "$1"; }
log_error() { printf "${RED}[SLIPSTREAM]${NC} %s\n" "$1"; }
# Detect architecture from rootfs
detect_arch() {
local rootfs="$1"
local arch=""
# Try reading from openwrt_release
if [ -f "$rootfs/etc/openwrt_release" ]; then
arch=$(grep "DISTRIB_ARCH" "$rootfs/etc/openwrt_release" 2>/dev/null | cut -d"'" -f2)
fi
# Fallback: check for common arch indicators
if [ -z "$arch" ]; then
if [ -d "$rootfs/lib/aarch64-linux-gnu" ] || file "$rootfs/bin/busybox" 2>/dev/null | grep -q "aarch64"; then
arch="aarch64_cortex-a72"
elif file "$rootfs/bin/busybox" 2>/dev/null | grep -q "x86-64"; then
arch="x86_64"
elif file "$rootfs/bin/busybox" 2>/dev/null | grep -q "ARM"; then
arch="arm_cortex-a7_neon-vfpv4"
fi
fi
echo "$arch"
}
# Create the customfeeds.conf with SecuBox repository
create_feeds_config() {
local rootfs="$1"
local arch="$2"
local feeds_file="$rootfs/etc/opkg/customfeeds.conf"
log_info "Creating SecuBox feed configuration..."
mkdir -p "$rootfs/etc/opkg"
cat > "$feeds_file" << EOF
# SecuBox Package Repository
# Pre-configured by secubox-slipstream.sh
# Architecture: $arch
# Generated: $(date -u +%Y-%m-%dT%H:%M:%SZ)
src/gz secubox_packages ${REPO_URL}/packages/${arch}
src/gz secubox_luci ${REPO_URL}/luci/${arch}
EOF
log_ok "Feed configuration created: $feeds_file"
}
# Install the seed script into the image
install_seed_script() {
local rootfs="$1"
local seed_script="$SCRIPT_DIR/secubox-seed.sh"
log_info "Installing seed script..."
mkdir -p "$rootfs/usr/sbin"
if [ -f "$seed_script" ]; then
cp "$seed_script" "$rootfs/usr/sbin/secubox-seed"
chmod +x "$rootfs/usr/sbin/secubox-seed"
log_ok "Seed script installed: /usr/sbin/secubox-seed"
else
log_warn "Seed script not found: $seed_script"
fi
}
# Create first-boot script for auto-setup
create_firstboot_script() {
local rootfs="$1"
local profile="$2"
log_info "Creating first-boot setup script..."
mkdir -p "$rootfs/etc/uci-defaults"
cat > "$rootfs/etc/uci-defaults/99-secubox-setup" << 'FIRSTBOOT'
#!/bin/sh
#
# SecuBox First-Boot Setup
# Runs once on first boot to complete SecuBox installation
#
PROFILE="${SECUBOX_PROFILE:-standard}"
LOG_FILE="/tmp/secubox-firstboot.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
log "SecuBox first-boot setup starting..."
# Check if opkg feeds are already configured
if grep -q "secubox_packages" /etc/opkg/customfeeds.conf 2>/dev/null; then
log "SecuBox feeds already configured"
else
log "Error: SecuBox feeds not configured!"
exit 1
fi
# Update package lists
log "Updating package lists..."
if opkg update 2>&1 | tee -a "$LOG_FILE"; then
log "Package lists updated successfully"
else
log "Warning: opkg update had errors"
fi
# Install core packages if not already installed
CORE_PACKAGES="secubox-core secubox-base luci-theme-secubox"
for pkg in $CORE_PACKAGES; do
if ! opkg list-installed | grep -q "^$pkg "; then
log "Installing $pkg..."
if opkg install "$pkg" 2>&1 | tee -a "$LOG_FILE"; then
log "$pkg installed successfully"
else
log "Warning: $pkg installation failed"
fi
else
log "$pkg already installed"
fi
done
# Set SecuBox theme as default
if [ -f /etc/config/luci ]; then
uci set luci.main.mediaurlbase='/luci-static/secubox' 2>/dev/null || true
uci commit luci 2>/dev/null || true
log "SecuBox theme set as default"
fi
# Mark setup complete
touch /etc/secubox-installed
log "SecuBox first-boot setup complete"
# Remove this script (run once)
exit 0
FIRSTBOOT
chmod +x "$rootfs/etc/uci-defaults/99-secubox-setup"
log_ok "First-boot script created"
}
# Create SecuBox branding
create_branding() {
local rootfs="$1"
log_info "Adding SecuBox branding..."
# Custom banner
mkdir -p "$rootfs/etc"
cat > "$rootfs/etc/banner" << 'BANNER'
____ ____
/ ___| ___ ___ _ _| __ ) _____ __
\___ \ / _ \/ __| | | | _ \ / _ \ \/ /
___) | __/ (__| |_| | |_) | (_) > <
|____/ \___|\___|\__,_|____/ \___/_/\_\
SecuBox - Security Gateway for OpenWrt
https://secubox.in
Run 'secubox-seed --help' for setup options
BANNER
# Version info
cat > "$rootfs/etc/secubox-release" << EOF
SECUBOX_VERSION="1.0.0"
SECUBOX_CODENAME="Genesis"
SECUBOX_BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
SECUBOX_PROFILE="${PROFILE}"
EOF
log_ok "Branding added"
}
# Slipstream into an existing rootfs directory
slipstream_rootfs() {
local rootfs="$1"
local profile="$2"
log_info "Slipstreaming SecuBox into rootfs: $rootfs"
if [ ! -d "$rootfs" ]; then
log_error "Rootfs directory not found: $rootfs"
exit 1
fi
# Detect architecture
local arch
arch=$(detect_arch "$rootfs")
if [ -z "$arch" ]; then
log_warn "Could not detect architecture, using x86_64"
arch="x86_64"
fi
log_info "Detected architecture: $arch"
# Apply slipstream
create_feeds_config "$rootfs" "$arch"
install_seed_script "$rootfs"
create_firstboot_script "$rootfs" "$profile"
create_branding "$rootfs"
log_ok "Slipstream complete for: $rootfs"
}
# Slipstream into a compressed image file
slipstream_image() {
local image="$1"
local profile="$2"
log_info "Slipstreaming SecuBox into image: $image"
if [ ! -f "$image" ]; then
log_error "Image file not found: $image"
exit 1
fi
# Create temp directory
local tmpdir
tmpdir=$(mktemp -d)
trap "rm -rf '$tmpdir'" EXIT
local mount_point="$tmpdir/rootfs"
local work_image="$tmpdir/work.img"
mkdir -p "$mount_point"
# Decompress if needed
case "$image" in
*.gz)
log_info "Decompressing image..."
gunzip -c "$image" > "$work_image"
;;
*.img|*.raw)
cp "$image" "$work_image"
;;
*)
log_error "Unsupported image format: $image"
exit 1
;;
esac
# Find and mount rootfs partition
log_info "Mounting image..."
# Try to find rootfs partition offset
local offset
offset=$(fdisk -l "$work_image" 2>/dev/null | grep -E "Linux|ext4" | tail -1 | awk '{print $2}')
if [ -n "$offset" ]; then
offset=$((offset * 512))
sudo mount -o loop,offset=$offset "$work_image" "$mount_point"
else
# Try mounting as-is (might be raw rootfs)
sudo mount -o loop "$work_image" "$mount_point"
fi
# Apply slipstream
slipstream_rootfs "$mount_point" "$profile"
# Unmount
log_info "Unmounting image..."
sudo umount "$mount_point"
# Recompress if original was compressed
case "$image" in
*.gz)
log_info "Recompressing image..."
local output="${image%.gz}-secubox.img.gz"
gzip -c "$work_image" > "$output"
log_ok "Output: $output"
;;
*)
local output="${image%.*}-secubox.${image##*.}"
mv "$work_image" "$output"
log_ok "Output: $output"
;;
esac
}
# Print usage
usage() {
cat << EOF
SecuBox Slipstream Script
Usage:
$0 <rootfs_dir> Slipstream into rootfs directory
$0 --image=<file.img.gz> Slipstream into image file
Options:
--profile=PROFILE Installation profile (minimal|standard|full)
--repo=URL Override repository URL
--help Show this help
Environment:
SECUBOX_REPO_URL Repository URL (default: https://repo.secubox.in)
SECUBOX_PROFILE Installation profile (default: standard)
Examples:
# During OpenWrt build (in files/):
$0 ../build_dir/target-*/root-*/
# Modify existing image:
$0 --image=openwrt-x86-64-generic-ext4-combined.img.gz
# With custom profile:
$0 --profile=full /path/to/rootfs
EOF
}
# Main
main() {
local rootfs=""
local image=""
# Parse arguments
while [ $# -gt 0 ]; do
case "$1" in
--image=*)
image="${1#*=}"
;;
--profile=*)
PROFILE="${1#*=}"
;;
--repo=*)
REPO_URL="${1#*=}"
;;
--help|-h)
usage
exit 0
;;
-*)
log_error "Unknown option: $1"
usage
exit 1
;;
*)
rootfs="$1"
;;
esac
shift
done
echo ""
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " SecuBox Slipstream"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo " Profile: $PROFILE"
echo " Repo: $REPO_URL"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
if [ -n "$image" ]; then
slipstream_image "$image" "$PROFILE"
elif [ -n "$rootfs" ]; then
slipstream_rootfs "$rootfs" "$PROFILE"
else
log_error "No rootfs directory or image specified"
usage
exit 1
fi
}
main "$@"