Diagnostics commands¶
Common global behavior is documented in the CLI hub. The complete diagnostic command contract follows.
gdsgate doctor¶
Run a read-only health checklist against the local configuration and state, then
exit. Findings are grouped into configuration (file paths exist and are readable,
0600 on secrets, semantic invariants such as ha needing PostgreSQL,
connector-backend validity), features (what is enabled, what is silently off, and
why), and state (store persistence, store schema and CA consistency for
Authority, transport-identity freshness for a node, cached logins for a client).
Every warning or failure carries a one-line fix.
A parameter that accepts the secret-reference
notation is reported by where
its value comes from: a file, a variable, or a command. The 0600 check
applies only to the file form; a value read from a variable or a command has no
file to check, and the report says so instead of guessing. Nothing behind a
reference is read for this: an unresolvable command or variable is reported at
the point that actually tries to resolve it, not by doctor.
Applicable checks are detected from the config: Authority checks run when a store
is configured, node checks when enrolment or connector backends are set, client
checks against ~/.gdsgate. Nothing is mutated, so it is safe as a preflight: a
store schema that is behind this binary is reported as a failure naming
gdsgate authority migrate instead of applied.
Most checks read local files. One does not: for a PostgreSQL backend in
session_role mode, doctor connects
with the backend's own service account and asks the database what each session
role can do, whether the role exists, whether the service account can assume it,
and what it can write, separating a grant made to PUBLIC, which reaches every
role, and a table the role owns, with full rights and no ACL entry, from an
ordinary grant. A profile declared read_only = true that can write is a
failure; the query is a SELECT against pg_catalog and nothing is written.
That catalog grant probe is PostgreSQL-only: it queries pg_catalog and does
not run against a CockroachDB catalog. The connector's session-role path still
supports both PostgreSQL and CockroachDB over the PostgreSQL wire protocol; a
CockroachDB backend is reported as unchecked for this doctor probe rather than
skipped in silence. Every other check covers every kind.
Grants live per database, and a session is not confined to the one in the DSN,
since <resource>.<db> opens the same backend against another database, so each
profile is checked in every database of the cluster the service account can
reach, up to twelve per run, and the report says when it stopped short. A
database that does not answer within five seconds is reported as unchecked rather
than clean, and an unreachable backend is a warning rather than a failure:
somebody else's database being down is not this host's misconfiguration.
--json emits a machine-readable report. The exit code is 2 if any check fails,
and 0 when only warnings or info remain, so it slots into a systemd
ExecStartPre= or a container healthcheck.
A configuration a service refuses to start on is exactly when the checklist is
wanted, so doctor is not gated on the settings a service is gated on. A
profile no process could publish stops
authority, proxy, connector and all; here it is a config.profile
finding, listed beside everything else the same run found. The one thing it does
need is a configuration to read: a --config that names a missing file, or a
file that is not valid TOML, fails the command, since there would be nothing to
report on but defaults nobody is running.
Findings that read identically are printed as one line with a count. A host with
a few hundred cached logins has a state.login finding for each of them, and the
report is a line instead of a page:
--explain lists what each folded line stands for, in place of the count. It has
no effect on --json, which carries every check either way.
Each run saves a snapshot to ~/.gdsgate/last-doctor.json and compares against
the previous one, so a check whose status changed since the last run is
annotated: ↓ worse than last run, ↑ better than last run for a failure that
is now only a warning, or ↑ recovered when nothing is left to do, with an
N worse than last run line in the summary. Each finding is compared with
itself: a check that covers several things, one cached login of many or one role
of two, carries which one it is about, so one login recovering says nothing about
the login beside it.
gdsgate --config node.toml doctor
gdsgate --config node.toml doctor --explain
gdsgate --config node.toml doctor --json
Reading a failure¶
Start with the check id and named source of truth. Missing identity, invalid TOML or Cedar, a store migration, and an unreachable route have different remediations. Capture JSON without including tokens, private keys, or complete policy contents in an incident ticket.