1 Commits

Author SHA1 Message Date
Serena Ruan 42f3d703c4 feat(cli): add omnigent diagnose environment snapshot (#3928)
* feat(cli): add `omnigent diagnose` environment snapshot

Add a read-only `omnigent diagnose` command that prints a small, secret-free
environment snapshot for bug reports: CLI version, OS/Python, and the server's
auth mode. With `--server <url>` (or a resolvable configured/local server) it
reads the server version and real auth mode from the unauthed `GET /v1/info`
endpoint, so version skew between CLI and server is visible — the same reason
the session-info popover shows `server · host`.

The auth mode doubles as the OSS-vs-managed signal: accounts | single_user |
oidc | header, derived from `/v1/info` when the server is reachable and falling
back to the local environment otherwise (tagged by `auth_source_origin` so the
two are never confused). The snapshot carries no secrets — only versions, OS,
and the coarse auth mode.

`omnigent doctor` (install-ledger migration) is left untouched.

Co-authored-by: Isaac

* fix(cli): address diagnose review — redact server_url, e2e test, help caution

Review follow-ups on the `omnigent diagnose` PR:

- Redact userinfo and query/fragment from the reported `server_url` so a
  `--server https://user:pass@host` value can't leak credentials into the
  snapshot (the "safe to paste into an issue" invariant).
- Add CLI-level tests (CliRunner + respx over /v1/info) exercising the command
  wiring and output format end-to-end, alongside the existing unit tests.
- Note in `--help` that `--server` should point only at a trusted server, since
  reaching a managed server may attach stored/ambient credentials to the request
  (same behavior as `session export` / `run --server`).

Auth is intentionally still attached to the /v1/info probe: a managed server
sits behind an auth proxy that 401s an unauthenticated request, so dropping it
would break the OSS-vs-managed signal for exactly the managed case. Attaching
credentials to the request does not put secrets in the output, which is what the
"secret-free" guarantee covers.

Co-authored-by: Isaac

* fix(cli): harden diagnose URL redaction + register in subcommand allowlist

- _redact_url: fix two leaks the review found. Scheme-less inputs with userinfo
  (`user:pass@host:6767`) were returned unchanged because urlsplit reads the
  `user:` as a scheme — now scrubbed. IPv6 literals lost their required `[...]`
  brackets when netloc was rebuilt from hostname/port — now the userinfo is
  dropped off the authority in place, preserving brackets and host casing.
- Add `diagnose` to `_CLICK_SUBCOMMANDS` so `omnigent diagnose` is reachable
  from main() (a registered command missing from the allowlist is rejected as
  removed ad-hoc chat). Fixes test_click_subcommands_allowlist_covers_registered_commands.

Co-authored-by: Isaac

* fix(cli): make diagnose URL redaction leak-proof on malformed/scheme-less input

Follow-up on review: _redact_url used urlsplit, which raises ValueError on a
malformed IPv6 URL (the fallback then returned the raw string, leaking any
user:pass@) and left query/fragment intact on scheme-less inputs. Rewrote it as
pure string surgery — cut at the first ?/#, then drop a user:pass@ prefix from
the authority — so credentials and tokens are stripped uniformly regardless of
URL shape, with no parser that can raise. IPv6 brackets and host casing are
preserved.

Co-authored-by: Isaac
2026-08-03 16:07:23 +08:00