Skip to content

Commit e8b5afc

Browse files
committed
feat: implement gspy with CI/CD, Debian packaging, and TrueColor UI
This commit consolidates the initial development and stabilization of gspy, including: - High-fidelity TrueColor (24-bit) TUI with lipgloss/bubbletea - BPF-powered goroutine-to-syscall tracing with ring buffer support - Forensic JSON snapshotting and readonly mode - Comprehensive CI/CD pipeline with GitHub Actions - Debian and Arch Linux (PKGBUILD) packaging support - Robust symbol resolution and frame inspection
1 parent d4e3fac commit e8b5afc

25 files changed

Lines changed: 1372 additions & 106 deletions

.editorconfig

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# EditorConfig for gspy
2+
# https://editorconfig.org
3+
4+
root = true
5+
6+
[*]
7+
charset = utf-8
8+
end_of_line = lf
9+
insert_final_newline = true
10+
trim_trailing_whitespace = true
11+
12+
[*.go]
13+
indent_style = tab
14+
indent_size = 4
15+
16+
[*.c]
17+
indent_style = tab
18+
indent_size = 8
19+
20+
[*.{yml,yaml}]
21+
indent_style = space
22+
indent_size = 2
23+
24+
[Makefile]
25+
indent_style = tab
26+
27+
[debian/*]
28+
indent_style = space
29+
indent_size = 2
30+
31+
[*.md]
32+
trim_trailing_whitespace = false

.github/workflows/build.yml

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
# SPDX-License-Identifier: GPL-2.0-only
2+
# GitHub Actions configuration for gspy
3+
4+
name: Build & Test
5+
6+
on:
7+
push:
8+
branches: [ master ]
9+
tags: [ 'v*' ]
10+
pull_request:
11+
branches: [ master ]
12+
13+
permissions:
14+
contents: write
15+
16+
env:
17+
GO_VERSION: 1.21
18+
CLANG_VERSION: 16
19+
20+
jobs:
21+
# ─────────────────────────────────────────────────────────
22+
# Job 1: Lint — ensure code quality and formatting
23+
# ─────────────────────────────────────────────────────────
24+
lint:
25+
name: Lint
26+
runs-on: ubuntu-latest
27+
steps:
28+
- name: Checkout
29+
uses: actions/checkout@v4
30+
31+
- name: Set up Go
32+
uses: actions/setup-go@v5
33+
with:
34+
go-version: ${{ env.GO_VERSION }}
35+
cache: true
36+
37+
- name: Install BPF toolchain and Generate
38+
run: |
39+
sudo apt-get update && sudo apt-get install -y clang-${{ env.CLANG_VERSION }} llvm-${{ env.CLANG_VERSION }} libbpf-dev libelf-dev
40+
sudo ln -sf /usr/bin/clang-${{ env.CLANG_VERSION }} /usr/bin/clang
41+
sudo ln -sf /usr/bin/llvm-strip-${{ env.CLANG_VERSION }} /usr/bin/llvm-strip
42+
go install github.com/cilium/ebpf/cmd/bpf2go@v0.14.0
43+
export PATH=$PATH:$(go env GOPATH)/bin
44+
make generate
45+
46+
- name: Install dependencies
47+
run: sudo apt-get update && sudo apt-get install -y libbpf-dev libelf-dev
48+
49+
- name: golangci-lint
50+
uses: golangci/golangci-lint-action@v4
51+
with:
52+
version: v1.54
53+
54+
# ─────────────────────────────────────────────────────────
55+
# Job 2: Test — run unit tests with mock BPF
56+
# ─────────────────────────────────────────────────────────
57+
test:
58+
name: Test (mock BPF)
59+
runs-on: ubuntu-latest
60+
steps:
61+
- name: Checkout
62+
uses: actions/checkout@v4
63+
64+
- name: Set up Go
65+
uses: actions/setup-go@v5
66+
with:
67+
go-version: ${{ env.GO_VERSION }}
68+
cache: true
69+
70+
- name: Run tests with race detector
71+
# -tags=testing ensures we use mock.go instead of loader.go
72+
run: go test -v -race -cover -tags=testing ./...
73+
74+
# ─────────────────────────────────────────────────────────
75+
# Job 3: Build — generate BPF and compile binary
76+
# ─────────────────────────────────────────────────────────
77+
build-linux:
78+
name: Build (Linux amd64)
79+
runs-on: ubuntu-latest
80+
needs: [test]
81+
steps:
82+
- name: Checkout
83+
uses: actions/checkout@v4
84+
with:
85+
fetch-depth: 0
86+
87+
- name: Set up Go
88+
uses: actions/setup-go@v5
89+
with:
90+
go-version: ${{ env.GO_VERSION }}
91+
cache: true
92+
93+
- name: Install BPF toolchain
94+
run: |
95+
sudo apt-get update
96+
sudo apt-get install -y \
97+
clang-${{ env.CLANG_VERSION }} \
98+
llvm-${{ env.CLANG_VERSION }} \
99+
libelf-dev \
100+
libbpf-dev \
101+
linux-tools-common \
102+
linux-tools-generic \
103+
linux-tools-$(uname -r) || true
104+
105+
# Symlink clang tools to versioned binaries for bpf2go
106+
sudo ln -sf /usr/bin/clang-${{ env.CLANG_VERSION }} /usr/bin/clang
107+
sudo ln -sf /usr/bin/llc-${{ env.CLANG_VERSION }} /usr/bin/llc
108+
sudo ln -sf /usr/bin/llvm-strip-${{ env.CLANG_VERSION }} /usr/bin/llvm-strip
109+
110+
- name: Generate BPF and Build
111+
env:
112+
CGO_ENABLED: 0
113+
run: |
114+
# Install bpf2go
115+
go install github.com/cilium/ebpf/cmd/bpf2go@v0.14.0
116+
117+
# Use local GOPATH/bin for tools
118+
export PATH=$PATH:$(go env GOPATH)/bin
119+
120+
# Generate & Build via Makefile
121+
# This handles BPF compilation and Go build in one pass
122+
make build VERSION=${{ github.ref_name }}
123+
124+
- name: Verify binary
125+
run: |
126+
ls -la bin/gspy
127+
file bin/gspy
128+
bin/gspy --version || true
129+
130+
- name: Upload binary artifact
131+
uses: actions/upload-artifact@v4
132+
with:
133+
name: gspy-linux-amd64
134+
path: bin/gspy
135+
retention-days: 30
136+
137+
# ─────────────────────────────────────────────────────────
138+
# Job 4: Release — create GitHub release on tag push
139+
# ─────────────────────────────────────────────────────────
140+
release:
141+
name: Release
142+
runs-on: ubuntu-latest
143+
needs: [build-linux, lint]
144+
if: startsWith(github.ref, 'refs/tags/v')
145+
steps:
146+
- uses: actions/checkout@v4
147+
148+
- name: Download build artifacts
149+
uses: actions/download-artifact@v4
150+
with:
151+
name: gspy-linux-amd64
152+
path: release/
153+
154+
- name: Compress binary
155+
run: |
156+
cd release
157+
chmod +x gspy
158+
tar czf gspy-linux-amd64.tar.gz gspy
159+
sha256sum gspy-linux-amd64.tar.gz > SHA256SUMS.txt
160+
sha256sum gspy >> SHA256SUMS.txt
161+
162+
- name: Create GitHub Release
163+
uses: softprops/action-gh-release@v2
164+
with:
165+
draft: false
166+
prerelease: false
167+
generate_release_notes: true
168+
files: |
169+
release/gspy-linux-amd64.tar.gz
170+
release/SHA256SUMS.txt

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Build artifacts
22
bin/
3-
gspy
3+
/gspy
44

55
# Generated BPF files
66
internal/bpf/gspy_bpfel.go

.golangci.yml

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# SPDX-License-Identifier: GPL-2.0-only
2+
# golangci-lint configuration for gspy
3+
4+
run:
5+
timeout: 5m
6+
modules-download-mode: readonly
7+
8+
linters:
9+
enable:
10+
- errcheck
11+
- gosimple
12+
- govet
13+
- ineffassign
14+
- staticcheck
15+
- unused
16+
- gofmt
17+
- goimports
18+
disable:
19+
# Too noisy for a security tool with intentional unsafe usage
20+
- gosec
21+
22+
linters-settings:
23+
staticcheck:
24+
checks:
25+
- all
26+
- "-SA1019" # Allow deprecated API usage for backward compat
27+
28+
issues:
29+
# Don't limit per-linter issue count
30+
max-issues-per-linter: 0
31+
max-same-issues: 0
32+
exclude-dirs:
33+
- vendor
34+
exclude-files:
35+
- ".*_bpfel.*\\.go$"
36+
- ".*_bpfeb.*\\.go$"
37+
exclude-rules:
38+
# Allow unused parameters in interface implementations
39+
- linters:
40+
- unused
41+
text: "parameter .* is unused"
42+
# Ignore build-tag separated files
43+
- path: loader\.go
44+
linters:
45+
- typecheck
46+
- path: vmreadv_linux\.go
47+
linters:
48+
- typecheck

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ man:
6969
# Generate vmlinux.h from the running kernel's BTF data.
7070
# Only needed if vmlinux.h is not already present.
7171
vmlinux:
72-
bpftool btf dump file /sys/kernel/btf/vmlinux format c > internal/bpf/vmlinux.h
72+
bpftool btf dump file /sys/kernel/btf/vmlinux format c > bpf/vmlinux.h
7373

7474
# Vendor all dependencies for offline builds and distro packaging.
7575
vendor:

PKGBUILD

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# Maintainer: Mutasem Kharma <mutasem@gspy.dev>
2+
# SPDX-License-Identifier: GPL-2.0-only
3+
#
4+
# PKGBUILD for gspy — forensic goroutine-to-syscall inspector
5+
# Targets: BlackArch Linux, Arch Linux AUR
6+
#
7+
# Build requirements:
8+
# - go >= 1.21
9+
# - clang >= 14
10+
# - linux-headers (for vmlinux.h generation)
11+
# - bpf (for BPF bytecode compilation)
12+
13+
pkgname=gspy
14+
pkgver=0.1.0
15+
pkgrel=1
16+
pkgdesc="Forensic goroutine-to-syscall inspector for live Go processes using eBPF"
17+
arch=('x86_64')
18+
url="https://github.com/Mutasem-mk4/gspy"
19+
license=('GPL-2.0-only')
20+
groups=('blackarch' 'blackarch-forensic' 'blackarch-debugger')
21+
depends=('glibc')
22+
makedepends=('go' 'clang' 'llvm' 'linux-headers' 'bpf')
23+
source=("${pkgname}-${pkgver}.tar.gz::${url}/archive/v${pkgver}.tar.gz")
24+
sha256sums=('SKIP')
25+
26+
build() {
27+
cd "${pkgname}-${pkgver}"
28+
29+
# Generate vmlinux.h from running kernel's BTF data if available
30+
if [ -f /sys/kernel/btf/vmlinux ]; then
31+
bpftool btf dump file /sys/kernel/btf/vmlinux format c > bpf/vmlinux.h
32+
fi
33+
34+
# Generate BPF bytecode from C source
35+
export PATH="${PATH}:$(go env GOPATH)/bin"
36+
go install github.com/cilium/ebpf/cmd/bpf2go@v0.14.0
37+
38+
cd internal/bpf
39+
bpf2go \
40+
-cc clang \
41+
-target bpfel \
42+
-type goroutine_meta \
43+
-type syscall_event \
44+
gspy ../../bpf/gspy.bpf.c -- \
45+
-I/usr/include \
46+
-I../../bpf \
47+
-O2 -g
48+
cd ../..
49+
50+
# Build the Go binary with reproducible flags
51+
export CGO_ENABLED=0
52+
export GOFLAGS="-buildmode=pie -trimpath -mod=readonly -modcacherw"
53+
54+
go build -trimpath \
55+
-ldflags="-s -w -X main.Version=${pkgver} -X main.BuildGoVersion=$(go version | awk '{print $3}')" \
56+
-o "${pkgname}" \
57+
./cmd/gspy
58+
}
59+
60+
check() {
61+
cd "${pkgname}-${pkgver}"
62+
# Tests use mock BPF layer — no root, no kernel, no BPF required
63+
go test -v -tags=testing ./...
64+
}
65+
66+
package() {
67+
cd "${pkgname}-${pkgver}"
68+
69+
# Binary
70+
install -Dm 755 "${pkgname}" "${pkgdir}/usr/bin/${pkgname}"
71+
72+
# Man page
73+
install -Dm 644 "man/${pkgname}.1" "${pkgdir}/usr/share/man/man1/${pkgname}.1"
74+
75+
# License
76+
install -Dm 644 LICENSE "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE"
77+
78+
# Documentation
79+
install -Dm 644 README.md "${pkgdir}/usr/share/doc/${pkgname}/README.md"
80+
}

SECURITY.md

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Security Policy
2+
3+
## Supported Versions
4+
5+
| Version | Supported |
6+
|---------|-----------|
7+
| 0.1.x | ✅ Current |
8+
9+
## Reporting Vulnerabilities
10+
11+
gspy is a security tool that runs with elevated kernel privileges (CAP_BPF, CAP_PERFMON). We take security seriously.
12+
13+
If you discover a vulnerability, please report it responsibly:
14+
15+
1. **DO NOT** open a public GitHub issue
16+
2. Email: mutasem@gspy.dev
17+
3. Include:
18+
- Description of the vulnerability
19+
- Steps to reproduce
20+
- Impact assessment
21+
- Kernel version and Go version tested
22+
23+
We will acknowledge receipt within 48 hours and provide a fix timeline within 7 days.
24+
25+
## Threat Model
26+
27+
gspy requires elevated privileges by design. The following are **not** considered vulnerabilities:
28+
29+
- Requiring CAP_BPF or CAP_SYS_ADMIN to operate
30+
- Ability to read memory from processes the user already has access to
31+
- Information disclosure about a process the user owns
32+
33+
The following **are** considered vulnerabilities:
34+
35+
- Memory corruption in the BPF layer that could cause kernel panic
36+
- Privilege escalation beyond the intended capability set
37+
- Writing to or modifying the target process (violating readonly guarantee)
38+
- Information leakage about processes the user does NOT have access to

0 commit comments

Comments
 (0)