diff --git a/.github/workflows/build-fio.yml b/.github/workflows/build-fio.yml new file mode 100644 index 0000000..8ecd08f --- /dev/null +++ b/.github/workflows/build-fio.yml @@ -0,0 +1,360 @@ +name: Build fio Static Binaries + +on: + workflow_dispatch: + +jobs: + check-release: + runs-on: ubuntu-latest + outputs: + latest-version: ${{ steps.get-version.outputs.version }} + should-build: ${{ steps.check-version.outputs.should-build }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Get latest fio release + id: get-version + run: | + # Get the latest release tag from GitHub API + LATEST_VERSION=$(curl -s https://api.github.com/repos/axboe/fio/releases/latest | jq -r '.tag_name') + echo "Latest fio version: $LATEST_VERSION" + echo "version=$LATEST_VERSION" >> $GITHUB_OUTPUT + + - name: Check if version exists in releases + id: check-version + run: | + VERSION="${{ steps.get-version.outputs.version }}" + + # Check if this version already exists in our releases + if gh release view "fio-$VERSION" --repo ${{ github.repository }} >/dev/null 2>&1; then + echo "Version $VERSION already exists in releases" + echo "should-build=false" >> $GITHUB_OUTPUT + else + echo "Version $VERSION does not exist, should build" + echo "should-build=true" >> $GITHUB_OUTPUT + fi + env: + GH_TOKEN: ${{ github.token }} + + build: + needs: check-release + if: needs.check-release.outputs.should-build == 'true' + runs-on: ubuntu-latest + strategy: + matrix: + include: + - arch: x64 + cross: x86_64-linux-musl + host: x86_64-linux-musl + - arch: x86 + cross: i686-linux-musl + host: i686-linux-musl + - arch: aarch64 + cross: aarch64-linux-musl + host: aarch64-linux-gnu + - arch: arm + cross: arm-linux-musleabihf + host: arm-linux-gnueabihf + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Create compilation script + run: | + VERSION="${{ needs.check-release.outputs.latest-version }}" + ARCH="${{ matrix.arch }}" + CROSS="${{ matrix.cross }}" + HOST="${{ matrix.host }}" + + # Single script for all architectures using musl cross-compilation + cat > compile-fio.sh << EOF + #!/bin/bash + set -e + + # Activate Holy Build Box lib compilation environment + source /hbb/activate + + set -x + + # remove obsolete CentOS repos + cd /etc/yum.repos.d/ + rm -f CentOS-Base.repo CentOS-SCLo-scl-rh.repo CentOS-SCLo-scl.repo CentOS-fasttrack.repo CentOS-x86_64-kernel.repo + + yum install -y yum-plugin-ovl # fix for docker overlay fs + yum install -y xz + + # download musl cross compilation toolchain + cd ~ + curl -L "https://musl.cc/\$CROSS-cross.tgz" -o "\$CROSS-cross.tgz" + tar xf "\$CROSS-cross.tgz" + + # download, compile, and install libaio as static library + cd ~ + curl -L http://ftp.de.debian.org/debian/pool/main/liba/libaio/libaio_0.3.113.orig.tar.gz -o "libaio.tar.gz" + tar xf libaio.tar.gz + cd libaio-*/src + CC=/root/\$CROSS-cross/bin/\$CROSS-gcc ENABLE_SHARED=0 make prefix=/hbb_exe install + + # Activate Holy Build Box exe compilation environment + source /hbb_exe/activate + + # download and compile fio + cd ~ + curl -L "https://github.com/axboe/fio/archive/\$VERSION.tar.gz" -o "fio.tar.gz" + tar xf fio.tar.gz + cd fio-\${VERSION#fio-}* + CC=/root/\$CROSS-cross/bin/\$CROSS-gcc ./configure --disable-native --build-static + make + + # verify no external shared library links + libcheck fio + # copy fio binary to mounted dir + cp fio "/io/fio_\$ARCH" + EOF + + chmod +x compile-fio.sh + + - name: Compile fio binary + run: | + ARCH="${{ matrix.arch }}" + CROSS="${{ matrix.cross }}" + HOST="${{ matrix.host }}" + + # Use musl cross-compilation for all architectures + docker run -t -i --rm -v $(pwd):/io --env ARCH=$ARCH --env CROSS=$CROSS --env HOST=$HOST --env VERSION="${{ needs.check-release.outputs.latest-version }}" phusion/holy-build-box-64:latest bash /io/compile-fio.sh + + - name: Verify binary + run: | + ARCH="${{ matrix.arch }}" + ls -la fio_$ARCH + file fio_$ARCH + + - name: Upload binary as artifact + uses: actions/upload-artifact@v4 + with: + name: fio_${{ matrix.arch }} + path: fio_${{ matrix.arch }} + retention-days: 1 + + virustotal-scan: + needs: [check-release, build] + if: needs.check-release.outputs.should-build == 'true' + runs-on: ubuntu-latest + outputs: + scan-results: ${{ steps.scan-summary.outputs.results }} + all-clean: ${{ steps.scan-summary.outputs.all-clean }} + steps: + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: Prepare binaries for scanning + run: | + mkdir -p scan-binaries + find artifacts -name "fio_*" -type f -exec cp {} scan-binaries/ \; + ls -la scan-binaries/ + + - name: Upload binaries to VirusTotal and scan + id: virustotal-upload + run: | + echo "## VirusTotal Scan Results" > scan_results.md + echo "| Binary | Status | Malicious | Suspicious | Undetected | VirusTotal URL |" >> scan_results.md + echo "|--------|--------|-----------|------------|------------|----------------|" >> scan_results.md + + ALL_CLEAN=true + SCAN_DATA="" + + for binary in scan-binaries/fio_*; do + filename=$(basename "$binary") + echo "Uploading $filename to VirusTotal..." + + # Upload to VirusTotal + upload_response=$(curl -s --request POST \ + --url https://www.virustotal.com/api/v3/files \ + --header 'accept: application/json' \ + --header 'content-type: multipart/form-data' \ + --header "x-apikey: ${{ secrets.VIRUSTOTAL_API_KEY }}" \ + --form "file=@$binary") + + analysis_id=$(echo "$upload_response" | jq -r '.data.id') + echo "Analysis ID for $filename: $analysis_id" + + if [ "$analysis_id" = "null" ] || [ -z "$analysis_id" ]; then + echo "Failed to upload $filename to VirusTotal" + echo "| $filename | Upload Failed | N/A | N/A | N/A | N/A |" >> scan_results.md + ALL_CLEAN=false + continue + fi + + # Store analysis ID for later retrieval + echo "${filename}:${analysis_id}" >> analysis_ids.txt + done + + echo "all_clean_upload=$ALL_CLEAN" >> $GITHUB_OUTPUT + + # Wait 2 minutes for scans to complete + echo "Waiting 2 minutes for VirusTotal scans to complete..." + sleep 120 + + - name: Retrieve VirusTotal scan results + id: get-results + run: | + ALL_CLEAN=true + SCAN_SUMMARY="" + + while IFS=':' read -r filename analysis_id; do + echo "Retrieving results for $filename (ID: $analysis_id)..." + + # Get scan results + result_response=$(curl -s --request GET \ + --url "https://www.virustotal.com/api/v3/analyses/$analysis_id" \ + --header 'accept: application/json' \ + --header "x-apikey: ${{ secrets.VIRUSTOTAL_API_KEY }}") + + status=$(echo "$result_response" | jq -r '.data.attributes.status // "unknown"') + + if [ "$status" = "completed" ]; then + malicious=$(echo "$result_response" | jq -r '.data.attributes.stats.malicious // 0') + suspicious=$(echo "$result_response" | jq -r '.data.attributes.stats.suspicious // 0') + undetected=$(echo "$result_response" | jq -r '.data.attributes.stats.undetected // 0') + + # Get file hash from the item link + item_link=$(echo "$result_response" | jq -r '.data.links.item // ""') + file_hash=$(echo "$item_link" | sed 's/.*files\///') + vt_url="https://www.virustotal.com/gui/file/$file_hash" + + if [ "$malicious" -gt 0 ] || [ "$suspicious" -gt 0 ]; then + status_text="⚠️ FLAGGED" + ALL_CLEAN=false + else + status_text="✅ Clean" + fi + + echo "| $filename | $status_text | $malicious | $suspicious | $undetected | [$file_hash]($vt_url) |" >> scan_results.md + + else + echo "| $filename | ⏳ Pending | N/A | N/A | N/A | Scan not completed |" >> scan_results.md + ALL_CLEAN=false + fi + + done < analysis_ids.txt + + echo "all_clean=$ALL_CLEAN" >> $GITHUB_OUTPUT + + # Add summary to GitHub step summary + cat scan_results.md >> $GITHUB_STEP_SUMMARY + + - name: Create scan summary + id: scan-summary + run: | + RESULTS=$(cat scan_results.md) + ALL_CLEAN="${{ steps.get-results.outputs.all_clean }}" + + # Escape newlines for GitHub output + RESULTS_ESCAPED=$(echo "$RESULTS" | sed ':a;N;$!ba;s/\n/\\n/g') + + echo "results=$RESULTS_ESCAPED" >> $GITHUB_OUTPUT + echo "all-clean=$ALL_CLEAN" >> $GITHUB_OUTPUT + + - name: Upload scan results as artifact + uses: actions/upload-artifact@v4 + with: + name: virustotal-scan-results + path: | + scan_results.md + analysis_ids.txt + retention-days: 30 + + create-release: + needs: [check-release, build, virustotal-scan] + if: needs.check-release.outputs.should-build == 'true' && needs.virustotal-scan.outputs.all-clean == 'true' + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: Prepare release assets + run: | + mkdir -p release-assets + # Move all binaries to release-assets directory + find artifacts -name "fio_*" -type f -exec cp {} release-assets/ \; + ls -la release-assets/ + + - name: Generate SHA256 checksums + run: | + cd release-assets + sha256sum fio_* > fio-checksums.sha256 + cat fio-checksums.sha256 + + - name: Download VirusTotal scan results + uses: actions/download-artifact@v4 + with: + name: virustotal-scan-results + path: vt-results + + - name: Create Release + uses: softprops/action-gh-release@v1 + with: + tag_name: fio-${{ needs.check-release.outputs.latest-version }} + name: fio ${{ needs.check-release.outputs.latest-version }} Static Binaries + body: | + Static binaries for fio ${{ needs.check-release.outputs.latest-version }} + + Built using musl toolchains for maximum compatibility. + + **Architectures:** + - `fio_x64` - x86_64 (64-bit) + - `fio_x86` - i686 (32-bit) + - `fio_aarch64` - ARM 64-bit + - `fio_arm` - ARM 32-bit + + **Security Verification:** + All binaries have been scanned by VirusTotal and verified clean. + + ${{ needs.virustotal-scan.outputs.scan-results }} + + **Checksum Verification:** + ```bash + # Verify checksums + sha256sum -c fio-checksums.sha256 + ``` + + For usage in YABS script, place these binaries in the `bin/fio/` directory. + files: | + release-assets/fio_* + release-assets/fio-checksums.sha256 + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + notify-failure: + needs: [check-release, build, virustotal-scan] + if: always() && needs.check-release.outputs.should-build == 'true' && (failure() || needs.virustotal-scan.outputs.all-clean == 'false') + runs-on: ubuntu-latest + steps: + - name: Send failure notification + run: | + echo "## ⚠️ fio Build Failed" >> $GITHUB_STEP_SUMMARY + echo "Version: ${{ needs.check-release.outputs.latest-version }}" >> $GITHUB_STEP_SUMMARY + + if [ "${{ needs.virustotal-scan.outputs.all-clean }}" == "false" ]; then + echo "**Reason:** VirusTotal scan detected issues with one or more binaries" >> $GITHUB_STEP_SUMMARY + echo "**Scan Results:**" >> $GITHUB_STEP_SUMMARY + echo "${{ needs.virustotal-scan.outputs.scan-results }}" >> $GITHUB_STEP_SUMMARY + else + echo "**Reason:** Build compilation failed" >> $GITHUB_STEP_SUMMARY + fi + + echo "Check the workflow logs for details: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/build-iperf3.yml b/.github/workflows/build-iperf3.yml new file mode 100644 index 0000000..f2aede6 --- /dev/null +++ b/.github/workflows/build-iperf3.yml @@ -0,0 +1,388 @@ +name: Build iperf3 Static Binaries + +on: + workflow_dispatch: + +jobs: + check-release: + runs-on: ubuntu-latest + outputs: + latest-version: ${{ steps.get-version.outputs.version }} + should-build: ${{ steps.check-version.outputs.should-build }} + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Get latest iperf3 release + id: get-version + run: | + # Get the latest release tag from GitHub API + LATEST_VERSION=$(curl -s https://api.github.com/repos/esnet/iperf/releases/latest | jq -r '.tag_name') + echo "Latest iperf3 version: $LATEST_VERSION" + echo "version=$LATEST_VERSION" >> $GITHUB_OUTPUT + + - name: Check if version exists in releases + id: check-version + run: | + VERSION="${{ steps.get-version.outputs.version }}" + + # Check if this version already exists in our releases + if gh release view "iperf3-$VERSION" --repo ${{ github.repository }} >/dev/null 2>&1; then + echo "Version $VERSION already exists in releases" + echo "should-build=false" >> $GITHUB_OUTPUT + else + echo "Version $VERSION does not exist, should build" + echo "should-build=true" >> $GITHUB_OUTPUT + fi + env: + GH_TOKEN: ${{ github.token }} + + build: + needs: check-release + if: needs.check-release.outputs.should-build == 'true' + runs-on: ubuntu-latest + strategy: + matrix: + include: + - arch: x64 + cross: x86_64-linux-musl + host: x86_64-linux-musl + - arch: x86 + cross: i686-linux-musl + host: i686-linux-musl + - arch: aarch64 + cross: aarch64-linux-musl + host: aarch64-linux-gnu + # Note: ARM 32-bit compilation of iperf3 >3.15 has known issues + # We'll still attempt it but expect potential failures + - arch: arm + cross: arm-linux-musleabihf + host: arm-linux-gnueabihf + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Create compilation script + run: | + VERSION="${{ needs.check-release.outputs.latest-version }}" + ARCH="${{ matrix.arch }}" + CROSS="${{ matrix.cross }}" + HOST="${{ matrix.host }}" + + # Single script for all architectures using musl cross-compilation + cat > compile-iperf3.sh << EOF + #!/bin/bash + set -e + + # Activate Holy Build Box lib compilation environment + source /hbb/activate + + set -x + + # remove obsolete CentOS repos + cd /etc/yum.repos.d/ + rm -f CentOS-Base.repo CentOS-SCLo-scl-rh.repo CentOS-SCLo-scl.repo CentOS-fasttrack.repo CentOS-x86_64-kernel.repo + + yum install -y yum-plugin-ovl # fix for docker overlay fs + yum install -y xz + + # download musl cross compilation toolchain + cd ~ + curl -L "https://musl.cc/\$CROSS-cross.tgz" -o "\$CROSS-cross.tgz" + tar xf "\$CROSS-cross.tgz" + + # Activate Holy Build Box exe compilation environment + source /hbb_exe/activate + + # download and compile iperf3 + cd ~ + curl -L "https://github.com/esnet/iperf/archive/\$VERSION.tar.gz" -o "iperf.tar.gz" + tar xf iperf.tar.gz + cd iperf-* + CC=/root/\$CROSS-cross/bin/\$CROSS-gcc ./configure --disable-shared --disable-profiling --build x86_64-pc-linux-gnu --host "\$HOST" --with-openssl=no --enable-static-bin + make + + # verify no external shared library links + libcheck src/iperf3 + # copy iperf3 binary to mounted dir + cp src/iperf3 "/io/iperf3_\$ARCH" + EOF + + chmod +x compile-iperf3.sh + + - name: Compile iperf3 binary + run: | + ARCH="${{ matrix.arch }}" + CROSS="${{ matrix.cross }}" + HOST="${{ matrix.host }}" + + # Use musl cross-compilation for all architectures + docker run -t -i --rm -v $(pwd):/io --env ARCH=$ARCH --env CROSS=$CROSS --env HOST=$HOST --env VERSION="${{ needs.check-release.outputs.latest-version }}" phusion/holy-build-box-64:latest bash /io/compile-iperf3.sh + + - name: Verify binary + run: | + ARCH="${{ matrix.arch }}" + ls -la iperf3_$ARCH + file iperf3_$ARCH + + - name: Upload binary as artifact + uses: actions/upload-artifact@v4 + with: + name: iperf3_${{ matrix.arch }} + path: iperf3_${{ matrix.arch }} + retention-days: 1 + # Allow arm builds to fail as ARM 32-bit has known compilation issues with newer versions + continue-on-error: ${{ matrix.arch == 'arm' }} + + virustotal-scan: + needs: [check-release, build] + if: needs.check-release.outputs.should-build == 'true' + runs-on: ubuntu-latest + outputs: + scan-results: ${{ steps.scan-summary.outputs.results }} + all-clean: ${{ steps.scan-summary.outputs.all-clean }} + steps: + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + continue-on-error: true + + - name: Prepare binaries for scanning + run: | + mkdir -p scan-binaries + find artifacts -name "iperf3_*" -type f -exec cp {} scan-binaries/ \; || true + ls -la scan-binaries/ + + # Check if we have at least the x64 binary + if [ ! -f "scan-binaries/iperf3_x64" ]; then + echo "Error: No iperf3_x64 binary found" + exit 1 + fi + + - name: Upload binaries to VirusTotal and scan + id: virustotal-upload + run: | + echo "## VirusTotal Scan Results" > scan_results.md + echo "| Binary | Status | Malicious | Suspicious | Undetected | VirusTotal URL |" >> scan_results.md + echo "|--------|--------|-----------|------------|------------|----------------|" >> scan_results.md + + ALL_CLEAN=true + SCAN_DATA="" + + for binary in scan-binaries/iperf3_*; do + filename=$(basename "$binary") + echo "Uploading $filename to VirusTotal..." + + # Upload to VirusTotal + upload_response=$(curl -s --request POST \ + --url https://www.virustotal.com/api/v3/files \ + --header 'accept: application/json' \ + --header 'content-type: multipart/form-data' \ + --header "x-apikey: ${{ secrets.VIRUSTOTAL_API_KEY }}" \ + --form "file=@$binary") + + analysis_id=$(echo "$upload_response" | jq -r '.data.id') + echo "Analysis ID for $filename: $analysis_id" + + if [ "$analysis_id" = "null" ] || [ -z "$analysis_id" ]; then + echo "Failed to upload $filename to VirusTotal" + echo "| $filename | Upload Failed | N/A | N/A | N/A | N/A |" >> scan_results.md + ALL_CLEAN=false + continue + fi + + # Store analysis ID for later retrieval + echo "${filename}:${analysis_id}" >> analysis_ids.txt + done + + echo "all_clean_upload=$ALL_CLEAN" >> $GITHUB_OUTPUT + + # Wait 2 minutes for scans to complete + echo "Waiting 2 minutes for VirusTotal scans to complete..." + sleep 120 + + - name: Retrieve VirusTotal scan results + id: get-results + run: | + ALL_CLEAN=true + SCAN_SUMMARY="" + + while IFS=':' read -r filename analysis_id; do + echo "Retrieving results for $filename (ID: $analysis_id)..." + + # Get scan results + result_response=$(curl -s --request GET \ + --url "https://www.virustotal.com/api/v3/analyses/$analysis_id" \ + --header 'accept: application/json' \ + --header "x-apikey: ${{ secrets.VIRUSTOTAL_API_KEY }}") + + status=$(echo "$result_response" | jq -r '.data.attributes.status // "unknown"') + + if [ "$status" = "completed" ]; then + malicious=$(echo "$result_response" | jq -r '.data.attributes.stats.malicious // 0') + suspicious=$(echo "$result_response" | jq -r '.data.attributes.stats.suspicious // 0') + undetected=$(echo "$result_response" | jq -r '.data.attributes.stats.undetected // 0') + + # Get file hash from the item link + item_link=$(echo "$result_response" | jq -r '.data.links.item // ""') + file_hash=$(echo "$item_link" | sed 's/.*files\///') + vt_url="https://www.virustotal.com/gui/file/$file_hash" + + if [ "$malicious" -gt 0 ] || [ "$suspicious" -gt 0 ]; then + status_text="⚠️ FLAGGED" + ALL_CLEAN=false + else + status_text="✅ Clean" + fi + + echo "| $filename | $status_text | $malicious | $suspicious | $undetected | [$file_hash]($vt_url) |" >> scan_results.md + + else + echo "| $filename | ⏳ Pending | N/A | N/A | N/A | Scan not completed |" >> scan_results.md + ALL_CLEAN=false + fi + + done < analysis_ids.txt + + echo "all_clean=$ALL_CLEAN" >> $GITHUB_OUTPUT + + # Add summary to GitHub step summary + cat scan_results.md >> $GITHUB_STEP_SUMMARY + + - name: Create scan summary + id: scan-summary + run: | + RESULTS=$(cat scan_results.md) + ALL_CLEAN="${{ steps.get-results.outputs.all_clean }}" + + # Escape newlines for GitHub output + RESULTS_ESCAPED=$(echo "$RESULTS" | sed ':a;N;$!ba;s/\n/\\n/g') + + echo "results=$RESULTS_ESCAPED" >> $GITHUB_OUTPUT + echo "all-clean=$ALL_CLEAN" >> $GITHUB_OUTPUT + + - name: Upload scan results as artifact + uses: actions/upload-artifact@v4 + with: + name: virustotal-scan-results + path: | + scan_results.md + analysis_ids.txt + retention-days: 30 + + create-release: + needs: [check-release, build, virustotal-scan] + if: needs.check-release.outputs.should-build == 'true' && needs.virustotal-scan.outputs.all-clean == 'true' + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + # Continue even if some artifacts (like arm) failed + continue-on-error: true + + - name: Prepare release assets + run: | + mkdir -p release-assets + # Move all binaries to release-assets directory + find artifacts -name "iperf3_*" -type f -exec cp {} release-assets/ \; || true + ls -la release-assets/ + + # Check if we have at least the x64 binary + if [ ! -f "release-assets/iperf3_x64" ]; then + echo "Error: No iperf3_x64 binary found" + exit 1 + fi + + - name: Generate SHA256 checksums + run: | + cd release-assets + if ls iperf3_* 1> /dev/null 2>&1; then + sha256sum iperf3_* > iperf3-checksums.sha256 + cat iperf3-checksums.sha256 + else + echo "No iperf3 binaries found to checksum" + exit 1 + fi + + - name: Check for ARM binary and add note + id: check-arm + run: | + if [ -f "release-assets/iperf3_arm" ]; then + echo "arm-note=" >> $GITHUB_OUTPUT + else + echo "arm-note=**Note:** ARM 32-bit binary compilation failed (known issue with iperf3 versions >3.15). Other architectures compiled successfully." >> $GITHUB_OUTPUT + fi + + - name: Download VirusTotal scan results + uses: actions/download-artifact@v4 + with: + name: virustotal-scan-results + path: vt-results + + - name: Create Release + uses: softprops/action-gh-release@v1 + with: + tag_name: iperf3-${{ needs.check-release.outputs.latest-version }} + name: iperf3 ${{ needs.check-release.outputs.latest-version }} Static Binaries + body: | + Static binaries for iperf3 ${{ needs.check-release.outputs.latest-version }} + + Built using musl toolchains for maximum compatibility. + + **Architectures:** + - `iperf3_x64` - x86_64 (64-bit) + - `iperf3_x86` - i686 (32-bit) + - `iperf3_aarch64` - ARM 64-bit + - `iperf3_arm` - ARM 32-bit (if available) + + ${{ steps.check-arm.outputs.arm-note }} + + **Security Verification:** + All binaries have been scanned by VirusTotal and verified clean. + + ${{ needs.virustotal-scan.outputs.scan-results }} + + **Checksum Verification:** + ```bash + # Verify checksums + sha256sum -c iperf3-checksums.sha256 + ``` + + For usage in YABS script, place these binaries in the `bin/iperf/` directory. + files: | + release-assets/iperf3_* + release-assets/iperf3-checksums.sha256 + draft: false + prerelease: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + notify-failure: + needs: [check-release, build, virustotal-scan] + if: always() && needs.check-release.outputs.should-build == 'true' && (failure() || needs.virustotal-scan.outputs.all-clean == 'false') + runs-on: ubuntu-latest + steps: + - name: Send failure notification + run: | + echo "## ⚠️ iperf3 Build Failed" >> $GITHUB_STEP_SUMMARY + echo "Version: ${{ needs.check-release.outputs.latest-version }}" >> $GITHUB_STEP_SUMMARY + + if [ "${{ needs.virustotal-scan.outputs.all-clean }}" == "false" ]; then + echo "**Reason:** VirusTotal scan detected issues with one or more binaries" >> $GITHUB_STEP_SUMMARY + echo "**Scan Results:**" >> $GITHUB_STEP_SUMMARY + echo "${{ needs.virustotal-scan.outputs.scan-results }}" >> $GITHUB_STEP_SUMMARY + else + echo "**Reason:** Build compilation failed" >> $GITHUB_STEP_SUMMARY + fi + + echo "Check the workflow logs for details: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/monitor-releases.yml b/.github/workflows/monitor-releases.yml new file mode 100644 index 0000000..a40869b --- /dev/null +++ b/.github/workflows/monitor-releases.yml @@ -0,0 +1,74 @@ +name: Monitor External Releases for Updates + +on: + schedule: + # Check every hour for new releases + - cron: '0 * * * *' + workflow_dispatch: + +jobs: + monitor-releases: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Check fio releases + id: check-fio + run: | + # Get latest fio release + LATEST_FIO=$(curl -s https://api.github.com/repos/axboe/fio/releases/latest | jq -r '.tag_name') + echo "Latest fio: $LATEST_FIO" + + # Check if we already have this version + if ! gh release view "fio-$LATEST_FIO" --repo ${{ github.repository }} >/dev/null 2>&1; then + echo "New fio version found: $LATEST_FIO" + echo "trigger-fio=true" >> $GITHUB_OUTPUT + echo "fio-version=$LATEST_FIO" >> $GITHUB_OUTPUT + else + echo "fio $LATEST_FIO already exists" + echo "trigger-fio=false" >> $GITHUB_OUTPUT + fi + env: + GH_TOKEN: ${{ github.token }} + + - name: Check iperf3 releases + id: check-iperf3 + run: | + # Get latest iperf3 release + LATEST_IPERF3=$(curl -s https://api.github.com/repos/esnet/iperf/releases/latest | jq -r '.tag_name') + echo "Latest iperf3: $LATEST_IPERF3" + + # Check if we already have this version + if ! gh release view "iperf3-$LATEST_IPERF3" --repo ${{ github.repository }} >/dev/null 2>&1; then + echo "New iperf3 version found: $LATEST_IPERF3" + echo "trigger-iperf3=true" >> $GITHUB_OUTPUT + echo "iperf3-version=$LATEST_IPERF3" >> $GITHUB_OUTPUT + else + echo "iperf3 $LATEST_IPERF3 already exists" + echo "trigger-iperf3=false" >> $GITHUB_OUTPUT + fi + env: + GH_TOKEN: ${{ github.token }} + + - name: Trigger fio build workflow + if: steps.check-fio.outputs.trigger-fio == 'true' + run: | + echo "Triggering fio build for version ${{ steps.check-fio.outputs.fio-version }}" + gh workflow run build-fio.yml --repo ${{ github.repository }} + env: + GH_TOKEN: ${{ github.token }} + + - name: Trigger iperf3 build workflow + if: steps.check-iperf3.outputs.trigger-iperf3 == 'true' + run: | + echo "Triggering iperf3 build for version ${{ steps.check-iperf3.outputs.iperf3-version }}" + gh workflow run build-iperf3.yml --repo ${{ github.repository }} + env: + GH_TOKEN: ${{ github.token }} + + - name: Summary + run: | + echo "## Release Monitoring Summary" >> $GITHUB_STEP_SUMMARY + echo "- fio: ${{ steps.check-fio.outputs.trigger-fio == 'true' && 'New version triggered build' || 'No new version' }}" >> $GITHUB_STEP_SUMMARY + echo "- iperf3: ${{ steps.check-iperf3.outputs.trigger-iperf3 == 'true' && 'New version triggered build' || 'No new version' }}" >> $GITHUB_STEP_SUMMARY