- Remove secubox-app-crowdsec (conflicts with feeds/packages/crowdsec) - Remove secubox-app-netifyd (conflicts with feeds/packages/netifyd) - Fix Makefile dependencies: crowdsec-firewall-bouncer, syslog-ng - Fix luci-app-secubox-portal Makefile (correct luci.mk path) - Fix luci-app-secubox-security-threats (add BuildPackage) - Disable sheeva64 device in GitHub Actions and local-build.sh - Update documentation with correct package names Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1032 lines
45 KiB
YAML
1032 lines
45 KiB
YAML
name: Build SecuBox Images (GlobalScale)
|
|
|
|
on:
|
|
# Manual trigger
|
|
workflow_dispatch:
|
|
inputs:
|
|
device:
|
|
description: 'Target device'
|
|
required: true
|
|
type: choice
|
|
options:
|
|
- espressobin-v7
|
|
- espressobin-ultra
|
|
- mochabin
|
|
- all
|
|
openwrt_version:
|
|
description: 'OpenWrt version'
|
|
required: true
|
|
default: '24.10.5'
|
|
type: choice
|
|
options:
|
|
- '24.10.5'
|
|
- '25.12.0-rc1'
|
|
- '23.05.5'
|
|
- '23.05.4'
|
|
- 'SNAPSHOT'
|
|
include_secubox:
|
|
description: 'Include SecuBox packages'
|
|
required: true
|
|
type: boolean
|
|
default: true
|
|
|
|
# Automatic trigger on version tags
|
|
push:
|
|
tags:
|
|
- 'v*.*.*'
|
|
- 'v*.*.*-*'
|
|
|
|
env:
|
|
# Use input if manual trigger, otherwise default to 24.10.5 for tag triggers
|
|
OPENWRT_VERSION: ${{ github.event.inputs.openwrt_version || '24.10.5' }}
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
jobs:
|
|
# ============================================
|
|
# Generate build matrix based on input
|
|
# ============================================
|
|
setup:
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
|
steps:
|
|
- name: Set build matrix
|
|
id: set-matrix
|
|
run: |
|
|
# If triggered by tag, build all devices; otherwise use input
|
|
DEVICE="${{ github.event.inputs.device || 'all' }}"
|
|
|
|
echo "🎯 Building for device: $DEVICE"
|
|
|
|
# Define all devices in a file to avoid heredoc issues
|
|
cat > /tmp/devices.json << 'DEVICES_EOF'
|
|
[
|
|
{
|
|
"device": "espressobin-v7",
|
|
"target": "mvebu",
|
|
"subtarget": "cortexa53",
|
|
"profile": "globalscale_espressobin",
|
|
"description": "ESPRESSObin V7 (1-2GB DDR4)"
|
|
},
|
|
{
|
|
"device": "espressobin-ultra",
|
|
"target": "mvebu",
|
|
"subtarget": "cortexa53",
|
|
"profile": "globalscale_espressobin-ultra",
|
|
"description": "ESPRESSObin Ultra (PoE, WiFi)"
|
|
},
|
|
{
|
|
"device": "mochabin",
|
|
"target": "mvebu",
|
|
"subtarget": "cortexa72",
|
|
"profile": "globalscale_mochabin",
|
|
"description": "MOCHAbin (Quad-core A72, 10G)"
|
|
}
|
|
]
|
|
DEVICES_EOF
|
|
|
|
# Filter based on input
|
|
if [[ "$DEVICE" == "all" ]]; then
|
|
MATRIX=$(jq -c '{"include": .}' /tmp/devices.json)
|
|
else
|
|
MATRIX=$(jq -c --arg dev "$DEVICE" '{"include": [.[] | select(.device == $dev)]}' /tmp/devices.json)
|
|
fi
|
|
|
|
# Use delimiter for multiline output
|
|
echo "matrix<<EOF" >> $GITHUB_OUTPUT
|
|
echo "$MATRIX" >> $GITHUB_OUTPUT
|
|
echo "EOF" >> $GITHUB_OUTPUT
|
|
|
|
echo "📋 Build matrix:"
|
|
echo "$MATRIX" | jq '.'
|
|
|
|
# ============================================
|
|
# Build firmware images for GlobalScale devices
|
|
# ============================================
|
|
build-image:
|
|
needs: setup
|
|
runs-on: ubuntu-latest
|
|
strategy:
|
|
fail-fast: false
|
|
matrix: ${{ fromJson(needs.setup.outputs.matrix) }}
|
|
|
|
name: ${{ matrix.description }}
|
|
|
|
steps:
|
|
- name: Checkout SecuBox packages
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Free disk space
|
|
run: |
|
|
echo "🧹 Cleaning up disk space..."
|
|
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 clang flex bison g++ gawk \
|
|
gcc-multilib g++-multilib gettext git libncurses5-dev \
|
|
libssl-dev python3-setuptools python3-dev rsync \
|
|
swig unzip zlib1g-dev file wget curl qemu-utils ninja-build
|
|
|
|
- name: Clone OpenWrt
|
|
run: |
|
|
if [[ "${{ env.OPENWRT_VERSION }}" == "SNAPSHOT" ]]; then
|
|
git clone --depth 1 https://github.com/openwrt/openwrt.git openwrt
|
|
else
|
|
git clone --depth 1 --branch v${{ env.OPENWRT_VERSION }} \
|
|
https://github.com/openwrt/openwrt.git openwrt
|
|
fi
|
|
|
|
- name: Update feeds
|
|
run: |
|
|
cd openwrt
|
|
|
|
# Remove unwanted feeds from feeds.conf.default BEFORE updating feeds
|
|
if [[ -f "feeds.conf.default" ]]; then
|
|
sed -i '/telephony/d' feeds.conf.default
|
|
sed -i '/routing/d' feeds.conf.default
|
|
echo "✅ Removed telephony and routing from feeds.conf.default"
|
|
fi
|
|
|
|
echo "🔄 Updating feeds..."
|
|
if ! ./scripts/feeds update -a 2>&1 | tee feed-update.log; then
|
|
echo "⚠️ Feed update had errors:"
|
|
tail -30 feed-update.log
|
|
echo "Continuing anyway..."
|
|
fi
|
|
|
|
echo "📦 Installing feeds..."
|
|
if ! ./scripts/feeds install -a 2>&1 | tee feed-install.log; then
|
|
echo "⚠️ Feed install had warnings, checking directories..."
|
|
fi
|
|
|
|
# Verify feeds were created
|
|
echo "🔍 Verifying feeds..."
|
|
for feed in packages luci; do
|
|
if [[ -d "feeds/$feed" ]]; then
|
|
FEED_SIZE=$(du -sh "feeds/$feed" 2>/dev/null | cut -f1 || echo "?")
|
|
echo " ✅ feeds/$feed ($FEED_SIZE)"
|
|
else
|
|
echo " ❌ feeds/$feed missing!"
|
|
ls -la feeds/ || echo "feeds directory doesn't exist"
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
- name: Copy SecuBox packages
|
|
if: ${{ github.event.inputs.include_secubox == 'true' || github.event_name == 'push' }}
|
|
run: |
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "📦 COPYING SECUBOX PACKAGES"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo ""
|
|
|
|
mkdir -p openwrt/package/secubox
|
|
|
|
PKG_COUNT=0
|
|
|
|
# Copy luci-app-* packages
|
|
for pkg in luci-app-*/; do
|
|
if [[ -d "$pkg" ]]; then
|
|
PKG_NAME=$(basename "$pkg")
|
|
echo " ✅ $PKG_NAME"
|
|
cp -r "$pkg" openwrt/package/secubox/
|
|
|
|
# Fix Makefile include path for direct package integration
|
|
# Change from ../../luci.mk to $(TOPDIR)/feeds/luci/luci.mk
|
|
if [[ -f "openwrt/package/secubox/$PKG_NAME/Makefile" ]]; then
|
|
sed -i 's|include.*luci\.mk|include $(TOPDIR)/feeds/luci/luci.mk|' "openwrt/package/secubox/$PKG_NAME/Makefile"
|
|
echo " ✓ Fixed Makefile include path"
|
|
fi
|
|
|
|
PKG_COUNT=$((PKG_COUNT + 1))
|
|
fi
|
|
done
|
|
|
|
# Copy luci-theme-secubox
|
|
if [[ -d "luci-theme-secubox" ]]; then
|
|
echo " ✅ luci-theme-secubox"
|
|
cp -r luci-theme-secubox openwrt/package/secubox/
|
|
if [[ -f "openwrt/package/secubox/luci-theme-secubox/Makefile" ]]; then
|
|
sed -i 's|include.*luci\.mk|include $(TOPDIR)/feeds/luci/luci.mk|' "openwrt/package/secubox/luci-theme-secubox/Makefile"
|
|
echo " ✓ Fixed Makefile include path"
|
|
fi
|
|
PKG_COUNT=$((PKG_COUNT + 1))
|
|
fi
|
|
|
|
# Copy package/secubox/secubox-app
|
|
if [[ -d "package/secubox/secubox-app" ]]; then
|
|
echo " ✅ secubox-app"
|
|
cp -r package/secubox/secubox-app openwrt/package/secubox/
|
|
PKG_COUNT=$((PKG_COUNT + 1))
|
|
fi
|
|
|
|
echo ""
|
|
echo "📊 Total: $PKG_COUNT SecuBox packages copied and fixed"
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
|
|
- name: Generate SecuBox config
|
|
run: |
|
|
cd openwrt
|
|
|
|
# Base configuration
|
|
cat > .config << EOF
|
|
# Target
|
|
CONFIG_TARGET_${{ matrix.target }}=y
|
|
CONFIG_TARGET_${{ matrix.target }}_${{ matrix.subtarget }}=y
|
|
CONFIG_TARGET_${{ matrix.target }}_${{ matrix.subtarget }}_DEVICE_${{ matrix.profile }}=y
|
|
|
|
# Image building (REQUIRED for firmware generation)
|
|
CONFIG_TARGET_MULTI_PROFILE=n
|
|
CONFIG_TARGET_ALL_PROFILES=n
|
|
CONFIG_TARGET_PER_DEVICE_ROOTFS=y
|
|
|
|
# Image settings
|
|
CONFIG_TARGET_ROOTFS_SQUASHFS=y
|
|
CONFIG_TARGET_ROOTFS_EXT4FS=y
|
|
CONFIG_TARGET_KERNEL_PARTSIZE=32
|
|
CONFIG_TARGET_ROOTFS_PARTSIZE=512
|
|
|
|
# Disable GDB in toolchain (fixes build issues)
|
|
# CONFIG_GDB is not set
|
|
CONFIG_BUILD_LOG=y
|
|
|
|
# Base packages
|
|
CONFIG_PACKAGE_luci=y
|
|
CONFIG_PACKAGE_luci-ssl=y
|
|
CONFIG_PACKAGE_luci-app-opkg=y
|
|
CONFIG_PACKAGE_luci-theme-openwrt-2020=y
|
|
CONFIG_PACKAGE_luci-theme-secubox=y
|
|
|
|
# DNS Server (fix conflict: use dnsmasq-full only)
|
|
# CONFIG_PACKAGE_dnsmasq is not set
|
|
CONFIG_PACKAGE_dnsmasq-full=y
|
|
|
|
# Networking essentials
|
|
CONFIG_PACKAGE_curl=y
|
|
CONFIG_PACKAGE_wget-ssl=y
|
|
CONFIG_PACKAGE_iptables=y
|
|
CONFIG_PACKAGE_ip6tables=y
|
|
CONFIG_PACKAGE_kmod-nft-core=y
|
|
|
|
# USB support
|
|
CONFIG_PACKAGE_kmod-usb-core=y
|
|
CONFIG_PACKAGE_kmod-usb3=y
|
|
CONFIG_PACKAGE_kmod-usb-storage=y
|
|
|
|
# Filesystem
|
|
CONFIG_PACKAGE_kmod-fs-ext4=y
|
|
CONFIG_PACKAGE_kmod-fs-vfat=y
|
|
CONFIG_PACKAGE_block-mount=y
|
|
|
|
# Wireless (if applicable)
|
|
CONFIG_PACKAGE_hostapd-common=y
|
|
CONFIG_PACKAGE_wpad-basic-mbedtls=y
|
|
|
|
# Monitoring tools
|
|
CONFIG_PACKAGE_htop=y
|
|
CONFIG_PACKAGE_iftop=y
|
|
CONFIG_PACKAGE_tcpdump=y
|
|
|
|
# SSH
|
|
CONFIG_PACKAGE_openssh-sftp-server=y
|
|
EOF
|
|
|
|
- name: Add SecuBox packages to config
|
|
if: ${{ github.event.inputs.include_secubox == 'true' || github.event_name == 'push' }}
|
|
run: |
|
|
cd openwrt
|
|
|
|
cat >> .config << 'EOF'
|
|
# SecuBox packages - Core
|
|
CONFIG_PACKAGE_secubox-app=y
|
|
CONFIG_PACKAGE_luci-app-secubox=y
|
|
CONFIG_PACKAGE_luci-app-system-hub=y
|
|
|
|
# SecuBox packages - Security & Monitoring
|
|
# CONFIG_PACKAGE_luci-app-crowdsec-dashboard is not set (requires crowdsec backend - compile fails)
|
|
CONFIG_PACKAGE_luci-app-netdata-dashboard=y
|
|
|
|
# SecuBox packages - Network Intelligence
|
|
CONFIG_PACKAGE_luci-app-netifyd-dashboard=y
|
|
CONFIG_PACKAGE_luci-app-network-modes=y
|
|
|
|
# SecuBox packages - VPN & Access Control
|
|
CONFIG_PACKAGE_wireguard-tools=y
|
|
CONFIG_PACKAGE_kmod-wireguard=y
|
|
CONFIG_PACKAGE_luci-app-wireguard-dashboard=y
|
|
CONFIG_PACKAGE_qrencode=y
|
|
CONFIG_PACKAGE_luci-app-client-guardian=y
|
|
# CONFIG_PACKAGE_luci-app-auth-guardian is not set (not stable yet)
|
|
|
|
# SecuBox packages - Bandwidth & Traffic
|
|
CONFIG_PACKAGE_luci-app-bandwidth-manager=y
|
|
CONFIG_PACKAGE_luci-app-media-flow=y
|
|
|
|
# SecuBox packages - Performance & Services
|
|
CONFIG_PACKAGE_luci-app-cdn-cache=y
|
|
CONFIG_PACKAGE_luci-app-vhost-manager=y
|
|
|
|
# SecuBox packages - Disabled (require compilation/not ready)
|
|
# CONFIG_PACKAGE_secubox-app-crowdsec is not set (requires Go 1.23+ - fails in firmware build)
|
|
# CONFIG_PACKAGE_luci-app-ksm-manager is not set (not stable)
|
|
# CONFIG_PACKAGE_luci-app-traffic-shaper is not set (not stable)
|
|
EOF
|
|
|
|
- name: Add device-specific packages
|
|
run: |
|
|
cd openwrt
|
|
|
|
case "${{ matrix.device }}" in
|
|
mochabin)
|
|
# 10G networking, more RAM
|
|
cat >> .config << EOF
|
|
CONFIG_PACKAGE_kmod-sfp=y
|
|
CONFIG_PACKAGE_kmod-phy-marvell-10g=y
|
|
CONFIG_PACKAGE_prometheus-node-exporter-lua=y
|
|
EOF
|
|
;;
|
|
|
|
espressobin-ultra)
|
|
# WiFi support
|
|
cat >> .config << EOF
|
|
CONFIG_PACKAGE_kmod-mt76=y
|
|
CONFIG_PACKAGE_kmod-mac80211=y
|
|
EOF
|
|
;;
|
|
esac
|
|
|
|
- name: Make defconfig
|
|
run: |
|
|
cd openwrt
|
|
|
|
# Final cleanup of unwanted feeds (if somehow they still got created)
|
|
rm -f feeds/telephony.index feeds/routing.index 2>/dev/null || true
|
|
rm -rf feeds/telephony feeds/routing 2>/dev/null || true
|
|
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "⚙️ Running make defconfig"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
|
|
make defconfig
|
|
|
|
- name: Verify device profile configuration
|
|
run: |
|
|
cd openwrt
|
|
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "🔍 Verifying Device Profile Configuration"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo ""
|
|
echo "Target device: ${{ matrix.description }}"
|
|
echo "Profile: ${{ matrix.profile }}"
|
|
echo ""
|
|
|
|
# Check if device profile is properly set
|
|
if grep -q "CONFIG_TARGET_${{ matrix.target }}_${{ matrix.subtarget }}_DEVICE_${{ matrix.profile }}=y" .config; then
|
|
echo "✅ Device profile correctly configured"
|
|
else
|
|
echo "❌ ERROR: Device profile not found in .config!"
|
|
echo ""
|
|
echo "Searching for profile in available profiles..."
|
|
if [[ -f "target/${{ matrix.target }}/${{ matrix.subtarget }}/target.mk" ]]; then
|
|
echo "Available profiles in target/${{ matrix.target }}/${{ matrix.subtarget }}:"
|
|
find "target/${{ matrix.target }}/${{ matrix.subtarget }}" -name "*.mk" -exec grep -l "DEVICE_NAME" {} \; | head -10
|
|
fi
|
|
exit 1
|
|
fi
|
|
|
|
# Verify image building is enabled
|
|
echo ""
|
|
echo "Checking image generation settings..."
|
|
if grep -q "CONFIG_TARGET_ROOTFS_SQUASHFS=y" .config; then
|
|
echo "✅ SQUASHFS image generation enabled"
|
|
else
|
|
echo "⚠️ SQUASHFS not enabled"
|
|
fi
|
|
|
|
if grep -q "CONFIG_TARGET_ROOTFS_EXT4FS=y" .config; then
|
|
echo "✅ EXT4 image generation enabled"
|
|
else
|
|
echo "⚠️ EXT4 not enabled"
|
|
fi
|
|
|
|
# Show relevant config
|
|
echo ""
|
|
echo "📋 Relevant configuration:"
|
|
grep "^CONFIG_TARGET_" .config | head -20
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
|
|
- name: Download packages
|
|
run: |
|
|
cd openwrt
|
|
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "📥 DOWNLOADING PACKAGES"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo ""
|
|
echo "Downloading source packages and dependencies..."
|
|
echo "This may take several minutes depending on network speed."
|
|
echo ""
|
|
|
|
if make download -j$(nproc) V=s; then
|
|
echo ""
|
|
echo "✅ All packages downloaded successfully"
|
|
else
|
|
echo ""
|
|
echo "⚠️ Parallel download failed, retrying with single thread..."
|
|
make download -j1 V=s
|
|
fi
|
|
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
|
|
- name: Build firmware
|
|
run: |
|
|
cd openwrt
|
|
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "🔨 BUILDING FIRMWARE"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo ""
|
|
echo "📋 Build Information:"
|
|
echo " • Device: ${{ matrix.description }}"
|
|
echo " • Profile: ${{ matrix.profile }}"
|
|
echo " • Target: ${{ matrix.target }}/${{ matrix.subtarget }}"
|
|
echo " • OpenWrt: ${{ env.OPENWRT_VERSION }}"
|
|
echo " • CPU Cores: $(nproc)"
|
|
echo " • Estimated Time: 1-2 hours"
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo ""
|
|
|
|
START_TIME=$(date +%s)
|
|
|
|
# Ensure staging directories exist to prevent opkg lock file errors
|
|
mkdir -p build_dir/target-*/root*/tmp 2>/dev/null || true
|
|
|
|
# Build with explicit profile specification to ensure images are generated
|
|
if make -j$(nproc) PROFILE="${{ matrix.profile }}" V=s 2>&1 | tee build.log; then
|
|
END_TIME=$(date +%s)
|
|
DURATION=$((END_TIME - START_TIME))
|
|
MINUTES=$((DURATION / 60))
|
|
SECONDS=$((DURATION % 60))
|
|
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "✅ BUILD SUCCESSFUL"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo ""
|
|
echo "⏱️ Build Time: ${MINUTES}m ${SECONDS}s"
|
|
echo "📁 Output: bin/targets/${{ matrix.target }}/${{ matrix.subtarget }}/"
|
|
echo ""
|
|
echo "📦 Generated Files:"
|
|
ls -lh "bin/targets/${{ matrix.target }}/${{ matrix.subtarget }}/" 2>/dev/null | grep -v "^total" | grep -v "^d" | head -20 || echo " (no files found)"
|
|
echo ""
|
|
else
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "⚠️ PARALLEL BUILD FAILED - RETRYING WITH SINGLE THREAD"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo ""
|
|
echo "This is often caused by race conditions in parallel builds."
|
|
echo "Retrying with -j1 (single thread) for better stability..."
|
|
echo ""
|
|
|
|
# Ensure staging directories exist before retry
|
|
mkdir -p build_dir/target-*/root*/tmp 2>/dev/null || true
|
|
|
|
if make -j1 PROFILE="${{ matrix.profile }}" V=s 2>&1 | tee build-retry.log; then
|
|
END_TIME=$(date +%s)
|
|
DURATION=$((END_TIME - START_TIME))
|
|
MINUTES=$((DURATION / 60))
|
|
SECONDS=$((DURATION % 60))
|
|
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "✅ BUILD SUCCESSFUL (after retry)"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo ""
|
|
echo "⏱️ Total Build Time: ${MINUTES}m ${SECONDS}s"
|
|
echo "📁 Output: bin/targets/${{ matrix.target }}/${{ matrix.subtarget }}/"
|
|
echo ""
|
|
echo "📦 Generated Files:"
|
|
ls -lh "bin/targets/${{ matrix.target }}/${{ matrix.subtarget }}/" 2>/dev/null | grep -v "^total" | grep -v "^d" | head -20 || echo " (no files found)"
|
|
echo ""
|
|
else
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "❌ BUILD FAILED"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo ""
|
|
echo "📋 Last 50 lines of build log:"
|
|
echo ""
|
|
tail -50 build-retry.log
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
- name: Prepare artifacts
|
|
id: prepare
|
|
run: |
|
|
mkdir -p artifacts
|
|
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "📦 Collecting Firmware Images"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
|
|
# List what was actually built
|
|
echo "🔍 Searching for firmware images in:"
|
|
echo " openwrt/bin/targets/${{ matrix.target }}/${{ matrix.subtarget }}/"
|
|
echo ""
|
|
|
|
if [[ -d "openwrt/bin/targets/${{ matrix.target }}/${{ matrix.subtarget }}" ]]; then
|
|
echo "📂 Directory contents:"
|
|
ls -lh "openwrt/bin/targets/${{ matrix.target }}/${{ matrix.subtarget }}/" | grep -v "^total" | grep -v "^d" || echo " (empty)"
|
|
echo ""
|
|
fi
|
|
|
|
# Copy firmware images (all common patterns)
|
|
IMG_COUNT=0
|
|
TARGET_DIR="openwrt/bin/targets/${{ matrix.target }}/${{ matrix.subtarget }}"
|
|
|
|
if [[ -d "$TARGET_DIR" ]]; then
|
|
# Find all firmware image files (not directories, not packages)
|
|
while IFS= read -r file; do
|
|
if [[ -f "$file" ]]; then
|
|
# Skip certain files
|
|
case "$(basename "$file")" in
|
|
*.ipk|*.manifest|*.json|sha256sums|*.buildinfo|packages)
|
|
continue
|
|
;;
|
|
*)
|
|
cp "$file" artifacts/
|
|
echo " ✅ $(basename "$file") ($(du -h "$file" | cut -f1))"
|
|
IMG_COUNT=$((IMG_COUNT + 1))
|
|
;;
|
|
esac
|
|
fi
|
|
done < <(find "$TARGET_DIR" -maxdepth 1 -type f 2>/dev/null)
|
|
else
|
|
echo "⚠️ Warning: Target directory not found: $TARGET_DIR"
|
|
fi
|
|
|
|
if [[ $IMG_COUNT -eq 0 ]]; then
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "⚠️ WARNING: No firmware images found!"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo ""
|
|
echo "🔍 Diagnostic Information:"
|
|
echo ""
|
|
|
|
# Check if target directory structure exists
|
|
if [[ -d "openwrt/bin/targets" ]]; then
|
|
echo "📂 Available targets:"
|
|
find openwrt/bin/targets -type d -mindepth 2 -maxdepth 2 2>/dev/null | sed 's|openwrt/bin/targets/||' || echo " (none)"
|
|
echo ""
|
|
fi
|
|
|
|
# Check build log for errors
|
|
if [[ -f "openwrt/build.log" ]]; then
|
|
echo "📋 Checking build log for errors..."
|
|
if grep -i "error\|failed\|cannot" openwrt/build.log | tail -10 | grep -v "warning" > /tmp/errors.txt 2>/dev/null; then
|
|
echo "Recent errors found:"
|
|
cat /tmp/errors.txt
|
|
else
|
|
echo " No obvious errors in build log"
|
|
fi
|
|
echo ""
|
|
fi
|
|
|
|
# Check if device profile was actually built
|
|
echo "🎯 Checking if device profile was built:"
|
|
if [[ -d "$TARGET_DIR" ]]; then
|
|
ALL_FILES=$(find "$TARGET_DIR" -type f 2>/dev/null | wc -l)
|
|
echo " Total files in target directory: $ALL_FILES"
|
|
|
|
if [[ $ALL_FILES -gt 0 ]]; then
|
|
echo " Files present:"
|
|
ls -lh "$TARGET_DIR" | grep -v "^total" | grep -v "^d"
|
|
fi
|
|
else
|
|
echo " ❌ Target directory doesn't exist: $TARGET_DIR"
|
|
fi
|
|
echo ""
|
|
|
|
echo "💡 This usually means:"
|
|
echo " 1. Device profile not properly selected in .config"
|
|
echo " 2. Build completed but only packages were built, not images"
|
|
echo " 3. Device profile name doesn't match OpenWrt version ${{ env.OPENWRT_VERSION }}"
|
|
echo ""
|
|
echo "🔧 Suggested actions:"
|
|
echo " 1. Check the 'Verify device profile configuration' step output"
|
|
echo " 2. Verify profile '${{ matrix.profile }}' exists for OpenWrt ${{ env.OPENWRT_VERSION }}"
|
|
echo " 3. Check if CONFIG_TARGET options are properly set in .config"
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
fi
|
|
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "📦 Collecting SecuBox Packages"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
|
|
# Copy packages
|
|
mkdir -p artifacts/packages
|
|
PKG_COUNT=0
|
|
for pattern in "luci-app-*secubox*.ipk" "luci-app-*dashboard*.ipk" "luci-app-*guardian*.ipk" "luci-app-*modes*.ipk" "luci-app-*hub*.ipk"; do
|
|
while IFS= read -r file; do
|
|
if [[ -f "$file" ]]; then
|
|
cp "$file" artifacts/packages/
|
|
echo " ✅ $(basename "$file")"
|
|
PKG_COUNT=$((PKG_COUNT + 1))
|
|
fi
|
|
done < <(find openwrt/bin/packages -name "$pattern" 2>/dev/null)
|
|
done
|
|
|
|
# Generate checksums
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "🔐 Generating Checksums"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
|
|
cd artifacts
|
|
sha256sum *.* > SHA256SUMS 2>/dev/null || true
|
|
if [[ -d packages ]] && [[ -n "$(ls -A packages)" ]]; then
|
|
(cd packages && sha256sum *.ipk > SHA256SUMS 2>/dev/null || true)
|
|
fi
|
|
|
|
# Create info file
|
|
SECUBOX_INCLUDED="${{ github.event.inputs.include_secubox }}"
|
|
if [[ "${{ github.event_name }}" == "push" ]]; then
|
|
SECUBOX_INCLUDED="true (auto)"
|
|
fi
|
|
|
|
cat > BUILD_INFO.txt << EOF
|
|
SecuBox Firmware Build
|
|
=======================
|
|
Device: ${{ matrix.description }}
|
|
Profile: ${{ matrix.profile }}
|
|
Target: ${{ matrix.target }}/${{ matrix.subtarget }}
|
|
OpenWrt: ${{ env.OPENWRT_VERSION }}
|
|
SecuBox: ${SECUBOX_INCLUDED:-true}
|
|
Built: $(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
Commit: ${{ github.sha }}
|
|
EOF
|
|
|
|
if [[ "${{ github.event_name }}" == "push" ]]; then
|
|
echo "Tag: ${{ github.ref_name }}" >> BUILD_INFO.txt
|
|
fi
|
|
|
|
cat >> BUILD_INFO.txt << EOF
|
|
|
|
Firmware Images: $IMG_COUNT
|
|
SecuBox Packages: $PKG_COUNT
|
|
EOF
|
|
|
|
echo ""
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "📋 Artifact Summary"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "Device: ${{ matrix.description }}"
|
|
echo "Firmware images: $IMG_COUNT files"
|
|
echo "SecuBox packages: $PKG_COUNT files"
|
|
echo ""
|
|
echo "📁 Contents:"
|
|
ls -lh
|
|
|
|
# Export counts for summary
|
|
echo "img_count=$IMG_COUNT" >> $GITHUB_OUTPUT
|
|
echo "pkg_count=$PKG_COUNT" >> $GITHUB_OUTPUT
|
|
|
|
- name: Save build logs and config
|
|
if: always()
|
|
run: |
|
|
mkdir -p artifacts/logs
|
|
|
|
# Save .config file
|
|
if [[ -f openwrt/.config ]]; then
|
|
cp openwrt/.config artifacts/logs/dotconfig
|
|
echo "✅ Saved .config as dotconfig"
|
|
fi
|
|
|
|
# Save build logs
|
|
if [[ -f openwrt/build.log ]]; then
|
|
cp openwrt/build.log artifacts/logs/
|
|
echo "✅ Saved build.log"
|
|
fi
|
|
|
|
if [[ -f openwrt/build-retry.log ]]; then
|
|
cp openwrt/build-retry.log artifacts/logs/
|
|
echo "✅ Saved build-retry.log"
|
|
fi
|
|
|
|
# Save make output
|
|
if [[ -f openwrt/logs ]]; then
|
|
cp -r openwrt/logs artifacts/logs/make-logs 2>/dev/null || true
|
|
fi
|
|
|
|
echo ""
|
|
echo "📋 Logs saved to artifacts/logs/ for debugging"
|
|
|
|
- name: Upload artifacts
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: secubox-${{ matrix.device }}-${{ env.OPENWRT_VERSION }}
|
|
path: artifacts/
|
|
retention-days: 30
|
|
|
|
- name: Generate build summary
|
|
if: always()
|
|
run: |
|
|
echo "# 🎯 Build Complete: ${{ matrix.description }}" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
|
|
echo "## 📊 Build Information" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY
|
|
echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
|
|
echo "| Device | ${{ matrix.description }} |" >> $GITHUB_STEP_SUMMARY
|
|
echo "| Profile | \`${{ matrix.profile }}\` |" >> $GITHUB_STEP_SUMMARY
|
|
echo "| Target | ${{ matrix.target }}/${{ matrix.subtarget }} |" >> $GITHUB_STEP_SUMMARY
|
|
echo "| OpenWrt Version | ${{ env.OPENWRT_VERSION }} |" >> $GITHUB_STEP_SUMMARY
|
|
echo "| SecuBox Included | ${{ github.event.inputs.include_secubox || 'true (auto)' }} |" >> $GITHUB_STEP_SUMMARY
|
|
echo "| Build Time | $(date -u +%Y-%m-%d\ %H:%M:%S\ UTC) |" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
|
|
echo "## 📦 Generated Artifacts" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "| Type | Count | Files |" >> $GITHUB_STEP_SUMMARY
|
|
echo "|------|-------|-------|" >> $GITHUB_STEP_SUMMARY
|
|
echo "| Firmware Images | ${{ steps.prepare.outputs.img_count }} | \`*.img.gz\`, \`*sysupgrade*\`, \`*factory*\` |" >> $GITHUB_STEP_SUMMARY
|
|
echo "| SecuBox Packages | ${{ steps.prepare.outputs.pkg_count }} | \`luci-app-*.ipk\` |" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
|
|
echo "## 📥 Download Artifacts" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "**Artifact Name:** \`secubox-${{ matrix.device }}-${{ env.OPENWRT_VERSION }}\`" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "To download:" >> $GITHUB_STEP_SUMMARY
|
|
echo "1. Go to the **Summary** page of this workflow run" >> $GITHUB_STEP_SUMMARY
|
|
echo "2. Scroll to the **Artifacts** section at the bottom" >> $GITHUB_STEP_SUMMARY
|
|
echo "3. Click on \`secubox-${{ matrix.device }}-${{ env.OPENWRT_VERSION }}\` to download" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
|
|
if [[ -f artifacts/BUILD_INFO.txt ]]; then
|
|
echo "## 📄 Build Details" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
|
cat artifacts/BUILD_INFO.txt >> $GITHUB_STEP_SUMMARY
|
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
fi
|
|
|
|
echo "## 📋 Firmware Files" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
|
ls -lh artifacts/*.{img.gz,bin} 2>/dev/null | awk '{print $9, "(" $5 ")"}' | sed 's|artifacts/||' || echo "No firmware images found"
|
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
|
|
if [[ -d artifacts/packages ]] && [[ -n "$(ls -A artifacts/packages 2>/dev/null)" ]]; then
|
|
echo "## 📦 SecuBox Packages" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
|
ls -1 artifacts/packages/*.ipk 2>/dev/null | xargs -I{} basename {} || echo "No packages"
|
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
|
fi
|
|
|
|
# ============================================
|
|
# Create combined release for all devices
|
|
# ============================================
|
|
release:
|
|
needs: [setup, build-image]
|
|
runs-on: ubuntu-latest
|
|
if: github.event.inputs.device == 'all' || github.event_name == 'push'
|
|
|
|
steps:
|
|
- name: Download all artifacts
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
path: firmware
|
|
pattern: secubox-*
|
|
|
|
- name: Organize release
|
|
run: |
|
|
mkdir -p release
|
|
|
|
for device_dir in firmware/secubox-*/; do
|
|
DEVICE=$(basename "$device_dir" | sed 's/secubox-//' | sed "s/-${{ env.OPENWRT_VERSION }}//")
|
|
echo "📦 Processing $DEVICE..."
|
|
|
|
# Create device archive
|
|
tar -czf "release/secubox-firmware-${DEVICE}.tar.gz" -C "$device_dir" .
|
|
done
|
|
|
|
# Global checksums
|
|
cd release
|
|
sha256sum *.tar.gz > SHA256SUMS
|
|
|
|
# Release notes
|
|
cat > RELEASE_NOTES.md << 'EOF'
|
|
# SecuBox Firmware Images
|
|
|
|
Pre-built firmware images for GlobalScale devices with SecuBox modules pre-installed.
|
|
|
|
## Included Devices
|
|
|
|
| Device | SoC | RAM | Description |
|
|
|--------|-----|-----|-------------|
|
|
| ESPRESSObin V7 | Armada 3720 | 1-2GB | Entry-level |
|
|
| ESPRESSObin Ultra | Armada 3720 | 1-2GB | WiFi + PoE |
|
|
| Sheeva64 | Armada 3720 | 1GB | Plug computer |
|
|
| MOCHAbin | Armada 7040 | 4-8GB | Quad-core + 10G |
|
|
|
|
## Pre-installed SecuBox Modules
|
|
|
|
**Security & Access Control:**
|
|
- luci-app-auth-guardian - Authentication & session manager
|
|
- luci-app-client-guardian - NAC & captive portal
|
|
- luci-app-crowdsec-dashboard - CrowdSec security monitoring
|
|
- luci-app-ksm-manager - Key storage & HSM
|
|
- luci-app-netifyd-dashboard - Deep packet inspection
|
|
|
|
**Monitoring & Analytics:**
|
|
- luci-app-media-flow - Media traffic detection
|
|
- luci-app-netdata-dashboard - System monitoring
|
|
|
|
**Network Management:**
|
|
- luci-app-bandwidth-manager - QoS & bandwidth quotas
|
|
- luci-app-cdn-cache - CDN proxy cache
|
|
- luci-app-network-modes - Network mode configuration
|
|
- luci-app-traffic-shaper - Advanced traffic shaping
|
|
- luci-app-wireguard-dashboard - WireGuard VPN
|
|
|
|
**System & Services:**
|
|
- luci-app-secubox - Central management hub
|
|
- luci-app-system-hub - System control center
|
|
- luci-app-vhost-manager - Virtual host manager
|
|
|
|
## Installation
|
|
|
|
1. Download the appropriate firmware for your device
|
|
2. Flash using OpenWrt sysupgrade or manufacturer tools
|
|
3. Access LuCI at http://192.168.1.1
|
|
4. Navigate to Services → SecuBox
|
|
|
|
## Support
|
|
|
|
- [Documentation](https://cybermind.fr/docs/secubox)
|
|
- [CyberMind.fr](https://cybermind.fr)
|
|
EOF
|
|
|
|
- name: Create release
|
|
if: startsWith(github.ref, 'refs/tags/v')
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
name: "SecuBox Firmware ${{ github.ref_name }}"
|
|
tag_name: ${{ github.ref_name }}
|
|
body_path: release/RELEASE_NOTES.md
|
|
files: |
|
|
release/*.tar.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 }}
|
|
|
|
# ============================================
|
|
# Final summary of all builds
|
|
# ============================================
|
|
summary:
|
|
needs: [setup, build-image]
|
|
runs-on: ubuntu-latest
|
|
if: always()
|
|
|
|
steps:
|
|
- name: Download all artifacts
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
path: all-artifacts
|
|
pattern: secubox-*
|
|
continue-on-error: true
|
|
|
|
- name: Generate final summary
|
|
run: |
|
|
echo "# 🏗️ SecuBox Firmware Build Summary" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
|
|
echo "## ⚙️ Build Configuration" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY
|
|
echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
|
|
echo "| OpenWrt Version | ${{ env.OPENWRT_VERSION }} |" >> $GITHUB_STEP_SUMMARY
|
|
echo "| SecuBox Included | ${{ github.event.inputs.include_secubox || 'true (auto)' }} |" >> $GITHUB_STEP_SUMMARY
|
|
echo "| Target Device | ${{ github.event.inputs.device || 'all (auto)' }} |" >> $GITHUB_STEP_SUMMARY
|
|
echo "| Workflow Run | #${{ github.run_number }} |" >> $GITHUB_STEP_SUMMARY
|
|
echo "| Triggered by | ${{ github.event_name }} |" >> $GITHUB_STEP_SUMMARY
|
|
|
|
# Add tag info if triggered by tag
|
|
if [[ "${{ github.event_name }}" == "push" ]] && [[ -n "${{ github.ref_name }}" ]]; then
|
|
echo "| Git Tag | \`${{ github.ref_name }}\` |" >> $GITHUB_STEP_SUMMARY
|
|
fi
|
|
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
|
|
echo "## 📦 Generated Artifacts" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
|
|
if [[ -d all-artifacts ]]; then
|
|
ARTIFACT_COUNT=$(find all-artifacts -type d -mindepth 1 -maxdepth 1 | wc -l)
|
|
|
|
if [[ $ARTIFACT_COUNT -gt 0 ]]; then
|
|
echo "✅ **$ARTIFACT_COUNT artifact(s) available for download**" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "| Device | Artifact Name | Firmware Images | Packages |" >> $GITHUB_STEP_SUMMARY
|
|
echo "|--------|---------------|-----------------|----------|" >> $GITHUB_STEP_SUMMARY
|
|
|
|
for artifact_dir in all-artifacts/secubox-*/; do
|
|
if [[ -d "$artifact_dir" ]]; then
|
|
ARTIFACT_NAME=$(basename "$artifact_dir")
|
|
DEVICE=$(echo "$ARTIFACT_NAME" | sed 's/secubox-//' | sed "s/-${{ env.OPENWRT_VERSION }}//")
|
|
|
|
# Count files
|
|
IMG_COUNT=$(find "$artifact_dir" -maxdepth 1 \( -name "*.img.gz" -o -name "*.bin" -o -name "*sysupgrade*" -o -name "*factory*" \) 2>/dev/null | wc -l)
|
|
PKG_COUNT=$(find "$artifact_dir/packages" -name "*.ipk" 2>/dev/null | wc -l)
|
|
|
|
echo "| $DEVICE | \`$ARTIFACT_NAME\` | $IMG_COUNT | $PKG_COUNT |" >> $GITHUB_STEP_SUMMARY
|
|
fi
|
|
done
|
|
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "### 📥 How to Download" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "1. Navigate to the **Summary** tab of this workflow run" >> $GITHUB_STEP_SUMMARY
|
|
echo "2. Scroll to the **Artifacts** section at the bottom of the page" >> $GITHUB_STEP_SUMMARY
|
|
echo "3. Click on the artifact name to download the ZIP file" >> $GITHUB_STEP_SUMMARY
|
|
echo "4. Extract the ZIP to access firmware images and packages" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
|
|
echo "### 📋 Artifact Contents" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "Each artifact contains:" >> $GITHUB_STEP_SUMMARY
|
|
echo "- **Firmware images**: \`*.img.gz\`, \`*sysupgrade.bin\`, \`*factory.bin\`" >> $GITHUB_STEP_SUMMARY
|
|
echo "- **SecuBox packages**: \`luci-app-*.ipk\` (in \`packages/\` subdirectory)" >> $GITHUB_STEP_SUMMARY
|
|
echo "- **Checksums**: \`SHA256SUMS\` for verification" >> $GITHUB_STEP_SUMMARY
|
|
echo "- **Build info**: \`BUILD_INFO.txt\` with build details" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
|
|
# List detailed contents of first artifact as example
|
|
FIRST_ARTIFACT=$(find all-artifacts -type d -mindepth 1 -maxdepth 1 | head -1)
|
|
if [[ -n "$FIRST_ARTIFACT" ]]; then
|
|
echo "### 📄 Example: $(basename "$FIRST_ARTIFACT")" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
|
echo "Firmware Images:" >> $GITHUB_STEP_SUMMARY
|
|
find "$FIRST_ARTIFACT" -maxdepth 1 -type f \( -name "*.img.gz" -o -name "*.bin" \) -exec basename {} \; 2>/dev/null | sort || echo " (none)"
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
if [[ -d "$FIRST_ARTIFACT/packages" ]]; then
|
|
echo "SecuBox Packages:" >> $GITHUB_STEP_SUMMARY
|
|
find "$FIRST_ARTIFACT/packages" -name "*.ipk" -exec basename {} \; 2>/dev/null | sort || echo " (none)"
|
|
fi
|
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
fi
|
|
|
|
echo "### 🔐 Verification" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "After downloading, verify file integrity:" >> $GITHUB_STEP_SUMMARY
|
|
echo '```bash' >> $GITHUB_STEP_SUMMARY
|
|
echo "# Extract artifact" >> $GITHUB_STEP_SUMMARY
|
|
echo "unzip secubox-*.zip" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "# Verify checksums" >> $GITHUB_STEP_SUMMARY
|
|
echo "sha256sum -c SHA256SUMS" >> $GITHUB_STEP_SUMMARY
|
|
echo '```' >> $GITHUB_STEP_SUMMARY
|
|
|
|
else
|
|
echo "⚠️ **No artifacts were generated**" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "Check the build logs above for errors." >> $GITHUB_STEP_SUMMARY
|
|
fi
|
|
else
|
|
echo "⚠️ **No artifacts found**" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "This may indicate that all builds failed. Check individual job logs for details." >> $GITHUB_STEP_SUMMARY
|
|
fi
|
|
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "---" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "📚 For installation instructions, see the [SecuBox documentation](https://github.com/gkerma/secubox)" >> $GITHUB_STEP_SUMMARY
|