dagx 0.2.0

A minimal, type-safe, runtime-agnostic async DAG executor with compile-time dependency validation
Documentation
# Security Policy

## Overview

dagx is a task execution library designed for safety and predictability. This document outlines security considerations, best practices, and limitations you should be aware of when using dagx in security-sensitive contexts.

## Supported Versions

| Version | Supported          |
| ------- | ------------------ |
| 0.1.x   | :white_check_mark: |

## Security Model

### What dagx Provides

- **Compile-time type safety**: Dependencies are validated at compile time, preventing type errors
- **Cycle detection**: Runtime detection of circular dependencies
- **Memory safety**: Rust's ownership system prevents memory corruption
- **Thread safety**: Interior mutability uses `parking_lot::Mutex` for safe concurrent access

### What dagx Does NOT Provide

- **Panic isolation**: Panics in one task will propagate and may affect other tasks (see Panic Handling below)
- **Resource limits**: No built-in timeout, memory limits, or CPU throttling
- **Sandboxing**: Tasks run with full process privileges
- **Authentication/Authorization**: No access control between tasks
- **Input validation**: Tasks must validate their own inputs

## Security Considerations

### 1. Panic Handling

**Current Behavior**: dagx does NOT isolate panics between tasks. If a task panics:

- The panic will propagate through the executor
- Other tasks in the same execution layer may or may not complete (timing-dependent)
- The entire DAG execution will terminate

**Recommendation**:

- Use `std::panic::catch_unwind` in tasks that may panic
- Return `Result<T, E>` from tasks and handle errors explicitly
- Test panic scenarios thoroughly

```rust
use dagx::{task, Task};
use std::panic;

struct SafeTask;

#[task]
impl SafeTask {
    async fn run(&mut self) -> Result<i32, String> {
        // Catch panics and convert to Result
        panic::catch_unwind(|| {
            // Potentially panicking code
            42
        })
        .map_err(|_| "Task panicked".to_string())
    }
}
```

### 2. Resource Limits

dagx does NOT enforce:

- Execution timeouts
- Memory limits
- CPU usage limits
- Task queue depth limits

**Recommendation**: Implement resource limits at the task level using your async runtime's facilities:

```rust
use dagx::{task, Task};
use tokio::time::{timeout, Duration};

struct TimeLimitedTask;

#[task]
impl TimeLimitedTask {
    async fn run(&mut self) -> Result<i32, String> {
        timeout(Duration::from_secs(30), async {
            // Your task logic here
            expensive_computation().await
        })
        .await
        .map_err(|_| "Task timed out".to_string())
    }
}

async fn expensive_computation() -> i32 {
    // Actual work
    42
}
```

### 3. Untrusted Input

If your DAG processes untrusted input:

- **Validate all inputs** at task boundaries
- **Sanitize outputs** before using in security-sensitive contexts
- **Limit resource consumption** (see Resource Limits above)
- **Use strongly-typed inputs** to leverage compile-time safety

```rust
use dagx::{task, Task};

struct ValidatedInput {
    max_size: usize,
}

#[task]
impl ValidatedInput {
    async fn run(&mut self, input: &String) -> Result<String, String> {
        // Validate input size
        if input.len() > self.max_size {
            return Err(format!("Input exceeds maximum size of {}", self.max_size));
        }

        // Validate input format
        if !input.chars().all(|c| c.is_alphanumeric()) {
            return Err("Input contains invalid characters".to_string());
        }

        Ok(input.clone())
    }
}
```

### 4. Dependency Injection

Tasks receive dependencies as references, which:

- **Prevents modification** of upstream results (read-only access)
- **Ensures consistency** across multiple dependent tasks
- **Avoids data races** through Rust's borrow checker

However, if your task output contains interior mutability (e.g., `Arc<Mutex<T>>`), be aware that:

- Multiple downstream tasks can mutate shared state
- This is intentional but requires careful synchronization

### 5. State Management

Tasks with mutable state (`&mut self`):

- Execute exactly once per DAG run
- Have exclusive access to their internal state during execution
- Are not reentrant (cannot execute concurrently with themselves)

**Safe**: Each task instance maintains isolated state
**Unsafe**: Sharing mutable state between tasks via global variables or `Arc<Mutex<T>>` requires manual synchronization

## Best Practices

### 1. Error Handling

Use `Result<T, E>` for all fallible operations:

```rust
use dagx::{task, Task};

struct FallibleTask;

#[task]
impl FallibleTask {
    async fn run(&mut self, input: &String) -> Result<i32, String> {
        input.parse::<i32>()
            .map_err(|e| format!("Parse error: {}", e))
    }
}
```

### 2. Timeouts

Implement timeouts for long-running or potentially-hanging operations:

```rust
use tokio::time::{timeout, Duration};

#[task]
impl MyTask {
    async fn run(&mut self) -> Result<String, String> {
        timeout(Duration::from_secs(10), async {
            // Network request or other potentially-slow operation
            fetch_data().await
        })
        .await
        .map_err(|_| "Operation timed out".to_string())?
    }
}

async fn fetch_data() -> Result<String, String> {
    Ok("data".to_string())
}
```

### 3. Resource Cleanup

Use RAII patterns and `Drop` implementations for resource cleanup:

```rust
struct FileTask {
    path: String,
}

#[task]
impl FileTask {
    async fn run(&mut self) -> Result<String, String> {
        let content = tokio::fs::read_to_string(&self.path)
            .await
            .map_err(|e| format!("File read error: {}", e))?;
        Ok(content)
    }
}
// File handle automatically closed when task completes
```

### 4. Logging and Monitoring

Add logging to tasks for observability:

```rust
use dagx::{task, Task};

struct MonitoredTask;

#[task]
impl MonitoredTask {
    async fn run(&mut self, input: &i32) -> i32 {
        println!("Task started with input: {}", input);
        let result = input * 2;
        println!("Task completed with result: {}", result);
        result
    }
}
```

### 5. Minimize Privilege

- Run dagx applications with minimum necessary privileges
- Avoid running as root or with elevated permissions
- Use operating system security features (containers, namespaces, etc.)

## Security Limitations

### Known Limitations

1. **No panic recovery**: Task panics will crash the DAG execution
2. **No resource limits**: Tasks can consume unlimited CPU, memory, or time
3. **No isolation**: All tasks run in the same process with same privileges
4. **Shared executor**: Tasks compete for executor resources

### Not Security Features

dagx is **not** designed to:

- Run untrusted code safely
- Enforce resource quotas
- Provide sandboxing
- Implement authentication or authorization
- Prevent side-channel attacks

If you need these features, consider:

- **WebAssembly sandboxing** (wasmtime, wasmer)
- **Container isolation** (Docker, podman)
- **Operating system isolation** (VMs, seccomp, AppArmor)
- **Dedicated security runtimes** (gVisor, Firecracker)

## Reporting a Vulnerability

If you discover a security vulnerability in dagx:

1. **DO NOT** open a public GitHub issue
2. Email the maintainer directly: <steve@waits.net>
3. Include:
   - Description of the vulnerability
   - Steps to reproduce
   - Potential impact
   - Suggested fix (if available)

You should receive a response within 48 hours. If the vulnerability is confirmed:

- A fix will be developed privately
- A security advisory will be published
- Credit will be given (unless you prefer anonymity)

## Security Updates

Security updates will be:

- Released as patch versions (e.g., 0.1.1)
- Announced in GitHub releases
- Published to crates.io immediately
- Documented in CHANGELOG.md

## Additional Resources

- [Rust Security Guidelines]https://anssi-fr.github.io/rust-guide/
- [OWASP Secure Coding Practices]https://owasp.org/www-project-secure-coding-practices-quick-reference-guide/
- [async-std Security]https://async.rs/security
- [Tokio Security]https://tokio.rs/tokio/topics/security

## License

This security policy is part of the dagx project and is licensed under the MIT License.