Skip to content

Add --debug flag to report winning cloud credential source#120

Merged
sdairs merged 16 commits into
issue-109-auth-status-env-varsfrom
issue-48-debug-auth-source
May 5, 2026
Merged

Add --debug flag to report winning cloud credential source#120
sdairs merged 16 commits into
issue-109-auth-status-env-varsfrom
issue-48-debug-auth-source

Conversation

@sdairs
Copy link
Copy Markdown
Collaborator

@sdairs sdairs commented Apr 16, 2026

Closes #48.

Stacked on top of #119 — merge that one first.

Summary

Credentials for clickhousectl cloud can come from four sources (CLI flags, .clickhouse/credentials.json, env vars, OAuth tokens), and until now it was hard to tell which one actually won precedence when debugging. A command could appear to be using env vars but actually be reading a project-local credentials.json.

  • New --debug global flag on cloud commands. When set, prints [debug] auth source: ... and [debug] api url: ... to stderr before the command runs. Going to stderr means it works equally well with and without --json — the command's own output (JSON or text) stays clean on stdout and remains pipeable to jq.
  • cloud auth status gains an Active column that marks which source actually wins precedence right now, so users no longer have to infer it from the resolution order.
  • Under the hood: new AuthSource enum, CloudClient::auth_source() / base_url() accessors, and a shared resolve_active_auth_source() helper so the client and auth status can't drift out of sync.

Test plan

  • cargo test -p clickhousectl — 206 passing, including new tests for AuthSource::{label,describe}, resolve_active_auth_source precedence, and the client's auth_source() accessor.
  • cargo clippy -p clickhousectl --all-targets clean.
  • Manually verified:
    • cloud --debug auth status prints debug line and table.
    • CLICKHOUSE_CLOUD_API_KEY=x CLICKHOUSE_CLOUD_API_SECRET=y cloud --debug --json auth status keeps JSON clean on stdout and debug info on stderr; Active: yes appears next to Env vars.

Closes #48. Credentials can come from CLI flags, `.clickhouse/credentials.json`,
env vars, or OAuth tokens, and it was hard to tell which one actually won
precedence when debugging. `--debug` now prints the resolved source and API
URL to stderr, so it works equally well with and without `--json`.

`cloud auth status` also gains an `Active` column that marks the winning
source, reusing the same resolution logic.
Plumbs all 13 ClickHouse Cloud managed Postgres operations into the CLI
under `clickhousectl cloud postgres ...` — CRUD, lifecycle (restart/
promote/switchover), CA certs, runtime config (get/replace/patch with
--set key=value overrides), password reset, read replica creation, and
PITR restore. Lives in its own src/cloud/postgres.rs module with 33 new
unit + parse tests and the full write-classification coverage.

Closes #116

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@sdairs sdairs mentioned this pull request Apr 16, 2026
5 tasks
sdairs and others added 10 commits April 17, 2026 14:42
Mirrors the ClickHouse service lifecycle test (create, wait-running, list,
certs, config get, PATCH tags, password reset, restart, delete) against the
Postgres endpoints, wired into the scheduled Cloud Integration workflow.

Password step treats a successful 200 as the pass condition: per the OpenAPI
spec, PostgresServicePasswordResource.password is only populated when the
request omits `password`, so the supplied-password path returns empty by
design.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Tables now render using only ASCII `|` and `-` instead of the
non-standard rounded box-drawing characters, so output is readable in
minimal terminals and log aggregators and pasteable into issues/PRs.

Closes #126
Closes #133. Uses the is-ai-agent crate to detect when the CLI is invoked under a known agent (Claude Code, Cursor, Gemini CLI, Codex, Goose, Devin, etc.) and appends an agent=<id> query param to outbound requests to ClickHouse-owned hosts (builds.clickhouse.com, packages.clickhouse.com, api.clickhouse.cloud). GitHub and other third-party hosts are not annotated. The cloud library gains a generic Client::with_extra_query_params builder so the CLI can attach the tag to every request.
Three of the four credential branches in CloudClient::new differed only in which (key, secret) pair they pulled and which AuthSource label to attach. Introduce ResolvedAuth + resolve_auth() to walk the precedence ladder once, then build the lib client and tag it with the agent param at a single site. resolve_active_auth_source becomes a thin wrapper that preserves its lenient half-set CLI-flag behavior for cloud auth status.
The helper is only called from cloud auth status, which never has --api-key/--api-secret to pass (the subcommand doesn't accept them). The half-set lenient branch and its test were protecting a contract no production caller exercises. Inlining the only sensible call removes the dead parameters and the dead branch, leaving a one-line wrapper that documents its actual purpose: peek at credential precedence without erroring on the empty case (which auth status needs to render no-creds-configured correctly).
The local AgentId -> kebab-case match arm was duplicating a mapping the crate already maintains for its AGENT= env var parser. is-ai-agent 0.2.1 exposes AgentId::as_str returning the canonical kebab-case id (claude-code, gemini-cli, etc.) — the inverse of the parser. Switch to it. Replaces our 12-arm match plus exhaustive variant test with a single delegation and a contract test against the upstream lookup. New agents added upstream automatically flow through without code changes here.
…arams

Rather than thread an agent search param through every clickhouse.com request (with a URL-domain gate, two helpers, and a generic extra-query-params feature on the cloud library), fold the signal into the User-Agent header that every outbound request already carries: clickhousectl/0.1.18 (agent=claude-code). RFC 7231 allows parenthesised comments in User-Agent, and this matches conventional shapes (Mozilla/5.0 etc). Detection still uses is-ai-agent. The change deletes the agent_signal module, the cloud library extra_query_params API + tests, the URL-host parser, and the per-call-site wrappers in version_manager — net -146 lines vs the previous implementation. Every reqwest::Client::builder() in the codebase already calls user_agent::user_agent(), so the new attribution flows through with zero per-call-site wiring.
It's now a one-line implementation detail of an analytics signal — not user-facing functionality, not configurable, not surprising for a future reader to understand from the user_agent.rs source. Doesn't earn a documentation entry.
Pull in upstream security fixes flagged by Dependabot. Both are transitive dependencies; lockfile-only update, no API or behaviour changes. Build and full workspace tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
sdairs added 4 commits May 5, 2026 18:02
@sdairs sdairs had a problem deploying to cloud-integration May 5, 2026 17:06 — with GitHub Actions Failure
@sdairs sdairs merged commit 153e8e9 into issue-109-auth-status-env-vars May 5, 2026
11 of 12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants