Add GitHub Actions workflows for plugin builds and releases #14
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Beta Build | |
| on: | |
| push: | |
| branches: | |
| - main | |
| paths-ignore: | |
| - '**.md' | |
| - 'LICENSE' | |
| - '.gitignore' | |
| env: | |
| GO_VERSION: '1.24' | |
| NODE_VERSION: '20' | |
| jobs: | |
| build-frontend: | |
| name: Build Frontend | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: ${{ env.NODE_VERSION }} | |
| cache: 'npm' | |
| cache-dependency-path: frontend/package-lock.json | |
| - name: Install dependencies | |
| working-directory: frontend | |
| run: npm ci | |
| - name: Build frontend | |
| working-directory: frontend | |
| run: npm run build | |
| - name: Upload frontend artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: frontend-dist | |
| path: frontend/dist | |
| retention-days: 1 | |
| build-binaries: | |
| name: Build ${{ matrix.name }} | |
| runs-on: ubuntu-latest | |
| needs: build-frontend | |
| strategy: | |
| matrix: | |
| include: | |
| - name: Linux x64 | |
| goos: linux | |
| goarch: amd64 | |
| artifact: nettool-linux-amd64 | |
| - name: Linux x32 | |
| goos: linux | |
| goarch: '386' | |
| artifact: nettool-linux-386 | |
| - name: Linux Pi Zero (ARMv6) | |
| goos: linux | |
| goarch: arm | |
| goarm: '6' | |
| artifact: nettool-linux-arm6 | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Setup Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| - name: Install UPX (for compression) | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y upx-ucl | |
| - name: Download frontend artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: frontend-dist | |
| path: frontend/dist | |
| - name: Get version info | |
| id: version | |
| run: | | |
| SHORT_SHA=$(git rev-parse --short HEAD) | |
| VERSION="beta-${SHORT_SHA}" | |
| echo "version=$VERSION" >> $GITHUB_OUTPUT | |
| echo "commit=$SHORT_SHA" >> $GITHUB_OUTPUT | |
| echo "build_time=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> $GITHUB_OUTPUT | |
| - name: Build binary (hardened) | |
| env: | |
| GOOS: ${{ matrix.goos }} | |
| GOARCH: ${{ matrix.goarch }} | |
| GOARM: ${{ matrix.goarm }} | |
| CGO_ENABLED: '0' | |
| run: | | |
| # Maximum size reduction and security hardening flags | |
| # -w: Omit DWARF symbol table (debug info) | |
| # -s: Omit symbol table and debug information | |
| # -buildid=: Remove build ID (reduces binary analysis) | |
| # -trimpath: Remove file system paths from binary | |
| # -extldflags "-static": Ensure static linking | |
| LDFLAGS="-w -s -buildid= -extldflags '-static'" | |
| LDFLAGS="$LDFLAGS -X main.Version=${{ steps.version.outputs.version }}" | |
| LDFLAGS="$LDFLAGS -X main.BuildTime=${{ steps.version.outputs.build_time }}" | |
| LDFLAGS="$LDFLAGS -X main.GitCommit=${{ steps.version.outputs.commit }}" | |
| LDFLAGS="$LDFLAGS -X github.com/gin-gonic/gin.Mode=release" | |
| LDFLAGS="$LDFLAGS -X github.com/NetScout-Go/NetTool/app/core.IntegrityEnabled=true" | |
| # Build tags for static compilation and optimizations | |
| # netgo: Use Go's network stack (no cgo) | |
| # osusergo: Use Go's user lookup (no cgo) | |
| BUILD_TAGS="netgo,osusergo" | |
| # Additional GC flags for smaller binaries | |
| export GOGC=off | |
| echo "Building NetTool for ${{ matrix.name }} (hardened beta)..." | |
| go build -a -trimpath -installsuffix cgo \ | |
| -tags "$BUILD_TAGS" \ | |
| -ldflags "$LDFLAGS" \ | |
| -gcflags=all="-l -B" \ | |
| -o nettool ./main.go | |
| echo "Building CLI tool..." | |
| go build -a -trimpath -installsuffix cgo \ | |
| -tags "$BUILD_TAGS" \ | |
| -ldflags "$LDFLAGS" \ | |
| -gcflags=all="-l -B" \ | |
| -o nettool-iterate ./app/cmd/iterate/main.go | |
| echo "Initial binary sizes:" | |
| ls -lh nettool nettool-iterate | |
| - name: Strip binaries (additional size reduction) | |
| run: | | |
| # Strip for x86 targets | |
| if [ "${{ matrix.goarch }}" = "amd64" ] || [ "${{ matrix.goarch }}" = "386" ]; then | |
| strip --strip-all nettool 2>/dev/null || true | |
| strip --strip-all nettool-iterate 2>/dev/null || true | |
| echo "After strip:" | |
| ls -lh nettool nettool-iterate | |
| fi | |
| - name: Compress binaries with UPX | |
| run: | | |
| # UPX compression for maximum size reduction | |
| # --best: Best compression (slower) | |
| # --lzma: Use LZMA compression (best ratio) | |
| # Note: UPX may not work well with all ARM variants | |
| echo "Compressing with UPX..." | |
| if [ "${{ matrix.goarch }}" = "arm" ]; then | |
| # ARM may have issues with UPX, use safer settings | |
| upx --best nettool 2>/dev/null || echo "UPX failed for nettool (ARM), skipping" | |
| upx --best nettool-iterate 2>/dev/null || echo "UPX failed for nettool-iterate (ARM), skipping" | |
| else | |
| # x86/x64 - use maximum compression | |
| upx --best --lzma nettool 2>/dev/null || upx --best nettool 2>/dev/null || echo "UPX failed for nettool, skipping" | |
| upx --best --lzma nettool-iterate 2>/dev/null || upx --best nettool-iterate 2>/dev/null || echo "UPX failed for nettool-iterate, skipping" | |
| fi | |
| echo "Final binary sizes after compression:" | |
| ls -lh nettool nettool-iterate | |
| - name: Generate checksums | |
| id: checksums | |
| run: | | |
| # Generate SHA256 checksums for binaries | |
| MAIN_HASH=$(sha256sum nettool | cut -d' ' -f1) | |
| CLI_HASH=$(sha256sum nettool-iterate | cut -d' ' -f1) | |
| echo "main_hash=$MAIN_HASH" >> $GITHUB_OUTPUT | |
| echo "cli_hash=$CLI_HASH" >> $GITHUB_OUTPUT | |
| # Create checksums file for the package | |
| echo "$MAIN_HASH nettool" > SHA256SUMS | |
| echo "$CLI_HASH nettool-iterate" >> SHA256SUMS | |
| # Create platform-specific binary checksums JSON for aggregation | |
| cat > binary-checksums.json << EOF | |
| { | |
| "platform": "${{ matrix.artifact }}", | |
| "binaries": { | |
| "nettool": "$MAIN_HASH", | |
| "nettool-iterate": "$CLI_HASH" | |
| } | |
| } | |
| EOF | |
| echo "Generated checksums for ${{ matrix.artifact }}:" | |
| cat SHA256SUMS | |
| cat binary-checksums.json | |
| - name: Prepare package | |
| run: | | |
| mkdir -p package/frontend/dist | |
| mkdir -p package/app/plugins/plugins | |
| cp nettool package/ | |
| cp nettool-iterate package/ | |
| cp SHA256SUMS package/ | |
| cp -r frontend/dist/* package/frontend/dist/ | |
| cp app/plugins/config.json.example package/app/plugins/ | |
| [ -f app/plugins/config.json ] && cp app/plugins/config.json package/app/plugins/ || true | |
| [ -d app/plugins/plugins/demo_plugin ] && cp -r app/plugins/plugins/demo_plugin package/app/plugins/plugins/ || true | |
| cp README.md package/ || true | |
| cp LICENSE package/ || true | |
| # Create install script with integrity verification | |
| cat > package/install.sh << 'INSTALL_EOF' | |
| #!/bin/bash | |
| set -e | |
| INSTALL_DIR="/opt/nettool" | |
| SERVICE_FILE="/etc/systemd/system/nettool.service" | |
| USER="nettool" | |
| GROUP="nettool" | |
| echo "🚀 Installing NetTool (Beta)..." | |
| if [ "$EUID" -ne 0 ]; then | |
| echo "❌ Please run as root (use sudo)" | |
| exit 1 | |
| fi | |
| # Verify checksums before installation | |
| echo "🔐 Verifying binary integrity..." | |
| if [ -f SHA256SUMS ]; then | |
| if sha256sum -c SHA256SUMS --status 2>/dev/null; then | |
| echo "✅ Checksums verified" | |
| else | |
| echo "⚠️ Checksum verification failed! Binaries may have been modified." | |
| read -p "Continue anyway? (y/N) " -n 1 -r | |
| echo | |
| if [[ ! $REPLY =~ ^[Yy]$ ]]; then | |
| exit 1 | |
| fi | |
| fi | |
| else | |
| echo "⚠️ No checksums file found, skipping verification" | |
| fi | |
| if ! getent group $GROUP >/dev/null; then | |
| groupadd --system $GROUP | |
| fi | |
| if ! getent passwd $USER >/dev/null; then | |
| useradd --system --gid $GROUP --shell /bin/false --home-dir $INSTALL_DIR $USER | |
| fi | |
| mkdir -p $INSTALL_DIR | |
| cp -r . $INSTALL_DIR/ | |
| chown -R $USER:$GROUP $INSTALL_DIR | |
| chmod +x $INSTALL_DIR/nettool $INSTALL_DIR/nettool-iterate | |
| ln -sf $INSTALL_DIR/nettool /usr/local/bin/nettool | |
| ln -sf $INSTALL_DIR/nettool-iterate /usr/local/bin/nettool-iterate | |
| cat > $SERVICE_FILE << 'SERVICE_EOF' | |
| [Unit] | |
| Description=NetTool Network Analysis Server | |
| After=network.target | |
| [Service] | |
| Type=simple | |
| User=nettool | |
| Group=nettool | |
| WorkingDirectory=/opt/nettool | |
| ExecStart=/opt/nettool/nettool --port=8080 | |
| Restart=always | |
| RestartSec=5 | |
| NoNewPrivileges=true | |
| PrivateTmp=true | |
| ProtectSystem=strict | |
| ProtectHome=true | |
| ReadWritePaths=/opt/nettool | |
| CapabilityBoundingSet=CAP_NET_RAW CAP_NET_ADMIN | |
| AmbientCapabilities=CAP_NET_RAW CAP_NET_ADMIN | |
| [Install] | |
| WantedBy=multi-user.target | |
| SERVICE_EOF | |
| systemctl daemon-reload | |
| systemctl enable nettool | |
| echo "✅ Installation complete!" | |
| echo " Start: sudo systemctl start nettool" | |
| echo " Logs: sudo journalctl -u nettool -f" | |
| echo " Web: http://localhost:8080" | |
| echo "" | |
| echo "🔐 Verify integrity anytime: nettool --integrity" | |
| INSTALL_EOF | |
| chmod +x package/install.sh | |
| - name: Create archive | |
| run: | | |
| cd package | |
| tar -czvf ../${{ matrix.artifact }}-beta.tar.gz . | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.artifact }} | |
| path: ${{ matrix.artifact }}-beta.tar.gz | |
| retention-days: 7 | |
| - name: Upload checksums artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: checksums-${{ matrix.artifact }} | |
| path: | | |
| SHA256SUMS | |
| binary-checksums.json | |
| retention-days: 7 | |
| update-beta-release: | |
| name: Update Beta Release | |
| runs-on: ubuntu-latest | |
| needs: build-binaries | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v4 | |
| - name: Get commit info | |
| id: info | |
| run: | | |
| echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT | |
| echo "sha_full=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT | |
| echo "date=$(date -u +%Y-%m-%d)" >> $GITHUB_OUTPUT | |
| echo "time=$(date -u +%H:%M:%S)" >> $GITHUB_OUTPUT | |
| echo "commit_msg=$(git log -1 --pretty=%s)" >> $GITHUB_OUTPUT | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: Move artifacts | |
| run: | | |
| mkdir -p release-files | |
| find artifacts -name "*.tar.gz" -exec mv {} release-files/ \; | |
| ls -la release-files/ | |
| - name: Generate combined checksums | |
| run: | | |
| cd release-files | |
| # Create archive checksums (for verifying downloaded tar.gz files) | |
| echo "Creating archive checksums..." | |
| sha256sum *.tar.gz > SHA256SUMS-archives | |
| echo "Archive checksums:" | |
| cat SHA256SUMS-archives | |
| cd .. | |
| # Collect all binary checksums from artifacts | |
| echo "Collecting binary checksums from all platforms..." | |
| mkdir -p binary-hashes | |
| # Only copy platform-specific checksums (not the generic binary-checksums.json) | |
| for dir in artifacts/checksums-*; do | |
| platform=$(basename "$dir" | sed 's/checksums-//') | |
| if [ -f "$dir/binary-checksums.json" ]; then | |
| cp "$dir/binary-checksums.json" "binary-hashes/${platform}.json" | |
| echo "Found checksums for: $platform" | |
| fi | |
| done | |
| # Create combined binary checksums JSON with proper formatting | |
| echo "Creating combined binary checksums..." | |
| # Start JSON | |
| echo '{' > release-files/binary-checksums.json | |
| echo ' "version": "beta-${{ steps.info.outputs.sha_short }}",' >> release-files/binary-checksums.json | |
| echo ' "build_time": "${{ steps.info.outputs.date }}T${{ steps.info.outputs.time }}Z",' >> release-files/binary-checksums.json | |
| echo ' "description": "SHA256 hashes of binaries inside each platform package",' >> release-files/binary-checksums.json | |
| echo ' "platforms": {' >> release-files/binary-checksums.json | |
| # Add each platform | |
| FIRST=true | |
| for f in binary-hashes/nettool-*.json; do | |
| if [ -f "$f" ]; then | |
| PLATFORM=$(basename "$f" .json) | |
| MAIN_HASH=$(grep -o '"nettool": "[^"]*"' "$f" | head -1 | cut -d'"' -f4) | |
| CLI_HASH=$(grep -o '"nettool-iterate": "[^"]*"' "$f" | head -1 | cut -d'"' -f4) | |
| if [ -n "$MAIN_HASH" ]; then | |
| if [ "$FIRST" = true ]; then | |
| FIRST=false | |
| else | |
| echo ',' >> release-files/binary-checksums.json | |
| fi | |
| echo " \"$PLATFORM\": {" >> release-files/binary-checksums.json | |
| echo " \"nettool\": \"$MAIN_HASH\"," >> release-files/binary-checksums.json | |
| echo " \"nettool-iterate\": \"$CLI_HASH\"" >> release-files/binary-checksums.json | |
| echo -n " }" >> release-files/binary-checksums.json | |
| fi | |
| fi | |
| done | |
| # Close JSON | |
| echo '' >> release-files/binary-checksums.json | |
| echo ' }' >> release-files/binary-checksums.json | |
| echo '}' >> release-files/binary-checksums.json | |
| echo "" | |
| echo "Binary checksums (for runtime verification):" | |
| cat release-files/binary-checksums.json | |
| # Validate JSON | |
| echo "" | |
| echo "Validating JSON..." | |
| python3 -m json.tool release-files/binary-checksums.json > /dev/null && echo "✅ JSON is valid" || echo "❌ JSON is invalid" | |
| # Move archive checksums to release | |
| mv release-files/SHA256SUMS-archives release-files/SHA256SUMS | |
| - name: Delete existing beta tag and release | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| # Delete the release if it exists | |
| gh release delete beta --yes || true | |
| # Delete the tag if it exists | |
| git push origin :refs/tags/beta || true | |
| - name: Create Beta Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: beta | |
| name: "🧪 Beta Build (${{ steps.info.outputs.date }})" | |
| body: | | |
| ## ⚠️ Beta Build - Use at Your Own Risk | |
| This is an automatically generated build from the latest `main` branch commit. | |
| **Build Info:** | |
| - 📅 Date: ${{ steps.info.outputs.date }} ${{ steps.info.outputs.time }} UTC | |
| - 🔖 Commit: [`${{ steps.info.outputs.sha_short }}`](https://github.com/${{ github.repository }}/commit/${{ steps.info.outputs.sha_full }}) | |
| - 💬 Message: ${{ steps.info.outputs.commit_msg }} | |
| **🔐 Security Features:** | |
| - Debug symbols stripped for smaller size | |
| - Build paths removed for privacy | |
| - Integrity verification enabled (`nettool --integrity`) | |
| - SHA256 checksums included | |
| **Downloads:** | |
| | Platform | File | | |
| |----------|------| | |
| | Linux x64 | `nettool-linux-amd64-beta.tar.gz` | | |
| | Linux x32 | `nettool-linux-386-beta.tar.gz` | | |
| | Pi Zero (ARMv6) | `nettool-linux-arm6-beta.tar.gz` | | |
| **Verify your download:** | |
| ```bash | |
| # Download and verify checksums | |
| curl -sL https://github.com/${{ github.repository }}/releases/download/beta/SHA256SUMS | sha256sum -c | |
| # Or verify after installation | |
| nettool --integrity | |
| ``` | |
| --- | |
| > 💡 For stable releases, check the [Releases](https://github.com/${{ github.repository }}/releases) page. | |
| files: | | |
| release-files/*.tar.gz | |
| release-files/binary-checksums.json | |
| release-files/SHA256SUMS | |
| prerelease: true | |
| draft: false | |
| make_latest: false | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |