552 lines
19 KiB
YAML
552 lines
19 KiB
YAML
name: Build OpenWrt Packages
|
|
|
|
on:
|
|
push:
|
|
branches: [main, master, develop]
|
|
tags:
|
|
- 'v*'
|
|
pull_request:
|
|
branches: [main, master]
|
|
workflow_dispatch:
|
|
inputs:
|
|
openwrt_version:
|
|
description: 'OpenWrt version'
|
|
required: true
|
|
default: '23.05.5'
|
|
type: choice
|
|
options:
|
|
- '23.05.5'
|
|
- '23.05.4'
|
|
- '22.03.7'
|
|
- 'SNAPSHOT'
|
|
architectures:
|
|
description: 'Architectures to build (comma-separated or "all")'
|
|
required: false
|
|
default: 'all'
|
|
|
|
env:
|
|
OPENWRT_VERSION: ${{ github.event.inputs.openwrt_version || '23.05.5' }}
|
|
|
|
jobs:
|
|
# ============================================
|
|
# Determine build matrix
|
|
# ============================================
|
|
setup:
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
matrix: ${{ steps.set-matrix.outputs.matrix }}
|
|
version: ${{ steps.version.outputs.version }}
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Determine version
|
|
id: version
|
|
run: |
|
|
if [[ "${{ github.ref }}" == refs/tags/v* ]]; then
|
|
VERSION="${{ github.ref_name }}"
|
|
else
|
|
VERSION="0.0.0-$(git rev-parse --short HEAD)"
|
|
fi
|
|
echo "version=${VERSION#v}" >> $GITHUB_OUTPUT
|
|
echo "📦 Package version: ${VERSION#v}"
|
|
|
|
- name: Set build matrix
|
|
id: set-matrix
|
|
run: |
|
|
# Full architecture matrix for OpenWrt
|
|
# Format: target/subtarget -> SDK name mapping
|
|
ALL_TARGETS=$(cat << 'EOF'
|
|
{
|
|
"include": [
|
|
{
|
|
"target": "x86-64",
|
|
"arch": "x86_64",
|
|
"sdk_name": "x86-64",
|
|
"description": "x86 64-bit (PC, VM, containers)"
|
|
},
|
|
{
|
|
"target": "x86-generic",
|
|
"arch": "i386_pentium4",
|
|
"sdk_name": "x86-generic",
|
|
"description": "x86 32-bit (legacy PC)"
|
|
},
|
|
{
|
|
"target": "aarch64-generic",
|
|
"arch": "aarch64_generic",
|
|
"sdk_name": "armsr-armv8",
|
|
"description": "ARM 64-bit generic (RPi4, Rock64)"
|
|
},
|
|
{
|
|
"target": "aarch64-cortex-a53",
|
|
"arch": "aarch64_cortex-a53",
|
|
"sdk_name": "mvebu-cortexa53",
|
|
"description": "ARM Cortex-A53 (ESPRESSObin, Sheeva64)"
|
|
},
|
|
{
|
|
"target": "aarch64-cortex-a72",
|
|
"arch": "aarch64_cortex-a72",
|
|
"sdk_name": "mvebu-cortexa72",
|
|
"description": "ARM Cortex-A72 (MOCHAbin, MACCHIATObin)"
|
|
},
|
|
{
|
|
"target": "arm-cortex-a7-neon",
|
|
"arch": "arm_cortex-a7_neon-vfpv4",
|
|
"sdk_name": "sunxi-cortexa7",
|
|
"description": "ARM Cortex-A7 (Orange Pi, Banana Pi)"
|
|
},
|
|
{
|
|
"target": "arm-cortex-a9-neon",
|
|
"arch": "arm_cortex-a9_neon",
|
|
"sdk_name": "mvebu-cortexa9",
|
|
"description": "ARM Cortex-A9 (Linksys WRT, Turris)"
|
|
},
|
|
{
|
|
"target": "arm-cortex-a15-neon",
|
|
"arch": "arm_cortex-a15_neon-vfpv4",
|
|
"sdk_name": "armvirt-32",
|
|
"description": "ARM Cortex-A15 (QEMU ARM)"
|
|
},
|
|
{
|
|
"target": "mips-24kc",
|
|
"arch": "mips_24kc",
|
|
"sdk_name": "ath79-generic",
|
|
"description": "MIPS 24Kc (TP-Link, Ubiquiti)"
|
|
},
|
|
{
|
|
"target": "mipsel-24kc",
|
|
"arch": "mipsel_24kc",
|
|
"sdk_name": "ramips-mt7621",
|
|
"description": "MIPS Little-Endian (Xiaomi, GL.iNet)"
|
|
},
|
|
{
|
|
"target": "mipsel-74kc",
|
|
"arch": "mipsel_74kc",
|
|
"sdk_name": "bcm47xx-mips74k",
|
|
"description": "MIPS 74Kc (Broadcom routers)"
|
|
},
|
|
{
|
|
"target": "mediatek-filogic",
|
|
"arch": "aarch64_cortex-a53",
|
|
"sdk_name": "mediatek-filogic",
|
|
"description": "MediaTek Filogic (MT7981, MT7986)"
|
|
},
|
|
{
|
|
"target": "qualcomm-ipq40xx",
|
|
"arch": "arm_cortex-a7_neon-vfpv4",
|
|
"sdk_name": "ipq40xx-generic",
|
|
"description": "Qualcomm IPQ40xx (Google WiFi, Zyxel)"
|
|
},
|
|
{
|
|
"target": "qualcomm-ipq806x",
|
|
"arch": "arm_cortex-a15_neon-vfpv4",
|
|
"sdk_name": "ipq806x-generic",
|
|
"description": "Qualcomm IPQ806x (Netgear R7800)"
|
|
},
|
|
{
|
|
"target": "rockchip-armv8",
|
|
"arch": "aarch64_generic",
|
|
"sdk_name": "rockchip-armv8",
|
|
"description": "Rockchip (NanoPi R4S, R5S)"
|
|
},
|
|
{
|
|
"target": "bcm27xx-bcm2711",
|
|
"arch": "aarch64_cortex-a72",
|
|
"sdk_name": "bcm27xx-bcm2711",
|
|
"description": "Raspberry Pi 4"
|
|
}
|
|
]
|
|
}
|
|
EOF
|
|
)
|
|
|
|
INPUT_ARCHS="${{ github.event.inputs.architectures }}"
|
|
if [[ -z "$INPUT_ARCHS" || "$INPUT_ARCHS" == "all" ]]; then
|
|
MATRIX="$ALL_TARGETS"
|
|
else
|
|
# Filter matrix based on input
|
|
MATRIX=$(echo "$ALL_TARGETS" | jq -c --arg archs "$INPUT_ARCHS" '
|
|
.include |= map(select(.target as $t | $archs | split(",") | map(gsub("^\\s+|\\s+$";"")) | any(. == $t or . == "all")))
|
|
')
|
|
fi
|
|
|
|
echo "matrix=$MATRIX" >> $GITHUB_OUTPUT
|
|
echo "📋 Build matrix:"
|
|
echo "$MATRIX" | jq '.'
|
|
|
|
# ============================================
|
|
# Build packages for each architecture
|
|
# ============================================
|
|
build:
|
|
needs: setup
|
|
runs-on: ubuntu-latest
|
|
strategy:
|
|
fail-fast: false
|
|
matrix: ${{ fromJson(needs.setup.outputs.matrix) }}
|
|
|
|
name: Build ${{ matrix.target }}
|
|
|
|
steps:
|
|
- name: Checkout source
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Free disk space
|
|
run: |
|
|
echo "🧹 Cleaning up disk space..."
|
|
sudo rm -rf /usr/share/dotnet
|
|
sudo rm -rf /usr/local/lib/android
|
|
sudo rm -rf /opt/ghc
|
|
sudo rm -rf /opt/hostedtoolcache/CodeQL
|
|
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 jq
|
|
|
|
- name: Cache OpenWrt SDK
|
|
uses: actions/cache@v4
|
|
id: cache-sdk
|
|
with:
|
|
path: ~/sdk
|
|
key: openwrt-sdk-${{ env.OPENWRT_VERSION }}-${{ matrix.sdk_name }}
|
|
|
|
- name: Download OpenWrt SDK
|
|
if: steps.cache-sdk.outputs.cache-hit != 'true'
|
|
run: |
|
|
echo "📥 Downloading SDK for ${{ matrix.description }}..."
|
|
|
|
VERSION="${{ env.OPENWRT_VERSION }}"
|
|
SDK_NAME="${{ matrix.sdk_name }}"
|
|
|
|
if [[ "$VERSION" == "SNAPSHOT" ]]; then
|
|
BASE_URL="https://downloads.openwrt.org/snapshots/targets"
|
|
else
|
|
BASE_URL="https://downloads.openwrt.org/releases/${VERSION}/targets"
|
|
fi
|
|
|
|
# Parse target/subtarget from sdk_name
|
|
TARGET=$(echo "$SDK_NAME" | cut -d'-' -f1)
|
|
SUBTARGET=$(echo "$SDK_NAME" | cut -d'-' -f2-)
|
|
|
|
SDK_URL="${BASE_URL}/${TARGET}/${SUBTARGET}"
|
|
|
|
echo "🔍 Looking for SDK at: $SDK_URL"
|
|
|
|
# Find SDK filename
|
|
SDK_FILE=$(curl -sL "$SDK_URL/" | grep -oP 'openwrt-sdk[^"]+\.tar\.(xz|zst)' | head -1)
|
|
|
|
if [[ -z "$SDK_FILE" ]]; then
|
|
echo "⚠️ SDK not found, trying alternative URL pattern..."
|
|
SDK_FILE=$(curl -sL "$SDK_URL/sha256sums" | grep -oP 'openwrt-sdk[^\s]+' | head -1)
|
|
fi
|
|
|
|
if [[ -z "$SDK_FILE" ]]; then
|
|
echo "❌ Could not find SDK for ${{ matrix.target }}"
|
|
echo "🔗 Checked: $SDK_URL"
|
|
exit 1
|
|
fi
|
|
|
|
echo "📦 Downloading: $SDK_FILE"
|
|
wget -q --show-progress "${SDK_URL}/${SDK_FILE}" -O /tmp/sdk.tar.xz || \
|
|
wget -q --show-progress "${SDK_URL}/${SDK_FILE}" -O /tmp/sdk.tar.zst
|
|
|
|
mkdir -p ~/sdk
|
|
if [[ "$SDK_FILE" == *.zst ]]; then
|
|
zstd -d /tmp/sdk.tar.zst -o /tmp/sdk.tar
|
|
tar -xf /tmp/sdk.tar -C ~/sdk --strip-components=1
|
|
else
|
|
tar -xf /tmp/sdk.tar.xz -C ~/sdk --strip-components=1
|
|
fi
|
|
|
|
echo "✅ SDK extracted to ~/sdk"
|
|
|
|
- name: Prepare SDK
|
|
run: |
|
|
cd ~/sdk
|
|
|
|
# Update feeds
|
|
echo "📋 Updating feeds..."
|
|
./scripts/feeds update -a
|
|
./scripts/feeds install -a
|
|
|
|
# Configure SDK
|
|
echo "⚙️ Configuring SDK..."
|
|
make defconfig
|
|
|
|
- name: Copy packages to SDK
|
|
run: |
|
|
echo "📁 Copying SecuBox packages to SDK..."
|
|
|
|
# List of our packages
|
|
PACKAGES=(
|
|
"luci-app-crowdsec-dashboard"
|
|
"luci-app-netdata-dashboard"
|
|
"luci-app-netifyd-dashboard"
|
|
"luci-app-wireguard-dashboard"
|
|
"luci-app-network-modes"
|
|
"luci-app-client-guardian"
|
|
"luci-app-system-hub"
|
|
)
|
|
|
|
# Create package directory
|
|
mkdir -p ~/sdk/package/secubox
|
|
|
|
# Copy each package if it exists
|
|
for pkg in "${PACKAGES[@]}"; do
|
|
if [[ -d "$GITHUB_WORKSPACE/$pkg" ]]; then
|
|
echo " 📦 $pkg"
|
|
cp -r "$GITHUB_WORKSPACE/$pkg" ~/sdk/package/secubox/
|
|
else
|
|
echo " ⚠️ $pkg not found in repository"
|
|
fi
|
|
done
|
|
|
|
# If packages are in a subdirectory
|
|
if [[ -d "$GITHUB_WORKSPACE/packages" ]]; then
|
|
cp -r "$GITHUB_WORKSPACE/packages/"* ~/sdk/package/secubox/ 2>/dev/null || true
|
|
fi
|
|
|
|
# List what we have
|
|
echo "📋 Packages in SDK:"
|
|
ls -la ~/sdk/package/secubox/ || echo " (empty)"
|
|
|
|
- name: Update package version
|
|
run: |
|
|
VERSION="${{ needs.setup.outputs.version }}"
|
|
echo "📝 Setting package version to: $VERSION"
|
|
|
|
# Update Makefile version in each package
|
|
for makefile in ~/sdk/package/secubox/*/Makefile; do
|
|
if [[ -f "$makefile" ]]; then
|
|
sed -i "s/PKG_VERSION:=.*/PKG_VERSION:=$VERSION/" "$makefile"
|
|
sed -i "s/PKG_RELEASE:=.*/PKG_RELEASE:=1/" "$makefile"
|
|
echo " ✅ Updated: $(dirname $makefile | xargs basename)"
|
|
fi
|
|
done
|
|
|
|
- name: Build packages
|
|
run: |
|
|
cd ~/sdk
|
|
|
|
echo "🔨 Building SecuBox packages for ${{ matrix.description }}..."
|
|
|
|
# Enable our packages
|
|
for pkg in ~/sdk/package/secubox/*/; do
|
|
PKG_NAME=$(basename "$pkg")
|
|
echo "CONFIG_PACKAGE_${PKG_NAME}=m" >> .config
|
|
done
|
|
|
|
make defconfig
|
|
|
|
# Build with verbose output on error
|
|
make package/secubox/compile V=s -j$(nproc) || {
|
|
echo "❌ Build failed, retrying with single thread..."
|
|
make package/secubox/compile V=s -j1
|
|
}
|
|
|
|
# Generate package index
|
|
make package/index V=s
|
|
|
|
- name: Collect artifacts
|
|
id: collect
|
|
run: |
|
|
echo "📦 Collecting built packages..."
|
|
|
|
mkdir -p $GITHUB_WORKSPACE/artifacts/${{ matrix.target }}
|
|
|
|
# Find and copy .ipk files
|
|
find ~/sdk/bin -name "*.ipk" -exec cp {} $GITHUB_WORKSPACE/artifacts/${{ matrix.target }}/ \;
|
|
|
|
# Copy package index
|
|
find ~/sdk/bin -name "Packages*" -exec cp {} $GITHUB_WORKSPACE/artifacts/${{ matrix.target }}/ \; 2>/dev/null || true
|
|
|
|
# List artifacts
|
|
echo "📋 Built packages for ${{ matrix.target }}:"
|
|
ls -la $GITHUB_WORKSPACE/artifacts/${{ matrix.target }}/
|
|
|
|
# Count packages
|
|
PKG_COUNT=$(find $GITHUB_WORKSPACE/artifacts/${{ matrix.target }} -name "*.ipk" | wc -l)
|
|
echo "pkg_count=$PKG_COUNT" >> $GITHUB_OUTPUT
|
|
|
|
if [[ $PKG_COUNT -eq 0 ]]; then
|
|
echo "⚠️ No packages built!"
|
|
exit 1
|
|
fi
|
|
|
|
- name: Create checksums
|
|
run: |
|
|
cd $GITHUB_WORKSPACE/artifacts/${{ matrix.target }}
|
|
sha256sum *.ipk > SHA256SUMS
|
|
echo "✅ Checksums created"
|
|
|
|
- name: Upload artifacts
|
|
uses: actions/upload-artifact@v4
|
|
with:
|
|
name: packages-${{ matrix.target }}
|
|
path: artifacts/${{ matrix.target }}/
|
|
retention-days: 30
|
|
|
|
# ============================================
|
|
# Create combined release
|
|
# ============================================
|
|
release:
|
|
needs: [setup, build]
|
|
runs-on: ubuntu-latest
|
|
if: startsWith(github.ref, 'refs/tags/v')
|
|
|
|
steps:
|
|
- name: Checkout
|
|
uses: actions/checkout@v4
|
|
|
|
- name: Download all artifacts
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
path: packages
|
|
pattern: packages-*
|
|
|
|
- name: Organize packages
|
|
run: |
|
|
echo "📁 Organizing release packages..."
|
|
|
|
VERSION="${{ needs.setup.outputs.version }}"
|
|
mkdir -p release
|
|
|
|
# Create architecture-specific archives
|
|
for arch_dir in packages/packages-*/; do
|
|
ARCH=$(basename "$arch_dir" | sed 's/packages-//')
|
|
echo "📦 Processing $ARCH..."
|
|
|
|
# Create tarball
|
|
tar -czf "release/secubox-${VERSION}-${ARCH}.tar.gz" -C "$arch_dir" .
|
|
|
|
# Copy individual .ipk files to flat structure
|
|
mkdir -p "release/ipk/${ARCH}"
|
|
cp "$arch_dir"/*.ipk "release/ipk/${ARCH}/" 2>/dev/null || true
|
|
done
|
|
|
|
# Create "all architectures" mega-archive
|
|
tar -czf "release/secubox-${VERSION}-all-architectures.tar.gz" -C packages .
|
|
|
|
# Create release notes
|
|
cat > release/RELEASE_NOTES.md << EOF
|
|
# SecuBox $VERSION
|
|
|
|
## 📦 Packages Included
|
|
|
|
- luci-app-crowdsec-dashboard - CrowdSec Security Dashboard
|
|
- luci-app-netdata-dashboard - Netdata Monitoring Dashboard
|
|
- luci-app-netifyd-dashboard - Netifyd DPI Dashboard
|
|
- luci-app-wireguard-dashboard - WireGuard VPN Dashboard
|
|
- luci-app-network-modes - Network Mode Switcher
|
|
- luci-app-client-guardian - NAC & Captive Portal
|
|
- luci-app-system-hub - System Hub Control Center
|
|
|
|
## 🏗️ Supported Architectures
|
|
|
|
| Target | Architecture | Description |
|
|
|--------|--------------|-------------|
|
|
| x86-64 | x86_64 | PC, VMs, Containers |
|
|
| aarch64-cortex-a53 | aarch64 | ESPRESSObin, Sheeva64 |
|
|
| aarch64-cortex-a72 | aarch64 | MOCHAbin, RPi4 |
|
|
| arm-cortex-a7 | arm | Orange Pi, Banana Pi |
|
|
| arm-cortex-a9 | arm | Linksys WRT, Turris |
|
|
| mips-24kc | mips | TP-Link, Ubiquiti |
|
|
| mipsel-24kc | mipsel | Xiaomi, GL.iNet |
|
|
| mediatek-filogic | aarch64 | MT7981, MT7986 |
|
|
| qualcomm-ipq40xx | arm | Google WiFi |
|
|
| rockchip-armv8 | aarch64 | NanoPi R4S, R5S |
|
|
|
|
## 📥 Installation
|
|
|
|
\`\`\`bash
|
|
# Download package for your architecture
|
|
opkg update
|
|
opkg install luci-app-crowdsec-dashboard_${VERSION}_*.ipk
|
|
# ... install other packages as needed
|
|
\`\`\`
|
|
|
|
## 🔗 Links
|
|
|
|
- [Documentation](https://cybermind.fr/docs/secubox)
|
|
- [GitHub](https://github.com/gkerma)
|
|
- [CyberMind.fr](https://cybermind.fr)
|
|
|
|
---
|
|
Built with OpenWrt SDK ${{ env.OPENWRT_VERSION }}
|
|
EOF
|
|
|
|
echo "✅ Release organized"
|
|
ls -la release/
|
|
|
|
- name: Create global checksums
|
|
run: |
|
|
cd release
|
|
sha256sum *.tar.gz > SHA256SUMS
|
|
echo "✅ Global checksums created"
|
|
|
|
- name: Create GitHub Release
|
|
uses: softprops/action-gh-release@v2
|
|
with:
|
|
name: SecuBox ${{ needs.setup.outputs.version }}
|
|
body_path: release/RELEASE_NOTES.md
|
|
files: |
|
|
release/*.tar.gz
|
|
release/SHA256SUMS
|
|
draft: false
|
|
prerelease: ${{ contains(github.ref, 'alpha') || contains(github.ref, 'beta') || contains(github.ref, 'rc') }}
|
|
env:
|
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
# ============================================
|
|
# Build status summary
|
|
# ============================================
|
|
summary:
|
|
needs: [setup, build]
|
|
runs-on: ubuntu-latest
|
|
if: always()
|
|
|
|
steps:
|
|
- name: Download all artifacts
|
|
uses: actions/download-artifact@v4
|
|
with:
|
|
path: packages
|
|
pattern: packages-*
|
|
continue-on-error: true
|
|
|
|
- name: Generate build summary
|
|
run: |
|
|
echo "# 📊 SecuBox Build Summary" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "**Version:** ${{ needs.setup.outputs.version }}" >> $GITHUB_STEP_SUMMARY
|
|
echo "**OpenWrt:** ${{ env.OPENWRT_VERSION }}" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "## Build Results" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "| Architecture | Status | Packages |" >> $GITHUB_STEP_SUMMARY
|
|
echo "|--------------|--------|----------|" >> $GITHUB_STEP_SUMMARY
|
|
|
|
for arch_dir in packages/packages-*/; do
|
|
if [[ -d "$arch_dir" ]]; then
|
|
ARCH=$(basename "$arch_dir" | sed 's/packages-//')
|
|
PKG_COUNT=$(find "$arch_dir" -name "*.ipk" 2>/dev/null | wc -l)
|
|
if [[ $PKG_COUNT -gt 0 ]]; then
|
|
echo "| $ARCH | ✅ Success | $PKG_COUNT |" >> $GITHUB_STEP_SUMMARY
|
|
else
|
|
echo "| $ARCH | ⚠️ No packages | 0 |" >> $GITHUB_STEP_SUMMARY
|
|
fi
|
|
fi
|
|
done
|
|
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "## 📦 Artifacts" >> $GITHUB_STEP_SUMMARY
|
|
echo "" >> $GITHUB_STEP_SUMMARY
|
|
echo "Download artifacts from the Actions tab above." >> $GITHUB_STEP_SUMMARY
|