feat(vm): Add ARM64 architectures to C3Box VM builds

- Add aarch64-generic (QEMU/Proxmox ARM)
- Add Raspberry Pi 4/400/CM4 (bcm27xx/bcm2711)
- Add Rockchip ARM64 (NanoPi R4S/R5S/R6S)
- Download arch-specific prebuilt packages
- Add architecture-specific kernel modules
- Create local build script with same logic
- Handle different image formats per arch

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
CyberMind-FR 2026-03-17 20:44:40 +01:00
parent 2c2d11423c
commit 9c4d8dcdfd
3 changed files with 532 additions and 24 deletions

View File

@ -575,7 +575,12 @@
"Bash(sudo -S rm:*)", "Bash(sudo -S rm:*)",
"Bash(sudo -S chmod:*)", "Bash(sudo -S chmod:*)",
"Bash(do curl -sk -o /dev/null -w \"%{http_code} \" https://quick.secubox.in/)", "Bash(do curl -sk -o /dev/null -w \"%{http_code} \" https://quick.secubox.in/)",
"Bash(# Check if the dashboard page loads curl -sk --max-time 10 \"\"https://192.168.255.1/cgi-bin/luci/admin/status/metrics\"\")" "Bash(# Check if the dashboard page loads curl -sk --max-time 10 \"\"https://192.168.255.1/cgi-bin/luci/admin/status/metrics\"\")",
"Bash(gh api:*)",
"Bash(gh workflow run:*)",
"Bash(git show:*)",
"Bash(jq -r '.[] | \"\" \"\" + .workflowName + \"\": \"\" + .conclusion + \"\" \\(ID: \"\" + \\(.databaseId | tostring\\) + \"\"\\)\"\"' echo \"\" echo \"=== VM Appliance Artifacts ===\" gh api repos/gkerma/secubox-openwrt/actions/runs/23205786221/artifacts --jq '.artifacts[] | \"\" \"\" + .name + \"\" \\(\"\" + \\(\\(.size_in_bytes / 1048576\\) | floor | tostring\\) + \"\" MB\\)\"\"' echo \"\" echo \"=== Package Build Artifacts ===\" gh api repos/gkerma/secubox-openwrt/actions/runs/23206423503/artifacts --jq '.artifacts[] | \"\" \"\" + .name + \"\" \\(\"\" + \\(\\(.size_in_bytes / 1048576\\) | floor | tostring\\) + \"\" MB\\)\"\"')",
"Bash(__NEW_LINE_0593582cd60ca850__ echo \"\")"
] ]
} }
} }

View File

@ -60,12 +60,33 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
# x86-64 targets
- name: x86-64-efi - name: x86-64-efi
target: x86/64
boot: efi boot: efi
pkg_arch: x86-64
description: "x86/64 EFI (Modern UEFI systems)" description: "x86/64 EFI (Modern UEFI systems)"
- name: x86-64-bios - name: x86-64-bios
target: x86/64
boot: bios boot: bios
pkg_arch: x86-64
description: "x86/64 BIOS (Legacy systems)" description: "x86/64 BIOS (Legacy systems)"
# ARM64 targets
- name: aarch64-generic
target: armsr/armv8
boot: efi
pkg_arch: aarch64-generic
description: "ARM64 Generic (QEMU/Proxmox ARM)"
- name: rpi4
target: bcm27xx/bcm2711
boot: native
pkg_arch: aarch64-cortex-a72
description: "Raspberry Pi 4/400/CM4"
- name: rockchip-armv8
target: rockchip/armv8
boot: native
pkg_arch: rockchip-armv8
description: "Rockchip ARM64 (NanoPi R4S/R5S/R6S)"
name: VM ${{ matrix.description }} name: VM ${{ matrix.description }}
@ -89,12 +110,17 @@ jobs:
- name: Download Image Builder - name: Download Image Builder
run: | run: |
VERSION="${{ env.OPENWRT_VERSION }}" VERSION="${{ env.OPENWRT_VERSION }}"
TARGET="${{ matrix.target }}"
TARGET_SAFE=$(echo "$TARGET" | tr '/' '-')
IB_URL="https://downloads.openwrt.org/releases/${VERSION}/targets/x86/64/openwrt-imagebuilder-${VERSION}-x86-64.Linux-x86_64.tar.zst" IB_URL="https://downloads.openwrt.org/releases/${VERSION}/targets/${TARGET}/openwrt-imagebuilder-${VERSION}-${TARGET_SAFE}.Linux-x86_64.tar.zst"
echo "📥 Downloading Image Builder for $TARGET..."
echo " URL: $IB_URL"
echo "📥 Downloading Image Builder..."
wget -q "$IB_URL" -O imagebuilder.tar.zst 2>/dev/null || { wget -q "$IB_URL" -O imagebuilder.tar.zst 2>/dev/null || {
IB_URL="${IB_URL%.zst}.xz" IB_URL="${IB_URL%.zst}.xz"
echo " Trying .xz: $IB_URL"
wget -q "$IB_URL" -O imagebuilder.tar.xz wget -q "$IB_URL" -O imagebuilder.tar.xz
tar -xf imagebuilder.tar.xz tar -xf imagebuilder.tar.xz
mv openwrt-imagebuilder-* imagebuilder mv openwrt-imagebuilder-* imagebuilder
@ -105,17 +131,18 @@ jobs:
mv openwrt-imagebuilder-* imagebuilder mv openwrt-imagebuilder-* imagebuilder
fi fi
echo "✅ Image Builder ready" echo "✅ Image Builder ready for ${{ matrix.name }}"
- name: Download prebuilt SecuBox packages - name: Download prebuilt SecuBox packages
run: | run: |
echo "📥 Downloading prebuilt SecuBox packages..." echo "📥 Downloading prebuilt SecuBox packages for ${{ matrix.pkg_arch }}..."
# Download x86-64 packages from release # Download architecture-specific packages from release
C3BOX_VER="${{ env.C3BOX_VERSION }}" C3BOX_VER="${{ env.C3BOX_VERSION }}"
PKG_ARCH="${{ matrix.pkg_arch }}"
# Try downloading from release artifacts # Try downloading from release artifacts
PKG_URL="https://github.com/gkerma/secubox-openwrt/releases/download/${C3BOX_VER}/secubox-${C3BOX_VER#v}-x86-64.tar.gz" PKG_URL="https://github.com/gkerma/secubox-openwrt/releases/download/${C3BOX_VER}/secubox-${C3BOX_VER#v}-${PKG_ARCH}.tar.gz"
mkdir -p imagebuilder/packages/secubox mkdir -p imagebuilder/packages/secubox
@ -578,7 +605,6 @@ jobs:
PACKAGES="$PACKAGES openssh-sftp-server" PACKAGES="$PACKAGES openssh-sftp-server"
PACKAGES="$PACKAGES block-mount kmod-fs-ext4 kmod-fs-vfat kmod-fs-btrfs" PACKAGES="$PACKAGES block-mount kmod-fs-ext4 kmod-fs-vfat kmod-fs-btrfs"
PACKAGES="$PACKAGES parted e2fsprogs resize2fs" PACKAGES="$PACKAGES parted e2fsprogs resize2fs"
PACKAGES="$PACKAGES qemu-ga" # QEMU guest agent for Proxmox
PACKAGES="$PACKAGES git rsync screen tmux bash jq" PACKAGES="$PACKAGES git rsync screen tmux bash jq"
PACKAGES="$PACKAGES docker dockerd containerd" PACKAGES="$PACKAGES docker dockerd containerd"
PACKAGES="$PACKAGES wireguard-tools kmod-wireguard luci-proto-wireguard" PACKAGES="$PACKAGES wireguard-tools kmod-wireguard luci-proto-wireguard"
@ -590,10 +616,27 @@ jobs:
PACKAGES="$PACKAGES haproxy bind-server bind-tools" PACKAGES="$PACKAGES haproxy bind-server bind-tools"
PACKAGES="$PACKAGES kmod-nf-conntrack kmod-nf-nat kmod-ipt-nat" PACKAGES="$PACKAGES kmod-nf-conntrack kmod-nf-nat kmod-ipt-nat"
# EFI-specific packages # Architecture-specific packages
if [[ "${{ matrix.boot }}" == "efi" ]]; then case "${{ matrix.target }}" in
PACKAGES="$PACKAGES grub2-efi" x86/64)
fi if [[ "${{ matrix.boot }}" == "efi" ]]; then
PACKAGES="$PACKAGES grub2-efi"
fi
PACKAGES="$PACKAGES qemu-ga" # QEMU guest agent for Proxmox
;;
armsr/armv8)
# ARM64 generic - virtio support for QEMU/Proxmox
PACKAGES="$PACKAGES kmod-virtio-net kmod-virtio-blk"
;;
bcm27xx/bcm2711)
# Raspberry Pi 4 specific
PACKAGES="$PACKAGES kmod-usb-net-asix-ax88179 kmod-usb-net-rtl8152"
;;
rockchip/armv8)
# Rockchip ARM64
PACKAGES="$PACKAGES kmod-usb-net-rtl8152"
;;
esac
# SecuBox packages from prebuilt artifacts (if available) # SecuBox packages from prebuilt artifacts (if available)
IPK_COUNT=$(find packages/secubox -name "*.ipk" 2>/dev/null | wc -l) IPK_COUNT=$(find packages/secubox -name "*.ipk" 2>/dev/null | wc -l)
@ -648,8 +691,27 @@ jobs:
echo "💾 Root partition: ${ROOT_SIZE}MB" echo "💾 Root partition: ${ROOT_SIZE}MB"
echo "" echo ""
# Build with combined-efi or ext4-combined based on boot type # Select profile based on target
PROFILE="generic" case "${{ matrix.target }}" in
x86/64)
PROFILE="generic"
;;
armsr/armv8)
PROFILE="generic"
;;
bcm27xx/bcm2711)
PROFILE="rpi-4"
;;
rockchip/armv8)
# List available profiles and pick first one
PROFILE=$(make info 2>/dev/null | grep -oP 'Default profile:\s+\K\S+' || echo "nanopi-r4s")
;;
*)
PROFILE="generic"
;;
esac
echo "🎯 Profile: $PROFILE"
make image \ make image \
PROFILE="$PROFILE" \ PROFILE="$PROFILE" \
@ -666,30 +728,44 @@ jobs:
run: | run: |
mkdir -p artifacts mkdir -p artifacts
TARGET_DIR="imagebuilder/bin/targets/x86/64" TARGET="${{ matrix.target }}"
TARGET_DIR="imagebuilder/bin/targets/${TARGET}"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "🔄 Converting to VM formats" echo "🔄 Converting to VM formats (${{ matrix.name }})"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
# Find the correct image based on boot type # Find the correct image based on boot type and architecture
if [[ "${{ matrix.boot }}" == "efi" ]]; then case "${{ matrix.boot }}" in
IMG_PATTERN="*-combined-efi.img.gz" efi)
else IMG_PATTERN="*-combined-efi.img.gz"
IMG_PATTERN="*-combined-ext4.img.gz" ;;
fi bios)
IMG_PATTERN="*-combined-ext4.img.gz"
;;
native)
# ARM boards use different image formats
IMG_PATTERN="*-ext4-factory.img.gz"
;;
esac
# Find and extract the image # Find and extract the image
IMG_FILE=$(find "$TARGET_DIR" -name "$IMG_PATTERN" 2>/dev/null | head -1) IMG_FILE=$(find "$TARGET_DIR" -name "$IMG_PATTERN" 2>/dev/null | head -1)
if [[ -z "$IMG_FILE" ]]; then if [[ -z "$IMG_FILE" ]]; then
# Fallback to any combined image # Fallback patterns for different architectures
IMG_FILE=$(find "$TARGET_DIR" -name "*combined*.img.gz" 2>/dev/null | head -1) IMG_FILE=$(find "$TARGET_DIR" -name "*combined*.img.gz" 2>/dev/null | head -1)
fi fi
if [[ -z "$IMG_FILE" ]]; then
# Try ext4-sysupgrade for ARM
IMG_FILE=$(find "$TARGET_DIR" -name "*-ext4-sysupgrade.img.gz" -o -name "*-squashfs-sysupgrade.img.gz" 2>/dev/null | head -1)
fi
if [[ -z "$IMG_FILE" ]]; then if [[ -z "$IMG_FILE" ]]; then
echo "❌ No firmware image found!" echo "❌ No firmware image found!"
ls -la "$TARGET_DIR/" echo "Available files in $TARGET_DIR:"
ls -la "$TARGET_DIR/" 2>/dev/null || find imagebuilder/bin -type f -name "*.img*"
exit 1 exit 1
fi fi

View File

@ -0,0 +1,427 @@
#!/bin/bash
#
# c3box-vm-full-build.sh - Build C3Box VM with full SecuBox package suite
#
# Uses prebuilt packages from release artifacts - same method as GitHub Actions
#
# Usage:
# ./c3box-vm-full-build.sh [version] [arch]
# ./c3box-vm-full-build.sh v1.0.0-beta x86-64
# ./c3box-vm-full-build.sh v1.0.0-beta aarch64
#
set -e
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
NC='\033[0m'
# Configuration
VERSION="${1:-v1.0.0-beta}"
ARCH="${2:-x86-64}"
OPENWRT_VERSION="${OPENWRT_VERSION:-24.10.5}"
DISK_SIZE="${DISK_SIZE:-8}"
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
REPO_ROOT=$(cd "$SCRIPT_DIR/.." && pwd)
BUILD_DIR="/tmp/c3box-vm-build-$$"
OUTPUT_DIR="${OUTPUT_DIR:-/tmp/c3box-vm-output}"
print_header() {
echo ""
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo -e "${CYAN} $1${NC}"
echo -e "${CYAN}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
echo ""
}
print_success() { echo -e "${GREEN}$1${NC}"; }
print_error() { echo -e "${RED}$1${NC}"; }
print_warning() { echo -e "${YELLOW}⚠️ $1${NC}"; }
print_info() { echo -e "${BLUE} $1${NC}"; }
cleanup() {
if [[ -d "$BUILD_DIR" ]]; then
print_info "Cleaning up build directory..."
rm -rf "$BUILD_DIR"
fi
}
trap cleanup EXIT
# Map architecture to OpenWrt target
get_openwrt_target() {
case "$ARCH" in
x86-64|x86_64)
echo "x86/64"
;;
aarch64|aarch64-generic)
echo "armsr/armv8"
;;
aarch64-cortex-a72|bcm27xx-bcm2711)
echo "bcm27xx/bcm2711"
;;
rockchip-armv8)
echo "rockchip/armv8"
;;
mediatek-filogic)
echo "mediatek/filogic"
;;
*)
echo "x86/64"
;;
esac
}
# Map architecture to package archive name
get_package_arch() {
case "$ARCH" in
x86-64|x86_64)
echo "x86-64"
;;
aarch64|aarch64-generic|armsr-armv8)
echo "aarch64-generic"
;;
aarch64-cortex-a72|bcm27xx-bcm2711)
echo "aarch64-cortex-a72"
;;
rockchip-armv8)
echo "rockchip-armv8"
;;
*)
echo "x86-64"
;;
esac
}
print_header "C3Box VM Full Build - SecuBox Suite"
echo "Version: $VERSION"
echo "Architecture: $ARCH"
echo "OpenWrt: $OPENWRT_VERSION"
echo "Disk Size: ${DISK_SIZE}GB"
echo "Output: $OUTPUT_DIR"
echo ""
mkdir -p "$BUILD_DIR" "$OUTPUT_DIR"
cd "$BUILD_DIR"
# Step 1: Download Image Builder
print_header "Downloading OpenWrt Image Builder"
TARGET=$(get_openwrt_target)
TARGET_SAFE=$(echo "$TARGET" | tr '/' '-')
IB_URL="https://downloads.openwrt.org/releases/${OPENWRT_VERSION}/targets/${TARGET}/openwrt-imagebuilder-${OPENWRT_VERSION}-${TARGET_SAFE}.Linux-x86_64.tar.zst"
print_info "Target: $TARGET"
print_info "URL: $IB_URL"
if wget -q "$IB_URL" -O imagebuilder.tar.zst 2>/dev/null; then
tar --zstd -xf imagebuilder.tar.zst
mv openwrt-imagebuilder-* imagebuilder
elif wget -q "${IB_URL%.zst}.xz" -O imagebuilder.tar.xz 2>/dev/null; then
tar -xf imagebuilder.tar.xz
mv openwrt-imagebuilder-* imagebuilder
else
print_error "Failed to download Image Builder"
exit 1
fi
print_success "Image Builder ready"
# Step 2: Download prebuilt SecuBox packages
print_header "Downloading Prebuilt SecuBox Packages"
PKG_ARCH=$(get_package_arch)
PKG_URL="https://github.com/gkerma/secubox-openwrt/releases/download/${VERSION}/secubox-${VERSION#v}-${PKG_ARCH}.tar.gz"
mkdir -p imagebuilder/packages/secubox
print_info "Package URL: $PKG_URL"
if wget -q "$PKG_URL" -O /tmp/secubox-packages.tar.gz 2>/dev/null; then
tar -xzf /tmp/secubox-packages.tar.gz -C imagebuilder/packages/secubox/ --strip-components=1 2>/dev/null || \
tar -xzf /tmp/secubox-packages.tar.gz -C imagebuilder/packages/secubox/
print_success "Downloaded release packages"
else
print_warning "Release packages not found, will use feed installation"
fi
IPK_COUNT=$(find imagebuilder/packages/secubox/ -name "*.ipk" 2>/dev/null | wc -l)
print_info "Found $IPK_COUNT prebuilt packages"
# Create local repository if packages exist
if [[ $IPK_COUNT -gt 0 ]]; then
print_info "Creating local package repository..."
cd imagebuilder/packages/secubox
for ipk in *.ipk; do
[ -f "$ipk" ] || continue
PKG_NAME=$(echo "$ipk" | sed 's/_.*//; s/^.*\///')
echo "Package: $PKG_NAME"
echo "Version: 1.0.0"
echo "Filename: $ipk"
echo ""
done > Packages
gzip -k Packages
cd "$BUILD_DIR"
# Add to repositories.conf
echo "src secubox file://$(pwd)/imagebuilder/packages/secubox" >> imagebuilder/repositories.conf
print_success "Local repository created"
fi
# Step 3: Create preseed files
print_header "Creating Preseed Configuration"
mkdir -p imagebuilder/files/etc/uci-defaults
mkdir -p imagebuilder/files/etc/c3box
mkdir -p imagebuilder/files/etc/opkg
mkdir -p imagebuilder/files/etc/secubox
# SecuBox feed configuration
cat > imagebuilder/files/etc/opkg/customfeeds.conf << 'EOF'
# SecuBox Official Package Feed
src/gz secubox_packages https://repo.secubox.org/packages/aarch64_generic
src/gz secubox_luci https://repo.secubox.org/luci/aarch64_generic
EOF
# Network preseed
cat > imagebuilder/files/etc/uci-defaults/10-c3box-network << 'EOF'
#!/bin/sh
# C3Box VM Network Configuration
uci set system.@system[0].hostname='c3box'
uci set system.@system[0].timezone='UTC'
uci set system.@system[0].zonename='UTC'
uci set network.lan.ipaddr='192.168.200.1'
uci set network.lan.netmask='255.255.255.0'
uci set network.lan.proto='static'
uci set network.wan=interface
uci set network.wan.device='eth1'
uci set network.wan.proto='dhcp'
uci set dhcp.lan.start='100'
uci set dhcp.lan.limit='150'
uci set dhcp.lan.leasetime='12h'
uci set firewall.@zone[0].input='ACCEPT'
uci set firewall.@zone[0].output='ACCEPT'
uci set firewall.@zone[0].forward='REJECT'
uci set firewall.@zone[1].input='REJECT'
uci set firewall.@zone[1].output='ACCEPT'
uci set firewall.@zone[1].forward='REJECT'
uci set firewall.@zone[1].masq='1'
uci set uhttpd.main.redirect_https='1'
uci commit
exit 0
EOF
chmod 755 imagebuilder/files/etc/uci-defaults/10-c3box-network
# SecuBox config preseed
cat > imagebuilder/files/etc/uci-defaults/20-secubox-config << 'EOF'
#!/bin/sh
# SecuBox Core Configuration
touch /etc/config/secubox
uci set secubox.main=core
uci set secubox.main.enabled='1'
uci set secubox.main.log_level='info'
uci set secubox.main.appstore_url='https://repo.secubox.org/catalog'
uci set secubox.main.appstore_fallback_local='1'
uci set secubox.main.health_check_interval='300'
uci set secubox.main.watchdog_interval='60'
uci set secubox.main.led_heartbeat='1'
uci set secubox.main.ai_enabled='0'
uci set secubox.main.ai_mode='copilot'
uci set secubox.enforcement=security
uci set secubox.enforcement.sandboxing='1'
uci set secubox.enforcement.module_signature_check='0'
uci set secubox.enforcement.allowed_repos='official'
uci set secubox.enforcement.auto_update_check='1'
uci set secubox.settings=diagnostics
uci set secubox.settings.collect_metrics='1'
uci set secubox.settings.retain_days='7'
uci set secubox.settings.alert_enabled='1'
uci set secubox.remote=wan_access
uci set secubox.remote.enabled='1'
uci set secubox.remote.https_enabled='1'
uci set secubox.remote.https_port='443'
uci set secubox.remote.ssh_enabled='1'
uci set secubox.external=settings
uci set secubox.external.enabled='1'
uci set secubox.external.wildcard_enabled='1'
uci set secubox.external.default_landing='1'
uci set secubox.local=domain
uci set secubox.local.enabled='1'
uci set secubox.local.base_domain='sb.local'
uci set secubox.local.suffix='_local'
uci commit secubox
exit 0
EOF
chmod 755 imagebuilder/files/etc/uci-defaults/20-secubox-config
# Filesystem resize
cat > imagebuilder/files/etc/uci-defaults/99-c3box-resize << 'EOF'
#!/bin/sh
if [ ! -f /etc/c3box/resized ]; then
ROOT_DEV=$(mount | grep ' / ' | cut -d' ' -f1)
if [ -n "$ROOT_DEV" ]; then
DISK_DEV=$(echo "$ROOT_DEV" | sed 's/[0-9]*$//')
PART_NUM=$(echo "$ROOT_DEV" | grep -o '[0-9]*$')
parted -s "$DISK_DEV" resizepart "$PART_NUM" 100% 2>/dev/null || true
resize2fs "$ROOT_DEV" 2>/dev/null || true
mkdir -p /etc/c3box
touch /etc/c3box/resized
fi
fi
touch /etc/c3box/configured
exit 0
EOF
chmod 755 imagebuilder/files/etc/uci-defaults/99-c3box-resize
# Release info
cat > imagebuilder/files/etc/c3box/release << EOF
C3BOX_VERSION="$VERSION"
C3BOX_BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
OPENWRT_VERSION="$OPENWRT_VERSION"
ARCH="$ARCH"
DISK_SIZE="${DISK_SIZE}GB"
SECUBOX_MODULES="101"
EOF
# Banner
cat > imagebuilder/files/etc/banner << 'EOF'
██████╗██████╗ ██████╗ ██████╗ ██╗ ██╗
██╔════╝╚════██╗██╔══██╗██╔═══██╗╚██╗██╔╝
██║ █████╔╝██████╔╝██║ ██║ ╚███╔╝
██║ ╚═══██╗██╔══██╗██║ ██║ ██╔██╗
╚██████╗██████╔╝██████╔╝╚██████╔╝██╔╝ ██╗
╚═════╝╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝
C3Box - CyberMind Security Appliance
SecuBox 101+ Modules | Master Target Mesh
Web UI: https://192.168.200.1
Wiki: https://github.com/gkerma/secubox-openwrt/wiki
EOF
print_success "Preseed configuration created"
# Step 4: Build firmware
print_header "Building Firmware Image"
cd imagebuilder
# Base packages
PACKAGES="luci luci-ssl luci-app-opkg luci-theme-openwrt-2020"
PACKAGES="$PACKAGES curl wget-ssl htop iftop tcpdump nano"
PACKAGES="$PACKAGES openssh-sftp-server"
PACKAGES="$PACKAGES block-mount kmod-fs-ext4 kmod-fs-vfat kmod-fs-btrfs"
PACKAGES="$PACKAGES parted e2fsprogs resize2fs"
PACKAGES="$PACKAGES git rsync screen tmux bash jq"
PACKAGES="$PACKAGES wireguard-tools kmod-wireguard luci-proto-wireguard"
PACKAGES="$PACKAGES -dnsmasq dnsmasq-full"
PACKAGES="$PACKAGES haproxy bind-server bind-tools"
# Add SecuBox packages if available
if [[ $IPK_COUNT -gt 0 ]]; then
SECUBOX_PKGS="secubox-core secubox-identity secubox-master-link secubox-p2p"
SECUBOX_PKGS="$SECUBOX_PKGS secubox-app secubox-app-bonus luci-theme-secubox"
SECUBOX_PKGS="$SECUBOX_PKGS luci-app-crowdsec-dashboard luci-app-mitmproxy"
SECUBOX_PKGS="$SECUBOX_PKGS luci-app-secubox luci-app-secubox-admin"
SECUBOX_PKGS="$SECUBOX_PKGS luci-app-secubox-portal luci-app-secubox-p2p"
SECUBOX_PKGS="$SECUBOX_PKGS luci-app-haproxy luci-app-wireguard-dashboard"
SECUBOX_PKGS="$SECUBOX_PKGS luci-app-vhost-manager luci-app-network-modes"
SECUBOX_PKGS="$SECUBOX_PKGS luci-app-system-hub luci-app-master-link"
SECUBOX_PKGS="$SECUBOX_PKGS luci-app-metrics-dashboard luci-app-config-vault"
for pkg in $SECUBOX_PKGS; do
if find packages/secubox -name "${pkg}_*.ipk" 2>/dev/null | head -1 | grep -q .; then
PACKAGES="$PACKAGES $pkg"
fi
done
fi
# Root partition size
ROOT_SIZE=$(( DISK_SIZE * 1024 - 64 ))
print_info "Packages: $PACKAGES"
print_info "Root partition: ${ROOT_SIZE}MB"
make image \
PROFILE="generic" \
PACKAGES="$PACKAGES" \
FILES="files" \
ROOTFS_PARTSIZE="$ROOT_SIZE" \
2>&1 | tee build.log
print_success "Firmware built"
# Step 5: Convert to VM formats
print_header "Converting to VM Formats"
# Find the image
IMG_FILE=$(find bin/targets/ -name "*combined*.img.gz" 2>/dev/null | head -1)
if [[ -z "$IMG_FILE" ]]; then
print_error "No firmware image found!"
ls -la bin/targets/
exit 1
fi
print_info "Source: $IMG_FILE"
# Extract (ignore trailing garbage warning)
gunzip -c "$IMG_FILE" > /tmp/openwrt.img 2>/dev/null || {
if [[ ! -s /tmp/openwrt.img ]]; then
print_error "Failed to extract"
exit 1
fi
}
# Expand to target size
TARGET_BYTES=$(( DISK_SIZE * 1024 * 1024 * 1024 ))
truncate -s ${TARGET_BYTES} /tmp/openwrt.img
BASENAME="c3box-vm-${VERSION}-${ARCH}"
# Convert formats
print_info "Creating VMDK..."
qemu-img convert -f raw -O vmdk /tmp/openwrt.img "$OUTPUT_DIR/${BASENAME}.vmdk"
print_info "Creating VDI..."
qemu-img convert -f raw -O vdi /tmp/openwrt.img "$OUTPUT_DIR/${BASENAME}.vdi"
print_info "Creating QCOW2..."
qemu-img convert -f raw -O qcow2 -c /tmp/openwrt.img "$OUTPUT_DIR/${BASENAME}.qcow2"
print_info "Compressing raw..."
gzip -c /tmp/openwrt.img > "$OUTPUT_DIR/${BASENAME}.img.gz"
rm /tmp/openwrt.img
# Checksums
cd "$OUTPUT_DIR"
sha256sum ${BASENAME}.* > "${BASENAME}-SHA256SUMS"
print_header "Build Complete!"
echo ""
ls -lh "$OUTPUT_DIR/${BASENAME}"*
echo ""
print_success "Output: $OUTPUT_DIR"