diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 9eff4519..3150357a 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -575,7 +575,12 @@ "Bash(sudo -S rm:*)", "Bash(sudo -S chmod:*)", "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 \"\")" ] } } diff --git a/.github/workflows/build-vm-appliance.yml b/.github/workflows/build-vm-appliance.yml index c04ebef2..013fbd6a 100644 --- a/.github/workflows/build-vm-appliance.yml +++ b/.github/workflows/build-vm-appliance.yml @@ -60,12 +60,33 @@ jobs: fail-fast: false matrix: include: + # x86-64 targets - name: x86-64-efi + target: x86/64 boot: efi + pkg_arch: x86-64 description: "x86/64 EFI (Modern UEFI systems)" - name: x86-64-bios + target: x86/64 boot: bios + pkg_arch: x86-64 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 }} @@ -89,12 +110,17 @@ jobs: - name: Download Image Builder run: | 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 || { IB_URL="${IB_URL%.zst}.xz" + echo " Trying .xz: $IB_URL" wget -q "$IB_URL" -O imagebuilder.tar.xz tar -xf imagebuilder.tar.xz mv openwrt-imagebuilder-* imagebuilder @@ -105,17 +131,18 @@ jobs: mv openwrt-imagebuilder-* imagebuilder fi - echo "✅ Image Builder ready" + echo "✅ Image Builder ready for ${{ matrix.name }}" - name: Download prebuilt SecuBox packages 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 }}" + PKG_ARCH="${{ matrix.pkg_arch }}" # 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 @@ -578,7 +605,6 @@ jobs: 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 qemu-ga" # QEMU guest agent for Proxmox PACKAGES="$PACKAGES git rsync screen tmux bash jq" PACKAGES="$PACKAGES docker dockerd containerd" PACKAGES="$PACKAGES wireguard-tools kmod-wireguard luci-proto-wireguard" @@ -590,10 +616,27 @@ jobs: PACKAGES="$PACKAGES haproxy bind-server bind-tools" PACKAGES="$PACKAGES kmod-nf-conntrack kmod-nf-nat kmod-ipt-nat" - # EFI-specific packages - if [[ "${{ matrix.boot }}" == "efi" ]]; then - PACKAGES="$PACKAGES grub2-efi" - fi + # Architecture-specific packages + case "${{ matrix.target }}" in + x86/64) + 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) IPK_COUNT=$(find packages/secubox -name "*.ipk" 2>/dev/null | wc -l) @@ -648,8 +691,27 @@ jobs: echo "💾 Root partition: ${ROOT_SIZE}MB" echo "" - # Build with combined-efi or ext4-combined based on boot type - PROFILE="generic" + # Select profile based on target + 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 \ PROFILE="$PROFILE" \ @@ -666,30 +728,44 @@ jobs: run: | mkdir -p artifacts - TARGET_DIR="imagebuilder/bin/targets/x86/64" + TARGET="${{ matrix.target }}" + TARGET_DIR="imagebuilder/bin/targets/${TARGET}" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - echo "🔄 Converting to VM formats" + echo "🔄 Converting to VM formats (${{ matrix.name }})" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - # Find the correct image based on boot type - if [[ "${{ matrix.boot }}" == "efi" ]]; then - IMG_PATTERN="*-combined-efi.img.gz" - else - IMG_PATTERN="*-combined-ext4.img.gz" - fi + # Find the correct image based on boot type and architecture + case "${{ matrix.boot }}" in + efi) + IMG_PATTERN="*-combined-efi.img.gz" + ;; + 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 IMG_FILE=$(find "$TARGET_DIR" -name "$IMG_PATTERN" 2>/dev/null | head -1) 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) 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 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 fi diff --git a/secubox-tools/c3box-vm-full-build.sh b/secubox-tools/c3box-vm-full-build.sh new file mode 100755 index 00000000..4e60cc66 --- /dev/null +++ b/secubox-tools/c3box-vm-full-build.sh @@ -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"