Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 138 additions & 38 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,76 @@
# Contributing to [RASP.Net](https://github.com/JVBotelho/RASP.Net)
# Contributing to RASP.Net

First of all, thank you for being here! RASP.Net is a project focused on the intersection of **Extreme Performance** and **Active Security**. To maintain our technical integrity, we follow a set of strict engineering standards.
Thank you for your interest in RASP.Net. This project explores the intersection of **extreme performance** and **active security** in .NET. Our goal is to prove that runtime protection doesn't require sacrificing throughput or latency.

## 🛡️ The Golden Rules
We welcome contributions from all skill levels, but we hold code to strict engineering standards. This document explains our performance philosophy and technical requirements.

---

## 🎯 Why Performance Matters

RASP.Net operates in the **request path** of high-throughput applications. In production:

- A typical API responds in **2-5ms**
- Our total inspection budget must stay under **5% of response time** (~100-250μs)
- One poorly optimized detection can destroy SLA compliance

We benchmark against physics, not intuition.

### The Physics of Latency

Understanding hardware limits is essential:

| Operation | Latency |
|-----------|---------|
| L1 Cache Access | ~1 ns |
| L2 Cache Access | ~3-10 ns |
| Main Memory (RAM) | ~100 ns |
| Context Switch | ~1-2 μs |

Your code operates in the **microsecond realm**. Design accordingly.

---

## 📊 Performance Tiers

We classify inspection logic into tiers based on **added latency** (p99). These align with real-world SLA requirements.

| Tier | Latency Budget | Context | Examples |
|------|---------------|---------|----------|
| **🏎️ Tier 1 (Hot Path)** | **< 2 μs** | Header inspection, URL scanning, auth tokens | `SearchValues<byte>`, SIMD (AVX2/512), branchless logic |
| **🚀 Tier 2 (Standard)** | **< 20 μs** | JSON body inspection (<4KB), shallow parsing | `Utf8JsonReader`, zero-allocation parsers |
| **⚙️ Tier 3 (Deep)** | **< 100 μs** | Complex grammar analysis (SQL/XML), regex with backtracking | DFA regex, careful state machines |
| **❌ Rejected** | **> 200 μs** | Single-inspection overhead breaks user SLA | N/A |

**Note:** If your PR falls into Tier 3 for hot-path code, we'll work with you during code review to identify optimizations (hidden allocations, boxing, inlining opportunities).

---

## 🛡️ Code Standards

### 1. Zero Allocations on Hot Path

The **Hot Path** refers to the detection engine's core loops and interceptors where <10ns overhead is critical. Any code triggered during request inspection must not allocate memory on the managed heap.
The **Hot Path** refers to the detection engine's core loops and interceptors where low-latency is critical. Any code triggered during request inspection must not allocate memory on the managed heap.

* **Avoid:** `new`, string concatenation (`+`), LINQ, or `Task` allocations.
* **Use:** `Span<T>`, `ReadOnlySpan<T>`, `stackalloc`, or `ArrayPool<T>`.
**Forbidden:**
- `new`, string concatenation (`+`), LINQ, or `Task` allocations
- `params object[]`, closures, boxing
- `async/await` state machines inside inspection loops

#### 💡 Memory Management Pattern
**Required:**
- `Span<T>`, `ReadOnlySpan<T>`, `stackalloc`, or `ArrayPool<T>`

When handling variable-sized buffers, always use the hybrid approach. Use the **Stack** for small payloads and the **ArrayPool** for larger ones. This avoids heap allocations while protecting against `StackOverflowException`.
#### 💡 Memory Management Pattern

When handling variable-sized buffers, always use the hybrid approach. Use the **Stack** for small payloads and the **ArrayPool** for larger ones. This avoids heap allocations while protecting against `StackOverflowException`.
```csharp
// 1. Safety check: avoid invalid or empty allocations
if (maxSize <= 0) return;
// Safety check: avoid invalid allocations or DoS attempts
// RASP should never inspect massive payloads in-memory.
const int MaxInspectionLimit = 32 * 1024; // 32KB Hard Limit
if (maxSize <= 0 || maxSize > MaxInspectionLimit) return;

// 2. Define a safe threshold for stack allocation
const int StackThreshold = 256;
const int StackThreshold = 512;

Span<byte> buffer;
byte[]? rented = null;
Expand All @@ -43,44 +93,72 @@ try
}
finally
{
// 3. Critical: Always return rented memory to avoid leaks
// Critical: Always return rented memory to avoid leaks
if (rented is not null)
{
// Use clearArray: true ONLY if the buffer contains sensitive data (e.g., passwords)
ArrayPool<byte>.Shared.Return(rented, clearArray: false);
}
}
```

> **Notes:**
> - The maxSize <= 0 check is our "safety belt" against runtime exceptions and potential memory corruption triggers.
> - The 256-byte threshold is a conservative guard to avoid excessive stack usage and is not a hard rule.
> - Do not use stackalloc across async/await boundaries.
> - For maxSize <= 0, the operation is a no-op by design.
> - The `maxSize <= 0` check is our "safety belt" against runtime exceptions and potential memory corruption triggers.
> - The 512-byte threshold is a conservative guard to avoid excessive stack usage and is not a hard rule.
> - Do not use `stackalloc` across `async/await` boundaries.
> - For `maxSize <= 0`, the operation is a no-op by design.

### 2. Benchmark or it didn't happen
---

Every detection logic change **must** include a [BenchmarkDotNet](https://benchmarkdotnet.org/) report in the Pull Request description. We prioritize **p95 and p99.9 latency**.
### 2. Benchmarks Are Mandatory

### 3. English Only
Every detection logic change **must** include a [BenchmarkDotNet](https://benchmarkdotnet.org/) report in the PR description. We prioritize **p95 and p99.9 latency**.

All code documentation (XML docs), error messages, and commit messages must be in English. This ensures that all global contributors and users can understand and audit the security logic effectively.
**Fail conditions:**
- Gen0/Gen1/Gen2 columns show anything other than `-` (zero) on hot path
- p99 latency regression > 10% vs baseline

**Pass criteria:**
- Overhead within ±5% of baseline
- Zero allocations confirmed

Run: `dotnet run -c Release --project src/Rasp.Benchmarks`

---

## 📊 Performance Tiers (The "Race Track")
### 3. Security Test Suite

We don't reject code simply because it doesn't hit the ideal nanoseconds on the first try. Instead, we classify contributions into **Tiers**. Our goal is to help you "tune" your code to Tier 1 through technical mentorship during Code Review.
Run the exploit suite before opening a PR:
```bash
dotnet test
```

| Tier | Latency Overhead | Status |
| --- | --- | --- |
| **🏎️ Elite (Tier 1)** | **< 10ns** | **Hot Path Ready.** Our gold standard. Essential for the core detection engine. |
| **🚀 Optimal (Tier 2)** | **10ns - 50ns** | **Feature Ready.** Acceptable for complex inspections, nested objects, or conditional logic. |
| **🐢 Standard (Tier 3)** | **> 50ns** | **Review Required.** Requires architectural discussion or optimization (e.g., SIMD or Source Generators). |
**Requirement:** 100% block rate on known attack vectors. Security is non-negotiable.

**How it works:**
---

### 4. Thread Safety

The RASP engine is a singleton. All state must be:
- Immutable (`readonly`, `init`)
- Thread-safe (use `Interlocked`, `FrozenDictionary<T>`, or `ConcurrentDictionary<T>`)

---

### 5. English Only

All code documentation (XML docs), error messages, and commit messages must be in English. This ensures that all global contributors and users can understand and audit the security logic effectively.

---

## 🚀 Pull Request Process

* If your PR falls into **Tier 3**, we will work with you to identify bottlenecks (hidden allocations, boxing, lack of inlining).
* Every new feature should strive to move up the tiers before being merged into the `develop` branch.
1. **Branching:** Create your feature branch from `develop`. The `master` branch is reserved for stable releases.
2. **Draft PRs:** We encourage opening a **Draft PR** early in the process to discuss architectural decisions before finalizing the code.
3. **Code Quality:** Ensure [CodeQL](https://codeql.github.com/) scans pass without new security alerts.
4. **ADR Updates:** If your PR introduces structural changes, please update or create a new **ADR (Architecture Decision Record)** in the `docs/ADR` folder.

We value **collaboration over gatekeeping**. If your PR needs optimization, we'll help during code review.

---

Expand All @@ -92,21 +170,43 @@ If you found a bug or have a suggestion for improvement:
2. **Provide a minimal reproducible example** (ideally a unit test or a small console app).
3. **Include your environment details**: .NET version, OS, and hardware (especially for performance-related issues).

When reporting bugs, please provide:
- **Full stack trace** with line numbers
- **Environment:** OS, architecture (x64/ARM64), .NET version
- **Minimal repro:** Failing unit test or small console app

---

## 🚀 Pull Request Process
## ⚠️ Common Pitfalls

1. **Branching**: Create your feature branch from `develop`. The `master` branch is reserved for stable releases.
2. **Draft PRs**: We encourage opening a **Draft PR** early in the process to discuss architectural decisions before finalizing the code.
3. **Code Quality**: Ensure [CodeQL](https://codeql.github.com/) scans pass without new security alerts.
4. **ADR Updates**: If your PR introduces structural changes, please update or create a new **ADR (Architecture Decision Record)** in the `docs/ADR` folder.
These patterns will require revision before merge:

| Anti-Pattern | Why It's Problematic | Better Alternative |
|--------------|---------------------|-------------------|
| `input.Contains("<script>")` | Allocates, slow | `input.AsSpan().IndexOfAny(SearchValues)` |
| `Regex` without timeout | ReDoS vulnerability | Set `RegexOptions.NonBacktracking` or use timeout |
| `.ToList()` / `.ToArray()` in middleware | Heap allocation | `foreach` over `IEnumerable<T>` |
| `catch (Exception) { }` | Hides bugs, destroys observability | Log or rethrow |
| `Console.WriteLine` | Synchronous, blocks thread | Use `ILogger` abstraction |

---

## 💻 Development Environment

To ensure benchmark consistency, please use the following setup for performance testing:

* **SDK**: .NET 10.0.102 or newer.
* **Mode**: Always run benchmarks in `Release` mode.
* **Hardware**: Specify your CPU and RAM speed in the PR. (Our reference baseline is the AMD Ryzen 7 7800X3D).
- **SDK:** .NET 10.0.102 or newer
- **Mode:** Always run benchmarks in `Release` mode
- **Hardware:** Specify your CPU and RAM speed in the PR. (Our reference baseline is the AMD Ryzen 7 7800X3D)

---

## 🏆 Recognition

Contributors who optimize a critical path by >20% or identify a major security gap get recognition in `ELITE_CONTRIBUTORS.md`.

We respect engineers who understand the machine.

---

**Questions?** Open a discussion in GitHub Discussions. We're here to help you ship high-quality code.
Loading