# MeshCentral ↔ OpenClaw Bridge — Complete Project Status **Snapshot:** 2026-08-25 22:17 EDT (America/Toronto) **Owner:** Rob **Project manager:** Clawdia **Project path:** `/home/ledadmin/projects/meshcentral-openclaw-bridge` **Current state:** ACTIVE — local protocol correction complete; live read-only verification pending **Progress cron:** `meshcentral-project-progress` disabled at Rob's request at 21:57 EDT; resume only when Rob asks. **Live-test gate:** CLOSED ## Executive summary The local read-only MVP is implemented and passes its local verification gate. The bridge has not yet completed a successful live MeshCentral inventory test. A live test was attempted with Rob's explicit approval on 2026-08-25, successfully established the TLS/WebSocket connection, then MeshCentral closed the control session before accepting the first `serverversion` request. No inventory, device metadata, command, diagnostic execution, or state-changing action completed. The exact MeshCentral 1.2.5 `meshctrl.js` protocol comparison is complete. The bridge was corrected to match the official authentication-header and response-correlation fields; local verification is green. The next task is a narrowly scoped live read-only compatibility test. ## Confirmed deployment facts - MeshCentral public/reverse-proxy URL: `https://mesh.ledrew.me` - MeshCentral backend: `10.10.10.177:80` - MeshCentral version: `1.2.5` - Installation: Proxmox Community Scripts MeshCentral installer - MeshCentral location: LXC on PVE2 - Service: `meshcentral.service` - Installation path: `/opt/meshcentral` - Data path: `/opt/meshcentral/meshcentral-data` - Test device: `PVE3` only - MeshCentral group: `Servers` - Integration username: `sa_clawdia` - External WebSocket endpoint expected by bridge: `wss://mesh.ledrew.me/control.ashx` - Reverse proxy: HTTPS enabled; WebSocket support reported enabled by Rob - Account permissions selected by Rob: - No New Device Groups - No New Devices - No Tools (MeshCmd/Router) - Lock Account Settings - No other listed permissions selected ### Secret handling The password is stored outside the project at: `/home/ledadmin/.openclaw/workspace/Credentials/.meshcentral-credentials` The file was changed to mode `0600` during this work session. Its contents must never be copied into this project, prompts, command lines, logs, reports, or chat. Do not record the password in future project notes. ## Local implementation status Location: `/home/ledadmin/projects/meshcentral-openclaw-bridge/implementation` Implemented capabilities: - Typed bridge contracts using Zod - Mock adapter for offline development - Real MeshCentral WebSocket adapter using `/control.ashx` - `x-meshauth` credential encoding - Credential validation before use - Generic credential/configuration errors - Credential and token redaction in structured logs - Explicit TLS certificate validation (`rejectUnauthorized: true`) - Optional custom CA configuration support in the client - Bounded response size (`MAX_RESPONSE_SIZE`) - JSON/protocol envelope validation - Action-specific response schema validation - Request/response action matching - Device and group allowlist enforcement/filtering - Timeout and bounded retry behavior - Token-bucket rate limiting - Bounded concurrent requests, safe default 5 - Configuration bounds validation for timeout, rate, burst, and concurrency - Structured audit events and controlled logger integration - Diagnostics remain mock-only - No remote commands or state-changing actions are implemented ### Local verification evidence Most recent successful verification during this session: ```text npm test -- --runInBand 11 test suites passed 90 tests passed npm run build passed npm run lint passed with no errors or warnings ``` Generated `dist/` output was rebuilt repeatedly as part of verification. The project has no committed baseline; files are currently workspace files under the project directory. ## Security and review artifacts Created/updated during this session: - `review/FINAL-HARDENING-REVIEW.md` - Current-source disposition of the older review findings - Local MVP gate: PASS - Live test: authorized by Rob for this project using the dedicated read-only account; operational scope remains strictly limited below - Deferred timeout separation and reconnect behavior recorded as non-blocking only for a single read-only test - `LIVE-TEST-PROCEDURE.md` - Preconditions - Allowed read-only operations - Stop conditions - Secret handling - Audit checks - Rollback procedure - `DEPLOYMENT.md` - Deployment facts - Secret handling - Live-test prerequisites - Hardening summary - Rollback rules - `TODO.md` - Local security review disposition marked complete - Deployment-specific live-test gates remain open Existing review artifacts: - `review/REVIEW.md` — earlier implementation review; contains findings from before later hardening - `review/LIVE-ADAPTER-REVIEW.md` — earlier live-adapter review; its findings were reconciled in `review/FINAL-HARDENING-REVIEW.md` ## Live test attempt and result **Approval:** Rob authorized read-only MeshCentral access for this project on 2026-08-26. This replaces the prior per-test approval requirement. The authorization does not expand the operation or target scope. The test used the protected external credential file and attempted only read-only operations: - Connect/authenticate - Health check / `serverversion` - Intended follow-up: groups, inventory, PVE3 metadata ### Observed results 1. Direct WebSocket connection to `wss://mesh.ledrew.me/control.ashx` succeeded. 2. TLS certificate validation succeeded; this was not a basic network/TLS failure. 3. The server sent a MeshCentral protocol close message before accepting `serverversion`. 4. Bridge `healthCheck()` returned `false`. 5. A direct client diagnostic showed the socket opened, then the request failed as `Not connected` after the server-side close. 6. No groups, devices, PVE3 metadata, diagnostics, commands, or state changes were performed. 7. No password, auth header, cookie, or token was printed or logged. A raw diagnostic observed a message shaped like: ```json {"action":"close","cause":"","msg":""} ``` The actual close values were not saved here because server-provided text may contain sensitive details. The server then closed with WebSocket code `1005` and no reason. ### Current hypothesis Likely possibilities: - MeshCentral 1.2.5 control-channel authentication/handshake sequence differs from the bridge implementation. - The official client sends an initial message or uses a subtly different header/auth format. - The reverse proxy accepts the WebSocket upgrade but affects the control protocol afterward. - The restrictive account permissions may not permit the control-channel session/commands even though the connection authenticates at the WebSocket layer. TLS and basic WebSocket reachability are less likely to be the primary failure because the handshake completed successfully. ## MeshCentral LXC evidence collected Rob provided: - `meshcentral.service` is active and running. - Main process: `/usr/bin/node /opt/meshcentral/node_modules/meshcentral/meshcentral` - Environment: `NODE_ENV=production` - No debug flags in `ExecStart` - Data files under `/opt/meshcentral/meshcentral-data` - No normal log file was found by the provided search. - `journalctl -u meshcentral.service` around the test window returned `-- No entries --`. - The service is not currently emitting useful connection/authentication diagnostics at its present logging configuration. No MeshCentral service configuration or debug setting was changed. ## Known blockers at pause 1. **Protocol comparison not started.** `PROTOCOL-COMPARISON.md` does not exist yet. 2. Need to compare the bridge with the exact MeshCentral 1.2.5 bundled `meshctrl.js` implementation, especially: - `x-meshauth` construction - WebSocket options and headers - Any initial message after socket open - First request framing and request IDs - Handling of server `action: close` - Permission behavior for inventory commands 3. Need to understand why the server closes the session before `serverversion`. 4. No successful live inventory test exists yet. 5. No current-source protocol compatibility test exists against a captured 1.2.5 fixture. ## Explicit safety boundaries - Do not retry the live connection with commands or state-changing operations; the corrected client is limited to the documented read-only test plan. - Do not run remote commands, diagnostics, shell access, file transfers, router operations, power operations, reboots, shutdowns, service changes, or any state-changing action. - PVE1/PVE2 production cluster is off-limits. - PVE3 is the only approved test target. - Do not enable public exposure. - Do not modify MeshCentral service configuration or enable debug logging without Rob's explicit request/approval. - Do not print, copy, or log the credential contents. - Stop immediately on unexpected protocol messages, TLS issues, authorization ambiguity, target ambiguity, sensitive output, or schema/action mismatch. ## Resume procedure When Rob asks to resume: 1. Confirm the progress cron should be re-enabled; it is currently disabled. 2. Read this file, `RESUME-HANDOFF.md`, `review/FINAL-HARDENING-REVIEW.md`, and `LIVE-TEST-PROCEDURE.md`. 3. Obtain the exact MeshCentral 1.2.5 `meshctrl.js` source from the deployed LXC or an exact version-pinned package/source reference without exposing secrets. 4. Write `PROTOCOL-COMPARISON.md` with observed differences and a decision. 5. Add/update mock protocol tests for the identified handshake/request sequence. 6. Run tests/build/lint. 7. Only if the local protocol fix passes, prepare a revised single-target read-only test. 8. Execute the authorized read-only live connection; do not expand the scope beyond server version, groups, inventory, and PVE3 metadata. 9. Do not expand the scope beyond server version, groups, inventory, and PVE3 metadata. ## Project status at pause **Local code:** verification-passing **Live compatibility:** failed initial read-only attempt; unresolved **Diagnostics:** mock-only **Remote commands/state changes:** not implemented and prohibited **Cron:** disabled by Rob **Subagents:** none active **Next work item:** controlled read-only live compatibility test **Required user input now:** none; resume only when Rob asks