# Diagnostic Access Improvements ## Goal Make it practical for an agent on a separate SSH machine to diagnose browser and production failures without granting broad production control or asking the user to paste console output. ## Browser Captures Diagnostic mode (`?diag=1`) offers **Capture diagnostic**. Upload and metadata remain authenticated. The PNG URL at `/api/debug/captures/{id}` is public by its 72-bit id, which is the explicit handoff capability a user shares with an agent. After inspecting a user-shared capture, the agent must immediately call: ``` DELETE /api/debug/captures/{id} ``` The 24-hour expiry and 50-capture cap remain a backstop. Do not inspect capture URLs that the user has not explicitly supplied. ## Production Diagnostics Do not grant an agent a general production shell or Docker-group membership. Docker access is effectively root access, and arbitrary shell access can expose environment variables, OAuth tokens, and mounted volumes. Instead create a dedicated `chart-debug` production account with a forced-command SSH wrapper. It accepts only a small, read-oriented command set: ``` logs --since status container-state recent-deploy capture-read capture-delete ``` The wrapper must reject arbitrary commands and paths. It should cap output, redact known secret patterns, and log every request. Use a dedicated SSH key that can be revoked without affecting deployment or normal administration. Expected agent usage: ``` ssh chart-debug@production logs --since 20m ``` ### Installation on the Coolify host The implementation lives in `ops/chart-debug-command` and `ops/install-chart-debug`. The Coolify-side agent must run as root on the Docker host, not inside the application container. 1. Identify the current chart container and a stable name prefix that survives deploys: ```bash docker ps --format 'table {{.ID}}\t{{.Names}}\t{{.Image}}' ``` The Coolify resource UUID is `dgvch0xqv8uvjfor7dl8bwl9`; a likely anchored pattern is `^dgvch0xqv8uvjfor7dl8bwl9`, but the agent must verify it matches exactly one running container before installation. 2. Run the installer from a checkout containing `ops/`, using the dedicated public key supplied out-of-band: ```bash sudo ./ops/install-chart-debug \ --public-key 'ssh-ed25519 AAAA... chart-debug restricted production diagnostics' \ --container-pattern '^VERIFIED-STABLE-PREFIX' \ --url https://chart.amow.com ``` 3. Verify the account is locked, files are root-owned, sudo policy is valid, the selector matches exactly one container, allowed commands work, and an arbitrary command is denied: ```bash passwd -S chart-debug stat -c '%U:%G %a %n' /usr/local/sbin/chart-debug-command \ /etc/chart-debug.conf /etc/sudoers.d/chart-debug visudo -cf /etc/sudoers.d/chart-debug sudo -u chart-debug sudo -n /usr/local/sbin/chart-debug-command 'container-state' sudo -u chart-debug sudo -n /usr/local/sbin/chart-debug-command 'logs --since 5m' if sudo -u chart-debug sudo -n /usr/local/sbin/chart-debug-command 'shell'; then echo 'ERROR: arbitrary command was allowed'; exit 1 else echo 'arbitrary command correctly denied' fi ``` 4. Confirm SSH permits the `chart-debug` user. If `AllowUsers` is configured, add `chart-debug`; do not enable password authentication. Report the host or IP and SSH port so the client alias can be configured. Security invariants: - Do not add `chart-debug` to the Docker group. - Do not install the private key on production or paste it into chat. - Keep `/etc/chart-debug.conf`, the wrapper and sudoers entry root-owned. - Keep the account password locked and the `authorized_keys` `restrict` forced command intact; no additional unrestricted keys. - The wrapper must match exactly one running container. Zero or multiple matches fail closed. - Verify denials as well as successful commands. Audit records are available via `journalctl -t chart-debug`. ## Observability Keep browser performance telemetry separate from production access. A future frontend recorder should locally aggregate frame timing, long tasks, tick rate, visible bars, and rendered line/level counts, then periodically upload compact, authenticated summaries. Pair it with server timing for bar handling, level rebuilds, WebSocket serialization, and the existing loop-lag measure. This separates rendering, feed, transport, and backend pressure without logging prices, drawing text, cursor positions, screenshots, or per-tick event history.