secubox-openwrt/.github/workflows/build-vm-appliance.yml
CyberMind-FR 276685f109 feat(repo): Add package repository at repo.secubox.in
- Fix preseed URLs from non-existent repo.secubox.org to repo.secubox.in
- Make feed URLs architecture-aware (x86_64, aarch64_cortex-a72, etc.)
- Add publish-package-repo.yml workflow for GitHub Pages deployment
- Workflow downloads release artifacts, generates opkg Packages index
- Supports all SecuBox architectures with proper opkg feed structure

Package repository structure:
- https://repo.secubox.in/packages/{arch}/ - Core SecuBox packages
- https://repo.secubox.in/luci/{arch}/ - LuCI apps
- https://repo.secubox.in/catalog/ - Repository metadata

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-18 09:10:01 +01:00

1058 lines
38 KiB
YAML

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
# Note: aarch64-generic (armsr/armv8) disabled - package repo issues
# - 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 - architecture-aware
PKG_ARCH="${{ matrix.pkg_arch }}"
# Normalize architecture string for opkg
case "$PKG_ARCH" in
x86-64) OPKG_ARCH="x86_64" ;;
aarch64-cortex-a72) OPKG_ARCH="aarch64_cortex-a72" ;;
rockchip-armv8) OPKG_ARCH="aarch64_generic" ;;
*) OPKG_ARCH="$PKG_ARCH" ;;
esac
cat > imagebuilder/files/etc/opkg/customfeeds.conf << FEED_EOF
# SecuBox Official Package Feed
src/gz secubox_packages https://repo.secubox.in/packages/${OPKG_ARCH}
src/gz secubox_luci https://repo.secubox.in/luci/${OPKG_ARCH}
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.in/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.in >/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 (common to all architectures)
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"
PACKAGES="$PACKAGES git rsync screen tmux bash jq"
PACKAGES="$PACKAGES wireguard-tools kmod-wireguard luci-proto-wireguard"
# Remove conflicting dnsmasq
PACKAGES="$PACKAGES -dnsmasq dnsmasq-full"
# Network packages (available on all platforms)
PACKAGES="$PACKAGES haproxy"
# Architecture-specific packages
case "${{ matrix.target }}" in
x86/64)
# x86-64 has the most packages available
PACKAGES="$PACKAGES parted e2fsprogs resize2fs"
PACKAGES="$PACKAGES kmod-fs-btrfs"
PACKAGES="$PACKAGES docker dockerd containerd"
PACKAGES="$PACKAGES bind-server bind-tools"
PACKAGES="$PACKAGES kmod-nf-conntrack kmod-nf-nat kmod-ipt-nat"
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"
PACKAGES="$PACKAGES parted e2fsprogs"
;;
bcm27xx/bcm2711)
# Raspberry Pi 4 specific
PACKAGES="$PACKAGES kmod-usb-net-asix-ax88179 kmod-usb-net-rtl8152"
PACKAGES="$PACKAGES parted e2fsprogs"
;;
rockchip/armv8)
# Rockchip ARM64
PACKAGES="$PACKAGES kmod-usb-net-rtl8152"
PACKAGES="$PACKAGES parted e2fsprogs"
;;
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)
# NanoPi R4S as default for rockchip
PROFILE="friendlyarm_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/${{ matrix.target }}/ || ls -lh bin/targets/
- 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 }}