Skip to content

Add a doctor command for read-only environment and connectivity diagnostics #205

Description

@mkrueger

Problem

Just an idea - cosmos/azure is very complex and problems tend to jump out of the box from nowehere. Would maybe be helpful to let the shell check problems for you before they occur.

After GA, the most common support traffic for a CLI is usually not feature requests — it is "it does not connect", "I get 403", or "it hangs". Diagnosing those today requires a round trip to collect shell version, install method, platform, auth mode, connection mode, endpoint, and RBAC state.

There is no single command that collects this and renders a verdict. info reports resource configuration and usage, and connect reports the current connection, but neither answers what is broken and what to do about it.

Proposed solution

Add a read-only doctor command that runs a fixed set of checks and reports PASS / WARN / FAIL / SKIP with actionable remediation text.

doctor
doctor --database MyDb --container Items
doctor --format json

Example output:

PASS  Shell version       1.0.213-preview (dotnet tool)
PASS  Authentication      Azure CLI credential acquired
PASS  Account endpoint    Reachable in 84 ms (Direct)
WARN  Control plane       No ARM context (account-key auth)
      mkdb/mkcon/rmdb/rmcon/indexpolicy may fail under strict data-plane RBAC.
      Reconnect with Entra ID, or pass --subscription and --resource-group.
FAIL  Container access    403 Forbidden
      Required data-plane role: Cosmos DB Built-in Data Reader

Scope: three tiers

ARM is not required, and must stay optional.

Tier Requires Checks
0 nothing shell version, OS/arch, install method, .NET runtime, relevant env vars, DNS, proxy, TLS, clock skew
1 data plane credential acquisition, endpoint reachability, connection mode, database/container existence, read + query permission
2 ARM (opt-in) account resource resolution, control-plane reachability, role assignments

Tier 2 runs only when an ARM context already exists on the state, or when the user passes --arm explicitly. A missing ARM context is reported as SKIP, never FAIL.

Why ARM must stay optional

  • CosmosArmResourceProvider.TryCreateContextAsync returns null immediately when credential == null, so account-key and connection-string auth have no ARM context at all.
  • The emulator has no ARM.
  • CosmosArmResourceProvider.DiscoverContextAsync enumerates every subscription and every Cosmos account until the endpoint matches. That is far too slow to sit on a diagnostic command's default path.
  • CI and workload-identity principals frequently have no ARM permission by design.

Notable checks

  1. ARM-context gap (highest value). The comment above CosmosArmResourceProvider.TryCreateContextAsync already documents this: key auth means no ARM context, so control-plane commands (mkdb, mkcon, rmdb, rmcon, indexpolicy) fall back to the data plane and then fail on accounts with strict data-plane RBAC. doctor should name this explicitly instead of leaving users to discover it through a failed command.
  2. RBAC parsing reuse. InfoCommand.PrincipalIdRegex already parses does not have required RBAC permissions to perform action. Extract and reuse it rather than writing a second parser.
  3. Direct-mode port probe. Direct mode needs outbound TCP 10250-10256. On corporate networks this presents as a hang rather than an error; the check should recommend --connect-mode gateway.
  4. Clock skew. Drift beyond roughly 5 minutes breaks token validation with unhelpful errors.
  5. Emulator certificate. Certificate validation is bypassed only for emulator endpoints, so a self-signed certificate on a non-emulator endpoint should be flagged rather than silently failing.

Non-goals for v1

  • No --fix and no mutating behavior. doctor stays read-only so it is safe to run and safe to paste into an issue.
  • No duplication of info or connect output beyond what a verdict requires.

Acceptance criteria

  • doctor runs with no connection and still produces Tier 0 results
  • Tier 1 checks run against the current or specified database/container
  • Tier 2 is skipped cleanly when no ARM context is present; --arm opts in
  • --database / --container target explicitly, consistent with other commands
  • Text output plus stable --format json output
  • Non-zero exit code when a required check fails (aligns with the non-interactive output contract in A1. Non-interactive output contract (NDJSON / --output json / stable exit codes) #155)
  • Output never contains keys, tokens, connection strings, or document data
  • Golden-file redaction test: run against a connection carrying a known key and token, assert neither appears in text or JSON output
  • Unit tests for severity resolution and remediation mapping
  • Exposed over MCP as a read-only tool so agents can self-diagnose connectivity
  • Help strings added to lang/en.ftl
  • Documented in docs/commands.md plus a troubleshooting section

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestguardrailsSafety, guardrails & observability

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions