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: 'aarch64-cortex-a72' 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 }} packages: ${{ steps.packages.outputs.list }} 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: List packages to build id: packages run: | # Find all luci-app-* directories with Makefile PACKAGES="" for pkg in luci-app-*/; do if [[ -f "${pkg}Makefile" ]]; then PKG_NAME=$(basename "$pkg") PACKAGES="${PACKAGES}${PKG_NAME}," echo "๐Ÿ“ฆ Found: $PKG_NAME" fi done # Remove trailing comma PACKAGES="${PACKAGES%,}" echo "list=${PACKAGES}" >> $GITHUB_OUTPUT echo "๐Ÿ“‹ Packages to build: $PACKAGES" - name: Set build matrix id: set-matrix run: | cat > /tmp/matrix.json << 'MATRIX_EOF' { "include": [ { "target": "x86-64", "arch": "x86_64", "sdk_name": "x86-64", "description": "x86 64-bit (PC, VM, containers)" }, { "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)" }, { "target": "aarch64-generic", "arch": "aarch64_generic", "sdk_name": "armsr-armv8", "description": "ARM 64-bit generic (RPi4, Rock64)" }, { "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": "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": "mediatek-filogic", "arch": "aarch64_cortex-a53", "sdk_name": "mediatek-filogic", "description": "MediaTek Filogic (MT7981, MT7986)" }, { "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" } ] } MATRIX_EOF INPUT_ARCHS="${{ github.event.inputs.architectures }}" if [[ -z "$INPUT_ARCHS" || "$INPUT_ARCHS" == "all" ]]; then MATRIX=$(cat /tmp/matrix.json | jq -c '.') else MATRIX=$(cat /tmp/matrix.json | 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<> $GITHUB_OUTPUT echo "$MATRIX" >> $GITHUB_OUTPUT echo "EOF" >> $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 /usr/local/lib/android /opt/ghc /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 }}-v2 - name: Download OpenWrt SDK if: steps.cache-sdk.outputs.cache-hit != 'true' run: | echo "๐Ÿ“ฅ Downloading SDK for ${{ matrix.description }}..." BASE_URL="https://downloads.openwrt.org/releases/${{ env.OPENWRT_VERSION }}/targets" # Map sdk_name to target/subtarget case "${{ matrix.sdk_name }}" in x86-64) TARGET_PATH="x86/64" ;; x86-generic) TARGET_PATH="x86/generic" ;; mvebu-cortexa53) TARGET_PATH="mvebu/cortexa53" ;; mvebu-cortexa72) TARGET_PATH="mvebu/cortexa72" ;; mvebu-cortexa9) TARGET_PATH="mvebu/cortexa9" ;; armsr-armv8) TARGET_PATH="armsr/armv8" ;; sunxi-cortexa7) TARGET_PATH="sunxi/cortexa7" ;; ath79-generic) TARGET_PATH="ath79/generic" ;; ramips-mt7621) TARGET_PATH="ramips/mt7621" ;; bcm47xx-mips74k) TARGET_PATH="bcm47xx/mips74k" ;; mediatek-filogic) TARGET_PATH="mediatek/filogic" ;; ipq40xx-generic) TARGET_PATH="ipq40xx/generic" ;; ipq806x-generic) TARGET_PATH="ipq806x/generic" ;; rockchip-armv8) TARGET_PATH="rockchip/armv8" ;; bcm27xx-bcm2711) TARGET_PATH="bcm27xx/bcm2711" ;; armvirt-32) TARGET_PATH="armvirt/32" ;; *) echo "โŒ Unknown SDK: ${{ matrix.sdk_name }}" exit 1 ;; esac SDK_URL="${BASE_URL}/${TARGET_PATH}" 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 for ${{ matrix.sdk_name }}" exit 1 fi echo "๐Ÿ“ฅ Downloading: $SDK_FILE" wget -q "${SDK_URL}/${SDK_FILE}" -O /tmp/sdk.tar.xz || \ wget -q "${SDK_URL}/${SDK_FILE}" -O /tmp/sdk.tar.zst # Extract mkdir -p ~/sdk if [[ -f /tmp/sdk.tar.xz ]]; then tar -xf /tmp/sdk.tar.xz -C ~/sdk --strip-components=1 else tar --zstd -xf /tmp/sdk.tar.zst -C ~/sdk --strip-components=1 fi echo "โœ… SDK extracted" - name: Setup SDK feeds run: | cd ~/sdk # Update and install feeds ./scripts/feeds update -a ./scripts/feeds install -a # Base config make defconfig echo "โœ… SDK feeds configured" - name: Copy packages to SDK run: | VERSION="${{ needs.setup.outputs.version }}" echo "๐Ÿ“ฆ Copying SecuBox packages (version: $VERSION)..." # IMPORTANT: Copy packages directly into package/, NOT into a subdirectory for pkg in luci-app-*/; do if [[ -d "$pkg" && -f "${pkg}Makefile" ]]; then PKG_NAME=$(basename "$pkg") echo " ๐Ÿ“ Copying $PKG_NAME..." cp -r "$pkg" ~/sdk/package/ # Update version in Makefile sed -i "s/PKG_VERSION:=.*/PKG_VERSION:=$VERSION/" ~/sdk/package/${PKG_NAME}/Makefile sed -i "s/PKG_RELEASE:=.*/PKG_RELEASE:=1/" ~/sdk/package/${PKG_NAME}/Makefile fi done echo "" echo "๐Ÿ“‹ Packages in SDK:" ls -la ~/sdk/package/luci-app-* 2>/dev/null || echo "No luci-app packages found" - name: Configure packages run: | cd ~/sdk echo "โš™๏ธ Enabling packages in config..." # Enable each package for pkg in ~/sdk/package/luci-app-*/; do if [[ -d "$pkg" ]]; then PKG_NAME=$(basename "$pkg") echo "CONFIG_PACKAGE_${PKG_NAME}=m" >> .config echo " โœ… Enabled: $PKG_NAME" fi done make defconfig echo "" echo "๐Ÿ“‹ Enabled packages:" grep "CONFIG_PACKAGE_luci-app" .config | head -20 - name: Build packages run: | cd ~/sdk echo "๐Ÿ”จ Building SecuBox packages for ${{ matrix.description }}..." echo "" BUILD_ERRORS=0 BUILT_PACKAGES="" # Build each package individually for pkg in ~/sdk/package/luci-app-*/; do if [[ -d "$pkg" ]]; then PKG_NAME=$(basename "$pkg") echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "๐Ÿ“ฆ Building: $PKG_NAME" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" # Build the specific package if make package/${PKG_NAME}/compile V=s -j$(nproc) 2>&1; then echo "โœ… Successfully built: $PKG_NAME" BUILT_PACKAGES="${BUILT_PACKAGES}${PKG_NAME}," else echo "โš ๏ธ Failed to build: $PKG_NAME, retrying with -j1..." if make package/${PKG_NAME}/compile V=s -j1 2>&1; then echo "โœ… Successfully built on retry: $PKG_NAME" BUILT_PACKAGES="${BUILT_PACKAGES}${PKG_NAME}," else echo "โŒ Failed to build: $PKG_NAME" BUILD_ERRORS=$((BUILD_ERRORS + 1)) fi fi echo "" fi done # Generate package index make package/index V=s || true echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "๐Ÿ“Š Build Summary" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "Built packages: $BUILT_PACKAGES" echo "Build errors: $BUILD_ERRORS" if [[ $BUILD_ERRORS -gt 0 ]]; then echo "โš ๏ธ Some packages failed to build" fi - 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 "luci-app-*.ipk" -exec cp {} $GITHUB_WORKSPACE/artifacts/${{ matrix.target }}/ \; # Also copy any dependency packages we might have built find ~/sdk/bin -name "*.ipk" -exec cp {} $GITHUB_WORKSPACE/artifacts/${{ matrix.target }}/ \; 2>/dev/null || true # Remove duplicates (keep largest) cd $GITHUB_WORKSPACE/artifacts/${{ matrix.target }} for f in *.ipk; do [[ -f "$f" ]] || continue done # Copy package index find ~/sdk/bin -name "Packages*" -exec cp {} $GITHUB_WORKSPACE/artifacts/${{ matrix.target }}/ \; 2>/dev/null || true # List artifacts echo "" echo "๐Ÿ“‹ Built packages for ${{ matrix.target }}:" ls -la $GITHUB_WORKSPACE/artifacts/${{ matrix.target }}/ # Count packages PKG_COUNT=$(find $GITHUB_WORKSPACE/artifacts/${{ matrix.target }} -name "luci-app-*.ipk" | wc -l) echo "pkg_count=$PKG_COUNT" >> $GITHUB_OUTPUT echo "" echo "๐Ÿ“ฆ Total SecuBox packages built: $PKG_COUNT" if [[ $PKG_COUNT -eq 0 ]]; then echo "โš ๏ธ No packages were built!" exit 1 fi - name: Create checksums run: | cd $GITHUB_WORKSPACE/artifacts/${{ matrix.target }} sha256sum *.ipk > SHA256SUMS 2>/dev/null || echo "No .ipk files to checksum" 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..." tar -czf "release/secubox-${VERSION}-${ARCH}.tar.gz" -C "$arch_dir" . 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 Packages v${{ needs.setup.outputs.version }} ## ๐Ÿ“ฆ Included Packages | Package | Description | |---------|-------------| | luci-app-secubox | SecuBox Hub - Central Dashboard | | luci-app-crowdsec-dashboard | CrowdSec Security Dashboard | | luci-app-netdata-dashboard | Netdata Monitoring | | 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 Control Center | | luci-app-bandwidth-manager | QoS & Bandwidth Control | | luci-app-auth-guardian | OAuth & Voucher Portal | | luci-app-media-flow | Streaming DPI | | luci-app-vhost-manager | Reverse Proxy Manager | | luci-app-cdn-cache | Local CDN Cache | ## ๐Ÿ“ฅ Installation ```bash # Upload .ipk to router, then: opkg update opkg install /tmp/luci-app-secubox_*.ipk ``` ## ๐Ÿ”— Links - [SecuBox Website](https://secubox.cybermood.eu) - [Documentation](https://cybermind.fr/docs/secubox) - [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 - 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 "luci-app-*.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