feat: Implement binary integrity verification and anti-tampering meas⦠#6
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: 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: | | |
| # Hardened build flags for security and size optimization | |
| # -w: Omit DWARF symbol table | |
| # -s: Omit symbol table and debug information | |
| # -buildid=: Remove build ID (reduces uniqueness for analysis) | |
| # -trimpath: Remove file system paths from binary | |
| LDFLAGS="-w -s -buildid=" | |
| 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 | |
| BUILD_TAGS="netgo,osusergo" | |
| echo "Building NetTool for ${{ matrix.name }} (hardened beta)..." | |
| go build -a -trimpath -installsuffix cgo -tags "$BUILD_TAGS" -ldflags "$LDFLAGS" -o nettool ./main.go | |
| echo "Building CLI tool..." | |
| go build -a -trimpath -installsuffix cgo -tags "$BUILD_TAGS" -ldflags "$LDFLAGS" -o nettool-iterate ./app/cmd/iterate/main.go | |
| - 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 | |
| fi | |
| - 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 | |
| echo "$MAIN_HASH nettool" > SHA256SUMS | |
| echo "$CLI_HASH nettool-iterate" >> SHA256SUMS | |
| echo "Generated checksums:" | |
| cat SHA256SUMS | |
| - 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 | |
| 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 checksums.json manifest | |
| echo '{' > checksums.json | |
| echo ' "version": "beta-${{ steps.info.outputs.sha_short }}",' >> checksums.json | |
| echo ' "build_time": "${{ steps.info.outputs.date }}T${{ steps.info.outputs.time }}Z",' >> checksums.json | |
| echo ' "hashes": {' >> checksums.json | |
| FIRST=true | |
| for file in *.tar.gz; do | |
| HASH=$(sha256sum "$file" | cut -d' ' -f1) | |
| if [ "$FIRST" = true ]; then | |
| FIRST=false | |
| else | |
| echo ',' >> checksums.json | |
| fi | |
| echo -n " \"$file\": \"$HASH\"" >> checksums.json | |
| done | |
| echo '' >> checksums.json | |
| echo ' }' >> checksums.json | |
| echo '}' >> checksums.json | |
| # Also create traditional SHA256SUMS file | |
| sha256sum *.tar.gz > SHA256SUMS | |
| echo "Generated checksums:" | |
| cat checksums.json | |
| cd .. | |
| - 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/checksums.json | |
| release-files/SHA256SUMS | |
| prerelease: true | |
| draft: false | |
| make_latest: false | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |