Implement GuruRMM Phase 1: Real-time tunnel infrastructure
Complete bidirectional tunnel communication between server and agents, enabling persistent secure channels for future command execution and file operations. Agents transition from heartbeat mode to tunnel mode on-demand while maintaining WebSocket connection. Server Implementation: - Database layer (db/tunnel.rs): Session CRUD, ownership validation, cleanup on disconnect (prevents orphaned sessions) - API endpoints (api/tunnel.rs): POST /open, POST /close, GET /status with JWT auth, UUID validation, proper HTTP status codes - Protocol extension (ws/mod.rs): TunnelOpen/Close/Data messages, agent response handlers (TunnelReady/Data/Error) - Migration (006_tunnel_sessions.sql): tech_sessions table with partial unique constraint, foreign keys with CASCADE, audit table Agent Implementation: - State machine (tunnel/mod.rs): AgentMode (Heartbeat ↔ Tunnel), channel multiplexing, concurrent session prevention - WebSocket handlers (transport/websocket.rs): Open/close tunnel, mode switching without dropping connection, cleanup on disconnect - Protocol extension (transport/mod.rs): TunnelReady/Data/Error messages matching server definitions - Unit tests: Lifecycle and channel management coverage Key Features: - Security: JWT auth, session ownership verification, SQL injection prevention, constraint-based duplicate session blocking - Cleanup: Automatic session closure on agent disconnect (both sides), channel cleanup, graceful state transitions - Error handling: Proper HTTP status codes (400/403/404/409/500), comprehensive Result types, detailed logging - Extensibility: Channel types ready (Terminal/File/Registry/Service), TunnelDataPayload enum for Phase 2+ expansion Phase 1 Scope (Implemented): - Tunnel session lifecycle management - Mode switching (heartbeat ↔ tunnel) - Protocol message routing - Database session tracking Phase 2 Next Steps: - Terminal command execution (tokio::process::Command) - Client WebSocket connections for output streaming - Command audit logging - File transfer operations Verification: - Server compiles successfully (0 errors) - Agent unit tests pass (tunnel lifecycle, channel management) - Code review approved (protocol alignment verified) - Database constraints enforce referential integrity - Cleanup tested (session closure on disconnect) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,319 @@
|
||||
# GuruRMM Tunnel - Phase 1 Agent Implementation
|
||||
|
||||
**Date:** 2026-04-14
|
||||
**Status:** COMPLETED
|
||||
**Component:** Agent (Rust)
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
Successfully implemented Phase 1 of the GuruRMM real-time tunnel feature on the agent side. The agent now supports mode switching between Heartbeat and Tunnel modes, handles tunnel lifecycle messages, and is ready for Phase 2 terminal command execution.
|
||||
|
||||
---
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### 1. Protocol Extensions
|
||||
|
||||
**File:** `agent/src/transport/mod.rs`
|
||||
|
||||
Added new message types to `AgentMessage` enum:
|
||||
- `TunnelReady { session_id: String }` - Confirmation that tunnel is ready
|
||||
- `TunnelData { channel_id: String, data: TunnelDataPayload }` - Bidirectional tunnel data
|
||||
- `TunnelError { channel_id: String, error: String }` - Error reporting
|
||||
|
||||
Added new message types to `ServerMessage` enum:
|
||||
- `TunnelOpen { session_id: String, tech_id: Uuid }` - Server request to open tunnel
|
||||
- `TunnelClose { session_id: String }` - Server request to close tunnel
|
||||
- `TunnelData { channel_id: String, data: TunnelDataPayload }` - Bidirectional tunnel data
|
||||
|
||||
Added `TunnelDataPayload` enum (Phase 1: Terminal only):
|
||||
- `Terminal { command: String }` - Terminal command request
|
||||
- `TerminalOutput { stdout: String, stderr: String, exit_code: Option<i32> }` - Terminal response
|
||||
|
||||
### 2. Tunnel Manager Module
|
||||
|
||||
**File:** `agent/src/tunnel/mod.rs` (NEW)
|
||||
|
||||
Created comprehensive tunnel state management:
|
||||
|
||||
**AgentMode enum:**
|
||||
```rust
|
||||
pub enum AgentMode {
|
||||
Heartbeat, // Default: 30s heartbeats, metrics, network monitoring
|
||||
Tunnel {
|
||||
session_id: String,
|
||||
tech_id: Uuid,
|
||||
channels: HashMap<String, ChannelType>,
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
**TunnelManager struct:**
|
||||
- `open_tunnel()` - Transition from Heartbeat to Tunnel mode
|
||||
- `close_tunnel()` - Transition back to Heartbeat mode
|
||||
- `add_channel()` - Register new channel (terminal, file, etc.)
|
||||
- `remove_channel()` - Cleanup channel
|
||||
- `force_close()` - Emergency cleanup on disconnect
|
||||
|
||||
**Channel types (extensible for future phases):**
|
||||
- `Terminal` - Command execution (Phase 1)
|
||||
- `File` - File operations (Phase 2+)
|
||||
- `Registry` - Registry operations (Phase 2+)
|
||||
- `Service` - Service management (Phase 2+)
|
||||
|
||||
### 3. WebSocket Integration
|
||||
|
||||
**File:** `agent/src/transport/websocket.rs`
|
||||
|
||||
Updated WebSocket client to support tunnel operations:
|
||||
|
||||
**New handler functions:**
|
||||
- `handle_tunnel_open()` - Process TunnelOpen request, send TunnelReady
|
||||
- `handle_tunnel_close()` - Process TunnelClose request, cleanup state
|
||||
- `handle_tunnel_data()` - Route tunnel data by channel (Phase 1: placeholder)
|
||||
|
||||
**Message loop updates:**
|
||||
- Created `TunnelManager` instance in connection lifecycle
|
||||
- Updated `handle_server_message()` signature to accept tunnel manager
|
||||
- Added tunnel message logging (TunnelReady, TunnelData, TunnelError)
|
||||
- Force-close tunnel on WebSocket disconnect
|
||||
|
||||
**Mode persistence:**
|
||||
- Tunnel state maintained across message loop iterations
|
||||
- Heartbeat continues in both modes (connection keepalive)
|
||||
- Clean shutdown closes active sessions
|
||||
|
||||
### 4. Module Registration
|
||||
|
||||
**File:** `agent/src/main.rs`
|
||||
|
||||
Added tunnel module to module tree:
|
||||
```rust
|
||||
mod tunnel;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
### Unit Tests
|
||||
|
||||
Created comprehensive test suite in `agent/src/tunnel/mod.rs`:
|
||||
|
||||
**Test: `test_tunnel_lifecycle`**
|
||||
- Starts in Heartbeat mode
|
||||
- Opens tunnel successfully
|
||||
- Rejects concurrent tunnel sessions
|
||||
- Closes tunnel and returns to Heartbeat mode
|
||||
|
||||
**Test: `test_channel_management`**
|
||||
- Rejects channel operations without active tunnel
|
||||
- Adds multiple channels
|
||||
- Retrieves channel types
|
||||
- Removes channels
|
||||
- Force-closes tunnel
|
||||
|
||||
**Test Results:**
|
||||
```
|
||||
running 2 tests
|
||||
test tunnel::tests::test_tunnel_lifecycle ... ok
|
||||
test tunnel::tests::test_channel_management ... ok
|
||||
|
||||
test result: ok. 2 passed; 0 failed; 0 ignored
|
||||
```
|
||||
|
||||
### Compilation
|
||||
|
||||
**Status:** SUCCESSFUL
|
||||
|
||||
**Warnings (expected, non-critical):**
|
||||
- `tech_id` field unused (will be used in Phase 2 for authorization)
|
||||
- Some enum variants unused (File, Registry, Service - Phase 2+)
|
||||
- Some methods unused (mode accessors - used in Phase 2)
|
||||
|
||||
---
|
||||
|
||||
## Protocol Flow
|
||||
|
||||
### Tunnel Open
|
||||
```
|
||||
Server → Agent: TunnelOpen { session_id, tech_id }
|
||||
Agent: tunnel_manager.open_tunnel()
|
||||
Agent → Server: TunnelReady { session_id }
|
||||
```
|
||||
|
||||
### Tunnel Close
|
||||
```
|
||||
Server → Agent: TunnelClose { session_id }
|
||||
Agent: tunnel_manager.close_tunnel()
|
||||
```
|
||||
|
||||
### Terminal Command (Phase 1 - Placeholder)
|
||||
```
|
||||
Server → Agent: TunnelData {
|
||||
channel_id: "...",
|
||||
data: Terminal { command: "..." }
|
||||
}
|
||||
Agent: Log command (execution in Phase 2)
|
||||
Agent → Server: TunnelData {
|
||||
channel_id: "...",
|
||||
data: TerminalOutput {
|
||||
stdout: "",
|
||||
stderr: "Not implemented",
|
||||
exit_code: Some(-1)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Connection Loss
|
||||
```
|
||||
WebSocket disconnect detected
|
||||
Agent: tunnel_manager.force_close()
|
||||
Agent: Cleanup tasks, return to heartbeat mode
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Features
|
||||
|
||||
### Mode Switching
|
||||
- Clean transition between Heartbeat and Tunnel modes
|
||||
- Single active tunnel per agent (prevents session conflicts)
|
||||
- Tunnel state persists across message loop iterations
|
||||
|
||||
### Channel Multiplexing
|
||||
- HashMap-based channel routing by `channel_id`
|
||||
- Extensible channel types (Terminal, File, Registry, Service)
|
||||
- Channel lifecycle management (add, remove, cleanup)
|
||||
|
||||
### Error Handling
|
||||
- Validates session IDs on close requests
|
||||
- Rejects concurrent tunnel sessions
|
||||
- Sends TunnelError messages for failures
|
||||
- Force-close on unexpected disconnect
|
||||
|
||||
### Logging
|
||||
- Info-level: Tunnel open/close, mode transitions
|
||||
- Debug-level: Channel operations, TunnelData routing
|
||||
- Warn-level: Errors, rejected operations
|
||||
|
||||
---
|
||||
|
||||
## Files Modified
|
||||
|
||||
1. `agent/src/transport/mod.rs` - Protocol message definitions
|
||||
2. `agent/src/transport/websocket.rs` - WebSocket tunnel integration
|
||||
3. `agent/src/main.rs` - Module registration
|
||||
4. `agent/src/tunnel/mod.rs` - NEW: Tunnel manager implementation
|
||||
|
||||
---
|
||||
|
||||
## Next Steps (Phase 2)
|
||||
|
||||
### Terminal Command Execution
|
||||
|
||||
**Implementation required in `handle_tunnel_data()`:**
|
||||
|
||||
1. Parse `TunnelDataPayload::Terminal { command }`
|
||||
2. Spawn process using `tokio::process::Command`
|
||||
3. Capture stdout/stderr streams
|
||||
4. Handle exit codes and timeouts
|
||||
5. Send `TunnelDataPayload::TerminalOutput` response
|
||||
|
||||
**Considerations:**
|
||||
- Shell selection (PowerShell, cmd, bash based on OS)
|
||||
- Working directory restrictions (security)
|
||||
- Timeout enforcement (prevent hung processes)
|
||||
- Error handling (process spawn failures, permission errors)
|
||||
|
||||
### Integration Testing
|
||||
|
||||
**Manual testing with server:**
|
||||
1. Deploy updated agent to test machine
|
||||
2. Server sends TunnelOpen via WebSocket
|
||||
3. Verify TunnelReady response
|
||||
4. Send Terminal command
|
||||
5. Verify TerminalOutput response (Phase 2)
|
||||
6. Server sends TunnelClose
|
||||
7. Verify graceful cleanup
|
||||
|
||||
---
|
||||
|
||||
## Compliance with Architecture Plan
|
||||
|
||||
**Alignment with `plans/real-time-tunnel-architecture.md`:**
|
||||
|
||||
- [OK] AgentMode state machine (Heartbeat ↔ Tunnel)
|
||||
- [OK] Channel routing by channel_id
|
||||
- [OK] TunnelOpen/TunnelClose lifecycle
|
||||
- [OK] TunnelReady confirmation message
|
||||
- [OK] TunnelDataPayload enum (Phase 1: Terminal only)
|
||||
- [OK] Heartbeat maintained in tunnel mode
|
||||
- [OK] Force-close on disconnect
|
||||
- [OK] Unit tests for state machine
|
||||
- [PENDING] Terminal command execution (Phase 2)
|
||||
- [PENDING] File operations (Phase 3)
|
||||
- [PENDING] MCP server integration (Phase 4)
|
||||
|
||||
---
|
||||
|
||||
## Known Limitations
|
||||
|
||||
1. **Terminal execution not implemented** - Phase 1 only handles protocol and state management. Actual command execution is Phase 2.
|
||||
|
||||
2. **No working directory restrictions** - Security layer for path validation will be added in Phase 2.
|
||||
|
||||
3. **Single tunnel per agent** - By design, prevents session conflicts. Multi-tech sessions deferred to future enhancement.
|
||||
|
||||
4. **No channel-level timeouts** - Will be added in Phase 2 with actual command execution.
|
||||
|
||||
---
|
||||
|
||||
## Security Notes
|
||||
|
||||
**Implemented:**
|
||||
- Session validation (session_id matching on close)
|
||||
- Single tunnel enforcement (rejects concurrent sessions)
|
||||
- Clean state transitions (no lingering channels)
|
||||
|
||||
**Pending (Phase 2+):**
|
||||
- Command sanitization (injection prevention)
|
||||
- Working directory allowlist
|
||||
- Rate limiting (server-side)
|
||||
- Audit logging (server-side)
|
||||
|
||||
---
|
||||
|
||||
## Performance Impact
|
||||
|
||||
**Memory:**
|
||||
- `TunnelManager`: ~200 bytes (enum + HashMap overhead)
|
||||
- Active per connection, deallocated on disconnect
|
||||
- Negligible impact on heartbeat mode
|
||||
|
||||
**CPU:**
|
||||
- Mode checks: O(1) enum match
|
||||
- Channel routing: O(1) HashMap lookup
|
||||
- No continuous tasks in tunnel mode
|
||||
- Heartbeat continues at 30s interval (unchanged)
|
||||
|
||||
**Network:**
|
||||
- TunnelReady: Single message on tunnel open (~100 bytes)
|
||||
- Heartbeat continues in tunnel mode (no change)
|
||||
- TunnelData: Variable (depends on command output in Phase 2)
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
Phase 1 agent implementation is **complete and tested**. The agent can now:
|
||||
- Switch between Heartbeat and Tunnel modes
|
||||
- Handle TunnelOpen/TunnelClose lifecycle
|
||||
- Route tunnel messages by channel_id
|
||||
- Maintain connection integrity in both modes
|
||||
|
||||
Ready for Phase 2: Terminal command execution implementation.
|
||||
|
||||
**Status:** READY FOR SERVER INTEGRATION TESTING
|
||||
Reference in New Issue
Block a user