coraza 0.1.0

Safe Rust bindings to OWASP Coraza WAF
# coraza-rs

Safe Rust bindings to [OWASP Coraza](https://coraza.io/) Web Application Firewall, based on the [official C bindings](https://github.com/corazawaf/libcoraza).

Coraza is a Go-based WAF compatible with ModSecurity's SecLang. This repository provides Rust crates to embed Coraza into Rust applications.

## Crates

| Crate | Description |
|-------|-------------|
| [`coraza`]coraza/ | Safe, idiomatic Rust API |
| [`coraza-sys`]coraza-sys/ | Raw FFI bindings (auto-generated from C header) |
| [`examples`]examples/ | Usage examples |

## Quick Start

```rust
use coraza::WafConfig;

fn main() {
    let waf = WafConfig::new()
        .unwrap()
        .with_directives("SecRuleEngine DetectionOnly")
        .with_directives("SecRequestBodyAccess On")
        .build()
        .unwrap();

    let mut tx = waf.new_transaction();

    tx.process_connection("127.0.0.1", 8080, "localhost", 80).unwrap();
    tx.process_uri("/path", "GET", "HTTP/1.1").unwrap();
    tx.add_request_header("Host", "localhost");
    tx.process_request_headers().unwrap();
    tx.process_logging();

    if let Some(intervention) = tx.intervention() {
        eprintln!("Blocked with status {}", intervention.status);
    }
}
```

## Build Requirements

- **Rust** 1.75+ (edition 2021)
- **Go** 1.21+ (for compiling the Coraza WAF engine)
- **C compiler** (gcc/clang on Unix, MSVC on Windows)
- **libclang** (for bindgen)

On Ubuntu/Debian:

```sh
sudo apt install golang-go libclang-dev
```

On macOS:

```sh
brew install go llvm
```

## Building

```sh
cargo build
```

The first build compiles the Go WAF engine into a static library and generates Rust FFI bindings. Subsequent builds are fast.

## Examples

```sh
cargo run --bin simple_get
cargo run --bin deny_rule
cargo run --bin with_callbacks
```

### `simple_get`

Minimal WAF usage with DetectionOnly mode — processes a GET request and checks for interventions.

### `deny_rule`

WAF with a deny rule that blocks requests from specific IPs — demonstrates handling a 403 intervention.

### `with_callbacks`

Registers debug log and error callbacks — shows how to capture matched rule details.

## API Overview

### Configuration

```rust
use coraza::{WafConfig, LogLevel};

let waf = WafConfig::new()?
    .with_directives("SecRuleEngine On")
    .with_directives("SecRequestBodyAccess On")
    .with_debug_log_callback(|level, msg, fields| {
        eprintln!("[{level}] {msg} {fields}");
    })
    .with_error_callback(|rule| {
        eprintln!("Rule {} matched: {}", rule.rule_id, rule.message);
    })
    .build()?;
```

### Transaction Processing

Transactions follow Coraza's phase-based lifecycle:

```rust
let mut tx = waf.new_transaction();

// Phase 0: Connection & URI
tx.process_connection("127.0.0.1", 8080, "localhost", 80)?;
tx.process_uri("/path", "GET", "HTTP/1.1")?;

// Phase 1: Request headers
tx.add_request_header("Host", "localhost");
tx.process_request_headers()?;  // may return Err(Intervention)

// Phase 2: Request body (if SecRequestBodyAccess On)
tx.append_request_body(b"hello=world")?;
tx.process_request_body()?;

// Phase 3: Response headers
tx.process_response_headers(200, "HTTP/1.1")?;

// Phase 4: Response body (if SecResponseBodyAccess On)
tx.append_response_body(b"<html>...</html>")?;
tx.process_response_body()?;

// Phase 5: Logging (always run, even on interruption)
tx.process_logging();

// Check for rule matches
if let Some(intervention) = tx.intervention() {
    eprintln!("Blocked: {}", intervention.status);
}
```

## Thread Safety

| Type | `Send` | `Sync` | Notes |
|------|--------|--------|-------|
| `Waf` | Yes | Yes | Immutable after creation; safe to share for concurrent transaction creation |
| `WafConfig` | Yes | No | Builder consumed by `build()` |
| `Transaction` | Yes | No | Mutable state; must not be shared across threads |

## License

Licensed under the [Apache License, Version 2.0](LICENSE).