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' - '24.10.0' - 'SNAPSHOT' architectures: description: 'Architectures (comma-separated or "all")' required: false default: 'x86-64' env: OPENWRT_VERSION: ${{ github.event.inputs.openwrt_version || '23.05.5' }} jobs: # ============================================ # Setup and 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: | cat > /tmp/matrix.json << 'EOF' { "include": [ { "target": "x86-64", "arch": "x86_64", "sdk_path": "x86/64", "description": "x86 64-bit (PC, VM)" }, { "target": "aarch64-cortex-a53", "arch": "aarch64_cortex-a53", "sdk_path": "mvebu/cortexa53", "description": "ARM Cortex-A53 (ESPRESSObin)" }, { "target": "aarch64-cortex-a72", "arch": "aarch64_cortex-a72", "sdk_path": "mvebu/cortexa72", "description": "ARM Cortex-A72 (MOCHAbin)" }, { "target": "aarch64-generic", "arch": "aarch64_generic", "sdk_path": "armsr/armv8", "description": "ARM 64-bit generic" }, { "target": "mips-24kc", "arch": "mips_24kc", "sdk_path": "ath79/generic", "description": "MIPS 24Kc (TP-Link)" }, { "target": "mipsel-24kc", "arch": "mipsel_24kc", "sdk_path": "ramips/mt7621", "description": "MIPS LE (Xiaomi, GL.iNet)" }, { "target": "mediatek-filogic", "arch": "aarch64_cortex-a53", "sdk_path": "mediatek/filogic", "description": "MediaTek Filogic" }, { "target": "rockchip-armv8", "arch": "aarch64_generic", "sdk_path": "rockchip/armv8", "description": "Rockchip (NanoPi R4S)" }, { "target": "bcm27xx-bcm2711", "arch": "aarch64_cortex-a72", "sdk_path": "bcm27xx/bcm2711", "description": "Raspberry Pi 4" } ] } EOF INPUT_ARCHS="${{ github.event.inputs.architectures }}" if [[ -z "$INPUT_ARCHS" || "$INPUT_ARCHS" == "all" ]]; then MATRIX=$(cat /tmp/matrix.json) else MATRIX=$(jq -c --arg archs "$INPUT_ARCHS" ' .include |= map(select(.target as $t | $archs | split(",") | map(gsub("^\\s+|\\s+$";"")) | any(. == $t))) ' /tmp/matrix.json) fi echo "matrix<> $GITHUB_OUTPUT echo "$MATRIX" >> $GITHUB_OUTPUT echo "EOF" >> $GITHUB_OUTPUT echo "๐Ÿ“‹ Build matrix:" echo "$MATRIX" | jq '.' # ============================================ # Build packages # ============================================ 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.target }}-v4 - 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/${{ matrix.sdk_path }}" # Find SDK filename with retry for attempt in 1 2 3; do echo "Attempt $attempt: Fetching SDK list..." SDK_FILE=$(curl -sL --retry 3 --retry-delay 5 "$BASE_URL/" | grep -oP 'openwrt-sdk[^"<>]+\.tar\.(xz|zst)' | head -1) && break sleep 10 done if [[ -z "$SDK_FILE" ]]; then echo "โŒ Could not find SDK" exit 1 fi echo "๐Ÿ“ฅ Downloading: $SDK_FILE" # Download with retry for attempt in 1 2 3; do echo "Download attempt $attempt..." wget -q --retry-connrefused --waitretry=5 --timeout=60 \ "${BASE_URL}/${SDK_FILE}" -O /tmp/sdk.tar.xz && break sleep 15 done # Extract mkdir -p sdk tar -xf /tmp/sdk.tar.xz -C sdk --strip-components=1 rm -f /tmp/sdk.tar.xz echo "โœ… SDK extracted" - name: Setup SDK feeds (GitHub mirrors) run: | cd sdk echo "๐Ÿ“ Configuring feeds with GitHub mirrors..." # Use GitHub mirrors - only essential feeds (no telephony) cat > feeds.conf << 'FEEDS' src-git base https://github.com/openwrt/openwrt.git;openwrt-23.05 src-git packages https://github.com/openwrt/packages.git;openwrt-23.05 src-git luci https://github.com/openwrt/luci.git;openwrt-23.05 FEEDS echo "๐Ÿ“‹ feeds.conf:" cat feeds.conf # Update feeds individually with error handling echo "" echo "๐Ÿ”„ Updating feeds..." FEEDS_OK=0 for feed in base packages luci; do echo "Updating feed: $feed" for attempt in 1 2 3; do if ./scripts/feeds update $feed 2>&1; then echo " โœ… $feed updated" FEEDS_OK=$((FEEDS_OK + 1)) break fi echo " โš ๏ธ Attempt $attempt failed, retrying..." sleep $((10 * attempt)) done done echo "" echo "๐Ÿ“Š Feeds updated: $FEEDS_OK/3" # Install feeds echo "" echo "๐Ÿ“ฆ Installing feeds..." ./scripts/feeds install -a 2>&1 || true # Verify luci.mk exists if [[ -f "feeds/luci/luci.mk" ]]; then echo "โœ… luci.mk found" else echo "โš ๏ธ Creating fallback luci.mk..." mkdir -p feeds/luci cat > feeds/luci/luci.mk << 'LUCI_MK' # Minimal LuCI build system fallback LUCI_PKGARCH:=all define Package/Default SECTION:=luci CATEGORY:=LuCI SUBMENU:=3. Applications PKGARCH:=all endef LUCI_MK fi # Clean up any stale feed references rm -f feeds/telephony.index 2>/dev/null || true rm -rf feeds/telephony 2>/dev/null || true make defconfig echo "โœ… SDK configured" - name: Copy packages to SDK run: | VERSION="${{ needs.setup.outputs.version }}" echo "๐Ÿ“ฆ Copying packages (version: $VERSION)..." for pkg in luci-app-*/; do if [[ -d "$pkg" && -f "${pkg}Makefile" ]]; then PKG_NAME=$(basename "$pkg") echo " ๐Ÿ“ $PKG_NAME" cp -r "$pkg" sdk/package/ # Update version 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 -d sdk/package/luci-app-*/ 2>/dev/null || echo "None" - name: Configure packages run: | cd sdk echo "โš™๏ธ Enabling packages..." for pkg in package/luci-app-*/; do if [[ -d "$pkg" ]]; then PKG_NAME=$(basename "$pkg") echo "CONFIG_PACKAGE_${PKG_NAME}=m" >> .config echo " โœ… $PKG_NAME" fi done make defconfig - name: Build packages run: | cd sdk echo "๐Ÿ”จ Building SecuBox packages..." echo "" BUILT=0 FAILED=0 BUILT_LIST="" FAILED_LIST="" for pkg in package/luci-app-*/; do [[ -d "$pkg" ]] || continue PKG_NAME=$(basename "$pkg") echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "๐Ÿ“ฆ Building: $PKG_NAME" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" # Show package contents for debugging echo "๐Ÿ“ Package contents:" ls -la "$pkg" # Verify Makefile syntax if ! grep -q "BuildPackage" "${pkg}Makefile"; then echo "โš ๏ธ WARNING: Makefile missing BuildPackage call" fi # Build with timeout (10 minutes per package) BUILD_LOG="/tmp/build-${PKG_NAME}.log" if timeout 600 make package/${PKG_NAME}/compile V=s -j$(nproc) > "$BUILD_LOG" 2>&1; then # Check if .ipk was created IPK_FILE=$(find bin -name "${PKG_NAME}*.ipk" 2>/dev/null | head -1) if [[ -n "$IPK_FILE" ]]; then echo "โœ… Built: $PKG_NAME" echo " โ†’ $IPK_FILE" BUILT=$((BUILT + 1)) BUILT_LIST="${BUILT_LIST}${PKG_NAME}," else echo "โš ๏ธ No .ipk generated for $PKG_NAME" echo "๐Ÿ“‹ Last 50 lines of build log:" tail -50 "$BUILD_LOG" FAILED=$((FAILED + 1)) FAILED_LIST="${FAILED_LIST}${PKG_NAME}," fi else echo "โŒ Build failed: $PKG_NAME" echo "๐Ÿ“‹ Last 100 lines of build log:" tail -100 "$BUILD_LOG" FAILED=$((FAILED + 1)) FAILED_LIST="${FAILED_LIST}${PKG_NAME}," fi echo "" done echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "๐Ÿ“Š Build Summary" echo "โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”" echo "โœ… Built: $BUILT packages" echo "โŒ Failed: $FAILED packages" echo "" echo "Built: $BUILT_LIST" if [[ -n "$FAILED_LIST" ]]; then echo "Failed: $FAILED_LIST" fi - name: Collect artifacts id: collect run: | echo "๐Ÿ“ฆ Collecting artifacts..." mkdir -p artifacts/${{ matrix.target }} # Find and copy .ipk files find sdk/bin -name "luci-app-*.ipk" -exec cp {} artifacts/${{ matrix.target }}/ \; 2>/dev/null || true # Also collect any SecuBox related packages find sdk/bin -name "*secubox*.ipk" -exec cp {} artifacts/${{ matrix.target }}/ \; 2>/dev/null || true # Count PKG_COUNT=$(find artifacts/${{ matrix.target }} -name "*.ipk" 2>/dev/null | wc -l) echo "pkg_count=$PKG_COUNT" >> $GITHUB_OUTPUT echo "" echo "๐Ÿ“‹ Built packages for ${{ matrix.target }}:" ls -la artifacts/${{ matrix.target }}/ 2>/dev/null || echo "No packages" # Create checksums if [[ $PKG_COUNT -gt 0 ]]; then cd artifacts/${{ matrix.target }} sha256sum *.ipk > SHA256SUMS fi echo "" echo "๐Ÿ“ฆ Total: $PKG_COUNT packages" - name: Upload artifacts uses: actions/upload-artifact@v4 if: steps.collect.outputs.pkg_count > 0 with: name: packages-${{ matrix.target }} path: artifacts/${{ matrix.target }}/ retention-days: 30 - name: Build Summary run: | PKG_COUNT="${{ steps.collect.outputs.pkg_count }}" echo "## ๐Ÿ“ฆ Build Results: ${{ matrix.target }}" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "| Property | Value |" >> $GITHUB_STEP_SUMMARY echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY echo "| Target | ${{ matrix.description }} |" >> $GITHUB_STEP_SUMMARY echo "| Architecture | ${{ matrix.arch }} |" >> $GITHUB_STEP_SUMMARY echo "| SDK Path | ${{ matrix.sdk_path }} |" >> $GITHUB_STEP_SUMMARY echo "| Packages Built | $PKG_COUNT |" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY if [[ "$PKG_COUNT" -gt 0 ]]; then echo "### Built Packages" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo '```' >> $GITHUB_STEP_SUMMARY ls artifacts/${{ matrix.target }}/*.ipk 2>/dev/null | xargs -I{} basename {} | sort echo '```' >> $GITHUB_STEP_SUMMARY fi # ============================================ # Publish combined artifacts (always) # ============================================ publish-artifacts: needs: [setup, build] runs-on: ubuntu-latest if: always() && needs.build.result == 'success' steps: - name: Download all artifacts uses: actions/download-artifact@v4 with: path: packages pattern: packages-* - name: Create combined archives run: | VERSION="${{ needs.setup.outputs.version }}" mkdir -p release echo "๐Ÿ“ Creating combined archives..." # Per-architecture archives for dir in packages/packages-*/; do [[ -d "$dir" ]] || continue ARCH=$(basename "$dir" | sed 's/packages-//') echo "๐Ÿ“ฆ $ARCH" # Copy .ipk files to release mkdir -p "release/${ARCH}" cp "$dir"/*.ipk "release/${ARCH}/" 2>/dev/null || true # Create archive if ls "release/${ARCH}"/*.ipk >/dev/null 2>&1; then tar -czf "release/secubox-${VERSION}-${ARCH}.tar.gz" -C "release/${ARCH}" . fi done # Create all-in-one archive tar -czf "release/secubox-${VERSION}-all-architectures.tar.gz" -C packages . # Checksums cd release sha256sum *.tar.gz > SHA256SUMS 2>/dev/null || true echo "" echo "๐Ÿ“‹ Release contents:" ls -la echo "" echo "๐Ÿ“Š Package count per architecture:" for dir in */; do [[ -d "$dir" ]] || continue COUNT=$(ls "$dir"/*.ipk 2>/dev/null | wc -l) echo " ${dir%/}: $COUNT packages" done - name: Upload combined release uses: actions/upload-artifact@v4 with: name: secubox-release-${{ needs.setup.outputs.version }} path: | release/*.tar.gz release/SHA256SUMS retention-days: 90 - name: Upload individual .ipk files uses: actions/upload-artifact@v4 with: name: secubox-all-ipk-${{ needs.setup.outputs.version }} path: release/*/*.ipk retention-days: 90 # ============================================ # Create GitHub Release (on tags or manual) # ============================================ release: needs: [setup, build, publish-artifacts] runs-on: ubuntu-latest if: startsWith(github.ref, 'refs/tags/v') || github.event_name == 'workflow_dispatch' steps: - name: Checkout uses: actions/checkout@v4 - name: Download release artifact uses: actions/download-artifact@v4 with: name: secubox-release-${{ needs.setup.outputs.version }} path: release - name: Download all .ipk files uses: actions/download-artifact@v4 with: name: secubox-all-ipk-${{ needs.setup.outputs.version }} path: ipk-files continue-on-error: true - name: List packages id: list-packages run: | echo "๐Ÿ“ฆ Packages in release:" find . -name "*.ipk" -exec basename {} \; | sort -u # Count unique packages PKG_LIST=$(find . -name "*.ipk" -exec basename {} \; | sort -u | sed 's/_[0-9].*//g' | sort -u | tr '\n' ', ' | sed 's/,$//') echo "packages=$PKG_LIST" >> $GITHUB_OUTPUT - name: Create GitHub Release uses: softprops/action-gh-release@v2 with: name: SecuBox ${{ needs.setup.outputs.version }} tag_name: ${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || format('v{0}', needs.setup.outputs.version) }} body: | ## ๐Ÿ“ฆ SecuBox Packages v${{ needs.setup.outputs.version }} Pre-built LuCI packages for OpenWrt ${{ env.OPENWRT_VERSION }}. ### โœ… Built Packages ${{ steps.list-packages.outputs.packages }} ### ๐Ÿ“ฅ Installation ```bash # Download the archive for your architecture # Extract and upload .ipk files to router opkg update opkg install /tmp/luci-app-*.ipk # Restart services /etc/init.d/rpcd restart ``` ### ๐Ÿ—๏ธ Supported Architectures - `x86-64` - PC, VMs, Proxmox - `aarch64-cortex-a72` - MOCHAbin, RPi4 - `aarch64-cortex-a53` - ESPRESSObin - `aarch64-generic` - Generic ARM64 - `mips-24kc` - TP-Link, ath79 - `mipsel-24kc` - Xiaomi, GL.iNet - `mediatek-filogic` - MT7981/MT7986 ### ๐Ÿ”— Links - [SecuBox Website](https://secubox.cybermood.eu) - [CyberMind.fr](https://cybermind.fr) files: | release/*.tar.gz release/SHA256SUMS draft: false prerelease: ${{ github.event_name == 'workflow_dispatch' }} env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # ============================================ # Final Summary # ============================================ summary: needs: [setup, build] runs-on: ubuntu-latest if: always() steps: - name: Download artifacts uses: actions/download-artifact@v4 with: path: packages pattern: packages-* continue-on-error: true - name: Generate summary run: | echo "# ๐Ÿ“Š SecuBox Build Summary" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "| Property | Value |" >> $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 "| Triggered by | ${{ github.event_name }} |" >> $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 TOTAL=0 for dir in packages/packages-*/; do if [[ -d "$dir" ]]; then ARCH=$(basename "$dir" | sed 's/packages-//') COUNT=$(find "$dir" -name "*.ipk" 2>/dev/null | wc -l) TOTAL=$((TOTAL + COUNT)) if [[ $COUNT -gt 0 ]]; then echo "| $ARCH | โœ… Success | $COUNT |" >> $GITHUB_STEP_SUMMARY else echo "| $ARCH | โš ๏ธ Empty | 0 |" >> $GITHUB_STEP_SUMMARY fi fi done echo "" >> $GITHUB_STEP_SUMMARY echo "**Total packages built: $TOTAL**" >> $GITHUB_STEP_SUMMARY