RavenFabric

Security-first distributed execution engine. Network-agnostic, E2E encrypted, policy-driven, ZTNA.

RavenFabric is a universal agent that provides secure, policy-controlled access to any system — regardless of network topology, operating system, or device class. It unifies mesh VPN, remote execution, configuration management, and zero-trust access into a single binary with no runtime dependencies.

Key Properties

  • E2E encrypted — Noise XX mutual authentication (same crypto core as WireGuard)
  • Deny-by-default — Policy engine rejects anything not explicitly allowed
  • Network-agnostic — Works over WebSocket, QUIC, WireGuard, Tor, LoRa, Bluetooth, and more
  • Single static binary — No runtime dependencies, deploys anywhere
  • Audit everything — Every action produces a structured JSON audit entry

Installation

RavenFabric requires Rust 1.85+ (Edition 2024).

# Clone the repository
git clone https://github.com/egkristi/RavenFabric.git
cd RavenFabric

# Build all binaries (release mode)
cargo build --release

# Binaries are in target/release/
ls target/release/rf target/release/rf-agent target/release/rf-relay

Static Binary (Linux)

For Linux deployments, build with musl for a fully static binary:

# Install musl target
rustup target add x86_64-unknown-linux-musl

# Build static binary
cargo build --release --target x86_64-unknown-linux-musl

Verify Installation

# Check CLI
./target/release/rf --version

# Check agent
./target/release/rf-agent --help

# Check relay
./target/release/rf-relay --help

Platform Support

PlatformStatusNotes
Linux x86_64Fully supportedStatic musl binaries
Linux aarch64Fully supportedStatic musl binaries
macOS x86_64Fully supported
macOS aarch64Fully supportedApple Silicon
Windows x86_64Fully supported
Linux armv7Best effortRaspberry Pi
FreeBSDBest effort
AndroidPlannedNDK cross-compile
iOSPlannedNetwork Extension

Quick Start

This guide walks through a minimal setup: one relay, one agent, one CLI client.

1. Generate Keys

# Generate agent keypair
rf-agent --generate-key /etc/ravenfabric/agent.key

# Generate CLI keypair
rf --generate-key ~/.config/ravenfabric/cli.key

2. Start the Relay

The relay is a stateless encrypted broker. It never sees plaintext.

rf-relay --listen 0.0.0.0:9090 --secret "your-meet-secret"

3. Start the Agent

rf-agent \
  --relay wss://relay.example.com:9090/meet \
  --key /etc/ravenfabric/agent.key \
  --policy /etc/ravenfabric/policy.yaml \
  --id web-01

4. Execute a Command

# One-time enrollment token
rf exec --relay wss://relay.example.com:9090/meet \
  --token "enrollment-token" \
  "hostname"

Output:

web-01

5. Verify Audit Log

Every action is logged:

{
  "timestamp": "2024-01-15T10:30:00Z",
  "action": "exec",
  "command": "hostname",
  "agent_id": "web-01",
  "result": "success",
  "exit_code": 0
}

Next Steps

Configuration

RavenFabric uses a TOML configuration file (raven.toml).

Agent Configuration

[agent]
id = "web-01"
relay = "wss://relay.example.com/meet"
key_path = "/etc/ravenfabric/agent.key"
policy_path = "/etc/ravenfabric/policy.yaml"
audit_path = "/var/log/ravenfabric/audit.jsonl"

[transport]
driver = "websocket"
reconnect_interval = 5
max_retries = 0  # infinite

[resources]
max_output_bytes = 10485760  # 10 MB
timeout_seconds = 300        # 5 minutes
max_concurrent = 10

Relay Configuration

[relay]
listen = "0.0.0.0:9090"
meet_secret = "env:RELAY_SECRET"  # Load from environment

[rate_limit]
requests_per_second = 100
burst = 200
per_ip = true

CLI Configuration

The CLI reads from ~/.config/ravenfabric/config.toml:

[cli]
default_relay = "wss://relay.example.com/meet"
key_path = "~/.config/ravenfabric/cli.key"
timeout = 30

Environment Variables

VariableDescription
RELAY_SECRETRelay meet secret (when using env: prefix)
RF_KEY_PATHOverride key file path
RF_RELAYOverride relay URL
RF_POLICYOverride policy file path
RUST_LOGLogging level (info, debug, trace)

Architecture Overview

RavenFabric is organized as a layered architecture with strict dependency boundaries.

Layers

┌──────────────────────────────────┐
│        Application Layer         │  rf-cli, rf-agent, rf-relay
│  (binaries, user-facing tools)   │
├──────────────────────────────────┤
│         Executor Layer           │  rf-executor
│  (command execution, streaming)  │
├──────────────────────────────────┤
│          Policy Layer            │  rf-policy
│  (deny-by-default enforcement)  │
├──────────────────────────────────┤
│           RPC Layer              │  rf-rpc
│  (message types, codec, mux)    │
├──────────────────────────────────┤
│        Transport Layer           │  rf-transport
│  (drivers, connection mgmt)     │
├──────────────────────────────────┤
│          Crypto Layer            │  rf-crypto
│  (Noise XX, key management)     │
└──────────────────────────────────┘

Crates

CratePurposeLOCTests
rf-cryptoNoise XX handshake, SecureChannel, key management, post-quantum KEM~1,30025
rf-transportDriver trait, WebSocket/QUIC/Memory, NAT, mesh, WireGuard, overlays~5,300121
rf-rpcMessage types, msgpack codec, yamux mux, DTN, routing, controller~2,90061
rf-auditStructured JSON-lines audit logging53
rf-policyPolicy enforcement, RBAC, capabilities, distributed policy~1,50031
rf-executorCommand execution, streaming, orchestration, PTY, plugins~3,60048
rf-bootstrapOTP enrollment, TrustStore~38011

Total: ~16,700 LOC | 336 tests | 0 clippy warnings

Data Flow

Client (rf CLI)
  │
  │ Noise XX handshake
  │ ↕ mutual authentication
  │
  ├── SecureChannel (E2E encrypted)
  │   │
  │   │ yamux multiplexed
  │   │
  │   ├── RPC stream (msgpack)
  │   │   ├── Request → Policy check → Execute → Audit → Response
  │   │   └── Streaming stdout/stderr
  │   │
  │   └── Control stream
  │       ├── Heartbeat
  │       └── Metrics
  │
  └── Transport (WebSocket / QUIC / Memory / ...)
      │
      └── Relay (opaque forwarding, never decrypts)
          │
          └── Agent (rf-agent)
              ├── Policy engine (final authority)
              ├── Executor (sandboxed)
              └── Audit log (append-only)

Design Principles

  1. Security is non-negotiable — No command executes without policy check
  2. Agent is final authority — Orchestrator cannot override agent policy
  3. Zero trust — Every connection mutually authenticated
  4. Audit everything — Every action logged, no exceptions
  5. Network agnostic — Any byte-moving channel is a valid transport
  6. Single binary — No runtime dependencies

Security Model

RavenFabric's security is built on three pillars: cryptographic identity, deny-by-default policy, and comprehensive audit logging.

Trust Model

               ┌─────────────┐
               │  Trust Root  │
               │  (key pair)  │
               └──────┬──────┘
                      │
         ┌────────────┼────────────┐
         │            │            │
    ┌────▼────┐  ┌────▼────┐  ┌───▼────┐
    │  Agent  │  │  Agent  │  │  CLI   │
    │ key pair│  │ key pair│  │key pair│
    └─────────┘  └─────────┘  └────────┘

Every entity has a unique Ed25519 key pair. Identity is cryptographic — there are no usernames, passwords, or certificates.

Noise XX Handshake

All connections use the Noise XX handshake pattern:

Noise_XX_25519_ChaChaPoly_BLAKE2s

This provides:

  • Mutual authentication — Both sides prove their identity
  • Forward secrecy — Ephemeral keys per session
  • Identity hiding — Static keys encrypted during handshake
  • Relay opacity — Relay sees only random bytes

Handshake Flow

Initiator                          Responder
    │                                  │
    │── e ─────────────────────────►   │  (ephemeral key)
    │                                  │
    │   ◄──────────────── e, ee, s, es │  (ephemeral + static)
    │                                  │
    │── s, se ─────────────────────►   │  (static key, encrypted)
    │                                  │
    │         [secure channel]         │

Policy Engine

The policy engine is deny-by-default. If a rule doesn't explicitly allow an action, it is denied.

Two-Phase Check

  1. Controller pre-flight — Validates the request before forwarding
  2. Agent local check — Agent independently validates (final authority)

A compromised controller cannot override agent policy.

Policy YAML

spec:
  commands:
    allow:
      - pattern: "^systemctl status .*"
      - pattern: "^journalctl.*"
    deny:
      - pattern: ".*rm.*-rf.*"
  filesystem:
    allow:
      - path: /opt/app
      - path: /var/log
    deny:
      - path: /etc/shadow
  resources:
    maxOutputBytes: 10485760
    timeoutSeconds: 300

Security Invariants

These invariants are enforced at all times:

  1. No command executes without policy check
  2. No connection accepted without completed Noise handshake
  3. Audit log is append-only (no delete/truncate)
  4. Private keys zeroed from memory on drop
  5. OTP tokens are single-use, hash-stored, TTL-enforced
  6. Symlink resolution before path policy checks
  7. Output size bounded (prevent memory exhaustion)
  8. Execution timeout enforced (prevent hanging)
  9. No shell injection — commands policy-checked
  10. Relay never decrypts payload (E2E between agent and client)

Capability Tokens

RavenFabric supports Biscuit-inspired capability tokens:

  • Self-contained — Carry their own signed permissions
  • Delegatable — Agent A can grant Agent B limited capabilities
  • Attenuatable — Capabilities can be narrowed, never widened
  • Offline-verifiable — No central authority needed at execution time

Post-Quantum Resistance

Hybrid key exchange (ML-KEM + X25519) protects against harvest-now-decrypt-later attacks. The post-quantum layer is additive — classical security is never weakened.

Wire Protocol

RavenFabric uses a custom binary wire protocol optimized for security and efficiency.

Frame Format

┌──────────────┬─────────┬──────────────────────────────────┐
│  Magic (4B)  │ Ver (1B)│         Payload                  │
│  R V N F     │  0x01   │  [Noise handshake / frames]      │
└──────────────┴─────────┴──────────────────────────────────┘

Magic Bytes

Every connection starts with RVNF (0x52 0x56 0x4E 0x46) followed by version byte (currently 0x01). Invalid magic causes immediate disconnection.

Handshake Phase

After magic + version validation, the Noise XX handshake begins:

Noise_XX_25519_ChaChaPoly_BLAKE2s

Message 1: Initiator → Responder:  e
Message 2: Responder → Initiator:  e, ee, s, es
Message 3: Initiator → Responder:  s, se

Encrypted Frame Format

After handshake completion, all data is encrypted:

┌────────────────┬──────────────────────────────────────┐
│ Length (4B BE)  │  Ciphertext + MAC (16B)              │
└────────────────┴──────────────────────────────────────┘
  • Length: 4 bytes, big-endian, total ciphertext length including MAC
  • Ciphertext: ChaCha20-Poly1305 encrypted payload
  • MAC: 16-byte Poly1305 authentication tag

Multiplexing

Yamux multiplexing runs over the SecureChannel, allowing concurrent RPC streams:

SecureChannel
  └── yamux
      ├── Stream 0: RPC requests/responses
      ├── Stream 1: stdout streaming
      ├── Stream 2: stderr streaming
      └── Stream N: additional streams

RPC Encoding

RPC messages are encoded with msgpack (MessagePack):

#![allow(unused)]
fn main() {
enum Request {
    Exec { command: String },
    FileRead { path: String },
    FileWrite { path: String, data: Vec<u8> },
    Status,
    Heartbeat,
}

enum Response {
    ExecResult { exit_code: i32, stdout: Vec<u8>, stderr: Vec<u8> },
    FileData { data: Vec<u8> },
    FileWritten { bytes: u64 },
    StatusInfo { ... },
    Pong,
    Error { message: String },
}
}

Transport Independence

The wire protocol is transport-agnostic. The same framing works over:

  • WebSocket (primary)
  • QUIC
  • TCP
  • Unix sockets
  • Memory channels (testing)
  • Any AsyncRead + AsyncWrite implementation

Transport Layer

The transport layer provides network-agnostic connectivity. Any channel that can move bytes is a valid transport.

Driver Trait

All transports implement the Driver trait:

#![allow(unused)]
fn main() {
#[async_trait]
pub trait Driver: Send + Sync {
    async fn connect(&self, addr: &str) -> Result<Connection>;
    async fn listen(&self, addr: &str) -> Result<Listener>;
}
}

Built-in Transports

WebSocket (Primary)

Default transport for relay connections. Works through firewalls, proxies, and CDNs.

[transport]
driver = "websocket"

QUIC

UDP-based transport with built-in encryption. Faster connection establishment.

[transport]
driver = "quic"

Memory

In-process transport for testing. Uses tokio::io::duplex.

WireGuard

Userspace WireGuard for direct peer-to-peer connections on open networks.

Exotic Transports

RavenFabric supports steganographic and physical transports for censorship resistance and air-gapped environments:

Steganographic

  • DNS tunneling
  • ICMP tunneling
  • Domain fronting (via CDN)
  • MASQUE (HTTP/3 proxy)
  • Protocol mimicry (looks like normal HTTPS/SSH)
  • Tor hidden service
  • Encrypted Client Hello (ECH)

Physical

  • Serial port (RS-232/USB)
  • Bluetooth/BLE
  • Wi-Fi Direct
  • LoRa/Meshtastic (10+ km range)
  • AX.25 packet radio
  • Audio modem (data over sound)
  • QR-stream (animated QR codes)
  • Satellite (Iridium/Starlink)
  • Physical media (USB/SD card, NNCP-style)

Overlay Networks

  • Reticulum Network Stack
  • Yggdrasil (self-configuring IPv6 mesh)
  • I2P (garlic routing)
  • Veilid (DHT-based, onion-routed)
  • Mixnet (Nym/Loopix)

Connection Management

The ConnectionManager handles:

  • Happy Eyeballs (parallel connection attempts)
  • Automatic reconnection with exponential backoff
  • Multipath scheduling (round-robin, latency-weighted)
  • Transport migration on tampering detection
  • Proxy detection and CONNECT tunneling

NAT Traversal

ICE-style hole punching with:

  • STUN binding discovery
  • Candidate gathering (host, server-reflexive, relay)
  • Birthday paradox port prediction for symmetric NAT
  • TURN relay fallback

Policy Engine

The policy engine is the security core of RavenFabric. It enforces deny-by-default access control at every level.

Deny-by-Default

If a policy does not explicitly allow an action, it is denied. There is no implicit "allow all" — every capability must be granted.

Policy YAML Format

spec:
  commands:
    allow:
      - pattern: "^systemctl status .*"
      - pattern: "^journalctl.*"
      - pattern: "^cat /var/log/.*"
    deny:
      - pattern: ".*rm.*-rf.*"
      - pattern: ".*shutdown.*"
  filesystem:
    allow:
      - path: /opt/app
      - path: /var/log
    deny:
      - path: /etc/shadow
      - path: /root
  resources:
    maxOutputBytes: 10485760    # 10 MB
    timeoutSeconds: 300          # 5 minutes

RBAC

Role-Based Access Control with five built-in roles:

RolePermissions
AdminFull access (execute, read, write, view status, manage policy)
OperatorExecute commands, read/write files, view status
ViewerView status only
AuditorView status, read audit logs
CustomUser-defined permission set

Capability Tokens

Biscuit-inspired capability tokens for fine-grained, delegatable authorization:

  • Authority block defines maximum scope
  • Attenuation blocks narrow (never widen) permissions
  • Caveats enforce constraints (time windows, source IPs)
  • Offline verification — no central authority needed

Distributed Policy

For disconnected or mesh deployments:

  • CRDT convergence — Policies converge without a master
  • Append-only logs — Signed hash chain (Scuttlebutt-inspired)
  • Content-addressed — Request policy by hash, any node can serve
  • Quorum verification — Multi-signer approval
  • Conflict resolution — Most-restrictive policy wins by default

Telemetry Governance

Policy controls what telemetry data is collected and exported:

telemetry:
  allow:
    - type: system_metrics
    - type: app_metrics
  deny:
    - type: process_metrics
  exporter:
    type: otlp
    endpoint: "https://otel.example.com:4317"

Remote Execution

RavenFabric supports multiple execution modes, from fire-and-forget to fully orchestrated playbooks.

Fire and Forget

Execute a command without waiting for results:

rf exec --mode fire-and-forget --target web-01 "touch /tmp/heartbeat"

Standard Execution

Execute and wait for results:

rf exec --target web-01 "systemctl status nginx"

Output is streamed in real-time via yamux multiplexing.

Multi-Agent Execution

Execute across multiple agents:

rf exec --target "web-*" "apt update && apt upgrade -y"

Interactive Shell

Open an interactive PTY session:

rf shell --target web-01 --cols 120 --rows 40

Execution Modes

ModeDescription
fire-and-forgetNo response expected
fire-and-verifyVerify exit code only
streamingReal-time stdout/stderr
orchestratedMulti-step with rollback

Resource Limits

Every execution is bounded by policy:

  • Output size: Maximum bytes of stdout/stderr (default: 10 MB)
  • Timeout: Maximum execution time (default: 300s)
  • Concurrent: Maximum parallel executions per agent

Security

  • Every command is checked against the policy engine before execution
  • Commands run via sh -c with the full command string policy-checked
  • Symlinks are resolved before path checks (prevents traversal)
  • Output is bounded to prevent memory exhaustion
  • Agent is always the final authority — controller cannot override

Policy Configuration

Creating a Policy File

Create a YAML file defining what actions are allowed:

# /etc/ravenfabric/policy.yaml
spec:
  commands:
    allow:
      - pattern: "^systemctl (status|restart) nginx"
      - pattern: "^journalctl -u nginx"
      - pattern: "^cat /var/log/nginx/.*"
    deny:
      - pattern: ".*rm.*-rf.*"
      - pattern: ".*>(>)?\\s*/dev/.*"
  filesystem:
    allow:
      - path: /opt/app
      - path: /var/log/nginx
    deny:
      - path: /etc/shadow
      - path: /root
      - path: /proc/kcore
  resources:
    maxOutputBytes: 10485760
    timeoutSeconds: 300

Pattern Syntax

Command patterns use Rust regex syntax:

PatternMatches
^systemctl status .*systemctl status nginx, systemctl status ssh
^cat /var/log/.*cat /var/log/syslog, cat /var/log/nginx/access.log
.*rm.*-rf.*Any command containing rm and -rf

Deny Takes Precedence

If both allow and deny match a command, deny wins:

commands:
  allow:
    - pattern: ".*"        # Allow everything
  deny:
    - pattern: ".*rm.*"    # Except rm (this wins)

Filesystem Policies

Path-based access control with symlink resolution:

filesystem:
  allow:
    - path: /opt/app           # Allow read/write under /opt/app
  deny:
    - path: /opt/app/secrets   # Deny the secrets subdirectory

Symlinks are resolved to their real path before policy checks, preventing traversal attacks.

Resource Limits

resources:
  maxOutputBytes: 10485760    # 10 MB max output
  timeoutSeconds: 300          # 5 minute timeout

These limits are enforced by the executor and cannot be overridden by the client.

Hot Reload

Send SIGHUP to the agent process to reload policy without restarting:

kill -HUP $(pidof rf-agent)

Agent Enrollment

RavenFabric uses a one-time password (OTP) enrollment flow. No certificate authority. No centralized key server.

Enrollment Flow

Admin                      Agent                    TrustStore
  │                          │                          │
  │─── generate OTP ─────────┼──────────────────────►   │
  │    (returns token)       │                          │
  │                          │                          │
  │─── give token to agent ─►│                          │
  │                          │                          │
  │                          │── enroll(token) ────────►│
  │                          │   (generates keypair)    │
  │                          │                          │
  │                          │◄── enrolled(pubkey) ─────│
  │                          │                          │

Generate an Enrollment Token

# Generate a one-time token (valid for 5 minutes)
rf admin enroll --ttl 300 --agent-id web-01
# Output: otp_abc123def456

Enroll an Agent

rf-agent --enroll \
  --token otp_abc123def456 \
  --relay wss://relay.example.com/meet \
  --key-path /etc/ravenfabric/agent.key

The agent:

  1. Generates a new Ed25519 key pair locally
  2. Sends the public key to the relay with the OTP token
  3. TrustStore validates the OTP (single-use, hash-stored, TTL-enforced)
  4. On success, the agent is registered and can receive RPC calls

Security Properties

  • OTP tokens are single-use — Once consumed, the token hash is marked used
  • Hash-stored — Only the hash of the OTP is stored, not the plaintext
  • TTL-enforced — Tokens expire after a configurable time window
  • No secrets in transit — The agent generates its key pair locally
  • No certificate authority — Identity is the key pair itself

Relay Setup

The relay is a stateless encrypted broker. It pairs agents with clients and forwards opaque bytes. It never sees plaintext or keys.

Quick Start

rf-relay --listen 0.0.0.0:9090 --secret "your-meet-secret"

Production Setup

Systemd Service

# /etc/systemd/system/rf-relay.service
[Unit]
Description=RavenFabric Relay
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
ExecStart=/usr/local/bin/rf-relay --listen 0.0.0.0:9090
Environment=RELAY_SECRET=your-secret-here
Restart=always
RestartSec=5
LimitNOFILE=65535

# Security hardening
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes

[Install]
WantedBy=multi-user.target

Behind Reverse Proxy

The relay uses WebSocket, so configure your reverse proxy accordingly:

Nginx:

server {
    listen 443 ssl;
    server_name relay.example.com;

    location /meet {
        proxy_pass http://127.0.0.1:9090;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host $host;
        proxy_read_timeout 86400;
    }
}

Geo-Distribution

Deploy multiple relays for latency optimization:

relay-eu.example.com  (Frankfurt)
relay-us.example.com  (Virginia)
relay-ap.example.com  (Singapore)

Agents connect to the nearest relay. The relay selection is automatic based on latency probing.

Security Properties

  • Stateless — No session data stored on disk
  • Opaque — Relay sees only encrypted bytes, never plaintext
  • No keys — Relay has no access to agent or client keys
  • Ephemeral — Can be restarted/replaced without state loss

CLI Reference

rf exec

Execute a command on a remote agent.

rf exec [OPTIONS] <COMMAND>

Options

OptionDescriptionDefault
--relay <URL>Relay WebSocket URLRequired
--token <TOKEN>Authentication tokenRequired
--target <ID>Target agent ID or patternRequired
--timeout <SECS>Execution timeout30
--mode <MODE>Execution mode (see below)streaming

Modes

  • fire-and-forget — No response
  • fire-and-verify — Exit code only
  • streaming — Real-time output
  • orchestrated — Multi-step

Examples

# Simple command
rf exec --relay wss://relay.example.com/meet \
  --token abc123 "hostname"

# Multi-agent
rf exec --target "web-*" "systemctl status nginx"

# With timeout
rf exec --timeout 60 "apt update"

rf shell

Open an interactive shell session.

rf shell [OPTIONS]

Options

OptionDescriptionDefault
--relay <URL>Relay WebSocket URLRequired
--token <TOKEN>Authentication tokenRequired
--target <ID>Target agent IDRequired
--cols <N>Terminal columns80
--rows <N>Terminal rows24

rf status

Query agent status.

rf status [OPTIONS]

rf completions

Generate shell completions.

rf completions <SHELL>

Supported shells: bash, zsh, fish, powershell, elvish.

# Generate and install zsh completions
rf completions zsh > ~/.zfunc/_rf

rf dev

Start a local development environment (relay + agent in one process).

rf dev [OPTIONS]
OptionDescriptionDefault
--port <PORT>Local relay port9090
--policy <PATH>Policy filepermissive default

Configuration File Reference

RavenFabric uses TOML configuration files.

Agent (/etc/ravenfabric/raven.toml)

[agent]
# Unique agent identifier
id = "web-01"

# Relay WebSocket URL
relay = "wss://relay.example.com/meet"

# Path to agent private key
key_path = "/etc/ravenfabric/agent.key"

# Path to policy file
policy_path = "/etc/ravenfabric/policy.yaml"

# Path to audit log (JSON lines)
audit_path = "/var/log/ravenfabric/audit.jsonl"

[transport]
# Transport driver: "websocket", "quic", "memory"
driver = "websocket"

# Reconnect interval (seconds)
reconnect_interval = 5

# Maximum reconnect attempts (0 = infinite)
max_retries = 0

[resources]
# Maximum output size per command (bytes)
max_output_bytes = 10485760  # 10 MB

# Maximum execution time per command (seconds)
timeout_seconds = 300

# Maximum concurrent executions
max_concurrent = 10

Relay

[relay]
# Listen address
listen = "0.0.0.0:9090"

# Meet secret (use env: prefix for environment variables)
meet_secret = "env:RELAY_SECRET"

[rate_limit]
# Requests per second per source IP
requests_per_second = 100

# Burst allowance
burst = 200

CLI (~/.config/ravenfabric/config.toml)

[cli]
# Default relay URL
default_relay = "wss://relay.example.com/meet"

# CLI key path
key_path = "~/.config/ravenfabric/cli.key"

# Default timeout (seconds)
timeout = 30

Environment Variables

All configuration values can be overridden via environment variables:

VariableOverrides
RF_AGENT_IDagent.id
RF_RELAYagent.relay
RF_KEY_PATHagent.key_path
RF_POLICYagent.policy_path
RELAY_SECRETrelay.meet_secret (with env: prefix)
RUST_LOGLogging level

Policy YAML Reference

Full Schema

spec:
  # Command execution policies
  commands:
    allow:
      - pattern: "<regex>"    # Rust regex syntax
    deny:
      - pattern: "<regex>"    # Deny takes precedence over allow

  # Filesystem access policies
  filesystem:
    allow:
      - path: "<absolute-path>"
    deny:
      - path: "<absolute-path>"

  # Resource limits
  resources:
    maxOutputBytes: 10485760    # Max stdout+stderr (bytes)
    timeoutSeconds: 300          # Max execution time (seconds)

Rules

  1. Deny-by-default: If no allow rule matches, the action is denied
  2. Deny wins: If both allow and deny match, deny takes precedence
  3. Regex matching: Command patterns use Rust regex syntax
  4. Path resolution: Symlinks are resolved before policy checks
  5. Immutable denies: Some deny rules cannot be overridden (e.g., /etc/shadow)

Examples

Web Server Administration

spec:
  commands:
    allow:
      - pattern: "^systemctl (status|restart|reload) nginx"
      - pattern: "^journalctl -u nginx.*"
      - pattern: "^cat /var/log/nginx/.*"
      - pattern: "^nginx -t"
    deny:
      - pattern: ".*rm.*-rf.*"
  filesystem:
    allow:
      - path: /etc/nginx
      - path: /var/log/nginx
    deny:
      - path: /etc/nginx/ssl
  resources:
    maxOutputBytes: 5242880
    timeoutSeconds: 60

Read-Only Monitoring

spec:
  commands:
    allow:
      - pattern: "^systemctl status .*"
      - pattern: "^df -h"
      - pattern: "^free -m"
      - pattern: "^uptime"
      - pattern: "^cat /proc/(meminfo|cpuinfo|loadavg)"
  filesystem:
    allow:
      - path: /var/log
    deny:
      - path: /var/log/audit
  resources:
    maxOutputBytes: 1048576
    timeoutSeconds: 30

Deny Everything (Lockdown)

spec:
  commands:
    allow: []
    deny:
      - pattern: ".*"
  filesystem:
    allow: []
    deny:
      - path: /
  resources:
    maxOutputBytes: 0
    timeoutSeconds: 0

RPC Protocol Reference

Overview

RavenFabric RPC uses msgpack encoding over yamux-multiplexed Noise XX secure channels.

Request Types

ActionDescriptionFields
ExecExecute a commandcommand: String
FileReadRead a filepath: String
FileWriteWrite a filepath: String, data: Vec<u8>
StatusQuery agent status
HeartbeatKeep-alive ping
ShellOpen PTY sessioncols: u16, rows: u16

Response Types

TypeDescriptionFields
ExecResultCommand resultexit_code: i32, stdout: Vec<u8>, stderr: Vec<u8>
FileDataFile contentsdata: Vec<u8>
FileWrittenWrite confirmationbytes: u64
StatusInfoAgent statusid: String, uptime: u64, ...
PongHeartbeat response
ErrorError responsemessage: String

Message Format

Request {
    id: u64,          // Unique request ID
    action: Action,   // Enum variant
}

Response {
    id: u64,          // Matching request ID
    result: Result,   // Enum variant
}

Encoding

All messages use msgpack (MessagePack) via rmp-serde:

#![allow(unused)]
fn main() {
// Serialize
let bytes = rmp_serde::to_vec(&request)?;

// Deserialize
let response: Response = rmp_serde::from_slice(&bytes)?;
}

Streaming

For long-running commands, stdout/stderr are streamed over separate yamux streams. The client receives output in real-time without waiting for command completion.

DTN (Delay-Tolerant Networking)

For air-gapped or high-latency environments, requests can be queued as DTN bundles with:

  • Priority levels (Low, Normal, High, Critical)
  • TTL-based expiration
  • Custody transfer (reliable delivery)
  • Idempotency keys (deduplication)

Building from Source

Prerequisites

  • Rust 1.85+ (Edition 2024)
  • Git
# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Verify version
rustc --version  # Must be 1.85.0 or later

Clone and Build

git clone https://github.com/egkristi/RavenFabric.git
cd RavenFabric

# Debug build
cargo build

# Release build (optimized, LTO, stripped)
cargo build --release

Cross-Compilation

Linux Static Binary (musl)

rustup target add x86_64-unknown-linux-musl
cargo build --release --target x86_64-unknown-linux-musl

Linux ARM64

rustup target add aarch64-unknown-linux-musl
cargo build --release --target aarch64-unknown-linux-musl

Linux ARMv7 (Raspberry Pi)

rustup target add armv7-unknown-linux-musleabihf
cargo build --release --target armv7-unknown-linux-musleabihf

Feature Flags

FeatureDefaultDescription
fullYesAll features enabled
minimalNoNo TUN, no sysinfo, no QUIC
websocketYesWebSocket transport
quicNoQUIC transport
# Minimal build (smaller binary)
cargo build --release --no-default-features --features minimal

# With QUIC
cargo build --release --features quic

Verify Build

# Run all tests
cargo test

# Lint
cargo clippy

# Format check
cargo fmt --check

Testing

Running Tests

# Run all tests
cargo test

# Run tests for a specific crate
cargo test -p rf-crypto
cargo test -p rf-transport
cargo test -p rf-policy

# Run a specific test
cargo test -p rf-policy test_capability_check

# Run with output
cargo test -- --nocapture

Test Coverage

CrateTestsCoverage Focus
rf-crypto25Noise handshake, key management, resumption, PQ KEM
rf-transport121NAT traversal, mesh, proxy, gossip, overlays, WireGuard, platforms
rf-rpc61Codec roundtrips, DTN queuing, routing, SOCKS5, controller
rf-policy31RBAC, capabilities, deny-by-default, distributed policy
rf-executor48Command execution, streaming, PTY, log tailing, plugins
rf-bootstrap11OTP enrollment, TrustStore
Integration2End-to-end relay + agent + client

Total: 336 tests

Writing Tests

Unit Tests

Place unit tests in the same file as the code:

#![allow(unused)]
fn main() {
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_deny_by_default() {
        let policy = Policy::empty();
        assert!(policy.check("rm -rf /").is_denied());
    }
}
}

Async Tests

Use #[tokio::test] for async tests:

#![allow(unused)]
fn main() {
#[tokio::test]
async fn test_secure_channel() {
    let (client, server) = tokio::io::duplex(8192);
    // ... test over simulated connection
}
}

Security Tests

Security-critical paths need both positive AND negative tests:

#![allow(unused)]
fn main() {
#[test]
fn test_policy_allows_valid_command() {
    let policy = load_policy("allow systemctl status");
    assert!(policy.check("systemctl status nginx").is_allowed());
}

#[test]
fn test_policy_denies_invalid_command() {
    let policy = load_policy("allow systemctl status");
    assert!(policy.check("rm -rf /").is_denied());
}
}

CI

Tests run automatically on every push via GitHub Actions:

  • All platforms: Linux, macOS, Windows
  • cargo test, cargo clippy, cargo fmt --check

Contributing

Thank you for your interest in contributing to RavenFabric.

Getting Started

  1. Fork the repository
  2. Clone your fork: git clone https://github.com/YOUR_USER/RavenFabric.git
  3. Create a feature branch: git checkout -b feat/my-feature
  4. Make your changes
  5. Run tests: cargo test
  6. Run linter: cargo clippy
  7. Format code: cargo fmt
  8. Push and open a Pull Request

Code Standards

  • Language: All code, comments, and documentation in English
  • Edition: Rust 2024, MSRV 1.85
  • Error handling: thiserror in libraries, anyhow only in binaries
  • Async: Use async-trait for async trait methods
  • Logging: tracing crate only — never println! in libraries
  • Tests: Every public function must have at least one test
  • Security: Every policy check, key validation, and crypto operation must have tests

Commit Messages

Use conventional commits:

feat: add QUIC transport driver
fix: resolve symlink before path policy check
refactor: extract connection manager from driver
docs: add relay setup guide
test: add roundtrip test for DTN bundle

Reference issues: feat: add QUIC transport #5

Security

  • Security is always the top priority
  • Never trade security for convenience
  • No unwrap() in library code — use ? and proper error types
  • All types must be Send + Sync
  • Deny-by-default — if unsure, deny

Reporting Security Issues

See SECURITY.md for responsible disclosure guidelines.