name: Build C3Box VM Appliance # Builds ready-to-use C3Box VM images (VMDK, VDI, QCOW2) for VMware, VirtualBox, Proxmox on: workflow_dispatch: inputs: version: description: 'Version tag (e.g. v1.0.0-beta)' required: true default: 'v1.0.0-beta' type: string openwrt_version: description: 'OpenWrt version' required: true default: '24.10.5' type: choice options: - '24.10.5' - '24.10.4' - '23.05.5' disk_size: description: 'Virtual disk size (GB)' required: true default: '8' type: choice options: - '4' - '8' - '16' - '32' memory: description: 'Recommended RAM (GB)' required: true default: '2' type: choice options: - '1' - '2' - '4' - '8' push: tags: - 'v*.*.*' - 'v*.*.*-*' env: OPENWRT_VERSION: ${{ github.event.inputs.openwrt_version || '24.10.5' }} DISK_SIZE: ${{ github.event.inputs.disk_size || '8' }} C3BOX_VERSION: ${{ github.event.inputs.version || github.ref_name }} permissions: contents: write jobs: build-vm: runs-on: ubuntu-latest strategy: 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 }} steps: - name: Checkout uses: actions/checkout@v4 - name: Free disk space run: | sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc sudo docker image prune --all --force df -h - name: Install dependencies run: | sudo apt-get update sudo apt-get install -y build-essential libncurses5-dev zlib1g-dev \ gawk git gettext libssl-dev xsltproc rsync wget unzip python3 \ qemu-utils parted dosfstools e2fsprogs - 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/${TARGET}/openwrt-imagebuilder-${VERSION}-${TARGET_SAFE}.Linux-x86_64.tar.zst" echo "📥 Downloading Image Builder for $TARGET..." echo " URL: $IB_URL" 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 } if [[ -f imagebuilder.tar.zst ]]; then tar --zstd -xf imagebuilder.tar.zst mv openwrt-imagebuilder-* imagebuilder fi echo "✅ Image Builder ready for ${{ matrix.name }}" - name: Download prebuilt SecuBox packages run: | echo "📥 Downloading prebuilt SecuBox packages for ${{ matrix.pkg_arch }}..." # 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}-${PKG_ARCH}.tar.gz" mkdir -p imagebuilder/packages/secubox if wget -q "$PKG_URL" -O /tmp/secubox-packages.tar.gz 2>/dev/null; then echo "✅ Downloaded release packages: $PKG_URL" 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/ else echo "⚠️ Release packages not found, will use feed installation" fi # Count packages IPK_COUNT=$(find imagebuilder/packages/secubox/ -name "*.ipk" 2>/dev/null | wc -l) echo "📦 Found $IPK_COUNT prebuilt packages" # Create local repository if packages exist if [[ $IPK_COUNT -gt 0 ]]; then echo "🔧 Creating local package repository..." cd imagebuilder/packages/secubox # Generate Packages index (required for opkg) if command -v gzip &>/dev/null; then # Simple package index 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 fi cd ../../.. echo "✅ Local repository created" fi - name: Create preseed configuration run: | 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 for opkg cat > imagebuilder/files/etc/opkg/customfeeds.conf << 'FEED_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 FEED_EOF # Preseed script for first boot - Network & System cat > imagebuilder/files/etc/uci-defaults/10-c3box-network << 'PRESEED_EOF' #!/bin/sh # C3Box VM Network Configuration - Devel/Beta Test # Set hostname uci set system.@system[0].hostname='c3box' uci set system.@system[0].timezone='UTC' uci set system.@system[0].zonename='UTC' # LAN: br-lan on eth0 - 192.168.200.x subnet for testing uci set network.lan.ipaddr='192.168.200.1' uci set network.lan.netmask='255.255.255.0' uci set network.lan.proto='static' # WAN: br-wan DHCP on eth1 uci set network.wan=interface uci set network.wan.device='eth1' uci set network.wan.proto='dhcp' # Enable DHCP server on LAN uci set dhcp.lan.start='100' uci set dhcp.lan.limit='150' uci set dhcp.lan.leasetime='12h' # Firewall: secure defaults 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' # Enable HTTPS for LuCI uci set uhttpd.main.redirect_https='1' uci commit exit 0 PRESEED_EOF chmod 755 imagebuilder/files/etc/uci-defaults/10-c3box-network # SecuBox Core configuration preseed cat > imagebuilder/files/etc/uci-defaults/20-secubox-config << 'PRESEED_EOF' #!/bin/sh # SecuBox Core Configuration - matching c3box.local # Create secubox config 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.settings.health_threshold_cpu='80' uci set secubox.settings.health_threshold_memory='90' uci set secubox.settings.health_threshold_storage='85' 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.http_enabled='0' uci set secubox.remote.ssh_enabled='1' uci set secubox.remote.ssh_port='22' 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 PRESEED_EOF chmod 755 imagebuilder/files/etc/uci-defaults/20-secubox-config # SecuBox package installation script (runs after network is up) cat > imagebuilder/files/etc/uci-defaults/90-secubox-packages << 'PRESEED_EOF' #!/bin/sh # SecuBox Package Installation # Create installation script for first boot with network mkdir -p /etc/secubox cat > /etc/secubox/install-packages.sh << 'INSTALL_EOF' #!/bin/sh # SecuBox Full Package Suite Installation # Run: /etc/secubox/install-packages.sh LOG="/var/log/secubox-install.log" exec > >(tee -a "$LOG") 2>&1 echo "==========================================" echo "SecuBox Package Installation" echo "Date: $(date)" echo "==========================================" # Wait for network echo "Waiting for network..." for i in $(seq 1 30); do if ping -c1 repo.secubox.org >/dev/null 2>&1; then echo "Network ready" break fi sleep 2 done # Update package lists echo "Updating package lists..." opkg update # Core SecuBox packages CORE_PACKAGES=" secubox-core secubox-identity secubox-master-link secubox-p2p secubox-app secubox-app-bonus luci-theme-secubox " # Security packages SECURITY_PACKAGES=" crowdsec crowdsec-firewall-bouncer secubox-app-crowdsec-custom secubox-app-mitmproxy secubox-app-auth-logger secubox-threat-analyst secubox-dns-guard luci-app-crowdsec-dashboard luci-app-mitmproxy luci-app-secubox-security-threats luci-app-threat-analyst luci-app-dnsguard luci-app-auth-guardian luci-app-exposure luci-app-mac-guardian luci-app-ipblocklist " # Network packages NETWORK_PACKAGES=" haproxy secubox-app-haproxy secubox-vortex-dns secubox-app-dns-provider netifyd secubox-app-ndpid secubox-app-netifyd luci-app-haproxy luci-app-wireguard-dashboard luci-app-vhost-manager luci-app-network-modes luci-app-network-tweaks luci-app-dns-provider luci-app-vortex-dns luci-app-ndpid luci-app-secubox-netifyd luci-app-traffic-shaper luci-app-bandwidth-manager " # Services packages SERVICES_PACKAGES=" secubox-app-jabber secubox-app-matrix secubox-app-jitsi secubox-app-jellyfin secubox-app-gitea secubox-app-nextcloud secubox-app-streamlit secubox-app-ollama secubox-app-localai secubox-app-hexojs secubox-app-metablogizer secubox-app-lyrion secubox-app-magicmirror2 secubox-app-glances luci-app-jabber luci-app-matrix luci-app-jitsi luci-app-jellyfin luci-app-gitea luci-app-nextcloud luci-app-streamlit luci-app-ollama luci-app-localai luci-app-hexojs luci-app-metablogizer luci-app-lyrion luci-app-magicmirror2 luci-app-glances luci-app-picobrew " # Dashboard & Admin packages ADMIN_PACKAGES=" luci-app-secubox luci-app-secubox-admin luci-app-secubox-portal luci-app-secubox-p2p luci-app-secubox-netdiag luci-app-system-hub luci-app-netdata-dashboard luci-app-service-registry luci-app-device-intel luci-app-master-link luci-app-media-flow luci-app-cyberfeed " # AI & Advanced packages AI_PACKAGES=" secubox-mcp-server secubox-app-device-intel luci-app-ai-gateway luci-app-ai-insights luci-app-localrecall " echo "" echo "Installing Core packages..." for pkg in $CORE_PACKAGES; do opkg install "$pkg" 2>/dev/null || echo " Skip: $pkg" done echo "" echo "Installing Security packages..." for pkg in $SECURITY_PACKAGES; do opkg install "$pkg" 2>/dev/null || echo " Skip: $pkg" done echo "" echo "Installing Network packages..." for pkg in $NETWORK_PACKAGES; do opkg install "$pkg" 2>/dev/null || echo " Skip: $pkg" done echo "" echo "Installing Services packages..." for pkg in $SERVICES_PACKAGES; do opkg install "$pkg" 2>/dev/null || echo " Skip: $pkg" done echo "" echo "Installing Admin packages..." for pkg in $ADMIN_PACKAGES; do opkg install "$pkg" 2>/dev/null || echo " Skip: $pkg" done echo "" echo "Installing AI packages..." for pkg in $AI_PACKAGES; do opkg install "$pkg" 2>/dev/null || echo " Skip: $pkg" done # Enable core services echo "" echo "Enabling services..." for svc in secubox-core crowdsec haproxy rpcd uhttpd; do [ -x /etc/init.d/$svc ] && /etc/init.d/$svc enable 2>/dev/null done # Generate identity if available if [ -x /usr/sbin/identityctl ]; then echo "Generating SecuBox identity..." /usr/sbin/identityctl keygen 2>/dev/null || true fi # Mark installation complete touch /etc/secubox/packages-installed echo "" echo "==========================================" echo "SecuBox installation complete!" echo "==========================================" # Restart services /etc/init.d/rpcd restart /etc/init.d/uhttpd restart INSTALL_EOF chmod 755 /etc/secubox/install-packages.sh # Create quick-install info cat > /etc/secubox/README << 'README_EOF' C3Box SecuBox VM Appliance This is a minimal base installation. To install the full SecuBox suite: /etc/secubox/install-packages.sh This will install 100+ SecuBox modules from the official repository. Network Configuration: LAN: 192.168.200.1/24 (br-lan/eth0) WAN: DHCP (br-wan/eth1) Web UI: https://192.168.200.1 README_EOF exit 0 PRESEED_EOF chmod 755 imagebuilder/files/etc/uci-defaults/90-secubox-packages # Filesystem resize script cat > imagebuilder/files/etc/uci-defaults/99-c3box-resize << 'PRESEED_EOF' #!/bin/sh # Expand root filesystem on first boot 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]*$') if command -v parted >/dev/null 2>&1; then parted -s "$DISK_DEV" resizepart "$PART_NUM" 100% 2>/dev/null || true fi if command -v resize2fs >/dev/null 2>&1; then resize2fs "$ROOT_DEV" 2>/dev/null || true fi mkdir -p /etc/c3box touch /etc/c3box/resized fi fi touch /etc/c3box/configured exit 0 PRESEED_EOF chmod 755 imagebuilder/files/etc/uci-defaults/99-c3box-resize # C3Box release info cat > imagebuilder/files/etc/c3box/release << EOF C3BOX_VERSION="${{ env.C3BOX_VERSION }}" C3BOX_BUILD_DATE="$(date -u +%Y-%m-%dT%H:%M:%SZ)" OPENWRT_VERSION="${{ env.OPENWRT_VERSION }}" VM_TYPE="${{ matrix.boot }}" DISK_SIZE="${{ env.DISK_SIZE }}GB" SECUBOX_MODULES="101" EOF # MOTD banner cat > imagebuilder/files/etc/banner << 'BANNER_EOF' ██████╗██████╗ ██████╗ ██████╗ ██╗ ██╗ ██╔════╝╚════██╗██╔══██╗██╔═══██╗╚██╗██╔╝ ██║ █████╔╝██████╔╝██║ ██║ ╚███╔╝ ██║ ╚═══██╗██╔══██╗██║ ██║ ██╔██╗ ╚██████╗██████╔╝██████╔╝╚██████╔╝██╔╝ ██╗ ╚═════╝╚═════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ C3Box - CyberMind Security Appliance SecuBox 101+ Modules | Master Target Mesh Web UI: https://192.168.200.1 Install: /etc/secubox/install-packages.sh Documentation: https://github.com/gkerma/secubox-openwrt/wiki BANNER_EOF echo "✅ Preseed configuration created with SecuBox package installer" - name: Build firmware image run: | cd imagebuilder echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "🔨 Building C3Box VM Image (${{ matrix.boot }})" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" # Add local SecuBox repository to Image Builder if [[ -d packages/secubox ]] && [[ $(find packages/secubox -name "*.ipk" | wc -l) -gt 0 ]]; then echo "📦 Adding local SecuBox package repository..." echo "src secubox file://$(pwd)/packages/secubox" >> repositories.conf cat repositories.conf fi # Base OpenWrt 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 docker dockerd containerd" PACKAGES="$PACKAGES wireguard-tools kmod-wireguard luci-proto-wireguard" # Remove conflicting dnsmasq PACKAGES="$PACKAGES -dnsmasq dnsmasq-full" # Network and security packages PACKAGES="$PACKAGES haproxy bind-server bind-tools" PACKAGES="$PACKAGES kmod-nf-conntrack kmod-nf-nat kmod-ipt-nat" # 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) if [[ $IPK_COUNT -gt 0 ]]; then echo "📦 Including $IPK_COUNT prebuilt SecuBox packages" # Core SecuBox packages SECUBOX_PKGS="secubox-core secubox-identity secubox-master-link secubox-p2p" SECUBOX_PKGS="$SECUBOX_PKGS secubox-app secubox-app-bonus luci-theme-secubox" # Security SECUBOX_PKGS="$SECUBOX_PKGS crowdsec crowdsec-firewall-bouncer" SECUBOX_PKGS="$SECUBOX_PKGS secubox-app-crowdsec-custom secubox-app-mitmproxy" SECUBOX_PKGS="$SECUBOX_PKGS secubox-threat-analyst secubox-dns-guard" SECUBOX_PKGS="$SECUBOX_PKGS luci-app-crowdsec-dashboard luci-app-mitmproxy" SECUBOX_PKGS="$SECUBOX_PKGS luci-app-secubox-security-threats luci-app-threat-analyst" SECUBOX_PKGS="$SECUBOX_PKGS luci-app-auth-guardian luci-app-exposure" # Network SECUBOX_PKGS="$SECUBOX_PKGS secubox-app-haproxy secubox-vortex-dns secubox-app-dns-provider" SECUBOX_PKGS="$SECUBOX_PKGS netifyd secubox-app-ndpid secubox-app-netifyd" 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-vortex-dns luci-app-ndpid luci-app-secubox-netifyd" # Services SECUBOX_PKGS="$SECUBOX_PKGS secubox-app-streamlit secubox-app-hexojs" SECUBOX_PKGS="$SECUBOX_PKGS secubox-app-glances secubox-app-metablogizer" SECUBOX_PKGS="$SECUBOX_PKGS luci-app-streamlit luci-app-hexojs" SECUBOX_PKGS="$SECUBOX_PKGS luci-app-glances luci-app-metablogizer" # Dashboard & Admin 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-system-hub luci-app-netdata-dashboard" SECUBOX_PKGS="$SECUBOX_PKGS luci-app-service-registry luci-app-device-intel" SECUBOX_PKGS="$SECUBOX_PKGS luci-app-master-link luci-app-cyberfeed" SECUBOX_PKGS="$SECUBOX_PKGS luci-app-metrics-dashboard luci-app-config-vault" # Add SecuBox packages to build list for pkg in $SECUBOX_PKGS; do if find packages/secubox -name "${pkg}_*.ipk" | head -1 | grep -q .; then PACKAGES="$PACKAGES $pkg" fi done fi # Calculate root partition size (disk size minus 64MB for boot) ROOT_SIZE=$(( ${{ env.DISK_SIZE }} * 1024 - 64 )) echo "📦 Packages: $PACKAGES" echo "💾 Root partition: ${ROOT_SIZE}MB" echo "" # 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" \ PACKAGES="$PACKAGES" \ FILES="files" \ ROOTFS_PARTSIZE="$ROOT_SIZE" \ 2>&1 | tee build.log echo "" echo "📦 Generated images:" ls -lh bin/targets/x86/64/ - name: Convert to VM formats run: | mkdir -p artifacts TARGET="${{ matrix.target }}" TARGET_DIR="imagebuilder/bin/targets/${TARGET}" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "🔄 Converting to VM formats (${{ matrix.name }})" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" # 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 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!" echo "Available files in $TARGET_DIR:" ls -la "$TARGET_DIR/" 2>/dev/null || find imagebuilder/bin -type f -name "*.img*" exit 1 fi echo "📦 Source image: $IMG_FILE" # Extract (ignore "trailing garbage" warning - normal for firmware images) # gunzip returns exit code 2 for warnings, which we can safely ignore gunzip -c "$IMG_FILE" > /tmp/openwrt.img 2>/dev/null || { # Check if extraction actually produced output if [[ ! -s /tmp/openwrt.img ]]; then echo "❌ Failed to extract image" exit 1 fi echo " (gunzip warning ignored - normal for firmware images)" } IMG_SIZE=$(stat -c%s /tmp/openwrt.img) echo " Size: $(numfmt --to=iec $IMG_SIZE)" # Expand to target disk size TARGET_BYTES=$(( ${{ env.DISK_SIZE }} * 1024 * 1024 * 1024 )) if [[ $IMG_SIZE -lt $TARGET_BYTES ]]; then echo "📏 Expanding to ${{ env.DISK_SIZE }}GB..." truncate -s ${TARGET_BYTES} /tmp/openwrt.img fi # Base filename - use version input or tag name VERSION="${{ env.C3BOX_VERSION }}" BASENAME="c3box-vm-${VERSION}-${{ matrix.name }}" # Convert to VMDK (VMware) echo "🔄 Creating VMDK (VMware)..." qemu-img convert -f raw -O vmdk /tmp/openwrt.img "artifacts/${BASENAME}.vmdk" echo " ✅ ${BASENAME}.vmdk ($(du -h "artifacts/${BASENAME}.vmdk" | cut -f1))" # Convert to VDI (VirtualBox) echo "🔄 Creating VDI (VirtualBox)..." qemu-img convert -f raw -O vdi /tmp/openwrt.img "artifacts/${BASENAME}.vdi" echo " ✅ ${BASENAME}.vdi ($(du -h "artifacts/${BASENAME}.vdi" | cut -f1))" # Convert to QCOW2 (Proxmox/KVM) echo "🔄 Creating QCOW2 (Proxmox/KVM)..." qemu-img convert -f raw -O qcow2 -c /tmp/openwrt.img "artifacts/${BASENAME}.qcow2" echo " ✅ ${BASENAME}.qcow2 ($(du -h "artifacts/${BASENAME}.qcow2" | cut -f1))" # Keep raw image compressed echo "🔄 Compressing raw image..." gzip -c /tmp/openwrt.img > "artifacts/${BASENAME}.img.gz" echo " ✅ ${BASENAME}.img.gz ($(du -h "artifacts/${BASENAME}.img.gz" | cut -f1))" rm /tmp/openwrt.img echo "" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo "✅ VM images created successfully" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" - name: Create documentation run: | VERSION="${{ env.C3BOX_VERSION }}" BASENAME="c3box-vm-${VERSION}-${{ matrix.name }}" cat > artifacts/README.md << EOF # C3Box VM Appliance - ${{ matrix.description }} **Full SecuBox Suite Pre-installed** - 101+ Security & Privacy Modules Pre-configured OpenWrt ${{ env.OPENWRT_VERSION }} virtual machine - CyberMind Security Appliance with complete SecuBox package suite matching production c3box.local. ## VM Images | Format | File | Platform | |--------|------|----------| | VMDK | \`${BASENAME}.vmdk\` | VMware Workstation/ESXi | | VDI | \`${BASENAME}.vdi\` | VirtualBox | | QCOW2 | \`${BASENAME}.qcow2\` | Proxmox/KVM/QEMU | | Raw | \`${BASENAME}.img.gz\` | Any hypervisor | ## Quick Start ### VMware 1. Create new VM → Other Linux 64-bit 2. Use existing disk → Select \`.vmdk\` file 3. RAM: 2GB minimum (4GB recommended) 4. Network: 2 adapters (LAN: bridged, WAN: NAT) ### VirtualBox 1. Create new VM → Linux → Other Linux 64-bit 2. Use existing disk → Select \`.vdi\` file 3. RAM: 2GB minimum (4GB recommended) 4. Network: Adapter 1 (bridged), Adapter 2 (NAT) ### Proxmox \`\`\`bash # Upload QCOW2 to Proxmox qm create 100 --name c3box --memory 2048 --cores 2 \\ --net0 virtio,bridge=vmbr0 --net1 virtio,bridge=vmbr1 qm importdisk 100 ${BASENAME}.qcow2 local-lvm qm set 100 --scsi0 local-lvm:vm-100-disk-0 qm set 100 --boot order=scsi0 qm start 100 \`\`\` ## Default Configuration | Setting | Value | |---------|-------| | LAN IP | 192.168.200.1 | | WAN | DHCP (eth1) | | Username | root | | Password | (none - set on first login) | | Web UI | https://192.168.200.1 | | SSH | Enabled | ## Network Interfaces - **eth0 (br-lan)**: 192.168.200.1/24, DHCP server (100-250) - **eth1 (br-wan)**: DHCP client for internet access ## Included SecuBox Modules ### Security (16 modules) - CrowdSec Dashboard - Threat intelligence - Mitmproxy WAF - HTTPS inspection - Auth Guardian - OAuth2/OIDC - Threat Analyst - AI-powered analysis - DNS Guard - DNS anomaly detection - MAC Guardian - WiFi spoofing detection ### Network (15 modules) - HAProxy - Load balancer with SSL/ACME - WireGuard Dashboard - VPN management - Vortex DNS - Mesh DNS resolution - Network Modes - Sniffer/AP/Relay - Traffic Shaper - QoS/CAKE ### Services (20+ modules) - Matrix/Jabber/Jitsi - Communication - Jellyfin/Lyrion - Media - Gitea/Hexo - Content platforms - LocalAI/Ollama - AI inference ### Mesh Features - Master Link - Node onboarding - P2P Hub - Peer discovery - Service Registry - Catalog sync - Vortex Firewall - Mesh security ## Post-Install (if minimal image) If SecuBox packages weren't included in the image: \`\`\`bash /etc/secubox/install-packages.sh \`\`\` ## Disk Resize The root filesystem will automatically expand on first boot. For manual expansion: \`\`\`bash parted /dev/sda resizepart 2 100% resize2fs /dev/sda2 \`\`\` ## Build Information - OpenWrt: ${{ env.OPENWRT_VERSION }} - SecuBox: ${{ env.C3BOX_VERSION }} - Boot: ${{ matrix.boot }} - Disk: ${{ env.DISK_SIZE }}GB - Modules: 101+ - Built: $(date -u +%Y-%m-%dT%H:%M:%SZ) EOF # Create checksums cd artifacts sha256sum *.vmdk *.vdi *.qcow2 *.img.gz > SHA256SUMS echo "📋 Artifacts ready:" ls -lh - name: Upload artifacts uses: actions/upload-artifact@v4 with: name: c3box-vm-${{ env.C3BOX_VERSION }}-${{ matrix.name }} path: artifacts/ retention-days: 30 - name: Generate summary run: | echo "# 🖥️ VM Appliance: ${{ matrix.description }}" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "| Format | Size |" >> $GITHUB_STEP_SUMMARY echo "|--------|------|" >> $GITHUB_STEP_SUMMARY for f in artifacts/*.vmdk artifacts/*.vdi artifacts/*.qcow2 artifacts/*.img.gz; do if [[ -f "$f" ]]; then echo "| $(basename "$f") | $(du -h "$f" | cut -f1) |" >> $GITHUB_STEP_SUMMARY fi done echo "" >> $GITHUB_STEP_SUMMARY echo "**Disk size:** ${{ env.DISK_SIZE }}GB" >> $GITHUB_STEP_SUMMARY echo "**Boot type:** ${{ matrix.boot }}" >> $GITHUB_STEP_SUMMARY # ============================================ # Create release # ============================================ release: needs: build-vm runs-on: ubuntu-latest if: startsWith(github.ref, 'refs/tags/v') steps: - name: Download all artifacts uses: actions/download-artifact@v4 with: path: vms pattern: c3box-vm-* - name: Organize release run: | mkdir -p release for dir in vms/c3box-vm-*/; do cp "$dir"/*.vmdk "$dir"/*.vdi "$dir"/*.qcow2 "$dir"/*.img.gz release/ 2>/dev/null || true cp "$dir"/README.md release/VM-README.md 2>/dev/null || true done cd release sha256sum *.vmdk *.vdi *.qcow2 *.img.gz > SHA256SUMS 2>/dev/null || true cat > RELEASE_NOTES.md << 'EOF' # C3Box VM Appliance Ready-to-use virtual machine images - CyberMind Security Appliance. ## Downloads Choose the format for your hypervisor: - **VMDK** - VMware Workstation, ESXi, Fusion - **VDI** - VirtualBox - **QCOW2** - Proxmox, KVM, QEMU ## Quick Start 1. Download the appropriate image for your hypervisor 2. Import/create VM with the disk image 3. Boot and access https://192.168.200.1 4. Login as `root` (no password initially) 5. Set a password and start configuring ## System Requirements - 1GB RAM minimum (2GB recommended) - 1 vCPU minimum - Network adapter (bridged or NAT) EOF - name: Create release uses: softprops/action-gh-release@v2 with: name: "C3Box VM Appliance ${{ github.ref_name }}" tag_name: ${{ github.ref_name }} body_path: release/RELEASE_NOTES.md files: | release/*.vmdk release/*.vdi release/*.qcow2 release/*.img.gz release/SHA256SUMS draft: false prerelease: ${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') || contains(github.ref_name, 'rc') }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}