aegis-wasm 0.1.1

Aegis - A local-first WebAssembly sandbox runtime
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
<div align="center">

# Aegis

**Run untrusted WebAssembly code safely**

[![Rust](https://img.shields.io/badge/rust-1.85%2B-orange.svg)](https://www.rust-lang.org/)
[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)](#license)
[![Crates.io](https://img.shields.io/crates/v/aegis.svg)](https://crates.io/crates/aegis)

[Installation]#installation | [CLI Usage]#cli-usage | [Library Usage]#library-usage | [Features]#features

</div>

---

## What is Aegis?

Aegis is a **WebAssembly sandbox** that lets you run untrusted code without risk. The code:

- Cannot access your filesystem (unless you allow it)
- Cannot access the network (unless you allow it)
- Cannot use unlimited memory (you set the limit)
- Cannot run forever (you set the timeout)
- Cannot crash your application

**Use cases:** Plugin systems, serverless functions, game mods, user-submitted code, CI/CD isolation, safe scripting.

---

## Installation

### CLI Tool

```bash
# From source
git clone https://github.com/aayushadhikari7/aegis
cd aegis
cargo install --path crates/aegis-cli

# Or directly (once published)
cargo install aegis-cli
```

### As a Library

Add to your `Cargo.toml`:

```toml
[dependencies]
aegis = { git = "https://github.com/aayushadhikari7/aegis" }
```

---

## CLI Usage

### Running WebAssembly

```bash
# Run a function with arguments
aegis run module.wasm --function add -- 5 10
# Output: Result: 15

# Run the default function (_start or main)
aegis run module.wasm

# Run with resource limits
aegis run module.wasm --function process \
    --memory-limit 33554432 \
    --fuel-limit 1000000 \
    --timeout 10

# Show execution metrics
aegis run module.wasm --function main --metrics
```

### Granting Permissions

By default, WASM code has **zero permissions**. You grant what it needs:

```bash
# Allow reading from /data directory
aegis run module.wasm --allow-read /data

# Allow reading and writing to /tmp
aegis run module.wasm --allow-write /tmp

# Allow logging output
aegis run module.wasm --allow-logging

# Allow access to system clock
aegis run module.wasm --allow-clock

# Combine permissions
aegis run module.wasm \
    --allow-read /data \
    --allow-write /tmp \
    --allow-logging
```

### Validating Modules

Check if a WASM file is valid before running:

```bash
aegis validate module.wasm
# Output: Module is valid

aegis validate corrupt.wasm
# Output: Module is invalid: ...
```

### Inspecting Modules

See what a WASM module contains:

```bash
# Show everything
aegis inspect module.wasm --all

# Show only exports (functions you can call)
aegis inspect module.wasm --exports

# Show only imports (what the module needs)
aegis inspect module.wasm --imports
```

Example output:
```
Module: plugin.wasm

Exports (3):
  add [function]: (i32, i32) -> (i32)
  multiply [function]: (i32, i32) -> (i32)
  memory [memory]: 1 pages

Imports (1):
  env.log [function]: (i32) -> ()
```

### Output Formats

```bash
# Human-readable (default)
aegis run module.wasm --function add -- 2 3

# JSON output
aegis run module.wasm --function add --format json -- 2 3

# Compact JSON (single line)
aegis run module.wasm --function add --format json-compact -- 2 3
```

### All CLI Options

```
aegis run <MODULE> [OPTIONS] [-- ARGS...]

Options:
  -e, --function <NAME>     Function to call (default: _start or main)
  --memory-limit <BYTES>    Max memory in bytes (default: 64MB)
  --fuel-limit <UNITS>      Max CPU fuel units (default: 1B)
  --timeout <SECONDS>       Max execution time (default: 30s)
  --allow-read <PATH>       Grant read access to path
  --allow-write <PATH>      Grant read/write access to path
  --allow-logging           Enable logging output
  --allow-clock             Enable clock/time access
  --metrics                 Show execution metrics
  -f, --format <FORMAT>     Output format: human, json, json-compact
  -v, --verbose             Increase verbosity (-v, -vv, -vvv)
  -q, --quiet               Suppress non-essential output
```

---

## Library Usage

### Basic Example

```rust
use aegis::prelude::*;
use std::time::Duration;

fn main() -> Result<(), AegisError> {
    // Create a sandboxed runtime
    let runtime = Aegis::builder()
        .with_memory_limit(64 * 1024 * 1024)  // 64 MB max
        .with_fuel_limit(1_000_000_000)        // 1 billion instructions max
        .with_timeout(Duration::from_secs(30)) // 30 second timeout
        .build()?;

    // Load a WASM module
    let module = runtime.load_file("plugin.wasm")?;

    // Create a sandbox and run code
    let mut sandbox = runtime.sandbox().build()?;
    sandbox.load_module(&module)?;

    // Call a function
    let result: i32 = sandbox.call("add", (2i32, 3i32))?;
    println!("2 + 3 = {}", result);

    Ok(())
}
```

### Loading WASM from Different Sources

```rust
// From a file
let module = runtime.load_file("plugin.wasm")?;

// From bytes (e.g., uploaded by user)
let wasm_bytes: Vec<u8> = receive_upload();
let module = runtime.load_bytes(&wasm_bytes)?;

// From WAT text format (useful for testing)
let module = runtime.load_wat(r#"
    (module
        (func (export "double") (param i32) (result i32)
            local.get 0
            i32.const 2
            i32.mul
        )
    )
"#)?;
```

### Granting Capabilities

```rust
use aegis::prelude::*;

let runtime = Aegis::builder()
    .with_memory_limit(64 * 1024 * 1024)
    .with_fuel_limit(1_000_000_000)

    // Allow reading from specific paths
    .with_filesystem(FilesystemCapability::read_only(&["/data", "/config"]))

    // Allow reading AND writing to specific paths
    .with_filesystem(FilesystemCapability::read_write(&["/tmp/sandbox"]))

    // Allow logging
    .with_logging(LoggingCapability::all())

    // Allow clock access
    .with_clock(ClockCapability::monotonic_only())

    .build()?;
```

### Registering Host Functions

Let WASM code call your Rust functions:

```rust
let mut sandbox = runtime.sandbox().build()?;

// Register a function that WASM can call
sandbox.register_func("env", "print_number", |value: i32| {
    println!("WASM says: {}", value);
})?;

sandbox.register_func("env", "add_numbers", |a: i32, b: i32| -> i32 {
    a + b
})?;

sandbox.load_module(&module)?;
sandbox.call_void("main")?;
```

### Getting Execution Metrics

```rust
let mut sandbox = runtime.sandbox().build()?;
sandbox.load_module(&module)?;

let result: i32 = sandbox.call("compute", (input,))?;

// Check how much resources were used
let metrics = sandbox.metrics();
println!("Execution time: {:?}", metrics.duration());
println!("Fuel consumed: {}", metrics.fuel_consumed);
println!("Peak memory: {} bytes", metrics.peak_memory);
```

### Handling Errors

```rust
use aegis::prelude::*;

match sandbox.call::<(i32,), i32>("process", (input,)) {
    Ok(result) => println!("Success: {}", result),

    Err(ExecutionError::OutOfFuel { consumed, limit }) => {
        println!("Code used too much CPU: {} / {}", consumed, limit);
    }

    Err(ExecutionError::Timeout(duration)) => {
        println!("Code took too long: {:?}", duration);
    }

    Err(ExecutionError::MemoryExceeded { used, limit }) => {
        println!("Code used too much memory: {} / {}", used, limit);
    }

    Err(ExecutionError::Trap(info)) => {
        println!("Code crashed: {}", info.message);
    }

    Err(e) => println!("Other error: {}", e),
}
```

### Reusing Sandboxes

```rust
let mut sandbox = runtime.sandbox().build()?;
sandbox.load_module(&module)?;

// Process multiple inputs with the same sandbox
for input in inputs {
    let result: i32 = sandbox.call("process", (input,))?;
    println!("Result: {}", result);
}

// Or reset and reuse
sandbox.reset();
sandbox.load_module(&another_module)?;
```

---

## Features

### Resource Limits

| Resource | What it Limits | Default |
|----------|---------------|---------|
| **Memory** | Max RAM the code can use | 64 MB |
| **Fuel** | Max CPU instructions (deterministic) | 1 billion |
| **Timeout** | Max wall-clock time | 30 seconds |
| **Stack** | Max call stack depth | 512 KB |

### Capabilities (Permissions)

| Capability | What it Allows |
|------------|---------------|
| **Filesystem** | Read/write specific directories |
| **Network** | Connect to specific hosts |
| **Logging** | Print output |
| **Clock** | Access system time |

**Principle:** Code has **zero** permissions by default. You explicitly grant what it needs.

### Supported Value Types

The CLI and library support these WASM types:

| Type | Example |
|------|---------|
| `i32` | `42`, `-17` |
| `i64` | `9999999999` |
| `f32` | `3.14` |
| `f64` | `3.141592653589793` |

---

## Security Model

```
┌─────────────────────────────────────┐
│         Untrusted WASM Code         │
├─────────────────────────────────────┤
│  Capability Layer (Permissions)     │  ← Can it access this resource?
├─────────────────────────────────────┤
│  Resource Limiter (Memory/CPU)      │  ← Has it exceeded limits?
├─────────────────────────────────────┤
│  Wasmtime Sandbox (Memory Safety)   │  ← Is the code valid?
└─────────────────────────────────────┘
```

**Guarantees:**
1. Code cannot access anything you don't explicitly allow
2. Code cannot use more resources than you allocate
3. Code cannot crash your application
4. Code cannot escape the sandbox

---

## Project Structure

| Crate | Description |
|-------|-------------|
| `aegis` | Main library - start here |
| `aegis-core` | Low-level engine and sandbox |
| `aegis-capability` | Permission system |
| `aegis-resource` | Memory/CPU/time limits |
| `aegis-host` | Host function registration |
| `aegis-observe` | Metrics and monitoring |
| `aegis-cli` | Command-line tool |

---

## Requirements

- **Rust 1.85+**
- Works on Linux, macOS, and Windows

---

## License

Dual-licensed under:

- [MIT License]LICENSE-MIT
- [Apache License 2.0]LICENSE-APACHE

Choose whichever you prefer.

---

## Contributing

Contributions welcome! Feel free to:

- Open issues for bugs or feature requests
- Submit pull requests
- Improve documentation

---

<div align="center">

**[GitHub]https://github.com/aayushadhikari7/aegis** | **[Issues]https://github.com/aayushadhikari7/aegis/issues**

</div>