-
Notifications
You must be signed in to change notification settings - Fork 2
WebSocket Test Harness
A standalone Go application for testing the TMI WebSocket interface for collaborative threat modeling.
Source Location: wstest/ directory in the TMI repository
- OAuth authentication with TMI test provider using login hints (
idp=test) - Ticket-based WebSocket authentication (obtains a short-lived ticket from
/ws/ticketbefore connecting) - Host mode: Creates threat models, adds participants with random permissions, creates diagrams, and starts collaboration sessions
-
Participant mode: Polls
/me/sessionsevery 5 seconds for available collaboration sessions and joins them; automatically reconnects after disconnection - Handles all AsyncAPI message types: participant updates, diagram operations, sync protocol, presenter controls, error/rejection messages, and authorization events
- Comprehensive structured logging (
slog) of all network interactions and WebSocket messages - Graceful shutdown on SIGINT/SIGTERM with proper WebSocket close handshake
- Supports multiple concurrent instances
- Uses the Gorilla WebSocket library
Use the make target (preferred):
make build-wstestOr build directly:
cd wstest
go mod tidy
go build -o wstestStart as a host to create a new collaboration session:
# Basic host mode
./wstest --user alice --host
# Host mode with participants
./wstest --user alice --host --participants "bob,charlie,dave"
# Custom server
./wstest --server http://localhost:8080 --user alice --hostStart as a participant to join existing collaboration sessions:
# Join any available session
./wstest --user bob
# Multiple participants
./wstest --user charlie &
./wstest --user dave &| Option | Description | Default |
|---|---|---|
--server <url> |
Server URL | localhost:8080 |
--user <hint> |
User login hint | Required |
--host |
Run in host mode | false |
--participants <list> |
Comma-separated list of participant hints (host mode only) | Empty |
Terminal 1 (Host):
./wstest --user alice --host --participants "bob"Terminal 2 (Participant):
./wstest --user bobTerminal 1 (Host):
./wstest --user alice --host --participants "bob,charlie,dave"Terminals 2-4 (Participants):
./wstest --user bob
./wstest --user charlie
./wstest --user daveUse the make target to automatically launch three terminal windows:
make wstestThis launches:
- Alice as host with participants "bob,charlie,hobobarbarian@gmail.com"
- Bob as participant
- Charlie as participant
Each instance has a 30-second timeout to prevent runaway processes.
The harness uses ticket-based authentication for WebSocket connections:
- After OAuth login, the harness requests a short-lived ticket from
GET /ws/ticket?session_id=<session_id>using the Bearer token. - The WebSocket connection URL includes the ticket as a query parameter:
/threat_models/<id>/diagrams/<id>/ws?session_id=<id>&ticket=<ticket>.
This approach avoids sending long-lived access tokens over the WebSocket upgrade request.
All WebSocket messages are logged with timestamps and pretty-printed JSON. The harness handles the following message types:
| Message Type | Description |
|---|---|
participants_update |
Full list of current participants, host, and current presenter |
diagram_operation_event |
A diagram operation applied by another user (includes operation_id, sequence_number, update_vector, operation) |
diagram_state |
Full diagram state with all cells (sent on sync) |
sync_status_response |
Current update_vector for the diagram |
error |
Server error with error, message, code, and timestamp fields |
operation_rejected |
A submitted operation was rejected (includes reason, affected_cells, requires_resync) |
presenter_cursor |
Presenter's cursor position (x, y coordinates) |
presenter_selection |
Cells currently selected by the presenter |
presenter_request_event |
Notification to host that a user is requesting presenter role |
presenter_denied_event |
Notification that a presenter request was denied |
authorization_denied |
An operation was denied due to insufficient permissions |
| Message Type | Description |
|---|---|
diagram_operation_request |
Submit a diagram operation (includes operation_id, base_vector, operation) |
sync_status_request |
Request current sync status |
sync_request |
Request diagram state sync (optionally from a specific update_vector) |
undo_request |
Request undo of the last operation |
redo_request |
Request redo of the last undone operation |
presenter_request |
Request to become the presenter |
change_presenter_request |
Request to change the presenter to another user |
presenter_denied_request |
Host denies a presenter request (includes denied_user) |
remove_participant_request |
Remove a participant from the session (includes removed_user) |
Full list of current participants (includes presenter info if any).
Structure:
{
"message_type": "participants_update",
"initiating_user": { /* user who triggered the update, or null for system events */ },
"participants": [
{
"user": {
"principal_type": "user",
"provider": "tmi",
"provider_id": "alice@tmi.local",
"email": "alice@tmi.local",
"display_name": "Alice (TMI User)"
},
"permissions": "owner",
"last_activity": "2025-01-24T12:00:00Z"
}
],
"host": { /* host user object */ },
"current_presenter": { /* presenter user object, or null if no presenter */ }
}The harness implements the OAuth authorization code flow:
- Starts a local HTTP server on a random port for the callback.
- Makes a GET request to
/oauth2/authorize?idp=test&login_hint=<user>&client_callback=<url>&scope=openid+email+profile. - Receives a redirect response from the server pointing to the local callback.
- Follows the redirect by making a GET request to the callback URL (headless -- no browser involved).
- The callback handler extracts the authorization code and exchanges it for tokens via POST to
/oauth2/token(JSON body withgrant_type,code,redirect_uri). - Calls
GET /oauth2/userinfowith the Bearer token to ensure the user is created in the database. - Uses the access token for all subsequent API calls and WebSocket ticket requests.
Note: The harness uses idp=test, the TMI development OAuth provider that creates test users based on login hints. The callback handler also supports implicit flow (tokens returned directly as query parameters) as a fallback.
The harness uses Go's slog structured logging (via the TMI slogging package). All network interactions are logged to the console:
- HTTP requests show method, URL, and request bodies (at DEBUG level)
- HTTP responses show status codes and response bodies (at DEBUG level)
- WebSocket messages are parsed by type and logged with relevant fields at INFO level; full JSON is logged at DEBUG level
- OAuth callback parameters are logged in detail at INFO level
- Errors and warnings use appropriate log levels (ERROR, WARN)
Use Ctrl+C to gracefully shutdown the application. The WebSocket connection will be properly closed.
| Target | Description |
|---|---|
make build-wstest |
Build the WebSocket test harness binary |
make wstest |
Launch 3-terminal test (alice as host, bob & charlie as participants) |
make monitor-wstest |
Run WebSocket harness with user 'monitor' in foreground |
make clean-wstest |
Stop all running WebSocket test harness instances |
Check:
- Verify the server is running (
make start-dev). - Verify the server URL is correct (default is
localhost:8080). - Confirm the OAuth flow completes successfully (check console output).
Check:
- Verify the host has started a session first.
- Verify the participant user has been added to the threat model authorization.
- Confirm the session is still active (not timed out).
Check:
- Review server logs for errors.
- Confirm the session has not been terminated by the host.
- Verify network connectivity.
- WebSocket-API-Reference -- Full WebSocket API documentation
- Collaborative-Threat-Modeling -- Collaboration features overview
- Debugging-Guide -- General debugging procedures
- AsyncAPI Specification -- WebSocket message schemas
- Using TMI for Threat Modeling
- Accessing TMI
- Authentication
- Creating Your First Threat Model
- Understanding the User Interface
- Working with Data Flow Diagrams
- Managing Threats
- Collaborative Threat Modeling
- Using Notes and Documentation
- Timmy AI Assistant
- Metadata and Extensions
- Planning Your Deployment
- Terraform Deployment (AWS, OCI, GCP, Azure)
- Deploying TMI Server
- OCI Container Deployment
- Certificate Automation
- Deploying TMI Web Application
- Setting Up Authentication
- Database Setup
- Component Integration
- Post-Deployment
- Branding and Customization
- Monitoring and Health
- Cloud Logging
- Database Operations
- Security Operations
- Performance and Scaling
- Maintenance Tasks
- Getting Started with Development
- Architecture and Design
- API Integration
- Testing
- Contributing
- Extending TMI
- Dependency Upgrade Plans
- DFD Graphing Library Reference
- Migration Instructions