Some checks failed
Build and Test / Build Server (Linux) (push) Has been cancelled
Build and Test / Build Agent (Windows) (push) Has been cancelled
Build and Test / Security Audit (push) Has been cancelled
Build and Test / Build Summary (push) Has been cancelled
Run Tests / Test Server (push) Has been cancelled
Run Tests / Test Agent (push) Has been cancelled
Run Tests / Code Coverage (push) Has been cancelled
Run Tests / Lint and Format Check (push) Has been cancelled
Brings azcomputerguru/guru-connect up to the authoritative working copy that had been maintained in the claudetools monorepo: Phase 1 security and infrastructure (middleware, metrics, utils, token blacklist, deployment scripts, security audits) plus the native-remote-control integration spec. Preserves the repo .gitignore, .cargo, and server/static/downloads. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
8.1 KiB
8.1 KiB
Native Remote Control — Code References
Two repos. GC = guru-connect (
D:\claudetools\projects\msp-tools\guru-connect, lives in the claudetools repo). RMM = GuruRMM (projects/msp-tools/guru-rmm, a git submodule trackingazcomputerguru/gururmm). Paths below are relative to each repo root.
Files that will be touched
guru-connect (GC)
server/src/main.rs— route table;create_code:382,list_sessions:425,get_session:433,list_machines:467,/health:254, public/api/version:300. Add the/api/integration/v1/namespace:GET .../capabilities,POST .../sessions,POST .../sessions/:id/viewer-token,POST .../agents/:agent_id/keys; register the server-to-server integration auth layer. Model the (unauthenticated) capabilities endpoint on the existing/api/versionroute.CONTRACT.md(new — GC repo root ordocs/) — the semver'd integration contract doc both teams keep front of mind. Source of truth for the surface; tested in CI (Task 11).server/src/api/releases.rs:76—GET /api/versionhandler (no auth, for agent polling). Pattern to modelGET /api/integration/v1/capabilitieson.server/static/viewer.html— the existing web viewer; gets an?embed=1mode (hide standalone chrome, accept host-provided session/token, emitpostMessagelifecycle events for the RMM host).server/src/middleware/security_headers.rs:30(frame-ancestors 'none') and:37-39(X-Frame-Options) — the embedding blocker. Add a per-route scoped allowlist for the viewer path only (RMM origin from env); leave every other route at'none'.server/src/session/mod.rs— in-memorySessionManager;register_agent():95,join_session():254. Change to allow a session to be pre-created/keyed byagent_idbefore the agent connects, then bound when the agent registers.server/src/db/sessions.rs—create_session():22. Change/add to persist pre-created sessions and ais_managed/sourcemarker; reconcile in-memory state on startup.server/src/db/support_codes.rs—create_support_code():24,get_support_code():43. Reused as-is for the attended path (broker callsPOST /api/codes).server/src/relay/mod.rs— agent WS handler:55/:236;validate_agent_api_key():187(currently JWT-or-shared-AGENT_API_KEY, comment at:200flags DB keys as future). Change to validate against the new per-machine key table.server/src/auth/jwt.rs— JWT signing/validation. Add a short-lived, session-scoped viewer token mint.server/migrations/— addconnect_agent_keys(per-machine keys) and session columns; follow the existing001_initial_schema.sql/003_auto_update.sqlstyle. Idempotent (IF NOT EXISTS).proto/guruconnect.proto—SessionRequest:8,StartStream:261,AgentStatus:271,AdminCommand:286. AddConsentRequest/ConsentResponsemessages.agent/src/session/mod.rs—SessionState:71, persistent-vs-support logic. Change to register against a broker-assignedagent_id(= GuruRMMdevice_id).agent/src/transport/websocket.rs—connect():32(builds?agent_id=&api_key=&support_code=). Pass the per-machine key.agent/src/tray/mod.rs+ a new consent dialog — add the attended-mode consent prompt (handleConsentRequest).agent/src/install.rs—register_protocol_handler():131(guruconnect://<session>?token=&server=). Reused for native-viewer launch URLs the broker returns.
GuruRMM (RMM)
server/src/api/commands.rs:87-157—POST /api/agents/{agent_id}/commanddispatch (online → WSServerMessage::Command; offline → queued). Reuse to push the "ensure + launch guru-connect" instruction to the endpoint agent.server/src/api/mod.rs:162— route registration site. Add the new broker route.server/src/api/— addremote_control.rs:POST /api/agents/:agent_id/remote-control(body selectsunattended|attended); talks to the GC server API, returns a viewer launch URL.server/src/db/+server/migrations/— add aremote_control_sessionsrecord (or reusetech_sessionsfrom010_tunnel_sessions.sql) for audit (agent_id,tech_id,connect_session_id,mode, timestamps).agent/src/transport/websocket.rs—run_command():1050,execute_command():971. Add aRemoteControl/launch path (or a dedicated command_type) that, on Windows, ensures the guru-connect agent binary is present (download + SHA-256 verify) and launches it in the requested mode passingdevice_idas the GCagent_id.agent/src/device_id.rs:1-99— source of the stable cross-product identity. Read-only.dashboard/src/pages/AgentDetail.tsx:1893-1931— tab/header + action-button area. Add the "Remote Control" button (open viewer URL on success).dashboard/src/components/CommandTerminal.tsx:60-106— the canonical button→api.post()→useQueryaction pattern to copy.dashboard/src/api/client.ts:293-310—commandsApipattern. AddremoteControlApi.start(agentId, mode).
Similar existing implementations (patterns to follow)
- Per-agent action dispatch (RMM):
server/src/api/commands.rs:87-157+ agent receptionagent/src/transport/websocket.rs:570-573→execute_command():971→run_command():1050. The broker's "launch guru-connect" instruction follows this exact send-command path. - Dashboard action button → poll (RMM):
dashboard/src/components/CommandTerminal.tsx:82-105(useMutation→commandsApi.send→useQuerypoll). The Remote Control button mirrors this. - Per-agent credential issuance (RMM):
server/src/api/enroll.rs:38-139—generate_api_key("agk_"):103,hash_api_key():104, plaintext returned once:138. Modelconnect_agent_keysprovisioning on this. - Support-code minting (GC):
server/src/main.rs:382create_code+server/src/db/support_codes.rs:24. The attended path reuses this directly. - Agent WS auth handshake (RMM):
agent/src/transport/websocket.rs:100-197— how api_key/device_id are presented; the per-machine GC key provisioning should align with this lifecycle. - Half-built generic tunnel (RMM), for reference only: server
server/src/api/tunnel.rs:1-232(routes NOT registered),server/src/db/tunnel.rs:1-152,server/migrations/010_tunnel_sessions.sql, agentagent/src/tunnel/mod.rs:62-197, WS msgsserver/src/ws/mod.rs:287-300. Thetech_sessions/tunnel_auditschema is a usable model for the remote-control audit record.
Database schema
guru-connect (existing — server/migrations/)
connect_machines(001_initial_schema.sql:8) —agent_idUNIQUE,hostname,is_persistent,status, plusagent_version/organization/site/tagsfrom003_auto_update.sql.connect_sessions(001_initial_schema.sql:27) —id,machine_id,is_support_session,support_code,status. Addis_managed/sourcemarker for broker-initiated sessions.connect_support_codes(001_initial_schema.sql:59) — reused unchanged for attended.connect_session_events(001_initial_schema.sql:43) — audit; emit broker/consent events here.releases(003_auto_update.sql:9) — haschecksum_sha256; reuse for the verify-before-launch supply-chain guard.- New:
connect_agent_keys—id,agent_idFK,key_hash,created_at,revoked_at. Idempotent migration, hashed keys only (mirror RMM enroll pattern).
GuruRMM (existing — server/migrations/)
- Agent identity:
agent_id(UUID, assigned at WS auth),device_id(agent/src/device_id.rs),site_id, per-agentagk_key (hashed) fromserver/src/api/enroll.rs. tech_sessions/tunnel_audit(010_tunnel_sessions.sql) — model for the newremote_control_sessionsaudit table (or extendtech_sessionswith amode).
Migration discipline for both Rust servers: idempotent
IF NOT EXISTS, let the server binary apply migrations on startup,cargo sqlx prepareif anyquery!()macro changes. Seegururmm/sqlx-migrationsstandard.