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>
397 lines
10 KiB
Bash
Executable File
397 lines
10 KiB
Bash
Executable File
#!/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 "$@"
|