panasyn 0.1.0

A lightweight GPU-accelerated terminal emulator for macOS and Linux.
# ANSI Fuzzing

## Overview

Panasyn includes a robust ANSI fuzzing framework for testing terminal robustness against malformed, invalid, or malicious input sequences. The terminal must **never panic** regardless of input.

## Fuzzing approach

The fuzzer generates random ANSI byte sequences and replays them through the parser/grid engine. Two modes are available:

### Random fuzzing

Generates fully random byte sequences (0-255) of varying lengths (1-4096 bytes):

```bash
cargo run --release -- fuzz 10000
```

### Categorized fuzzing

Targets specific vulnerability categories:

```bash
cargo run --release -- fuzz --categories
```

Output:
```
=== Fuzz Category Report ===
  ✓ malformed_utf8: 100 passes, 0 crashes
  ✓ broken_csi: 100 passes, 0 crashes
  ✓ oversized_params: 100 passes, 0 crashes
  ✓ incomplete_osc: 100 passes, 0 crashes
  ✓ all_byte_values: 100 passes, 0 crashes
  ✓ unicode_edge: 100 passes, 0 crashes
```

## Input categories

| Category | Description | Example |
|----------|-------------|---------|
| Malformed UTF-8 | Incomplete sequences, overlong encodings | `\xE2\x82` (incomplete 3-byte) |
| Broken CSI | CSI sequences without final byte | `\x1B[0` (truncated) |
| Oversized parameters | Extreme SGR values, 9-digit numbers | `\x1B[999999999m` |
| Incomplete OSC | OSC sequences without BEL/ST | `\x1B]0;title` (never terminated) |
| Strobed ESC | Rapid ESC sequences | `\x1B\x1B\x1B\x1B...` |
| Unicode edge | Non-characters, BOM, zero-width | U+FFFE, U+FFFF, U+200B |
| Invalid wide chars | Combining marks in isolation | U+0300, U+094D |
| DEC private sequences | Random `\x1B[?...` | `\x1B[?9999h` |
| Interleaved controls | Mixed control + printable | `\x01\x02Hello\x03` |

## Fuzzing requirements

- Terminal must **never panic** on any input
- Renderer must **never crash**
- Invalid sequences are **handled safely** (ignored or gracefully degraded)
- Errors are **only logged in debug mode** (no stderr spam in release)
- Memory must not grow unboundedly
- No undefined behavior or unsafe code panics

## How it works

```
fuzz::fuzz_iterations(n, cols, rows)
  │
  ├── generate_random_fuzz()   (75% of iterations)
  └── generate_structured_fuzz() (25% of iterations)
  fuzz_bytes(data, cols, rows)
    ├── std::panic::catch_unwind
    │     │
    │     ├── Grid::new()
    │     ├── Scrollback::new_scrollback()
    │     ├── Parser::new()
    │     ├── parser.advance(data, terminal)
    │     └── return "ok" or panic message
    ├── Ok → pass
    └── Err → crash (record data + message)
```

## Adding new fuzz patterns

Edit `generate_structured_fuzz()` in `src/replay/fuzz.rs`:

```rust
fn generate_structured_fuzz(rng: &mut impl FnMut() -> u8) -> Vec<u8> {
    let kind = rng();  // which pattern to generate
    match kind % 12 {
        0 => { /* malformed UTF-8 */ }
        1 => { /* broken CSI */ }
        // ... add new patterns here
        _ => {}
    }
}
```

## CI integration

On every push:

```bash
cargo run --release -- fuzz 1000 --categories
```

Any crash fails CI immediately.

## Performance

- ~50,000 iterations/second on M4 MacBook
- Memory: ~1 MB per iteration (cleaned between runs)
- Each iteration creates fresh grid + scrollback + parser

## Future improvements

- [ ] `cargo-fuzz` / `libfuzzer` integration for coverage-guided fuzzing
- [ ] AFL++ corpus generation
- [ ] Structured fuzzing for OSC sequences (title, clipboard, hyperlinks)
- [ ] Fuzzing with large scrollback states
- [ ] Differential fuzzing against Alacritty/Kitty output