Contributing Guide
How to contribute to NERRF development
Welcome Contributors! 👋
NERRF is an open-source project actively seeking contributions. Whether you're a security researcher, kernel engineer, ML enthusiast, or DevOps engineer, there's a place for you.
Code of Conduct
We are committed to providing a welcoming and inclusive environment. Please read our Code of Conduct before participating.
Getting Started
1. Fork & Clone
git clone https://github.com/YOUR_USERNAME/nerrf.git
cd nerrf
git remote add upstream https://github.com/Itz-Agasta/nerrf.git2. Set Up Development Environment
# Install dependencies
cd tracker && bash scripts/install-deps.sh
# Build locally
make tracker
# Run tests
make test3. Create a Feature Branch
git checkout -b feature/my-featureContribution Types
Bug Reports
Found a bug?
- Check existing issues: existing issues
- Create a new issue with:
- Clear title and description
- Steps to reproduce
- Expected vs. actual behavior
- Environment (OS, kernel version, Go version)
- Tracker logs (if applicable)
Example:
Title: Tracker crashes on kernel 5.4 with eBPF ring buffer
Description:
When running the tracker on Ubuntu 20.04 (kernel 5.4),
the tracker panics with "ringbuf read error: operation not supported"
Steps:
1. uname -r # 5.4.0-42-generic
2. make tracker
3. sudo ./bin/tracker
4. Observe panic
Expected: Tracker attaches and streams events
Actual: Crashes immediatelyFeature Requests
Want a new feature?
- Open a discussion: Discussions
- For concrete proposals, open an issue with:
- Feature description
- Use case / motivation
- Proposed implementation approach
- Estimated effort (small/medium/large)
Documentation
Improve docs?
- Fix typos, add examples, clarify concepts
- Update diagrams or architecture docs
- Add troubleshooting sections
- Create new guides for common scenarios
No PR needed for minor fixes! Just point them out in an issue.
Code Contributions
Ready to code?
- Small fixes (typos, comments): Direct PR
- Medium features (new syscall, new metric): Discuss in issue first
- Large features (new detection model, new sandbox): Open a discussion + RFC
Development Workflow
Tracker Component Example
Goal: Add support for the chmod syscall
Step 1: Plan
Open issue: "Feature: Add chmod syscall instrumentation"
Description:
Add capability to detect permission changes on files,
useful for detecting ransomware disabling security tools.
Implementation:
1. Add tracepoint in tracepoints.c: sys_enter_fchmod + sys_enter_chmod
2. Update event struct with new/old permissions
3. Add syscall ID mapping in main.go
4. Update protobuf schema (trace.proto)
5. Regenerate gRPC stubs
6. Add unit tests for permission parsing
7. Update docs/tracker/overview.mdStep 2: Branch
git checkout -b feat/chmod-syscallStep 3: Implement eBPF
Edit tracker/bpf/tracepoints.c:
SEC("tracepoint/syscalls/sys_enter_chmod")
int trace_chmod(struct trace_event_raw_sys_enter *ctx) {
struct event *e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
if (!e) return 0;
fill_common(e, ctx);
e->syscall_id = 4; // New ID for chmod
const char *pathname = (const char *)ctx->args[0];
bpf_probe_read_user_str(&e->path, sizeof(e->path), pathname);
// Extract mode argument
e->mode = ctx->args[1]; // Second argument is mode
bpf_ringbuf_submit(e, 0);
return 0;
}Step 4: Update Protobuf
Edit proto/trace.proto:
message Event {
// ... existing fields ...
uint32 mode = 11; // New field for chmod
}Step 5: Regenerate Stubs
make protoc # Regenerates trace.pb.go, trace_grpc.pb.goStep 6: Update Userspace
Edit tracker/cmd/tracker/main.go:
func syscallName(id uint32) string {
switch id {
case 1:
return "openat"
case 2:
return "write"
case 3:
return "rename"
case 4:
return "chmod" // NEW
default:
return "unknown"
}
}
// Also update event struct if needed:
type event struct {
// ... existing fields ...
Mode uint32 // New field
}Step 7: Test
# Build
make tracker
# Manual test
sudo ./bin/tracker &
chmod 000 /tmp/testfile # Generate chmod syscall
grpcurl -plaintext -d '{}' localhost:50051 nerrf.trace.Tracker/StreamEvents | grep chmod
# Stop tracker
pkill trackerStep 8: Add Tests
Create tracker/cmd/tracker/main_test.go:
func TestSyscallName(t *testing.T) {
tests := []struct{
id uint32
expected string
}{
{1, "openat"},
{2, "write"},
{3, "rename"},
{4, "chmod"}, // NEW
}
for _, tt := range tests {
result := syscallName(tt.id)
if result != tt.expected {
t.Errorf("syscallName(%d) = %s, want %s", tt.id, result, tt.expected)
}
}
}Step 9: Document
Update docs/content/docs/tracker/overview.mdx:
| Syscall | ID | Purpose |
| ------- | -- | -------------------------------- |
| openat | 1 | File open/create |
| write | 2 | File write |
| rename | 3 | File rename |
| chmod | 4 | Permission changes | ← NEWStep 10: Commit
git add tracker/bpf/tracepoints.c proto/trace.proto \
tracker/cmd/tracker/main.go tracker/cmd/tracker/main_test.go \
docs/content/docs/tracker/overview.mdx
git commit -m "feat: add chmod syscall instrumentation
- Add sys_enter_chmod tracepoint (ID 4)
- Extract mode parameter from syscall args
- Update protobuf schema with mode field
- Add syscall name mapping
- Include unit tests
- Update Tracker documentation"Step 11: Push & Create PR
git push origin feat/chmod-syscallThen open PR on GitHub with title and description referencing the issue.
Code Style Guidelines
Go Code
// Use short, meaningful variable names
func processEvent(e *event) {
pid := e.Pid // OK
p := e.Pid // OK (loop counter)
processIdentifier := e.Pid // Too verbose
}
// Comment exported functions
// processEvent handles eBPF event conversion
func processEvent(e *event) error { ... }
// Keep functions small (<50 lines)
// If >50 lines, consider breaking into helpers
// Use standard library when possible
// Avoid external dependencies unless necessaryeBPF Code
// Inline comments for complex logic
static __always_inline void fill_common(struct event *e, struct pt_regs *ctx) {
e->ts = bpf_ktime_get_ns(); // Kernel monotonic time
e->pid = bpf_get_current_pid_tgid() >> 32; // Extract PID from tgid
}
// Avoid unnecessary memory allocations
// All eBPF variables must be stack-allocated
// Always validate reservations
struct event *e = bpf_ringbuf_reserve(&events, sizeof(*e), 0);
if (!e) return 0; // Essential error checkProtobuf
// Use clear, descriptive field names
message Event {
google.protobuf.Timestamp ts = 1; // Good
uint32 pid = 2; // Good
string reserved_field_1 = 3; // Don't do this
}
// Reserve field numbers for future use
reserved 10 to 20; // Reserved for future expansionTesting Requirements
Minimum Coverage
- Tracker changes: ≥80% code coverage
- eBPF changes: Unit tests + integration tests
- Protobuf changes: Forward/backward compatibility tests
Running Tests
# Unit tests
make test
# Coverage report
make coverage
# Integration tests (requires root + eBPF)
make e2e
# Load tests
make benchExample Test
func TestSanitizeString(t *testing.T) {
tests := []struct {
input []byte
expected string
desc string
}{
{
input: []byte("/etc/passwd\x00\x00\x00\x00"),
expected: "/etc/passwd",
desc: "null-terminated string",
},
{
input: []byte("valid-utf8\x00"),
expected: "valid-utf8",
desc: "valid UTF-8",
},
{
input: []byte("invalid\xff\xfe\x00"),
expected: "invalid??",
desc: "invalid UTF-8 replaced",
},
}
for _, tt := range tests {
result := sanitizeString(tt.input)
if result != tt.expected {
t.Errorf("%s: got %q, want %q", tt.desc, result, tt.expected)
}
}
}Commit Message Guidelines
Use Conventional Commits:
<type>(<scope>): <subject>
<body>
<footer>Types:
feat– New featurefix– Bug fixdocs– Documentationstyle– Formatting, missing semicolons, etc.refactor– Code cleanup without functionality changeperf– Performance improvementtest– Adding/updating testschore– Build, CI, dependency updates
Example:
feat(tracker): add chmod syscall support
- Instrument sys_enter_chmod and sys_enter_fchmod tracepoints
- Extract permission bits from syscall arguments
- Update event protobuf schema with mode field
- Add 10 new unit tests with 95% coverage
Fixes #123Documentation Standards
For Code Changes
Every significant code change should include:
- Comment block (if exported)
- Inline comments (for non-obvious logic)
- Unit tests (with test documentation)
- CHANGELOG entry (if user-facing)
For New Features
Create/update docs in docs/content/docs/:
docs/content/docs/
├── tracker/
│ ├── overview.mdx (← Add feature to capabilities table)
│ ├── implementation.mdx (← Add implementation details)
│ └── quick-start.mdx (← Add usage example)
├── architecture.mdx (← Update system diagram if relevant)
└── threat-model.mdx (← Update detection section if relevant)Questions?
- Discussions: Discussions
- Email: rupam.golui@proton.me
- Twitter: @nerrf_ai
- Documentation: You're reading it!