Skip to content

chore(deps): bump actions/upload-artifact from 4.6.0 to 7.0.1 #108

chore(deps): bump actions/upload-artifact from 4.6.0 to 7.0.1

chore(deps): bump actions/upload-artifact from 4.6.0 to 7.0.1 #108

Workflow file for this run

# SPDX-License-Identifier: GPL-2.0-only
# GitHub Actions configuration for gspy
name: Build & Test
on:
push:
branches: [ master ]
tags: [ 'v*' ]
pull_request:
branches: [ master ]
permissions:
contents: read
env:
GO_VERSION: "1.24"
CLANG_VERSION: "16"
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
GOFLAGS: "-mod=mod"
jobs:
# ─────────────────────────────────────────────────────────
# Job 1: Lint — ensure code quality and formatting
# ─────────────────────────────────────────────────────────
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v6
- name: Set up Go
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v6
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Install BPF toolchain
run: |
sudo apt-get update && sudo apt-get install -y \
clang-${{ env.CLANG_VERSION }} \
llvm-${{ env.CLANG_VERSION }} \
libbpf-dev libelf-dev
sudo ln -sf /usr/bin/clang-${{ env.CLANG_VERSION }} /usr/bin/clang
sudo ln -sf /usr/bin/llvm-strip-${{ env.CLANG_VERSION }} /usr/bin/llvm-strip
# Install bpftool — try kernel-specific, then build from source
sudo apt-get install -y linux-tools-$(uname -r) 2>/dev/null || \
sudo apt-get install -y linux-tools-azure 2>/dev/null || true
if ! sudo bpftool version 2>/dev/null; then
sudo apt-get install -y git pkg-config
git clone --depth 1 --recurse-submodules \
https://github.com/libbpf/bpftool.git /tmp/bpftool
cd /tmp/bpftool/src && make -j$(nproc) && sudo make install prefix=/usr && cd -
fi
- name: Generate BPF bindings
run: |
go install github.com/cilium/ebpf/cmd/bpf2go@v0.17.1
export PATH=$PATH:$(go env GOPATH)/bin
make generate
- name: Check SPDX headers
run: |
MISSING=$(grep -rL "SPDX-License-Identifier" \
--include="*.go" --include="*.c" . \
| grep -v vendor/ \
| grep -vE 'internal/bpf/gspy_.*_bpf(el|eb)\.go' || true)
if [ -n "$MISSING" ]; then
echo "ERROR: Missing SPDX headers:"; echo "$MISSING"; exit 1
fi
echo "✓ All source files have SPDX headers"
- name: golangci-lint
uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6
with:
version: v1.64.2
args: --timeout=5m --build-tags=testing
# ─────────────────────────────────────────────────────────
# Job 2: Test — run unit tests with mock BPF
# ─────────────────────────────────────────────────────────
test:
name: Test (mock BPF)
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v6
- name: Set up Go
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v6
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Run tests with race detector
run: |
go test -v -race -coverprofile=coverage.out -tags=testing ./...
go tool cover -func=coverage.out | tail -1
# ─────────────────────────────────────────────────────────
# Job 2b: ABI Test — ensure Go versions don't break struct offsets
# ─────────────────────────────────────────────────────────
abi-test:
name: ABI Tests (${{ matrix.go-version }})
runs-on: ubuntu-latest
strategy:
matrix:
go-version: ['1.21', '1.22', '1.23', '1.24']
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v6
- name: Set up Go
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v6
with:
go-version: ${{ matrix.go-version }}
- name: Test ABI logic
run: go test -v -tags=testing ./internal/attach/...
# ─────────────────────────────────────────────────────────
# Job 3: Build — generate BPF and compile binary
# ─────────────────────────────────────────────────────────
build-linux:
name: Build (Linux ${{ matrix.arch }})
runs-on: ubuntu-latest
needs: [test]
strategy:
fail-fast: false
matrix:
arch: [amd64, arm64]
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v6
with:
fetch-depth: 0
- name: Set up Go
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v6
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Install bpf2go
run: |
go install github.com/cilium/ebpf/cmd/bpf2go@v0.17.1
echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
- name: Install BPF toolchain
run: |
sudo apt-get update
sudo apt-get install -y \
clang-${{ env.CLANG_VERSION }} \
llvm-${{ env.CLANG_VERSION }} \
libelf-dev \
libbpf-dev
sudo ln -sf /usr/bin/clang-${{ env.CLANG_VERSION }} /usr/bin/clang
sudo ln -sf /usr/bin/llc-${{ env.CLANG_VERSION }} /usr/bin/llc
sudo ln -sf /usr/bin/llvm-strip-${{ env.CLANG_VERSION }} /usr/bin/llvm-strip
# Install bpftool
sudo apt-get install -y linux-tools-$(uname -r) 2>/dev/null || \
sudo apt-get install -y linux-tools-azure 2>/dev/null || true
if ! sudo bpftool version 2>/dev/null; then
sudo apt-get install -y git pkg-config
git clone --depth 1 --recurse-submodules \
https://github.com/libbpf/bpftool.git /tmp/bpftool
cd /tmp/bpftool/src && make -j$(nproc) && sudo make install prefix=/usr && cd -
fi
- name: Generate BPF and Build
env:
CGO_ENABLED: "0"
run: |
# FIX BUG 1: Use git describe for proper version string
VERSION=$(git describe --tags --always --dirty 2>/dev/null || echo "dev")
echo "Building with VERSION=${VERSION}"
# 1. Generate (Must run on host arch to execute bpf2go)
make generate
# 2. Build (Target specific arch)
make build VERSION=${VERSION} GOARCH=${{ matrix.arch }}
- name: Verify binary
run: |
ls -la bin/gspy
file bin/gspy
# Smoke test only on native runner arch
if [ "${{ matrix.arch }}" = "amd64" ]; then
bin/gspy --version
bin/gspy --help
! bin/gspy notapid 2>/dev/null
fi
- name: Verify man page exists
run: |
test -s man/gspy.1 || { echo "ERROR: man/gspy.1 is missing or empty"; exit 1; }
- name: Upload binary artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: gspy-linux-${{ matrix.arch }}
path: bin/gspy
retention-days: 30
# ─────────────────────────────────────────────────────────
# Job 4: Integration test — real BPF against real process
# ─────────────────────────────────────────────────────────
integration:
name: Integration test (real BPF)
runs-on: ubuntu-latest
needs: [build-linux]
steps:
- name: Checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v6
- name: Set up Go
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v6
with:
go-version: ${{ env.GO_VERSION }}
cache: true
- name: Download binary artifact
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v8
with:
name: gspy-linux-amd64
path: bin/
- name: Build test target process
run: |
chmod +x bin/gspy
cat > /tmp/testproc.go << 'TESTEOF'
package main
import (
"net/http"
"time"
)
func main() {
go func() {
for {
http.Get("http://127.0.0.1:19999")
time.Sleep(100 * time.Millisecond)
}
}()
select {}
}
TESTEOF
go build -o /tmp/gspy-testproc /tmp/testproc.go
- name: Run integration test
run: |
set -euo pipefail
# Allow unprivileged BPF access for testing
sudo sysctl -w kernel.perf_event_paranoid=2 || true
sudo sysctl -w kernel.unprivileged_bpf_disabled=0 || true
# Start the test target process
/tmp/gspy-testproc &
TESTPID=$!
echo "Test target PID: $TESTPID"
sleep 2
# Verify test process is running
kill -0 $TESTPID || { echo "ERROR: test process not running"; exit 1; }
# Run gspy in JSON mode for 5 seconds (--json avoids TUI/TTY issues)
sudo timeout 5 ./bin/gspy $TESTPID --json > /tmp/gspy-out.json 2>/tmp/gspy-err.txt || true
# Kill the test process
kill $TESTPID 2>/dev/null || true
# Print output for debugging
echo "=== gspy stdout ==="
head -20 /tmp/gspy-out.json || true
echo "=== gspy stderr ==="
cat /tmp/gspy-err.txt || true
# Check if BPF/perf is available on this runner
if grep -q "TUI error\|could not open\|BPF.*fail\|perf_event" /tmp/gspy-err.txt 2>/dev/null; then
echo "WARN: BPF/perf not fully available on this runner. Skipping JSON validation."
echo "This is expected on some GitHub Actions runners with restricted BPF."
exit 0
fi
# Validate: output must exist and be non-empty
if [ ! -s /tmp/gspy-out.json ]; then
echo "FAIL: gspy produced no JSON output"
exit 1
fi
# At least one valid JSON line must exist with gid > 0
python3 -c "
import json, sys
events = []
with open('/tmp/gspy-out.json') as f:
for line in f:
line = line.strip()
if line:
try:
events.append(json.loads(line))
except:
pass
if not events:
print('FAIL: no parseable JSON events')
sys.exit(1)
valid = [e for e in events if e.get('gid', 0) > 0]
if not valid:
print(f'FAIL: no events with gid > 0. Got {len(events)} events total.')
sys.exit(1)
print(f'PASS: {len(valid)} events with valid GID out of {len(events)} total')
"
release:
name: Release
runs-on: ubuntu-latest
needs: [build-linux, lint, integration]
if: startsWith(github.ref, 'refs/tags/v')
permissions:
contents: write
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v6
- name: Install nFPM
run: |
go install github.com/goreleaser/nfpm/v2/cmd/nfpm@latest
echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
- name: Download amd64 build
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v8
with:
name: gspy-linux-amd64
path: bin-amd64/
- name: Download arm64 build
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v8
with:
name: gspy-linux-arm64
path: bin-arm64/
- name: Generate Multi-Arch Packages
run: |
VERSION=${GITHUB_REF#refs/tags/v}
gzip -k man/gspy.1
mkdir -p release-dist
for arch in amd64 arm64; do
echo "--- Packaging for $arch ---"
# Setup working directory structure for nfpm mapping
mkdir -p bin
cp bin-$arch/gspy bin/gspy
chmod +x bin/gspy
# 1. Generate compressed tarball
tar czf release-dist/gspy-v${VERSION}-linux-${arch}.tar.gz bin/gspy man/gspy.1.gz LICENSE README.md
# 2. Generate .deb and .rpm using nfpm
# ARCH and VERSION are picked up as environment variables in nfpm.yaml
VERSION=${VERSION} ARCH=${arch} nfpm pkg --packager deb --target release-dist/
VERSION=${VERSION} ARCH=${arch} nfpm pkg --packager rpm --target release-dist/
# Cleanup for next arch iteration
rm -rf bin
done
# 3. Generate Checksums for all assets
cd release-dist
sha256sum * > SHA256SUMS.txt
shell: bash
- name: Create GitHub Release
uses: softprops/action-gh-release@01570a1f39cb168c169c802c3bceb9e93fb10974 # v3
with:
draft: false
prerelease: false
generate_release_notes: true
files: |
release-dist/*